前一篇文章《【音视频】获取桌面程序窗口列表以及桌面、窗口的缩略图(4-4)》获取App窗口缩略图有一点瑕疵,经过felicityWSH的指点,自己抽空研究了下,终于将其优化了,感谢!
本章采用了DWM(Desktop Window Manage)技术解决采集App缩略图遗留的问题,主要用到DwmRegisterThumbnail、DwmUpdateThumbnailProperties和DwmUnregisterThumbnail。因为主要针对采集缩小化的窗口缩略图采集不到问题,所以思路如下:依然遍历所有App窗口,如果没有最小化那么按照原来思路采集,如果是最小化窗口,则使用DWM将最小化窗口显示在自己创建的Layered窗口X上面,窗口X远离屏幕显示区域显示,接着用原来的采集方法采集X的缩略图即可。
修改App窗口枚举方法:
BOOL CALLBACK VideoDevice::enumWindowProc(HWND hwnd, LPARAM dwData)
{
std::list<VIDEO_DEVICE>* devices = reinterpret_cast<std::list<VIDEO_DEVICE>*>(dwData);
/* 省略 */
VIDEO_DEVICE device = {};
/* 省略 */
if (!device.id.empty() && !device.name.empty()) {
int err;
if (IsIconic(hwnd)) { // 窗口最小化
err = registerThumbnailWindow(hwnd, device.thumbnail);
}
else {
err = allocWindowThumbnail(hwnd, device.thumbnail);
}
/* 省略 */
devices->push_back(device);
}
return TRUE;
}
实现缩略图窗口注册方法:
int VideoDevice::registerThumbnailWindow(HWND hWnd, VIDEO_THUMBNAIL& thumbnailInfo)
{
if (m_layeredThumbnailWindow == nullptr) {
m_layeredThumbnailWindow = createLayeredWindow();
}
if (m_layeredThumbnailWindow == nullptr) {
return ERROR_CODE_NULL_POINTER;
}
HTHUMBNAIL thumbnail = NULL;
HRESULT hr = DwmRegisterThumbnail(m_layeredThumbnailWindow, hWnd, &thumbnail);
if (FAILED(hr)) {
return ERROR_CODE_DEVICE_REGISTER_THUMBNAIL_FAILED;
}
RECT dest;
GetClientRect(m_layeredThumbnailWindow, &dest);
DWM_THUMBNAIL_PROPERTIES dskThumbProps;
dskThumbProps.dwFlags = DWM_TNP_RECTDESTINATION | DWM_TNP_VISIBLE | DWM_TNP_SOURCECLIENTAREAONLY | DWM_TNP_OPACITY;
dskThumbProps.fSourceClientAreaOnly = FALSE;
dskThumbProps.fVisible = TRUE;
dskThumbProps.rcDestination = dest;
dskThumbProps.opacity = 255;
hr = DwmUpdateThumbnailProperties(thumbnail, &dskThumbProps);
if (FAILED(hr)) {
DwmUnregisterThumbnail(thumbnail);
return ERROR_CODE_DEVICE_UPDATE_THUMBNAIL_PROPERTY_FAILED;
}
// 使用原来方法采集缩略图
allocWindowThumbnail(m_layeredThumbnailWindow, thumbnailInfo);
DwmUnregisterThumbnail(thumbnail);
return ERROR_CODE_OK;
}
创建Layered窗口用来显示最小化的App:
HWND VideoDevice::createLayeredWindow()
{
WNDCLASS wndCls;
wndCls.cbClsExtra = 0;
wndCls.cbWndExtra = 0;
wndCls.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wndCls.hCursor = nullptr;
wndCls.hInstance = nullptr;
wndCls.hIcon = nullptr;
wndCls.lpfnWndProc = layeredWindowProc;
wndCls.lpszClassName = L"Capture Minimize Window Class";
wndCls.lpszMenuName = nullptr;
wndCls.style = CS_NOCLOSE;
// 注册自己的窗口类
RegisterClass(&wndCls);
HWND hWnd = CreateWindow(wndCls.lpszClassName, L"Capture Minimize Window", WS_POPUPWINDOW, -32000, -32000, 640, 360, nullptr, nullptr, nullptr, nullptr);
if (hWnd == nullptr) {
return nullptr;
}
ShowWindow(hWnd, SW_SHOWNORMAL);
// 去除任务栏缩略图显示
SetWindowLong(hWnd, GWL_EXSTYLE, GetWindowLong(hWnd, GWL_EXSTYLE) & ~WS_EX_APPWINDOW);
UpdateWindow(hWnd);
return hWnd;
}
窗口类方法使用默认调用方式即可:
LRESULT CALLBACK VideoDevice::layeredWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
删除allocWindowThumbnail方法中原来处理最小化App窗口的片段:
至此,获取App窗口缩略图优化完成,完美收尾!只要不断努力钻研,有朝一日定有收获。