使用WS_OVERLAPPED,AdjustWindowRectEx()和GetWindowRect()给出错误的大小

时间:2015-01-13 17:45:14

标签: winapi

我想在打开窗口之前计算窗口的完整大小。我正在使用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;
}   

2 个答案:

答案 0 :(得分:5)

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

答案 1 :(得分:0)

如果AdjustWindowRect不起作用,只需尝试创建窗口并在创建窗口后调整大小。

// Create the window with a nearly correct size
RECT rect;
rect.left = 0;
rect.top = 0;
rect.right = 640;
rect.bottom = 480;  
AdjustWindowRectEx(&rect, WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX, FALSE, 0); 

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

// Get the size that is really required and adjust
RECT rectCreated;
GetWindowRect(hWnd, &rectCreated);
rect.right += rectCreated.right-rectcreated.left;
rect.bottom += rectCreated.bottom-rectcreated.top;

// Resize to let the window fir the inner client aea
SetWindowPos(hWnd,NULL,0,0,rect.right-rect.left,rect.bottom-rect.top,SWP_NOMOVE|SWP_NOZORDER);

// Show it.
ShowWindow(hWnd, SW_SHOWNORMAL);

代码未经过测试。希望我没有错误或语法错误。