EnumDisplayDevices와 WMI Win32_DesktopMonitor, 활성 모니터를 감지하는 방법은 무엇입니까?
문제
현재 C++ 프로젝트의 경우 많은 수의 컴퓨터에 연결되어 활성화되어 있는 모든 모니터에 대해 고유한 문자열을 검색해야 합니다.
연구에서는 두 가지 옵션을 지적했습니다.
WMI를 사용하고 모든 활성 모니터에 대해 Win32_DesktopMonitor를 쿼리합니다.모니터의 고유 식별을 위해 PNPDeviceID를 사용합니다.
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을 사용할 수 있는지 확인하는 것입니다.