[英]Win32: capture handle to Display monitor
我目前正在开发一个应用程序,该应用程序需要为连接到系统的每个屏幕使用HDC
。
我目前正在使用这样的代码:
std::vector<HDC> dcs;
HDC dcMain = ::GetDC(nullptr); // <-- don't understand this
::EnumDisplayMonitors(dcMain, nullptr, MONITORENUMPROC(&DisplayMonitorCallback), LPARAM(&dcs));
我的回调如下:
BOOL DisplayMonitorCallback(const HMONITOR monitor, const HDC hdcMonitor, const LPRECT lprcMonitor, std::vector<HDC>& dcs)
{
dcs.push_back(hdcMonitor);
// here is where it gets weird!
HBRUSH br = CreateSolidBrush(RGB(0, 255, 0));
auto rst = FillRect(hdcMonitor, lprcMonitor, br);
// Process all monitors
return TRUE;
}
请注意,我目前正在每个屏幕上渲染绿色画笔。 这在此上下文中(即在回调中)完美运行。
现在的问题是,我正在捕获这些HDC
以便以后使用。
所以几行之后,我要遍历我的dcs
向量:
for (HDC dc : dcs)
{
HBRUSH br = CreateSolidBrush(RGB(255, 255, 0));
RECT x = { 100, 100, 500, 500 };
auto rst = FillRect(dc, &x, br);
printf("%d", rst);
}
因此,我的问题是:
对于dcMain
,我必须将其传递给我,这是获得一个的好方法吗?
为什么渲染在回调中起作用,但是当我捕获HDC
并在以后对其进行迭代时却不起作用?
是的,这在EnumDisplayMonitors()
文档中有所提及:
要为每个显示监视器最佳地绘制整个虚拟屏幕,可以使用如下代码:
hdc = GetDC(NULL); EnumDisplayMonitors(hdc, NULL, MyPaintScreenEnumProc, 0); ReleaseDC(NULL, hdc);
HDC
仅在回调内部有效,如@andlabs建议。 这是有道理的,因为必须先获取并释放HDC
,但是只有EnumDisplayMonitors()
知道如何获取每个HDC
,因此只有它知道如何正确释放每个HDC
。 由于没有用于释放枚举的HDC
API函数,因此这意味着HDC
在枚举之外无效。
MSDN告诉您如何获取给定监视器的HDC
:
每个物理显示都由
HMONITOR
类型的监视器句柄表示。 有效的HMONITOR
保证为非NULL。 物理显示器具有相同的HMONITOR
,只要它是桌面的一部分即可。 发送WM_DISPLAYCHANGE
消息后,任何监视器都可能会从桌面上删除,因此其HMONITOR
变为无效或已更改其设置。 因此,应用程序应在发送此消息时检查所有HMONITORS
是否有效。任何返回显示设备上下文(DC)的功能通常都会返回主监视器的DC。 若要获取另一台监视器的DC,请使用
EnumDisplayMonitors
函数。 或者,您可以使用GetMonitorInfo
函数中的设备名称通过CreateDC
创建DC 。 但是,如果该函数(例如GetWindowDC
或BeginPaint
)获得了跨越一个以上显示器的窗口的DC,则DC也将跨越两个显示器。
例如:
typedef std::vector<HDC> hdc_vector; BOOL CALLBACK DisplayMonitorCallback(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) { MONITORINFOEX mi = {0}; mi.cbSize = sizeof(mi); if (GetMonitorInfo(hMonitor, &mi)) { HDC dc = CreateDC(NULL, mi.szDevice, NULL, NULL); if (dc) reinterpret_cast<hdc_vector*>(dwData)->push_back(dc); } ... return TRUE; }
hdc_vector dcs; EnumDisplayMonitors(dcMain, nullptr, DisplayMonitorCallback, reinterpret_cast<LPARAM>(&dcs)); ... for (HDC dc : dcs) { ... } ... for (HDC dc : dcs) DeleteDC(dc);
由于您显然使用的是C ++ 11,因此建议您将std::unique_ptr
用于HDC
的内存管理,因此您不必手动调用DeleteDC()
。 我将使用lambda进行回调,并将std::vector
更改为std::map
(以便您可以在需要时查找任何特定监视器的HDC
):
typedef std::unique_ptr<std::remove_pointer<HDC>::type, decltype(::DeleteDC)> device_hdc; typedef std::map<HMONITOR, device_hdc> device_hdc_map; device_hdc_map dcs; EnumDisplayMonitors(dcMain, nullptr, [](HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) -> BOOL { MONITORINFOEX mi = {0}; mi.cbSize = sizeof(mi); if (GetMonitorInfo(hMonitor, &mi)) { HDC dc = CreateDC(NULL, mi.szDevice, NULL, NULL); if (dc) (*reinterpret_cast<device_hdc_map*>(dwData))[hMonitor] = device_hdc(dc, &::DeleteDC); } ... return TRUE; }, reinterpret_cast<LPARAM>(&dcs) ); ... for (device_hdc_map::value_type &dc : dcs) { // use dc.second.get() (the actual HDC) as needed ... }
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.