GetDIBits在屏幕捕获功能中多次迭代后返回零

问题描述 投票:0回答:1

我正在使用此代码捕获屏幕和光标。

// 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位计算机上运行此程序。如果删除游标捕获代码,似乎不会出现此问题。

c++ winapi gdi getdibits
1个回答
0
投票
DeleteObject(info.hbmColor);
DeleteObject(info.hbmMask);
DeleteObject(cursor.hCursor);

添加这些行就可以了。感谢Raymond ChenIInspectable

© www.soinside.com 2019 - 2024. All rights reserved.