How to Take Screenshots of a Window with C++ in Windows

What is the best way to take screenshots of a Window with C++ in Windows?

You have to get the device context of the window (GetWindowDC()) and copy image (BitBlt()) from it. Depending on what else you know about the application you will use different methods to find which window's handle to pass into GetWindowDC().

C: take screenshot

Have you tried google? This forum entry has an example, complete with C source code using the Win32 API.

EDIT: Found a duplicate in the meantime: How can I take a screenshot and save it as JPEG on Windows?

C++ WinAPI screenshot of a window in the background

This can happen with many applications where the target window is simply a container and is not responsible for paint messages. Standard win32 applications like notepad don't behave as such. But you may run in to this problem with many browsers for example.

You can always take screenshot of desktop window. You can get the screen coordinate of target window, then bitblt that section of target window. Make the following changes to your code:

//GetClientRect(handle, &client_rect);
GetWindowRect(handle, &client_rect);

//HDC hdcScreen = GetDC(handle);
HDC hdcScreen = GetDC(HWND_DESKTOP);

//BitBlt(hdc, 0, 0, width, height, hdcScreen, 0, 0, SRCCOPY);
BitBlt(hdc, 0, 0, width, height, hdcScreen, client_rect.left, client_rect.top, SRCCOPY);

//ReleaseDC(NULL, hdcScreen);
ReleaseDC(HWND_DESKTOP, hdcScreen);

The target window must be top-most visible window on the screen before taking screen shot. For example you can call screenshot_window in this order:

HWND hwnd = FindWindow(0, L"Calculator");
SetForegroundWindow(hwnd);
Sleep(1000);
screenshot_window(hwnd);

Alternatively, you can use Dwm Thumbnail APIs to paint the target window in your own window. But again, you cannot use GetDC(my_hWnd) to access the bitmap from "Dwm Thumbnail" on your window. Again you would have to take screen shot of desktop window using GetDC(HWND_DESKTOP). This time make sure your own window is the top window.

Application must be DPI aware otherwise screen coordinates will not match.


Also there is a resource leak in the original code. GetDC should be cleaned up with ReleaseDC using the same handle, not NULL

HDC hdcScreen = GetDC(handle);
...
//ReleaseDC(NULL, hdcScreen);
ReleaseDC(handle, hdcScreen);

How to get screenshot of a window as bitmap object in C++?

you should call the PrintWindow API:

void CScreenShotDlg::OnPaint()
{
// device context for painting
CPaintDC dc(this);

// Get the window handle of calculator application.
HWND hWnd = ::FindWindow( 0, _T( "Calculator" ));

// Take screenshot.
PrintWindow( hWnd,
dc.GetSafeHdc(),
0 );
}

see this question: getting window screenshot windows API

if you are not using MFC, here the pure PrintWindow signature:

BOOL PrintWindow(
HWND hwnd,
HDC hdcBlt,
UINT nFlags
);

see MSDN for more details: http://msdn.microsoft.com/en-us/library/dd162869(v=vs.85).aspx

about how to save it as bitmap asMatteo said depends on the actual framework you are using...

EDIT:

here full example in raw C++

#define _WIN32_WINNT    0x0501        //xp
#include <windows.h>

int main()
{
RECT rc;
HWND hwnd = FindWindow(TEXT("Notepad"), NULL); //the window can't be min
if (hwnd == NULL)
{
cout << "it can't find any 'note' window" << endl;
return 0;
}
GetClientRect(hwnd, &rc);

//create
HDC hdcScreen = GetDC(NULL);
HDC hdc = CreateCompatibleDC(hdcScreen);
HBITMAP hbmp = CreateCompatibleBitmap(hdcScreen,
rc.right - rc.left, rc.bottom - rc.top);
SelectObject(hdc, hbmp);

//Print to memory hdc
PrintWindow(hwnd, hdc, PW_CLIENTONLY);

//copy to clipboard
OpenClipboard(NULL);
EmptyClipboard();
SetClipboardData(CF_BITMAP, hbmp);
CloseClipboard();

//release
DeleteDC(hdc);
DeleteObject(hbmp);
ReleaseDC(NULL, hdcScreen);

cout << "success copy to clipboard, please paste it to the 'mspaint'" << endl;

return 0;
}

How can I take a screenshot in a windows application?


HDC hScreenDC = GetDC(nullptr); // CreateDC("DISPLAY",nullptr,nullptr,nullptr);
HDC hMemoryDC = CreateCompatibleDC(hScreenDC);
int width = GetDeviceCaps(hScreenDC,HORZRES);
int height = GetDeviceCaps(hScreenDC,VERTRES);
HBITMAP hBitmap = CreateCompatibleBitmap(hScreenDC,width,height);
HBITMAP hOldBitmap = static_cast<HBITMAP>(SelectObject(hMemoryDC,hBitmap));
BitBlt(hMemoryDC,0,0,width,height,hScreenDC,0,0,SRCCOPY);
hBitmap = static_cast<HBITMAP>(SelectObject(hMemoryDC,hOldBitmap));
DeleteDC(hMemoryDC);
DeleteDC(hScreenDC);

Taking a screenshot of the Windows desktop with a C program.

Assuming Visual Studio:

This is copy & paste from working code (some lines ommited):

HDC     hdcScreen   = NULL;
HDC hdcMemDC = NULL;
HBITMAP hbmScreen = NULL;

CImage myimage;
IStream* pIStream = NULL;
STATSTG stg;
HGLOBAL hGlobal = NULL;
HRESULT hResult = 0;

UINT nDataSize = 0;

do
{
//
// Get the screen capture in an HBITMAP.
// -------------------------------------
// Retrieve the handle to a display device context for the client
// area of the window.
hdcScreen = ::GetDC(NULL);
if ( hdcScreen == NULL )
{
SET_CHECKPOINT();
break;
}

// Create a compatible DC which is used in a BitBlt from the window DC
hdcMemDC = CreateCompatibleDC(hdcScreen);
if ( hdcMemDC == NULL )
{
SET_CHECKPOINT();
break;
}

// Get the client area for size calculation
int cx = GetSystemMetrics(SM_CXSCREEN);
int cy = GetSystemMetrics(SM_CYSCREEN);

// Create a compatible bitmap from the Window DC
hbmScreen = CreateCompatibleBitmap(hdcScreen, cx, cy);
if ( hbmScreen == NULL )
{
SET_CHECKPOINT();
break;
}

// Select the compatible bitmap into the compatible memory DC.
SelectObject(hdcMemDC,hbmScreen);

// Bit block transfer into our compatible memory DC.
BitBlt(hdcMemDC, 0,0, cx, cy, hdcScreen, 0,0, SRCCOPY);

// Create a stream to have CImage write data to.
hResult = CreateStreamOnHGlobal(NULL, TRUE, &pIStream);
if ( hResult != S_OK )
{
SET_CHECKPOINT();
break;
}

// Attach an ATL CImage to the hbitmap.
myimage.Attach(hbmScreen);

// Write data to stream.
hResult = myimage.Save(pIStream, Gdiplus::ImageFormatJPEG);
if ( hResult != S_OK )
{
SET_CHECKPOINT();
break;
}
myimage.Detach();

// Get the stream's HGLOBAL.
hResult = GetHGlobalFromStream(pIStream, &hGlobal);
if ( hResult != S_OK )
{
SET_CHECKPOINT();
break;
}

// Get a pointer to the data in the HGLOBAL.
char* pJPGData = (char*)GlobalLock(hGlobal);
pIStream->Stat(&stg, STATFLAG_NONAME);
nDataSize = (UINT)stg.cbSize.QuadPart;

// TODO: Open a file instead of a pipe...

//pJPGData points to the data, nDataSize is, well...
if ( WriteFile(hFile, pJPGData, nDataSize, &dwBytesWritten, NULL) == FALSE )
{
SET_CHECKPOINT();
break;
}

// TODO: Close the file.
}
while (0,0);

//
// Free resources.
// ---------------
if ( pIStream != NULL ) pIStream->Release();

//Clean up
if ( hbmScreen ) DeleteObject(hbmScreen);
if ( hdcMemDC ) DeleteObject(hdcMemDC);
if ( hdcScreen ) ::ReleaseDC(NULL,hdcScreen);


Related Topics



Leave a reply



Submit