I would like to take a screenshot of a region of my screen programmatically (so I can do it every time through a loop, for example.) Does anyone know how to do this? I guess it would involve the win32api - I've not used this before so any hints would be great!

Thanks,

Dave

I would like to take a screenshot of a region of my screen programmatically (so I can do it every time through a loop, for example.) Does anyone know how to do this? I guess it would involve the win32api - I've not used this before so any hints would be great!

Thanks,

Dave

You can use the windows GDI functions. You'll need to include the GDI library, and windows.h.

GetDC(0) returns the device context of the screen. You can copy the screen to a bitmap you create with CreateBitmap, or CreateCompatibleBitmap using BitBlt.

Here's an example of copying the screen onto itself (very simplistic, but shows it's working)

BitBlt(GetDC(0), 300, 300, 300, 300, GetDC(0), 0, 0, SRCCOPY);

dougy83, thanks, i'll take a look

niek_e - that example seems to use a sendkeys printscreen type of thing - i was thinking more along the lines of selecting a region to capture

i'll report back on the GDI stuff - dougy83, how would I save that to a file?

dougy83 - how do i save it to a file? I have the simple example of just writing it back to the screen working so far!

Thanks,

Dave

You can do something like try to give the computer coordinates and then take a whole screenshot of your computer After that cut of all other parts except the selected coordinates.

OOPS LATE ANSWER

dougy83, thanks, i'll take a look

niek_e - that example seems to use a sendkeys printscreen type of thing - i was thinking more along the lines of selecting a region to capture

i'll report back on the GDI stuff - dougy83, how would I save that to a file?

Sorry david for not writing, i's busy.

While that example might use the clipboard, the bmp saving part is still relevant for what you want to do. You would just have to copy the screen to a memory bitmap you create.

Here's a working example for you to use; hope it's of use.

#include <windows.h>

bool SaveBMPFile(char *filename, HBITMAP bitmap, HDC bitmapDC, int width, int height);

bool ScreenCapture(int x, int y, int width, int height, char *filename){
   // get a DC compat. w/ the screen
   HDC hDc = CreateCompatibleDC(0);    
   
   // make a bmp in memory to store the capture in
   HBITMAP hBmp = CreateCompatibleBitmap(GetDC(0), width, height);   
   
   // join em up
   SelectObject(hDc, hBmp);   
   
   // copy from the screen to my bitmap
   BitBlt(hDc, 0, 0, width, height, GetDC(0), x, y, SRCCOPY);  
   
   // save my bitmap
   bool ret = SaveBMPFile(filename, hBmp, hDc, width, height); 
   
   // free the bitmap memory
   DeleteObject(hBmp);  
   
   return ret;
   }
   
main(){
   ScreenCapture(500, 200, 300, 300, "c:\\testScreenCap.bmp");
   system("pause");
   }

The SaveBMPFile function referenced above is attached (I didn't write it), or you could cut-and-paste from the 'printscreen'-type example code.

Attachments
//---------------------------------------------------------------------------
//    Based on:
//    Screenshot - Author: Michael Ftsch; Date: May 31, 2000
//
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
#include <windows.h>

// Helper function to retrieve current position of file pointer:
inline int GetFilePointer(HANDLE FileHandle){
	return SetFilePointer(FileHandle, 0, 0, FILE_CURRENT);
	}
//---------------------------------------------------------------------------

// Screenshot
//    -> FileName: Name of file to save screenshot to
//    -> lpDDS: DirectDraw surface to capture
//    <- Result: Success
//
extern bool SaveBMPFile(char *filename, HBITMAP bitmap, HDC bitmapDC, int width, int height){
    bool Success=false;
    HDC SurfDC=NULL;        // GDI-compatible device context for the surface
    HBITMAP OffscrBmp=NULL; // bitmap that is converted to a DIB
    HDC OffscrDC=NULL;      // offscreen DC that we can select OffscrBmp into
    LPBITMAPINFO lpbi=NULL; // bitmap format info; used by GetDIBits
    LPVOID lpvBits=NULL;    // pointer to bitmap bits array
    HANDLE BmpFile=INVALID_HANDLE_VALUE;    // destination .bmp file
    BITMAPFILEHEADER bmfh;  // .bmp file header

    // We need an HBITMAP to convert it to a DIB:
    if ((OffscrBmp = CreateCompatibleBitmap(bitmapDC, width, height)) == NULL)
        return false;

    // The bitmap is empty, so let's copy the contents of the surface to it.
    // For that we need to select it into a device context. We create one.
    if ((OffscrDC = CreateCompatibleDC(bitmapDC)) == NULL)
		return false;

    // Select OffscrBmp into OffscrDC:
    HBITMAP OldBmp = (HBITMAP)SelectObject(OffscrDC, OffscrBmp);

    // Now we can copy the contents of the surface to the offscreen bitmap:
    BitBlt(OffscrDC, 0, 0, width, height, bitmapDC, 0, 0, SRCCOPY);

    // GetDIBits requires format info about the bitmap. We can have GetDIBits
    // fill a structure with that info if we pass a NULL pointer for lpvBits:
    // Reserve memory for bitmap info (BITMAPINFOHEADER + largest possible
    // palette):
    if ((lpbi = (LPBITMAPINFO)(new char[sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)])) == NULL) 
		return false;


    ZeroMemory(&lpbi->bmiHeader, sizeof(BITMAPINFOHEADER));
    lpbi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    // Get info but first de-select OffscrBmp because GetDIBits requires it:
    SelectObject(OffscrDC, OldBmp);
    if (!GetDIBits(OffscrDC, OffscrBmp, 0, height, NULL, lpbi, DIB_RGB_COLORS))
        return false;

    // Reserve memory for bitmap bits:
    if ((lpvBits = new char[lpbi->bmiHeader.biSizeImage]) == NULL)
        return false;

    // Have GetDIBits convert OffscrBmp to a DIB (device-independent bitmap):
    if (!GetDIBits(OffscrDC, OffscrBmp, 0, height, lpvBits, lpbi, DIB_RGB_COLORS))
		return false;

    // Create a file to save the DIB to:
    if ((BmpFile = CreateFile(filename,
                              GENERIC_WRITE,
                              0, NULL,
                              CREATE_ALWAYS,
                              FILE_ATTRIBUTE_NORMAL,
                              NULL)) == INVALID_HANDLE_VALUE)
							  
							  return false;

    DWORD Written;    // number of bytes written by WriteFile
    
    // Write a file header to the file:
    bmfh.bfType = 19778;        // 'BM'
    // bmfh.bfSize = ???        // we'll write that later
    bmfh.bfReserved1 = bmfh.bfReserved2 = 0;
    // bmfh.bfOffBits = ???     // we'll write that later
    if (!WriteFile(BmpFile, &bmfh, sizeof(bmfh), &Written, NULL))
        return false;

    if (Written < sizeof(bmfh)) 
		return false; 

    // Write BITMAPINFOHEADER to the file:
    if (!WriteFile(BmpFile, &lpbi->bmiHeader, sizeof(BITMAPINFOHEADER), &Written, NULL)) 
		return false;
	
    if (Written < sizeof(BITMAPINFOHEADER)) 
			return false;

    // Calculate size of palette:
    int PalEntries;
    // 16-bit or 32-bit bitmaps require bit masks:
    if (lpbi->bmiHeader.biCompression == BI_BITFIELDS) 
		PalEntries = 3;
    else
        // bitmap is palettized?
        PalEntries = (lpbi->bmiHeader.biBitCount <= 8) ?
            // 2^biBitCount palette entries max.:
            (int)(1 << lpbi->bmiHeader.biBitCount)
        // bitmap is TrueColor -> no palette:
        : 0;
    // If biClrUsed use only biClrUsed palette entries:
    if(lpbi->bmiHeader.biClrUsed) 
		PalEntries = lpbi->bmiHeader.biClrUsed;

    // Write palette to the file:
    if(PalEntries){
        if (!WriteFile(BmpFile, &lpbi->bmiColors, PalEntries * sizeof(RGBQUAD), &Written, NULL)) 
			return false;

        if (Written < PalEntries * sizeof(RGBQUAD)) 
			return false;
		}

    // The current position in the file (at the beginning of the bitmap bits)
    // will be saved to the BITMAPFILEHEADER:
    bmfh.bfOffBits = GetFilePointer(BmpFile);

    // Write bitmap bits to the file:
    if (!WriteFile(BmpFile, lpvBits, lpbi->bmiHeader.biSizeImage, &Written, NULL)) 
		return false;
	
    if (Written < lpbi->bmiHeader.biSizeImage) 
		return false;

    // The current pos. in the file is the final file size and will be saved:
    bmfh.bfSize = GetFilePointer(BmpFile);

    // We have all the info for the file header. Save the updated version:
    SetFilePointer(BmpFile, 0, 0, FILE_BEGIN);
    if (!WriteFile(BmpFile, &bmfh, sizeof(bmfh), &Written, NULL))
        return false;

    if (Written < sizeof(bmfh)) 
		return false;

    return true;
	}

is it possible to write a program in C(only C) for windows to capture the screen and save it as a picture. if yes please share your work such that i can enhance my knowledge..

i changed cpp code to C... in that process i did few changes like changing "new" keyword with malloc(saveBMP.cpp) but no use...

#include <windows.h>
#include <stdio.h>

#define GetPixel(Bmp, X, Y) (((Bmp)->Pixels[(Y) * (Bmp)->Width + (X)]) & 0x00FFFFFF)
#define PixelToColour(Pixel) (COLORREF)(((Pixel) & 0xFF00FF00) | (((Pixel) & 0xFF0000) >> 16) | (((Pixel) & 0xFF) << 16))

typedef struct
{
    HBITMAP hBmp;
    int Width, Height;
    unsigned int* Pixels;
    unsigned short BitsPerPixel;
} BmpData;

typedef enum {false = 0, true = 1} bool;

bool ScreenShot(BmpData* Data)
{
    bool Result = false;
    memset(Data, 0, sizeof(BmpData));
    HDC hdcScreen = GetDC(NULL);
    HDC hdcMem = CreateCompatibleDC(NULL);
    Data->Width = GetDeviceCaps(hdcScreen, HORZRES);
    Data->Height = GetDeviceCaps(hdcScreen, VERTRES);

    unsigned char* Pixels = NULL;
    unsigned short BitsPerPixel = 32;
    BITMAPINFO Info = {{sizeof(BITMAPINFOHEADER), Data->Width, -Data->Height, 1, BitsPerPixel, BI_RGB, 0, 0, 0, 0, 0}};

    Data->hBmp = CreateDIBSection(hdcScreen, &Info, DIB_RGB_COLORS, (void**)&Pixels, NULL, 0);
    if(Data->hBmp)
    {
        HBITMAP hOld = (HBITMAP)SelectObject(hdcMem, Data->hBmp);
        BitBlt(hdcMem, 0, 0, Data->Width, Data->Height, hdcScreen, 0, 0, SRCCOPY);
        SelectObject(hdcMem, hOld);
        Data->Height *= -1;
        Data->BitsPerPixel = BitsPerPixel;
        Data->Pixels = (unsigned int*)Pixels;
        Result = true;
    }

    DeleteDC(hdcMem);
    DeleteDC(hdcScreen);
    return Result;
}

void SaveBitmap(const char* FilePath, const BmpData* Data)
{
    FILE* hFile = fopen(FilePath, "wb+");
    if (!hFile)
    {
        printf("%s", "Error. Cannot Create Bitmap.");
        return;
    }

    unsigned int Trash = 0;
    unsigned short Planes = 1;
    unsigned int biSize = 40;
    unsigned short Type = 0x4D42;
    unsigned int compression = 0;
    unsigned int PixelsOffsetBits = 54;
    int Width = Data->Width;
    int Height = -Data->Height;
    unsigned short BitsPerPixel = Data->BitsPerPixel;
    unsigned int size = ((Width * BitsPerPixel + 31) / 32) * 4 * Height;
    unsigned int bfSize = 54 + size;
    Height *= -1;

    fwrite(&Type, sizeof(char), sizeof(Type), hFile);
    fwrite(&bfSize, sizeof(char), sizeof(bfSize), hFile);
    fwrite(&Trash, sizeof(char), sizeof(Trash), hFile);
    fwrite(&PixelsOffsetBits, sizeof(char), sizeof(PixelsOffsetBits), hFile);
    fwrite(&biSize, sizeof(char), sizeof(biSize), hFile);
    fwrite(&Width, sizeof(char), sizeof(Width), hFile);
    fwrite(&Height, sizeof(char), sizeof(Height), hFile);
    fwrite(&Planes, sizeof(char), sizeof(Planes), hFile);
    fwrite(&BitsPerPixel, sizeof(char), sizeof(BitsPerPixel), hFile);
    fwrite(&compression, sizeof(char), sizeof(compression), hFile);
    fwrite(&size, sizeof(char), sizeof(size), hFile);
    fwrite(&Trash, sizeof(char), sizeof(Trash), hFile);
    fwrite(&Trash, sizeof(char), sizeof(Trash), hFile);
    fwrite(&Trash, sizeof(char), sizeof(Trash), hFile);
    fwrite(&Trash, sizeof(char), sizeof(Trash), hFile);
    fwrite(&Data->Pixels, sizeof(char), size, hFile);
    fclose(hFile);
}

int main()
{
    int X = 15, Y = 16;
    BmpData Data = {0};
    ScreenShot(&Data);
    printf("The colour at: (%i, %i) is: %lu\n\n", X, Y, PixelToColour(GetPixel(&Data, X, Y)));
    SaveBitmap("C:/Users/Brandon/Desktop/Foo.bmp", &Data);
    DeleteObject(Data.hBmp);
    return 0;
}

Everything works except the stupid SaveBitmap. I'm not sure why it won't save properly but I translated it from my C++ code below which works

void SaveBitmap(const char* FilePath, const BmpData* Data)
{
    std::fstream hFile(FilePath, std::ios::out | std::ios::binary);
    if (!hFile.is_open())
    {
        printf("%s", "Error. Cannot Create Bitmap.");
        return;
    }

    unsigned int Trash = 0;
    unsigned short Planes = 1;
    unsigned int biSize = 40;
    unsigned short Type = 0x4D42;
    unsigned int compression = 0;
    unsigned int PixelsOffsetBits = 54;
    int Width = Data->Width;
    int Height = -Data->Height;
    unsigned short BitsPerPixel = Data->BitsPerPixel;
    unsigned int size = ((Width * BitsPerPixel + 31) / 32) * 4 * Height;
    unsigned int bfSize = 54 + size;
    Height *= -1;

    hFile.write(reinterpret_cast<char*>(&Type), sizeof(Type));
    hFile.write(reinterpret_cast<char*>(&bfSize), sizeof(bfSize));
    hFile.write(reinterpret_cast<char*>(&Trash), sizeof(Trash));
    hFile.write(reinterpret_cast<char*>(&PixelsOffsetBits), sizeof(PixelsOffsetBits));
    hFile.write(reinterpret_cast<char*>(&biSize), sizeof(biSize));
    hFile.write(reinterpret_cast<char*>(&Width), sizeof(Width));
    hFile.write(reinterpret_cast<char*>(&Height), sizeof(Height));
    hFile.write(reinterpret_cast<char*>(&Planes), sizeof(Planes));
    hFile.write(reinterpret_cast<char*>(&BitsPerPixel), sizeof(BitsPerPixel));
    hFile.write(reinterpret_cast<char*>(&compression), sizeof(compression));
    hFile.write(reinterpret_cast<char*>(&size), sizeof(size));
    hFile.write(reinterpret_cast<char*>(&Trash), sizeof(Trash));
    hFile.write(reinterpret_cast<char*>(&Trash), sizeof(Trash));
    hFile.write(reinterpret_cast<char*>(&Trash), sizeof(Trash));
    hFile.write(reinterpret_cast<char*>(&Trash), sizeof(Trash));
    hFile.write(reinterpret_cast<char*>(Data->Pixels), size);
    hFile.close();
}

Edited 2 Years Ago by triumphost

Everything works except the stupid SaveBitmap. I'm not sure why it won't save properly but I translated it from my C++ code below which works

Are you using a 64-bit OS and compiler? If so, all of your int types will be 8 bytes rather than 4. So try #including <cstdint>, and use the size-specific types, e.g. uint32_t, int32_t, etc. if this is the issue.

Edited 2 Years Ago by dougy83

I just downloaded the original code and after defining {bool, true, false} and replacing new with malloc it compiled and ran fine, creating the bmp on my desktop (note I had to change the save directory from "c:\" to a directory I have write access to). This was on a Win-7 32-bit system.

Note that the original savebitmap function doesn't free the allocated memory.

This article has been dead for over six months. Start a new discussion instead.