Thread: GDI BitBlt Screenshot + BMP corruption

  1. #1
    Registered User
    Join Date
    Dec 2006

    GDI BitBlt Screenshot + BMP corruption

    As mentioned in this thread - Video-based remote desktop , I'm trying to implement screen capturing using GDI BitBlt. I've simplified it down to single capture and store as BMP.

    It looks like it's ALMOST working, but there is some corruption going on, and I'm not sure where that came from.

    Can someone please have a look?

    Minimum compilable code, no special setup required -
    #include <iostream>
    #include <fstream>
    #include <cstdint>
    #include <cassert>
    #include <Windows.h>
    int main()
    	HDC screen = GetDC(NULL);
    	HDC target = CreateCompatibleDC(screen);
    	uint32_t width = GetSystemMetrics(SM_CXSCREEN);
    	uint32_t height = GetSystemMetrics(SM_CYSCREEN);
    	HBITMAP bmp = CreateCompatibleBitmap(screen, width, height);
    	SelectObject(target, bmp);
    	int ret = 0;
    	ret = BitBlt(target, 0, 0, width, height, screen, 0, 0, SRCCOPY | CAPTUREBLT);
    	BITMAPINFO bminfo;
    	bminfo.bmiHeader.biBitCount = 32;
    	bminfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    	bminfo.bmiHeader.biCompression = BI_RGB;
    	bminfo.bmiHeader.biPlanes = 1;
    	bminfo.bmiHeader.biWidth = width;
    	bminfo.bmiHeader.biHeight = height;
    	bminfo.bmiHeader.biSizeImage = width * 4 * height; // must be DWORD aligned
    	bminfo.bmiHeader.biXPelsPerMeter = 0;
    	bminfo.bmiHeader.biYPelsPerMeter = 0;
    	bminfo.bmiHeader.biClrUsed = 0;
    	bminfo.bmiHeader.biClrImportant = 0;
    	// get bitmap info from the bitmap
    	//ret = GetDIBits(mTarget, mBmp, 0, mHeight, NULL, (BITMAPINFO *) &bminfo, DIB_RGB_COLORS);
    	uint8_t *bmpBuffer = new uint8_t[bminfo.bmiHeader.biSizeImage];
    	// real capture
    	ret = GetDIBits(target, bmp, 0, height, bmpBuffer, &bminfo, DIB_RGB_COLORS);
    	fheader.bfType = 0x4D42;
    	fheader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + bminfo.bmiHeader.biSizeImage;
    	fheader.bfReserved1 = 0;
    	fheader.bfReserved2 = 0;
    	fheader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
    	std::ofstream bmp_file("test.bmp");
    	bmp_file.write((const char *) &fheader, sizeof(fheader));
    	bmp_file.write((const char *) &(bminfo.bmiHeader), sizeof(bminfo.bmiHeader));
    	bmp_file.write((const char *) bmpBuffer, bminfo.bmiHeader.biSizeImage);
    	std::cout << "done" << std::endl;
    	return true;
    It should capture your primary screen, and generate a bmp in your working directory.

    Attached is the output image (BMP in ZIP, because I want to preserve the BMP byte by byte).

    I've tried it on 2 computers with the same result.

    Attached Images Attached Images GDI BitBlt Screenshot + BMP corruption-test-jpg 
    Attached Files Attached Files

  2. #2
    Registered User
    Join Date
    Dec 2006

    Turns out Windows ofstream opens files in ASCII mode by default...
    std::ofstream bmp_file("test.bmp", std::ios_base::binary);

  3. #3
    Super Moderator VirtualAce's Avatar
    Join Date
    Aug 2001
    Also remember that each scan line in BMPs are byte padded to the nearest 4 byte boundary. If you do not take this into account your code will only work when the image sizes are a multiple of 4. Also BMPs are stored bottom,right to top,left in BGRX order.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. BitBlt
    By abraham2119 in forum Windows Programming
    Replies: 8
    Last Post: 08-28-2010, 10:44 PM
  2. BitBlt()
    By Gordon in forum Windows Programming
    Replies: 2
    Last Post: 05-29-2008, 12:38 AM
  3. BitBlt
    By Gordon in forum Windows Programming
    Replies: 3
    Last Post: 10-05-2007, 03:11 PM
  4. Using BitBlt
    By Frantic- in forum Windows Programming
    Replies: 4
    Last Post: 08-31-2005, 06:47 PM
  5. BitBlt (Yet Again)
    By bartybasher in forum Windows Programming
    Replies: 9
    Last Post: 09-27-2003, 10:58 AM