-
June 14th, 2003, 08:52 PM
#1
Closing a Yes/No message box via code.
I need the ability to close message boxes. I've found a few code examples explaining how to do this, but none of them work for message boxes set to vbYesNo. I've tried sending the following messages to it:
- SendMessage hWndOfMsgBox, WM_CLOSE, 0, ByVal 0&
- PostMessage hWndOfMsgBox, WM_CLOSE, 0, ByVal 0&
- SendMessage hWndOfMsgBox, WM_DESTROY, 0, ByVal 0&
- SendMessage hWndOfMsgBox, WM_SYSCOMMAND, SC_CLOSE, ByVal 0&
None of these will work. It seems that the message box steals these commands. I've also tried using SendKeys to do...
- {ESC}
- %{F4}
These won't work either. (Sending ALT-N is not an option because my app doesn't know if it's a vbYesNo message box. Unless there is a way to identify the type of message box that is open.)
This is very frustrating!
I hope you all can find a solution, because I think I'm at a wit's end.
(Note: Creating my own message boxes via forms is not an option, because I need the ability to close message boxes not owned by my program. Such as those owned by common dialogs and 3rd party tools.)
Here is my test code if you want to take a crack at it. The timer in this code will only trigger on the compiled EXE, not when running it from the IDE.
Code:
Option Explicit
' Define win32 callbacks.
Private Declare Function PostMessage Lib "user32" Alias "PostMessageA" _
(ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" _
(ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" _
(ByVal lpClassName As String, ByVal lpWindowName As String) As Long
' Define PostMessage constants.
Private Const WM_DESTROY As Long = &H2
Private Const WM_CLOSE As Long = &H10
Private Const WM_SYSCOMMAND As Long = &H112
Private Const SC_CLOSE As Long = &HF060
' Called when a command button named "cmdTest" is clicked.
Private Sub cmdTest_Click()
timTest.Interval = 1000
timTest.Enabled = True
MsgBox "This is a test!", vbYesNo, "The Test"
End Sub
' Called when a timer control named "timTest" is triggered.
Private Sub timTest_Timer()
Dim hWnd As Long
timTest.Enabled = False
hWnd = FindWindow(vbNullString, "The Test")
If (hWnd <> 0) Then
SendMessage hWnd, WM_CLOSE, 0, ByVal 0&
' SendMessage hWnd, WM_DESTROY, 0, ByVal 0&
' SendMessage hWnd, WM_SYSCOMMAND, SC_CLOSE, 0&
Else
MsgBox "Error finding message box!", vbOKOnly
End If
End Sub
Last edited by JQuick; June 14th, 2003 at 08:58 PM.
-
June 14th, 2003, 11:25 PM
#2
The first problem I encountered in your program is that the timer is not triggered while the MessageBox is there. To work around this, we create a timer using the SetTimer API. 2nd, to close the dialog we have to simulate clicking the "NO" button. We do this by send WM_COMMAND. Here's my code
Code:
'Module1.bas
Private Declare Function PostMessage Lib "user32" Alias "PostMessageA" _
(ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" _
(ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Public Declare Function SetTimer Lib "user32" (ByVal hWnd As Long, ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long
Public Declare Function KillTimer Lib "user32" (ByVal hWnd As Long, ByVal nIDEvent As Long) As Long
Private Const WM_COMMAND = &H111
Private Const IDNO = 7
Public idTimer As Long
Sub TimerProc(ByVal hWnd&, ByVal uMsg&, ByVal idEvent&, ByVal dwTime&)
Call KillTimer(0, idTimer)
hWnd = FindWindow(vbNullString, "The Test")
If (hWnd <> 0) Then
SendMessage hWnd, WM_COMMAND, IDNO, ByVal 0&
Else
MsgBox "Error finding message box!", vbOKOnly
End If
End Sub
'form1.frm
Private Sub cmdTest_Click()
idTimer = SetTimer(0, 101, 5000, AddressOf TimerProc)
MsgBox "This is a test!", vbYesNo, "The Test"
End Sub
Be aware not to place breakpoint inside TimerProc. This will hang your program since the IDE is disabled when the message box is shown.
Hope it will help you
-
June 14th, 2003, 11:38 PM
#3
The timer in my code works for the compiled version only. It doesn' work when running the program through the IDE. However, it's nice to see a different approach to setting up timers in VB. Those functions remind me of my C/C++ days.
As far as your approach to closing the message box via IDNO, I don't think I can use it. I'm trying to setup my main program to auto-shutdown itself after a period of time. This means that I need to close all modal dialogs, which can be anything. So far, sending WM_CLOSE works on all types of windows including forms, common dialogs, and all message boxes except vbYesNo.
So, in summary, I'm looking for a command that can close all kinds of windows. I haven't found it yet, if in fact it even exists. Now, if I can identify the type of window (such as message box) and identify what it takes to close it (such as IDNO for vbYesNo) then your solution will work.
-
June 15th, 2003, 02:26 AM
#4
You can use GetClassName to determine if it's a dialog box, then use GetDlgItem to check if it has IDNO button. If so, then close it using my method, if not, use yours.
Code:
Declare Function GetClassName Lib "user32" Alias "GetClassNameA" _
(ByVal hwnd&, ByVal lpClassName$, ByVal nMaxCount&) As Long
Declare Function GetDlgItem Lib "user32" (ByVal hDlg&, ByVal nIDDlgItem&) As Long
...
...
Dim sClass As String
sClass = String(100, 0)
Call GetClassName(hwnd, sClass, 100)
sClass = Left(sClass, InStr(1, sClass, Chr(0)) - 1)
If sClass = "#32770" And GetDlgItem(hwnd, IDNO) Then
Call SendMessage(hwnd, WM_COMMAND, IDNO, ByVal 0&)
Else
Call SendMessage(hwnd, WM_CLOSE, 0, ByVal 0&)
End If
Hope it will help you
-
June 15th, 2003, 12:55 PM
#5
That's a brilliant idea! Gosh, I guess I should have put my MFC hat on while I was working on this problem.
Thanks again rxbagain!
-
June 16th, 2003, 12:40 AM
#6
'add reference to Windows Scripting host Object model
Dim wshShell As New IWshShell_Class
Dim lngReturn As Long
Dim intSeconds2Wait As Integer
intSeconds2Wait = 2
lngReturn = wshShell.Popup("Place Your Text Here", intSeconds2Wait, "Hello", vbYesNo)
-
June 16th, 2003, 08:02 AM
#7
Yo urs, great code ! Simple, yet elegant. Get's job done with very little coding.
If kids were left to their own devices, would they ever come up with a thing like war?......The Wheel / Todd Rundgren
Do canibals not eat clowns because they taste funny?
-
June 16th, 2003, 12:25 PM
#8
rxbagain, your code worked like a dream! You get 5 stars from me. I think your code is very simple as well.
urs, thanks for your suggestion, but it will not work for me. I needed code that could close all dialogs, including ones that I don't popup myself such as message boxes displayed by common dialogs.
-
June 17th, 2003, 10:29 PM
#9
Hi,
Just out of curiosity ... your sample code suggests that you are getting the msgbox window handle using FindWindow with the title of the msgbox dialog.
Since as you said, you are using 3rd party controls etc., do you always know what your msgbox dialog title is going to be?
Without thinking about it too hard myself ... (lazy boy today), I would love to know if there is an easy reliable way to find out if your application has a msgbox dialog open, not neccessarily just to close it.
I guess one way would be to use the enumchildwindows proc and check to see what the class string is.
Anyone else got any ideas?
Zen-Programming:
If a compiler beeps in the IDE forest, and nobody hears it, was there really a bug?
-
June 17th, 2003, 10:38 PM
#10
Hi Tinbum!
I used the FindWindow() function for testing purposes only and to keep this discussion simple.
See another thread of mine to see how I'm fetching the hWnd of the top most dialog.
http://www.codeguru.com/forum/showth...hreadid=250548
To sum it up, I tried the EnumChildWindows() function, but it was only giving me a list of controls, not dialogs. Instead, I had to use EnumThreadWindows(). Now this code does not identify the top most dialog as message box, it just assumes it is if it has the specified window class name and a control ID of IDNO. So, this solution is probably not bullet proof, but it works fine on my app.
-
September 10th, 2019, 01:40 PM
#11
Re: Closing a Yes/No message box via code.
hi, rxbagain
i want to use your code but i dont know how to use it
i copy and paste to my visual basic.net window editor and i gave some errors
what i do wrong ?
thank you
-
September 11th, 2019, 04:19 AM
#12
Re: Closing a Yes/No message box via code.
The rxbagain code is for VB6, not vb.net. They are not the same languages.
All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!
C++23 Compiler: Microsoft VS2022 (17.6.5)
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|