假设我有3台显示器。 我如何才能通过索引获得第二个句柄? EnumDisplayMonitors()不能工作,因为它枚举伪设备以及EnumDisplayDevices()不给我处理。
您需要使用EnumDisplayMonitors()
而不是EnumDisplayDevices()
来访问每个监视器的HMONITOR
句柄。
但是,监视器不是按索引来标识的。 GetMonitorInfo()
可以告诉你哪个监视器是“主”,但这是全部。 没有办法知道哪个监视器是“第二”,“第三”等等。而且不能使用监视器位置来确定“第二”监视器可以被定位在与“主”监视器,然后可以将“第三”监视器定位在与“第一”或“第二”监视器相关的任何位置。
所以你必须希望EnumDisplayMonitors()
按照显示器安装顺序枚举,然后你可以这样做:
struct sEnumInfo { int iIndex; HMONITOR hMonitor; }; BOOL CALLBACK GetMonitorByIndex(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) { sEnumInfo *info = (sEnumInfo*) dwData; if (--info->iIndex < 0) { info->hMonitor = hMonitor; return FALSE; } return TRUE; }
sEnumInfo info; info.index = 1; info.hMonitor = NULL; EnumDisplayMonitors(NULL, NULL, GetMonitorByIndex, (LPARAM)&info); if (info->hMonitor != NULL) { //... }
您可以使用EnumDisplayMonitors()
枚举设备,并检查它是否使用EnumDisplayDevices()
伪监视
在使用GetMonitorInfo()
遍历显示监视器时,可以使用监视器设备的名称获取MONITORINFOEX
。
然后使用EnumDisplayDevices()
你可以得到DISPLAY_DEVICE
,其中包含带有信息的StateFlags
,如果当前监视器是一个伪监视器(或者如果连接到桌面)
BOOL DispayEnumeratorProc(_In_ HMONITOR hMonitor, _In_ HDC hdcMonitor, _In_ LPRECT lprcMonitor, _In_ LPARAM dwData) { TClass* self = (TClass*)dwData; if (self == nullptr) return FALSE; MONITORINFOEX monitorInfo; ::ZeroMemory(&monitorInfo, sizeof(monitorInfo)); monitorInfo.cbSize = sizeof(monitorInfo); BOOL res = ::GetMonitorInfo(hMonitor, &monitorInfo); if (res == FALSE) return TRUE; DISPLAY_DEVICE displayDevice; ::ZeroMemory(&displayDevice, sizeof(displayDevice)); displayDevice.cb = sizeof(displayDevice); res = ::EnumDisplayDevices(monitorInfo.szDevice, 0, &displayDevice, 0); if (res == FALSE) return TRUE; if (displayDevice.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) self->RegisterDisplay(monitorInfo); return TRUE; } void TClass::EnumerateDisplayMonitors() { BOOL res = ::EnumDisplayMonitors(NULL, NULL, &DispayEnumeratorProc, (LPARAM)this); if (res == FALSE) Print("Failed"); }
你也可以通过迭代EnumDisplayDevices()
如果将NULL
作为第一个参数传递给EnumDisplayDevices()
,它将根据第二个参数返回适配器的信息。 在这种情况下,您的设备将确定订单。
您可以将DISPLAY_DEVICE
DeviceName
与您之前存储的MONITORINFOEX
中的szDevice
进行比较,以对HMONITORs
进行排序
void TClass::SortDisplayMonitors() { DISPLAY_DEVICE displayDevice; ::ZeroMemory(&displayDevice, sizeof(displayDevice)); displayDevice.cb = sizeof(displayDevice); std::map<std::string, DWORD> devices; for (DWORD iDevNum = 0; ::EnumDisplayDevices(NULL, iDevNum, &displayDevice, 0) != FALSE; ++iDevNum) devices.insert({displayDevice.DeviceName, iDevNum}); auto compare = [&devices](MONITORINFOEX& l, MONITORINFOEX& r) { DWORD il = -1; DWORD ir = -1; auto foundL = devices.lower_bound(l.szDevice); if (foundL != devices.end()) il = foundL->second; auto foundR = devices.lower_bound(r.szDevice); if (foundR != devices.end()) ir = foundR->second; return (il < ir); }; std::sort(m_monitors.begin(), m_monitors.end(), compare); }
PS:你可以写
DWORD il = std :: numeric_limits <DWORD> :: max();
侮辱了
DWORD il = -1;
但是在包含Windows.h之前不要忘记定义NOMINMAX