关於执行外部进程 |
尚未結案
|
KFC
一般會員 發表:43 回覆:73 積分:23 註冊:2003-03-27 發送簡訊給我 |
|
banson1716
高階會員 發表:55 回覆:182 積分:167 註冊:2002-04-14 發送簡訊給我 |
|
KFC
一般會員 發表:43 回覆:73 積分:23 註冊:2003-03-27 發送簡訊給我 |
|
banson1716
高階會員 發表:55 回覆:182 積分:167 註冊:2002-04-14 發送簡訊給我 |
參考看看 CreateProcess的使用方法 procedure TForm1.Button1Click(Sender: TObject);
Var
sCommandLine: string;
bCreateProcess: boolean;
lpProcessInformation,lpStartupInfo: TStartupInfo;
Begin
sCommandLine := 'C:\Pwin95\notepad';
bCreateProcess := CreateProcessA(nil, PChar(sCommandLine),nil, nil,
True,NORMAL_PRIORITY_CLASS,nil, nil, lpStartupInfo,lpProcessInformation);
End;
=========================================
//如何●●關閉外部程式
var HWndCalculator : HWnd;
begin
// 尋找已開啟"記事本"視窗
HWndCalculator := Winprocs.FindWindow(nil, '記事本');
// 關閉已開啟"記事本"視窗
if HWndCalculator <> 0 then
SendMessage(HWndCalculator, WM_CLOSE, 0, 0);
end;
==================================================================
關閉視窗
SendMessage(GetActiveWindow,WM_CLOSE,0,0); 發表人 - banson1716 於 2003/05/03 14:32:25
|
KFC
一般會員 發表:43 回覆:73 積分:23 註冊:2003-03-27 發送簡訊給我 |
|
banson1716
高階會員 發表:55 回覆:182 積分:167 註冊:2002-04-14 發送簡訊給我 |
避免程序重復運行三法
1查找窗口法
program oneapp;
uses forms,windows;
var hwnd:Thandle;
begon
hwnd:=findwindow('Tfrom1','singleApp');
if hwnd=0 then
begin
Application.Initializa;
....
....
Application.Run;
end
else messagebox(0,'程序已經運行,請檢查!','form1信息',mb_ok);
end. 2互斥對像法
program oneapp;
uses forms,windows;
var mutex:Thandle;
begin
mutex:=createmutex(nil,true,'singleapp');
if GetLastError<>ERROR_ALREADY_EXISTS then
begin
application.title:='oneapp';
...
application.run;
end
else messagebox(0,'程序已經運行,請檢查!','form1信息',mb_ok);
end. 3全局原子法
program oneapp;
uses windows;
const iAtom='singleApp';
begin
if Global FindAtom(iAtom)=0 then
begin
Global addAtom(iAtom);
application.initialize;
application.createform(Tform1.form1);
application.run;
Global DeteAtom(Global FindAtom(iAtom));
end
else messagebox(0,'程序已經運行,請檢查!','form1信息',mb_ok);
end.
|
KFC
一般會員 發表:43 回覆:73 積分:23 註冊:2003-03-27 發送簡訊給我 |
|
banson1716
高階會員 發表:55 回覆:182 積分:167 註冊:2002-04-14 發送簡訊給我 |
外部程式是否正在執行
---------------------------------------------------------------
如何知道外部程式是否正在RUNing ? WIN32 API HWND FindWindow( LPCTSTR lpClassName, // pointer to class name
LPCTSTR lpWindowName // pointer to window name
); EX:
var
h:THandle;
begin
h:= FindWindow('小畫家',0);
if h <> INVALID_HANDLE_VALUE then
begin
//You Get It.
end; end;
|
banson1716
高階會員 發表:55 回覆:182 積分:167 註冊:2002-04-14 發送簡訊給我 |
由delphi控制外部應用程式的執行
julian V.Moss
想由您的Delphi程式控制應用程式的執行嗎?這篇文章告訴您如何經由Delphi 1.0以及32 bit的Delphi 2.0執行另處的程式,開啟或列印檔案,並示 如何在Delphi 2.0中得知所執行的應用程式已經執行完畢,並取得它的結束碼(exit code).) 引言部份 在Delphi程式開發者眼中, 有一個經常困擾著大家的問題,那就是如何由自己的Delphi程式控制外部程式的執行.由於Delphi本身並沒有提供這方面的功能,因此我們就必須借助於Window API.總括來說,我們有幾個選擇:在16位元 Window下有二個API可供呼叫,在32位元Window下也有不同的二個API可以運用. 比較簡單的方式:WinExec 如果你想要的隻是去執行另一個個應用程式,那最簡單的方法就是利用戶WinExec函式. WinExec可以在WINPROCS單元中找到,它是以下列方式宣告: function WinExec(CmdLine:PChar;CmdShow:Word):Word; 這個函式有二個參數,第一個參數CmdLine是指到包含要執行的命令而且以null字元結尾的字串指標,字串內容包含所要執行程式的名稱以及所需的任何選擇參數.由於Window本身會依照正常程序來執行這個程式,因此它並不需要一定要以 .exe,.com或者是.bat為副檔名,而且如果這個檔案在目前的目錄,Window的根目錄或是繫統目錄,Delphi程式所在的目錄或者是在繫統設定的PATH下找得到的話,我們也可以不給完整的路徑資訊. 參數CmdShow則用來指定該應用程式開始執行時的狀態,其中可能的值可以是WINTYPES單元中的Window常數中定義的任何一個值.你比較可能用到的有SW_SHOW ,SW_SHOWMAXIMIZED以及SW_SHOWMINIMIZED.其中SW_SHOW表示將程式用它預設值或初始值的設定狀態顯示出來,另外二個我就不多做解釋,大家看字面就應該會明白了. 你也可以用SW_SHOWNOACTIVE來把應用程式叫出並停留在初始狀態,然後依然把上前的執行權交回給你寫的Delphi程式.指定SW_SHOWMINNOACTIVE時狀況大致和上述的一樣,隻不過被執行的應用程式會保留在最小化的狀態. WinExec會傳回一個16位元instance,其實它是一個用來辨別所執行程式(正確一點應該是程式模組)的數字.合法 instance handle值必須大於或等於32,如果小於32時,Window會給你一個error code來告訴你WinExec執行失敗的原因. 用ShellExecute玩些把戲 WinExec雖然簡單好用,但是卻隻能用來執行程式而已. 從Windows 3.1開始多了一個新的函式叫做 ShellExecute,在Delphi的SHELLAPI單元中有定義.就如它字面上意義一樣,ShellExecute提供像Program Maneger之類Windows Shell程式的功能.這個函式除了提供執行應用程式的功能之外,你可以利用WIN.INI Registration Database或Windows 95 Registry中有關的資訊來開啟或列印檔案. ShellExecute也可以在我們沒有加上.PIF副檔名的情況下執行PIF,並且會尋找在WIN.INI或95 registry下(Program)項目中有關該程式的徑設定. ShellExecute用起來有點比較復雜,它的宣告如下: functionShellExecute(Wnd:HWnd;Operation,FileName,Parameters,Directory:PChar;ShowCmd:Integer):THandle;
其中Wnd參數為用來設定繫統任何可能發生的錯誤訊息的父視窗的handle,可以把它設為0.而四個PChar參數Operation.FileName.Parameters以及Dircetory 則為指到以null字元結尾字串的指標值,這些值都必須由Pascal型式的字串轉換過來. Operation參數指定要執行的功能,在Windows 3.1下隻有二個選擇: open 以及 print .Windows 95則增加了如 printto 利用rgeistry機制的新功能,可以用來擴充到包含別的執行功能. open 操作的效果和double-click程式的小圖式一樣,如果在Filename參數中指定的是一個執行檔的話,它就會被執行.如果是一個資料檔,那 就會執行它所連結的程式,如果它本身並沒有連結到任何程式的話,你會得到一個Windows的錯誤訊息. print 操作則是用所連結的列印程式把檔案內容列印出來,列印的方式則與所安裝的列印該型式格式資料的程式有關,如果沒有安裝可以列印該格式資料的列印程式,那 Windows就會顯示一個錯誤訊息對話框. Parameters參數包含Filename中所指定程式的命令行參數,如果Filename中指定不是一個可執行的程式,那 Parameters的內容應該設為NULL. Windows95相容的程式通常都能夠支援它所能辨識檔案型式的 操作.在這種情況下, 字串就必須包含如印表機,驅動程式和裝置類別的名稱,請參考以下的例子. ' Microsoft Fax WPSUNI.DRV FAV:' 'Olivetti JP 250 JP350.DRVLPT1:' 由於印表機名稱之中包含空格,因此必須用雙引號括起來.利用 printto 操作我們可以把文件送到非預設的印表機上,這在Windows 3.1下是無法做到的. Directory參數讓你指定Shell操作的啟始目錄,如果不指定,就使用目前的目錄. ShellExecute的傳回值THandle和WinExec一樣都是程式的instance handle.同樣的,我們必須測試它的值是否大於等於32. 程式還在執行嗎? 如果想要知道你由WinExec或者是ShellExecute所執行的程式是否還在執行中,我們應該要儲存傳回來的instance handle值,GetModuleUsage函式(在WINPROCS中宣告)傳回由你所給的instance handle所指到的程式模組載入的次數,宣告如下: function GetModuleUsage(Module:THandle):integer;通常這個傳回值在程式還在執行時為1,執行結束後為0.以下的程式可以用來測試Hanle值為ih的程式是否還在執行. isRunning:=GetModuleUsage(ih)>0;在通常情況下,我們會肥如上的指令放在一個回圈內,以方便別的程式使用CPU的資源,並一直等到GetModuleUsage的傳回值變為0. 把WinExec及ShellExecute重新包裝 程式列表一以及列表二分別包含了可以使用WinExec或ShellExecute執行程式的Delphi函式.你必須傳給它一個命令行參數,一個用來指定視窗初始狀態的SW_SHOW常數以及一個Boolean參數Wait,以告訴這個函式要在開始末執行外部應用程式後就直接跳出,或者是要等到所執行的應用程式執行完畢後纔離開.這二個函數會在執行成功後傳回True,失敗則傳回False. 程式列表一:利用WinExec執行程式 function Execute(const commandstr:String;show:Word;wait:Boolean):Boolean; var ih:Word; cmdbuf:Array[0..255]of Char; begin ih:=WinExec(StrPCopy(cmdbuf,commandstr),show); Result:=ih>=32; if Result and wait then repeat Application.ProcessMessages until GetModuleUsage(ih)=0; end; 程式列表二:利用ShellExecute執行程式 function ShellExec(const op,fn,par,dir:String show:Word;wait:Boolean):Boolean; var ih:Word; Operation,FileName,Parameters,Directory:PChar; begin GetMem(Operation,Length(op) 1); GetMem(Filename,Length(fn) 1); GetMem(Parameters,Length(par) 1); GetMem(Directory,Length(dir) 1); try StrPCopy(Operation,op); StrPCopy(Filename,fn); StrPCopy(Parameters,par); StrPCopy(Directory,dir); ih:=ShellExecute(0,Opeation,Filename, Parameters,Directory,SW_SHOW); Result and wait then repeat Application.ProcessMessages until GetModuleUsage(ih)=0; finally FreeMem(Directory,Length(dir) 1); FreeMem(Parameters,Length(par) 1); FreeMem(Filename,Length(fn) 1); FreeMem(Operation,Length(op) 1); end; end; 你可以利用本期所附磁片中的 例程式Exec16來試試這兩個函式的功能. 如果你寫的程式是打算在Windows95下運作的,那 利用GetModuleUsage這個函式來測試一個程式是否已經執行結束就會發生一些問題.問題的根源在於在 Win32 底下,instance handle ih 並不是用來辨識某個應用程式的唯一handle.舉例來說,如果你一次執行了兩個Notepad,那GetModuleUsage會一直等到兩個Notepad都結束執行以後纔會傳回0這個值.幸運的是,這種情況不常發生,不過卻也沒甚 好的解決方法,除非使用Win32中新提供的函式來執行外部程式.當然,要這 做的話,我們就必須要用到Delphi 2.0版了. Delphi2.0和Windows 95 在把使用WinExec或者ShellExec函式的Delphi1.0程式移植到Delphi2.0的環境中並不會造成任何問題,然而由於Win32 API並不支援GetModuleUsage這個函式,因此在像程式列表一或二中這類使用情況下,Delphi2.0的編譯器就會給你一個錯誤訊息.加此如果我想要在Win32底下測試一個程式是否已經執行完畢,就必須利用 32 bit的API函式重寫我們的程式. 在Win32中有二個函式可以用來控制應用程式的執行,分別為CreateProcessc以及ShellExecuteEx.其中CreateProcessc大致上具備WinExec的所有功能,不過參數多得嚇人,共有10個.其中有4個是指到記錄結構(record structure)的指標值,這些記錄包含程式安全屬性(process security attributes),執行緒安全屬性(thread security attributes),啟始屬性(startup attributes)以及關於這個程序的傳回資訊(return information).CreateProcess事實上是一個具有相當多功能的通用函式,執行程式隻是其中的一個功能.如果你要的隻是執行一個外部的應用和一式的話,使用ShellExecuteEx應該會簡單一些.ShellExecuteEx的功用基本上各16位元版本的hellExecute函式差不多,其中Ex代表的是Extended的意思,這個字通常用來標示具有類似功能16位元函式的32位元版本. ShellExecuteEx 定義如下: function ShellExecuteEx(PShellExecuteinfo):Boolean;PShellExecuteinfo 是指到型態為TShellExecuteinfo的一筆記錄的指標值,另外這個函式也會在執行成功後傳回True,失敗則傳回False.傳給ShellExecuteEx 函式的資訊是以參數方式進行,並且使用TshellExecuteInfo結構,這個結構同時也用來將資訊傳回給原呼叫程序. TshellExecuteInfo結構的定義如下: TShellExecuteInfo=Record cbSize:DWord; fMask:ULong; ipVerb:PChar; ipFile:PChar; ipParameters:PChar; ipDirectory:PChar; nShow:Word; hlnstApp:ULong; iplDList:Pointer; ipClass:PChar; hkeyClass:hKey; dwHotKey:DWord; hlcon:THandle; hProcess:THandle; end; Delphi2.0編譯器能接受如C 語言中DWord以及ULong等32位元的無正負號值,這些東西雖然看起來沒有Pascal的味道,但是在參考以C 為準所撰寫的文件時會變得比較容易. 在使用TShellEXecuteInfo結構之前,我們必須把它初始化為0,並且得在cbSize 欄位中填入結構的大小.fMask欄位含了一些告訴ShellExecuteEx如何來處理結構中其它資料的旗標值(flag),其中最基本的一個是SEE_MASK_NOCLOSEPROCESS,這會使得函式傳回在hProcess欄位中所建立的Process的handle值.另外的指標值則用來指出允許的hotKey或者是改變該程式執行時的小圖示(icon). 旗標SEE_MASK_CONNECTNETDRY指出lpFile字串是一個在網路上UNC(Universal Naming Convention)路徑上的檔案,因此繫統須連到網路磁碟機.SEE_MASK_DOENVSUBST指出lpFile或lpDirectory字串內的環境變數會被展開.由於這些旗標值都是用位元做mask,因此在同時需要指定兩個以上的功能時,我們可以直接將這些SEE_MASK_XXX常數加起來. lpVerb,lpFile,lpParameter和lpDirectory分別是指到代表要進行的操作,檔案名稱,命令行參數以及啟始目錄的null結尾字串.nShow的值則可以是SW_SHOW數值中的任一個,用來指定被執行的應用程式起始的狀態.lpIDList,lpClass,hKeyClass,dwHotKey以及hIcon欄位通常都沒有用到,除非你在fMask中設定一個到目前為止我們還沒有提到的旗標值.如果各位讀者想寫一個 Windows Shell程式,那 建議你參考Win32 API方面的文件以獲得更詳細的資訊,因為每個欄位都蠻有用處的,然而如果你隻想要由Delphi執行一個程式或者列印檔案,你也可以不管上述的這些參數. 函式中還有一個欄位用來收取所執行程式的相關資訊.hInstApp欄位的內容就相當於16元的WinExce或者是ShellExecute呼叫所傳回的值.ShellExecuteEx的傳回值則包含要被執行程式如果無法啟動時的錯誤碼,不過不管怎 說,最重要的還是hProcess這個代表新執行程序的唯一handle值. 程式還在執行嗎?32位元版 我們可以利用hProcess以及新的32位元函式WaitForSingleObject來測試程序是否已經執行完畢. WaitForSingleObject的宣告如下: function WaitForSingleObject(hObject:Thandle;dwTimeout:Dword):DWord; hObject是我們要等待的物件的handle值,在這個例子中就是hProcess程序的handle.dwTimeOut則為此函式要等待的最長時間,以millisecond為單位.傳回值DWord則有兩種可能,第一是常數WAIT_TIMEOUT,告訴我們經過所設定的時間之後,這個程式還在執行,第二則是傳回WAIT_OBJECT_0,用來告訴我們程式已經執行完畢. 用來等待程式執行結束的回圈大致如下: while WaitForSingleObject(hProcess,100)=WAIT_TIMEOUT do Application.ProcessMessage;其中WaitForSingleObject將你的Delphi程式(或者更精確地,執行緒,不過通常都一樣,除非你寫的是一個多執行緒的程式)在等待timeout的期間完全進入睡眠狀態. 當程式在睡眠狀態時它並不能處理傳進來的訊息,也就是說,如果程式在最小化狀態或者因為有別的程式執行遮蓋到它的視窗畫面之後又結束時,它便無法再重繪自己的視窗,因此在選擇dwTimeOut的值時必須不能太長,譬如說100ms,以便在程式的執行效率以及程式必須要能回應發生事件所需等待的時間兩者之間取得最佳的協調. 取得結束碼 32位元Windows API提供了程式師長久以來想要的東西,那就是提供被叫用程式(通常為DOS程式,雖然Windows程式也會傳回結束碼)的結束碼.要取得結束碼相當簡單,隻要在程序結束時使用GetExitCodeProcess呼叫即可, 函式宣告如下: function GetExitCodeProcess(hProcess:THandle;var lpExitCode:DWord):Boolean; 這時,hProcess這個handle依舊是代表這個程式的唯一值,傳回的值(或者例外情況下傳回的例外值)會被放到變數lpExitCode中,如果這個程式還在運作,lpExitCode的值就是STILL_ACTIVE.如果有某些原因造成它執行錯誤,GetExitCodeProcess會傳回false. 32位元版的ShellExec 程表式列表參是一個32位元版的ShellExec函式,它用的參數與程式列表二中的16位元版本一樣,不同的是,傳回的是一個32位元的值.其中wait參數如果設為 True,函式將會等到所執行程式結束纔回傳回它的結束碼,如果設為False的話,那 就會因為無法得到結束碼而隻傳回0.如果其中呼叫ShellExecEx或者是GetExitCodeProcess的過程有問題的話,傳回值則為-1. 程式列表參是,利用ShellExecuteEx執行程式 fumction ShellExec(op,fn,par,dir:PChar;show:Word;wait:Boolean):Longlnt; var ih:Word; OK:Boolean; info:TShellExecutelnfo; begin FillChar(info,SizeOf(info),Chr(0)); info.cbSize:=SizeOf(info); info.fMask:=SEE_MASK_NOCLOSEPROCESS; info.ipVerb:=op info.ipFile:=fn; info.lpParameters:=par; info.lpDirectory:=dir; info.nShow:=show; OK:Boolean(ShellExecuteEx(@info)); if OK then bgein if wait then bgein while WaitForSingleObject(info.hProcess,100)=WAIT_TINEOUT do Application.ProcessMessages; OK:=GetExitCodeProcess(info.hProcess,DWord(Result)); end else Result:=0; end; if not OK then Result:=-1; end;
|
KFC
一般會員 發表:43 回覆:73 積分:23 註冊:2003-03-27 發送簡訊給我 |
|
banson1716
高階會員 發表:55 回覆:182 積分:167 註冊:2002-04-14 發送簡訊給我 |
|
KFC
一般會員 發表:43 回覆:73 積分:23 註冊:2003-03-27 發送簡訊給我 |
谢谢。我用了CreateProcess来打开进程
然后用
GetExitCodeProcess(piProcInfo.hProcess,dwExitCode);
TerminateProcess(piProcInfo.hProcess, dwExitCode);
CloseHandle(piProcInfo.hThread);
CloseHandle(piProcInfo.hProcess);
等代码去关闭它。虽然没问题。但程序的图标还是留在Tray上,实际上它是关闭了。当你用mouse移过去时它消失。怎样解决?谢谢
|
wnhoo
高階會員 發表:75 回覆:443 積分:198 註冊:2003-04-22 發送簡訊給我 |
在工程文件中处理:
program Project1;
uses windows, Forms,
Unit1 in 'Unit1.pas'{Form1}; {$R *.RES}
const classname='TForm1'; {声明为主窗体的类名}
var handle:integer; {变量} begin
{-----------------主要为该判断部分----------------------}
handle:=findwindow(classname,nil);{查找是否有此类的窗体}
if handle<>0 then {不为0则程序已运行}
begin
messagebox(0,'该程序已经有一个在运行中!','运行',0);{提示程序已运行}
halt; {退出程序}
end;
{------------------------------------------------------}
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
该程序在测试时由于Delphi也生成了此类实例窗体,所以会出现提示框,只有关闭Delphi后单独运行程序才能实现。 风花雪月 e梦情缘
------
风花雪月 e梦情缘 |
KFC
一般會員 發表:43 回覆:73 積分:23 註冊:2003-03-27 發送簡訊給我 |
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |