EnumDisplayDevices vs WMI Win32_DesktopMonitor、アクティブなモニターを検出する方法は?

StackOverflow https://stackoverflow.com/questions/181064

  •  05-07-2019
  •  | 
  •  

質問

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

研究では2つのオプションが示されています

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

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

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

WMIメソッドで問題が発生しました。Vistaマシンでモニターを1つだけ返しているようです。ドコを見ると、WDDM以外のデバイスでは期待どおりに動作しません。

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

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

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

役に立ちましたか?

解決

これは、モニターデバイス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++; 
}

他のヒント

service =" monitor"のWin32_PnPEntityを照会すると、すべてのモニターが返されることがわかりました。

私のマシンでの結果:

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

現在のビデオカードメーカーが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 );

かなり愚かですが、動作しています。

サービスから実行しようとしたことはありませんが、 EnumDisplayDevices は一般的にユーザーとして実行した場合にうまく機能します。サービスは別の(およびヘッドレス)セッションで実行されるため、そこで発生している問題を説明できます。

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

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

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

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

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

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

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top