6

I want to position Form on top left corner of the screen.

I have tried this.Location = new Point(0,0) but window is positioned at (7,0) - top of the window is on top of the screen but left side is 7 pixels from the screen edge. I created new WinForms app for testing and added only this code:

private void Form1_Load(object sender, EventArgs e)
{
    Point p = new Point(0, 0);

    WindowState = FormWindowState.Maximized;
    Debug.WriteLine("\nMaximized");
    Debug.WriteLine("Location: " + Location);
    Debug.WriteLine("Size: " + Size);
    Debug.WriteLine("PointToScreen(0,0): " + PointToScreen(p));

    WindowState = FormWindowState.Normal;
    Location = p;            
    Debug.WriteLine("\nNormal");
    Debug.WriteLine("Location: " + Location);
    Debug.WriteLine("Size: " + Size);
    Debug.WriteLine("PointToScreen(0,0): " + PointToScreen(p));

    Debug.Write("\nScreen.PrimaryScreen.WorkingArea: ");
    Debug.WriteLine(Screen.PrimaryScreen.WorkingArea);
}

The output is:

Maximized  
Location: {X=-8,Y=-8}  
Size: {Width=1936, Height=1056}
PointToScreen(0,0): {X=0,Y=23}

Normal
Location: {X=0,Y=0}
Size: {Width=300, Height=300}
PointToScreen(0,0): {X=8,Y=31}

Screen.PrimaryScreen.WorkingArea: {X=0,Y=0,Width=1920,Height=1040}

Why Location = new Point(0,0) doesn't position form on (0,0)? Is this due to something on my system? I have Win10 and VS2015. Taskbar is on the bottom, there is nothing on the left side of my desktop. In order to position it on (0,0) I actually have to position it on (-7,0). Also, reported width of the maximized form is 16 pixels larger than screen width. I understand that because of window edges, title bar etc there is a difference between client area size and form size, but this is not it. When the form is maximized there are no left and right edges (client area width = desktop width) but form width is +16px. There is +8px on each of the 4 sides of the form but Y position is OK. Why is Y-position OK and X is not?

c4551u5
  • 111
  • 1
  • 6
  • You set the location to `0,0` and the `Debug.WriteLine` shows `Location: {X=0,Y=0}`. So what's the problem? Also `PointToScreen(0,0): {X=8,Y=31}` is OK, it is the screen coordinates of the point `0,0` of client area of form. – Reza Aghaei Sep 20 '16 at 20:32
  • I haven't noticed this positioning issue before on Win10 or 8.1 for that matter. If I had to guess, I would say that the observed issue is a result of Desktop Window Manager composition that can no longer be disabled. Something new to investigate. Thanks. :) – TnTinMn Sep 20 '16 at 21:36
  • The problem is, like I wrote, that position of the window (in reality, that is - what I can see) is 7 pixels to the right. Notice client coordinates (8,31) - X is 8 because the window position is 7, plus 1 pixel of window edge, and Y is 31 because of the title bar. That's why when I set position to (-7,0) the window is in the corner. So, client coordinates are OK - client rectangle _really_ starts at (8,31). Form coordinates are not OK - form location is _really_ (7,0), not (0,0) as its says. – c4551u5 Sep 20 '16 at 21:50

2 Answers2

5

Thanks to Uwe Keim and his own answer to his question, I've created MoveForm function that calculates offset and sets location of the form correctly, regardless of Windows version (ie border size):

    void MoveForm(Point p)   // Move form to point 'p'
    {
        this.WindowState = FormWindowState.Normal;
        this.Location = new Point(0, 0);
        Rectangle rec = WindowHelper.GetWindowRectangle(this.Handle);
        p.Offset(-rec.Location.X, -rec.Location.Y);
        this.Location = p;
    }

MoveForm function uses WindowHelper class from Uwe Keim's post:

public static class WindowHelper
{
    // https://code.google.com/p/zscreen/source/browse/trunk/ZScreenLib/Global/GraphicsCore.cs?r=1349

    /// <summary>
    /// Get real window size, no matter whether Win XP, Win Vista, 7 or 8.
    /// </summary>
    public static Rectangle GetWindowRectangle(IntPtr handle)
    {
        if (Environment.OSVersion.Version.Major < 6)
        {
            return GetWindowRect(handle);
        }
        else
        {
            Rectangle rectangle;
            return DWMWA_EXTENDED_FRAME_BOUNDS(handle, out rectangle) ? rectangle : GetWindowRect(handle);
        }
    }

    [DllImport(@"dwmapi.dll")]
    private static extern int DwmGetWindowAttribute(IntPtr hwnd, int dwAttribute, out Rect pvAttribute, int cbAttribute);

    private enum Dwmwindowattribute
    {
        DwmwaExtendedFrameBounds = 9
    }

    [Serializable, StructLayout(LayoutKind.Sequential)]
    private struct Rect
    {
        // ReSharper disable MemberCanBePrivate.Local
        // ReSharper disable FieldCanBeMadeReadOnly.Local
        public int Left;
        public int Top;
        public int Right;
        public int Bottom;
        // ReSharper restore FieldCanBeMadeReadOnly.Local
        // ReSharper restore MemberCanBePrivate.Local

        public Rectangle ToRectangle()
        {
            return Rectangle.FromLTRB(Left, Top, Right, Bottom);
        }
    }

    private static bool DWMWA_EXTENDED_FRAME_BOUNDS(IntPtr handle, out Rectangle rectangle)
    {
        Rect rect;
        var result = DwmGetWindowAttribute(handle, (int)Dwmwindowattribute.DwmwaExtendedFrameBounds,
            out rect, Marshal.SizeOf(typeof(Rect)));
        rectangle = rect.ToRectangle();
        return result >= 0;
    }

    [DllImport(@"user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool GetWindowRect(IntPtr hWnd, out Rect lpRect);

    private static Rectangle GetWindowRect(IntPtr handle)
    {
        Rect rect;
        GetWindowRect(handle, out rect);
        return rect.ToRectangle();
    }
}
Community
  • 1
  • 1
c4551u5
  • 111
  • 1
  • 6
  • 1
    I'm glad you found a workaround. I had found a similar solution [here](http://www.vbforums.com/showthread.php?824699-RESOLVED-Form-Placement-Considering-Aero-Borders&p=5019707&viewfull=1#post5019707) that also indicated that setting the `SubsystemVersion` to 6.0 would solve the issue, but it only worked for Vista thru Win 8. The majority of the offset its due to the combined effect of `BorderWidth` and `PaddedBorderWidth` setting under `HKEY_CURRENT_USER\Control Panel\Desktop\WindowMetrics` in the registry. Setting both those to zero, still leaves a 1 px offset though. – TnTinMn Sep 22 '16 at 04:15
  • I've seen similar solutions that are setting SubsystemVersion, but this one is more 'elegant' (if anything in this problem/solution can be called that). Here SubsystemVersion is not changed, but depending on the version, one of two different approaches of measuring real window rectangle is chosen. Thanks for the WindowMetric registry info. – c4551u5 Sep 22 '16 at 10:41
  • 1
    A bit more info. If you override the `Form.OnHandleCreated` and call [SetWindowTheme(this.Handle, "", "")](http://pinvoke.net/default.aspx/uxtheme/SetWindowTheme.html), this will disable theming on the form itself. You will now see the full border drawn around the form. It appears as though what appears as an offset on the left border is actually a transparent border area. – TnTinMn Sep 23 '16 at 01:33
  • 1
    Yes, it looks like that offset is transparent border area, but whole thing is messed up, I wish Microsoft would fix that. After all, WinForms and Windows have both 'windows' and 'forms' in their names, it's ridiculous that there is a problem with size and position of windows/forms. – c4551u5 Sep 23 '16 at 09:31
  • This is perfect for my needs. To bad you don't have a SizeForm() function we can use as well. Having issues dealing with the size being off and not filling the entire width etc. *sigh* – Arvo Bowen Apr 20 '23 at 03:14
0

I figured out the problem.

Just set

this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;

and test the result. for me it is this:

Maximized
Location: {X=0,Y=0}
Size: {Width=1280, Height=800}
PointToScreen(0,0): {X=0,Y=0}

Normal
Location: {X=0,Y=0}
Size: {Width=477, Height=321}
PointToScreen(0,0): {X=0,Y=0}

It is all about the border.

Look at this

MSL
  • 990
  • 1
  • 12
  • 28
  • That is OK if you want borderless window, but I need a regular window. – c4551u5 Sep 21 '16 at 10:29
  • then, You should do some calculations to get right locations and sizes. border of a window is always 8 and 31 pixels. – MSL Sep 21 '16 at 10:33
  • They are not always that size, that's (the part of) the problem. Aside different Windows versions and their default settings, users can also customize those settings... Luckily, `DWMWA_EXTENDED_FRAME_BOUNDS` can be used to get real values – c4551u5 Sep 23 '16 at 18:37