簡體   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