I create a screenshot from the desktop and receive a vector with the pixel data, but I am having problems when trying to draw the pixel data on my screen.
CODE TO CREATE SCREENSHOT SNIPPET
std::vector<RGBQUAD> recvScreenSnippet(int x, int y, int width, int height) {
std::vector<RGBQUAD> v_screen_data(width*height);
HDC screen_dc = GetDC(NULL);
HDC mem_dc = CreateCompatibleDC(NULL);
HBITMAP hBmp = CreateCompatibleBitmap(screen_dc, width, height);
auto oldBmp = SelectObject(mem_dc, hBmp);
// 32 bit & Upside Down headers
BITMAPINFO bmi{};
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = BI_RGB;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biHeight = height;
bmi.bmiHeader.biWidth = width;
bmi.bmiHeader.biSize = sizeof(BITMAPINFO);
// Receive pixel data from hdc
BitBlt(mem_dc, 0, 0, width, height, screen_dc, x, y, SRCCOPY);
GetDIBits(mem_dc, hBmp, 0, height, &v_screen_data[0], &bmi, DIB_RGB_COLORS);
// Cleanup
SelectObject(mem_dc, oldBmp);
DeleteObject(hBmp);
DeleteDC(mem_dc);
ReleaseDC(0, screen_dc);
return v_screen_data;
}
CODE TO PAINT THE PIXEL DATA ON MY SCREEN:
void setScreenSnippet(int x, int y, int width, int height, std::vector<RGBQUAD> &v_pixel_data) {
HDC screen_dc = GetDC(0);
HDC mem_dc = CreateCompatibleDC(0);
// 32 bit & Upside Down headers
BITMAPINFO bmi{};
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = BI_RGB;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biHeight = height;
bmi.bmiHeader.biWidth = width;
bmi.bmiHeader.biSize = sizeof(BITMAPINFO);
// Create bitmap
HBITMAP bitmap = CreateCompatibleBitmap(mem_dc,width,height);
// Store pixel data in bitmap
SetDIBits(mem_dc, bitmap, 0, height, &v_pixel_data[0], &bmi, DIB_RGB_COLORS);
// Select bitmap data into mem_dc
SelectObject(mem_dc, bitmap);
while (true)
{
BitBlt(screen_dc, x, y, width, height, mem_dc, 0, 0, SRCCOPY);
Sleep(1);
}
// Cleanup
SelectObject(mem_dc, bitmap);
DeleteObject(bitmap);
ReleaseDC(0, screen_dc);
}
HOW I AM CALLING IT
int main()
{
Sleep(5000);
std::vector<RGBQUAD> v_pixel_data = recvScreenSnippet(600,600,400,400);
setScreenSnippet(100, 600, 400, 400, v_pixel_data);
system("pause"), exit(1);
}
The issue is that the painted screenshot is black on the top, which means that something is not working.
What am I doing wrong?
First of all, I have to apologize that I have used C++ only in bare metal projects where no standard library functions (
std::...) were used, so my knowledge of these functions is very limited.However, let's look at the following code:
Not knowing much about the
std::vectordata type, I cannot tell you what "line 2" is doing; maybe the size of thevectorexample1is changed so it has at least 21 elements.However, I can definitely tell you what happens in "lines 3 and 4":
In line 3, a pointer to the element
[0]of thevectoris generated.In line 4, an operation on the pointer (but not on the
vector) is performed. This means that the compiler does not know that this operation accesses an element in theexample2vector.For this reason, the compiler definitely does not re-size the
vectorin this line.If the
vectorexample2was already larger than 300 elements, "line 4" will write toexample2[300]; if it was smaller than 301 elements, this line of code will write to anywhere in the RAM and may crash your program because of overwriting important data (such as the return addresses on the stack).For this reason, you must ensure that
example2is already larger than 300 elements before accessingpExample[300].What does this have to do with your problem?
Windows API functions perform pointer operations, not
vectoroperations.This means:
GetDIBits()internally works like this:For this reason, you must ensure that the vector
v_pixel_dataalready has a size of at leastwidth * heightelements before you callGetDIBits().Windows stores the bottom pixels first and the top pixels last.
Maybe, your
vectorwas large enough to hold a part of the image but not the full image.