C# 带SetupDiGetDriverInfoDetail的PInvoke

C# 带SetupDiGetDriverInfoDetail的PInvoke,c#,pinvoke,C#,Pinvoke,我正在尝试从C#应用程序调用SetupDiGetDriverInfo详细信息。调用失败,返回的win32错误为0x6F8(“提供的用户缓冲区对于请求的操作无效”)。到目前为止,我已经能够成功地调用其他setupdi函数,因此我认为问题在于我封送函数或SP_DRVINFO_DETAIL_数据结构的方式 我不确定,但我认为问题可能出在SP_DRVINFO_DETAIL_数据结构的HardwareID成员上。我尝试过将HardwareID指定为不同的类型(例如字节数组和在设置大小和调用函数之前分配缓冲

我正在尝试从C#应用程序调用SetupDiGetDriverInfo详细信息。调用失败,返回的win32错误为0x6F8(“提供的用户缓冲区对于请求的操作无效”)。到目前为止,我已经能够成功地调用其他setupdi函数,因此我认为问题在于我封送函数或SP_DRVINFO_DETAIL_数据结构的方式

我不确定,但我认为问题可能出在SP_DRVINFO_DETAIL_数据结构的HardwareID成员上。我尝试过将HardwareID指定为不同的类型(例如字节数组和在设置大小和调用函数之前分配缓冲区),但总是出现相同的错误。如果有人对此电话有任何经验或有任何建议,我将不胜感激

下面是我的结构定义、函数导入和代码片段。在这个版本中,我使用一个固定大小的硬件缓冲区。我还尝试将缓冲区大小指定为1,期望出现“缓冲区太小”错误,但我总是遇到“无效缓冲区”错误


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

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

ANSI 797
UNICODE 1570
对于两个适当大小的值(您需要自己确定需要哪一个…)

相比之下,
Marshal.SizeOf(typeof(SP_DRVINFO_DETAIL_DATA))
对于您的结构,长度为1048

我想在你继续之前,你需要把它排好

我怀疑如果DriverInfoDetailDataSize太小,可能会返回缓冲区太小错误,但是如果cbSize错误,则会返回无效缓冲区错误

SetupDiGetDriverInfoDetail的帮助也明确指出cbSize和DriverInfoDetailDataSize不应该是相同的值(因为ANYSIZE_数组只是定义为1作为占位符),因此您不应该期望Marshal.SizeOf能够正确处理故意过大的结构

补充更正:

InfFilename成员的长度也不正确-与SETUPAPI中的结构完全匹配的结构是:

    [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。

函数声明错误,第二个和第三个参数由ref传递。解释“无效缓冲区”,API需要一个指针。小心使用Pack,它在32位操作系统上仅为1。将平台目标设置为x86以确保。您应该首先测量所需的结构尺寸。要做到这一点很棘手,要使硬件ID美观大方,不要吝啬,要投入16K。

SetupAPI的结构在32位版本上是1字节压缩,在64位版本上是8字节压缩。这个结构的ANSI版本的标准大小是奇数个字节,这很好地说明了“默认打包”的数量。但是你是对的,另外两个参数应该是ref。32/64位版本的Win32的这种对齐变化是否适用于API的整个表面区域?@David-不,这是相当不寻常的。在SDK include目录中搜索pshpack1和pshpack4以查找异常。
    [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;
    };