[英]get the handle of a (real) monitor by its index
假設我有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.iIndex = 1;
info.hMonitor = NULL;
EnumDisplayMonitors(NULL, NULL, GetMonitorByIndex, (LPARAM)&info);
if (info.hMonitor != NULL)
{
//...
}
您可以排除主監視器,這是示例代碼(樣式可能有所不同):
如果DEVMODE dmPosition x == 0且y == 0,則它是主監視器。
僅對於顯示設備,是POINTL結構,該結構指示相對於桌面區域的顯示設備的位置坐標。 主顯示設備始終位於坐標(0,0)。
選中x,y以定義第二或第三。
LONG second_x=0;
LONG second_y=0;
DWORD deviceNum = 0;
DISPLAY_DEVICE displayDevice;
DEVMODE devMode;
memset(&displayDevice, 0, sizeof(displayDevice));
displayDevice.cb = sizeof(DISPLAY_DEVICE);
while(EnumDisplayDevices(NULL, deviceNum, &displayDevice, 0))
{
EnumDisplaySettings(displayDevice.DeviceName, ENUM_CURRENT_SETTINGS, &devMode);
if (devMode.dmPosition.x == 0 && devMode.dmPosition.y == 0)
{
// primary monitor
}
else
{
// second or third monitor
second_x = devMode.dmPosition.x;
second_y = devMode.dmPosition.y;
}
++deviceNum;
}
m_pMainWnd->SetWindowPos(NULL,(int)second_x,(int)second_y,0,0,SWP_SHOWWINDOW | SWP_NOSIZE);
您可以枚舉與設備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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.