将指针从C#传递到非托管的C 代码中

Passing a pointer to class into unmanaged c++ code from C#

本文关键字:代码 指针      更新时间:2023-10-16

我在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

在C#中我们有class ES和struct s。所有class类型都是参考,但struct类型是值类型。这意味着当您具有class MyStruct之类的东西并且编写MyStruct s时,实际上是类似于基类的指针,当您通过参考将其传递时,您实际上是通过该指针的地址,因此它与C 无关到主struct。根据您问题的解决方案,是将class转换为struct

long和C#中的ulong是64位类型,而C 中的32位(MSVC至少为MSVC),因此当您声明函数以使其第一个参数为long时,您会发送额外的32位值,该额外的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,32位值

sizeof()返回32,因为对8个字节值类型Ulong的对齐要求。structlayoutattribute.pack的默认值为8,与本机代码中使用的默认包装相同。因此,Data1被对齐以抵消8,并且在NERVERDER和DATAID 1之间存在4个字节差距。因此4 x 1 4 3 x 8 = 32。

您可能会遇到差距,因为在与MSVC编译器编译的本机C 代码中,ulong为4个字节。与C#中的UINT相同。因此,修复结构声明,用UINT代替Ulong。

下一个问题,即AV的原因,是您将结构声明为C#中的类。这是一种始终通过参考传递的参考类型。您当前的声明等效于C 代码中的Mystruct **。在声明中删除 ref ,或将其声明为结构而不是类。