加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

VB Shell调用后 等待程序运行结束

(2011-12-20 12:12:33)
标签:

it

分类: VB编程笔记
  1. Private Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long  
  2.   
  3. Private Declare Function GetExitCodeProcess Lib "kernel32" (ByVal hProcess As Long, lpExitCode As Long) As Long  
  4.   
  5. Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long  
  6.   
  7.   
  8.   
  9. Const PROCESS_QUERY_INFORMATION = &H400   
  10.   
  11. Const STILL_ALIVE = &H103  
  12. view plaincopy to clipboardprint?
  13.   
  14.   
  15. Private Sub Command1_Click()   
  16.   
  17. Dim pid As Long  
  18.   
  19. pid = Shell("c:\a.bat", vbNormalFocus)   
  20.   
  21. hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, 0, pid)   
  22.   
  23. Do  
  24.   
  25. Call GetExitCodeProcess(hProcess, ExitCode)   
  26.   
  27. DoEvents   
  28.   
  29. Loop While ExitCode = STILL_ALIVE   
  30.   
  31. Call CloseHandle(hProcess)   
  32.   
  33.   
  34.   
  35. MsgBox ("运行结束")   
  36.   
  37. End Sub  
  38.  
  39.  
  40. VB启动/结束另一程序(Shell 等待程序运行结束)    
  41. VB 中,常以Shell指令来执行外部程式,然而它在Create该外部process 後,立刻    
  42. 就会回到vb 的下一行程式,无法做到等待该Process结束时,才执行下一行指令,    
  43. 或是说,无法得知该Process是否已结束,甚者,该Process执行到一半,又该如何    
  44. 中止其执行等等,这些都不是Shell指令所能控制的,因此我们需使API的帮助来完    
  45. 成。    
  46.   
  47. 第一个问题,如何等待shell所Create的process结束後才往後执行vb的程式。    
  48. 首先要知道的是,每个Process有唯一的一个ProcessID,这是OS给定的,用来    
  49. 区别每个 Process,这个Process ID(PID)主要可用来取得该Process相对应的一些    
  50. 资讯,然而要对该Process的控制,却大多透过 Process Handle(hProcess)。VB    
  51. Shell指令的传回值是PID,而非hProcess,所以我们需透过OpenProcess这个API来    
  52. 取得 hProcess而OpenProcess()的第一个叁数,指的是所取得的hProcess所具有的    
  53. 能力,像 PROCESS_QUERY_INFORMATION 便是让GetExitCode()可取得hProcess所指    
  54. 的process之状态,而PROCESS_TERMINATE,便是让TerminateProcess(hProcess..)    
  55. 的指令能够生效,也就是说,不同叁数设定,使hProcess所具有的权限、能力有所    
  56. 不同。取得 hProcess後便可以使用WaitForSingleObject()来等待hProcess状态的    
  57. 改变,也就是说,它会等待 hProcess所指的process执行完,这个指令才结束,它    
  58. 第二个叁数所指的是 WaitForSingleObject()所要等待的时间(in milliseconds )    
  59. ,如果超过所指的时间,就TimeOut而结束WaitForSingleObject()的等待。若要它    
  60. 无限的等下去,就设定为INFIN99vE。    
  61.   
  62. pid = Shell("C:\tools\spe3\pe2.exe", vbNormalFocus)    
  63. hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, 0, pid)    
  64. ExitEvent = WaitForSingleObject(hProcess, INFIN99vE)    
  65. Call CloseHandle(hProcess)    
  66.   
  67. 上例会无限等待shell指令create之process结束後,才再做後面的vb指令。有    
  68. 时觉得那会等太久,所以有第二个解决方式:等process结束时再通知vb 就好,即    
  69. :设定一个公用变数(isDone),当它变成True时代表Shell所Create的Process已结    
  70. 束。当Process还在执行时,GetExitCodeProcess会传&H103给其第二个叁数,直到    
  71. 结束时才传另外的数值,如果程式正常结束,那Exitcode = 0,否则就得看它如何    
  72. 结束了。或许有人在其他地方看到 loop的地方是Loop while Exitcode <> 0,那    
  73. 有一点危险,如果以这程子来看,您不是用F4来离开pe2而是用右上方 X 的结束    
  74. dos window那麽,会因为ExitCode的值永远不会是0,而进入无穷的回圈。    
  75.   
  76. Dim pid As Long    
  77. pid = Shell("C:\tools\spe3\pe2.exe", vbNormalFocus)    
  78. hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, 0, pid)    
  79. isDone = False    
  80. Do    
  81. Call GetExitCodeProcess(hProcess, ExitCode)    
  82. Debug.Print ExitCode    
  83. DoEvents    
  84. Loop While ExitCode = STILL_ALIVE    
  85. Call CloseHandle(hProcess)    
  86. isDone = True    
  87.   
  88. 另外,如果您的shell所Create的程式,有视窗且为立刻Focus者,可另外用以    
  89. 下的方式Dim pid As Long    
  90. Dim hwnd5 As Long    
  91. pid = Shell("c:\tools\spe3\pe2.exe", vbNormalFocus)    
  92. hwnd5 = GetForegroundWindow()    
  93. isDone = False    
  94. Do While IsWindow(hwnd5)    
  95. DoEvents    
  96. Loop    
  97. isDone = True    
  98.   
  99.   
  100.   
  101. 而如何强迫shell所Create的process结束呢,那便是    
  102. Dim aa As Long    
  103. If hProcess <> 0 Then    
  104. aa = TerminateProcess(hProcess, 3838)    
  105. End If    
  106.   
  107. hProcess便是先前的例子中所取得的那个Process Handle, 3838所指的是传给    
  108. GetExitCodeProcess()中的第二叁数,这是我们任意给的,但最好不要是0,因为    
  109. 0一般是代表正常结束,当然这样设也不会有错。当然不可设&H103,以这个例子来    
  110. 看,如果程式正处於以下的LOOP    
  111. Do    
  112. Call GetExitCodeProcess(hProcess, ExitCode)    
  113. Debug.Print ExitCode    
  114. DoEvents    
  115. Loop While ExitCode = STILL_ALIVE    
  116. Debug.print ExitCode    
  117.   
  118. 而执行了 TerminateProcess(hProcess, 3838)那会看到ExitCode = 3838。然    
  119. 而,这个方式在win95没问题,在NT中,可能您要在OpenProcess()的第一个叁数要    
  120. 更改成 PROCESS_QUERY_INFORMATION Or PROCESS_TERMINATE 这样才能Work。不过    
  121. 良心的建议,非到最後关头,不要使用TerminateProcess(),因不正常的结束,往    
  122. 往许多程式结束前所要做的事都没有做,可能造成Resource的浪费,甚者,下次再    
  123. 执行某些程式时会有问题,例如:本人常使用MS-dos Shell Link 的方式执行一程    
  124. 式,透过Com port与大电脑的联结,如果Ms-dos Shell Link 不正常结束,下次再    
  125. 想Link时,会发现too Many Opens,这便是一例。    
  126.   
  127. 另外,有人使用Shell来执行.bat档,即:    
  128. pid = Shell("c:\aa.bat", vbNormalFocus)    
  129. 可是却遇上aa.bat结束了,但ms-dos的Window却仍活着,那可以用以下的方式来做    
  130. pid = Shell("c:\command.com /c c:\aa.bat", vbNormalFocus)    
  131. 那是执行Command.com,而Command.com指定执行c:\aa.bat 而且结束时自动Close    
  132. 所有程式如下:    
  133. Private Declare Function OpenProcess Lib "kernel32" _    
  134. (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, _    
  135. ByVal dwProcessId As Long) As Long  
  136.   
  137. Private Declare Function WaitForSingleObject Lib "kernel32" _    
  138. (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long    
  139. Private Declare Function CloseHandle Lib "kernel32" _    
  140. (ByVal hObject As Long) As Long    
  141. Private Declare Function GetExitCodeProcess Lib "kernel32" _    
  142. (ByVal hProcess As Long, lpExitCode As Long) As Long    
  143. Private Declare Function TerminateProcess Lib "kernel32" _    
  144. (ByVal hProcess As Long, ByVal uExitCode As Long) As Long    
  145. Private Declare Function GetForegroundWindow Lib "user32" () As Long    
  146. Private Declare Function IsWindow Lib "user32" _    
  147. (ByVal hwnd As Long) As Long    
  148.   
  149. Const PROCESS_QUERY_INFORMATION = &H400    
  150. Const STILL_ALIVE = &H103    
  151. Const INFIN99vE = &HFFFF    
  152.   
  153. Private ExitCode As Long    
  154. Private hProcess As Long    
  155. Private isDone As Long    
  156. Private Sub Command1_Click()    
  157. Dim pid As Long    
  158. pid = Shell("C:\tools\spe\pe2.exe", vbNormalFocus)    
  159. hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, 0, pid)    
  160. isDone = False    
  161. Do    
  162. Call GetExitCodeProcess(hProcess, ExitCode)    
  163. Debug.Print ExitCode    
  164. DoEvents    
  165. Loop While ExitCode = STILL_ALIVE    
  166. Call CloseHandle(hProcess)    
  167. isDone = True    
  168. End Sub    
  169.   
  170. Private Sub Command2_Click()    
  171. Dim pid As Long    
  172. Dim ExitEvent As Long    
  173. pid = Shell("C:\tools\spe3\pe2.exe", vbNormalFocus)    
  174. hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, 0, pid)    
  175. ExitEvent = WaitForSingleObject(hProcess, INFIN99vE)    
  176. Call CloseHandle(hProcess)    
  177. End Sub    
  178.   
  179. Private Sub Command3_Click()    
  180. Dim aa As Long    
  181. If hProcess <> 0 Then    
  182. aa = TerminateProcess(hProcess, 3838)    
  183. End If    
  184.   
  185. End Sub    
  186.   
  187. Private Sub Command4_Click()    
  188. Dim pid As Long    
  189. Dim hwnd5 As Long    
  190. pid = Shell("c:\tools\spe3\pe2.exe", vbNormalFocus)    
  191. hwnd5 = GetForegroundWindow()    
  192. isDone = False    
  193. Do While IsWindow(hwnd5)    
  194. DoEvents    
  195. Loop    
  196. isDone = True    
  197. End Sub    
  198.   
  199. Private Sub Command5_Click()    
  200. Dim pid As Long    
  201. 'pid = Shell("c:\windows\command\xcopy c:\aa.bat a:", vbHide)    
  202. pid = Shell("c:\command.com /c c:\aa.bat", vbNormalFocus)    
  203. End Sub      
  204.   
  205. [url]http://blog.csdn.net/szwangdf/archive/2007/01/29/1496640.aspx[/url]   
  206.   
  207. 【Modest】:   
  208. 在使用shell后,如何等待此程序完成后,程序才继续执行.我们使用 shell 调用一个外部程序的时候,通常 vb(a) 会在调用之后继续下面的语句,而不管此 shell 程序执行完成没有.有时我们需要在此 shell 执行完成之后才继续,又当如何呢?   
  209. 请看源程:   
  210. Public Declare Function OpenProcess Lib "kernel32" Alias "OpenProcess" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long  
  211. Public Declare Function WaitForSingleObject Lib "kernel32" Alias "WaitForSingleObject" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long  
  212. Public Declare Function CloseHandle Lib "kernel32" Alias "CloseHandle" (ByVal hObject As Long) As Long  
  213. Dim lngPId As Long    
  214. Dim lngPHandle As Long  
  215. lngPId = Shell("Notepad", vbNormalFocus)   
  216. lngPHandle = OpenProcess(SYNCHRONIZE, 0, lngpId)   
  217. If lngPHandle <> 0 Then    
  218.     Call WaitForSingleObject(lngPHandle, INFINITE) ' 无限等待, 直到程式结束   
  219.     Call CloseHandle(lngPHandle)    
  220. End If  
  221. 需要注意的是,在 shell 程序未完成前,你的程序不能做任何事,请小心为之   
  222.   
  223. [url]http://bbs.office-cn.net/dispbbs.asp?boardid=150&ID=7623[/url]   
  224.   
  225. 【laviewpbt】:   
  226. Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long  
  227. Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long  
  228. Private Declare Function ShellExecuteEx Lib "shell32.dll" Alias "ShellExecuteExA" (lpInfo As Any) As Long  
  229.     
  230. Private Type SHELLEXECUTEINFO   
  231.        cbSize  As Long  
  232.        fMask  As Long  
  233.        hwnd  As Long  
  234.        lpVerb  As String  
  235.        lpFile  As String  
  236.        lpParameters  As String  
  237.        lpDirectory  As String  
  238.        nShow  As Long  
  239.        hInstApp  As Long  
  240.        '  Optional  members   
  241.        lpIDList  As Long  
  242.        lpClass    As String  
  243.        hkeyClass  As Long  
  244.        dwHotKey  As Long  
  245.        hIcon_OR_Monitor  As Long  
  246.        hProcess  As Long  
  247. End Type   
  248.     
  249.  Private Sub Form_Load()   
  250.     Dim si   As SHELLEXECUTEINFO   
  251.     si.cbSize = Len(si)   
  252.     si.lpVerb = "open"  
  253.     si.lpFile = "notepad.exe"  
  254.     si.lpParameters = ""  
  255.     si.lpDirectory = ""  
  256.     si.nShow = 5            'SW_SHOW   
  257.     si.fMask = &H40      'SEE_MASK_NOCLOSEPROCESS   
  258.     ShellExecuteEx si   
  259.     If si.hProcess <> 0 Then  
  260.         WaitForSingleObject si.hProcess, &HFFFFFFFF      '  无限等待,  直到程式结束   
  261.         CloseHandle si.hProcess   
  262.         MsgBox "程序运行完毕!"  
  263.     End If  
  264. End Sub 

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有