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

时间:2016-09-01 16:08:02

标签: c++ winapi gdi

我目前正在为连接到系统的每个屏幕开发一个需要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;
}

请注意,我目前正在每个屏幕上渲染绿色画笔。这在 THIS 上下文中完全有效(即在回调中)。

现在,问题是,我正在捕获稍后要使用的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 个答案:

答案 0 :(得分:2)

  1. 是的,EnumDisplayMonitors()文档中提到了这一点:

      

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

    hdc = GetDC(NULL);
    EnumDisplayMonitors(hdc, NULL, MyPaintScreenEnumProc, 0);
    ReleaseDC(NULL, hdc);
    
  2. {@ 1}}只在回调中有效,正如@andlabs建议的那样。这是有道理的,因为必须获取然后释放HDC,但只有HDC知道如何获得每个EnumDisplayMonitors(),因此只有它知道如何正确发布每一个。由于没有用于释放枚举HDC的API函数,这意味着HDC在枚举之外无效。

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

    HMONITOR and the Device Context

      

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

         

    任何返回显示设备上下文(DC)的函数通常都会返回主监视器的DC。要获取另一台显示器的DC,请使用HMONITORS功能。 或者,您可以使用EnumDisplayMonitors功能中的设备名称创建一个GetMonitorInfo 的DC。但是,如果函数(例如CreateDCGetWindowDC)获得跨越多个显示器的窗口的DC,则DC也将跨越两个显示器。

    例如:

    BeginPaint

    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;
    }
    

    由于您显然正在使用C ++ 11,我建议使用hdc_vector dcs; EnumDisplayMonitors(dcMain, nullptr, DisplayMonitorCallback, reinterpret_cast<LPARAM>(&dcs)); ... for (HDC dc : dcs) { ... } ... for (HDC dc : dcs) DeleteDC(dc); 进行std::unique_ptr的内存管理,这样您就不必手动调用HDC。我会使用lambda进行回调,并将DeleteDC()更改为std::vector(这样您就可以在需要时查找任何特定监视器的std::map):

    HDC
相关问题