通过 PInvoke 从 C# 到 C++ 的简单结构中的垃圾数据

Posted

技术标签:

【中文标题】通过 PInvoke 从 C# 到 C++ 的简单结构中的垃圾数据【英文标题】:Garbage data in simple struct from C# to C++ via PInvoke 【发布时间】:2017-10-21 19:37:17 【问题描述】:

我有一个简单的 Size 结构,它被定义为

#pragma pack(push, 8)
struct Size final

public:
  std::int32_t Width = 0;
  std::int32_t Height = 0;
;
#pragma pack(pop)

在 C++ 和 as 中

[StructLayout(LayoutKind.Sequential, Pack = 8)]
public class Size

    public System.Int32 Width  get; set; 
    public System.Int32 Height  get; set; 

在 C# 中。

现在,我正在尝试创建一个 C# Size 对象并将其发送到 C++ 代码,因为我在 C++ 中有这个函数

extern "C" 
__declspec(dllexport) auto Test(Common::Size size) -> void;


auto Test(const Common::Size size) -> void

    // Do something

和一个 PInvoke C# 函数将其称为:

[DllImport("mydll.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "Test")]
public static extern void Test(Common.Size size);

总结一下,我用这段代码调用了 Test 函数:

var outputSize = new Common.Size()  Width = 100, Height = 200 ;
PluginApi.Test(outputSize);

现在,我希望 C++ 函数中的参数大小分别具有 100 和 200 到 Width 和 Height 的值,但我得到的是垃圾编号,更准确地说,132313736 表示 Width 和 0 到高度。

在这种情况下我做错了什么?

【问题讨论】:

我认为这与public class Size 有关,它可能会为每个持有的对象引入一个“标题”,例如类型信息(如果需要,可以使用“vtable 指针”)。所以 c# 中对象的内存布局和 C 中结构的实例可能不匹配。您是否尝试过在 C# 中使用结构? 你完全正确!这是我的一个重大疏忽。将其更改为 struct 解决了它!您可以添加您的评论作为答案,以便我可以将其标记为已解决吗?非常感谢 它会解决问题,但原因完全不同。 【参考方案1】:

它与 C# 中的public class Size 有关,它可能会为每个持有的对象引入一个“标题”,例如类型信息(如果需要,可以使用“vtable 指针”)。所以 c# 中的对象的内存布局和 C++ 中的 struct 的实例可能会不匹配。

在 C# 中使用结构而不是类应该可以解决问题。

【讨论】:

不正确。真正的区别是c#类被编组为引用,即指针,而c#结构被编组为值。

以上是关于通过 PInvoke 从 C# 到 C++ 的简单结构中的垃圾数据的主要内容,如果未能解决你的问题,请参考以下文章

将带有结构字段的结构从 c++ 返回到 c# pinvoke

从 c++ 到 c# 的 pinvoke 字节数组

将字符串从 C++ 传递到 C#

如何使用 PInvoke 将 std::wstring 从 C++ 返回到 C# 而无需编写字符串缓冲区转换 [重复]

从 PInvoke 返回一个字符串? [复制]

PInvoke 与指针 - C++ 到 C#