EnumDisplayDevices와 WMI Win32_DesktopMonitor, 활성 모니터를 감지하는 방법은 무엇입니까?

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

  •  05-07-2019
  •  | 
  •  

문제

현재 C++ 프로젝트의 경우 많은 수의 컴퓨터에 연결되어 활성화되어 있는 모든 모니터에 대해 고유한 문자열을 검색해야 합니다.

연구에서는 두 가지 옵션을 지적했습니다.

  1. WMI를 사용하고 모든 활성 모니터에 대해 Win32_DesktopMonitor를 쿼리합니다.모니터의 고유 식별을 위해 PNPDeviceID를 사용합니다.

  2. EnumDisplayDevices API를 사용하고 자세히 알아보면 장치 ID를 얻을 수 있습니다.

기본 플러그 앤 플레이 드라이버를 사용하는 모니터는 일반 문자열을 모니터 이름 "기본 플러그 앤 플레이 모니터"로 보고하므로 고유 모델 식별을 위해 장치 ID를 사용하고 싶습니다.

WMI 방법에 문제가 발생했습니다. Vista 시스템에서 모니터 1개만 반환하는 것 같습니다. doco를 살펴보면 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++; 
}

다른 팁

방금 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

현재 비디오 카드 제조업체가 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에서 코드를 실행하는 것이 충분히 신뢰할 수없는 경우, 사용자의 컨텍스트에서 실행되는 헬퍼 프로세스 (CreateProcessAsuser 사용 또는 활성화 모니 커와 COM을 사용할 수 있는지 확인하는 것입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top