Advertisement
Guest User

CShellProg.cls

a guest
Nov 23rd, 2017
82
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. Option Explicit
  2.  
  3. '
  4. ' CShellProg.cls
  5. '
  6.  
  7. ' Wait return codes
  8. Private Const WAIT_OBJECT_0 = &H0&
  9. Private Const WAIT_TIMEOUT = &H102&
  10. Private Const WAIT_IO_COMPLETION = &HC0&
  11. Private Const WAIT_ABANDONED = &H80&
  12. Private Const WAIT_FAILED = &HFFFFFFFF
  13.  
  14. ' Returned by getexitcodeprocess (not used)
  15. Private Const STILL_ACTIVE = &H103&
  16.  
  17. ' OpenProcess flags
  18. Private Const PROCESS_QUERY_INFORMATION = &H400&
  19. Private Const PROCESS_TERMINATE = &H1&
  20. Private Const SYNCHRONIZE = &H100000
  21. Private Const INVALID_HANDLE_VALUE = 0&
  22.  
  23. ' APIs
  24. Private Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessID As Long) As Long
  25. Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long
  26. Private Declare Function GetExitCodeProcess Lib "kernel32" (ByVal hProcess As Long, lpExitCode As Long) As Long
  27. Private Declare Function TerminateProcess Lib "kernel32" (ByVal hProcess As Long, ByVal uExitCode As Long) As Long
  28. Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
  29. Private Declare Sub Sleep Lib "kernel32.dll" (ByVal dwMilliseconds As Long)
  30.  
  31. ' Possible process statuses
  32. Public Enum ProcStatus
  33.     psNone
  34.     psRunning
  35.     psTerminated
  36.     psAborted
  37. End Enum
  38.  
  39. ' feedback events
  40. Public Event Started(ByVal dwPID As Long, ByVal hProcess As Long)
  41. Public Event Running()
  42. Public Event Waiting(bCancel As Boolean)
  43. Public Event Terminated(ByVal nStatus As ProcStatus, ByVal lExitCode As Long, ByVal lErrCode As Long)
  44. Public Event Error(ByVal lErrCode As Long, ByVal sSource As String)
  45.  
  46. ' Local storage for properties
  47. Private msCommandLine As String
  48. Private msStartFolder As String
  49. Private mnStatus As ProcStatus
  50. Private mlProcessID As Long
  51. Private mlProcessHandle As Long
  52. Private mlErrNum As Long
  53. Private mlReturnCode As Long
  54.  
  55. ' save area for current path
  56. Private msCurrPath As String
  57.  
  58. ' =========================================
  59. ' public properties - read only
  60. ' =========================================
  61.  
  62. ' command line used to start the process
  63. Public Property Get CommandLine() As String
  64.     CommandLine = msCommandLine
  65. End Property
  66.  
  67. ' startup folder for the process
  68. Public Property Get StartFolder() As String
  69.     StartFolder = msStartFolder
  70. End Property
  71.  
  72. ' PID for the running process
  73. Public Property Get ProcessID() As Long
  74.     ProcessID = mlProcessID
  75. End Property
  76.  
  77. ' handle for the running process
  78. Public Property Get ProcessHandle() As Long
  79.     ProcessHandle = mlProcessHandle
  80. End Property
  81.  
  82. ' current process status
  83. Public Property Get Status() As ProcStatus
  84.     Status = mnStatus
  85. End Property
  86.  
  87. ' exit code from the terminated process
  88. Public Property Get ReturnCode() As Long
  89.     ReturnCode = mlReturnCode
  90. End Property
  91.  
  92. ' last error
  93. Public Property Get ErrNum() As Long
  94.     ErrNum = mlErrNum
  95. End Property
  96.  
  97. ' =========================================
  98. ' public methods
  99. ' =========================================
  100.  
  101. ' start the given program and obtain the process handle
  102. Public Function Execute(ByVal sCmdLine As String, Optional ByVal sStartFolder As String = "", Optional ByVal nWindowStyle As VbAppWinStyle = vbNormalFocus) As Boolean
  103.   Dim lFlags As Long
  104.  
  105.   ' init
  106.  Execute = False
  107.   CleanStorage
  108.  
  109.   ' saves cmdline and start folder
  110.  msCommandLine = sCmdLine
  111.   msStartFolder = sStartFolder
  112.  
  113.   ' set drive/folder and start app
  114.  SetFolder sStartFolder
  115.   mlProcessID = Shell(sCmdLine, nWindowStyle)
  116.   If mlProcessID = 0 Then
  117.     mlErrNum = Err.LastDllError
  118.     RaiseEvent Error(mlErrNum, "Shell")
  119.   End If
  120.  
  121.   ' restore drive/folder and check if all ok
  122.  SetFolder ""
  123.   If mlProcessID = 0 Then
  124.     Exit Function
  125.   End If
  126.  
  127.   ' open process to obtain handle
  128.  lFlags = PROCESS_QUERY_INFORMATION Or PROCESS_TERMINATE Or SYNCHRONIZE
  129.   mlProcessHandle = OpenProcess(lFlags, 0, mlProcessID)
  130.   If mlProcessHandle = INVALID_HANDLE_VALUE Then
  131.     mlErrNum = Err.LastDllError
  132.     RaiseEvent Error(mlErrNum, "OpenProcess")
  133.     Exit Function
  134.   End If
  135.  
  136.   ' all done
  137.  mnStatus = psRunning
  138.   RaiseEvent Started(mlProcessID, mlProcessHandle)
  139.   Execute = True
  140. End Function
  141.  
  142. ' checks the status for the started program
  143. Public Function CheckStatus() As ProcStatus
  144.   Dim lWait As Long
  145.  
  146.   ' checks the handle status using a wait
  147.  lWait = WaitForSingleObject(mlProcessHandle, 1)
  148.   Select Case lWait
  149.     Case WAIT_TIMEOUT
  150.       ' process still running
  151.      mnStatus = psRunning
  152.       RaiseEvent Running
  153.     Case WAIT_OBJECT_0
  154.       ' process terminated
  155.      mnStatus = psTerminated
  156.       Call GetExitCodeProcess(mlProcessHandle, mlReturnCode)
  157.       RaiseEvent Terminated(mnStatus, mlReturnCode, mlErrNum)
  158.     Case Else
  159.       ' error status
  160.      mnStatus = psAborted
  161.       mlErrNum = Err.LastDllError
  162.       RaiseEvent Terminated(mnStatus, mlReturnCode, mlErrNum)
  163.   End Select
  164.  
  165.   ' return current status
  166.  CheckStatus = mnStatus
  167. End Function
  168.  
  169. ' cleans up and optionally forces termination
  170. Public Sub Terminate(Optional ByVal bKillProcess As Boolean = False)
  171.   Dim lRet As Long
  172.  
  173.   ' if we don't have a valid handle, exit
  174.  If mlProcessHandle = INVALID_HANDLE_VALUE Then
  175.     Exit Sub
  176.   End If
  177.   ' errand process or forced kill ?
  178.  If (bKillProcess = True) Or (mnStatus = psAborted) Then
  179.     lRet = TerminateProcess(mlProcessHandle, 0&)
  180.     If lRet = 0 Then
  181.       lRet = Err.LastDllError
  182.       RaiseEvent Error(lRet, "TerminateProcess")
  183.     End If
  184.     mnStatus = psAborted
  185.   End If
  186.   ' close the handle, cleanup and return
  187.  lRet = CloseHandle(mlProcessHandle)
  188.   If lRet = 0 Then
  189.     lRet = Err.LastDllError
  190.     RaiseEvent Error(lRet, "CloseHandle")
  191.   End If
  192.   mlProcessHandle = INVALID_HANDLE_VALUE
  193.   mlProcessID = 0
  194. End Sub
  195.  
  196. ' wait for the external process to terminate
  197. ' allows to cancel the wait and return
  198. Public Function Wait(Optional ByVal lInterval As Long = 150) As ProcStatus
  199.   Dim nStatus As ProcStatus
  200.   Dim bCancel As Boolean
  201.  
  202.   ' init and start waiting
  203.  nStatus = CheckStatus()
  204.   While (nStatus = WAIT_TIMEOUT) And (bCancel = False)
  205.     Call Sleep(lInterval)
  206.     RaiseEvent Waiting(bCancel)
  207.     If bCancel = False Then
  208.       nStatus = CheckStatus()
  209.     End If
  210.   Wend
  211.    
  212.   ' return status
  213.  Wait = nStatus
  214. End Function
  215.  
  216. ' =========================================
  217. ' private code
  218. ' =========================================
  219.  
  220. ' constructor
  221. Private Sub Class_Initialize()
  222.   ' initialize storage
  223.  CleanStorage
  224.   msCurrPath = ""
  225. End Sub
  226.  
  227. ' destructor
  228. Private Sub Class_Terminate()
  229.   ' ensure to cleanup after ourselves
  230.  Terminate 'True
  231.  CleanStorage
  232. End Sub
  233.  
  234. ' set/reset current folder
  235. Private Sub SetFolder(ByVal sNewFolder As String)
  236.   Dim sFolder As String, sDrive As String
  237.  
  238.   ' check new folder
  239.  sFolder = sNewFolder
  240.   If Len(sFolder) < 1 Then
  241.     sFolder = msCurrPath
  242.     If Len(sFolder) < 1 Then
  243.       Exit Sub
  244.     End If
  245.   End If
  246.   ' if same as current, do nothing
  247.  If CurDir() = sFolder Then
  248.     Exit Sub
  249.   End If
  250.   ' save current folder and set new one
  251.  msCurrPath = CurDir()
  252.   sDrive = Mid(sFolder, 1, 2)
  253.   ChDrive sDrive
  254.   ChDir sFolder
  255. End Sub
  256.  
  257. ' clean local storage
  258. Private Sub CleanStorage()
  259.   mnStatus = psNone
  260.   mlProcessID = 0
  261.   mlProcessHandle = INVALID_HANDLE_VALUE
  262.   mlErrNum = 0
  263.   mlReturnCode = 0
  264.   msCommandLine = ""
  265.   msStartFolder = ""
  266. End Sub
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement