c# - 在 32 位和 64 位运行时编码(marshal)结构时的不同行为

标签 c# winapi data-structures pinvoke marshalling

我在 PInvoking 时发现了这个 SetupDiCreateDeviceInfoList .

C++ 函数签名是:

HDEVINFO SetupDiCreateDeviceInfoList(
  _In_opt_ const GUID *ClassGuid,
  _In_opt_       HWND hwndParent
);

在 C# 中,我定义了这样的 GUID 结构:

[StructLayout(LayoutKind.Sequential)]
public struct GUID
{
    public uint Data1;
    public ushort Data2;
    public ushort Data3;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
    public byte[] Data4;
}

和这样的功能:

[DllImport("Setupapi.dll")]
public static extern IntPtr SetupDiCreateDeviceInfoList(GUID ClassGuid, IntPtr hwndParent);

由于在 C# 中,结构默认通过副本传递(与类不同),因此该函数签名不应匹配。事实上,在 32 位运行时调用函数时:

GUID classGuid = new GUID();
IntPtr deviceInfoSet = SetupDiCreateDeviceInfoList(classGuid, IntPtr.Zero);

我得到一个错误:

SetupDiCreateDeviceInfoList' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.

但是在 64 位运行时上面的代码可以工作。为什么???

当然,如果我改为通过引用传递结构,该函数在 32 位和 64 位运行时都能正常工作:

[DllImport("Setupapi.dll")]
public static extern IntPtr SetupDiCreateDeviceInfoList(ref GUID ClassGuid, IntPtr hwndParent);

GUID classGuid = new GUID();
IntPtr deviceInfoSet = SetupDiCreateDeviceInfoList(ref classGuid, IntPtr.Zero);

最佳答案

x64 调用约定与 x86 约定非常不同。您将在 this MSDN page 中找到概述.重要的部分是:

Any argument that doesn’t fit in 8 bytes, or is not 1, 2, 4, or 8 bytes, must be passed by reference.

x64 编译器在必要时强制执行此要求,创建结构的副本并在程序按值传递此类结构时传递指向它的指针。在这种情况下,pinvoke 编码器会处理它。所以,没有堆栈不平衡。

关于c# - 在 32 位和 64 位运行时编码(marshal)结构时的不同行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31459262/

相关文章:

winapi - explorer.exe重启后如何恢复 "missing"通知图标?

c++ - 从 OpenGL 切换到 GDI

database - 如何存储信息?数据库、数据结构、日志文件

c# - 从 DynamicObject 中删除事件

c# - DataGridView 如何使 WrapMode = true (多行单元格)并正确自动调整宽度?

winapi - 在 D 程序中使用 Win32 API 未定义 PostMessage?

python - 在python中重新排列嵌套字典的级别

algorithm - 在 2 个 AVL 节点之间搜索最大值

c# - Visual Studio 在哪里寻找程序集?

c# - 复制 xml 文件并在特定位置插入新元素 - C#