CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 12 of 12
  1. #1
    Join Date
    Oct 2002
    Location
    USA, California
    Posts
    58

    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.

  2. #2
    Join Date
    Apr 2003
    Posts
    1,755

    Smile

    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

  3. #3
    Join Date
    Oct 2002
    Location
    USA, California
    Posts
    58
    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.

  4. #4
    Join Date
    Apr 2003
    Posts
    1,755

    Smile

    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

  5. #5
    Join Date
    Oct 2002
    Location
    USA, California
    Posts
    58

    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!

  6. #6
    Join Date
    Jul 2001
    Location
    maharashtra,india
    Posts
    181
    '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)

  7. #7
    Join Date
    Jan 2001
    Posts
    486
    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?

  8. #8
    Join Date
    Oct 2002
    Location
    USA, California
    Posts
    58

    Thumbs up

    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.

  9. #9
    Join Date
    May 2003
    Location
    Australia
    Posts
    155
    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?

  10. #10
    Join Date
    Oct 2002
    Location
    USA, California
    Posts
    58
    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.

  11. #11
    Join Date
    Sep 2019
    Posts
    1

    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

  12. #12
    2kaud's Avatar
    2kaud is offline Super Moderator Power Poster
    Join Date
    Dec 2012
    Location
    England
    Posts
    7,824

    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
  •  





Click Here to Expand Forum to Full Width

Featured