程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> Visual Basic語言 >> VB綜合教程 >> 使用Shell指令具有Wait的功能

使用Shell指令具有Wait的功能

編輯:VB綜合教程
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: oolsspe3pe2.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: oolsspe3pe2.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: oolsspe3pe2.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: oolsspe3pe2.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: oolsspe3pe2.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: oolsspe3pe2.exe",vbNormalFocus)
  hwnd5=GetForegroundWindow()
  isDone=False
  DoWhileIsWindow(hwnd5)
  DoEvents
  Loop
  isDone=True
  EndSub
  
  PrivateSubCommand5_Click()
  DimpidAsLong
  'pid=Shell("c:windowscommandxcopyc:aa.bata:",vbHide)
  pid=Shell("c:command.com/cc:aa.bat",vbNormalFocus)
  EndSub->

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved