#include <windows.h>
#include <unknwn.h> // 必须在 WinRT 之前包含,处理 IUnknown 冲突
#include <d3d11.h>
#include <dxgi1_2.h>
#include <wrl/client.h>
#include <iostream>
#include <vector>
#include <future>
#include <Inspectable.h> // 必须包含这个处理基础接口
#include <fstream>
#include <iostream>
// C++/WinRT 头文件
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Graphics.Capture.h>
#include <winrt/Windows.Graphics.DirectX.Direct3D11.h>
#include <windows.graphics.capture.interop.h>
#include <windows.graphics.directx.direct3d11.interop.h>
#pragma comment(lib, "windowsapp.lib")
#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "dxgi.lib")
// 明确指定命名空间,避免 "Windows" 冲突
namespace winrt_cap = winrt::Windows::Graphics::Capture;
namespace winrt_d3d = winrt::Windows::Graphics::DirectX::Direct3D11;
using namespace Microsoft::WRL;
class VulkanWindowCapturer {
public:
VulkanWindowCapturer() {
// 1. 初始化 D3D11 设备
UINT flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
HRESULT hr = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, flags,
nullptr, 0, D3D11_SDK_VERSION, &m_d3dDevice, nullptr, &m_d3dContext);
if (FAILED(hr)) throw std::runtime_error("D3D11 Device Creation Failed");
// 2. 将 D3D11 设备转换为 WinRT 设备
ComPtr<IDXGIDevice> dxgiDevice;
m_d3dDevice.As(&dxgiDevice);
winrt::com_ptr<::IInspectable> inspectable;
// 使用全局作用域限定符调用 API
hr = ::CreateDirect3D11DeviceFromDXGIDevice(dxgiDevice.Get(), inspectable.put());
if (FAILED(hr)) throw std::runtime_error("WinRT Device Bridge Failed");
m_winrtDevice = inspectable.as<winrt_d3d::IDirect3DDevice>();
}
bool Capture(HWND hwnd) {
if (!IsWindow(hwnd)) return false;
auto factory = winrt::get_activation_factory<winrt_cap::GraphicsCaptureItem, IGraphicsCaptureItemInterop>();
winrt_cap::GraphicsCaptureItem item{ nullptr };
factory->CreateForWindow(hwnd, winrt::guid_of<ABI::Windows::Graphics::Capture::IGraphicsCaptureItem>(), winrt::put_abi(item));
auto size = item.Size();
// 使用 promise 来同步异步回调
auto isProcessed = std::make_shared<std::atomic<bool>>(false);
auto framePromise = std::make_shared<std::promise<cv::Mat>>();
auto frameFuture = framePromise->get_future();
auto framePool = winrt_cap::Direct3D11CaptureFramePool::CreateFreeThreaded(
m_winrtDevice,
winrt::Windows::Graphics::DirectX::DirectXPixelFormat::R8G8B8A8UIntNormalized,
1,
size);
auto session = framePool.CreateCaptureSession(item);
auto token = framePool.FrameArrived([&, isProcessed, framePromise, session](winrt_cap::Direct3D11CaptureFramePool const& sender, auto const&) {
// 如果已经处理过了,直接返回
if (isProcessed->load()) return;
auto frame = sender.TryGetNextFrame();
if (!frame) return;
// 标记已处理,防止并发进入
isProcessed->store(true);
// 获取纹理
auto frameSurface = frame.Surface();
auto access = frameSurface.as<::Windows::Graphics::DirectX::Direct3D11::IDirect3DDxgiInterfaceAccess>();
ComPtr<ID3D11Texture2D> frameTexture;
access->GetInterface(IID_PPV_ARGS(&frameTexture));
// 创建并拷贝到 Staging Texture
D3D11_TEXTURE2D_DESC desc;
frameTexture->GetDesc(&desc);
desc.Usage = D3D11_USAGE_STAGING;
desc.BindFlags = 0;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
desc.MiscFlags = 0;
ComPtr<ID3D11Texture2D> stagingTexture;
m_d3dDevice->CreateTexture2D(&desc, nullptr, &stagingTexture);
// 重要:将 GPU 数据同步到 Staging 纹理
m_d3dContext->CopyResource(stagingTexture.Get(), frameTexture.Get());
D3D11_MAPPED_SUBRESOURCE mapped;
if (SUCCEEDED(m_d3dContext->Map(stagingTexture.Get(), 0, D3D11_MAP_READ, 0, &mapped))) {
// 保存到 OpenCV Mat
cv::Mat raw(size.Height, size.Width, CV_8UC4, mapped.pData, mapped.RowPitch);
cv::Mat finalImg;
cv::cvtColor(raw, finalImg, cv::COLOR_RGBA2BGR); // 纠正偏红问题
framePromise->set_value(finalImg.clone()); // 传出数据
m_d3dContext->Unmap(stagingTexture.Get(), 0);
}
});
session.StartCapture();
// 等待结果
if (frameFuture.wait_for(std::chrono::seconds(2)) == std::future_status::ready) {
cv::Mat result = frameFuture.get();
cv::imshow("output.png", result); cv::waitKey();
// --- 安全退出的关键 ---
// 1. 先取消事件订阅
framePool.FrameArrived(token);
// 2. 退出作用域或显式让 session 变量失效即可,不必强行 Close()
// 或者在外部调用:
session.Close();
}
return true;
}
private:
ComPtr<ID3D11Device> m_d3dDevice;
ComPtr<ID3D11DeviceContext> m_d3dContext;
winrt_d3d::IDirect3DDevice m_winrtDevice{ nullptr };
};
int main() {
// 显式调用 winrt 命名空间
winrt::init_apartment(winrt::apartment_type::multi_threaded);
HWND targetHwnd = FindWindowW(NULL, L"MuMu安卓设备");
if (!targetHwnd) {
std::cout << "Window not found!" << std::endl;
return -1;
}
try {
VulkanWindowCapturer capturer;
capturer.Capture(targetHwnd);
}
catch (const std::exception& e) {
std::cerr << "Exception: " << e.what() << std::endl;
}
return 0;
}以上方法,虽然可以抓图,但是底层并未将所有图像数据绘制超出部分。目前临时解决方法,强制刷新
void SuperForceRefresh(HWND m_hWnd) {
if (!IsWindow(m_hWnd)) return;
WINDOWPLACEMENT wp;
wp.length = sizeof(WINDOWPLACEMENT);
GetWindowPlacement(m_hWnd, &wp);
wp.showCmd = SW_SHOWMINIMIZED;
SetWindowPlacement(m_hWnd, &wp);
wp.showCmd = SW_SHOWDEFAULT;
SetWindowPlacement(m_hWnd, &wp);
}后续再研究。。。
收藏的用户(0) X
正在加载信息~
推荐阅读
最新回复 (0)
站点信息
- 文章2319
- 用户1336
- 访客11976275
每日一句
Gentleness is my strength, sharpness is my boundary.
温柔是我的力量,锋利是我的边界。
温柔是我的力量,锋利是我的边界。