如何用SendMessage替代SendInput模拟硬件按键实现游戏截图?
解决游戏屏蔽GDI与注入按键的截图问题
一、纠正SendMessage的认知误区
VK_SNAPSHOT的系统截图逻辑不是通过WM_KEYDOWN/WM_KEYUP消息传递给桌面窗口实现的,而是由Windows内核级键盘处理逻辑直接响应物理按键事件,所以直接给桌面窗口发送这类消息完全无效,你的假设不成立。
二、修复SendInput模拟PrintScreen的问题
你当前的SendInput代码错误地给VK_SNAPSHOT添加了KEYEVENTF_EXTENDEDKEY标记——VK_SNAPSHOT不属于扩展按键(扩展按键指小键盘键、Home/End等特殊键),多余的标记可能让游戏钩子更容易识别出这是注入事件。修改代码如下:
INPUT inputs[2]; memset(inputs, 0x00, sizeof(INPUT) * 2); // 按下PrintScreen inputs[0].type = INPUT_KEYBOARD; inputs[0].ki.wVk = VK_SNAPSHOT; // 移除KEYEVENTF_EXTENDEDKEY标记 // 释放PrintScreen inputs[1].type = INPUT_KEYBOARD; inputs[1].ki.wVk = VK_SNAPSHOT; inputs[1].ki.dwFlags = KEYEVENTF_KEYUP; SendInput(2, inputs, sizeof(INPUT));
如果仍被拦截,说明游戏的低级钩子确实在检查LLKHF_INJECTED标记,SendInput的注入事件无法绕过,需更换截图方案。
三、替代截图方案(绕过GDI Hook)
1. 使用DXGI/Direct3D捕获屏幕
对于Direct3D渲染的游戏,DXGI提供的屏幕捕获能力不受GDI Hook影响,核心步骤:
- 初始化D3D设备并获取DXGI接口;
- 创建桌面输出副本;
- 循环捕获帧数据并转换为位图。
核心代码片段:
// 初始化D3D设备 ID3D11Device* pDevice = nullptr; D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, 0, nullptr, 0, D3D11_SDK_VERSION, &pDevice, nullptr, nullptr); // 获取DXGI设备接口 IDXGIDevice* pDxgiDevice = nullptr; pDevice->QueryInterface(__uuidof(IDXGIDevice), (void**)&pDxgiDevice); // 获取适配器与主显示器输出 IDXGIAdapter* pAdapter = nullptr; pDxgiDevice->GetParent(__uuidof(IDXGIAdapter), (void**)&pAdapter); IDXGIOutput* pOutput = nullptr; pAdapter->EnumOutputs(0, &pOutput); // 创建桌面副本 IDXGIOutputDuplication* pOutputDupl = nullptr; pOutput->DuplicateOutput(pDevice, &pOutputDupl); // 捕获帧 DXGI_OUTDUPL_FRAME_INFO frameInfo; IDXGIResource* pDesktopResource = nullptr; pOutputDupl->AcquireNextFrame(INFINITE, &frameInfo, &pDesktopResource);
2. 使用Windows.Graphics.Capture(Win10 1809+)
这是WinRT提供的现代屏幕捕获API,支持捕获整个屏幕或特定窗口,不受传统Hook影响。C语言可通过COM接口调用,核心逻辑:
- 用
GraphicsCapturePicker选择捕获目标; - 创建
GraphicsCaptureSession启动捕获; - 通过
Direct3D11CaptureFramePool获取帧数据。
3. 尝试PrintWindow API
如果游戏窗口未限制,可尝试直接捕获窗口内容:
HWND gameWnd = FindWindowA(nullptr, "游戏窗口标题"); // 替换为实际窗口标题 HDC hdcScreen = GetDC(nullptr); HDC hdcMem = CreateCompatibleDC(hdcScreen); RECT rect; GetWindowRect(gameWnd, &rect); HBITMAP hBitmap = CreateCompatibleBitmap(hdcScreen, rect.right - rect.left, rect.bottom - rect.top); SelectObject(hdcMem, hBitmap); PrintWindow(gameWnd, hdcMem, PW_CLIENTONLY); // 后续将hBitmap保存到文件或剪贴板 DeleteDC(hdcMem); ReleaseDC(nullptr, hdcScreen); DeleteObject(hBitmap);
四、其他注意事项
- 确保程序以管理员权限运行,部分游戏会限制非管理员进程的截图操作;
- 若游戏使用反作弊系统,需确保截图行为符合用户协议。
内容的提问来源于stack exchange,提问作者Aravind A
相关产品推荐
相关产品推荐

