WinAPI CreateWindow 函数创建小于设置 windows

WinAPI CreateWindow function creates smaller windows than set

我的任务是重新创建具有与 Windows 截图工具类似的功能的应用程序。其中之一是捕获当前处于活动状态的 window 的屏幕截图,这就是导致我出现问题的原因。一切几乎都很好,但是 "snip" 应用程序比实际应用程序大几个像素,这是因为它 window 比我设置的要小一些。

这是我对主要 window 的 CreateWindow 调用,我在以下位置对其进行了测试:

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

然后收集有关 window 大小的信息并继续执行 "taking snip" 函数的过程:

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

最后是采用这些片段的函数的一部分:

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);
...

正如我所说 - 一切几乎都很好,正在创建的图片实际上是 350x400 但实际 window 的尺寸似乎是 336x393。我还附上了两张图片 - 完美剪裁的一张是由 Windows' 工具创建的,另一张是我的。

Result of my tool 350x400Result of Windows' snipping tool 336x393

此问题是 Windows 10 特有的,它与 Windows 10 透明边框有关。例如,如果 window 有 re-sizing 个边框,那么 left/right/bottom 上的边框大约为 7 个像素。

如果您正在截屏,那么您可能希望排除透明边框。将 GetWindowRect 替换为:

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

GetWindowRect相比,DwmGetWindowAttribute得到的矩形左、右、下各小了7个像素左右。

#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);
...

其次,不要使用GetDC(0)(那样),因为它会导致资源泄漏。您必须保存从 GetDC 获得的句柄,稍后释放它。例如:

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

编辑:
或使用

HDC hdc = GetDC(0);
...
ReleaseDC(0, hdc);

在 CreateWindow() 调用 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