c# - 将指向类的指针从 C# 传递到非托管 C++ 代码

标签 c# c++ marshalling unmanaged

我在 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# 中,我们有 classstruct。所有 class 类型都是引用,但 struct 类型是值类型。这意味着当你有类似 class MyStruct 的东西并且你写 MyStruct s 它实际上就像一个指向基类的指针,当你通过引用传递它时你实际上传递了地址该指针的一部分,因此它与期望指向主 struct 的指针的 C++ 无关。根据此解决方案,您的问题是将 class 转换为 struct

longulong 在 C# 中是 64 位类型,而在 C++(至少 MSVC)中它们是 32 位类型,所以当你声明你的函数时,它的第一个参数是 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 位值

关于c# - 将指向类的指针从 C# 传递到非托管 C++ 代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12978160/

相关文章:

java 对象编码

xml - 通过 UnMarshal 和 MarshalIndent 往返 xml

c# - 无法编码(marshal) 'return value' : Invalid managed/unmanaged type combination

c# - 损坏的 "rename"功能

c# - 如何访问 UWP 中的当前应用程序文件夹?

c# - 检查 MVC 模型返回字段中的空值

c# - 如何从 Windows 10 通用应用程序将 Firebase 与 C# 连接?

c++ - 使用 boost.python 导入带有 opencv 调用的方法但由于编译后未找到符号而失败

c++ - 在 MacOS X 中使用 c++11 和编译的 Boost 库难题

c++ - 通过缓存元函数优化编译时性能