全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:5060
推到 Plurk!
推到 Facebook!

如何使用mutex判斷程式是否已經被執行?

答題得分者是:pceyes
lkkplayer
一般會員


發表:26
回覆:59
積分:17
註冊:2006-11-22

發送簡訊給我
#1 引用回覆 回覆 發表時間:2008-02-05 22:29:19 IP:220.129.xxx.xxx 訂閱
請教各位大大我欲寫一個程式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]
編輯記錄
lkkplayer 重新編輯於 2008-02-05 22:31:47, 註解 無‧
lkkplayer 重新編輯於 2008-02-13 18:22:39, 註解 無‧
pceyes
尊榮會員


發表:70
回覆:657
積分:1140
註冊:2003-03-13

發送簡訊給我
#2 引用回覆 回覆 發表時間:2008-02-06 08:05:17 IP:220.141.xxx.xxx 訂閱
請教一個問題
為什麼B還在執行, 但A卻停止了, 是什麼情形?
------
努力會更接近成功
lkkplayer
一般會員


發表:26
回覆:59
積分:17
註冊:2006-11-22

發送簡訊給我
#3 引用回覆 回覆 發表時間:2008-02-06 10:11:19 IP:218.172.xxx.xxx 訂閱
pceyes大大:

不好意思,關於這個我沒有說的很清楚
程式A可以看成一個監看控制許多像程式B的主要程式
程式A的關閉不影響程式B的運作
但是程式A只要一執行就要去判斷程式B是否還活著,
我會用燈號顏色去顯示他是否還再執行,
依照顏色我可以判斷去啟動程式B或者關閉程式B
這個是我要寫的程式目標。

===================引 用 pceyes 文 章===================
請教一個問題
為什麼B還在執行, 但A卻停止了, 是什麼情形?
pceyes
尊榮會員


發表:70
回覆:657
積分:1140
註冊:2003-03-13

發送簡訊給我
#4 引用回覆 回覆 發表時間:2008-02-06 15:44:31 IP:61.229.xxx.xxx 訂閱
個人猜測, 未證實
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:當某調用者所請求創建的互斥對象已經被命名了並且存在,這時這個調用者為“第二個調用者
------
努力會更接近成功
編輯記錄
pceyes 重新編輯於 2008-02-06 15:53:48, 註解 無‧
pceyes 重新編輯於 2008-02-06 15:57:59, 註解 無‧
pceyes 重新編輯於 2008-02-06 16:34:03, 註解 無‧
lkkplayer
一般會員


發表:26
回覆:59
積分:17
註冊:2006-11-22

發送簡訊給我
#5 引用回覆 回覆 發表時間:2008-02-06 18:51:23 IP:218.172.xxx.xxx 訂閱
pceyes大大:

謝謝你找這麼完整的範例給我,我也蠻同意你的見解,只是程式A不能關閉
的話,這樣不能達到我想要的程式目標,而且畢竟監控程式不一定只在一台電
腦執行,程式A關掉重啟要再去偵測程式B是否有運行,使用mutex似乎也沒有
辦法達到,你有其他的方法可以建議嗎??
pceyes
尊榮會員


發表:70
回覆:657
積分:1140
註冊:2003-03-13

發送簡訊給我
#6 引用回覆 回覆 發表時間:2008-02-06 20:12:07 IP:61.229.xxx.xxx 訂閱
找一個我目前在玩的方式如下:
利用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

發送簡訊給我
#7 引用回覆 回覆 發表時間:2008-02-07 01:27:21 IP:218.172.xxx.xxx 訂閱
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

發送簡訊給我
#8 引用回覆 回覆 發表時間:2008-02-07 09:55:35 IP:61.229.xxx.xxx 訂閱
昨天太晚, 還沒回, 要伺候小孩睡了, 直接關機了, 你和我想的一樣
...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

發送簡訊給我
#9 引用回覆 回覆 發表時間:2008-02-13 16:42:28 IP:218.164.xxx.xxx 訂閱
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

發送簡訊給我
#10 引用回覆 回覆 發表時間:2008-02-13 17:40:29 IP:220.141.xxx.xxx 訂閱
既然你已用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更好。
------
努力會更接近成功
lkkplayer
一般會員


發表:26
回覆:59
積分:17
註冊:2006-11-22

發送簡訊給我
#11 引用回覆 回覆 發表時間:2008-02-13 18:21:20 IP:218.164.xxx.xxx 訂閱
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更好。
系統時間:2024-07-01 4:54:42
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!