vbscript sleep command in outlook

Hello,

I'm running code in an Outlook task form.  I want the code to pause for 2 seconds.  This code gives me the error "Object doesn't support this property or method: 'Myshell.Sleep'"

Set Myshell = CreateObject("WScript.Shell")
Myshell.Sleep 2000

Any ideas?
Joel
Genius123Asked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

ltlbearand3Commented:
Declare this at the top of your code:

Public Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)

Open in new window


And then you can use the Sleep command:
Sleep 2000
DoEvents

Open in new window

Genius123Author Commented:
This is at the top of my code:

Public Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)


Option Explicit

Dim oParent
Dim oNS
Dim oFolder


I get the error: "Expected end of statement Line No:1
zalazarCommented:
You can use
Application.Wait (Now + TimeValue("0:00:02"))
Determine the Perfect Price for Your IT Services

Do you wonder if your IT business is truly profitable or if you should raise your prices? Learn how to calculate your overhead burden with our free interactive tool and use it to determine the right price for your IT services. Download your free eBook now!

Genius123Author Commented:
error "Object doesn't support this property or method: 'Application.Wait'"
zalazarCommented:
If it's vbscript then:
Wscript.Sleep 2000
Genius123Author Commented:
I got the same error with that one.  Keep in mind this code is in an Outlook form.  I think the vbscript for that might be a tad different that other vbscript.  I could be wrong though.
ltlbearand3Commented:
Outlook VBA does not have the sleep command inherently available.  It should work in a form.  You may need to post your code for your form, but here is what it might look like:

Public Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Option Explicit

Public Sub MySubToDoSomething()
    Dim strVar1 As String
    Dim strVar2 As String
    
    strVar1 = "This is my test"
    Sleep 2000
    msgbox strVar1

End Sub

Open in new window

zalazarCommented:
I think you are right. I have the same experience with hta's.

I use there an extra file to implement a sleep function but it's not that convenient.
Set Myshell = CreateObject("WScript.Shell") 
Myshell.Run "wscript.exe Sleep.vbs", 7, True

Open in new window


Create a file named: Sleep.vbs
Wscript.Sleep 2000

Open in new window

zalazarCommented:
This will probably work but it will give a little more CPU load then the method from ltlbearand3.
 tTime0 = Now
 Do Until tTime0 + TimeValue("00:00:02") < Now
   DoEvents
 Loop

Open in new window

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
ltlbearand3Commented:
The vbscript and the Loop would both work, but there is not a need for them.  The Sleep command will work, as I run it in outlook code.  I just tested it on a form and change the declaration from a public to private event and it should work.  Here is some code I just created that ran on a form with a label and a command button.  When the button is clicked it runs the sleep event:

Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Option Explicit

Private Sub CommandButton1_Click()
    Label1.Caption = "This is now starting"
    DoEvents
    Sleep 5000
    Label1.Caption = "This has now ended"
End Sub

Open in new window

zalazarCommented:
Although the vbscript and the "Do Loop" would work and the "Do Loop" is also easy to implement I agree with "ltlbearand3". Using the sleep API function is the better option then.

The "Sleep" function has a disadvantage of not repainting the window.
This old Microsoft article describes it.
http://support2.microsoft.com/kb/231298
quote/
Many programmers use the Sleep API function to pause the execution of their programs. One of the disadvantages of using Sleep is that it pauses the thread that the application is running in, and that any window that the application has open will not repaint properly. This may present an unattractive user interface to the user. An alternative to Sleep is to use SetWaitableTimer, which will allow the screen to repaint, receive DDE messages, and so forth.
/quote

If repainting is important for you then you might want to use the code below.
I have simplified it and made it suitable for VBA.

Create a new module with the following code
Option Explicit

Private Type FILETIME
  dwLowDateTime As Long
  dwHighDateTime As Long
End Type

Private Const WAIT_OBJECT_0& = 0
Private Const INFINITE = &HFFFF
Private Const ERROR_ALREADY_EXISTS = 183&
Private Const QS_HOTKEY& = &H80
Private Const QS_KEY& = &H1
Private Const QS_MOUSEBUTTON& = &H4
Private Const QS_MOUSEMOVE& = &H2
Private Const QS_PAINT& = &H20
Private Const QS_POSTMESSAGE& = &H8
Private Const QS_SENDMESSAGE& = &H40
Private Const QS_TIMER& = &H10
Private Const QS_ALLINPUT& = (QS_SENDMESSAGE Or QS_PAINT Or QS_TIMER Or QS_POSTMESSAGE Or QS_MOUSEBUTTON Or QS_MOUSEMOVE Or QS_HOTKEY Or QS_KEY)

Private Declare Function CreateWaitableTimer Lib "kernel32" Alias "CreateWaitableTimerA" ( _
  ByVal lpSemaphoreAttributes As Long, ByVal bManualReset As Long, ByVal lpName As String) As Long
Private Declare Function SetWaitableTimer Lib "kernel32" (ByVal hTimer As Long, _
  lpDueTime As FILETIME, ByVal lPeriod As Long, ByVal pfnCompletionRoutine As Long, _
  ByVal lpArgToCompletionRoutine As Long, ByVal fResume As Long) As Long
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Private Declare Function MsgWaitForMultipleObjects Lib "user32" (ByVal nCount As Long, pHandles As Long, _
  ByVal fWaitAll As Long, ByVal dwMilliseconds As Long, ByVal dwWakeMask As Long) As Long

Public Sub Wait(lNumberOfSeconds As Long)
    Dim ft As FILETIME
    Dim lBusy As Long, lRet As Long, dblDelay As Double, dblDelayLow As Double, dblUnits As Double, hTimer As Long
    
    hTimer = CreateWaitableTimer(0, True, "VBA_Timer")
    If Err.LastDllError = ERROR_ALREADY_EXISTS Then
      ' If the timer already exists, it does not hurt to open it
      ' as long as the person who is trying to open it has the proper access rights.
    Else
      ft.dwLowDateTime = -1
      ft.dwHighDateTime = -1
      lRet = SetWaitableTimer(hTimer, ft, 0, 0, 0, 0)
    End If
    
    ' Convert the Units to nanoseconds.
    dblUnits = CDbl(&H10000) * CDbl(&H10000)
    dblDelay = CDbl(lNumberOfSeconds) * 1000 * 10000
    
    ' By setting the high/low time to a negative number, it tells the Wait (in SetWaitableTimer) to use an offset time as
    ' opposed to a hardcoded time. If it were positive, it would try to convert the value to GMT.
    ft.dwHighDateTime = -CLng(dblDelay / dblUnits) - 1
    dblDelayLow = -dblUnits * (dblDelay / dblUnits - Fix(dblDelay / dblUnits))
    
    If dblDelayLow < CDbl(&H80000000) Then
        ' &H80000000 is MAX_LONG, so you are just making sure that you don't overflow when you try to stick it into the FILETIME structure.
        dblDelayLow = dblUnits + dblDelayLow
        ft.dwHighDateTime = ft.dwHighDateTime + 1
    End If
    
    ft.dwLowDateTime = CLng(dblDelayLow)
    lRet = SetWaitableTimer(hTimer, ft, 0, 0, 0, False)
    Do
        ' QS_ALLINPUT means that MsgWaitForMultipleObjects will return every time the thread in which it is running gets
        ' a message. If you wanted to handle messages in here you could, but by calling Doevents you are letting DefWindowProc
        ' do its normal windows message handling---Like DDE, etc.
        lBusy = MsgWaitForMultipleObjects(1, hTimer, False, INFINITE, QS_ALLINPUT&)
        DoEvents
    Loop Until lBusy = WAIT_OBJECT_0
    
    ' Close the handles when you are done with them.
    CloseHandle hTimer
End Sub

Open in new window


You can then insert a sleep of 2 seconds via the following code:
Wait 2
ltlbearand3Commented:
@zalazar - You are correct that Sleep does not repaint the screen.  However, if that is important usually a simple DoEvents after the Sleep command will address the repaint issues.  Therefore a much simpler code is:

Sleep 2000
DoEvents

In over simplified terms, the DoEvents command tells the running process to pause and let the OS finish any steps in queue.
zalazarCommented:
@ltlbearand3 - Yes I agree with you about the repainting and thanks for the feedback.
Another small advantage about the code I posted is that it does give the possibility to do other things within Outlook during the sleep.
But if you just need a simple sleep and this doesn't matter your method is less complex and probably easier to implement.
Genius123Author Commented:
This worked and is a clever way to do it.  I'm sure other comments may have worked, but this seemed to be the easiest for me to understand.  Thanks.
zalazarCommented:
You're welcome and thanks too.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Outlook

From novice to tech pro — start learning today.