9

Possible Duplicate:
how to make screen screenshot with win32 in c++?

I am currently trying to create an application that saved a portion of the screen to a bmp. I have found BitBlt but I really don't know what to do with it. I have tried searching for some answers but I still haven't found a clarifying one using C++.

So, basically I want this function:

bool capturePartScreen(int x, int y, int w int, h, string dest){
    //Capture part of screen according to coordinates, width and height.
    //Save that captured image as a bmp to dest.
    //Return true if success, false if failure
}

BitBlt:

BOOL BitBlt(
    __in  HDC hdcDest,
    __in  int nXDest,
    __in  int nYDest,
    //The three above are the ones I don't understand!
    __in  int nWidth,
    __in  int nHeight,
    __in  HDC hdcSrc,
    __in  int nXSrc,
    __in  int nYSrc,
    __in  DWORD dwRop
);

What should that hdc be and how do I obtain the bmp?

Community
  • 1
  • 1
Anton
  • 1,435
  • 2
  • 10
  • 21
  • 1
    Look at this [SO question](http://stackoverflow.com/questions/3291167/how-to-make-screen-screenshot-with-win32-in-c). – Jesse Good Mar 01 '12 at 21:48
  • Check out this [question](http://stackoverflow.com/questions/5292700/efficiently-acquiring-a-screenshot-of-the-windows-desktop), it should point you in the right direction –  Mar 01 '12 at 22:30
  • @Jesse: Thanks, that post helped me out quite a bit :) – Anton Mar 01 '12 at 23:25
  • 2
    Not an exact duplicate, since a key part of the question is how to get the bitmap into a file. The other question does not address that at all. – Adrian McCarthy Mar 01 '12 at 23:43
  • Indeed.. Well, at least I managed to post an answer before it was closed :/ – Anton Mar 01 '12 at 23:49
  • 1
    This is not a duplicate at all - aside from the file saving, this question asks about capturing *part* of a screen whereas the linked question asks about capturing the *entire* screen. Trigger-happy question closing is annoying. – JBentley Mar 21 '13 at 19:40

2 Answers2

21

It took a while, but I have now finally ended up with a functioning script.

Requirements:

#include <iostream>
#include <ole2.h>
#include <olectl.h>

Also you might(?) have to add ole32, oleaut32 and uuid to your linker.

screenCapturePart:

bool screenCapturePart(int x, int y, int w, int h, LPCSTR fname){
    HDC hdcSource = GetDC(NULL);
    HDC hdcMemory = CreateCompatibleDC(hdcSource);

    int capX = GetDeviceCaps(hdcSource, HORZRES);
    int capY = GetDeviceCaps(hdcSource, VERTRES);

    HBITMAP hBitmap = CreateCompatibleBitmap(hdcSource, w, h);
    HBITMAP hBitmapOld = (HBITMAP)SelectObject(hdcMemory, hBitmap);

    BitBlt(hdcMemory, 0, 0, w, h, hdcSource, x, y, SRCCOPY);
    hBitmap = (HBITMAP)SelectObject(hdcMemory, hBitmapOld);

    DeleteDC(hdcSource);
    DeleteDC(hdcMemory);

    HPALETTE hpal = NULL;
    if(saveBitmap(fname, hBitmap, hpal)) return true;
    return false;
}

saveBitmap:

bool saveBitmap(LPCSTR filename, HBITMAP bmp, HPALETTE pal)
{
    bool result = false;
    PICTDESC pd;

    pd.cbSizeofstruct   = sizeof(PICTDESC);
    pd.picType      = PICTYPE_BITMAP;
    pd.bmp.hbitmap  = bmp;
    pd.bmp.hpal     = pal;

    LPPICTURE picture;
    HRESULT res = OleCreatePictureIndirect(&pd, IID_IPicture, false,
                       reinterpret_cast<void**>(&picture));

    if (!SUCCEEDED(res))
    return false;

    LPSTREAM stream;
    res = CreateStreamOnHGlobal(0, true, &stream);

    if (!SUCCEEDED(res))
    {
    picture->Release();
    return false;
    }

    LONG bytes_streamed;
    res = picture->SaveAsFile(stream, true, &bytes_streamed);

    HANDLE file = CreateFile(filename, GENERIC_WRITE, FILE_SHARE_READ, 0,
                 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);

    if (!SUCCEEDED(res) || !file)
    {
    stream->Release();
    picture->Release();
    return false;
    }

    HGLOBAL mem = 0;
    GetHGlobalFromStream(stream, &mem);
    LPVOID data = GlobalLock(mem);

    DWORD bytes_written;

    result   = !!WriteFile(file, data, bytes_streamed, &bytes_written, 0);
    result  &= (bytes_written == static_cast<DWORD>(bytes_streamed));

    GlobalUnlock(mem);
    CloseHandle(file);

    stream->Release();
    picture->Release();

    return result;
}
Anton
  • 1,435
  • 2
  • 10
  • 21
  • 1
    For those getting E_UNEXPECTED after OleCreatePictureIndirect, I forgot to set PICTDESC.picType to PICTYPE_BMP. – CS. Apr 27 '13 at 16:08
  • 1
    Just a note for future readers... In that first code block `screenCapturePart` the bit that reads `BitBlt(hdcMemory, 0, 0, w, h, hdcSource, x, x, SRCCOPY);` should actually be `BitBlt(hdcMemory, 0, 0, w, h, hdcSource, x, y, SRCCOPY);`. – Chris Barlow Feb 06 '14 at 22:29
  • 1
    @ChrisBarlow Fixed, thanks for noticing and telling! – Anton Feb 08 '14 at 20:45
  • Thanks a lot! I SO did not want to figure that out for myself. One note, I was getting `cannot convert argument from 'LPCSTR' to 'LPCWSTR'` which I fixed by using `CreateFileA` instead of `CreateFile`. – user875234 Nov 01 '18 at 15:52
3

You can use GetDC(NULL) to get the device context for the entire screen, then use that with BitBlt as the source device context.

As for the rest of what to do:

Bitmap Creation (Windows)

Bitmap Storage (Windows)

MSN
  • 53,214
  • 7
  • 75
  • 105
  • Yes I know, but what I don't understand is how to define the destination hdc. How do I go from a hdc to a bmp? Sorry for not clarifying that. – Anton Mar 01 '12 at 21:35