9

私の現在の C++ プロジェクトでは、多数のコンピューターで接続されアクティブになっているモニターごとに一意の文字列を検出する必要があります。

研究は2つの選択肢を指摘しています

  1. WMI を使用して、すべてのアクティブなモニターについて Win32_DesktopMonitor を照会します。モニターを一意に識別するために PNPDeviceID を使用します。

  2. EnumDisplayDevices API を使用し、掘り下げてデバイス ID を取得します。

デフォルトのプラグ アンド プレイ ドライバーを使用するモニターは、モニター名として「デフォルトのプラグ アンド プレイ モニター」として一般的な文字列を報告するため、一意のモデル識別にデバイス ID を使用することに関心があります。

WMI メソッドで問題が発生しています。Vista マシンで 1 つのモニターしか返されないようです。doco を見ると、非 WDDM デバイスでは期待どおりに動作しないことがわかりました。

EnumDisplayDevices は、バックグラウンド サービス (特に Vista で) から実行するときに少し問題があるようです。セッション 0 にある場合、情報は返されません。

  • 他の誰かが同様のことをしなければなりませんでしたか (接続されているすべてのアクティブなモニターに対して一意のモデル文字列を見つけますか?)

  • どのアプローチが最も効果的でしたか?

4

5 に答える 5

10

これは、モニターデバイスIDを確実に検出するための現在進行中のコードです。

CString DeviceID;
DISPLAY_DEVICE dd; 
dd.cb = sizeof(dd); 
DWORD dev = 0; 
// device index 
int id = 1; 
// monitor number, as used by Display Properties > Settings

while (EnumDisplayDevices(0, dev, &dd, 0))
{
    DISPLAY_DEVICE ddMon;
    ZeroMemory(&ddMon, sizeof(ddMon));
    ddMon.cb = sizeof(ddMon);
    DWORD devMon = 0;

    while (EnumDisplayDevices(dd.DeviceName, devMon, &ddMon, 0))
    {
        if (ddMon.StateFlags & DISPLAY_DEVICE_ACTIVE && 
                     !(ddMon.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER))
        {
            DeviceID.Format (L"%s", ddMon.DeviceID);
            DeviceID = DeviceID.Mid (8, DeviceID.Find (L"\\", 9) - 8);
        }
        devMon++;

        ZeroMemory(&ddMon, sizeof(ddMon));
        ddMon.cb = sizeof(ddMon);
    }

    ZeroMemory(&dd, sizeof(dd));
    dd.cb = sizeof(dd);
    dev++; 
}
于 2008-10-14T21:13:30.393 に答える
2

Win32_PnPEntity で service="monitor" をクエリすると、すべてのモニターが返されることを発見しました。

私のマシンでの結果:

select * from Win32_PnPEntity where service="monitor"

Availability | Caption               | ClassGuid                              | CompatibleID | ConfigManagerErrorCode | ConfigManagerUserConfig | CreationClassName | Description           | DeviceID                           | ErrorCleared | ErrorDescription | HardwareID  | InstallDate | LastErrorCode | Manufacturer | Name                  | PNPDeviceID                        | PowerManagementCapabilities | PowerManagementSupported | Service | Status | StatusInfo | SystemCreationClassName | SystemName
             | Dell 2007FP (Digital) | {4d36e96e-e325-11ce-bfc1-08002be10318} | array[0..0]  | 0                      | False                   | Win32_PnPEntity   | Dell 2007FP (Digital) | DISPLAY\DELA021\5&4F61016&0&UID257 |              |                  | array[0..0] |             |               | Dell Inc.    | Dell 2007FP (Digital) | DISPLAY\DELA021\5&4F61016&0&UID257 |                             |                          | monitor | OK     |            | Win32_ComputerSystem    | 8HVS05J
             | Dell ST2320L_Digital  | {4d36e96e-e325-11ce-bfc1-08002be10318} | array[0..0]  | 0                      | False                   | Win32_PnPEntity   | Dell ST2320L_Digital  | DISPLAY\DELF023\5&4F61016&0&UID256 |              |                  | array[0..0] |             |               | Dell Inc.    | Dell ST2320L_Digital  | DISPLAY\DELF023\5&4F61016&0&UID256 |                             |                          | monitor | OK     |            | Win32_ComputerSystem    | 8HVS05J
于 2011-09-19T08:47:08.303 に答える
1

現在のビデオ カードの製造元が NVIDIA かどうかを検出するために、EnumDisplayDevices をいじっています。それは同じではありませんが、おそらく役立つでしょう。私たちの作品は次のように見えました:

int disp_num = 0;
    BOOL res = TRUE;
    do {
        DISPLAY_DEVICE disp_dev_info; 
        ZeroMemory( &disp_dev_info, sizeof(DISPLAY_DEVICE) );
        disp_dev_info.cb = sizeof(DISPLAY_DEVICE);
        res = EnumDisplayDevices( 0, disp_num++, &disp_dev_info, 0x00000001 );
        if(res &&
           disp_dev_info.DeviceString[0]!=0 && disp_dev_info.DeviceString[0]=='N' &&
           disp_dev_info.DeviceString[1]!=0 && disp_dev_info.DeviceString[1]=='V' && 
           disp_dev_info.DeviceString[2]!=0 && disp_dev_info.DeviceString[2]=='I' && 
           disp_dev_info.DeviceString[3]!=0 && disp_dev_info.DeviceString[3]=='D' && 
           disp_dev_info.DeviceString[4]!=0 && disp_dev_info.DeviceString[4]=='I' && 
           disp_dev_info.DeviceString[5]!=0 && disp_dev_info.DeviceString[5]=='A'){
            isNVidia = true;
        }
        int x = 0;
    }while( res != FALSE );

かなりばかげていますが、働いています。

于 2008-10-08T16:21:24.817 に答える
1

Win32_DesktopMonitor メソッドは、Vista マシンでも 1 つのモニターのみを返します。ただし、PnP ID は正しく設定されているようです。

私は EnumDisplayDevices API を簡単に試してみましたが、アダプターの詳細を確実に検出しているように見えますが (おそらく、ほとんどの人が「標準 VGA」のままにしておくことはないため)、「プラグ アンド プレイ モニター」しか返されません。接続されたモニター用。

これは、私が数年前に行った調査を反映しています (それらの記憶を取り除くのを助けるためにいくつかのコードをまとめる必要がありました)。

これは、通常のユーザー アカウントからのものです。通常のユーザー セッションであっても、EnumDisplayDevices に PnP ID を返す信頼できる方法がある場合は、興味があります。現在、この情報のいずれかがデバイス ドライバーで利用できるかどうかを調査しています。

セッション #0 からコードを実行しても信頼性が十分でない場合にできることの 1 つは、ユーザーのコンテキストで実行されるヘルパー プロセス (CreateProcessAsUser を使用するか、アクティベーション モニカーを使用して COM を使用する) を生成できるかどうかを確認することです。

于 2008-10-14T15:44:55.953 に答える
0

サービスから実行しようとしたことはありませんが、EnumDisplayDevices通常、ユーザーとして実行するとうまく機能します。サービスは別の (そしてヘッドレスの) セッションで実行されると思います。

ディスプレイにアクセスできるユーザー アカウントになりすまして、サービスからヘルパー プログラムを実行できますか?

于 2008-10-08T15:07:43.360 に答える