Показать окно сообщения со значением тайм-аута - PullRequest
5 голосов
/ 25 ноября 2010

Вопрос возникает из кода, подобного следующему.

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

Это простой способ отобразить окно сообщения с таймаутом от VBA (или VB6).

В Excel 2007 (по-видимому, иногда также происходит в Internet Explorer) всплывающее окно не будет иметь тайм-аут и вместо этого будет ждать ввода пользователя.

Эта проблема сложна для отладки, так как это происходит только изредка, и я не знаю, как воспроизвестивопрос.Я полагаю, что это проблема с модальными диалоговыми окнами Office, и Excel не распознает, что время ожидания истекло.

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

Обнаруженные мной обходные пути:

A.Используйте вызов Win32 API

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.Используйте ручной таймер с пользовательской формой VBA, которая выглядит как окно сообщений.Используйте глобальную переменную или аналогичную для сохранения любого состояния, которое необходимо передать обратно в вызывающий код.Убедитесь, что метод Show пользовательской формы вызывается с предоставленным параметром vbModeless.

C.Оберните вызов метода wscript.popup в процессе MSHTA, который позволит коду выйти из процесса и избежать модальной природы Office.

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

Как лучше всего использовать A, B или Cили ваш собственный ответ для отображения окна сообщения со значением времени ожидания в VBA?

Ответы [ 4 ]

7 голосов
/ 01 февраля 2016

Это длинный ответ, но есть много оснований для его рассмотрения: это также поздний ответ, но все изменилось, так как некоторые ответы на этот (и подобные вопросы) были размещены в стеке.Это отстой, как пылесос на трехфазном переменном токе, потому что они были хорошими ответами, когда они были опубликованы, и много думали о них.

Короткая версия: Я заметил, что Script WsShellВсплывающее решение перестало работать для меня в VBA год назад, и я закодировал работающий обратный вызов таймера API для функции VBA MsgBox.

Перейдите прямо к коду под заголовком VBA-код для вызоваокно сообщения с тайм-аутом , если вам нужен спешный ответ - и я сделал это, у меня есть буквально тысячи экземпляров самозапускающегося MsgPopup, заменяющего VBA.MsgBox для редактирования, и приведенный ниже код вписывается вавтономный модуль.

Однако здесь кодеры VBA, включая меня, нуждаются в некотором объяснении того, почему совершенно хороший код больше не работает.И если вы понимаете причины, вы можете использовать частичный обходной путь для диалогов «Отмена», скрытых в тексте.

Я заметил, что всплывающее решение Script WsShell перестало работать для меня в VBA год назад- Тайм-аут 'SecondsToWait' игнорировался, и диалог просто зависал, как знакомый VBA.MsgBox:

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

И я думаю, я знаю причину, почему: вы больше не можете отправлять WM_CLOSE или WM_QUITсообщение в диалоговое окно из любого места, кроме потока, который его открыл.Аналогично, функция User32 DestroyWindow () не закроет диалоговое окно, если она не вызвана потоком, открывшим диалоговое окно.

Кому-то в Редмонде не нравится идея сценария, работающего в фоновом режиме и отправляющегоWM_CLOSE подает команды всем тем существенным предупреждениям, которые останавливают вашу работу (и, в наши дни, чтобы заставить их уйти навсегда, нужны права локального администратора).

Я не могу представить , кто написал бы такой сценарий, это ужасная идея!

У этого решения есть последствия и сопутствующий ущерб: WsScript.Popup () объекты в однопоточной среде VBA реализуют свой тайм-аут SecondsToWait с помощью обратного вызова Timer, и этот обратный вызов отправляет сообщение WM_CLOSE или что-то подобное ... Что в большинстве случаев игнорируется, поскольку это поток обратного вызова, а непоток владельца для этого диалога.

Вы могли бы заставить его работать во всплывающем окне с помощью кнопки 'ОТМЕНА', и станет понятно, почему это происходит через минуту или две.

Я пытался написать таймер обратного вызова для WM_CLOSE во всплывающем окне, но в большинстве случаев это тоже не получалось.

Я пробовал несколько экзотических обратных вызовов API, чтобы связываться с окнами VBA.MsgBox и WsShell.Popup, и теперь я могу сказать вам, что они не работали.Вы не можете работать с тем, чего нет: эти диалоговые окна очень просты, и большинство из них вообще не содержат никакой функциональности, за исключением ответов на нажатия кнопок - Да, Нет, ОК, Отмена, Отмена, Повторить, Пропустить и Справка.

«Отмена» - это интересный вопрос: кажется, что вы получаете бесплатную от примитивного Windows API для встроенных диалогов, когда вы указываете vbOKCancel или vbRetryCancel илиvbYesNoCancel - функция «Отмена» автоматически реализуется с помощью кнопки «Закрыть» в строке меню диалогового окна (вы не получаете этого с другими кнопками, но можете попробовать ее в диалоговом окне, содержащем «Игнорировать»),это означает, что ....

Диалоги WsShell.Popup () иногда будут реагировать на тайм-аут SecondsToWait, если у них есть опция «Отмена».

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

Это может быть достаточно хорошимОбходной путь для тех, кто читает это, если все, что вам нужно, это получить функции WsShell.Popup () для повторного ответа на параметр SecondsToWait.

Это также означает, что вы можете отправить сообщение WM_CLOSEПерейдите в диалог «Отмена» с помощью вызова API SendMessage () для обратного вызова:

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

Строго говоря, это должно работать только для сообщения WM_SYSCOMMAND, SC_CLOSE - поле «Закрыть» на панели команд - это «системное» меню со специальным классом команд, но, как я уже сказал, мы получаем халяву от Windows API.

Я получил это на работу, и я начал думать: Если бы я мог работать только с тем, что там, возможно, я бы лучше выяснил, что на самом деле там ...

И ответ оказывается очевидным: диалоговые окна имеют свой собственный набор параметров сообщения WM_COMMAND -

' 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

И, поскольку это «пользовательские» сообщения, которые возвращают пользовательские ответы на вызывающего (то есть вызывающего потока) диалогового окна, диалоговое окно с радостью принимает их и закрывает себя.

Вы можете опросить диалоговое окно, чтобы увидеть, реализует ли оно определенную команду, и, если оно это делает, вы можете отправить эту команду:

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

Остальной задачей является обнаружение «тайм-аута» и перехват возвращаемого ответа «Окна сообщения», а также подстановка собственного значения: -1, если мы следуем соглашению, установленному функцией WsShell.Popup(). Итак, наша оболочка msgPopup для окна сообщений с тайм-аутом должна сделать три вещи:

  1. Позвоните в наш API Timer для отложенного закрытия диалогового окна;
  2. Открыть окно сообщения, передав обычные параметры;
  3. Либо: определить тайм-аут и заменить ответ «тайм-аут» ...
    ... Или вернуть ответ пользователя в диалог, если он ответил в время

В других случаях нам нужно объявить вызовы API для всего этого, и мы абсолютно должны иметь публично объявленную функцию 'TimerProc' для вызова API Timer. Эта функция должна существовать, и она должна запускаться до «End Function» без ошибок или точек останова - любое прерывание, и API Timer () вызовет гнев операционной системы.

Код VBA для вызова окна сообщения с тайм-аутом:

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 />

&#35;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("&#35;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 />

&#35;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("&#35;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 />

&#35;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("&#35;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 />
&#35;End If

А вот и объявления API - обратите внимание на условные объявления для VBA7, 64-битной Windows и простой-ванильной 32-битной:

'&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

&#35;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;
&#35;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
&#35;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
&#35;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

Последнее замечание: я бы приветствовал предложения по улучшению от опытных разработчиков MFC C ++, поскольку вы будете гораздо лучше понимать основные концепции передачи сообщений Windows, лежащие в основе окна «Диалог» - я работаю на упрощенном языке и вполне вероятно, что упрощения в моем понимании перешли черту в прямые ошибки в моем объяснении.

5 голосов
/ 29 ноября 2010

Идем с Ответом А. Решение Win32.Это соответствует требованиям и пока не поддается проверке.

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
0 голосов
/ 06 февраля 2017

Easy

Call CreateObject("WScript.Shell").Popup("Timed message box", 1, "Title", vbOKOnly)
0 голосов
/ 06 января 2017

Начиная с примеров в этом посте, мой окончательный код выглядит следующим образом:

' Coded by Clint Smith
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' tMsgBox Function (Timered Message Box)
' By Clint Smith, clintasm@gmail.com
' Created 04-Sep-2014
' 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.
' This was written using undocumented procedure in user32.dll
' due to a buggy WScript.shell result where message window did
' not close after timer expiration.
'
' Defaults to regular information top most message box with ok
' button only.
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
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

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

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

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)
    AppHWnd = FindWindow(wParentType, wParentName)
    tMsgBoxResult = tMsgBoxA(AppHWnd, sMessage, sTitle, hNtype, hLangID, 1000 * iTimer)
End Sub
...