Solved

Always on top window blocks modal msgbox

Posted on 2002-04-25
30
2,657 Views
Last Modified: 2007-11-27
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?
0
Comment
Question by:gibsonts
  • 8
  • 6
  • 4
  • +4
30 Comments
 
LVL 142

Expert Comment

by:Guy Hengel [angelIII / a3]
ID: 6968366
I think you should rather display your forms like this:

modalform.show vbmodeless, mainform

CHeers
0
 

Author Comment

by:gibsonts
ID: 6968397
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
 
LVL 142

Expert Comment

by:Guy Hengel [angelIII / a3]
ID: 6968411
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
 
LVL 5

Expert Comment

by:rkot2000
ID: 6968425
you can try to use vbSystemModal to display your message box
MsgBox "MyText", vbSystemModal
0
 

Author Comment

by:gibsonts
ID: 6968468
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
 
LVL 142

Expert Comment

by:Guy Hengel [angelIII / a3]
ID: 6968484
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
 

Author Comment

by:gibsonts
ID: 6968490
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
 

Author Comment

by:gibsonts
ID: 6968539
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
 
LVL 142

Expert Comment

by:Guy Hengel [angelIII / a3]
ID: 6968567
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
 
LVL 18

Expert Comment

by:mdougan
ID: 6968599
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
 

Author Comment

by:gibsonts
ID: 6968814
Angellll,

I tried your example.  The modeless form did not stay on top of the other form where a parent was given.
0
 

Author Comment

by:gibsonts
ID: 6968829
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
 
LVL 15

Accepted Solution

by:
ameba earned 100 total points
ID: 6969089
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
 
LVL 5

Expert Comment

by:rkot2000
ID: 6969138
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
 
LVL 15

Expert Comment

by:ameba
ID: 6969154
We can do the same for InputBox (this is left to reader as an exercise :)
0
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.

 
LVL 18

Expert Comment

by:mdougan
ID: 6969431
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
 
LVL 5

Expert Comment

by:rkot2000
ID: 6969478
or you can create your own messagebox form and display it as you wish(topmost, nottopmost, modal, and nonmodal) :)



0
 
LVL 16

Expert Comment

by:Richie_Simonetti
ID: 6969630
what is wrong with rkot2000's first comment?
0
 
LVL 15

Expert Comment

by:ameba
ID: 6969937
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
 
LVL 15

Expert Comment

by:ameba
ID: 6969977
So, my TOPMOST function is different, or your app has more threads, or you are showing topmost window when msgbox is already shown.
0
 
LVL 15

Expert Comment

by:ameba
ID: 6969984
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
 
LVL 18

Expert Comment

by:mdougan
ID: 6970061
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
 
LVL 16

Expert Comment

by:Richie_Simonetti
ID: 6970362
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
 
LVL 15

Expert Comment

by:ameba
ID: 6970962
B grade is insult!  If something was not clear, you should have asked for more info!
0
 
LVL 16

Expert Comment

by:Richie_Simonetti
ID: 6971084
I agree with Ameba.
0
 
LVL 5

Expert Comment

by:rkot2000
ID: 6971298
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
 
LVL 1

Expert Comment

by:Moondancer
ID: 6971438
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
 
LVL 15

Expert Comment

by:ameba
ID: 6971503
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
 
LVL 15

Expert Comment

by:ameba
ID: 6971545
I reproduced the problem after setting BorderStyle to 0-None.
And solution (NOTTOPMOST -> MsgBox -> TOPMOST) works.
0
 
LVL 1

Expert Comment

by:Moondancer
ID: 6971566
Thank you, ameba, for going that extra mile, and thanks to all who participated in this collaboration effort.
:) Moondancer - EE Moderator
0

Featured Post

Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

Join & Write a Comment

If you have ever used Microsoft Word then you know that it has a good spell checker and it may have occurred to you that the ability to check spelling might be a nice piece of functionality to add to certain applications of yours. Well the code that…
If you need to start windows update installation remotely or as a scheduled task you will find this very helpful.
As developers, we are not limited to the functions provided by the VBA language. In addition, we can call the functions that are part of the Windows operating system. These functions are part of the Windows API (Application Programming Interface). U…
Get people started with the utilization of class modules. Class modules can be a powerful tool in Microsoft Access. They allow you to create self-contained objects that encapsulate functionality. They can easily hide the complexity of a process from…

757 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

20 Experts available now in Live!

Get 1:1 Help Now