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 350x400 和
Result 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
);
我的任务是重新创建具有与 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 350x400 和 Result 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
);