我正在调用SetupDiGetDeviceInterfaceDetail()here,并且SP_DEVICE_INTERFACE_DETAIL_DATA结构未正确编组。可以找到结构定义here。我已经尝试过使用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;
}
正如我所提到的,我已经尝试定义PInvoke.net为SP_DEVICE_INTERFACE_DETAIL_DATA(见上面的链接)概述的结构,并制作了一个新的PInvoke方法签名来处理它。当从64位系统运行时,我得到相同的问题,即函数返回1784.原因似乎是C#中的引用,当在64位运行时运行时,是8字节对齐的(在另一个中找到) StackOverflow文章)。我尝试了各种布局到试图强制布局(使用显式和字段偏移)到4字节对齐的结构,但这对我也不起作用。我有编译时间问题。
我尝试过对PInvoke方法sigature参数使用各种装饰。比如,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,否则为TCHAR。 DWORD始终是32位数量(4个字节),Unicode的单个TCHAR是2个字节。所以,4 + 2 = 6.为什么是8?这是因为该结构的字节对齐是否为64位?我真的很想理解这一点。
无论如何,将cbSize成员设置为8表示64位,6表示32位工作,我可以使用上面定义的结构而不是原始内存分配/解除分配和编组。
答案 0 :(得分:0)
我也遇到了这个问题,因为我从这个答案中复制了代码:https://stackoverflow.com/a/2937588/1070906 在结构定义中有错误。 也许你犯了同样的错误。
在http://msdn.microsoft.com/en-us/library/windows/hardware/ff552344(v=vs.85).aspx查看SP_DEVINFO_DATA的定义,它的最后一个参数是指针,而不是另一篇文章中的uint。
因为我将结构定义更改为:
[StructLayout(LayoutKind.Sequential)]
private struct SP_DEVINFO_DATA
{
/// <summary>Size of the structure, in bytes.</summary>
public uint cbSize;
/// <summary>GUID of the device interface class.</summary>
public Guid ClassGuid;
/// <summary>Handle to this device instance.</summary>
public uint DevInst;
/// <summary>Reserved; do not use.</summary>
public IntPtr Reserved;
}
它有效!
Marshall.SizeOf(new SP_DEVINFO_DATA())现在返回32而不是28,并显示我的串口。