我在这里调用 SetupDiGetDeviceInterfaceDetail()并且 SP_DEVICE_INTERFACE_DETAIL_DATA 结构没有正确编组。结构定义可以在这里找到。我尝试使用来自 PInvoke.net 的此结构的定义,here,但无济于事。
至此,当函数调用成功时(即封送器没有抛出错误),返回值为1784(INVALID_USER_BUFFER)。更重要的是,当这段代码从我的机器上的 32 位进程执行时,所有这些都可以正常工作。当它在 64 位进程中运行时,我遇到了这个问题。
我当前的 SetupDiGetInterfaceDetailData() 签名如下所示:
[DllImport(@"c:\Windows\System32\SetupApi.dll", SetLastError = true, CharSet = CharSet.Auto)]
[return : MarshalAs(UnmanagedType.Bool)]
public static extern bool SetupDiGetDeviceInterfaceDetail(
SafeHandleZeroOrMinusOneIsInvalid deviceInfoSet,
ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData,
IntPtr deviceInterfaceDetailData,
uint deviceInterfaceDetailDataSize,
IntPtr requiredSize,
IntPtr deviceInfoData);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct SP_DEVICE_INTERFACE_DETAIL_DATA
{
public UInt32 cbSize;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string DevicePath;
}
目前,我正在使用 Marshal.AllocHGlobal() 分配内存,并使用 Marshal.* 系列函数从该缓冲区写入/读取数据。
作为参考,这就是我正在做的事情:
public string GetPathToDevice(SafeHandleZeroOrMinusOneIsInvalid hDevList,
SP_DEVICE_INTERFACE_DATA devIntfData)
{
uint sizeNeeded = 0;
// get's the size needed
SetupApi.SetupDiGetDeviceInterfaceDetailData(hDevList,
ref devIntfData,
IntPtr.Zero,
0,
ref sizeNeeded,
IntPtr.Zero);
IntPtr pBuffer = Marshal.AllocHGlobal((int)(sizeNeeded + 4)); // +4 for cbSize
SetupApi.SetupDiGetDeviceInterfaceDetailData(hDevList,
ref devIntfData,
pBuffer,
sizeNeeded,
IntPtr.Zero,
IntPtr.Zero);
// copy bytes from unmanaged space in pBuffer to a manged byte array
// free unmanaged memory
return theStringParsedFromByteArray;
}
正如我所提到的,我已经尝试为 SP_DEVICE_INTERFACE_DETAIL_DATA 定义 PInvoke.net 概述的结构(参见上面的链接),并创建了一个新的 PInvoke 方法签名来处理它。从 64 位系统运行时,我遇到了同样的问题,即函数返回 1784。原因似乎是 C# 中的引用在 64 位运行时运行时是 8 字节对齐的(发现在另一个StackOverflow 文章)。我已经尝试了对该结构的各种布局,试图将布局(使用显式和字段偏移)强制为 4 字节对齐的结构,但这对我也不起作用。我有编译时问题。
我尝试对 PInvoke 方法签名参数使用各种装饰。例如,我不断不正确配对的 MarshalAs(UnmanagedType.LPStruct)。我现在到了需要帮助的地步。
我真的不明白为什么会这样。即使在 32 位运行时运行时它确实在我的机器上工作,64 位运行时不会简单地将我连接到正确的 64 位版本的 Setup API 吗?有什么问题?
感谢您的帮助,安迪
问题解决了
好消息是,现在已经解决了,烦人的是我不喜欢在发帖后的一两个小时内解决问题。所以,问题确实是它是一个 64 位的问题。Marshal.GetLastWin32Error() 的错误代码告诉我问题所在。cbSize 值不正确。我将其更改为 8,现在一切正常。
请有人向我解释为什么现在 64 位上的大小是 8?该结构现在在上面(一位评论者要求我将其包括在内)。该结构由两个成员组成,一个 DWORD 和一个 TCHAR[ANYSIZE_ARRAY]。ANYSIZE_ARRAY 的计算结果为 1,如果 Unicode,则 TCHAR 始终为 WCHAR,否则为 char。DWORD 始终是 32 位数量(4 个字节),而 Unicode 的单个 TCHAR 是 2 个字节。所以,4 + 2 = 6。为什么是 8?这是因为 64 位结构的字节对齐吗?我真的很想明白这一点。
无论如何,将 cbSize 成员设置为 8(对于 64 位)和 6(对于 32 位)是可行的,并且我能够使用上面定义的结构而不是原始内存分配/解除分配和封送处理。