6

EDIDブロックから派生した情報(モニターモデル、ID、S / Nなど)を対応するモニターのダイアログに表示するアプリケーションを開発しています。

このコードは、ディスプレイのEDID情報を見つけるために機能します。HKLM \ SYSTEM \ CurrentControlSet \ Enum \ DISPLAY \ [Monitor] \ [PnPID] \ Device Parameters\EDIDの下にあるDISPLAYキーを列挙してEDID情報を抽出します。

更新:上記のコードは、レジストリのPnP使用の「副作用」に依存しています。現在、SetupAPIを使用してモニターを列挙しています。これは、接続/削除されているモニターを正しく処理します(上記のリンクのコードとは異なります)。

Windows.Forms.Screen.AllScreens [](\\。\ DISPLAY1、\\。\ DISPLAY2など)の各画面を、上記のレジストリ検査から返されたエントリと関連付けようとしています。

注:以下のコードブロックでは、DisplayDetails.GetMonitorDetails()が、SetupAPIを使用してより堅牢なレジストリ列挙コードに置き換えられましたが、返されるデータは同じです。

例えば

private void Form1_Load(object sender, EventArgs e)
{
    Console.WriteLine("Polling displays on {0}:", System.Environment.MachineName);
    int i = 0;
    foreach ( DisplayDetails dd in DisplayDetails.GetMonitorDetails())
    {
        Console.WriteLine( "Info: Model: {0}, MonitorID: {1}, PnPID: {2}, Serial#:{3}", dd.Model, dd.MonitorID, dd.PnPID, dd.SerialNumber );
        Console.WriteLine( "Does this correlate to Screen: {0}?", Screen.AllScreens[i++].DeviceName );
    }
}

出力:

情報:モデル:DELL P2411H、MonitorID:DELA06E、PnPID:5&2e2fefea&0&UID1078018、Serial#:F8NDP0C ... PU

これは画面:\\。\ DISPLAY1と相関関係がありますか?

情報:モデル:DELL P2411H、MonitorID:DELA06E、PnPID:5&2e2fefea&0&UID1078019、Serial#:F8NDP0C ... AU

これは画面:\\。\ DISPLAY2と相関関係がありますか?


回答:いいえ

テストでは、これらが確実に相関していないことがわかりました(最初に列挙されるディスプレイが\\。\ DISPLAY2であるシステムがあります)。

私の質問: 特定のForms.ScreenのEDID情報を確実に取得する方法はありますか? EDIDブロックを取得できますが、これをUIトップレベルフォームに関連付けるパスが見つかりません。私のユースケースでは、2つ(またはそれ以上)のモニターが同じモデルと解像度であり、S / Nが数桁異なるだけなので、ユーザーにプロンプ​​トを表示することは望ましくありません。

Forms.Screen API、Win32 EnumDisplay、その他のレジストリGUID(PnPおよびドライバー関連)に続くパスを探しましたが、有望なパスは見つかりませんでした。

WMI Win32_DesktopMonitor API(Windows 7)も調査しましたが、Windows.Forms.Screen.AllScreens[]エントリとの関連付けに役立つ情報がこれ以上ないようです。

これを行う方法があるかどうかは疑わしいです。それはSetupAPIを介して行われますが、まだ見つけていません。

4

1 に答える 1

7

GDIをSetupAPIに解決する方法は、EnumDisplayDevicesAPIで利用できますdwFlagsにEDD_GET_DEVICE_INTERFACE_NAMEを渡すと、モニターの列挙は次の形式のDeviceID情報を返します。

Monitor 0 info:
DeviceName: \\.\DISPLAY1
MonitorInfo: Dell P2411H(Digital)
DeviceID: \\?\DISPLAY#DELA06E#5&2e2fefea&0&UID1078018#{e6f07b5f-ee97-4a90-b076-3
3f57bf4eaa7}
Monitor 1 info:
DeviceName: \\.\DISPLAY2
MonitorInfo: Dell P2411H(Digital)
DeviceID: \\?\DISPLAY#DELA06E#5&2e2fefea&0&UID1078019#{e6f07b5f-ee97-4a90-b076-3
3f57bf4eaa7}

以下のC#フラグメントで取得されているように、DeviceIDフィールドはdidd.DevicePathの結果と一致するようになりました。

    Guid MonitorGUID = new Guid(Win32.GUID_DEVINTERFACE_MONITOR);

    // We start at the "root" of the device tree and look for all
    // devices that match the interface GUID of a monitor
    IntPtr h = Win32.SetupDiGetClassDevs(ref MonitorGUID, IntPtr.Zero, IntPtr.Zero, (uint)(Win32.DIGCF_PRESENT | Win32.DIGCF_DEVICEINTERFACE));
    if (h.ToInt64() != Win32.INVALID_HANDLE_VALUE)
    {
        bool Success = true;
        uint i = 0;
        while (Success)
        {
            // create a Device Interface Data structure
            Win32.SP_DEVICE_INTERFACE_DATA dia = new Win32.SP_DEVICE_INTERFACE_DATA();
            dia.cbSize = (uint)Marshal.SizeOf(dia);

            // start the enumeration 
            Success = Win32.SetupDiEnumDeviceInterfaces(h, IntPtr.Zero, ref MonitorGUID, i, ref dia);
            if (Success)
            {
                // build a DevInfo Data structure
                Win32.SP_DEVINFO_DATA da = new Win32.SP_DEVINFO_DATA();
                da.cbSize = (uint)Marshal.SizeOf(da);

                // build a Device Interface Detail Data structure
                Win32.SP_DEVICE_INTERFACE_DETAIL_DATA didd = new Win32.SP_DEVICE_INTERFACE_DETAIL_DATA();
                didd.cbSize = (uint)(4 + Marshal.SystemDefaultCharSize); // trust me :)

                // now we can get some more detailed information
                uint nRequiredSize = 0;
                uint nBytes = Win32.BUFFER_SIZE;
                if (Win32.SetupDiGetDeviceInterfaceDetail(h, ref dia, ref didd, nBytes, out nRequiredSize, ref da))
                {
                    // Now we get the InstanceID
                    IntPtr ptrInstanceBuf = Marshal.AllocHGlobal((int)nBytes);
                    Win32.CM_Get_Device_ID(da.DevInst, ptrInstanceBuf, (int)nBytes, 0);
                    string InstanceID = Marshal.PtrToStringAuto(ptrInstanceBuf);
                    Console.WriteLine("InstanceID: {0}", InstanceID );
                    Marshal.FreeHGlobal(ptrInstanceBuf);
                   
                    Console.WriteLine("DevicePath: {0}", didd.DevicePath );
                }
                i++;
            }
        }
    }
    Win32.SetupDiDestroyDeviceInfoList(h);
}

サンプル出力:

InstanceID: DISPLAY\DELA06E\5&2E2FEFEA&0&UID1078018
DevicePath: \\?\display#dela06e#5&2e2fefea&0&uid1078018#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}

元のEnumDisplayDevicesのDeviceNameは、Forms.Screen.DeviceNameプロパティと一致します。

これらの2つの情報により、次のようなフラグメントを使用して、 SetupDIEnumDeviceInterfaceトラバーサル中にEDIDブロックを読み取ることができるようになりました。

private static byte[] GetMonitorEDID(IntPtr pDevInfoSet, SP_DEVINFO_DATA deviceInfoData)
{
    IntPtr hDeviceRegistryKey = SetupDiOpenDevRegKey(pDevInfoSet, ref deviceInfoData,
        DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE);
    if (hDeviceRegistryKey == IntPtr.Zero)
    {
        throw new Exception("Failed to open a registry key for device-specific configuration information");
    }

    IntPtr ptrBuff = Marshal.AllocHGlobal((int)256);
    try
    {
        RegistryValueKind lpRegKeyType = RegistryValueKind.Binary;
        int length = 256;
        uint result = RegQueryValueEx(hDeviceRegistryKey, "EDID", 0, ref lpRegKeyType, ptrBuff, ref length);
        if (result != 0)
        {
            throw new Exception("Can not read registry value EDID for device " + deviceInfoData.ClassGuid);
        }
    }
    finally
    {
        RegCloseKey(hDeviceRegistryKey);
    }
    byte[] edidBlock = new byte[256];
    Marshal.Copy(ptrBuff, edidBlock, 0, 256);
    Marshal.FreeHGlobal(ptrBuff);
    return edidBlock;
}

最後に、このコードのDisplayDetails.GetMonitorDetails()メソッドに示されているように、VESA記述子ブロックに対して解析できます。

于 2012-04-24T18:11:30.780 に答える