Advertisement
Guest User

vba_ShellAndWait

a guest
May 3rd, 2012
131
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. Option Explicit
  2. Option Compare Text
  3.  
  4. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  5. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  6. ' modShellAndWait
  7. ' By Chip Pearson, chip@cpearson.com, www.cpearson.com
  8. ' This page on the web site: www.cpearson.com/Excel/ShellAndWait.aspx
  9. ' 9-September-2008
  10. '
  11. ' This module contains code for the ShellAndWait function that will Shell to a process
  12. ' and wait for that process to end before returning to the caller.
  13. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  14. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  15. Private Declare Function WaitForSingleObject Lib "kernel32" ( _
  16.     ByVal hHandle As Long, _
  17.     ByVal dwMilliseconds As Long) As Long
  18.  
  19. Private Declare Function OpenProcess Lib "kernel32.dll" ( _
  20.     ByVal dwDesiredAccess As Long, _
  21.     ByVal bInheritHandle As Long, _
  22.     ByVal dwProcessId As Long) As Long
  23.  
  24. Private Declare Function CloseHandle Lib "kernel32" ( _
  25.     ByVal hObject As Long) As Long
  26.  
  27. Private Const SYNCHRONIZE = &H100000
  28.  
  29. Public Enum ShellAndWaitResult
  30.     Success = 0
  31.     Failure = 1
  32.     TimeOut = 2
  33.     InvalidParameter = 3
  34.     SysWaitAbandoned = 4
  35.     UserWaitAbandoned = 5
  36.     UserBreak = 6
  37. End Enum
  38.  
  39. Public Enum ActionOnBreak
  40.     IgnoreBreak = 0
  41.     AbandonWait = 1
  42.     PromptUser = 2
  43. End Enum
  44.  
  45. Private Const STATUS_ABANDONED_WAIT_0 As Long = &H80
  46. Private Const STATUS_WAIT_0 As Long = &H0
  47. Private Const WAIT_ABANDONED As Long = (STATUS_ABANDONED_WAIT_0 + 0)
  48. Private Const WAIT_OBJECT_0 As Long = (STATUS_WAIT_0 + 0)
  49. Private Const WAIT_TIMEOUT As Long = 258&
  50. Private Const WAIT_FAILED As Long = &HFFFFFFFF
  51. Private Const WAIT_INFINITE = -1&
  52.  
  53.  
  54. Public Function ShellAndWait(ShellCommand As String, _
  55.                     TimeOutMs As Long, _
  56.                     ShellWindowState As VbAppWinStyle, _
  57.                     BreakKey As ActionOnBreak) As ShellAndWaitResult
  58. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  59. ' ShellAndWait
  60. '
  61. ' This function calls Shell and passes to it the command text in ShellCommand. The function
  62. ' then waits for TimeOutMs (in milliseconds) to expire.
  63. '
  64. '   Parameters:
  65. '       ShellCommand
  66. '           is the command text to pass to the Shell function.
  67. '
  68. '       TimeOutMs
  69. '           is the number of milliseconds to wait for the shell'd program to wait. If the
  70. '           shell'd program terminates before TimeOutMs has expired, the function returns
  71. '           ShellAndWaitResult.Success = 0. If TimeOutMs expires before the shell'd program
  72. '           terminates, the return value is ShellAndWaitResult.TimeOut = 2.
  73. '
  74. '       ShellWindowState
  75. '           is an item in VbAppWinStyle specifying the window state for the shell'd program.
  76. '
  77. '       BreakKey
  78. '           is an item in ActionOnBreak indicating how to handle the application's cancel key
  79. '           (Ctrl Break). If BreakKey is ActionOnBreak.AbandonWait and the user cancels, the
  80. '           wait is abandoned and the result is ShellAndWaitResult.UserWaitAbandoned = 5.
  81. '           If BreakKey is ActionOnBreak.IgnoreBreak, the cancel key is ignored. If
  82. '           BreakKey is ActionOnBreak.PromptUser, the user is given a ?Continue? message. If the
  83. '           user selects "do not continue", the function returns ShellAndWaitResult.UserBreak = 6.
  84. '           If the user selects "continue", the wait is continued.
  85. '
  86. '   Return values:
  87. '            ShellAndWaitResult.Success = 0
  88. '               indicates the the process completed successfully.
  89. '            ShellAndWaitResult.Failure = 1
  90. '               indicates that the Wait operation failed due to a Windows error.
  91. '            ShellAndWaitResult.TimeOut = 2
  92. '               indicates that the TimeOutMs interval timed out the Wait.
  93. '            ShellAndWaitResult.InvalidParameter = 3
  94. '               indicates that an invalid value was passed to the procedure.
  95. '            ShellAndWaitResult.SysWaitAbandoned = 4
  96. '               indicates that the system abandoned the wait.
  97. '            ShellAndWaitResult.UserWaitAbandoned = 5
  98. '               indicates that the user abandoned the wait via the cancel key (Ctrl+Break).
  99. '               This happens only if BreakKey is set to ActionOnBreak.AbandonWait.
  100. '            ShellAndWaitResult.UserBreak = 6
  101. '               indicates that the user broke out of the wait after being prompted with
  102. '               a ?Continue message. This happens only if BreakKey is set to
  103. '               ActionOnBreak.PromptUser.
  104. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  105.  
  106. Dim TaskID As Long
  107. Dim ProcHandle As Long
  108. Dim WaitRes As Long
  109. Dim Ms As Long
  110. Dim MsgRes As VbMsgBoxResult
  111. 'Dim SaveCancelKey As Integer
  112. Dim ElapsedTime As Long
  113. Dim Quit As Boolean
  114. Const ERR_BREAK_KEY = 18
  115. Const DEFAULT_POLL_INTERVAL = 500
  116.  
  117. If Trim(ShellCommand) = vbNullString Then
  118.     ShellAndWait = ShellAndWaitResult.InvalidParameter
  119.     Exit Function
  120. End If
  121.  
  122. If TimeOutMs < 0 Then
  123.     ShellAndWait = ShellAndWaitResult.InvalidParameter
  124.     Exit Function
  125. ElseIf TimeOutMs = 0 Then
  126.     Ms = WAIT_INFINITE
  127. Else
  128.     Ms = TimeOutMs
  129. End If
  130.  
  131. Select Case BreakKey
  132.     Case AbandonWait, IgnoreBreak, PromptUser
  133.         ' valid
  134.    Case Else
  135.         ShellAndWait = ShellAndWaitResult.InvalidParameter
  136.         Exit Function
  137. End Select
  138.  
  139. Select Case ShellWindowState
  140.     Case vbHide, vbMaximizedFocus, vbMinimizedFocus, vbMinimizedNoFocus, vbNormalFocus, vbNormalNoFocus
  141.         ' valid
  142.    Case Else
  143.         ShellAndWait = ShellAndWaitResult.InvalidParameter
  144.         Exit Function
  145. End Select
  146.  
  147. On Error Resume Next
  148. Err.Clear
  149. TaskID = Shell(ShellCommand, ShellWindowState)
  150. If (Err.Number <> 0) Or (TaskID = 0) Then
  151.     ShellAndWait = ShellAndWaitResult.Failure
  152.     Exit Function
  153. End If
  154.  
  155. ProcHandle = OpenProcess(SYNCHRONIZE, False, TaskID)
  156. If ProcHandle = 0 Then
  157.     ShellAndWait = ShellAndWaitResult.Failure
  158.     Exit Function
  159. End If
  160.  
  161. On Error GoTo ErrH:
  162. 'SaveCancelKey = Application.EnableCancelKey
  163. 'Application.EnableCancelKey = xlErrorHandler
  164. WaitRes = WaitForSingleObject(ProcHandle, DEFAULT_POLL_INTERVAL)
  165. Do Until WaitRes = WAIT_OBJECT_0
  166.     DoEvents
  167.     Select Case WaitRes
  168.         Case WAIT_ABANDONED
  169.             ' Windows abandoned the wait
  170.            ShellAndWait = ShellAndWaitResult.SysWaitAbandoned
  171.             Exit Do
  172.         Case WAIT_OBJECT_0
  173.             ' Successful completion
  174.            ShellAndWait = ShellAndWaitResult.Success
  175.             Exit Do
  176.         Case WAIT_FAILED
  177.             ' attach failed
  178.            ShellAndWait = ShellAndWaitResult.Failure
  179.             Exit Do
  180.         Case WAIT_TIMEOUT
  181.             ' Wait timed out. Here, this time out is on DEFAULT_POLL_INTERVAL.
  182.            ' See if ElapsedTime is greater than the user specified wait
  183.            ' time out. If we have exceed that, get out with a TimeOut status.
  184.            ' Otherwise, reissue as wait and continue.
  185.            ElapsedTime = ElapsedTime + DEFAULT_POLL_INTERVAL
  186.             If Ms > 0 Then
  187.                 ' user specified timeout
  188.                If ElapsedTime > Ms Then
  189.                     ShellAndWait = ShellAndWaitResult.TimeOut
  190.                     Exit Do
  191.                 Else
  192.                     ' user defined timeout has not expired.
  193.                End If
  194.             Else
  195.                 ' infinite wait -- do nothing
  196.            End If
  197.             ' reissue the Wait on ProcHandle
  198.            WaitRes = WaitForSingleObject(ProcHandle, DEFAULT_POLL_INTERVAL)
  199.            
  200.         Case Else
  201.             ' unknown result, assume failure
  202.            ShellAndWait = ShellAndWaitResult.Failure
  203.             Exit Do
  204.             Quit = True
  205.     End Select
  206. Loop
  207.  
  208. CloseHandle ProcHandle
  209. 'Application.EnableCancelKey = SaveCancelKey
  210. Exit Function
  211.  
  212. ErrH:
  213. 'Debug.Print "ErrH: Cancel: " & Application.EnableCancelKey
  214. If Err.Number = ERR_BREAK_KEY Then
  215.     If BreakKey = ActionOnBreak.AbandonWait Then
  216.         CloseHandle ProcHandle
  217.         ShellAndWait = ShellAndWaitResult.UserWaitAbandoned
  218.         'Application.EnableCancelKey = SaveCancelKey
  219.        Exit Function
  220.     ElseIf BreakKey = ActionOnBreak.IgnoreBreak Then
  221.         Err.Clear
  222.         Resume
  223.     ElseIf BreakKey = ActionOnBreak.PromptUser Then
  224.         MsgRes = MsgBox("User Process Break." & vbCrLf & _
  225.             "Continue to wait?", vbYesNo)
  226.         If MsgRes = vbNo Then
  227.             CloseHandle ProcHandle
  228.             ShellAndWait = ShellAndWaitResult.UserBreak
  229.             'Application.EnableCancelKey = SaveCancelKey
  230.        Else
  231.             Err.Clear
  232.             Resume Next
  233.         End If
  234.     Else
  235.         CloseHandle ProcHandle
  236.         'Application.EnableCancelKey = SaveCancelKey
  237.        ShellAndWait = ShellAndWaitResult.Failure
  238.     End If
  239. Else
  240.     ' some other error. assume failure
  241.    CloseHandle ProcHandle
  242.     ShellAndWait = ShellAndWaitResult.Failure
  243. End If
  244.  
  245. 'Application.EnableCancelKey = SaveCancelKey
  246.  
  247. End Function
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement