0

对于我的程序,我需要获取有关当前显示的详细信息。在我的研究中,我遇到了这篇关于链接 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 无法正确输出的问题是什么。

4

1 回答 1

1

原来我使用了错误的 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);
于 2017-07-27T22:49:59.150 回答