我在dll中有一个c ++导出函数:
int MyMethod(ulong pid, MyStruct* struct);
MyStruct被描述为类:
class MyStruct
{
public:
uchar nVersion;
uchar nModuleType;
uchar nMachine64;
uchar nReserved;
ulong data1;
ulong data2;
ulong data3;
};
我试图将此功能导入我的C#代码,如下所示:
[DllImport("mydll.dll", EntryPoint = "#24")]
private static extern int _MyMethod(long pid, ref MyStruct struct);
C#中的类:
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
stuct MyStruct
{
public byte nVersion;
public byte nModuleType;
public byte nMachine64;
public byte nReserved;
public ulong data1;
public ulong data2;
public ulong data3;
}
我得到System.AccessViolationException
:
MyStruct struct = new MyStruct();
_MyMethod(4728, ref struct);
出了什么问题?
更新:
System.Runtime.InteropServices.Marshal.SizeOf(struct)
返回32.为什么?我认为它应该是4 * 1 + 8 * 3 = 28
答案 0 :(得分:1)
在C#中,我们有class
个es和struct
个。所有class
类型都是引用,但struct
类型是值类型。这意味着当你有类似class MyStruct
的东西而你写MyStruct s
时,它实际上就像是指向基类的指针,当你通过引用传递它时你实际上传递了该指针的地址,所以它什么都没有期待指向主struct
的指针的C ++。根据此解决方案,您的问题是将class
转换为struct
。
long
和ulong
是64位类型,而它们在C ++中是32位(至少是MSVC),所以当你声明你的函数时它的第一个参数是long
您发送额外的32位值,可能会覆盖下一个参数并导致它无效:
Stack:
32 bit: [first 32 bit of the first parameter]
32 bit: [second 32 bit of the first parameter]
32 bit: [address of your structure]
因此,当函数调用它时,将使用无效参数作为struct的地址。所以只需将您的函数定义更改为:
[DllImport("mydll.dll", EntryPoint = "#24")]
private static extern int _MyMethod(int pid, ref MyStruct struct);
你的结构:
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
stuct MyStruct
{
public byte nVersion;
public byte nModuleType;
public byte nMachine64;
public byte nReserved;
public uint data1;
public uint data2;
public uint data3;
}
可能是你的错误的来源是函数的第一个参数,因为函数需要一个32位的值而你提供一个64位的实际上你提供2,3位的值来导致函数的函数
答案 1 :(得分:1)
由于ulong的对齐要求,SizeOf()返回32,这是一个8字节的值类型。 StructLayoutAttribute.Pack的默认值为8,与本机代码中使用的默认包装相同。因此data1与偏移量8对齐,nReserved和data1之间有4个字节的间隙。所以4 x 1 + 4 + 3 x 8 = 32。
您可能会遇到这种差距,因为在使用MSVC编译器编译的本机C ++代码中,ulong是4个字节。与C#中的uint相同。所以修复结构声明,用uint替换ulong。
下一个问题,即AV的原因,就是你在C#中将结构声明为一个类。哪个是始终通过引用传递的引用类型。您当前的声明等同于C ++代码中的MyStruct **。删除声明中的 ref 或将其声明为结构而不是类。