VB Shell調用後 等待程序運行結束

  1. Private Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As LongByVal bInheritHandle As LongByVal dwProcessId As LongAs Long  
  2.   
  3. Private Declare Function GetExitCodeProcess Lib "kernel32" (ByVal hProcess As Long, lpExitCode As LongAs Long  
  4.   
  5. Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As LongAs Long  
  6.   
  7.   
  8.   
  9. Const PROCESS_QUERY_INFORMATION = &H400   
  10.   
  11. Const STILL_ALIVE = &H103  
  1.   
  2.   
  3. Private Sub Command1_Click()   
  4.   
  5. Dim pid As Long  
  6.   
  7. pid = Shell("c:\a.bat", vbNormalFocus)   
  8.   
  9. hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, 0, pid)   
  10.   
  11. Do  
  12.   
  13. Call GetExitCodeProcess(hProcess, ExitCode)   
  14.   
  15. DoEvents   
  16.   
  17. Loop While ExitCode = STILL_ALIVE   
  18.   
  19. Call CloseHandle(hProcess)   
  20.   
  21.   
  22.   
  23. MsgBox ("運行結束")   
  24.   
  25. End Sub  
 
 
  1. VB啓動/結束另一程序(Shell 等待程序運行結束)    
  2. VB 中,常以Shell指令來執行外部程式,然而它在Create該外部process 後,立刻    
  3. 就會回到vb 的下一行程式,無法做到等待該Process結束時,才執行下一行指令,    
  4. 或是說,無法得知該Process是否已結束,甚者,該Process執行到一半,又該如何    
  5. 中止其執行等等,這些都不是Shell指令所能控制的,因此我們需使API的幫助來完    
  6. 成。    
  7.   
  8. 第一個問題,如何等待shell所Create的process結束後才往後執行vb的程式。    
  9. 首先要知道的是,每個Process有唯一的一個ProcessID,這是OS給定的,用來    
  10. 區別每個 Process,這個Process ID(PID)主要可用來取得該Process相對應的一些    
  11. 資訊,然而要對該Process的控制,卻大多透過 Process Handle(hProcess)。VB    
  12. Shell指令的傳回值是PID,而非hProcess,所以我們需透過OpenProcess這個API來    
  13. 取得 hProcess而OpenProcess()的第一個叄數,指的是所取得的hProcess所具有的    
  14. 能力,像 PROCESS_QUERY_INFORMATION 便是讓GetExitCode()可取得hProcess所指    
  15. 的process之狀態,而PROCESS_TERMINATE,便是讓TerminateProcess(hProcess..)    
  16. 的指令能夠生效,也就是說,不同叄數設定,使hProcess所具有的權限、能力有所    
  17. 不同。取得 hProcess後便可以使用WaitForSingleObject()來等待hProcess狀態的    
  18. 改變,也就是說,它會等待 hProcess所指的process執行完,這個指令才結束,它    
  19. 第二個叄數所指的是 WaitForSingleObject()所要等待的時間(in milliseconds )    
  20. ,如果超過所指的時間,就TimeOut而結束WaitForSingleObject()的等待。若要它    
  21. 無限的等下去,就設定爲INFIN99vE。    
  22.   
  23. pid = Shell("C:\tools\spe3\pe2.exe", vbNormalFocus)    
  24. hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, 0, pid)    
  25. ExitEvent = WaitForSingleObject(hProcess, INFIN99vE)    
  26. Call CloseHandle(hProcess)    
  27.   
  28. 上例會無限等待shell指令create之process結束後,纔再做後面的vb指令。有    
  29. 時覺得那會等太久,所以有第二個解決方式:等process結束時再通知vb 就好,即    
  30. :設定一個公用變數(isDone),當它變成True時代表Shell所Create的Process已結    
  31. 束。當Process還在執行時,GetExitCodeProcess會傳&H103給其第二個叄數,直到    
  32. 結束時才傳另外的數值,如果程式正常結束,那Exitcode = 0,否則就得看它如何    
  33. 結束了。或許有人在其他地方看到 loop的地方是Loop while Exitcode <> 0,那    
  34. 有一點危險,如果以這程子來看,您不是用F4來離開pe2而是用右上方 X 的結束    
  35. dos window那麼,會因爲ExitCode的值永遠不會是0,而進入無窮的迴圈。    
  36.   
  37. Dim pid As Long    
  38. pid = Shell("C:\tools\spe3\pe2.exe", vbNormalFocus)    
  39. hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, 0, pid)    
  40. isDone = False    
  41. Do    
  42. Call GetExitCodeProcess(hProcess, ExitCode)    
  43. Debug.Print ExitCode    
  44. DoEvents    
  45. Loop While ExitCode = STILL_ALIVE    
  46. Call CloseHandle(hProcess)    
  47. isDone = True    
  48.   
  49. 另外,如果您的shell所Create的程式,有視窗且爲立刻Focus者,可另外用以    
  50. 下的方式Dim pid As Long    
  51. Dim hwnd5 As Long    
  52. pid = Shell("c:\tools\spe3\pe2.exe", vbNormalFocus)    
  53. hwnd5 = GetForegroundWindow()    
  54. isDone = False    
  55. Do While IsWindow(hwnd5)    
  56. DoEvents    
  57. Loop    
  58. isDone = True    
  59.   
  60.   
  61.   
  62. 而如何強迫shell所Create的process結束呢,那便是    
  63. Dim aa As Long    
  64. If hProcess <> 0 Then    
  65. aa = TerminateProcess(hProcess, 3838)    
  66. End If    
  67.   
  68. hProcess便是先前的例子中所取得的那個Process Handle, 3838所指的是傳給    
  69. GetExitCodeProcess()中的第二叄數,這是我們任意給的,但最好不要是0,因爲    
  70. 0一般是代表正常結束,當然這樣設也不會有錯。當然不可設&H103,以這個例子來    
  71. 看,如果程式正處於以下的LOOP    
  72. Do    
  73. Call GetExitCodeProcess(hProcess, ExitCode)    
  74. Debug.Print ExitCode    
  75. DoEvents    
  76. Loop While ExitCode = STILL_ALIVE    
  77. Debug.print ExitCode    
  78.   
  79. 而執行了 TerminateProcess(hProcess, 3838)那會看到ExitCode = 3838。然    
  80. 而,這個方式在win95沒問題,在NT中,可能您要在OpenProcess()的第一個叄數要    
  81. 更改成 PROCESS_QUERY_INFORMATION Or PROCESS_TERMINATE 這樣才能Work。不過    
  82. 良心的建議,非到最後關頭,不要使用TerminateProcess(),因不正常的結束,往    
  83. 往許多程式結束前所要做的事都沒有做,可能造成Resource的浪費,甚者,下次再    
  84. 執行某些程式時會有問題,例如:本人常使用MS-dos Shell Link 的方式執行一程    
  85. 式,透過Com port與大電腦的聯結,如果Ms-dos Shell Link 不正常結束,下次再    
  86. 想Link時,會發現too Many Opens,這便是一例。    
  87.   
  88. 另外,有人使用Shell來執行.bat檔,即:    
  89. pid = Shell("c:\aa.bat", vbNormalFocus)    
  90. 可是卻遇上aa.bat結束了,但ms-dos的Window卻仍活着,那可以用以下的方式來做    
  91. pid = Shell("c:\command.com /c c:\aa.bat", vbNormalFocus)    
  92. 那是執行Command.com,而Command.com指定執行c:\aa.bat 而且結束時自動Close    
  93. 所有程式如下:    
  94. Private Declare Function OpenProcess Lib "kernel32" _    
  95. (ByVal dwDesiredAccess As LongByVal bInheritHandle As Long, _    
  96. ByVal dwProcessId As LongAs Long  
  97.   
  98. Private Declare Function WaitForSingleObject Lib "kernel32" _    
  99. (ByVal hHandle As LongByVal dwMilliseconds As LongAs Long    
  100. Private Declare Function CloseHandle Lib "kernel32" _    
  101. (ByVal hObject As LongAs Long    
  102. Private Declare Function GetExitCodeProcess Lib "kernel32" _    
  103. (ByVal hProcess As Long, lpExitCode As LongAs Long    
  104. Private Declare Function TerminateProcess Lib "kernel32" _    
  105. (ByVal hProcess As LongByVal uExitCode As LongAs Long    
  106. Private Declare Function GetForegroundWindow Lib "user32" () As Long    
  107. Private Declare Function IsWindow Lib "user32" _    
  108. (ByVal hwnd As LongAs Long    
  109.   
  110. Const PROCESS_QUERY_INFORMATION = &H400    
  111. Const STILL_ALIVE = &H103    
  112. Const INFIN99vE = &HFFFF    
  113.   
  114. Private ExitCode As Long    
  115. Private hProcess As Long    
  116. Private isDone As Long    
  117. Private Sub Command1_Click()    
  118. Dim pid As Long    
  119. pid = Shell("C:\tools\spe\pe2.exe", vbNormalFocus)    
  120. hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, 0, pid)    
  121. isDone = False    
  122. Do    
  123. Call GetExitCodeProcess(hProcess, ExitCode)    
  124. Debug.Print ExitCode    
  125. DoEvents    
  126. Loop While ExitCode = STILL_ALIVE    
  127. Call CloseHandle(hProcess)    
  128. isDone = True    
  129. End Sub    
  130.   
  131. Private Sub Command2_Click()    
  132. Dim pid As Long    
  133. Dim ExitEvent As Long    
  134. pid = Shell("C:\tools\spe3\pe2.exe", vbNormalFocus)    
  135. hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, 0, pid)    
  136. ExitEvent = WaitForSingleObject(hProcess, INFIN99vE)    
  137. Call CloseHandle(hProcess)    
  138. End Sub    
  139.   
  140. Private Sub Command3_Click()    
  141. Dim aa As Long    
  142. If hProcess <> 0 Then    
  143. aa = TerminateProcess(hProcess, 3838)    
  144. End If    
  145.   
  146. End Sub    
  147.   
  148. Private Sub Command4_Click()    
  149. Dim pid As Long    
  150. Dim hwnd5 As Long    
  151. pid = Shell("c:\tools\spe3\pe2.exe", vbNormalFocus)    
  152. hwnd5 = GetForegroundWindow()    
  153. isDone = False    
  154. Do While IsWindow(hwnd5)    
  155. DoEvents    
  156. Loop    
  157. isDone = True    
  158. End Sub    
  159.   
  160. Private Sub Command5_Click()    
  161. Dim pid As Long    
  162. 'pid = Shell("c:\windows\command\xcopy c:\aa.bat a:", vbHide)    
  163. pid = Shell("c:\command.com /c c:\aa.bat", vbNormalFocus)    
  164. End Sub      
  165.   
  166. [url]http://blog.csdn.net/szwangdf/archive/2007/01/29/1496640.aspx[/url]   
  167.   
  168. 【Modest】:   
  169. 在使用shell後,如何等待此程序完成後,程序才繼續執行.我們使用 shell 調用一個外部程序的時候,通常 vb(a) 會在調用之後繼續下面的語句,而不管此 shell 程序執行完成沒有.有時我們需要在此 shell 執行完成之後才繼續,又當如何呢?   
  170. 請看源程:   
  171. Public Declare Function OpenProcess Lib "kernel32" Alias "OpenProcess" (ByVal dwDesiredAccess As LongByVal bInheritHandle As LongByVal dwProcessId As LongAs Long  
  172. Public Declare Function WaitForSingleObject Lib "kernel32" Alias "WaitForSingleObject" (ByVal hHandle As LongByVal dwMilliseconds As LongAs Long  
  173. Public Declare Function CloseHandle Lib "kernel32" Alias "CloseHandle" (ByVal hObject As LongAs Long  
  174. Dim lngPId As Long    
  175. Dim lngPHandle As Long  
  176. lngPId = Shell("Notepad", vbNormalFocus)   
  177. lngPHandle = OpenProcess(SYNCHRONIZE, 0, lngpId)   
  178. If lngPHandle <> 0 Then    
  179.     Call WaitForSingleObject(lngPHandle, INFINITE) ' 無限等待, 直到程式結束   
  180.     Call CloseHandle(lngPHandle)    
  181. End If  
  182. 需要注意的是,在 shell 程序未完成前,你的程序不能做任何事,請小心爲之   
  183.   
  184. [url]http://bbs.office-cn.net/dispbbs.asp?boardid=150&ID=7623[/url]   
  185.   
  186. 【laviewpbt】:   
  187. Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As LongByVal dwMilliseconds As LongAs Long  
  188. Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As LongAs Long  
  189. Private Declare Function ShellExecuteEx Lib "shell32.dll" Alias "ShellExecuteExA" (lpInfo As Any) As Long  
  190.     
  191. Private Type SHELLEXECUTEINFO   
  192.        cbSize  As Long  
  193.        fMask  As Long  
  194.        hwnd  As Long  
  195.        lpVerb  As String  
  196.        lpFile  As String  
  197.        lpParameters  As String  
  198.        lpDirectory  As String  
  199.        nShow  As Long  
  200.        hInstApp  As Long  
  201.        '  Optional  members   
  202.        lpIDList  As Long  
  203.        lpClass    As String  
  204.        hkeyClass  As Long  
  205.        dwHotKey  As Long  
  206.        hIcon_OR_Monitor  As Long  
  207.        hProcess  As Long  
  208. End Type   
  209.     
  210.  Private Sub Form_Load()   
  211.     Dim si   As SHELLEXECUTEINFO   
  212.     si.cbSize = Len(si)   
  213.     si.lpVerb = "open"  
  214.     si.lpFile = "notepad.exe"  
  215.     si.lpParameters = ""  
  216.     si.lpDirectory = ""  
  217.     si.nShow = 5            'SW_SHOW   
  218.     si.fMask = &H40      'SEE_MASK_NOCLOSEPROCESS   
  219.     ShellExecuteEx si   
  220.     If si.hProcess <> 0 Then  
  221.         WaitForSingleObject si.hProcess, &HFFFFFFFF      '  無限等待,  直到程式結束   
  222.         CloseHandle si.hProcess   
  223.         MsgBox "程序運行完畢!"  
  224.     End If  
  225. End Sub  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章