照例先上参考资料
参考资料
New Ways to do Screen Capture
C++/WinRT
CPP ScreenCaptureForHWND
限制
WindowsGraphicsCapture APIs first shipped in the Windows 10 April 2018 Update (1803). These APIs were built for developers who depended on screen capture functionality for their modern applications without depending on restricted capabilities. These APIs enable capture of application windows, displays, and environments in a secure, easy to use way with the use of a system picker UI control.
C++/WinRT is an entirely standard modern C++17 language projection for Windows Runtime (WinRT) APIs, implemented as a header-file-based library, and designed to provide you with first-class access to the modern Windows API. With C++/WinRT, you can author and consume Windows Runtime APIs using any standards-compliant C++17 compiler. The Windows SDK includes C++/WinRT; it was introduced in version 10.0.17134.0 (Windows 10, version 1803).
综上想要基于最新的捕获技术WindowsGraphicsCapture进行图像捕获有以下限制
- 系统版本不低于10.0.17134.0 (Windows 10, version 1803)
- 相关接口均基于微软的新一代运行时库接口C++/WinRT,而且是最低要求 c++17
一般项目开发中不太会使用c++17,所以都会将基于WGC的图像捕获功能封装到动态库中,在判断系统支持WGC后基本都会优先使用WGC来捕获图像。
添加桌面捕获功能
- 项目中添加头文件 Win32MonitorEnumeration.h,封装了枚举显示器的功能
#pragma once
#include <dwmapi.h>
struct Monitor {
public:
Monitor(nullptr_t) {}
Monitor(HMONITOR hmonitor, std::wstring &className, bool isPrimary) {
m_hmonitor = hmonitor;
m_className = className;
m_bIsPrimary = isPrimary;
}
HMONITOR Hmonitor() const noexcept { return m_hmonitor; }
std::wstring ClassName() const noexcept { return m_className; }
bool IsPrimary() const noexcept { return m_bIsPrimary; }
private:
HMONITOR m_hmonitor;
std::wstring m_className;
bool m_bIsPrimary;
};
BOOL WINAPI EnumMonitorProc(HMONITOR hmonitor, HDC hdc, LPRECT lprc,
LPARAM data) {
MONITORINFOEX info_ex;
info_ex.cbSize = sizeof(MONITORINFOEX);
GetMonitorInfo(hmonitor, &info_ex);
if (info_ex.dwFlags == DISPLAY_DEVICE_MIRRORING_DRIVER)
return true;
auto monitors = ((std::vector<Monitor> *)data);
std::wstring name = info_ex.szDevice;
auto monitor =
Monitor(hmonitor, name, info_ex.dwFlags & MONITORINFOF_PRIMARY);
monitors->emplace_back(monitor);
return true;
}
std::vector<Monitor> EnumerateMonitors() {
std::vector<Monitor> monitors;
::EnumDisplayMonitors(NULL, NULL, EnumMonitorProc, (LPARAM)&monitors);
return monitors;
}
- capture.interop.h 添加根据显示器句柄创建Capture的功能
inline auto CreateCaptureItemForMonitor(HMONITOR hmonitor) {
auto activation_factory = winrt::get_activation_factory<
winrt::Windows::Graphics::Capture::GraphicsCaptureItem>();
auto interop_factory = activation_factory.as<IGraphicsCaptureItemInterop>();
winrt::Windows::Graphics::Capture::GraphicsCaptureItem item = {nullptr};
interop_factory->CreateForMonitor(
hmonitor,
winrt::guid_of<ABI::Windows::Graphics::Capture::IGraphicsCaptureItem>(),
reinterpret_cast<void **>(winrt::put_abi(item)));
return item;
}
- App.h 中添加开始捕获函数声明
void StartCapture(HMONITOR hmonitor);
- App.cpp中添加开始捕获函数定义
void App::StartCapture(HMONITOR hmonitor) {
if (m_capture) {
m_capture->Close();
m_capture = nullptr;
}
auto item = CreateCaptureItemForMonitor(hmonitor);
m_capture = std::make_unique<SimpleCapture>(m_device, item);
auto surface = m_capture->CreateSurface(m_compositor);
m_brush.Surface(surface);
m_capture->StartCapture();
}
- main.cpp中引入头文件
#include "Win32MonitorEnumeration.h"
- main.cpp中添加枚举显示器操作
auto g_monitors = EnumerateMonitors();
- main.cpp中向控件Combox添加枚举到的显示器信息
for (auto &monitor : g_monitors) {
SendMessage(comboBoxHwnd, CB_ADDSTRING, 0,
(LPARAM)monitor.ClassName().c_str());
}
- main.cpp中添加处理选中显示器时的操作
if (index < g_windows.size() - 1) {
auto window = g_windows[index];
g_app->StartCapture(window.Hwnd());
} else {
auto monitor = g_monitors[index - g_windows.size()];
g_app->StartCapture(monitor.Hmonitor());
}
- 再次编译运行,会发现程序的窗口列表框里多出了你所有的显示器信息,选择它即可开始采集并实时显示捕获到的画面