【发布时间】:2017-09-09 04:03:45
【问题描述】:
使用 Visual Studio 2017,vc141,以下代码应该从游戏前窗口获取屏幕截图,但现在它返回一个黑色和空白的图像。
只有游戏有问题(试过 OpenGL 和 Vulkan,ogl 返回黑色,vulkan 返回白色)
在升级到 windows 10 1703 之前,它适用于 windows 10 1607 和 windows 7 sp1
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
代码:
BOOL ScreenShot(cv::Mat *img, HWND hWnd = NULL) {
HBITMAP hBitmap;
HDC hdcSys = GetDC(hWnd);
HDC hdcMem = CreateCompatibleDC(hdcSys);
void *ptrBitmapPixels;
BITMAPINFO bi;
HDC hdc;
RECT rect;
if (!GetWindowRect(hWnd, &rect) || (hWnd == NULL)) {
return FALSE;
}
ZeroMemory(&bi, sizeof(BITMAPINFO));
LONG lWidth = rect.right - rect.left;
LONG lHeight = rect.bottom - rect.top;
bi.bmiHeader.biSize = sizeof(BITMAPINFO);
bi.bmiHeader.biWidth = lWidth;
bi.bmiHeader.biHeight = -lHeight;
bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biBitCount = 32;
hdc = GetDC(hWnd);
hBitmap = CreateDIBSection(hdc, &bi, DIB_RGB_COLORS, &ptrBitmapPixels, NULL, 0);
SelectObject(hdcMem, hBitmap);
*img = cv::Mat(lHeight, lWidth, CV_8UC4, ptrBitmapPixels, 0);
BitBlt(hdcMem, 0, 0, lWidth, lHeight, hdcSys, 0, 0, SRCCOPY);
//DeleteObject(hBitmap);
DeleteDC(hdcMem);
ReleaseDC(hWnd, hdcSys);
ReleaseDC(hWnd, hdc);
return TRUE;
}
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
/*...*/
HotKeyId = GlobalAddAtom(L"DBKGNDSCREENSHOT");
RegisterHotKey(hWnd, HotKeyId, NULL, VK_F10);
/*...*/
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
/*...*/
case WM_HOTKEY:
if (wParam == HotKeyId) {
cv::Mat t;
HWND MainHWND;
MainHWND = GetForegroundWindow();
ScreenShot(&t, MainHWND);
cv::imshow("1", t);
}
break;
/*...*/
}
甚至 PrintWindow 仍然是黑色的(至少我们有一个标题栏)
PrintWindow(hWnd, hdcMem, 0);
//BitBlt(hdcMem, 0, 0, lWidth, lHeight, hdcSys, 0, 0, SRCCOPY);
我将此程序发送给我的朋友(没有任何修改,他的 OS=win7 x64),但他得到了正确的结果。
那我该怎么办?
【问题讨论】:
-
不应该在之前调用
BitBlt调用cv::Mat吗? -
你肯定需要打电话给
GetClientRect而不是GetWindowRect。否则你的位图会比 hdcSys 和 hdcMem 的实际内容大。 -
谢谢,但问题是我现在无法获取位图。该代码在升级系统之前没有问题。我只是安装了新版本的“obs-studio”,窗口盖模块给出了与我相同的结果。我打算让我朋友测试一下。
-
查看
BitBlt的返回值。如果它返回FALSE,那么随后对GetLastError()的调用什么时候返回? -
@selbie BitBlt 返回 1 (TRUE),GetLastError() 返回 0(无错误)