使用Setup Api枚举监视器pnp device ids

时间:2017-07-27 20:36:01

标签: c# pinvoke setupapi

对于我的程序,我需要获取有关当前显示的详细信息。在我的研究中,我遇到了this帖子,讨论了如何链接System.Windows.Forms.Screen类及其EDID信息。起初我尝试复制并粘贴使用p / invoke找到的代码来提供所有必需的本机方法和结构,但它不起作用,只给了我一串?对于InstanceID。所以相反,我尝试使用MSDN资源,并再次p / invoke自己创建代码。这就是我想出的:

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}

我的问题是以什么问题导致InstanceID无法正确输出。

1 个答案:

答案 0 :(得分:0)

原来我使用了错误的p / invoke签名。 CM_Get_Device_ID应如下所示:

{"result":{"messages":[{"id":"15d862a00074a324","threadId":"15d862a00074a324"},{"id":"15d8628752224d1b","threadId":"15d8628752224d1b"},{"id":"15d8231cfbca0608","threadId":"15d8231cfbca0608"},{"id":"15d812cb47b30f24","threadId":"15d812cb47b30f24"},{"id":"15d5e26548a7fe5b","threadId":"15d5e26548a7fe5b"}],"resultSizeEstimate":5},"body":"{\n \"messages\": [\n  {\n   \"id\": \"15d862a00074a324\",\n   \"threadId\": \"15d862a00074a324\"\n  },\n  {\n   \"id\": \"15d8628752224d1b\",\n   \"threadId\": \"15d8628752224d1b\"\n  },\n  {\n   \"id\": \"15d8231cfbca0608\",\n   \"threadId\": \"15d8231cfbca0608\"\n  },\n  {\n   \"id\": \"15d812cb47b30f24\",\n   \"threadId\": \"15d812cb47b30f24\"\n  },\n  {\n   \"id\": \"15d5e26548a7fe5b\",\n   \"threadId\": \"15d5e26548a7fe5b\"\n  }\n ],\n \"resultSizeEstimate\": 5\n}\n"}

还更新了使用代码:

resultSizeEstimate