C#上64位架构的SetupDiEnumDeviceInterfaces

时间:2014-11-10 19:16:20

标签: c# winapi 32bit-64bit

我尝试在64位架构上从C#调用Window API函数 SetupDiEnumDeviceInterfaces 。 我导入函数并声明其他结构。

    [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
    internal static extern bool SetupDiEnumDeviceInterfaces(
        IntPtr deviceInfoSet,
        SP_DEVINFO_DATA deviceInfoData,
        ref Guid interfaceClassGuid,
        int memberIndex,
        SP_DEVICE_INTERFACE_DATA deviceInterfaceData);

    [StructLayout(LayoutKind.Sequential)]
    internal class SP_DEVINFO_DATA
    {
        internal int cbSize = Marshal.SizeOf(typeof(SP_DEVINFO_DATA));
        internal Guid classGuid = Guid.Empty; // temp
        internal int devInst = 0; // dumy
        internal int reserved = 0;
    }

    [StructLayout(LayoutKind.Sequential, Pack = 2)]
    internal struct SP_DEVICE_INTERFACE_DETAIL_DATA
    {
        internal int cbSize;
        internal short devicePath;
    }

然后我按如下方式调用此函数:

        int index = 0;
        Guid _classGuid = Guid.Empty;
        IntPtr _deviceInfoSet = IntPtr.Zero;

        Native.SP_DEVICE_INTERFACE_DATA interfaceData = new Native.SP_DEVICE_INTERFACE_DATA();

        if (!Native.SetupDiEnumDeviceInterfaces(_deviceInfoSet, null, ref _classGuid, index, interfaceData))
       {
             int error = Marshal.GetLastWin32Error();
             if (error != Native.ERROR_NO_MORE_ITEMS)
                 throw new Win32Exception(error);
             break;
         }

如果在 32bits 架构上运行,那么一切都很顺利。

如果在 64bits 架构上运行,则 SetupDiEnumDeviceInterfaces 将返回false,最后一次获胜错误等于1784。 原因是在struct interfaceData 字段中 cbSize对于64位体系结构没有有效值(作为int别名Int32)。

来自官方文件

  

DeviceInterfaceData [out]指向调用者分配的缓冲区的指针   成功返回时,包含已完成的SP_DEVICE_INTERFACE_DATA   标识符合搜索的接口的结构   参数。调用者必须将DeviceInterfaceData.cbSize设置为   调用此函数之前的sizeof(SP_DEVICE_INTERFACE_DATA)。

尝试替换Int64类型的int(别名Int32)类型为:cbSize,devInt,reserved。

如何为64位架构替换类Guid?

如果我尝试使用long类型替换Gu​​id:

[StructLayout(LayoutKind.Sequential)]
    internal class SP_DEVICE_INTERFACE_DATA 
    {
        internal Int64 cbSize = Marshal.SizeOf(typeof(SP_DEVICE_INTERFACE_DATA));
        internal long  interfaceClassGuid = 0; // temp
        internal Int64 flags = 1;
        internal Int64 reserved = 0;
    }

这样的结构定义一切正常但我失去了使用guid特殊类的便利性。在类定义中,Guid也使用了int类型,因此不会在64位架构上计算正确的大小。

3 个答案:

答案 0 :(得分:0)

问题不在于您的GUID声明; SetupDiEnumDeviceInterfaces在64位平台上失败的原因是您没有在reservedSP_DEVINFO_DATA的每个SP_DEVICE_INTERFACE_DATA字段上使用正确的数据类型。< / p>

SP_DEVINFO_DATASP_DEVICE_INTERFACE_DATA的结构定义表明reserved字段声明为UINT_PTR,这是一种指针类型。这些应在P / Invoke类型中声明为IntPtr

(此外,您的所有int字段都应定义为uint,因为这些字段会映射到DWORD原生类型。)

[StructLayout(LayoutKind.Sequential)]
internal class SP_DEVINFO_DATA
{
    internal uint cbSize = (uint)Marshal.SizeOf(typeof(SP_DEVINFO_DATA));
    internal Guid classGuid;
    internal uint devInst;
    internal IntPtr reserved;
}

[StructLayout(LayoutKind.Sequential, Pack = 2)]
internal struct SP_DEVICE_INTERFACE_DETAIL_DATA
{
    internal uint cbSize;
    internal short devicePath;
}

[StructLayout(LayoutKind.Sequential)]
internal class SP_DEVICE_INTERFACE_DATA 
{
    internal uint cbSize = (uint)Marshal.SizeOf(typeof(SP_DEVICE_INTERFACE_DATA));
    internal Guid interfaceClassGuid;
    internal uint flags;
    internal IntPtr reserved;
}

答案 1 :(得分:0)

您可以尝试设置

[StructLayout(LayoutKind.Sequential, Pack = 2)]
internal struct SP_DEVICE_INTERFACE_DETAIL_DATA

为:

[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct SP_DEVICE_INTERFACE_DETAIL_DATA

根据我的阅读,Pack = 8表示32位,Pack = 1表示64位。

答案 2 :(得分:0)

  

您需要在保留字段中的所有字段(不是 int )和 IntPtr 中使用 uint

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct SP_DEVINFO_DATA
{
    public uint cbSize;
    public Guid ClassGuid;
    public uint DevInst;
    public IntPtr Reserved;
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct SP_DEVICE_INTERFACE_DATA
{
    public uint cbSize;
    public Guid InterfaceClassGuid;
    public uint Flags;
    public IntPtr Reserved;
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct SP_DEVICE_INTERFACE_DETAIL_DATA
{
    public uint cbSize;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
    public string DevicePath;
}
  

要在代码中设置 cbSize ,请使用:

Win32.SP_DEVICE_INTERFACE_DATA did = new Win32.SP_DEVICE_INTERFACE_DATA();
did.cbSize = (uint)Marshal.SizeOf(did);

Win32.SP_DEVICE_INTERFACE_DETAIL_DATA didd = new Win32.SP_DEVICE_INTERFACE_DETAIL_DATA();
didd.cbSize = (uint)Marshal.SizeOf(didd);