使用 SetupDiGetDriverInfoDetail 进行 PInvoke
我正在尝试从 C# 应用程序调用 SetupDiGetDriverInfoDetail。调用失败,我返回的 win32 错误是 0x6F8(“提供的用户缓冲区对于请求的操作无效。”)。到目前为止,我已经能够成功调用其他 setupdi 函数,因此我认为问题在于我封送函数或 SP_DRVINFO_DETAIL_DATA 结构的方式。
我不确定,但我认为问题可能出在 SP_DRVINFO_DETAIL_DATA 结构的 HardwareID 成员上。我尝试将 HardwareID 指定为不同类型(例如,字节数组并在设置大小和调用函数之前分配缓冲区),但总是出现相同的错误。如果有人对此通话有任何经验或有任何指示,我将不胜感激。
下面是我的结构定义、函数导入和代码片段。在此版本中,我使用固定大小的 HardwareID 缓冲区。我还尝试将缓冲区大小指定为 1,期望出现“缓冲区太小”错误,但总是收到“无效缓冲区”错误。
[DllImport("setupapi.dll", SetLastError = true)]
internal static extern Int32 SetupDiGetDriverInfoDetail(
IntPtr DeviceInfoSet,
SP_DEVINFO_DATA DeviceInfoData,
SP_DRVINFO_DATA DriverInfoData,
ref SP_DRVINFO_DETAIL_DATA DriverInfoDetailData,
Int32 DriverInfoDetailDataSize,
ref Int32 RequiredSize);
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct SP_DRVINFO_DETAIL_DATA
{
public Int32 cbSize;
public System.Runtime.InteropServices.ComTypes.FILETIME InfDate;
public Int32 CompatIDsOffset;
public Int32 CompatIDsLength;
public IntPtr Reserved;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public String SectionName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public String InfFileName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public String DrvDescription;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public String HardwareID;
};
SetupApiWrapper.SP_DRVINFO_DETAIL_DATA DriverInfoDetailData = new SetupApiWrapper.SP_DRVINFO_DETAIL_DATA();
DriverInfoDetailData.cbSize = Marshal.SizeOf(DriverInfoDetailData);
result = SetupApiWrapper.SetupDiGetDriverInfoDetail(
DevInfo,
DeviceInfoData,
DriverInfoData,
ref DriverInfoDetailData,
DriverInfoDetailData.cbSize,
ref reqSize);
I'm trying to call SetupDiGetDriverInfoDetail from a C# application. The call fails and the win32 error I get back is 0x6F8 ("The supplied user buffer is not valid for the requested operation."). Up to this point I have been able to call other setupdi functions with success so I think the problem is with the way that I marshal either the function or SP_DRVINFO_DETAIL_DATA struct.
I'm not sure, but I think the problem may be with the HardwareID member of the SP_DRVINFO_DETAIL_DATA struct. I've tried specifying the HardwareID as different types (ex. a byte array and allocating the buffer before setting the size and calling the function), but always the same error. If anyone has any experience with this call or has any pointers, I would appreciate the help.
Below is my structure definition, function import and code snippet. In this version I use a fixed size HardwareID buffer. I've also tried specifying a buffer size of 1 expecting an "buffer too small" error, but I always get the "invalid buffer" error.
[DllImport("setupapi.dll", SetLastError = true)]
internal static extern Int32 SetupDiGetDriverInfoDetail(
IntPtr DeviceInfoSet,
SP_DEVINFO_DATA DeviceInfoData,
SP_DRVINFO_DATA DriverInfoData,
ref SP_DRVINFO_DETAIL_DATA DriverInfoDetailData,
Int32 DriverInfoDetailDataSize,
ref Int32 RequiredSize);
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct SP_DRVINFO_DETAIL_DATA
{
public Int32 cbSize;
public System.Runtime.InteropServices.ComTypes.FILETIME InfDate;
public Int32 CompatIDsOffset;
public Int32 CompatIDsLength;
public IntPtr Reserved;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public String SectionName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public String InfFileName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public String DrvDescription;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public String HardwareID;
};
SetupApiWrapper.SP_DRVINFO_DETAIL_DATA DriverInfoDetailData = new SetupApiWrapper.SP_DRVINFO_DETAIL_DATA();
DriverInfoDetailData.cbSize = Marshal.SizeOf(DriverInfoDetailData);
result = SetupApiWrapper.SetupDiGetDriverInfoDetail(
DevInfo,
DeviceInfoData,
DriverInfoData,
ref DriverInfoDetailData,
DriverInfoDetailData.cbSize,
ref reqSize);
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
o虽然我同意错误代码似乎是意外的,但我认为问题在于 cbSize 应该设置为 sizeof(SP_DRVINFO_DETAIL_DATA) (这是正确的 C sizeof,而不是 p/invoke 结构上的 Marshal.SizeOf。)
使用两个进行快速测试C 行程序给出:
对于两个正确的 sizeof 值(您需要自己计算出需要哪一个...)
相比之下,您的结构的 Marshal.SizeOf(typeof(SP_DRVINFO_DETAIL_DATA)) 给出 1048 作为一个长度。
我认为在继续之前你需要先做好准备。
我怀疑如果DriverInfoDetailDataSize太小可能会返回buffer-too-small错误,但如果cbSize错误则返回invalid-buffer错误。
SetupDiGetDriverInfoDetail 的帮助也明确指出 cbSize 和 DriverInfoDetailDataSize 不应该是相同的值(因为 ANYSIZE_ARRAY 只是定义为 1 作为占位符),因此您不应期望让 Marshal.SizeOf 能够与您故意超大的结构一起正常工作。
附加更正:
您的 InfFilename 成员的长度也是错误的 - 与 SETUPAPI.H 中的结构完全匹配的结构是:
这给出了正确的长度,无论是在 ANSI 还是 UNICODE 版本中。但是,您不想按原样使用此值,因为您需要更长的 HardwareID,因此您必须调整其长度,然后接受 Marshal.SizeOf 为直接插入 cbSize 提供的错误值。
oAlthough I agree that the error code seems unexpected, I think the problem is that cbSize should be set to sizeof(SP_DRVINFO_DETAIL_DATA) (that's the proper C sizeof, not Marshal.SizeOf on your p/invoke structure.)
A quick test with a two line C program gives:
For the two proper sizeof values (you need to work out which one you need yourself...)
In contrast
Marshal.SizeOf(typeof(SP_DRVINFO_DETAIL_DATA))
for your structure gives 1048 as a length.I think you need to get that lined up before you go any further.
I suspect that it might be that the buffer-too-small error is returned if DriverInfoDetailDataSize is too small, but the invalid-buffer error is returned if cbSize is wrong.
The help for SetupDiGetDriverInfoDetail is also explicit that cbSize and DriverInfoDetailDataSize are not supposed to be the same value (because ANYSIZE_ARRAY is just defined as 1 as a placeholder), so you should not expect to get Marshal.SizeOf to work correctly with your deliberately oversized structure.
Additional correction:
Your InfFilename member is also the wrong length - a structure which exactly matches the structure from SETUPAPI.H is:
This gives the correct lengths, both in the ANSI and UNICODE versions. However, you don't want to use this as-is, because you need HardwareID to be longer, so you'll have to adjust the length of that and then live with Marshal.SizeOf giving the wrong value for plugging directly into cbSize.
函数声明错误,第二个和第三个参数是通过ref传递的。解释“无效缓冲区”,API 需要一个指针。小心 Pack,它在 32 位操作系统上只有 1。确保将平台目标设置为 x86。您应该首先测量所需的结构尺寸。做起来很棘手,让 HardwareID 又好又大,不要节俭地扔 16K 给它。
The function declaration is wrong, the 2nd and 3rd arguments are passed by ref. Explains "invalid buffer", the API wants a pointer. Careful with Pack, it is only 1 on 32-bit operating systems. Set the Platform target to x86 to be sure. You are supposed to measure the required structure size first. Tricky to do, make the HardwareID nice and big, don't be frugal and throw 16K at it.