Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
318 views
in Technique[技术] by (71.8m points)

c# - Both MoveWindow and SetWindowPos result in incorrect window position/size

I want to move and resize an application's window (ex: Notepad). I tried both MoveWindow and SetWindowPos, and both has the exact same issue. The new position/size is always inaccurate.

MoveWindow(handle, rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height, true);
SetWindowPos(handle, IntPtr.Zero, rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height, 0);

I tested this on different PCs (both running Windows 10) and I noticed a pattern. On the first PC, the "drift" was X:+7, Y:0, W: -14, H: -7. On the second PC, the "drift" was X:+8, Y:0, W:-16, H-8.

I did test it on a third PC, but the result was way worse which I'm guessing it has something to do with it having 2 monitors.

I can see the "drift" with my own eyes, it's especially clear when I feed it X:0 and Y:0. I don't understand why this is happening though or how I can fix it.

This is the function I use to get a Window's (ex: Notepad) position and dimensions:

public static Rectangle GetWindowRectangle(IntPtr handle)
{
    Rect rect = new Rect();
    if (Environment.OSVersion.Version.Major >= 6)
    {
        int size = Marshal.SizeOf(typeof(Rect));
        DwmGetWindowAttribute(handle, (int)DwmWindowAttribute.DWMWA_EXTENDED_FRAME_BOUNDS, out rect, size);
    }
    else if (Environment.OSVersion.Version.Major < 6 || rect.ToRectangle().Width == 0)
    {
        GetWindowRect(handle, out rect);
    }

    return rect.ToRectangle();
}
question from:https://stackoverflow.com/questions/65599491/both-movewindow-and-setwindowpos-result-in-incorrect-window-position-size

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

You've ignored the shadow of the window. In win10, you will use DwmGetWindowAttribute + DWMWA_EXTENDED_FRAME_BOUNDS in GetWindowRectangle, and according to the documentation, this will get the window bounds excluding the drop shadow.

And in Windows Vista and later, the Window Rect now includes the area occupied by the drop shadow. So, function MoveWindow and SetWindowPos think that the position/size you pass includes the shadow.

if you want to move and resize the area that excludes the shadow, then you need to first calculate the size of the shadow (C++ sample):

RECT exclude_shadow = {}, include_shadow = {};
GetWindowRectangle(hwnd,&exclude_shadow);
GetWindowRect(hwnd, &include_shadow);
RECT shadow = {};
shadow.left = include_shadow.left - exclude_shadow.left; // -7
shadow.right = include_shadow.right - exclude_shadow.right; // +7
shadow.top = include_shadow.top - exclude_shadow.top; //0
shadow.bottom = include_shadow.bottom - exclude_shadow.bottom; // +7

LONG Width = include_shadow.right - include_shadow.left;
LONG Height = include_shadow.bottom - include_shadow.top;

//SetWindowPos(hwnd, NULL, 0 + shadow.left, 0 + shadow.top, Width, Height, 0);
SetWindowPos(hwnd, NULL, 0 + shadow.left, 0 + shadow.top, 0, 0, SWP_NOSIZE); // use SWP_NOSIZE if you want to keep the size.

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...