【问题标题】:WinAPI CreateWindow function creates smaller windows than setWinAPI CreateWindow 函数创建比设置更小的窗口
【发布时间】:2016-01-04 00:14:54
【问题描述】:

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

这是我测试的主窗口的 CreateWindow 调用:

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

然后收集有关该窗口大小的信息并继续执行“截图”功能的过程:

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,但实际窗口的大小似乎是 336x393。我还附上了两张图片 - 完美的一张是由 Windows 工具创建的,另一张是我的。

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

【问题讨论】:

  • 无法测试 atm,但您可能需要查看 this function
  • BUT actual window's size seems to be 336x393 -- 你如何确定这个?
  • 这是“Windows 10 对没有特殊清单的程序的窗口大小撒谎”这一常见问题的另一种情况吗?
  • @CareyGregory,如果我要启动 Windows 的截图工具并选择“窗口截图”我的应用程序的选项 - 它将创建一个大小为 336x393 的图像。我还附上了这种操作的确切结果。问题是我实际上已经将 350 和 400 作为大小传递给了 CreateWindow() 函数。
  • @andlabs,我不确定。我认为我没有足够的经验来回答你的问题。我不介意我的窗口比我设置的要小一些。我希望能够截取不包括超出窗口范围的区域的屏幕截图。

标签: c++ winapi screenshot


【解决方案1】:

此问题是 Windows 10 特有的,它与 Windows 10 透明边框有关。例如,如果窗口具有重新调整大小的边框,则左/右/下的边框约为 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);

【讨论】:

  • GetDC(0) 非常好。泄漏不是因为 0 被通过了。
  • 是的,我更新了答案以使其更加清晰。或者也许使用HWND_DESKTOP而不是0,这样代码更具可读性。
  • 是的!这正是使它按预期工作的原因。谢谢你和那个额外的提示 - 为了更清楚,我修复了它。
【解决方案2】:

在 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

【讨论】:

    猜你喜欢
    • 2015-02-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-30
    • 2021-06-18
    • 1970-01-01
    • 2016-12-26
    • 1970-01-01
    相关资源
    最近更新 更多