简体   繁体   English

C#上64位体系结构上的SetupDiEnumDeviceInterfaces

[英]SetupDiEnumDeviceInterfaces on 64bit architecture on C#

I try to call Window API function SetupDiEnumDeviceInterfaces from C# on 64bits architecture. 我尝试在64位体系结构上从C#调用Window API函数SetupDiEnumDeviceInterfaces I import function and declare additional structures. 我导入函数并声明其他结构。

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

Then I call this function as follows: 然后我按如下方式调用此函数:

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

If runnig on 32bits architecture then all is well. 如果在32位架构上运行,那么一切都很好。

If runnig on 64bits architecture then SetupDiEnumDeviceInterfaces return false with last win error equal 1784. The reason is that in struct interfaceData field cbSize has not valid value for 64bits architecture(as int alias Int32). 如果在64位体系结构上运行runnig,SetupDiEnumDeviceInterfaces返回false,最后一次取胜错误等于1784。原因是在struct interfaceData字段中, cbSize对于64位体系结构没有有效值 (如int别名Int32)。

From official documentation 从官方文件

DeviceInterfaceData [out] A pointer to a caller-allocated buffer that contains, on successful return, a completed SP_DEVICE_INTERFACE_DATA structure that identifies an interface that meets the search parameters. DeviceInterfaceData [out]指向分配给调用方的缓冲区的指针,该缓冲区包含成功返回时已完成的SP_DEVICE_INTERFACE_DATA结构,该结构标识满足搜索参数的接口。 The caller must set DeviceInterfaceData.cbSize to sizeof(SP_DEVICE_INTERFACE_DATA) before calling this function. 调用此函数之前,调用者必须将DeviceInterfaceData.cbSize设置为sizeof(SP_DEVICE_INTERFACE_DATA)。

Trying to replace the type int(alias Int32) of the type Int64 for fields: cbSize, devInt, reserved. 尝试将以下字段的类型替换为Int64类型的int(别名Int32):cbSize,devInt,保留。

How Can I replace class Guid for 64bits architecture? 如何替换64位体系结构的Guid类?

If I try replace Guid simply of the type long: 如果我尝试简单地替换long类型的Guid:

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

With such a structure definition all works but I lose the convenience of working with a special class for guid. 有了这样的结构定义,所有的作品都可以使用,但是我失去了为guid使用特殊类的便利。 In the class definition Guid also used the type int so the right size will not be calculated on 64bits architecture. Guid在类定义中还使用了int类型,因此在64位体系结构上不会计算出正确的大小。

The problem is not your GUID declarations; 问题不在于您的GUID声明。 the reason SetupDiEnumDeviceInterfaces is failing out on 64-bit platforms is that you're not using the correct data type for the reserved field on each of SP_DEVINFO_DATA and SP_DEVICE_INTERFACE_DATA . SetupDiEnumDeviceInterfaces在64位平台上出现故障的原因是,您没有为SP_DEVINFO_DATASP_DEVICE_INTERFACE_DATAreserved字段使用正确的数据类型。

The structure definitions for SP_DEVINFO_DATA and SP_DEVICE_INTERFACE_DATA show that the reserved fields are declared as UINT_PTR , which is a pointer type. SP_DEVINFO_DATASP_DEVICE_INTERFACE_DATA的结构定义表明, reserved字段被声明为UINT_PTR ,这是一种指针类型。 These should be declared in your P/Invoke types as IntPtr . 这些应该在您的P / Invoke类型中声明为IntPtr

(Also, all of your int fields should instead be defined as uint , as those fields map to the DWORD native type.) (此外,应该将所有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;
}

You might try setting your 您可以尝试设置

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

to: 至:

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

From what I've read, Pack = 8 for 32 bit, Pack = 1 for 64 bit. 根据我的阅读,Pack = 8 for 32 bit,Pack = 1 for 64 bit。

You need to use uint in all fields(not int ), and IntPtr in Reserved field. 您需要在所有字段(不是int )中使用uint ,在保留字段中使用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;
}

To set cbSize in code use this: 要在代码中设置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);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM