Jaafar Tribak

Well-known Member
Joined
Dec 5, 2002
Messages
9,621
Office Version
  1. 2016
Platform
  1. Windows
Hi all,

I have seen this requested on some occasions and the usual answer is to create a userform that looks and behaves like an inputbox and then use OnTime to schedule the closing of the userform upon time-out.

In case anyone is interested, I am showing here an alternative that uses the actual standard vba InputBox function to which I have added an extra optional argument at the end named SecondsTimeOut

Add a new Standard Module to your VBProject and give the module the name of : TimedInputBas

Place this code in the added module:
Code:
Option Explicit

[URL="https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=If"]#If[/URL]  VBA7 Then
    Private Declare PtrSafe Function SetTimer Lib "user32" (ByVal hwnd As LongPtr, ByVal nIDEvent As LongPtr, ByVal uElapse As Long, ByVal lpTimerFunc As LongPtr) As LongPtr
    Private Declare PtrSafe Function KillTimer Lib "user32" (ByVal hwnd As LongPtr, ByVal nIDEvent As LongPtr) As Long
    Private Declare PtrSafe Function GetLastActivePopup Lib "user32" (ByVal hwndOwnder As LongPtr) As LongPtr
    Private Declare PtrSafe Function GetActiveWindow Lib "user32" () As LongPtr
    Private Declare PtrSafe Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As LongPtr, ByVal wMsg As Long, ByVal wParam As LongPtr, lParam As Any) As LongPtr
    Private Declare PtrSafe Function GetDlgItem Lib "user32" (ByVal hDlg As LongPtr, ByVal nIDDlgItem As Long) As LongPtr
[URL="https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=Else"]#Else[/URL] 
    Private Declare Function SetTimer Lib "user32" (ByVal hwnd As Long, ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long
    Private Declare Function KillTimer Lib "user32" (ByVal hwnd As Long, ByVal nIDEvent As Long) As Long
    Private Declare Function GetLastActivePopup Lib "user32" (ByVal hwndOwnder As Long) As Long
    Private Declare Function GetActiveWindow Lib "user32" () 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 GetDlgItem Lib "user32" (ByVal hDlg As Long, ByVal nIDDlgItem As Long) As Long
[URL="https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=End"]#End[/URL]  If
 
Private Const IDCANCEL = &H2
Private Const BM_CLICK = &HF5


Function Timed_InputBox( _
    Prompt, _
    Optional Title, _
    Optional Default, _
    Optional XPos, _
    Optional YPos, _
    Optional HelpFile, _
    Optional Context, _
    Optional SecondsTimeOut As Single _
) As String

    Static bFlag As Boolean
    Static hwnd As Long
    Static sTimer As Single
    Static sTimeOut As Single
    
    On Error GoTo ErrHandler
    
    If bFlag = False Then
        bFlag = True
        SetTimer Application.hwnd, 0, 0, AddressOf TimedInputbas.Timed_InputBox
        hwnd = 0
        sTimer = Timer
        If SecondsTimeOut <= 0 Then KillTimer Application.hwnd, 0: bFlag = False Else sTimeOut = SecondsTimeOut
        Timed_InputBox = InputBox(Prompt, Title, Default, XPos, YPos, HelpFile, Context)
        If bFlag = False And SecondsTimeOut > 0 Then Timed_InputBox = "InputBox Timed-Out"
        Exit Function
    End If
    
    If hwnd = 0 Then hwnd = CLng(GetActiveWindow)
    
    If (Timer - sTimer) >= sTimeOut Or GetLastActivePopup(Application.hwnd) = Application.hwnd Then
        bFlag = False
        KillTimer Application.hwnd, 0
        Call SendMessage(GetDlgItem(hwnd, IDCANCEL), BM_CLICK, 0, ByVal 0)
    End If
    
    Exit Function
    
ErrHandler:
    KillTimer Application.hwnd, 0
    
End Function

Here is an example of how to use the timed InputBox :
Code:
Option Explicit

Sub Test()

    Dim sInputText As String
    
    sInputText = Timed_InputBox(Prompt:="Enter Some Text :", Title:="Time-Out InputBox Demo.", SecondsTimeOut:=6) [COLOR=#008000]'Wait 6 Secs for user input.[/COLOR]
    
    MsgBox sInputText

End Sub
 
Last edited:

Excel Facts

Spell Check in Excel
Press F7 to start spell check in Excel. Be careful, by default, Excel does not check Capitalized Werds (whoops)
Hello Jaafar,

As usual ... Brilliant Solution ... :wink:

Thanks a lot for sharing ...

Cheers
 
Upvote 0
Hi again,

I was surprised to find out that the above code crashes when ran on 32bit excel (at least that's what I experienced when testing on a 32bit machine)

So please, ignore the previous code and use the following one .

Also, I have now added a nice feature to the timed vba InputBox and that is a small countdown clock under the Cancel button



Workbook demo

Code in a Standard Module :
Code:
Option Explicit

Type POINTAPI
    x As Long
    y As Long
End Type

Type RECT
    Left As Long
    Top As Long
    Right As Long
    Bottom As Long
End Type

Type LOGFONT
    lfHeight As Long
    lfWidth As Long
    lfEscapement As Long
    lfOrientation As Long
    lfWeight As Long
    lfItalic As Byte
    lfUnderline As Byte
    lfStrikeOut As Byte
    lfCharSet As Byte
    lfOutPrecision As Byte
    lfClipPrecision As Byte
    lfQuality As Byte
    lfPitchAndFamily As Byte
    lfFaceName As String * 32
End Type

[URL=https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=If]#If[/URL]  VBA7 Then
    Private Declare PtrSafe Function SetTimer Lib "user32" (ByVal hwnd As LongPtr, ByVal nIDEvent As LongPtr, ByVal uElapse As Long, ByVal lpTimerFunc As LongPtr) As LongPtr
    Private Declare PtrSafe Function KillTimer Lib "user32" (ByVal hwnd As LongPtr, ByVal nIDEvent As LongPtr) As Long
    Private Declare PtrSafe Function GetLastActivePopup Lib "user32" (ByVal hwndOwnder As LongPtr) As LongPtr
    Private Declare PtrSafe Function GetActiveWindow Lib "user32" () As LongPtr
    Private Declare PtrSafe Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As LongPtr, ByVal wMsg As Long, ByVal wParam As LongPtr, lParam As Any) As LongPtr
    Private Declare PtrSafe Function GetDlgItem Lib "user32" (ByVal hDlg As LongPtr, ByVal nIDDlgItem As Long) As LongPtr
    Private Declare PtrSafe Function GetDC Lib "user32" (ByVal hwnd As LongPtr) As LongPtr
    Private Declare PtrSafe Function ReleaseDC Lib "user32" (ByVal hwnd As LongPtr, ByVal hDC As LongPtr) As Long
    Private Declare PtrSafe Function GetWindowRect Lib "user32" (ByVal hwnd As LongPtr, lpRect As RECT) As Long
    Private Declare PtrSafe Function ScreenToClient Lib "user32" (ByVal hwnd As LongPtr, lpPoint As POINTAPI) As Long
    Private Declare PtrSafe Function TextOut Lib "gdi32" Alias "TextOutA" (ByVal hDC As LongPtr, ByVal x As Long, ByVal y As Long, ByVal lpString As String, ByVal nCount As Long) As Long
    Private Declare PtrSafe Function CreateFontIndirect Lib "gdi32" Alias "CreateFontIndirectA" (lpLogFont As LOGFONT) As LongPtr
    Private Declare PtrSafe Function SelectObject Lib "gdi32" (ByVal hDC As LongPtr, ByVal hObject As LongPtr) As LongPtr
    Private Declare PtrSafe Function DeleteObject Lib "gdi32" (ByVal hObject As LongPtr) As Long
    Private Declare PtrSafe Function SetTextColor Lib "gdi32" (ByVal hDC As LongPtr, ByVal crColor As Long) As Long
    Private Declare PtrSafe Function SetBkColor Lib "gdi32" (ByVal hDC As LongPtr, ByVal crColor As Long) As Long
    Private Declare PtrSafe Function GetSysColor Lib "user32" (ByVal nIndex As Long) As Long
    Private Declare PtrSafe Function DrawText Lib "user32" Alias "DrawTextA" (ByVal hDC As LongPtr, ByVal lpStr As String, ByVal nCount As Long, lpRect As RECT, ByVal wFormat As Long) As Long
    Private Declare PtrSafe Function DrawEdge Lib "user32" (ByVal hDC As LongPtr, qrc As RECT, ByVal edge As Long, ByVal grfFlags As Long) As Long
    Private Declare PtrSafe Function SetRect Lib "user32" (lpRect As RECT, ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long) As Long

[URL=https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=Else]#Else[/URL] 
    Private Declare Function SetTimer Lib "user32" (ByVal hwnd As Long, ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long
    Private Declare Function KillTimer Lib "user32" (ByVal hwnd As Long, ByVal nIDEvent As Long) As Long
    Private Declare Function GetLastActivePopup Lib "user32" (ByVal hwndOwnder As Long) As Long
    Private Declare Function GetActiveWindow Lib "user32" () 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 GetDlgItem Lib "user32" (ByVal hDlg As Long, ByVal nIDDlgItem As Long) As Long
    Private Declare Function GetDC Lib "user32" (ByVal hwnd As Long) As Long
    Private Declare Function ReleaseDC Lib "user32" (ByVal hwnd As Long, ByVal hDC As Long) As Long
    Private Declare Function GetWindowRect Lib "user32" (ByVal hwnd As Long, lpRect As RECT) As Long
    Private Declare Function ScreenToClient Lib "user32" (ByVal hwnd As Long, lpPoint As POINTAPI) As Long
    Private Declare Function TextOut Lib "gdi32" Alias "TextOutA" (ByVal hDC As Long, ByVal x As Long, ByVal y As Long, ByVal lpString As String, ByVal nCount As Long) As Long
    Private Declare Function CreateFontIndirect Lib "gdi32" Alias "CreateFontIndirectA" (lpLogFont As LOGFONT) As Long
    Private Declare Function SelectObject Lib "gdi32" (ByVal hDC As Long, ByVal hObject As Long) As Long
    Private Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long
    Private Declare Function SetTextColor Lib "gdi32" (ByVal hDC As Long, ByVal crColor As Long) As Long
    Private Declare Function SetBkColor Lib "gdi32" (ByVal hDC As Long, ByVal crColor As Long) As Long
    Private Declare Function GetSysColor Lib "user32" (ByVal nIndex As Long) As Long
    Private Declare Function DrawText Lib "user32" Alias "DrawTextA" (ByVal hDC As Long, ByVal lpStr As String, ByVal nCount As Long, lpRect As RECT, ByVal wFormat As Long) As Long
    Private Declare Function DrawEdge Lib "user32" (ByVal hDC As Long, qrc As RECT, ByVal edge As Long, ByVal grfFlags As Long) As Long
    Private Declare Function SetRect Lib "user32" (lpRect As RECT, ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long) As Long

[URL=https://www.mrexcel.com/forum/usertag.php?do=list&action=hash&hash=End]#End[/URL]  If
 
Private Const IDCANCEL = &H2
Private Const BM_CLICK = &HF5
Private Const DT_CALCRECT = &H400
Private Const COLOR_BTNFACE = 15
Private Const BDR_SUNKENOUTER = &H2
Private Const BDR_RAISEDINNER = &H4
Private Const EDGE_ETCHED = (BDR_SUNKENOUTER Or BDR_RAISEDINNER)
Private Const BF_BOTTOM = &H8
Private Const BF_LEFT = &H1
Private Const BF_RIGHT = &H4
Private Const BF_TOP = &H2
Private Const BF_RECT = (BF_LEFT Or BF_TOP Or BF_RIGHT Or BF_BOTTOM)

Private bTimedOut As Boolean
Private bShowCountDown As Boolean
Private sTimer As Single
Private sTimeOut As Single
Private hwnd As Long
  
Function Timed_InputBox( _
    Prompt, _
    Optional Title, _
    Optional Default, _
    Optional XPos, _
    Optional YPos, _
    Optional HelpFile, _
    Optional Context, _
    Optional SecondsTimeOut As Single, _
    Optional ShowCountDown As Boolean = False _
) As String

        bShowCountDown = ShowCountDown
        sTimer = Timer
        sTimeOut = IIf(SecondsTimeOut > 86400, 86400, SecondsTimeOut)
        bTimedOut = False
        hwnd = 0
        
        SetTimer Application.hwnd, 0, 0, AddressOf TimerProc
        Timed_InputBox = InputBox(Prompt, Title, Default, XPos, YPos, HelpFile, Context)
        If bTimedOut = True Then Timed_InputBox = "InputBox Timed-Out"
    
End Function

Private Sub TimerProc()
    
    Dim tFont As LOGFONT, tRect As RECT, tEdgeRect As RECT, tPt1 As POINTAPI, tpt2 As POINTAPI
    Dim sTimeLeft As String, hNewFont As Long, hDC As Long
    
    If sTimeOut Then
 
        If hwnd = 0 Then hwnd = CLng(GetActiveWindow)
        
        sTimeLeft = sTimeOut - (Timer - sTimer)
        sTimeLeft = Format(Int(sTimeLeft / 3600), "00") & ":" & Format(Int((sTimeLeft Mod 3600) / 60), "00") & _
        ":" & Format(sTimeLeft Mod 60, "00")
        
        If bShowCountDown And IsDate(sTimeLeft) Then
        
            Call GetWindowRect(GetDlgItem(hwnd, IDCANCEL), tRect)
            
            tPt1.x = tRect.Left + 2: tPt1.y = tRect.Top + (tRect.Bottom - tRect.Top) * 1.5
            tpt2.x = tRect.Right + 1: tpt2.y = tPt1.y + (tRect.Bottom - tRect.Top) / 1.5
            Call ScreenToClient(hwnd, tPt1)
            Call ScreenToClient(hwnd, tpt2)
            
            hDC = CLng(GetDC(hwnd))
        
            With tFont
                .lfHeight = 13: .lfFaceName = "Rockwell Extra Bold" & Chr(0)
            End With
            hNewFont = CLng(CreateFontIndirect(tFont))
            Call DeleteObject(SelectObject(hDC, hNewFont))
            
            Call SetRect(tEdgeRect, tPt1.x - 2, tPt1.y - 2, tpt2.x, tpt2.y)
            Call DrawEdge(hDC, tEdgeRect, EDGE_ETCHED, BF_RECT)
        
            Call SetTextColor(hDC, vbRed)
            Call SetBkColor(hDC, GetSysColor(COLOR_BTNFACE))
            
            With tRect
                Call DrawText(hDC, sTimeLeft, Len(sTimeLeft), tRect, DT_CALCRECT)
                Call TextOut(hDC, tPt1.x, tPt1.y, sTimeLeft, Len(sTimeLeft))
            End With
            
            Call DeleteObject(hNewFont)
            Call ReleaseDC(hwnd, hDC)
        
        End If
        
        bTimedOut = (Timer - sTimer) >= sTimeOut
         
        If (Timer - sTimer) >= sTimeOut Xor GetLastActivePopup(Application.hwnd) <> hwnd Then
            Call KillTimer(Application.hwnd, 0)
            Call SendMessage(GetDlgItem(hwnd, IDCANCEL), BM_CLICK, 0, ByVal 0)
        End If
    
    Else
    
        Call KillTimer(Application.hwnd, 0)
    
    End If

End Sub

And here is how to use the timed InputBox :
Code:
Option Explicit

Sub Test()

    Dim sInputText As String
    
[COLOR=#008000]    'Wait 10 Secs for user input.[/COLOR]
    sInputText = Timed_InputBox(Prompt:="Enter Some Text :", Title:="Time-Out InputBox Demo.", SecondsTimeOut:=10, _
    ShowCountDown:=True)
    
    MsgBox sInputText

End Sub
 
Upvote 0
Hi Jaafar,

For your info ... at my end ... your code does not crash on a 32bit machine ...

Thanks for the added feature ...:wink:
 
Upvote 0
Hi Jaafar,

Strong, for your info ok on a 64 bit machine ...

Thanks
 
Last edited:
Upvote 0
@ISY, Ingolf

Thank you for the feedback and glad you liked it.
 
Upvote 0
awesome code @Jaafar Tribak . It is possible to include the character used and left near the countdown. Also, is it possible to increase the character count to 1000?
 
Upvote 0

Forum statistics

Threads
1,215,054
Messages
6,122,895
Members
449,097
Latest member
dbomb1414

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top