通过劫持NVIDIA GeForce或AMD Software的窗口,即可实现全屏渲染。
Overlay.h
#pragma once
#include <d2d1.h>
#include <dwrite.h>
#include <windows.h>
class Overlay
{
public:
Overlay(const wchar_t* font, float fontSize);
~Overlay();
bool Init();
bool InitD2D();
void UnInitD2D() const;
void BeginScene() const;
void EndScene() const;
void ClearScene() const;
void DrawTextA(int x, int y, const char* text, D2D1::ColorF color, ...) const;
void DrawLine(int x, int y, int x2, int y2, D2D1::ColorF color, float thickness) const;
private:
HWND m_hijackedHwnd;
ID2D1Factory* m_d2dFactory;
ID2D1HwndRenderTarget* m_renderTarget;
IDWriteFactory* m_writeFactory;
ID2D1SolidColorBrush* m_brush;
IDWriteTextFormat* m_format;
const wchar_t* m_font;
float m_size;
bool m_isAmdGPU;
};
Overlay.cpp
#include "Overlay.h"
#include <dwmapi.h>
#include <string>
#pragma comment(lib, "d2d1.lib")
#pragma comment(lib, "Dwrite.lib")
#pragma comment(lib, "Dwmapi.lib")
Overlay::Overlay(const wchar_t* font, float fontSize)
{
m_font = font;
m_size = fontSize;
}
Overlay::~Overlay()
{
BeginScene();
ClearScene();
EndScene();
UnInitD2D();
}
bool Overlay::Init()
{
m_hijackedHwnd = FindWindowA("CEF-OSC-WIDGET", "NVIDIA GeForce Overlay");
if (NULL != m_hijackedHwnd)
{
m_isAmdGPU = false;
}
else
{
m_hijackedHwnd = FindWindowA("AMDDVROVERLAYWINDOWCLASS", "amd dvr overlay");
if (NULL != m_hijackedHwnd)
{
m_isAmdGPU = true;
}
else
{
return false;
}
}
ShowWindow(m_hijackedHwnd, SW_SHOW);
//SetWindowLongA(m_hijackedHwnd, GWL_EXSTYLE, WS_EX_TRANSPARENT | WS_EX_TOOLWINDOW | WS_EX_LAYERED);
const auto info = GetWindowLongA(m_hijackedHwnd, GWL_EXSTYLE);
if (!info)
return false;
const auto attrChange = SetWindowLongPtrA(m_hijackedHwnd, GWL_EXSTYLE, (info | WS_EX_TRANSPARENT));
if (!attrChange)
return false;
// AMD GPU需要
if (m_isAmdGPU)
{
const auto screenWidth = GetSystemMetrics(SM_CXSCREEN);
const auto screenHeight = GetSystemMetrics(SM_CYSCREEN);
MoveWindow(m_hijackedHwnd, 0, 0, screenWidth, screenHeight, false);
}
MARGINS margin;
margin.cyBottomHeight = margin.cyTopHeight = margin.cxLeftWidth = margin.cxRightWidth = -1;
if (DwmExtendFrameIntoClientArea(m_hijackedHwnd, &margin) != S_OK)
return false;
if (!SetLayeredWindowAttributes(m_hijackedHwnd, 0x000000, 0xFF, 0x02))
return false;
if (!SetWindowPos(m_hijackedHwnd, HWND_TOPMOST, 0, 0, 0, 0, 0x0002 | 0x0001))
return false;
UpdateWindow(m_hijackedHwnd);
return true;
}
bool Overlay::InitD2D()
{
RECT rc;
if (SUCCEEDED(D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &m_d2dFactory)))
{
if (SUCCEEDED(DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), reinterpret_cast<IUnknown**>(&m_writeFactory))))
{
m_writeFactory->CreateTextFormat(m_font, NULL, DWRITE_FONT_WEIGHT_REGULAR, DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, m_size, L"", &m_format);
GetClientRect(m_hijackedHwnd, &rc);
if (SUCCEEDED(m_d2dFactory->CreateHwndRenderTarget(D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT,
D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED)),
D2D1::HwndRenderTargetProperties(m_hijackedHwnd, D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top)), &m_renderTarget)))
{
const D2D1_BRUSH_PROPERTIES properties = { 1.0f, D2D1::Matrix3x2F::Identity() };
m_renderTarget->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::White), properties, &m_brush);
return true;
}
}
}
return false;
}
void Overlay::UnInitD2D() const
{
m_renderTarget->Release();
m_writeFactory->Release();
m_brush->Release();
m_d2dFactory->Release();
}
void Overlay::BeginScene() const
{
m_renderTarget->BeginDraw();
}
void Overlay::EndScene() const
{
m_renderTarget->EndDraw();
}
void Overlay::ClearScene() const
{
m_renderTarget->Clear();
}
void Overlay::DrawTextA(const int x, const int y, const char* text, const D2D1::ColorF color, ...) const
{
char buffer[4096]{};
RECT windowMetrics{};
if (!GetWindowRect(m_hijackedHwnd, &windowMetrics))
return;
va_list arg_list;
va_start(arg_list, text);
vsnprintf_s(buffer, sizeof(buffer), text, arg_list);
va_end(arg_list);
wchar_t out[256]{};
size_t length = 0;
mbstowcs_s(&length, out, buffer, strlen(buffer));
m_renderTarget->DrawTextA(out, length, m_format, D2D1::RectF(x, y, windowMetrics.right - windowMetrics.left, windowMetrics.bottom - windowMetrics.top), m_brush);
m_brush->SetColor(color);
}
void Overlay::DrawLine(const int x, const int y, const int x2, const int y2, const D2D1::ColorF color, const float thickness) const
{
m_renderTarget->DrawLine(D2D1::Point2F(x, y), D2D1::Point2F(x2, y2), m_brush, thickness);
m_brush->SetColor(color);
}
Comments