[英]How to marshal an array of structure In C#?
我必须在C#中调用C ++ dll。 dll的头文件如下(简化):
// C ++的标题
struct vector
{
float x;
float y;
vector()
{}
vector(float x0, float y0)
{
x = x0;
y = y0;
}
};
struct unmanaged_struct
{
int int_var;
float float_var;
char* chars_var;
vector vector_var;
unmanaged_struct(int i, float f, char* ch, float vec_x, float vec_y)
{
int_var = i;
float_var = f;
chars_var = ch;
vector_var = vector(vec_x, vec_y);
}
};
//此函数用于输出struct实例的所有变量值
extern "C" __declspec( dllexport ) void unmanagedstruct_summary(unmanaged_struct* us_list, int length);
我在C#中定义了以下类
// CSHARP
[StructLayout(LayoutKind.Sequential)]
public class Vector
{
public float x;
public float y;
public Vector(float f1, float f2)
{
x = f1;
y = f2;
}
}
[StructLayout(LayoutKind.Sequential)]
public class UnmanagedStruct
{
public int int_var;
public float float_var;
public string char_var;
public Vector vector_var;
public UnmanagedStruct(int i, float f, string s, Vector vec)
{
this.int_var = i;
this.float_var = f;
this.char_var = s;
this.vector_var = vec;
}
}
class UnmanagedDllCallTest
{
[DllImport("unmanageddll.dll", EntryPoint = "unmanagedstruct_summary")]
public static extern void unmanagedstruct_summary([Out]UnmanagedStruct[] usList, int length);
static void Main(string[] args)
{
UnmanagedStruct[] usList = new UnmanagedStruct[1];
usList[0] = new UnmanagedStruct(1, 1.0f, "aa", new Vector(10, 1));
usList[1] = new UnmanagedStruct(2, 2.0f, "ba", new Vector(20, 2));
UnmanagedDllCallTest.unmanagedstruct_summary(usList, 2);
}
输出如下:
unmanaged_struct摘要:
0
1.12104e-044
未处理的异常:System.AccessViolationException:尝试读取或写入受保护的内存。 这通常表明其他内存已损坏。 在c:\\ users \\ dynaturtle \\ docnt nts \\ visual studio 2010 \\ Projects \\ callunmanageddll \\ callunmanageddll \\ Program中的callunmanageddll.Program.Main(String [] args)中的callunmanageddll.UnmanagedDllCallTest.unmanagedstruct_summary(UnmanagedStr uct [] usList,Int32长度) .cs:lin e 68
C ++ dll正常,因为我已经用C ++编写了测试,并且该功能运行良好。 我已经阅读了该线程,但是看来该解决方案在我的情况下不起作用。 有什么建议么? 提前致谢!
使用Marshal.PtrToStructure
。 有一个样品在这里 。
因此,您必须将方法的签名从out结构数组更改为out IntPtr。 但是,您需要知道要传递的缓冲区的大小。
public struct Vector
{
public float x;
public float y;
}
public struct UnmanagedStruct
{
public int int_var;
public float float_var;
public string char_var;
public Vector vector_var;
}
class UnmanagedDllCallTest
{
[DllImport("unmanageddll.dll", EntryPoint = "unmanagedstruct_summary")]
public static extern void unmanagedstruct_summary([Out] IntPtr ptr, int length);
static void Main(string[] args)
{
for(int i=0; i<length; i++)
{
UnmanagedStruc st;
Marshal.PtrToStructure(ptr, st);
// increment ptr and move forward
}
}
第一:Vector和UnmanagedStruct应该是结构,而不是类。
JIC我会分享我的方法。 也许这不是我一次花时间来解决问题的预期答案。
我具有以下结构来公开DLL中的某些数据。
//C++ code
struct State
{
const wchar_t * name;
unsigned int state;
};
APIENTRY bool get_states(H_PRCSR, MacroState *, const int sz); //pay attention, function accepts already allocated array and size for it
从C ++接受此数据,我可以这样做
std::vector<State> states(desired_size);
get_states(hparser, &states[0], states.size());
为了在C#上执行相同的操作,我使用了以下方法
//C#
[StructLayout(LayoutKind.Sequential)]
public struct Status
{
public IntPtr name;
public uint state;
public string getName()
{
if (name == IntPtr.Zero) return "<no-value>";
return Marshal.PtrToStringUni(name);
}
}
//And import function...
[DllImport(dll, CallingConvention = CallingConvention.Winapi)]
private static extern bool get_states(IntPtr p, [Out]MacroFlag[] flags, int flags_size);
//And simple decoder
public static Status[] getAll(IntPtr p, int size)
{
var results = new Status[size];
get_states(p, results, size);
return results;
}
因此,我看到了执行此操作的不同方法。 这就是其中之一。 它对我有用。 也许,这篇文章无法解决问题,但将是一个不错的起点
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.