2024-05-03 01:54:36 +08:00
|
|
|
|
#include "define.h"
|
2024-01-08 23:37:00 +08:00
|
|
|
|
#include <dxgi.h>
|
|
|
|
|
#include <inspectable.h>
|
|
|
|
|
#include <dxgi1_2.h>
|
|
|
|
|
#include <d3d11.h>
|
|
|
|
|
#include <winrt/Windows.System.h>
|
|
|
|
|
#include <winrt/Windows.Foundation.h>
|
|
|
|
|
#include <winrt/Windows.Foundation.Collections.h>
|
|
|
|
|
#include <winrt/Windows.Graphics.Capture.h>
|
|
|
|
|
#include <Windows.Graphics.Capture.Interop.h>
|
|
|
|
|
#include <windows.graphics.directx.direct3d11.interop.h>
|
2024-04-02 15:36:52 +08:00
|
|
|
|
#include <winrt/Windows.Foundation.Metadata.h>
|
2024-01-08 23:37:00 +08:00
|
|
|
|
#include <winrt/Windows.Graphics.DirectX.h>
|
|
|
|
|
#include <winrt/Windows.Graphics.DirectX.Direct3d11.h>
|
|
|
|
|
#include <winrt/Windows.Graphics.Imaging.h>
|
|
|
|
|
#include <winrt/Windows.Security.Authorization.AppCapabilityAccess.h>
|
|
|
|
|
#include <winrt/Windows.Storage.h>
|
|
|
|
|
#include <winrt/Windows.Storage.Pickers.h>
|
2024-04-02 15:36:52 +08:00
|
|
|
|
#include <winrt/Windows.Storage.Streams.h>
|
|
|
|
|
#include <roerrorapi.h>
|
2024-01-08 23:37:00 +08:00
|
|
|
|
#include <gdiplus.h>
|
2024-04-02 15:36:52 +08:00
|
|
|
|
// #include "ImageFormatConversion.hpp"
|
2024-01-08 23:37:00 +08:00
|
|
|
|
|
|
|
|
|
#pragma comment(lib, "windowsapp.lib")
|
|
|
|
|
#pragma comment(lib, "DXGI.lib")
|
|
|
|
|
#pragma comment(lib, "gdiplus.lib")
|
|
|
|
|
#pragma comment(lib, "d3d11.lib")
|
2024-04-02 15:36:52 +08:00
|
|
|
|
#pragma comment(lib, "Windowscodecs.lib")
|
|
|
|
|
int GetEncoderClsid(const WCHAR *format, CLSID *pClsid)
|
2024-01-08 23:37:00 +08:00
|
|
|
|
{
|
2024-04-02 15:36:52 +08:00
|
|
|
|
UINT num = 0; // number of image encoders
|
|
|
|
|
UINT size = 0; // size of the image encoder array in bytes
|
2024-01-08 23:37:00 +08:00
|
|
|
|
|
2024-04-02 15:36:52 +08:00
|
|
|
|
Gdiplus::ImageCodecInfo *pImageCodecInfo = NULL;
|
2024-01-08 23:37:00 +08:00
|
|
|
|
|
|
|
|
|
Gdiplus::GetImageEncodersSize(&num, &size);
|
|
|
|
|
if (size == 0)
|
2024-04-02 15:36:52 +08:00
|
|
|
|
return -1; // Failure
|
2024-01-08 23:37:00 +08:00
|
|
|
|
|
2024-04-02 15:36:52 +08:00
|
|
|
|
pImageCodecInfo = (Gdiplus::ImageCodecInfo *)(malloc(size));
|
2024-01-08 23:37:00 +08:00
|
|
|
|
if (pImageCodecInfo == NULL)
|
2024-04-02 15:36:52 +08:00
|
|
|
|
return -1; // Failure
|
2024-01-08 23:37:00 +08:00
|
|
|
|
|
|
|
|
|
GetImageEncoders(num, size, pImageCodecInfo);
|
|
|
|
|
|
|
|
|
|
for (UINT j = 0; j < num; ++j)
|
|
|
|
|
{
|
|
|
|
|
if (wcscmp(pImageCodecInfo[j].MimeType, format) == 0)
|
|
|
|
|
{
|
|
|
|
|
*pClsid = pImageCodecInfo[j].Clsid;
|
|
|
|
|
free(pImageCodecInfo);
|
2024-04-02 15:36:52 +08:00
|
|
|
|
return j; // Success
|
2024-01-08 23:37:00 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
free(pImageCodecInfo);
|
2024-04-02 15:36:52 +08:00
|
|
|
|
return -1; // Failure
|
2024-01-08 23:37:00 +08:00
|
|
|
|
}
|
2024-04-02 15:36:52 +08:00
|
|
|
|
void capture_window(HWND window_handle, const std::wstring &output_file_path)
|
2024-01-08 23:37:00 +08:00
|
|
|
|
{
|
|
|
|
|
HMODULE hModule = LoadLibrary(TEXT("d3d11.dll"));
|
2024-04-02 15:36:52 +08:00
|
|
|
|
HRESULT typedef(_stdcall * CreateDirect3D11DeviceFromDXGIDevice_t)(
|
|
|
|
|
_In_ IDXGIDevice * dxgiDevice,
|
|
|
|
|
_COM_Outptr_ IInspectable * *graphicsDevice);
|
2024-01-08 23:37:00 +08:00
|
|
|
|
CreateDirect3D11DeviceFromDXGIDevice_t CreateDirect3D11DeviceFromDXGIDevice = reinterpret_cast<CreateDirect3D11DeviceFromDXGIDevice_t>(
|
|
|
|
|
GetProcAddress(hModule, "CreateDirect3D11DeviceFromDXGIDevice"));
|
2024-04-02 15:36:52 +08:00
|
|
|
|
if (CreateDirect3D11DeviceFromDXGIDevice == NULL)
|
|
|
|
|
return;
|
|
|
|
|
// Init COM
|
|
|
|
|
// init_apartment(winrt::apartment_type::multi_threaded);
|
|
|
|
|
|
2024-01-08 23:37:00 +08:00
|
|
|
|
// Create Direct 3D Device
|
|
|
|
|
winrt::com_ptr<ID3D11Device> d3d_device;
|
|
|
|
|
|
|
|
|
|
winrt::check_hresult(D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, D3D11_CREATE_DEVICE_BGRA_SUPPORT,
|
2024-04-02 15:36:52 +08:00
|
|
|
|
nullptr, 0, D3D11_SDK_VERSION, d3d_device.put(), nullptr, nullptr));
|
|
|
|
|
|
2024-01-08 23:37:00 +08:00
|
|
|
|
winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice device;
|
|
|
|
|
const auto dxgiDevice = d3d_device.as<IDXGIDevice>();
|
|
|
|
|
{
|
|
|
|
|
winrt::com_ptr<IInspectable> inspectable;
|
|
|
|
|
winrt::check_hresult(CreateDirect3D11DeviceFromDXGIDevice(dxgiDevice.get(), inspectable.put()));
|
|
|
|
|
device = inspectable.as<winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice>();
|
|
|
|
|
}
|
2024-04-02 15:36:52 +08:00
|
|
|
|
|
2024-01-08 23:37:00 +08:00
|
|
|
|
auto idxgi_device2 = dxgiDevice.as<IDXGIDevice2>();
|
|
|
|
|
winrt::com_ptr<IDXGIAdapter> adapter;
|
|
|
|
|
winrt::check_hresult(idxgi_device2->GetParent(winrt::guid_of<IDXGIAdapter>(), adapter.put_void()));
|
|
|
|
|
winrt::com_ptr<IDXGIFactory2> factory;
|
|
|
|
|
winrt::check_hresult(adapter->GetParent(winrt::guid_of<IDXGIFactory2>(), factory.put_void()));
|
2024-05-27 12:14:04 +08:00
|
|
|
|
|
|
|
|
|
winrt::com_ptr<ID3D11DeviceContext> d3d_context;
|
|
|
|
|
d3d_device->GetImmediateContext(d3d_context.put());
|
2024-01-08 23:37:00 +08:00
|
|
|
|
|
|
|
|
|
RECT rect{};
|
|
|
|
|
DwmGetWindowAttribute(window_handle, DWMWA_EXTENDED_FRAME_BOUNDS, &rect, sizeof(RECT));
|
2024-04-02 15:36:52 +08:00
|
|
|
|
const auto size = winrt::Windows::Graphics::SizeInt32{rect.right - rect.left, rect.bottom - rect.top};
|
|
|
|
|
|
2024-01-08 23:37:00 +08:00
|
|
|
|
winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool m_frame_pool =
|
|
|
|
|
winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool::Create(
|
|
|
|
|
device,
|
|
|
|
|
winrt::Windows::Graphics::DirectX::DirectXPixelFormat::B8G8R8A8UIntNormalized,
|
|
|
|
|
2,
|
|
|
|
|
size);
|
2024-04-02 15:36:52 +08:00
|
|
|
|
|
2024-01-08 23:37:00 +08:00
|
|
|
|
const auto activation_factory = winrt::get_activation_factory<
|
|
|
|
|
winrt::Windows::Graphics::Capture::GraphicsCaptureItem>();
|
|
|
|
|
auto interop_factory = activation_factory.as<IGraphicsCaptureItemInterop>();
|
2024-04-02 15:36:52 +08:00
|
|
|
|
winrt::Windows::Graphics::Capture::GraphicsCaptureItem capture_item = {nullptr};
|
2024-01-08 23:37:00 +08:00
|
|
|
|
interop_factory->CreateForWindow(window_handle, winrt::guid_of<ABI::Windows::Graphics::Capture::IGraphicsCaptureItem>(),
|
2024-04-02 15:36:52 +08:00
|
|
|
|
winrt::put_abi(capture_item));
|
2024-01-08 23:37:00 +08:00
|
|
|
|
|
|
|
|
|
auto is_frame_arrived = false;
|
|
|
|
|
winrt::com_ptr<ID3D11Texture2D> texture;
|
|
|
|
|
const auto session = m_frame_pool.CreateCaptureSession(capture_item);
|
|
|
|
|
session.IsCursorCaptureEnabled(false);
|
2024-04-02 15:36:52 +08:00
|
|
|
|
m_frame_pool.FrameArrived([&](auto &frame_pool, auto &)
|
|
|
|
|
{
|
2024-01-08 23:37:00 +08:00
|
|
|
|
if (is_frame_arrived)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
auto frame = frame_pool.TryGetNextFrame();
|
|
|
|
|
|
|
|
|
|
struct __declspec(uuid("A9B3D012-3DF2-4EE3-B8D1-8695F457D3C1"))
|
|
|
|
|
IDirect3DDxgiInterfaceAccess : ::IUnknown
|
|
|
|
|
{
|
|
|
|
|
virtual HRESULT __stdcall GetInterface(GUID const& id, void** object) = 0;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
auto access = frame.Surface().as<IDirect3DDxgiInterfaceAccess>();
|
|
|
|
|
access->GetInterface(winrt::guid_of<ID3D11Texture2D>(), texture.put_void());
|
|
|
|
|
is_frame_arrived = true;
|
2024-04-02 15:36:52 +08:00
|
|
|
|
return; });
|
2024-01-08 23:37:00 +08:00
|
|
|
|
|
|
|
|
|
session.StartCapture();
|
|
|
|
|
|
|
|
|
|
// Message pump
|
|
|
|
|
MSG message;
|
|
|
|
|
while (!is_frame_arrived)
|
|
|
|
|
{
|
|
|
|
|
if (PeekMessage(&message, nullptr, 0, 0, PM_REMOVE) > 0)
|
|
|
|
|
{
|
|
|
|
|
DispatchMessage(&message);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
session.Close();
|
|
|
|
|
//??
|
|
|
|
|
|
|
|
|
|
D3D11_TEXTURE2D_DESC captured_texture_desc;
|
|
|
|
|
texture->GetDesc(&captured_texture_desc);
|
|
|
|
|
|
|
|
|
|
captured_texture_desc.Usage = D3D11_USAGE_STAGING;
|
|
|
|
|
captured_texture_desc.BindFlags = 0;
|
|
|
|
|
captured_texture_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
|
|
|
|
captured_texture_desc.MiscFlags = 0;
|
|
|
|
|
|
|
|
|
|
winrt::com_ptr<ID3D11Texture2D> user_texture = nullptr;
|
|
|
|
|
winrt::check_hresult(d3d_device->CreateTexture2D(&captured_texture_desc, nullptr, user_texture.put()));
|
|
|
|
|
|
|
|
|
|
d3d_context->CopyResource(user_texture.get(), texture.get());
|
|
|
|
|
|
|
|
|
|
D3D11_MAPPED_SUBRESOURCE resource;
|
|
|
|
|
winrt::check_hresult(d3d_context->Map(user_texture.get(), NULL, D3D11_MAP_READ, 0, &resource));
|
|
|
|
|
|
|
|
|
|
BITMAPINFO l_bmp_info;
|
|
|
|
|
|
|
|
|
|
// BMP 32 bpp
|
|
|
|
|
ZeroMemory(&l_bmp_info, sizeof(BITMAPINFO));
|
|
|
|
|
l_bmp_info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
|
|
|
|
l_bmp_info.bmiHeader.biBitCount = 32;
|
|
|
|
|
l_bmp_info.bmiHeader.biCompression = BI_RGB;
|
|
|
|
|
l_bmp_info.bmiHeader.biWidth = captured_texture_desc.Width;
|
|
|
|
|
l_bmp_info.bmiHeader.biHeight = captured_texture_desc.Height;
|
|
|
|
|
l_bmp_info.bmiHeader.biPlanes = 1;
|
|
|
|
|
l_bmp_info.bmiHeader.biSizeImage = captured_texture_desc.Width * captured_texture_desc.Height * 4;
|
|
|
|
|
|
2024-05-27 12:14:04 +08:00
|
|
|
|
auto p_buf = std::make_unique<BYTE[]>(l_bmp_info.bmiHeader.biSizeImage);
|
2024-01-08 23:37:00 +08:00
|
|
|
|
UINT l_bmp_row_pitch = captured_texture_desc.Width * 4;
|
2024-04-02 15:36:52 +08:00
|
|
|
|
auto sptr = static_cast<BYTE *>(resource.pData);
|
2024-01-08 23:37:00 +08:00
|
|
|
|
auto dptr = p_buf.get() + l_bmp_info.bmiHeader.biSizeImage - l_bmp_row_pitch;
|
|
|
|
|
|
|
|
|
|
UINT l_row_pitch = std::min<UINT>(l_bmp_row_pitch, resource.RowPitch);
|
|
|
|
|
|
|
|
|
|
for (size_t h = 0; h < captured_texture_desc.Height; ++h)
|
|
|
|
|
{
|
|
|
|
|
memcpy_s(dptr, l_bmp_row_pitch, sptr, l_row_pitch);
|
|
|
|
|
sptr += resource.RowPitch;
|
|
|
|
|
dptr -= l_bmp_row_pitch;
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-02 15:36:52 +08:00
|
|
|
|
// FILE* lfile = nullptr;
|
2024-01-08 23:37:00 +08:00
|
|
|
|
|
2024-04-02 15:36:52 +08:00
|
|
|
|
// if (auto lerr = _wfopen_s(&lfile, output_file_path.c_str(), L"wb"); lerr != 0)
|
2024-01-08 23:37:00 +08:00
|
|
|
|
//{
|
2024-04-02 15:36:52 +08:00
|
|
|
|
// return;
|
|
|
|
|
// }
|
2024-01-08 23:37:00 +08:00
|
|
|
|
|
2024-04-02 15:36:52 +08:00
|
|
|
|
// if (lfile != nullptr)
|
2024-01-08 23:37:00 +08:00
|
|
|
|
//{
|
2024-04-02 15:36:52 +08:00
|
|
|
|
// BITMAPFILEHEADER bmp_file_header;
|
2024-01-08 23:37:00 +08:00
|
|
|
|
|
|
|
|
|
// bmp_file_header.bfReserved1 = 0;
|
|
|
|
|
// bmp_file_header.bfReserved2 = 0;
|
|
|
|
|
// bmp_file_header.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + l_bmp_info.bmiHeader.biSizeImage;
|
|
|
|
|
// bmp_file_header.bfType = 'MB';
|
|
|
|
|
// bmp_file_header.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
|
|
|
|
|
|
|
|
|
|
// fwrite(&bmp_file_header, sizeof(BITMAPFILEHEADER), 1, lfile);
|
|
|
|
|
// fwrite(&l_bmp_info.bmiHeader, sizeof(BITMAPINFOHEADER), 1, lfile);
|
|
|
|
|
// fwrite(p_buf.get(), l_bmp_info.bmiHeader.biSizeImage, 1, lfile);
|
|
|
|
|
|
|
|
|
|
// fclose(lfile);
|
|
|
|
|
|
|
|
|
|
// //convert_image_encoding(output_file_path, L"png");
|
|
|
|
|
//}
|
|
|
|
|
Gdiplus::GdiplusStartupInput gdiplusStartupInput;
|
|
|
|
|
ULONG_PTR gdiplusToken;
|
|
|
|
|
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
|
2024-04-02 15:36:52 +08:00
|
|
|
|
Gdiplus::Bitmap *image = Gdiplus::Bitmap::FromBITMAPINFO(&l_bmp_info, p_buf.get());
|
2024-01-08 23:37:00 +08:00
|
|
|
|
|
2024-04-02 15:36:52 +08:00
|
|
|
|
CLSID encoderClsid;
|
2024-01-08 23:37:00 +08:00
|
|
|
|
GetEncoderClsid(L"image/png", &encoderClsid);
|
|
|
|
|
|
|
|
|
|
image->Save(output_file_path.c_str(), &encoderClsid, NULL);
|
2024-05-27 12:14:04 +08:00
|
|
|
|
delete image;
|
2024-01-08 23:37:00 +08:00
|
|
|
|
Gdiplus::GdiplusShutdown(gdiplusToken);
|
|
|
|
|
}
|
2024-04-02 15:36:52 +08:00
|
|
|
|
void winrt_capture_window(wchar_t *savepath, HWND hwnd)
|
|
|
|
|
{
|
|
|
|
|
// auto hwnd = GetForegroundWindow();// FindWindow(L"Window_Magpie_967EB565-6F73-4E94-AE53-00CC42592A22", 0);
|
2024-01-08 23:37:00 +08:00
|
|
|
|
auto style_ex = GetWindowLong(hwnd, GWL_EXSTYLE);
|
|
|
|
|
auto style_ex_save = style_ex;
|
2024-04-02 15:36:52 +08:00
|
|
|
|
bool needset = !(((style_ex & WS_EX_APPWINDOW) && !(style_ex & WS_EX_TOOLWINDOW)));
|
|
|
|
|
if (needset)
|
|
|
|
|
{
|
2024-01-08 23:37:00 +08:00
|
|
|
|
|
|
|
|
|
style_ex |= WS_EX_APPWINDOW;
|
|
|
|
|
style_ex &= ~WS_EX_TOOLWINDOW;
|
|
|
|
|
SetWindowLong(hwnd, GWL_EXSTYLE, style_ex);
|
|
|
|
|
}
|
2024-04-02 15:36:52 +08:00
|
|
|
|
|
2024-01-08 23:37:00 +08:00
|
|
|
|
capture_window(hwnd, savepath);
|
|
|
|
|
if (needset)
|
|
|
|
|
SetWindowLong(hwnd, GWL_EXSTYLE, style_ex_save);
|
|
|
|
|
}
|