C# 在32位运行时封送结构与在64位运行时封送结构时的行为不同
我是在品吐的时候发现的C# 在32位运行时封送结构与在64位运行时封送结构时的行为不同,c#,winapi,data-structures,pinvoke,marshalling,C#,Winapi,Data Structures,Pinvoke,Marshalling,我是在品吐的时候发现的 C++函数签名为: HDEVINFO SetupDiCreateDeviceInfoList( _In_opt_ const GUID *ClassGuid, _In_opt_ HWND hwndParent ); 在C#中,我定义了GUID结构,如下所示: [StructLayout(LayoutKind.Sequential)] public struct GUID { public uint Data1; public ush
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);
功能如下:
[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);
我得到一个错误:
SetupDiCreateDeviceInfo列表“”已使堆栈不平衡。这是可能的
因为托管PInvoke签名与非托管PInvoke签名不匹配
目标签名。检查的调用约定和参数是否正确
PInvoke签名与目标非托管签名匹配
但是在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约定非常不同。您将在中找到概述。重要部分是: 任何不适合8字节或不是1、2、4或8字节的参数都必须通过引用传递
x64编译器在必要时强制执行此要求,创建结构的副本,并在程序按值传递此结构时传递指向它的指针。在这种情况下,品沃克马歇尔负责处理。因此,没有堆栈不平衡。@PeterDuniho在x64上,我收到一个指向设备信息集的有效指针。我在64位环境下开发了这个,每次都成功安装了驱动程序。当我决定在32位环境中测试时,我才发现了错误的函数签名。