gpt4 book ai didi

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

转载 作者:太空宇宙 更新时间:2023-11-03 19:03:56 25 4
gpt4 key购买 nike

我在 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/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com