|
使用Shell指令具有Wait的功能
发表日期:2006-2-27
|
VB中,常以Shell指令来执行外部程式,然而它在Create该外部process後,立刻 就会回到vb的下一行程式,无法做到等待该Process结束时,才执行下一行指令, 或是说,无法得知该Process是否已结束,甚者,该Process执行到一半,又该如何 中止其执行等等,这些都不是Shell指令所能控制的,因此我们需使API的帮助来完 成。
第一个问题,如何等待shell所Create的process结束後才往後执行vb的程式。 首先要知道的是,每个Process有唯一的一个ProcessID,这是OS给定的,用来 区别每个Process,这个ProcessID(PID)主要可用来取得该Process相对应的一些 资讯,然而要对该Process的控制,却大多透过ProcessHandle(hProcess)。VB Shell指令的传回值是PID,而非hProcess,所以我们需透过OpenProcess这个API来 取得hProcess而OpenProcess()的第一个叁数,指的是所取得的hProcess所具有的 能力,像PROCESS_QUERY_INFORMATION便是让GetExitCode()可取得hProcess所指 的process之状态,而PROCESS_TERMINATE,便是让TerminateProcess(hProcess..) 的指令能够生效,也就是说,不同叁数设定,使hProcess所具有的权限、能力有所 不同。取得hProcess後便可以使用WaitForSingleObject()来等待hProcess状态的 改变,也就是说,它会等待hProcess所指的process执行完,这个指令才结束,它 第二个叁数所指的是WaitForSingleObject()所要等待的时间(inmilliseconds) ,如果超过所指的时间,就TimeOut而结束WaitForSingleObject()的等待。若要它 无限的等下去,就设定为INFINITE。
pid=Shell("C:\tools\spe3\pe2.exe",vbNormalFocus) hProcess=OpenProcess(PROCESS_QUERY_INFORMATION,0,pid) ExitEvent=WaitForSingleObject(hProcess,INFINITE) CallCloseHandle(hProcess)
上例会无限等待shell指令create之process结束後,才再做後面的vb指令。有 时觉得那会等太久,所以有第二个解决方式:等process结束时再通知vb就好,即 :设定一个公用变数(isDone),当它变成True时代表Shell所Create的Process已结 束。当Process还在执行时,GetExitCodeProcess会传&H103给其第二个叁数,直到 结束时才传另外的数值,如果程式正常结束,那Exitcode=0,否则就得看它如何 结束了。或许有人在其他地方看到loop的地方是LoopwhileExitcode<>0,那 有一点危险,如果以这程子来看,您不是用F4来离开pe2而是用右上方X的结束 doswindow那麽,会因为ExitCode的值永远不会是0,而进入无穷的回圈。
DimpidAsLong pid=Shell("C:\tools\spe3\pe2.exe",vbNormalFocus) hProcess=OpenProcess(PROCESS_QUERY_INFORMATION,0,pid) isDone=False Do CallGetExitCodeProcess(hProcess,ExitCode) Debug.PrintExitCode DoEvents LoopWhileExitCode=STILL_ALIVE CallCloseHandle(hProcess) isDone=True
另外,如果您的shell所Create的程式,有视窗且为立刻Focus者,可另外用以 下的方式DimpidAsLong Dimhwnd5AsLong pid=Shell("c:\tools\spe3\pe2.exe",vbNormalFocus) hwnd5=GetForegroundWindow() isDone=False DoWhileIsWindow(hwnd5) DoEvents Loop isDone=True
而如何强迫shell所Create的process结束呢,那便是 DimaaAsLong IfhProcess<>0Then aa=TerminateProcess(hProcess,3838) EndIf
hProcess便是先前的例子中所取得的那个ProcessHandle,3838所指的是传给 GetExitCodeProcess()中的第二叁数,这是我们任意给的,但最好不要是0,因为 0一般是代表正常结束,当然这样设也不会有错。当然不可设&H103,以这个例子来 看,如果程式正处於以下的LOOP Do CallGetExitCodeProcess(hProcess,ExitCode) Debug.PrintExitCode DoEvents LoopWhileExitCode=STILL_ALIVE Debug.printExitCode
而执行了TerminateProcess(hProcess,3838)那会看到ExitCode=3838。然 而,这个方式在win95没问题,在NT中,可能您要在OpenProcess()的第一个叁数要 更改成PROCESS_QUERY_INFORMATIONOrPROCESS_TERMINATE这样才能Work。不过 良心的建议,非到最後关头,不要使用TerminateProcess(),因不正常的结束,往 往许多程式结束前所要做的事都没有做,可能造成Resource的浪费,甚者,下次再 执行某些程式时会有问题,例如:本人常使用MS-dosShellLink的方式执行一程 式,透过Comport与大电脑的联结,如果Ms-dosShellLink不正常结束,下次再 想Link时,会发现tooManyOpens,这便是一例。
另外,有人使用Shell来执行.bat档,即: pid=Shell("c:\aa.bat",vbNormalFocus) 可是却遇上aa.bat结束了,但ms-dos的Window却仍活着,那可以用以下的方式来做 pid=Shell("c:\command.com/cc:\aa.bat",vbNormalFocus) 那是执行Command.com,而Command.com指定执行c:\aa.bat而且结束时自动Close 所有程式如下: PrivateDeclareFunctionOpenProcessLib"kernel32"_ (ByValdwDesiredAccessAsLong,ByValbInheritHandleAsLong,_ ByValdwProcessIdAsLong)AsLong PrivateDeclareFunctionWaitForSingleObjectLib"kernel32"_ (ByValhHandleAsLong,ByValdwMillisecondsAsLong)AsLong PrivateDeclareFunctionCloseHandleLib"kernel32"_ (ByValhObjectAsLong)AsLong PrivateDeclareFunctionGetExitCodeProcessLib"kernel32"_ (ByValhProcessAsLong,lpExitCodeAsLong)AsLong PrivateDeclareFunctionTerminateProcessLib"kernel32"_ (ByValhProcessAsLong,ByValuExitCodeAsLong)AsLong PrivateDeclareFunctionGetForegroundWindowLib"user32"()AsLong PrivateDeclareFunctionIsWindowLib"user32"_ (ByValhwndAsLong)AsLong
ConstPROCESS_QUERY_INFORMATION=&H400 ConstSTILL_ALIVE=&H103 ConstINFINITE=&HFFFF
PrivateExitCodeAsLong PrivatehProcessAsLong PrivateisDoneAsLong PrivateSubCommand1_Click() DimpidAsLong pid=Shell("C:\tools\spe3\pe2.exe",vbNormalFocus) hProcess=OpenProcess(PROCESS_QUERY_INFORMATION,0,pid) isDone=False Do CallGetExitCodeProcess(hProcess,ExitCode) Debug.PrintExitCode DoEvents LoopWhileExitCode=STILL_ALIVE CallCloseHandle(hProcess) isDone=True EndSub
PrivateSubCommand2_Click() DimpidAsLong DimExitEventAsLong pid=Shell("C:\tools\spe3\pe2.exe",vbNormalFocus) hProcess=OpenProcess(PROCESS_QUERY_INFORMATION,0,pid) ExitEvent=WaitForSingleObject(hProcess,INFINITE) CallCloseHandle(hProcess) EndSub
PrivateSubCommand3_Click() DimaaAsLong IfhProcess<>0Then aa=TerminateProcess(hProcess,3838) EndIf
EndSub
PrivateSubCommand4_Click() DimpidAsLong Dimhwnd5AsLong pid=Shell("c:\tools\spe3\pe2.exe",vbNormalFocus) hwnd5=GetForegroundWindow() isDone=False DoWhileIsWindow(hwnd5) DoEvents Loop isDone=True EndSub
PrivateSubCommand5_Click() DimpidAsLong 'pid=Shell("c:\windows\command\xcopyc:\aa.bata:",vbHide) pid=Shell("c:\command.com/cc:\aa.bat",vbNormalFocus) EndSub->
|
|
上一篇:如何使用文件复制对话框
人气:3451
下一篇:ADO设定独占性的资料库
人气:2835 |
浏览全部Visual Basic的内容
Dreamweaver插件下载 网页广告代码 祝你圣诞节快乐 2009年新年快乐
|
|