簡體   English   中英

C#上64位體系結構上的SetupDiEnumDeviceInterfaces

[英]SetupDiEnumDeviceInterfaces on 64bit architecture on C#

我嘗試在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位體系結構上運行runnig,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類?

如果我嘗試簡單地替換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;
    }

有了這樣的結構定義,所有的作品都可以使用,但是我失去了為guid使用特殊類的便利。 Guid在類定義中還使用了int類型,因此在64位體系結構上不會計算出正確的大小。

問題不在於您的GUID聲明。 SetupDiEnumDeviceInterfaces在64位平台上出現故障的原因是,您沒有為SP_DEVINFO_DATASP_DEVICE_INTERFACE_DATAreserved字段使用正確的數據類型。

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

您可以嘗試設置

[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 for 32 bit,Pack = 1 for 64 bit。

您需要在所有字段(不是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;
}

要在代碼中設置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