How to loop over monitors and get their coordinates on Windows in C++?¶
The previous three blogs (Capturing the screen on Windows in C++ using OpenCV & Capturing the screen on Windows in C++ using GDI+ and Comparing screen capturing using GDI+ and OpenCV on Windows in C++) described capturing a screenshot of only one monitor. However, nowadays we often use multiple monitors and capturing the content of all of them or a specific one, two or more. Therefore, we will need to retrieve the coordinates of the targeted monitors. This blog will provide a short explanation and a C++ implementation for how to loop the existing monitors in a multiple monitors setup, get their dimensions and coordinates which can be used later into capturing the monitors content.
Approach and implementation¶
The trick for looping the screens dimensions is to use the function EnumDisplayMonitors(NULL, NULL, MyInfoEnumProc, 0)
, which is available as part of the Win32 API.
A nice approach to this, is to pack the enumeration code in a structure that can be looped to retrieve the information related to each monitor.
This can be done as in the following:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | #include <windows.h>
#include <vector>
#include <iostream>
// Structure that includes all screen hanldes and rectangles
struct cMonitorsVec
{
std::vector<int> iMonitors;
std::vector<HMONITOR> hMonitors;
std::vector<HDC> hdcMonitors;
std::vector<RECT> rcMonitors;
static BOOL CALLBACK MonitorEnum(HMONITOR hMon, HDC hdc, LPRECT lprcMonitor, LPARAM pData)
{
cMonitorsVec* pThis = reinterpret_cast<cMonitorsVec*>(pData);
pThis->hMonitors.push_back(hMon);
pThis->hdcMonitors.push_back(hdc);
pThis->rcMonitors.push_back(*lprcMonitor);
pThis->iMonitors.push_back(pThis->hdcMonitors.size());
return TRUE;
}
cMonitorsVec()
{
EnumDisplayMonitors(0, 0, MonitorEnum, (LPARAM)this);
}
};
int main()
{
cMonitorsVec Monitors;
for (int monitorIndex=0; monitorIndex < Monitors.iMonitors.size(); monitorIndex++)
{
std::wcout << "Screen id: " << monitorIndex << std::endl;
std::wcout << "-----------------------------------------------------" << std::endl;
std::wcout << " - screen left-top corner coordinates : (" << Monitors.rcMonitors[monitorIndex].left
<< "," << Monitors.rcMonitors[monitorIndex].top
<< ")" << std::endl;
std::wcout << " - screen dimensions (width x height) : (" << std::abs(Monitors.rcMonitors[monitorIndex].right - Monitors.rcMonitors[monitorIndex].left)
<< "," << std::abs(Monitors.rcMonitors[monitorIndex].top - Monitors.rcMonitors[monitorIndex].bottom)
<< ")" << std::endl;
std::wcout << "-----------------------------------------------------" << std::endl;
}
}
|
The previous code can be also found under here.
Conclusion¶
This post introduced a small example of how to retrieve the coordinates and dimensions of the connected monitors using C++ on Windows in the case of a multi-monitors setup. The retrieved coordinates can then be used in capturing the screens content using the snippets from the previous blogs (Capturing the screen on Windows in C++ using OpenCV & Capturing the screen on Windows in C++ using GDI+)
References and Further readings¶
- 1
EnumDisplayMonitors function (winuser.h), Microsoft, https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-enumdisplaymonitors
- 2
Enumeration and Display Control, Microsoft, https://docs.microsoft.com/en-us/windows/win32/gdi/enumeration-and-display-control
- 3
Multi-monitor Screenshots only 2 monitors in C++ with WinApi, Stackoverflow, https://stackoverflow.com/questions/37132196/multi-monitor-screenshots-only-2-monitors-in-c-with-winapi