5

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

4

2 回答 2

1

在 C# 中,我们有classes 和structs。所有class类型都是引用,但struct类型是值类型。这意味着当你有类似的东西class MyStruct并且你写MyStruct s它实际上就像一个指向基类的指针时,当你通过引用传递它时,你实际上传递了那个指针的地址,所以它与 C++ 没有任何关系,它期望一个指向 main 的指针struct. 根据这个解决你的问题是转换classstruct.

long并且ulong在 C# 中是 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]

因此,当调用函数时,它将采用无效参数作为结构的地址。所以只需将您的函数定义更改为:

[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 位的值

于 2012-10-19T16:09:47.203 回答
1

由于 ulong 的对齐要求,SizeOf() 返回 32,ulong 是一个 8 字节的值类型。StructLayoutAttribute.Pack 的默认值为 8,与本机代码中使用的默认打包相同。因此 data1 与偏移量 8 对齐,并且 nReserved 和 data1 之间有 4 个字节的间隙。所以 4 x 1 + 4 + 3 x 8 = 32。

您可能有这个差距,因为在使用 MSVC 编译器编译的本机 C++ 代码中,一个 ulong 是 4 个字节。与 C# 中的 uint 相同。所以修复结构声明,将ulong替换为uint。

下一个问题,即 AV 的原因,是您在 C# 中将结构声明为类。这是一个总是通过引用传递的引用类型。您当前的声明等同于 C++ 代码中的 MyStruct**。删除声明中的ref或将其声明为结构而不是类。

于 2012-10-19T18:46:13.547 回答