繁体   English   中英

Win32:捕获到显示监视器的句柄

[英]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);
}

因此,我的问题是:

  1. 对于dcMain ,我必须将其传递给我,这是获得一个的好方法吗?

  2. 为什么渲染在回调中起作用,但是当我捕获HDC并在以后对其进行迭代时却不起作用?

  1. 是的,这在EnumDisplayMonitors()文档中有所提及:

    要为每个显示监视器最佳地绘制整个虚拟屏幕,可以使用如下代码:

     hdc = GetDC(NULL); EnumDisplayMonitors(hdc, NULL, MyPaintScreenEnumProc, 0); ReleaseDC(NULL, hdc); 
  2. HDC仅在回调内部有效,如@andlabs建议。 这是有道理的,因为必须先获取并释放HDC ,但是只有EnumDisplayMonitors()知道如何获取每个HDC ,因此只有它知道如何正确释放每个HDC 由于没有用于释放枚举的HDC API函数,因此这意味着HDC在枚举之外无效。

    MSDN告诉您如何获取给定监视器的HDC

    HMONITOR和设备上下文

    每个物理显示都由HMONITOR类型的监视器句柄表示。 有效的HMONITOR保证为非NULL。 物理显示器具有相同的HMONITOR ,只要它是桌面的一部分即可。 发送WM_DISPLAYCHANGE消息后,任何监视器都可能会从桌面上删除,因此其HMONITOR变为无效或已更改其设置。 因此,应用程序应在发送此消息时检查所有HMONITORS是否有效。

    任何返回显示设备上下文(DC)的功能通常都会返回主监视器的DC。 若要获取另一台监视器的DC,请使用EnumDisplayMonitors函数。 或者,您可以使用GetMonitorInfo函数中的设备名称通过CreateDC创建DC 但是,如果该函数(例如GetWindowDCBeginPaint )获得了跨越一个以上显示器的窗口的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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM