Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/318.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在32位运行时封送结构与在64位运行时封送结构时的行为不同_C#_Winapi_Data Structures_Pinvoke_Marshalling - Fatal编程技术网

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位环境中测试时,我才发现了错误的函数签名。