I am using this code to capture screen and cursor.
// 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
}
}
The Screen Capture works perfectly , but always fails after screen capture of just more than 8 mins and 30 seconds. After 8 min and 30 seconds GetDIBits starts to return 0 . I am running this on a 64bit machine with windows 10 professional ediiton. This Issue seems to not apear if i remove the cursor capturing code .
DeleteObject(info.hbmColor);
DeleteObject(info.hbmMask);
Adding these lines did the trick. Thanks to Raymond Chen and IInspectable