Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WinAPI CreateWindow function creates smaller windows than set

My task is to recreate application with features similar to these of Windows' snipping tool. One of them is capturing a screenshot of a window that is currently active and that's what causes me problems. Everything is almost perfectly fine, however "snip" taken of an app is bigger than the actual app by few pixels and that's because it's window is slightly smaller than I set it to be.

Here's my CreateWindow call for the main window I test it on:

hwnd = CreateWindow(TEXT("Klasa okien"), TEXT("Screenshot"), WS_OVERLAPPEDWINDOW, 
        10, 10, 350, 400, NULL, NULL, hInstance, NULL);

then procedure of gathering information about that very window's size and proceeding to "taking snip" function:

RECT okno;
HWND aktywne = GetForegroundWindow();
GetWindowRect(aktywne, &okno);
CaptureScreen(okno.left, okno.top, okno.right-okno.left, okno.bottom-okno.top);

Finally part of the function that takes these snips:

void CaptureScreen(int x, int y, int width, int height)
{
    HDC hDc = CreateCompatibleDC(0);
    HBITMAP hBmp = CreateCompatibleBitmap(GetDC(0), width, height);
    SelectObject(hDc, hBmp);
    BitBlt(hDc, 0, 0, width, height, GetDC(0), x, y, SRCCOPY);
    Bitmap *p_bmp = Bitmap::FromHBITMAP(hBmp, NULL);
...

and as I said - everything is almost fine and the picture that is being created is in fact 350x400 BUT actual window's size seems to be 336x393. I'm also attaching two pictures - the perfectly snipped one is the one created by Windows' tool and the other one is mine.

Result of my tool 350x400 and Result of Windows' snipping tool 336x393

like image 960
PlainLazy Avatar asked Jan 04 '16 00:01

PlainLazy


2 Answers

This issue is Windows 10 specific, it has to do with Windows 10 transparent borders. If for example window has re-sizing borders, then the borders on left/right/bottom are about 7 pixels.

If you are taking screen shot then you may wish to exclude the transparent borders. Replace GetWindowRect with:

DwmGetWindowAttribute(hwnd, DWMWA_EXTENDED_FRAME_BOUNDS, &rc, sizeof(RECT)); 
//requires at least Windows Vista

Compared to GetWindowRect, the rectangle obtained from DwmGetWindowAttribute could be smaller by about 7 pixels on left, right, and bottom.

#include "Dwmapi.h"
#pragma comment( lib, "Dwmapi.lib" )
...

RECT rc;
DwmGetWindowAttribute(hwnd, DWMWA_EXTENDED_FRAME_BOUNDS, &rc, sizeof(RECT));
int w = rc.right - rc.left;
int h = rc.bottom - rc.top;

HDC memdc = CreateCompatibleDC(hdc);
HBITMAP bmp = CreateCompatibleBitmap(hdc, w, h);
SelectObject(memdc, bmp);
BitBlt(memdc, 0, 0, w, h, hdc, rc.left, rc.top, CAPTUREBLT | SRCCOPY);
...

Secondly, don't use GetDC(0) (in that way), because it causes resource leak. You must save the handle obtained from GetDC and release it later. For example:

HWND desktopWnd = GetDesktopWindow();
HDC hdc = GetDC(desktopWnd);
...
ReleaseDC(desktopWnd, hdc);

Edit:
or use

HDC hdc = GetDC(0);
...
ReleaseDC(0, hdc);
like image 161
Barmak Shemirani Avatar answered Sep 28 '22 08:09

Barmak Shemirani


Before CreateWindow() call AdjustWindowRectEx():

int x = 10;
int y = 10;
int w = 350;
int h = 400;

RECT rect;
rect.left   = x;
rect.top    = y;
rect.right  = x + w;
rect.bottom = y + h;

UINT style = WS_OVERLAPPEDWINDOW;

AdjustWindowRectEx( &rect, style, 0, 0 );

hwnd = CreateWindow(
         TEXT("Klasa okien"), TEXT("Screenshot"), style, 
         rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, 
         NULL, NULL, hInstance, NULL
       );

AdjustWindowRectEx

like image 21
Vitaly Fadeev Avatar answered Sep 28 '22 08:09

Vitaly Fadeev