Title bar of Windows form is stuck in resize state when x coordinates and top y coordinate of form a

B

b.engelbrecht

Hello,

I think I found a bug in the Windows forms engine related to multiple
monitors and I wonder if anyone saw that too. If yes, any workaround?

Steps to reproduce:
1. connect two monitors to your PC, extend your desktop to both
monitors
2. In the monitor settings dialog, drag monitor 2 so that it is to the
left of monitor 1. This makes x screen coordinates of monitor 2
negative. Also make sure monitor 2 extends above monitor 1, so that top
y coordinate is negative as well. This happens to be my default setup,
I have a larger monitor to the left of my laptop screen.
3. Open a sizeable modal dialog in a dotnet 1.1 Windows forms
application.
4. Click and hold the left mouse button on the title bar of the dialog,
move it to monitor 2.
5. Now release the mouse.
6. Move the mouse over the title bar area, notice what happens.

What I see:
- If the window is on the left screen and its top is above the top
border of monitor 1, mouse cursor is always NW-SE resize cursor over
the title bar unless the dialog is maximized. If the title bar is
partially above the y=0 coordinate, the strange behavior is only
apparent for the part where y is negative.
- it is no longer possible to move the dialog by dragging the title
bar. Attempting to do so resizes the window rather than moving it
- it is not possible to use the [x] button to close the window unless
it is maximized
- normal behavior will only resume after you manage to move the window
back to monitor 1 by resizing it. This will not be possible at all
unless the "show in taskbar" property of the Window is set and maximize
is allowed.
 
B

b.engelbrecht

I did some more testing, my problem only happens in very specific
circumstances. Dotnet 1.1 or 2.0 does not make any difference in the
behaviour.

Problem seems to be related to these circumstances:
- host application is non-dotnet and opens the form through COM interop
- form is opened using ShowDialog

I have made a test project demonstrating the problem:
http://support.decos.nl/TestModal2003.zip (dotnet 1.1)
http://support.decos.nl/TestModal2005.zip (dotnet 2.0)

Full source code is included in the zip file.

Usage:
- start TestHost\Project1.exe
- click [ShowDialog]: has problem
- click [Show]: does not have problem

ShowDialog eventually does this:

dlg.ShowDialog(new WindowWrapper(m_iHwnd));

It passes the hwnd of the external owner window as m_iHwnd. To make
things even more interesting the software first creates a new STA
thread in which the dialog object is created. This is required because
the form hosts an Acrobat ActiveX control and that needs a STA thread.
The real host application is multithreaded so that the calling thread
would usually be MTA.

Show does this:
dlg.Show();
while(dlg.Visible)
{
Application.DoEvents();
Thread.Sleep(100);
}

When this is called, the problem wiht the title bar does not happen.
Show also waits for the window to close (simulating one property of a
modal dialog), but what I miss is a method to make the external
non-dotnet application window the owner. I tried this:

dlg.Owner = (Form)Control.FromHandle((IntPtr)m_iHwnd);
dlg.Show();

It does show the dialog, but it does not behave as if the host
application window is the owner (e.g., the "modal" window does not stay
on top of the application window). The host application varies, it can
be an old MFC C++ application or a Microsoft Office applcation (we have
to support all Office versions from Office 97 onward), so we do prefer
the real ShowDialog method for the sake of stability.

Best regards,

Berend



Ciaran O''''Donnell schreef:
Doesnt happen to me in .NET 2 so try upgrading

--
Ciaran O''''Donnell
http://wannabedeveloper.spaces.live.com


Hello,

I think I found a bug in the Windows forms engine related to multiple
monitors and I wonder if anyone saw that too. If yes, any workaround?

Steps to reproduce:
1. connect two monitors to your PC, extend your desktop to both
monitors
2. In the monitor settings dialog, drag monitor 2 so that it is to the
left of monitor 1. This makes x screen coordinates of monitor 2
negative. Also make sure monitor 2 extends above monitor 1, so that top
y coordinate is negative as well. This happens to be my default setup,
I have a larger monitor to the left of my laptop screen.
3. Open a sizeable modal dialog in a dotnet 1.1 Windows forms
application.
4. Click and hold the left mouse button on the title bar of the dialog,
move it to monitor 2.
5. Now release the mouse.
6. Move the mouse over the title bar area, notice what happens.

What I see:
- If the window is on the left screen and its top is above the top
border of monitor 1, mouse cursor is always NW-SE resize cursor over
the title bar unless the dialog is maximized. If the title bar is
partially above the y=0 coordinate, the strange behavior is only
apparent for the part where y is negative.
- it is no longer possible to move the dialog by dragging the title
bar. Attempting to do so resizes the window rather than moving it
- it is not possible to use the [x] button to close the window unless
it is maximized
- normal behavior will only resume after you manage to move the window
back to monitor 1 by resizing it. This will not be possible at all
unless the "show in taskbar" property of the Window is set and maximize
is allowed.
 
B

b.engelbrecht

By the way, the test project of course needs to be registered for COM
interop before the test host works. Just recompile it once with your
preferred version of Visual Studio, or use regasm.
 
B

b.engelbrecht

Hello,

Since I did not get a useful response, I have looked into the
implementation of System.Windows.Forms.Form myself, aided by Lutz
Roeder's .NET Reflector. I found a bug in the framework implementation
of WmNCHitTest, which I think may be related to the problem that I
have. The implementation in System.Windows.Forms.dll v1.0.5000.0 is the
following:

private void WmNCHitTest(ref Message m)
{
bool flag1 = true;
if (this.formState[Form.FormStateRenderSizeGrip] != 0)
{
int num1 = NativeMethods.Util.LOWORD(m.LParam);
int num2 = NativeMethods.Util.HIWORD(m.LParam);
Rectangle rectangle1 = base.Bounds;
if (((num1 >= ((rectangle1.X + rectangle1.Width) - 0x10))
&& (num1 <= (rectangle1.X + rectangle1.Width))) && ((num2 >=
((rectangle1.Y + rectangle1.Height) - 0x10)) && (num2 <= (rectangle1.Y
+ rectangle1.Height))))
{
m.Result = (IntPtr) 0x11;
flag1 = false;
}
}
if (flag1)
{
base.WndProc(ref m);
}
}

The bug is in these two lines, that will always result in positive
numbers:
int num1 = NativeMethods.Util.LOWORD(m.LParam);
int num2 = NativeMethods.Util.HIWORD(m.LParam);
However, the documentation of WM_NCHITTEST in the Win32 library
specified the following:
lParam: The low-order word specifies the x-coordinate of the cursor.
The coordinate is relative to the upper-left corner of the screen. The
high-order word specifies the y-coordinate of the cursor. The
coordinate is relative to the upper-left corner of the screen.

Actually, the coordinate is relative to the upper left coordinate of
the *primary* screen. This means that in a multiple screen setup,
LOWORD and HIWORD may signify negative numbers. The documentation of
WM_NCHITTEST tells you how this should be handled:

Use the following code to obtain the horizontal and vertical position:
xPos = GET_X_LPARAM(lParam);
yPos = GET_Y_LPARAM(lParam);

The GET_X_LPARAM and GET_Y_LPARAM macros are defined as follows:
#define GET_X_LPARAM(lp)
((int)(short)LOWORD(lp))
#define GET_Y_LPARAM(lp)
((int)(short)HIWORD(lp))
From this it follows that the indicated lines in the framework should
have been:
int num1 = NativeMethods.Util.SignedLOWORD(m.LParam);
int num2 = NativeMethods.Util.SignedHIWORD(m.LParam);

The same bug is present in v2.0.0.0 of the assembly.

Of course it is not feasible to correct the framework for an obscure
bug like this, but would there be any way to allow me to use a private
implementation of the hit test to correct the behavior in my software?

Best regards,

Berend


(e-mail address removed) schreef:
I did some more testing, my problem only happens in very specific
circumstances. Dotnet 1.1 or 2.0 does not make any difference in the
behaviour.

Problem seems to be related to these circumstances:
- host application is non-dotnet and opens the form through COM interop
- form is opened using ShowDialog

I have made a test project demonstrating the problem:
http://support.decos.nl/TestModal2003.zip (dotnet 1.1)
http://support.decos.nl/TestModal2005.zip (dotnet 2.0)

Full source code is included in the zip file.

Usage:
- start TestHost\Project1.exe
- click [ShowDialog]: has problem
- click [Show]: does not have problem

ShowDialog eventually does this:

dlg.ShowDialog(new WindowWrapper(m_iHwnd));

It passes the hwnd of the external owner window as m_iHwnd. To make
things even more interesting the software first creates a new STA
thread in which the dialog object is created. This is required because
the form hosts an Acrobat ActiveX control and that needs a STA thread.
The real host application is multithreaded so that the calling thread
would usually be MTA.

Show does this:
dlg.Show();
while(dlg.Visible)
{
Application.DoEvents();
Thread.Sleep(100);
}

When this is called, the problem wiht the title bar does not happen.
Show also waits for the window to close (simulating one property of a
modal dialog), but what I miss is a method to make the external
non-dotnet application window the owner. I tried this:

dlg.Owner = (Form)Control.FromHandle((IntPtr)m_iHwnd);
dlg.Show();

It does show the dialog, but it does not behave as if the host
application window is the owner (e.g., the "modal" window does not stay
on top of the application window). The host application varies, it can
be an old MFC C++ application or a Microsoft Office applcation (we have
to support all Office versions from Office 97 onward), so we do prefer
the real ShowDialog method for the sake of stability.

Best regards,

Berend



Ciaran O''''Donnell schreef:
Doesnt happen to me in .NET 2 so try upgrading

--
Ciaran O''''Donnell
http://wannabedeveloper.spaces.live.com


Hello,

I think I found a bug in the Windows forms engine related to multiple
monitors and I wonder if anyone saw that too. If yes, any workaround?

Steps to reproduce:
1. connect two monitors to your PC, extend your desktop to both
monitors
2. In the monitor settings dialog, drag monitor 2 so that it is to the
left of monitor 1. This makes x screen coordinates of monitor 2
negative. Also make sure monitor 2 extends above monitor 1, so that top
y coordinate is negative as well. This happens to be my default setup,
I have a larger monitor to the left of my laptop screen.
3. Open a sizeable modal dialog in a dotnet 1.1 Windows forms
application.
4. Click and hold the left mouse button on the title bar of the dialog,
move it to monitor 2.
5. Now release the mouse.
6. Move the mouse over the title bar area, notice what happens.

What I see:
- If the window is on the left screen and its top is above the top
border of monitor 1, mouse cursor is always NW-SE resize cursor over
the title bar unless the dialog is maximized. If the title bar is
partially above the y=0 coordinate, the strange behavior is only
apparent for the part where y is negative.
- it is no longer possible to move the dialog by dragging the title
bar. Attempting to do so resizes the window rather than moving it
- it is not possible to use the [x] button to close the window unless
it is maximized
- normal behavior will only resume after you manage to move the window
back to monitor 1 by resizing it. This will not be possible at all
unless the "show in taskbar" property of the Window is set and maximize
is allowed.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top