C++ Win32:显示监视器的捕获句柄
我目前正在开发一个应用程序,它要求连接到系统的每个屏幕都有一个C++ Win32:显示监视器的捕获句柄,c++,winapi,gdi,C++,Winapi,Gdi,我目前正在开发一个应用程序,它要求连接到系统的每个屏幕都有一个HDC 我目前使用的代码如下: std::vector<HDC> dcs; HDC dcMain = ::GetDC(nullptr); // <-- don't understand this ::EnumDisplayMonitors(dcMain, nullptr, MONITORENUMPROC(&DisplayMonitorCallback), LPARAM(&dcs)); 因此,我的问
HDC
我目前使用的代码如下:
std::vector<HDC> dcs;
HDC dcMain = ::GetDC(nullptr); // <-- don't understand this
::EnumDisplayMonitors(dcMain, nullptr, MONITORENUMPROC(&DisplayMonitorCallback), LPARAM(&dcs));
因此,我的问题是:
dcMain
,我必须将其传递进来,这是获得一个的好方法吗HDC
s并稍后对其进行迭代时不工作hdc = GetDC(NULL);
EnumDisplayMonitors(hdc, NULL, MyPaintScreenEnumProc, 0);
ReleaseDC(NULL, hdc);
HDC
s仅在回调内部有效。这是有意义的,因为必须先获得一个HDC
,然后再释放,但只有EnumDisplayMonitors()
知道如何获得每个HDC
,因此只有它知道如何正确释放每个。由于没有用于释放枚举的HDC
的API函数,这意味着HDC
在枚举之外无效
MSDN告诉您如何获取给定监视器的HDC
:
每个物理显示器由类型为HMONITOR
的监视器手柄表示。有效的HMONITOR
保证为非空。物理显示器具有相同的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 = GetDC(NULL);
EnumDisplayMonitors(hdc, NULL, MyPaintScreenEnumProc, 0);
ReleaseDC(NULL, hdc);
HDC
s仅在回调内部有效。这是有意义的,因为必须先获得一个HDC
,然后再释放,但只有EnumDisplayMonitors()
知道如何获得每个HDC
,因此只有它知道如何正确释放每个。由于没有用于释放枚举的HDC
的API函数,这意味着HDC
在枚举之外无效
MSDN告诉您如何获取给定监视器的HDC
:
每个物理显示器由类型为HMONITOR
的监视器手柄表示。有效的HMONITOR
保证为非空。物理显示器具有相同的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;
}
文档中没有详细说明,但您可以假设,鉴于类似的枚举函数在其他API中的工作方式,在枚举过程中,EnumDisplayMonitors()本身会获取给定给每个回调函数的HDC,然后在回调返回时立即释放;也就是说,只有在回调函数本身期间使用该HDC可能是安全的。但是,继续这一思路将使我们进入XY问题领域,因此:您想做什么,需要单独的监视器HDC?@andlabs谢谢,我需要HDC实例化IDXGISurface1:该方法返回与IDXGISurface1关联的HDC;您使用什么来实际创建对象?文档中没有详细说明,但是您可以假设,鉴于类似的枚举函数在其他API中的工作方式,在枚举过程中,EnumDisplayMonitors()本身获取了给定给每个回调函数的HDC,然后在回调返回时立即释放;也就是说,只有在回调函数本身期间使用该HDC可能是安全的。但是,继续这一思路将使我们进入XY问题领域,因此:您想做什么,需要单独的监视器HDC?@andlabs谢谢,我需要HDC实例化IDXGISurface1:该方法返回与IDXGISurface1关联的HDC;您使用什么来实际创建对象?
hdc_vector dcs;
EnumDisplayMonitors(dcMain, nullptr, DisplayMonitorCallback, reinterpret_cast<LPARAM>(&dcs));
...
for (HDC dc : dcs)
{
...
}
...
for (HDC dc : dcs)
DeleteDC(dc);
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 ...
}