2017-07-27 38 views
0

對於我的程序,我需要獲取有關當前顯示的詳細信息。在我的研究中,我遇到了關於鏈接System.Windows.Forms.Screen類和它的EDID信息的文章this。起初,我嘗試複製並粘貼使用p/invoke發現的代碼來提供所有必需的本地方法和結構,但它不起作用,只給了我一串?爲InstanceID。因此,我試圖使用MSDN資源,並再次p/invoke自己創建代碼。這是我想出了:使用安裝程序Api來枚舉監視器PNP設備ID

private static void Foo() 
{ 
    Guid DisplayGUID = new Guid(Bar.GUID_DEVINTERFACE_MONITOR); 

    IntPtr DisplaysHandle = Bar.SetupDiGetClassDevs(ref DisplayGUID, null, IntPtr.Zero, (uint)(Win32.DIGCF_PRESENT | Win32.DIGCF_DEVICEINTERFACE)); 

    Bar.SP_DEVICE_INTERFACE_DATA Data = new Bar.SP_DEVICE_INTERFACE_DATA(); 
    Data.cbSize = Marshal.SizeOf(Data); 

    for (uint id = 0; Bar.SetupDiEnumDeviceInterfaces(DisplaysHandle, IntPtr.Zero, ref DisplayGUID, id, ref Data); id++) 
    { 
     Bar.SP_DEVINFO_DATA SPDID = new Bar.SP_DEVINFO_DATA(); 
     SPDID.cbSize = (uint)Marshal.SizeOf(SPDID); 

     Bar.SP_DEVICE_INTERFACE_DETAIL_DATA NDIDD = new Bar.SP_DEVICE_INTERFACE_DETAIL_DATA(); 

     if (IntPtr.Size == 8) //64 bit 
      NDIDD.cbSize = 8; 
     else //32 bit 
      NDIDD.cbSize = 4 + Marshal.SystemDefaultCharSize; 

     uint requiredsize = 0; 
     uint buffer = Bar.BUFFER_SIZE; 

     if (Bar.SetupDiGetDeviceInterfaceDetail(DisplaysHandle, ref Data, ref NDIDD, buffer, ref requiredsize, ref SPDID)) 
     { 
      uint size = 0; 
      Bar.CM_Get_Device_ID_Size(out size, SPDID.DevInst); 

      IntPtr ptrInstanceBuf = Marshal.AllocHGlobal((int)size); 

      Bar.CM_Get_Device_ID(SPDID.DevInst, ref ptrInstanceBuf, size); 

      string InstanceID = Marshal.PtrToStringAuto(ptrInstanceBuf); 

      Console.WriteLine("InstanceID: {0}", InstanceID); 

      Marshal.FreeHGlobal(ptrInstanceBuf); 

      Console.WriteLine("DevicePath: {0}\n", NDIDD.DevicePath); 
     } 
    } 

    Bar.SetupDiDestroyDeviceInfoList(DisplaysHandle); 
} 

private class Bar 
{ 
    [DllImport("setupapi.dll", CharSet = CharSet.Auto)] 
    public static extern IntPtr SetupDiGetClassDevs(ref Guid ClassGuid, [MarshalAs(UnmanagedType.LPTStr)] string Enumerator, IntPtr hwndParent, uint Flags); 

    [DllImport("setupapi.dll", SetLastError = true)] 
    public static extern bool SetupDiDestroyDeviceInfoList(IntPtr DeviceInfoSet); 

    [DllImport(@"setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)] 
    public static extern Boolean SetupDiEnumDeviceInterfaces(IntPtr hDevInfo, IntPtr devInfo, ref Guid interfaceClassGuid, UInt32 memberIndex, ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData); 

    [DllImport(@"setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)] 
    public static extern Boolean SetupDiGetDeviceInterfaceDetail(IntPtr hDevInfo, ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData, ref SP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData, UInt32 deviceInterfaceDetailDataSize, ref UInt32 requiredSize, ref SP_DEVINFO_DATA deviceInfoData); 

    [DllImport("setupapi.dll", SetLastError = true)] 
    public static extern int CM_Get_Device_ID_Size(out uint pulLen, UInt32 dnDevInst, int flags = 0); 

    [DllImport("setupapi.dll", SetLastError = true)] 
    public static extern int CM_Get_Device_ID(uint dnDevInst, ref IntPtr Buffer, uint BufferLen, int ulFlags = 0); 

    public const int BUFFER_SIZE = 168; //guess 

    public const string GUID_DEVINTERFACE_MONITOR = "{E6F07B5F-EE97-4a90-B076-33F57BF4EAA7}"; 

    [Flags] 
    public enum DiGetClassFlags : uint 
    { 
     DIGCF_DEFAULT = 0x00000001, // only valid with DIGCF_DEVICEINTERFACE 
     DIGCF_PRESENT = 0x00000002, 
     DIGCF_ALLCLASSES = 0x00000004, 
     DIGCF_PROFILE = 0x00000008, 
     DIGCF_DEVICEINTERFACE = 0x00000010, 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    public struct SP_DEVICE_INTERFACE_DATA 
    { 
     public Int32 cbSize; 
     public Guid interfaceClassGuid; 
     public Int32 flags; 
     private UIntPtr reserved; 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    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_DETAIL_DATA 
    { 
     public int cbSize; 
     [MarshalAs(UnmanagedType.ByValTStr, SizeConst = BUFFER_SIZE)] 
     public string DevicePath; 
    } 
} 

我的代碼編譯和運行,但它不給我輸出我在找。

,我尋找的輸出是:

InstanceID: DISPLAY\DELA00B\5&786e6ca&0&UID1048832 
DevicePath: \\?\display#dela00b#5&786e6ca&0&uid1048832#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7} 

但是,這是我收到的輸出:

InstanceID: l 
DevicePath: \\?\display#dela00b#5&786e6ca&0&uid1048832#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7} 

我的問題來自於什麼原因造成的實例id的問題形式不能正確輸出。

回答

0

原來我使用了錯誤的p/invoke簽名。 CM_Get_Device_ID應該是這樣的:

[DllImport("setupapi.dll", SetLastError = true)] 
public static extern int CM_Get_Device_ID(uint dnDevInst, StringBuilder Buffer, int BufferLen, int ulFlags = 0); 

還更新了使用碼:

StringBuilder IDBuffer = new StringBuilder((int)buffer); 
Bar.CM_Get_Device_ID(SPDID.DevInst, IDBuffer, (int)buffer); 

Console.WriteLine("InstanceID: {0}", IDBuffer.ToString()); 
Console.WriteLine("DevicePath: {0}\n", NDIDD.DevicePath);