我想在打开一个窗口之前计算它的完整大小。我正在使用AdjustWindowRectEx()实现此目的。对于客户端大小为640x480的窗口,我的代码如下所示:

    wrect.left = 0;
    wrect.top = 0;
    wrect.right = 640;
    wrect.bottom = 480;
    AdjustWindowRectEx(&wrect, WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX, FALSE, 0);


这将返回以下值:

    left: -3
    top: -22
    right: 643
    bottom: 483


但是,使用CreateWindowEx()打开窗口并传递时

    wrect.right - wrect.left
    wrect.bottom - wrect.top


作为窗口大小,窗口的大小实际大小实际上是656x515像素。尽管如此,GetWindowRect()返回646x505,即与AdjustWindowRectEx()返回的尺寸相同,但是正如我说的那样,当我截取桌面的屏幕截图并使用绘画程序测量窗口的大小时,其物理大小实际上是656x515像素。有人对此有解释吗?

客户端大小是正确的,它是640x480,但看起来边框大小计算错误,因为边框使用的像素比AdjustWindowRectEx()和GetWindowRect()计算的像素更多。

我在Windows 7上。

编辑:

这是因为问题的标题误导了人们的看法吗?如MSDN autodocs中所述,AdjustWindowRectEx()不支持WS_OVERLAPPED。那么,还有其他方法可以计算WS_OVERLAPPED窗口的尺寸吗?而是使用WS_OVERLAPPEDWINDOW不是解决方案,因为它设置了我不需要的WS_THICKFRAME和WS_MAXIMIZEBOX。

现在是一些测试代码,它显示了问题。您可以看到客户端大小尚可,但是窗口的物理大小大于GetWindowRect()返回的大小。

#include <stdio.h>

#include <windows.h>

#define CLASSNAME "Test"

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    WNDCLASSEX wcx;
    RECT wrect;
    HWND hWnd;
    char tmpstr[256];

    memset(&wcx, 0, sizeof(WNDCLASSEX));

    wcx.cbSize = sizeof(WNDCLASSEX);
    wcx.style = CS_HREDRAW|CS_VREDRAW;
    wcx.lpfnWndProc = WindowProc;
    wcx.hInstance = hInstance;
    wcx.hCursor = LoadCursor(NULL, IDC_ARROW);
    wcx.hbrBackground = GetStockObject(BLACK_BRUSH);  // important! otherwise a borderless window resize will not be drawn correctly
    wcx.lpszClassName = CLASSNAME;

    RegisterClassEx(&wcx);

    wrect.left = 0;
    wrect.top = 0;
    wrect.right = 640;
    wrect.bottom = 480;
    AdjustWindowRectEx(&wrect, WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX, FALSE, 0);

    hWnd = CreateWindowEx(0, CLASSNAME, "Test", WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_OVERLAPPED, 0, 0, wrect.right - wrect.left, wrect.bottom - wrect.top, NULL, NULL, hInstance, NULL);
    ShowWindow(hWnd, SW_SHOWNORMAL);

    GetWindowRect(hWnd, &wrect);
    sprintf(tmpstr, "%d %d %d %d\n", wrect.left, wrect.top, wrect.right, wrect.bottom);

    AllocConsole();
    WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), tmpstr, strlen(tmpstr), NULL, NULL);

    GetClientRect(hWnd, &wrect);
    sprintf(tmpstr, "%d %d %d %d\n", wrect.left, wrect.top, wrect.right, wrect.bottom);
    WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), tmpstr, strlen(tmpstr), NULL, NULL);

    Sleep(10000);

    DestroyWindow(hWnd);
    UnregisterClass(CLASSNAME, hInstance);

    return 0;
}

最佳答案

GetWindowRect api的大小不正确:

Due to compatability requirements, certain metrics are reported in such a way that they're not consistent with what is actually drawn on the screen when Aero Glass (more accurately, "Windows Vista Aero") is enabled. This sort of approach is needed in order to change the look of the system for the vast majority of apps for which this isn't an issue.However, there's been a recent change in the system which will be coming out in Vista RC1 that will return the correct rendered value from GetWindowRect() for executables that are linked with "winver = 6.0". This allows new and newly-linked applications to get the "correct" values from GetWindowRect().

GetWindowRect on non-resizable windows under Aero Glass

使用DwmGetWindowAttribute来获取正确的大小:

DwmGetWindowAttribute(hWnd, DWMWA_EXTENDED_FRAME_BOUNDS, &wrect, sizeof(wrect));

08-26 18:43
查看更多