Always on top window blocks modal msgbox

I'm using the SetWindowPos API with the HWND_TOPMOST parameter to create an always-on-top window.

Depending on where the window is positioned on the screen, it can sometimes appear on top of a modal message box.  The always-on-top window can't be moved because the modal window behind it has focus.

How can I disable the always-on-top behavior when the window with focus is modal?  I would also like to re-enable the always-on-top behavior when the modal window is closed?
gibsontsAsked:
Who is Participating?
 
amebaCommented:
I'm still not sure ... OnTop of some forms, but Under modal forms... hmm

>"Re-coding all of these calls" is not that hard:
Replace all "MsgBox" with "MyMsgBox"

Public Function MyMsgBox(ByVal Prompt As String, _
    Optional ByVal Buttons As VbMsgBoxStyle = vbOKOnly, _
    Optional ByVal Title As String = "") As VbMsgBoxResult
   
    If Len(Title) = 0 Then Title = App.Title
   
    ' set something (and fill collection)
    '....
    MyMsgBox = MsgBox(Prompt, Buttons, Title)
    ' reset something
    '....
End Function
0
 
Guy Hengel [angelIII / a3]Billing EngineerCommented:
I think you should rather display your forms like this:

modalform.show vbmodeless, mainform

CHeers
0
 
gibsontsAuthor Commented:
The modal windows in question are generally displayed using the MsgBox function, which as far as I know will not allow you to display a modeless window.  (Correct me if I'm mistaken.)

In any case, I don't have the luxury of re-coding all the calls to MsgBox throughout the application.

I'm hoping there's a way to modify the always-on-top form that will solve my problem.
0
Ultimate Tool Kit for Technology Solution Provider

Broken down into practical pointers and step-by-step instructions, the IT Service Excellence Tool Kit delivers expert advice for technology solution providers. Get your free copy now.

 
Guy Hengel [angelIII / a3]Billing EngineerCommented:
What i meant with modalform is in fact the AlwaysOnTopForm:

AlwaysOnTopForm.Show vbModeless, MainForm

This will allow you to display a MsgBox (in front of the Modeless form), while that will stay in front of all the other forms that are not modal or modeless.

The problem with the API is that your form will be in front of all the forms, even those of other applications (which i guess isn't really what you need).

CHeers
0
 
rkot2000Commented:
you can try to use vbSystemModal to display your message box
MsgBox "MyText", vbSystemModal
0
 
gibsontsAuthor Commented:
Angellll,

Ok, now I understand...

But that only keeps it on top of the form it was called from (or whatever I specify as the parent).  I need it to stay on top of ALL other forms in the application - unless they're modal, of course.
0
 
Guy Hengel [angelIII / a3]Billing EngineerCommented:
For that, you must "Show" all the other forms by providing the parent:
AnyFormA.Show , MainForm
AnyFormB.Show , MainForm
OnTopForm.Show vbModeless, MainForm

Only using the .Visible property will fail to work for the modeless form.

Cheers



0
 
gibsontsAuthor Commented:
Angellll,

Ok, now I understand...

But that only keeps it on top of the form it was called from (or whatever I specify as the parent).  I need it to stay on top of ALL other forms in the application - unless they're modal, of course.
0
 
gibsontsAuthor Commented:
How will this keep OnTopForm on top of AnyFormA and AnyFormB? They're all children of the same parent, and they're all vbModeless (the default).
0
 
Guy Hengel [angelIII / a3]Billing EngineerCommented:
Ok, i suggest that you try out the following:
create an empty project, with formA and formB, formA as Startup form.
IN formA:


Public Sub Form_Load()
  dim f AS FORMB

  set f = new formb
  f.Caption = "<no modal property>, no parent"
  f.show

  set f = new formb
  f.Caption = "<no modal property>, parent"
  f.show , me

  set f = new formb
  f.Caption = "<modeless property>, parent"
  f.show vbModeless, me


  set f = new formb
  f.Caption = "<modal property>, parent"
  f.show vbModal, me

End Sub

You will get 5 forms loaded, but you can only click on the one that is modal (you might have a command button on that form to check using a msgbox).

As soon as you close that form, you can play around with the others:
the modeless form will stay over the main form and the one where you gave a parent, but not over the one where you didn't supply the parent property

Cheers
0
 
mdouganCommented:
It depends on whether it was your code or some other code that displays the messagebox.  If it's your code, then you can simply use the same API to set the topmost window to not topmost:

HWND_NOTTOPMOST (I think)

Just before you display the message box.  And then you can set it back to topmost after the messagebox is cleared.

If it's someone else's code (another application), there is not much you can do. This is why you should only use topmost windows with care, and generally make them small enough or position them such that they wont cover the middle of the screen where most message boxes are displayed.
0
 
gibsontsAuthor Commented:
Angellll,

I tried your example.  The modeless form did not stay on top of the other form where a parent was given.
0
 
gibsontsAuthor Commented:
mdougan and rkot2000,

Please see my previous comment.

The application has hundreds of calls to MsgBox that could cause this problem.  Re-coding all of these calls is not an option I wish to pursue.
0
 
rkot2000Commented:
or even simpler :

>"Re-coding all of these calls" is not that hard:
Replace all "MsgBox" with "MyMsgBox"

Public Function MsgBox(ByVal Prompt As String, _
   Optional ByVal Buttons As VbMsgBoxStyle = vbOKOnly, _
   Optional ByVal Title As String = "") As VbMsgBoxResult
   
   If Len(Title) = 0 Then Title = App.Title
   
   ' set something (and fill collection)
   '....
   MsgBox = Vba.MsgBox(Prompt, Buttons, Title)
   ' reset something
   '....
End Function


next time just biuld a function to display a messagebox :)
0
 
amebaCommented:
We can do the same for InputBox (this is left to reader as an exercise :)
0
 
mdouganCommented:
ameba's suggestion fully coded:

Private Function NewMsgBox(sMsg As String, lButtons As VbMsgBoxStyle, sTitle As String) As VbMsgBoxResult
Dim RC As VbMsgBoxResult

   Call SetWindowPos(Me.hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, _
                     SWP_NOSIZE Or SWP_NOMOVE)
                                               
   RC = MsgBox(sMsg, lButtons, sTitle)
   
   Call SetWindowPos(Me.hwnd, HWND_TOPMOST, 0, 0, 0, 0, _
                     SWP_NOSIZE Or SWP_NOMOVE)
   
   NewMsgBox = RC
   
End Function

Then, a global search and replace on msgbox to NewMsgBox would take all of about a minute to do.

It always amuses me when people say they don't wish to pursue the option that will solve their problem.  Fine, then live with it....
0
 
rkot2000Commented:
or you can create your own messagebox form and display it as you wish(topmost, nottopmost, modal, and nonmodal) :)



0
 
Richie_SimonettiIT OperationsCommented:
what is wrong with rkot2000's first comment?
0
 
amebaCommented:
If I call Msgbox, msgbox will show in front of any window in my app.

I cannot make Msgbox appear *under* window which is TOPMOST
0
 
amebaCommented:
So, my TOPMOST function is different, or your app has more threads, or you are showing topmost window when msgbox is already shown.
0
 
amebaCommented:
If you have Form1 with 2 buttons:
- button1 shows Form2 TOPMOST
- button2 shows Msgbox "Hello!"

If you press button1, then button2, Msgbox will go *under* Form2 ?!?
0
 
mdouganCommented:
Richie_Simonetti,

rkot2000's first comment, about using vbSystemModal would be catestrophic in this case.  Because it wouldn't do anything to put the messagebox in front of other windows, however it would lock your entire windows session so that you couldn't even close your app with the Task Manager.  You'd have to hard-boot your machine to recover.....
0
 
Richie_SimonettiIT OperationsCommented:
mdougan, that OK. But after the comment, other people post similar comments hence my question.
To me, if you need to show a msgbox on top, you need to call it from windows that was setted as TOPMOST.
0
 
amebaCommented:
B grade is insult!  If something was not clear, you should have asked for more info!
0
 
Richie_SimonettiIT OperationsCommented:
I agree with Ameba.
0
 
rkot2000Commented:
just found on msdn:

PRB: Message Box Appears Behind Form Set as Top-Most Window (Q178401)


A Visual Basic form can be displayed as the top z-ordered (or top-most) window by using the SetWindowPos API function. Under Windows 95 or Windows 98, if the top-most window then displays a message box, the message box may display behind the top-most window. The user cannot continue or exit the program because the user cannot close the message box.


RESOLUTION
Do not display a message box from a form set as the top-most window. If you must use a message box from the form, unload the form first before displaying the message box.



STATUS
This behavior is by design.

0
 
MoondancerCommented:
I have corrected the grade from "B" to an "A" since the PAQ value here is excellent and all points covered.  If anyone feels I have made an error in judgment here, please let me know.
Thank you,
Moondancer - EE Moderator
0
 
amebaCommented:
Thanks, Moondancer

rkot2000,

thanks for the info, that explains when does the problem show
>message box may display behind the top-most window

On Win95, I wasn't able to reproduce that behaviour (tested in IDE, EXE, msgbox from different forms)


Credits to mdougan, who first mentioned what should be done to active form if it is topmost:

> you can simply use the same API to set the topmost window to not topmost:
>
> HWND_NOTTOPMOST (I think)
>
> Just before you display the message box.  And then you can set it back to topmost after the messagebox
is cleared.
0
 
amebaCommented:
I reproduced the problem after setting BorderStyle to 0-None.
And solution (NOTTOPMOST -> MsgBox -> TOPMOST) works.
0
 
MoondancerCommented:
Thank you, ameba, for going that extra mile, and thanks to all who participated in this collaboration effort.
:) Moondancer - EE Moderator
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.