Programmatically dismiss a MsgBox

前端 未结 1 738
夕颜
夕颜 2021-01-24 16:20

I have a master macro in an Excel file, \'file A\' that opens another Excel file, \'file B\'. On open, an add-in imports data into \'file B\'. I would like to close \'file B\' o

相关标签:
1条回答
  • 2021-01-24 17:04

    Since the "add-in" and Excel/VBA run in the same context, we cannot launch it and monitor its message-box within the same VBA application, because each VBA application is a single-threaded process. Fortunately however, there is a solution that can exploit the fact that different VBA applications run in different contexts, so they can run in parallel.

    My suggested solution is to create a MS-Word document that is dedicated to monitoring and closing that message box. We need this in Word (or any other office application) in order to make the monitoring code and the addin's code run in parallel, in different contexts.

    1- create a Word macro-enable document, named mboxKiller.docm and place it in some folder; i.e. C:\SO in my example. place this code in ThisDocument and save:

    Private Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
    Private Declare PtrSafe Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    
    Public Sub WaitAndKillWindow()
        On Error Resume Next
        Dim h As Long: h = FindWindow(vbNullString, "Microsoft Excel")
        If h <> 0 Then SendMessage h, 16, 0, 0 ' <-- WM_Close
        Application.OnTime Now + TimeSerial(0, 0, 1), "WaitAndKillWindow"
    End Sub
    
    Private Sub Document_Open()
        WaitAndKillWindow
    End Sub
    

    2- In the Excel workbook's VBA, create a class module, named mboxKiller with this code:

    Private killerDoc As Object
    
    Private Sub Class_Initialize()
        On Error Resume Next
        Set killerDoc = CreateObject("Word.Application").Documents.Open(Filename:="C:\SO\mboxKiller.docm", ReadOnly:=True)
        If Err.Number <> 0 Then
            If Not killerDoc Is Nothing Then killerDoc.Close False
            Set killerDoc = Nothing
            MsgBox "could not lauch The mboxKiller killer. The message-box shall be closed manuallt by the user."
        End If
    End Sub
    
    Private Sub Class_Terminate()
        On Error Resume Next
        If Not killerDoc Is Nothing Then killerDoc.Application.Quit False
    End Sub
    

    3- Testing and Usage. In a normal class Module, place the following code and test the procedure

    Sub Test() ' <-- run this for testing after finishing the setup
        Dim killer: Set killer = New mboxKiller
        simulateAddin
        simulateAddin
        simulateAddin
    End Sub
    
    ' Procedure supposed to do some calculation then display a message box
    Private Sub simulateAddin()
        Dim i As Long
        For i = 0 To 1000: DoEvents: Next ' simulates some calculations
        MsgBox "This is a message box to simulate the message box of the addin." & VbCrLf & _
        "It will be automatically closed by the Word app mboxKiller"
    End Sub
    
    0 讨论(0)
提交回复
热议问题