c++ - GetDIBits 在屏幕捕获函数中多次迭代后返回零
问题描述
我正在使用此代码来捕获屏幕和光标。
// ConsoleApplication1.cpp : This file contains the 'main' function. Program execution begins and ends there.
#include <Windows.h>
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>
using namespace std;
using namespace cv;
HWND hwndDesktop = NULL;
bool flg;
CURSORINFO cursor;
ICONINFOEXW info;
BITMAP bmpCursor;
HDC hwindowDC, hwindowCompatibleDC;
HBITMAP hbwindow;
int height, width, srcheight, srcwidth;
Mat src;
BITMAPINFOHEADER bi;
RECT windowsize;
Mat hwnd2mat(HWND hwnd)
{
src.create(height, width, CV_8UC4);
int val = 0;
// use the previously created device context with the bitmap
HGDIOBJ hPrevBitmap = SelectObject(hwindowCompatibleDC, hbwindow);
// copy from the window device context to the bitmap device context
val = StretchBlt(hwindowCompatibleDC, 0, 0, width, height, hwindowDC, 0, 0, srcwidth, srcheight, SRCCOPY); //change SRCCOPY to NOTSRCCOPY for wacky colors !
if (val <= 0) {
DWORD error_ = GetLastError();
cout << "error " << error_ << endl;
}
cursor = { sizeof(cursor) };
::GetCursorInfo(&cursor);
if (cursor.flags == CURSOR_SHOWING and flg) {
info = { sizeof(info) };
::GetIconInfoExW(cursor.hCursor, &info);
const int x = cursor.ptScreenPos.x - windowsize.left - info.xHotspot;
const int y = cursor.ptScreenPos.y - windowsize.top - info.yHotspot;
bmpCursor = { 0 };
val = ::GetObject(info.hbmColor, sizeof(bmpCursor), &bmpCursor);
val = ::DrawIconEx(hwindowCompatibleDC, x, y, cursor.hCursor, bmpCursor.bmWidth, bmpCursor.bmHeight,
0, NULL, DI_NORMAL);
if (val <= 0) {
DWORD error_ = GetLastError();
cout << "error " << error_ << endl;
flg = false;
}
}
val = GetDIBits(hwindowCompatibleDC, hbwindow, 0, height, src.data, (BITMAPINFO *)&bi, DIB_RGB_COLORS); //copy from hwindowCompatibleDC to hbwindow
if (val <= 0) {
DWORD error_ = GetLastError();
cout << "error " << error_ << endl;
GdiFlush();
flg = false;
}
SelectObject(hwindowCompatibleDC, hPrevBitmap);
return src;
}
int main(int argc, char **argv)
{
flg = true;
hwndDesktop = GetDesktopWindow();
namedWindow("output", WINDOW_NORMAL);
int key = 0;
hwindowDC = GetDC(hwndDesktop);
if (hwindowDC == NULL) {
DWORD error_ = GetLastError();
cout << "error " << error_ << endl;
}
hwindowCompatibleDC = CreateCompatibleDC(hwindowDC);
if (hwindowCompatibleDC == NULL) {
DWORD error_ = GetLastError();
cout << "error " << error_ << endl;
}
SetStretchBltMode(hwindowCompatibleDC, COLORONCOLOR);
GetClientRect(hwndDesktop, &windowsize);
srcheight = windowsize.bottom;
srcwidth = windowsize.right;
height = windowsize.bottom / 1; //change this to whatever size you want to resize to
width = windowsize.right / 1;
hbwindow = CreateCompatibleBitmap(hwindowDC, width, height);
if (hbwindow == NULL) {
DWORD error_ = GetLastError();
cout << "error " << error_ << endl;
}
bi.biSize = sizeof(BITMAPINFOHEADER); //http://msdn.microsoft.com/en-us/library/windows/window/dd183402%28v=vs.85%29.aspx
bi.biWidth = width;
bi.biHeight = -height; //this is the line that makes it draw upside down or not
bi.biPlanes = 1;
bi.biBitCount = 32;
bi.biCompression = BI_RGB;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;
while (key != 27)
{
Mat src = hwnd2mat(hwndDesktop);
// you can do some image processing here
imshow("output", src);
key = waitKey(1); // you can change wait time
}
}
屏幕截图完美运行,但在屏幕截图超过 8 分 30 秒后总是失败。8 分 30 秒后 GetDIBits 开始返回 0 。我在装有 Windows 10 专业版的 64 位机器上运行它。如果我删除光标捕获代码,此问题似乎不会出现。
解决方案
DeleteObject(info.hbmColor);
DeleteObject(info.hbmMask);
添加这些行就可以了。感谢Raymond Chen和IInspectable
推荐阅读
- swift - 更新 Facebook SDK 问题
- sql - 显示不同模式的所有表
- xamarin.android - InputFilter 行为不正确
- prometheus - 如何为所有指标添加额外标签
- r - 如何遍历循环
- distributed-computing - 将 Chapel 1.19 与 GASNet PSM (OmniPath) 基板一起使用时的问题
- python - 创建一个 Python 模块,其依赖项自包含
- python - 有和没有@tf.function 的不同行为
- mysql - 如何在 JPQL 选择查询中从新创建的对象中按值排序实体?
- azure - OpenLiberty Docker 映像示例应用程序无法正常工作