c# - 使用 SetupDiGetDriverInfoDetail 调用 PInvoke

标签 c# 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);

最佳答案

o虽然我同意错误代码似乎出乎意料,但我认为问题在于 cbSize 应该设置为 sizeof(SP_DRVINFO_DETAIL_DATA)(这是正确的 C sizeof,而不是 p/invoke 结构上的 Marshal.SizeOf。)

使用两行 C 程序的快速测试给出:

ANSI 797
UNICODE 1570

对于两个合适的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 中的结构完全匹配的结构是:

    [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet=CharSet.Unicode)]
    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 = 260)]
        public String InfFileName;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
        public String DrvDescription;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1)]
        public String HardwareID;
    };

这给出了正确的长度,无论是在 ANSI 还是 UNICODE 版本中。但是,您不想按原样使用它,因为您需要 HardwareID 更长,所以您必须调整它的长度,然后忍受 Marshal.SizeOf 给出错误的值以直接插入 cbSize。

关于c# - 使用 SetupDiGetDriverInfoDetail 调用 PInvoke,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5120371/

相关文章:

c# - Java枚举支持方法?但不是在 C# 中?

c# - 单客户端 TCP 服务器模型

c# - P/Invoke - 使用 DLLImport 的自定义类型的 C# 签名?

c# - 在多线程应用程序中使用带有媒体基础接口(interface)的 P/Invoke 发生 AccessViolationException

c# - 如何处理执行区域受限的分配?

c# - 在哪里将数据库置于 visual studio 解决方案下以进行构建并单击一次部署?

c# - 在单个解决方案中处理多个项目中的公共(public)类

c# - 有没有办法知道是什么让对象在 C# 中保持事件状态

c# - AudioQueueEnqueueBufferWithParameters 是否在 Monotouch 中实现?

c# - 将 pair<int,float> 的二维数组从 c# 传递到 c dll