如何使用mutex判斷程式是否已經被執行? |
答題得分者是:pceyes
|
lkkplayer
一般會員 發表:26 回覆:59 積分:17 註冊:2006-11-22 發送簡訊給我 |
請教各位大大我欲寫一個程式A去控制程式B的執行與停止,
而且不會重複執行基本上我尋找過網路上人家的範例,算是有成功, 我想請教的問題是萬一程式A已經停止了,但是程式B還在執行中, 我再一次執行程式A然後再用程式A再一次執行程式B, 照我要的動作應該是不允許再執行,但是結果卻是可以再執行, 造成有兩個程式B在跑主要的程式碼如下,請教大家我問題是出在哪? 另外請教一下大家我程式B原本是有form的, 我加了Application.ShowMainForm:=false 把他隱藏起來, 那執行後我可以控制程式B的form裡面的元件(按鈕之類)嗎? [code delphi] procedure TMainForm.StartProgram(ProName: string); var Mutexhandle: THandle; begin Mutexhandle := CreateMutex(nil, true, PChar(ProName)); //建立Mutex if GetLastError = ERROR_ALREADY_EXISTS then //程式已在執行 begin MessageBox(0, '程式執行中', '警告', mb_iconhand); //Halt; //結束程式 end else begin proc_exe(ProName '.exe'); end; end; procedure TMainForm.proc_exe(s: string); var sCommandLine: string; bCreateProcess: boolean; lpStartupInfo: TStartupInfo; //lpProcessInformation: TProcessInformation; begin sCommandLine := s; FillChar(lpStartupInfo,Sizeof(TStartupInfo),#0); lpStartupInfo.cb := Sizeof(TStartupInfo); lpStartupInfo.dwFlags := STARTF_USESHOWWINDOW; lpStartupInfo.wShowWindow := SW_NORMAL; bCreateProcess := CreateProcess(nil,PChar(sCommandLine),nil,nil,True, CREATE_NEW_CONSOLE OR NORMAL_PRIORITY_CLASS, nil,nil,lpStartupInfo,lpProcessInformation); end; procedure TMainForm.proc_terminate; begin TerminateProcess(lpProcessInformation.hProcess, 0); end; [/code] |
pceyes
尊榮會員 發表:70 回覆:657 積分:1140 註冊:2003-03-13 發送簡訊給我 |
|
lkkplayer
一般會員 發表:26 回覆:59 積分:17 註冊:2006-11-22 發送簡訊給我 |
|
pceyes
尊榮會員 發表:70 回覆:657 積分:1140 註冊:2003-03-13 發送簡訊給我 |
個人猜測, 未證實
1. 程式A關閉後CreateMute失去作用(和findwindow不同,它是抓Process Id), 故第二次CreateMute沒有作用, 2. 因此, 所有的程式應由A來執行就不會有問題, 也就是說 : 絶對不能讓A程式關閉, 在其他次程式還有在運行中。 幫你找一個,寫得不錯 VC和Delphi程式隻運行一個實例的方法http://209.85.175.104/search?q=cache:3ax43xe9PocJ:big5.yesky.com/b5/dev.yesky.com/480/2322980.shtml delphi ERROR_ALREADY_EXISTS&hl=zh-TW&ct=clnk&cd=1&gl=tw [code delphi] program OnlyOne; uses Windows, Forms, uOnlyOneWindow in 'uOnlyOneWindow.pas' {OnlyOneWindow}; {$R *.res} var hAppMutex: THandle; begin Application.Initialize; //創建互斥對象 hAppMutex := CreateMutex(nil, false, PChar('OnlyOne')); if (hAppMutex = 0) then begin MessageBox(0,PChar('創建互斥對象失敗!'),PChar('Error'),MB_OK MB_ICONINFORMATION); exit; end; //查看是否是第一次運行程式 if ((hAppMutex <> 0) and (GetLastError() = ERROR_ALREADY_EXISTS)) then begin MessageBox(0,PChar('不是第一次運行這個程式!'),PChar('OK'),MB_OK MB_ICONINFORMATION); //關閉互斥對象,退出程式 CloseHandle(hAppMutex); exit; end; Application.CreateForm(TOnlyOneWindow, OnlyOneWindow); Application.Run; //關閉互斥對象 CloseHandle(hAppMutex); end. [/code] 注意: 1.在User中,要把Windows放在Form前頭; 2.開始創建互斥對象的代碼要在Application.Initialize之後; 3.關閉互斥對象操作要放在Application.Run之後; 這樣,我們隻用了較少的代碼和較少的系統資源消耗就實現了應用程式偵測自己是否被多次運行,從而保證隻運行一個示例這樣的效果。 以上程式在Visual C 6.0(SP6)、Delphi 7(Build 8.1)中編譯,在Windows XP SP2中測試透過。 注1:當某調用者所請求創建的互斥對象已經被命名了並且存在,這時這個調用者為“第二個調用者
------
努力會更接近成功 |
lkkplayer
一般會員 發表:26 回覆:59 積分:17 註冊:2006-11-22 發送簡訊給我 |
|
pceyes
尊榮會員 發表:70 回覆:657 積分:1140 註冊:2003-03-13 發送簡訊給我 |
找一個我目前在玩的方式如下:
利用SendMessage傳遞記憶體位址傳送中文或字串 http://delphi.ktop.com.tw/board.php?cid=31&fid=79&tid=76861 這是M$推薦的處理方式,且不論您的程式是show或hide,只要是活著的程式,皆可呼叫, 我幫你想的方法如下: 1. A程式先叫出B程式,B程式sendmessage給A程式,告訴A程式B程式起來了, 2. A程式寫入ini,註明B程式執行中(隠藏)。 3. 程式A可以用Sendmessage要求程式B作任何事(要按鍵也可)。 4. 當程式A要關閉時也可Sendmessage程式B通知A關閉。
------
努力會更接近成功 |
lkkplayer
一般會員 發表:26 回覆:59 積分:17 註冊:2006-11-22 發送簡訊給我 |
pceyes大大:
SendMessage有這樣的方式喔!!真是神奇。我在爬文的時候找到pcboy 發表的顯示目前執行的程序(Process List) (含Source Code) http://delphi.ktop.com.tw/board.php?cid=31&fid=79&tid=86821 我想這個可能也可以達到我某部分的目標,或許跟你的方法混著用的 在此先跟你說聲謝謝.....並祝你新年快樂^^" ===================引 用 pceyes 文 章=================== 找一個我目前在玩的方式如下: 利用SendMessage傳遞記憶體位址傳送中文或字串 http://delphi.ktop.com.tw/board.php?cid=31&fid=79&tid=76861 這是M$推薦的處理方式,且不論您的程式是show或hide,只要是活著的程式,皆可呼叫, 我幫你想的方法如下: 1. A程式先叫出B程式,B程式sendmessage給A程式,告訴A程式B程式起來了, 2. A程式寫入ini,註明B程式執行中(隠藏)。 3. 程式A可以用Sendmessage要求程式B作任何事(要按鍵也可)。 4. 當程式A要關閉時也可Sendmessage程式B通知A關閉。 |
pceyes
尊榮會員 發表:70 回覆:657 積分:1140 註冊:2003-03-13 發送簡訊給我 |
昨天太晚, 還沒回, 要伺候小孩睡了, 直接關機了, 你和我想的一樣
...get a list of all running Exe-Files/ Check if a Exe-File is running? http://www.swissdelphicenter.ch/torry/showcode.php?id=616
------
努力會更接近成功 |
lkkplayer
一般會員 發表:26 回覆:59 積分:17 註冊:2006-11-22 發送簡訊給我 |
pceyes大大:
我混用processlist和sendmessage的方法終於達到我的程式目的啦! 在此非常感謝你,不過有關sendmessage我有碰到一個問題,想請教你 一下就是我用a程式的按鈕BitBtn3去啟動b程式,接著馬上送訊息給b 程式去執行按鈕Button1的事件,有啟動成功但是卻沒有去執行按鈕 Button1的事件,但是在b程式是在已經執行的情況下,我送訊息給b 程式去執行按鈕Button2的事件,卻ok耶,真是非常奇怪??,我目前 解決的方法是在程式b的FormCreate事件直接加入觸發Button1的事件 只是這個問題不知道為什麼,不知道你有遇到過嗎? 我列出我的程式碼如下: a程式: [code delphi] procedure TMainForm.BitBtn3Click(Sender: TObject); begin StartProgram('Project2.exe',Shape1); end; procedure TMainForm.BitBtn4Click(Sender: TObject); begin StopProgram('Project2.exe',Shape1); end; procedure TMainForm.StartProgram(ProName: string;Shape: TShape); begin if EXE_Running(ProName, False) then //程式已在執行 begin MessageBox(0, '程式執行中', '警告', mb_iconhand); end else begin proc_exe(ProName); <---啟動程式 send_message(leftstr(ProName,6) 'START'); <---送訊息給程式b Shape.Brush.Color:=clLime end; end; procedure TMainForm.StopProgram(ProName: string;Shape: TShape); begin if EXE_Running(ProName, False) then //程式已在執行 begin send_message(leftstr(ProName,6) 'STOP'); <---送訊息給程式b Shape.Brush.Color:=clRed; end else begin MessageBox(0, '程式非執行中', '警告', mb_iconhand); end; end; procedure TMainForm.proc_exe(s: string); var sCommandLine: string; bCreateProcess: boolean; lpStartupInfo: TStartupInfo; lpProcessInformation: TProcessInformation; begin sCommandLine := s; FillChar(lpStartupInfo,Sizeof(TStartupInfo),#0); lpStartupInfo.cb := Sizeof(TStartupInfo); lpStartupInfo.dwFlags := STARTF_USESHOWWINDOW; lpStartupInfo.wShowWindow := SW_NORMAL; bCreateProcess := CreateProcess(nil,PChar(sCommandLine),nil,nil,True, CREATE_NEW_CONSOLE OR NORMAL_PRIORITY_CLASS, nil,nil,lpStartupInfo,lpProcessInformation); end; procedure TMainForm.send_message(s: string); begin strcopy(str,pchar(s)); SendMessage(HWND_BROADCAST,WM_TEST,Longint(@str),application.Handle); end; [/code] b程式: [code delphi] procedure TForm1.Wndproc(var Message:TMessage); var AProcessID,WridCount:DWORD; gg:longbool; pt:THandle; begin Case Message.Msg of WM_TEST:begin GetWindowThreadProcessId(Message.LParam, @AProcessID); pt:=openprocess(PROCESS_VM_READ,false,AProcessID);//要求打開拜訪行程 gg:=ReadProcessMemory(pt,Pointer(message.WParam),@str,25,WridCount);//讀取記憶體內容 if pchar(@str)='ProjecSTART' then Button1.Click else if pchar(@str)='ProjecSTOP' then Button2.Click end; end; inherited Wndproc(Message); end; procedure TForm1.Button1Click(Sender: TObject); begin ShowMessage('啟動成功'); end; procedure TForm1.Button2Click(Sender: TObject); begin ShowMessage('停止成功'); close; end; [/code] ===================引 用 pceyes 文 章=================== 昨天太晚, 還沒回, 要伺候小孩睡了, 直接關機了, 你和我想的一樣 ...get a list of all running Exe-Files/ Check if a Exe-File is running? http://www.swissdelphicenter.ch/torry/showcode.php?id=616
編輯記錄
Coffee 重新編輯於 2008-02-13 16:49:43, 註解 請盡量使用程式碼區塊排版‧
|
pceyes
尊榮會員 發表:70 回覆:657 積分:1140 註冊:2003-03-13 發送簡訊給我 |
|
lkkplayer
一般會員 發表:26 回覆:59 積分:17 註冊:2006-11-22 發送簡訊給我 |
pceyes大大:
我剛剛照你的意思去改寫,已經成功啦!謝謝你^^" ===================引 用 pceyes 文 章=================== 既然你已用Sendmessage了, 你可以試著這樣用 : 1. A 執行 B 2. B Active 時 Sendmessage "B Active Ready"給 A 3. A 收到message "B Active Ready" 時 再 Sendmessage "B Do Something" 給B 你會失敗的原因可能A Sendmessage時,B 程序還沒起來,用這種方式比起用Wait更好。 |
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |