0

I have a .net 2.0 windows forms application.

I have overridden the WndProc method to capture the user activities on the form

Ex:

const int HTCLOSE           = 0x0014;
bool m_bCloseButtonActive   = false;

if (m.Msg == WM_NCHITTEST)
{
    base.WndProc(ref m);
    m_bCloseButtonActive = (m.Result.ToInt32() == HTCLOSE);
}

Based on the value of m_bCloseButtonActive i take further actions.

The issue now i face is my form doesn't close as it is not able to capture the Close button clicked event in the Operating systems Vista and above(even Windows 7).

i.e the condition m.Result.ToInt32() == HTCLOSE is never true and my form never closes when i click the close button.

My application works in previous OS (Windows 2000, XP, XP Embedded). Also an interesting thing is that it works when i specify

Application.VisualStyleState = System.Windows.Forms.VisualStyles.VisualStyleState.ClientAreaEnabled;

Any idea whats going on in here. Is this something related to the Desktop Windows Manager, my application is not able to trap the close button clicked event.

Thanks in advance

this-Me
  • 2,139
  • 6
  • 43
  • 70

2 Answers2

6

Hit test messages doesn't seem to me to be the appropriate way to do this. For example, what if the user closes the form through the system menu, or through the Alt+F4 shortcut?

I think that you should be responding to WM_SYSCOMMAND messages with wParam == SC_CLOSE.

Windows Aero is fundamentally different when it comes to the handling of the non-client area which explains why it works in 2000/XP and when you disable DWM. But using WM_SYSCOMMAND works in all versions of Windows.

Note that you need to read the MSDN documentation for WM_SYSCOMMAND quite carefully because the message parameters contain extra information that needs to be masked out. To detect the close button you need code like this:

const int WM_SYSCOMMAND = 0x0112;
const int SC_CLOSE = 0xF060;

protected override void WndProc(ref Message m)
{
    if (m.Msg == WM_SYSCOMMAND)
        if ((m.WParam.ToInt32() & 0xFFF0) == SC_CLOSE)
            MessageBox.Show("close button pressed");
    }
    base.WndProc(ref m);
}

If you want to change the behaviour when the user closes the form, why don't you handle the Closing event?

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • With this my code is not entering the if statement condition .............where ......const int SC_CLOSE = 0xF060; const int WM_SYSCOMMAND = 0x0112; if (m.Msg == WM_SYSCOMMAND) { base.WndProc(ref m); m_bCloseButtonActive = (m.Result.ToInt32() == SC_CLOSE); } – this-Me Mar 21 '11 at 09:58
  • @this-Me I can see what you are doing wrong - see my update. Note that I suspect that all your hit test based code is very brittle and should be re-written in this manner. – David Heffernan Mar 21 '11 at 10:14
  • The condition if (m.Msg == WM_SYSCOMMAND) is only failing ! The value of m.Msg is never equal to the integer value of WM_SYSCOMMAND (274) – this-Me Mar 21 '11 at 10:23
  • @this-Me that must be due to something you are doing in your app. – David Heffernan Mar 21 '11 at 10:25
  • No im not doing anything in my application apart from this. Although i observe that the close(X) button gets disabled once i click it – this-Me Mar 21 '11 at 10:48
  • @this-Me I can't help any more if we have the same code but different behaviour. That's just plain weird. – David Heffernan Mar 21 '11 at 10:56
  • @David : Yes, it is weird because i made a sample application and it works there but not in my application. I shall look slightly deeper in my application. Thanks for your help – this-Me Mar 21 '11 at 12:00
  • @this-Me If you want to thank me, you could accept my answer and maybe even up-vote it if you felt it was helpful! – David Heffernan Mar 21 '11 at 12:02
  • @David : I used ShowDialog() instead of Form.Show(). Now i see i can close my form. But with only one side effect: The form flickers a lot before showing up – this-Me Mar 21 '11 at 12:35
  • @this-Me This sounds rather like a new problem worthy of a new question. – David Heffernan Mar 21 '11 at 12:38
-1

This finally worked ... I used WM_NCMOUSEMOVE instead of the non client HITTEST information The WParam contained all the related events.

This link helped : http://social.msdn.microsoft.com/Forums/en/windowsuidevelopment/thread/9a8a63c8-79b5-43a8-82eb-f659be947add

const int WM_NCMOUSEMOVE = 0x00A0;

  if (m.Msg == WM_NCMOUSEMOVE)
    {
    base.WndProc(ref m);
    if ((m.WParam.ToInt32() == HTCLOSE))
    {
      m_bCloseButtonActive = true;
    }
   }
this-Me
  • 2,139
  • 6
  • 43
  • 70