Home » excel » excel – Display a message box with a timeout value

excel – Display a message box with a timeout value

Posted by: admin March 9, 2020 Leave a comment

Questions:

The question comes from code like this.

Set scriptshell = CreateObject("wscript.shell")
    Const TIMEOUT_IN_SECS = 60
    Select Case scriptshell.popup("Yes or No? leaving this window for 1 min is the same as clicking Yes.", TIMEOUT_IN_SECS, "popup window", vbYesNo + vbQuestion)
        Case vbYes
            Call MethodFoo
        Case -1
            Call MethodFoo
    End Select

This is a simple way to display a message box with a timeout from VBA (or VB6).

In Excel 2007 (apparently also happens in Internet Explorer at times) the popup window will not timeout, and instead wait for user input.

This issue is tough to debug as it only happens occasionally and I do not know the steps to reproduce the issue. I believe it to be an issue with Office modal dialogs and Excel not recognising the timeout has expired.

See http://social.technet.microsoft.com/Forums/en-US/ITCG/thread/251143a6-e4ea-4359-b821-34877ddf91fb/

The workarounds I found are:

A. Use a Win32 API call

Declare Function MessageBoxTimeout Lib "user32.dll" Alias "MessageBoxTimeoutA" ( _
ByVal hwnd As Long, _
ByVal lpText As String, _
ByVal lpCaption As String, _
ByVal uType As Long, _
ByVal wLanguageID As Long, _
ByVal lngMilliseconds As Long) As Long

Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" ( _
ByVal lpClassName As String, _
ByVal lpWindowName As String) As Long

Public Sub MsgBoxDelay()
    Const cmsg As String = "Yes or No? leaving this window for 1 min is the same as clicking Yes."
    Const cTitle As String = "popup window"
    Dim retval As Long
    retval = MessageBoxTimeout(FindWindow(vbNullString, Title), cmsg, cTitle, 4, 0, 60000)

    If retval <> 7 Then
        Call MethodFoo
    End If

End Sub  

B. Use a manual timer with a VBA userform that is designed to look like a messagebox. Use a global variable or similar to save any state that needs to be passed back to the calling code. Ensure that the Show method of the userform is called with the vbModeless parameter supplied.

C. Wrap the call to wscript.popup method in the MSHTA process which would allow the code to run out of process and avoid the modal nature of Office.

CreateObject("WScript.Shell").Run "mshta.exe vbscript:close(CreateObject(""WScript.Shell"").Popup(""Test"",2,""Real%20Time%20Status%20Message""))"

What is the best way of A, B or C or your own answer to display a message box with a timeout value in VBA?

How to&Answers:

This is a long answer, but there’s a lot of ground to cover: it’s also a late reply, but things have changed since some of the replies to this (and similar questions) have been posted on the stack. That sucks like a vacuum cleaner on triple-phase AC, because they were good answers when they were posted and a lot of thought went into them.

The short version is: I noticed that the Script WsShell Popup solution stopped working for me in VBA a year ago, and I coded a working API timer callback for the VBA MsgBox function.

Skip straight to the code under the heading VBA code to call a Message Box with a Timeout if you need an answer in a hurry – and I did, I have literally thousands of instances of a self-dismissing ‘MsgPopup’ substitute for VBA.MsgBox to redact, and the code below fits into a self-contained module.

However, the VBA coders here – myself included – need some explanation as to why perfectly good code no longer seems to work. And if you understand the reasons, you may be able to use the partial workaround for ‘Cancel’ dialogs, buried in the text.

I noticed that the Script WsShell Popup solution stopped working for me in VBA a year ago – The ‘SecondsToWait’ timeout was being ignored, and the dialog just hung around like the familiar VBA.MsgBox:

MsgPopup = objWShell.PopUp(Prompt, SecondsToWait, Title, Buttons)

And I think I know the reason why: you can no longer send a WM_CLOSE or WM_QUIT message to a dialog window from anywhere other than the thread which opened it. Likewise, the User32 DestroyWindow() function will not close a dialog window unless it’s called by the thread that opened the dialog.

Someone in Redmond doesn’t like the idea of a script running in the background and sending a WM_CLOSE commands to all those essential warnings that halt your work (and, these days, making them go away permanently needs local admin privileges).

I can’t imagine who would write a script like that, it’s a terrible idea!

There are consequences and collateral damage to that decision: WsScript.Popup() objects in the single-threaded VBA environment implement their ‘SecondsToWait’ timeout using a Timer callback, and that callback sends a WM_CLOSE message, or something like it… Which is ignored in most cases, because it’s a callback thread, not the owner thread for the dialog.

You might get it to work on a popup with a ‘CANCEL’ button, and it’ll become clear why that is in a minute or two.

I’ve tried writing a timer callback to WM_CLOSE the popup, and that failed for me, too, in most cases.

I’ve tried some exotic API callbacks to mess with the VBA.MsgBox and WsShell.Popup window, and I can tell you now that that they didn’t work. You can’t work with what isn’t there: those dialog windows are very simple and most of them don’t contain any functionality, at all, except for the responses in the button clicks – Yes, No, OK, Cancel, Abort, Retry, Ignore, and Help.

‘Cancel’ is an interesting one: it appears that you get a freebie from the primitive Windows API for built-in dialogs when you specify vbOKCancel or vbRetryCancel or vbYesNoCancel – the ‘Cancel’ function is automatically implemented with a ‘close’ button in the dialog’s Menu bar (you don’t get that with the other buttons, but feel free to try it with a dialog containing ‘Ignore’), which means that….

WsShell.Popup() dialogs will sometimes respond to the SecondsToWait timeout if they have a ‘Cancel’ option.

objWShell.PopUp("Test&nbsp;Me",&nbsp;10,&nbsp;"Dialog&nbsp;Test",&nbsp;vbQuestion&nbsp;+&nbsp;vbOkCancel)

That might be a good enough workaround for someone reading this, if all you wanted was to get WsShell.Popup() functions to respond to the SecondsToWait parameter again.

This also means that you can send WM_CLOSE messages to the ‘Cancel’ dialog using the SendMessage() API call on a callback:

SendMessage(hwndDlgBox, WM_CLOSE, ByVal 0&, ByVal 0&)

Strictly speaking, this should only work for the WM_SYSCOMMAND, SC_CLOSE message – the ‘close’ box in the command bar is a ‘system’ menu with a special class of commands but, like I said, we’re getting freebies from the Windows API.

I got that to work, and I started thinking: If I can only work with what’s there, maybe I’d better find out what’s actually there

And the answer turns out to be obvious: Dialog boxes have their own set of WM_COMMAND message parameters –

' Dialog window message parameters, replicating Enum vbMsgBoxResult:
CONST dlgOK      As Long = 1
CONST dlgCANCEL  As Long = 2
CONST dlgABORT   As Long = 3
CONST dlgRETRY   As Long = 4
CONST dlgIGNORE  As Long = 5
CONST dlgYES     As Long = 6
CONST dlgNO      As Long = 7

And, as these are the ‘user’ messages which return the user responses to the caller (that is to say, the calling thread) of the dialog, the dialog box is happy to accept them and close itself.

You can interrogate a dialog window to see if it implements a particular command and, if it does, you can send that command:

If GetDlgItem(hWndMsgBox, vbRetry) <> 0 Then
    SendMessage hWndMsgBox, WM_COMMAND, vbRetry, 0&
    Exit For
End If

The remaining challenge is to detect a ‘Timeout’ and intercept the returning Message Box response, and substitute our own value: -1 if we’re following the convention established by the WsShell.Popup() function. So our ‘msgPopup’ wrapper for a Message Box with a timeout needs to do three things:

  1. Call our API Timer for the delayed dismissal of the dialog;
  2. Open the message Box, passing in the usual parameters;
  3. Either: Detect a timeout and substitute the ‘timeout’ response…

    …Or return the user response to the dialog, if they responded in
    time

Elsewhere, we need to declare the API calls for all this, and we absolutely must have Publicly-declared ‘TimerProc’ function for the Timer API to call. That function has to exist, and it has to run to ‘End Function’ without errors or breakpoints – any interruption, and the API Timer() will call down the wrath of the operating system.

VBA code to call a Message Box with a Timeout:

Option Explicit
Option Private Module<BR />
' Nigel Heffernan January 2016<BR />
' Modified from code published by Microsoft on MSDN, and on StackOverflow: this code is in<BR />' the public domain.<BR />
' This module implements a message box with a 'timeout'<BR />
' It is similar to implementations of the WsShell.Popup() that use a VB.MessageBox interface
' with an additional 'SecondsToWait' or 'Timeout' parameter.<BR />
Private m_strCaption As String<BR />
Public Function MsgPopup(Optional Prompt As String, _
                         Optional Buttons As VbMsgBoxStyle = vbOKOnly, _
                         Optional Title As String, _
                         Optional SecondsToWait As Long = 0) As VbMsgBoxResult<BR />
' Replicates the VBA MsgBox() function, with an added parameter to automatically dismiss the message box after n seconds
' If dismissed automatically, this will return -1: NOT 'cancel', nor the default button choice.<BR />
Dim TimerStart As Single<BR />
If Title = "" Then
    Title = ThisWorkbook.Name
End If<BR />
If SecondsToWait &GT; 0 Then
    ' TimedmessageBox launches a callback to close the MsgBox dialog
    TimedMessageBox Title, SecondsToWait
    TimerStart = VBA.Timer
End If<BR /><BR />
MsgPopup = MsgBox(Prompt, Buttons, Title)<BR /><BR />
If SecondsToWait &GT; 0 Then
    ' Catch the timeout, substitute -1 as the response
    If (VBA.Timer - TimerStart) &GT;= SecondsToWait Then
        MsgPopup = -1
    End If
End If<BR />
End Function<BR />

Public Function MsgBoxResultText(ByVal MsgBoxResult As VbMsgBoxResult) As String<BR />' Returns a text value for the integers returned by VBA MsgBox() and WsShell.Popup() dialogs<BR />
' Additional value: 'TIMEOUT', returned when the MsgBoxResult = -1<BR />' All other values return the string 'ERROR'<BR /><BR />
On Error Resume Next<BR /><BR />
If (MsgBoxResult &GT;= vbOK) And (MsgBoxResult &LT;= vbNo) Then
    MsgBoxResultText = Split("ERROR,OK,CANCEL,ABORT,RETRY,IGNORE,YES,NO,", ",")(MsgBoxResult)
ElseIf MsgBoxResult = dlgTIMEOUT Then
    MsgBoxResultText = "TIMEOUT"
Else
    MsgBoxResultText = "ERROR"
End If<BR />End Function
'
'
'
'
'
'
'
'
'
'
Private Property Get MessageBox_Caption() As String
    MessageBox_Caption = m_strCaption
End Property<BR />
Private Property Let MessageBox_Caption(NewCaption As String)
    m_strCaption = NewCaption 
End Property<BR /><BR />
Private Sub TimedMessageBox(Caption As String, Seconds As Long)
On Error Resume Next<BR />
    ' REQUIRED for Function msgPopup
   ' Public Sub  TimerProcMessageBox  MUST EXIST<BR />
    MessageBox_Caption = Caption<BR />
    SetTimer 0&, 0&, Seconds * 1000, AddressOf TimerProcMessageBox<BR />
    Debug.Print "start Timer " & Now<BR />
End Sub<BR />

#If VBA7 And Win64 Then     ' 64 bit Excel under 64-bit windows<BR />                                ' Use LongLong and LongPtr<BR /><BR />
    Public Sub TimerProcMessageBox(ByVal hwnd As LongPtr, _
                                   ByVal wMsg As Long, _
                                   ByVal idEvent As LongPtr, _
                                   ByVal dwTime As LongLong)
    On Error Resume Next<BR />
    ' REQUIRED for Function msgPopup
    ' https://msdn.microsoft.com/en-US/library/windows/desktop/ms644907(v=vs.85).aspx<BR />
    ' Closes a dialog box (Shell.Popup or VBA.MsgBox) having a caption stored in MessageBox_Caption
    ' This TimerProc sends *any* message that can close the dialog: the objective is solely to close
    ' the dialog and resume the VBA thread. Your caller must detect the expired TimerProc interval
    ' and insert a custom return value (or default) that signals the 'Timeout' for responses.<BR />
    ' The MsgPopup implementation in this project returns -1 for this 'Timeout'<BR />
    Dim hWndMsgBox As LongPtr   ' Handle to VBA MsgBox<BR />
    KillTimer hWndMsgBox, idEvent<BR />
    hWndMsgBox = 0
    hWndMsgBox = FindWindow("#32770", MessageBox_Caption)<BR />
    If hWndMsgBox &LT;&GT; 0 Then<BR />
        ' Enumerate WM_COMMAND values
        For iDlgCommand = vbOK To vbNo
            If GetDlgItem(hWndMsgBox, iDlgCommand) &LT;&GT; 0 Then
                SendMessage hWndMsgBox, WM_COMMAND, iDlgCommand, 0&
                Exit For
            End If
        Next iDlgCommand<BR />
    End If<BR />
    End Sub<BR />

#ElseIf VBA7 Then    ' 64 bit Excel in all environments<BR />                         ' Use LongPtr only<BR /><BR />
    Public Sub TimerProcMessageBox(ByVal hwnd As LongPtr, _
                                   ByVal wMsg As Long, _
                                   ByVal idEvent As LongPtr, _
                                   ByVal dwTime As Long)
    On Error Resume Next<BR />                         
    ' REQUIRED for Function msgPopup
    ' https://msdn.microsoft.com/en-US/library/windows/desktop/ms644907(v=vs.85).aspx<BR />
    ' Closes a dialog box (Shell.Popup or VBA.MsgBox) having a caption stored in MessageBox_Caption
    ' This TimerProc sends *any* message that can close the dialog: the objective is solely to close
    ' the dialog and resume the VBA thread. Your caller must detect the expired TimerProc interval
    ' and insert a custom return value (or default) that signals the 'Timeout' for responses.<BR />    
    ' The MsgPopup implementation in this project returns -1 for this 'Timeout'<BR />
    Dim hWndMsgBox  As LongPtr          ' Handle to VBA MsgBox
    Dim iDlgCommand As VbMsgBoxResult   ' Dialog command values: OK, CANCEL, YES, NO, etc<BR />
    KillTimer hwnd, idEvent<BR />
    hWndMsgBox = 0
    hWndMsgBox = FindWindow("#32770", MessageBox_Caption)<BR />
    If hWndMsgBox &LT;&GT; 0 Then<BR />
        ' Enumerate WM_COMMAND values 
        For iDlgCommand = vbOK To vbNo
            If GetDlgItem(hWndMsgBox, iDlgCommand) &LT;&GT; 0 Then
                SendMessage hWndMsgBox, WM_COMMAND, iDlgCommand, 0&
                Exit For
            End If
        Next iDlgCommand<BR />
    End If<BR />
    End Sub<BR />

#Else    ' 32 bit Excel<BR /><BR />
    Public Sub TimerProcMessageBox(ByVal hwnd As Long, _
                                   ByVal wMsg As Long, _
                                   ByVal idEvent As Long, _
                                   ByVal dwTime As Long)
    On Error Resume Next<BR />
    ' REQUIRED for Function msgPopup<BR />
    ' The MsgPopup implementation in this project returns -1 for this 'Timeout'<BR />
    Dim hWndMsgBox As Long    ' Handle to VBA MsgBox<BR />
    KillTimer hwnd, idEvent<BR />
    hWndMsgBox = 0
    hWndMsgBox = FindWindow("#32770", MessageBox_Caption)<BR />
    If hWndMsgBox &LT;&GT; 0 Then<BR />
        ' Enumerate WM_COMMAND values 
        For iDlgCommand = vbOK To vbNo
            If GetDlgItem(hWndMsgBox, iDlgCommand) &LT;&GT; 0 Then
                SendMessage hWndMsgBox, WM_COMMAND, iDlgCommand, 0&
                Exit For
            End If
        Next iDlgCommand<BR />
    End If<BR />
    End Sub<BR />
#End If

And here are the API declarations – note the conditional declarations for VBA7, 64-Bit Windows, and plain-vanilla 32-bit:

'&nbsp;Explanation&nbsp;of&nbsp;compiler&nbsp;constants&nbsp;for&nbsp;64-Bit&nbsp;VBA&nbsp;and&nbsp;API&nbsp;declarations&nbsp;: '&nbsp;https://msdn.microsoft.com/en-us/library/office/ee691831(v=office.14).aspx #If&nbsp;VBA7&nbsp;And&nbsp;Win64&nbsp;Then&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'&nbsp;64&nbsp;bit&nbsp;Excel&nbsp;under&nbsp;64-bit&nbsp;windows&nbsp;'&nbsp;Use&nbsp;LongLong&nbsp;and&nbsp;LongPtr &nbsp;&nbsp;&nbsp;&nbsp;Private&nbsp;Declare&nbsp;PtrSafe&nbsp;Function&nbsp;FindWindow&nbsp;Lib&nbsp;"user32"&nbsp;Alias&nbsp;"FindWindowA"&nbsp;_ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ByVal&nbsp;lpClassName&nbsp;As&nbsp;String,&nbsp;_ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByVal&nbsp;lpWindowName&nbsp;As&nbsp;String)&nbsp;As&nbsp;LongPtr &nbsp;&nbsp;&nbsp;&nbsp;Private&nbsp;Declare&nbsp;PtrSafe&nbsp;Function&nbsp;SendMessage&nbsp;Lib&nbsp;"user32"&nbsp;Alias&nbsp;"SendMessageA"&nbsp;_ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ByVal&nbsp;hwnd&nbsp;As&nbsp;LongPtr,&nbsp;_ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByVal&nbsp;wMsg&nbsp;As&nbsp;Long,&nbsp;_ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByVal&nbsp;wParam&nbsp;As&nbsp;Long,&nbsp;_ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByRef&nbsp;lParam&nbsp;As&nbsp;Any&nbsp;_ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;)&nbsp;As&nbsp;LongPtr &nbsp;&nbsp;&nbsp;&nbsp;Private&nbsp;Declare&nbsp;PtrSafe&nbsp;Function&nbsp;SetTimer&nbsp;Lib&nbsp;"user32"&nbsp;_ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ByVal&nbsp;hwnd&nbsp;As&nbsp;LongPtr,&nbsp;_ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByVal&nbsp;nIDEvent&nbsp;As&nbsp;LongPtr,&nbsp;_ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByVal&nbsp;uElapse&nbsp;As&nbsp;Long,&nbsp;_ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByVal&nbsp;lpTimerFunc&nbsp;As&nbsp;LongPtr&nbsp;_ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;)&nbsp;As&nbsp;Long &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Public&nbsp;Declare&nbsp;PtrSafe&nbsp;Function&nbsp;KillTimer&nbsp;Lib&nbsp;"user32"&nbsp;_ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ByVal&nbsp;hwnd&nbsp;As&nbsp;LongPtr,&nbsp;_ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByVal&nbsp;nIDEvent&nbsp;As&nbsp;LongPtr&nbsp;_ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;)&nbsp;As&nbsp;Long &nbsp;&nbsp;&nbsp;&nbsp;Private&nbsp;Declare&nbsp;PtrSafe&nbsp;Function&nbsp;GetDlgItem&nbsp;Lib&nbsp;"user32"&nbsp;_ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ByVal&nbsp;hWndDlg&nbsp;As&nbsp;LongPtr,&nbsp;_ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByVal&nbsp;nIDDlgItem&nbsp;As&nbsp;Long&nbsp;_ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;)&nbsp;As&nbsp;LongPtr &nbsp;&nbsp;&nbsp;&nbsp; #ElseIf&nbsp;VBA7&nbsp;Then&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'&nbsp;VBA7&nbsp;in&nbsp;all&nbsp;environments,&nbsp;including&nbsp;32-Bit&nbsp;Office&nbsp;&nbsp;'&nbsp;Use&nbsp;LongPtr&nbsp;for&nbsp;ptrSafe&nbsp;declarations,&nbsp;LongLong&nbsp;is&nbsp;not&nbsp;available &nbsp;&nbsp;&nbsp;&nbsp;Private&nbsp;Declare&nbsp;PtrSafe&nbsp;Function&nbsp;FindWindow&nbsp;Lib&nbsp;"user32"&nbsp;Alias&nbsp;"FindWindowA"&nbsp;_ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ByVal&nbsp;lpClassName&nbsp;As&nbsp;String,&nbsp;_ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByVal&nbsp;lpWindowName&nbsp;As&nbsp;String)&nbsp;As&nbsp;LongPtr &nbsp;&nbsp;&nbsp;&nbsp;Private&nbsp;Declare&nbsp;PtrSafe&nbsp;Function&nbsp;SendMessage&nbsp;Lib&nbsp;"user32"&nbsp;Alias&nbsp;"SendMessageA"&nbsp;_ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ByVal&nbsp;hwnd&nbsp;As&nbsp;LongPtr,&nbsp;_ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByVal&nbsp;wMsg&nbsp;As&nbsp;Long,&nbsp;_ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByVal&nbsp;wParam&nbsp;As&nbsp;Long,&nbsp;_ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByRef&nbsp;lParam&nbsp;As&nbsp;Any&nbsp;_ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;)&nbsp;As&nbsp;LongPtr &nbsp;&nbsp;&nbsp;&nbsp;Private&nbsp;Declare&nbsp;PtrSafe&nbsp;Function&nbsp;SetTimer&nbsp;Lib&nbsp;"user32"&nbsp;_ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ByVal&nbsp;hwnd&nbsp;As&nbsp;LongPtr,&nbsp;_ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByVal&nbsp;nIDEvent&nbsp;As&nbsp;Long,&nbsp;_ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByVal&nbsp;uElapse&nbsp;As&nbsp;Long,&nbsp;_ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByVal&nbsp;lpTimerFunc&nbsp;As&nbsp;LongPtr)&nbsp;As&nbsp;LongPtr &nbsp;&nbsp;&nbsp;&nbsp;Private&nbsp;Declare&nbsp;PtrSafe&nbsp;Function&nbsp;KillTimer&nbsp;Lib&nbsp;"user32"&nbsp;_ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ByVal&nbsp;hwnd&nbsp;As&nbsp;LongPtr,&nbsp;_ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByVal&nbsp;nIDEvent&nbsp;As&nbsp;Long)&nbsp;As&nbsp;Long &nbsp;&nbsp;&nbsp;&nbsp;Private&nbsp;Declare&nbsp;PtrSafe&nbsp;Function&nbsp;GetDlgItem&nbsp;Lib&nbsp;"user32"&nbsp;_ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ByVal&nbsp;hWndDlg&nbsp;As&nbsp;LongPtr,&nbsp;_ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByVal&nbsp;nIDDlgItem&nbsp;As&nbsp;Long&nbsp;_ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;)&nbsp;As&nbsp;LongPtr #Else &nbsp;&nbsp;&nbsp;&nbsp;Private&nbsp;Declare&nbsp;Function&nbsp;FindWindow&nbsp;Lib&nbsp;"user32"&nbsp;Alias&nbsp;"FindWindowA"&nbsp;_ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ByVal&nbsp;lpClassName&nbsp;As&nbsp;String,&nbsp;_ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByVal&nbsp;lpWindowName&nbsp;As&nbsp;String)&nbsp;As&nbsp;Long &nbsp;&nbsp;&nbsp;&nbsp;Private&nbsp;Declare&nbsp;Function&nbsp;SendMessage&nbsp;Lib&nbsp;"user32"&nbsp;Alias&nbsp;"SendMessageA"&nbsp;_ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ByVal&nbsp;hwnd&nbsp;As&nbsp;Long,&nbsp;_ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByVal&nbsp;wMsg&nbsp;As&nbsp;Long,&nbsp;_ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByVal&nbsp;wParam&nbsp;As&nbsp;Long,&nbsp;_ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByRef&nbsp;lParam&nbsp;As&nbsp;Any&nbsp;_ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;)&nbsp;As&nbsp;Long &nbsp;&nbsp;&nbsp;&nbsp;Private&nbsp;Declare&nbsp;Function&nbsp;SetTimer&nbsp;Lib&nbsp;"user32"&nbsp;_ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ByVal&nbsp;hwnd&nbsp;As&nbsp;Long,&nbsp;_ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByVal&nbsp;nIDEvent&nbsp;As&nbsp;Long,&nbsp;_ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByVal&nbsp;uElapse&nbsp;As&nbsp;Long,&nbsp;_ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByVal&nbsp;lpTimerFunc&nbsp;As&nbsp;Long)&nbsp;As&nbsp;Long &nbsp;&nbsp;&nbsp;&nbsp;Public&nbsp;Declare&nbsp;Function&nbsp;KillTimer&nbsp;Lib&nbsp;"user32"&nbsp;_ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ByVal&nbsp;hwnd&nbsp;As&nbsp;Long,&nbsp;_ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByVal&nbsp;nIDEvent&nbsp;As&nbsp;Long)&nbsp;As&nbsp;Long &nbsp;&nbsp;&nbsp;&nbsp;Private&nbsp;Declare&nbsp;Function&nbsp;GetDlgItem&nbsp;Lib&nbsp;"user32"&nbsp;_<BR />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ByVal&nbsp;hWndDlg,&nbsp;ByVal&nbsp;nIDDlgItem&nbsp;As&nbsp;Long)&nbsp;As&nbsp;Long #End&nbsp;If Private&nbsp;Enum&nbsp;WINDOW_MESSAGE WM_ACTIVATE&nbsp;=&nbsp;6 WM_SETFOCUS&nbsp;=&nbsp;7 WM_KILLFOCUS&nbsp;=&nbsp;8 WM_PAINT&nbsp;=&nbsp;&HF WM_CLOSE&nbsp;=&nbsp;&H10 WM_QUIT&nbsp;=&nbsp;&H12 WM_COMMAND&nbsp;=&nbsp;&H111 WM_SYSCOMMAND&nbsp;=&nbsp;&H112 End&nbsp;Enum '&nbsp;Dialog&nbsp;Box&nbsp;Command&nbsp;IDs&nbsp;-&nbsp;replicates&nbsp;vbMsgBoxResult,&nbsp;with&nbsp;the&nbsp;addition&nbsp;of&nbsp;'dlgTIMEOUT' Public Enum DIALOGBOX_COMMAND dlgTIMEOUT&nbsp;=&nbsp;-1 dlgOK&nbsp;=&nbsp;1 dlgCANCEL&nbsp;=&nbsp;2 dlgABORT&nbsp;=&nbsp;3 dlgRETRY&nbsp;=&nbsp;4 dlgIGNORE&nbsp;=&nbsp;5 dlgYES&nbsp;=&nbsp;6 dlgNO&nbsp;=&nbsp;7 End Enum 

A final note: I would welcome suggestions for improvement from experienced MFC C++ developers, as you are going to have a much better grasp of the basic Windows message-passing concepts underlying a ‘Dialog’ window – I work in an oversimplified language and it is likely that the oversimplifications in my understanding have crossed the line into outright errors in my explanation.

Answer:

Going with Answer A. the Win32 solution. This meets the requirements, and is robust from testing so far.

Declare Function MessageBoxTimeout Lib "user32.dll" Alias "MessageBoxTimeoutA" ( _ ByVal hwnd As Long, _ ByVal lpText As String, _ ByVal lpCaption As String, _ ByVal uType As Long, _ ByVal wLanguageID As Long, _ ByVal lngMilliseconds As Long) As Long Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" ( _ ByVal lpClassName As String, _ ByVal lpWindowName As String) As Long Public Sub MsgBoxDelay() Const cmsg As String = "Yes or No? leaving this window for 1 min is the same as clicking Yes." Const cTitle As String = "popup window" Dim retval As Long retval = MessageBoxTimeout(FindWindow(vbNullString, Title), cmsg, cTitle, 4, 0, 60000) If retval <> 7 Then Call MethodFoo End If End Sub 

Answer:

Easy

Call CreateObject("WScript.Shell").Popup("Timed message box", 1, "Title", vbOKOnly) 

Answer:

Starting with the samples in this post my final code is as follows:

' Coded by Clint Smith ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' tMsgBox Function (Timered Message Box) ' By Clint Smith, [email protected] ' Created 04-Sep-2014 ' Updated for 64-bit 03-Mar-2020 ' This provides an publicly accessible procedure named ' tMsgBox that when invoked instantiates a timered ' message box. Many constants predefined for easy use. ' There is also a global result variable tMsgBoxResult. ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' Public Const mbBTN_Ok = vbOKOnly 'Default Public Const mbBTN_OkCancel = vbOKCancel Public Const mbBTN_AbortRetryIgnore = vbAbortRetryIgnore Public Const mbBTN_YesNoCancel = vbYesNoCancel Public Const mbBTN_YesNo = vbYesNo Public Const mbBTN_RetryCancel = vbRetryCancel Public Const mbBTN_CanceTryagainContinue = &H6 Public Const mbICON_Stop = vbCritical Public Const mbICON_Question = vbQuestion Public Const mbICON_Exclaim = vbExclamation Public Const mbICON_Info = vbInformation Public Const mbBTN_2ndDefault = vbDefaultButton2 Public Const mbBTN_3rdDefault = vbDefaultButton3 Public Const mbBTN_4rdDefault = vbDefaultButton4 Public Const mbBOX_Modal = vbSystemModal Public Const mbBTN_AddHelp = vbMsgBoxHelpButton Public Const mbTXT_RightJustified = vbMsgBoxRight Public Const mbWIN_Top = &H40000 'Default Public Const mbcTimeOut = 32000 Public Const mbcOk = vbOK Public Const mbcCancel = vbCancel Public Const mbcAbort = vbAbort Public Const mbcRetry = vbRetry Public Const mbcIgnore = vbIgnore Public Const mbcYes = vbYes Public Const mbcNo = vbNo Public Const mbcTryagain = 10 Public Const mbcContinue = 11 Public Const wAccessWin = "OMain" Public Const wExcelWin = "XLMAIN" Public Const wWordWin = "OpusApp" Public tMsgBoxResult As Long #If VBA7 Then Private Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" _ (ByVal lpClassName As String, _ ByVal lpWindowName As String) As Long Public Declare PtrSafe Function tMsgBoxA Lib "user32.dll" Alias "MessageBoxTimeoutA" ( _ ByVal hwnd As Long, _ ByVal lpText As String, _ ByVal lpCaption As String, _ ByVal uType As Long, _ ByVal wLanguageID As Long, _ ByVal lngMilliseconds As Long) As Long #Else Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" _ (ByVal lpClassName As String, _ ByVal lpWindowName As String) As Long Public Declare Function tMsgBoxA Lib "user32.dll" Alias "MessageBoxTimeoutA" ( _ ByVal hwnd As Long, _ ByVal lpText As String, _ ByVal lpCaption As String, _ ByVal uType As Long, _ ByVal wLanguageID As Long, _ ByVal lngMilliseconds As Long) As Long #End If Public Sub tMsgBox( _ Optional sMessage As String = "Default: (10 sec timeout)" & vbLf & "Coded by Clint Smith", _ Optional sTitle As String = "Message Box with Timer", _ Optional iTimer As Integer = 10, _ Optional hNtype As Long = mbBTN_Ok + mbWIN_Top, _ Optional hLangID As Long = &H0, _ Optional wParentType As String = vbNullString, _ Optional wParentName As String = vbNullString) tMsgBoxResult = tMsgBoxA(FindWindow(wParentType, wParentName), sMessage, sTitle, hNtype, hLangID, 1000 * iTimer) End Sub