Solved

How do I detect a MessageBox dialog?

Posted on 2009-05-19
12
348 Views
Last Modified: 2012-05-07
Hi,
I have two applications (src and target) that asynchronously communicate with each other via  a TextBox. Target application has many forms and src application (amongst other things) monitors which (Target) Form is open and whether a MessageBox is being displayed at the time.

I know how to determine active form but don't know how to determine if a MessageBox is being displayed at the time (keeping in mind that communication between the two applications is asynchronous and I don't want to resort to setting some global flag every time I show a MessageBox).

Thanks,
     Michael

P.S. I am using VB2008 and .Net 3.5
0
Comment
Question by:gem56
  • 7
  • 5
12 Comments
 
LVL 39

Expert Comment

by:abel
ID: 24421456
Is it OK for you to check whether a certain top level window is a messagebox? From your explanation, I understand so far that you already have the top level window, so I assume you have the handle of it. But you still need a trick. It goes as follows:

  1. Get the parent window handle
  2. Use GetwindowLong on the parent handle
  3. If the parent has the flag set for WS_DISABLED, the child window is a modal window.
This is explained in more detail with an example in this knowledge base article: http://support.microsoft.com/kb/77316
0
 

Author Comment

by:gem56
ID: 24421772
Not sure if I understand your comment so here's a bit more info wile I'm following up your suggestion.

Src app sends a message to target app (by writing to a TextBox in target app) and it's within the target app that I determine what is the active form, etc. and return that information back to src app. The bit missing is how to determine if the active window (that I've identified) has a MessageBox shown.

/Michael
0
 
LVL 39

Expert Comment

by:abel
ID: 24422211
I thought it was the reverse, that the source window would determine prior to sending whether the target window was a dialog window or not.

If the target app is going to determine it by itself, you may be in trouble, normally the processing of input stops while the dialog is open. In which case the target app cannot determine whether a dialog is open.

If I had to choose, I would go for a simple OO way of solving this. For instance, I assume you are using ShowDialog to show a modal window. If that is the case, you can use this in your form to set the property for HasDialogOpen, and anybody calling ShowDialog, even your current code, will automatically set that property:

Public HasDialogOpen As Boolean
 

Public Shadows Function ShowDialog() As DialogResult

    ' may pass null, same as ShowDialog() without args '

    Return Me.ShowDialog(Nothing)

End Function
 

Public Shadows Function ShowDialog(ByVal owner As IWin32Window) As DialogResult

    Dim dlgResult As DialogResult

    HasDialogOpen = True

    dlgResult = MyBase.ShowDialog(owner)

    HasDialogOpen = False

    Return dlgResult

End Function

Open in new window

0
 

Author Comment

by:gem56
ID: 24423593
"If the target app is going to determine it by itself, you may be in trouble, normally the processing of input stops while the dialog is open. In which case the target app cannot determine whether a dialog is open."
I'm aware that input processing stops while dialog is open however I seem to be able to handle incoming events even while the MessageBox is displayed. Maybe that's because I'm handling messages from the Src application via a 'TextBox.TextChanged' event (asynchronously). Basically I do something on the target app and get Src to verify the result/status via the TextBox interface.
The target is an MDI application with each window being an MDI child that I display using frmForm.Show so the ShowDialog is not troubling me but I can see how I can (perhaps) use the same principle to solve my MessageBox problem.
If I'm reading you right, should I be able to also override the MessageBox.Show function with a locally declared function that has (inbuilt) functionality to set 'HasDialogOpen' flag?
If that's correct, how would i go about shadowing a MessageBox.Show function, as I'm not so familiar with shadowing/overriding of functions?
 
0
 
LVL 39

Accepted Solution

by:
abel earned 500 total points
ID: 24425378
Ah, that's different. Yes, normally you should be able to override any function in a class that you inherit of. However, you do not inherit from MessageBox, but from Form. I assumed a modal dialog form, which is stupid, as it is just as possible to use a MessageBox.

Unfortunately Microsoft has decided to make the MessageBox sealed. That means that it will cause a whole lot more trouble to get this to work with MessageBox and actually: MS tries to prevent it (a sealed class cannot be inherited, and if you cannot inherit, you cannot shadow).

Now there are several ways out of this, you can of course still make some global method, but now that I know that you do not have any trouble with the asynchronous methods calling. You can use the GetWindowLong(Me.Hwnd) to check the settings of the current window, which basically brings us back to the first answer i gave.

Here's a try, not tested:

Const GWL_STYLE As Integer = (-16)

Const WS_DISABLED = &H8000000
 

<DllImport("user32.dll", SetLastError:=True)> _

Private Shared Function GetWindowLong( _

     ByVal hWnd As IntPtr, _

     ByVal nIndex As Integer) As Integer

End Function
 

Function HasDialogOpen() As Boolean

    Dim WinStyle As Integer = GetWindowLong(Me.Handle, GWL_STYLE)

    Return WinStyle And WS_DISABLED   ' bitwise compare '

End Function

Open in new window

0
 

Author Comment

by:gem56
ID: 24427729
Makes sense and I tried exactly as you suggested however it always returns False.
Actually I had to change teh declaration a bit as it gave me a error, as per below.

Maybe it's getting confused with the fact that MessageBox is involved and not other forms/dialogs.
The value that GetWindowLong returns is 1475280896 (0x57EF 0000)

I tried all sorts of combinations but no joy!

Any more suggestions?

Private Const GWL_STYLE As Integer = (-16)

Public Const WS_DISABLED As Integer = &H8000000

Public Declare Function GetWindowLong Lib "user32" Aias "GetWindowLongA" _

    (ByVal hWnd As IntPtr, ByVal nIndex As Integer) As Integer
 
 

Function HasDialogOpen(ByVal frm As System.Windows.Forms.Form) As Boolean

   Dim WinStyle As Integer = GetWindowLong(frm.Handle, GWL_STYLE)

   Return CBool(WinStyle And WS_DISABLED)   ' bitwise compare '

End Function

Open in new window

0
IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
LVL 39

Expert Comment

by:abel
ID: 24427911
Mmm, it is correct that it returns false, check the bit mapping:

01010111111011110000000000000000 (0x57EF0000)
00001000000000000000000000000000 (0x08000000)

this sounds that the window is not "disabled" when your messagebox pops up. Can you click that window and give it focus? When I try it myself I get:

00011110110011110000000000000000 (0x1ECF0000, disabled/msgbox)
00010110110011110000000000000000 (0x16CF0000, enabled/no msgbox)
00001000000000000000000000000000 (0x08000000)

which is correct. The "1" of the 0x8000000 gets set in one situation and unset in the other, giving false in one and true in another.

Strange you got an error on that declaration. I used that declaration (taken from pinvoke.net) and it works for me...

To resolve this better, take a look at Spy++ (under your Visual Studio tools in the start menu). Use the Find Window command and hover with the target-mouse over your window (the disabled parent) and you should find the properties of your window when you click OK (see screenshots). The result of GetWindowLong is under the tab  "Styles". Hope you find the/a difference between with / without dialog (do not compare the list, compare the hexadecimal value of the Styles or Extended Styles).

-- Abel --


ScreenShot296.png
ScreenShot295.png
ScreenShot294.png
ScreenShot297.png
0
 

Author Comment

by:gem56
ID: 24428714
Hi abel,
Firstly thanks for pointing out how to use Spy++, as I haven't used it before, and secondly I've got it working as you indicated so that's great and you've got the points.

If I use the ActiveFom handle, in this case being a child of the MDI container, in GetWindowLong statement then it always shows False. If however I use the handle of the MDI container then I get the correct results, as you indicated. Maybe I've miss interpreted your directions and that's what you intended all along. It seems that if an MDI child is involved then one must use the MDI parent handle whereas if a dialog Form is involved (not MessageBox?) then you need to use the dialog Form handle. I'm still verifying the last bit about the dialog but that's how it's looking at this stage.

In Spy++ I can see the MessageBox window and the text that it shows so I'm wondering if there is an easy way of associating that window to it's parent, be that dialog or the MDI itself. If you already know the answer to that question I'm happy to create another post with extra points.

/Michael
0
 
LVL 39

Expert Comment

by:abel
ID: 24430316
The ActiveForm is not necessarily the same as the parent of the dialog form if you use ShowDialog (the first parameter can set the actual owner/parent). Using ActiveForm is equal to using the GetForegroundWindow API function. If a dialog is showing, the ActiveForm will return the dialog, or null / Nothing if it is a MessageBox.

You should not use ActiveMdiChild, which will return something else (the active MDI child) which is not usable for you here.

Both a MessageBox and a ShowDialog will block the owner, which is the main form, not a particular MdiChild (iirc). So you are correct in using the main form for checking for being WS_DISABLED. It will always be the handle of the form that is currently blocked, not the blocking window / form itself.

-- Abel --
0
 
LVL 39

Expert Comment

by:abel
ID: 24430364
PS, on this one:

> In Spy++ I can see the MessageBox window and the text that it shows
> so I'm wondering if there is an easy way of associating that window to it's parent,


If you call MessageBox without an owner parameter (the first one, you can set it to Me), it will be associated with the current active window. Internally, the GetActiveWindow API call is used, which is slightly different from GetForegroundWindow. The latter works system wide (giving the one that the user is currently working with, which is why ActiveForm returns Nothing when that's not eq. to the .NET form), the previous works only on the current thread (and thus guarantees that the returned handle, if any, belongs to a form of your app). But I'm quite in the details now, not sure if you need all that intel... ;-)
0
 

Author Comment

by:gem56
ID: 24430956
Thanks a lot for all your patience and of course solution.
/Michael
0
 
LVL 39

Expert Comment

by:abel
ID: 24431048
You're welcome, glad to be of help :)
0

Featured Post

Maximize Your Threat Intelligence Reporting

Reporting is one of the most important and least talked about aspects of a world-class threat intelligence program. Here’s how to do it right.

Join & Write a Comment

This tutorial demonstrates one way to create an application that runs without any Forms but still has a GUI presence via an Icon in the System Tray. The magic lies in Inheriting from the ApplicationContext Class and passing that to Application.Ru…
If you're writing a .NET application to connect to an Access .mdb database and use pre-existing queries that require parameters, you've come to the right place! Let's say the pre-existing query(qryCust) in Access takes a Date as a parameter and l…
Access reports are powerful and flexible. Learn how to create a query and then a grouped report using the wizard. Modify the report design after the wizard is done to make it look better. There will be another video to explain how to put the final p…
This video explains how to create simple products associated to Magento configurable product and offers fast way of their generation with Store Manager for Magento tool.

746 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

17 Experts available now in Live!

Get 1:1 Help Now