【问题标题】:SetupDiEnumDeviceInterfaces on 64bit architecture on C#C# 上 64 位架构上的 SetupDiEnumDeviceInterfaces
【发布时间】:2015-01-07 04:41:51
【问题描述】:

我尝试在 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;
         }

如果在 32 位 架构上运行,那么一切都很好。

如果在 64 位 架构上运行,则 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、保留。

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

如果我尝试将 Guid 替换为 long 类型:

[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 位架构上计算正确的大小。

【问题讨论】:

    标签: c# winapi 32bit-64bit


    【解决方案1】:

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

    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;
    }
    

    【讨论】:

    • 无效。请注意,类型 uint 是别名 UInt32 因此替换 uint 的类型 int 是无用的
    【解决方案2】:

    您可以尝试设置您的

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

    【讨论】:

      【解决方案3】:

      您需要在所有字段中使用uint(不是int),在Reserved字段中使用IntPtr

      [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);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-05-22
        • 2019-06-29
        • 2011-12-18
        • 1970-01-01
        • 2011-03-16
        • 1970-01-01
        • 2014-12-17
        相关资源
        最近更新 更多