如何避免运行一个已经在运行的程序?(70分)

  • 主题发起人 主题发起人 kk.wang
  • 开始时间 开始时间
K

kk.wang

Unregistered / Unconfirmed
GUEST, unregistred user!
如何避免运行一个已经在运行的程序?如:我正在运行一个自做的应用程序,但我又点击
了它的EXE文件,那么如何能让程序检测到其已在运行,而不再同时启动两个?用什么函数?
请高手指教?
 
var
hMutex:HWND;
Ret:Integer;

hMutex:=CreateMutex(nil,False,'系统信息');
Ret:=GetLastError;
If Ret=ERROR_ALREADY_EXISTS Then
begin
Application.MessageBox('注意!程序已在运行!','系统信息',MB_OK+MB_ICONWARNING);
ReleaseMutex(hMutex);
halt;
end;
 
var
hMutex: THandle;

begin
HMutex := CreateMutex (nil, False, 'OneCopyMutex');
if WaitForSingleObject (hMutex, 0) <> wait_TimeOut then
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end;
end.
 
program Project1;

uses
Windows,
Messages,
Forms,
Unit1 in 'Unit1.pas' {Form1};

{$R *.RES}
const
CM_RESTORE = WM_USER + $1000;
MYAPPNAME = 'duchengfu';

var
RvHandle:integer;
begin
RvHandle := FindWindow(MYAPPNAME,nil);
if RvHandle > 0 then
begin
PostMessage(RvHandle, CM_RESTORE, 0, 0);
Exit;
end;
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.



unit Unit1;

interface



uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;

const
CM_RESTORE = WM_USER + $1000;
MYAPPNAME = 'duchengfu'
type
TForm1 = class(TForm)
private
{ Private declarations }
public
procedure CreateParams(var Params: TCreateParams);override;
procedure RestoreRequest(var message: TMessage);message CM_RESTORE;
{ Public declarations }
end;
var
Form1: TForm1;

implementation

{$R *.DFM}
procedure TForm1.CreateParams(var Params: TCreateParams);
begin
inherited CreateParams(Params);
Params.WinClassName := MYAPPNAME;
end;

procedure TForm1.RestoreRequest(var message: TMessage);
begin
if IsIconic(Application.Handle) = TRUE then
Application.Restore
else
Application.BringToFront;
end;

end.
看清楚一点即可
 
在主程序的 formcreate 事件中写:
procedure TMainForm.FormCreate(Sender: TObject);
var
ZAppName: array[0..127] of char;
Hold: String;
Found: HWND;
begin
Hold := Application.Title;
Application.Title := 'OnlyOne'+ IntToStr(HInstance); // 暂时修改窗口标题
StrPCopy(ZAppName, Hold); // 原窗口标题
Found := FindWindow(nil, ZAppName); // 查找窗口
Application.Title := Hold; // 恢复窗口标题
if Found<>0 then
begin
// 若找到则激活已运行的程序并结束自身
ShowWindow(Found, SW_RESTORE);
Application.Terminate;
end;
end;


搞定了吧!!!!!!!!procedure TSelect_FLow_Form.FormCreate(Sender: TObject);
var
ZAppName: array[0..127] of char;
Hold: String;
Found: HWND;
begin
Hold := Application.Title;
Application.Title := 'OnlyOne'+ IntToStr(HInstance); // 暂时修改窗口标题
StrPCopy(ZAppName, Hold); // 原窗口标题
Found := FindWindow(nil, ZAppName); // 查找窗口
Application.Title := Hold; // 恢复窗口标题
if Found<>0 then
begin
// 若找到则激活已运行的程序并结束自身
ShowWindow(Found, SW_RESTORE);
Application.Terminate;
end;
end;

搞定了吧!!
 
判断只运行一个程序(单实例)的方法一般有3种,前面已经列举了FindWindow方法和
CreateMutex方法,还有一种是全局原子法,具体如下:
在.dpr的文件如下:
program Project1;

uses
Forms,windows,dialogs,
Unit1 in 'Unit1.pas' {Form1};

{$R *.RES}
const iAtom='SingleAPP';
begin
if GlobalFindAtom(iAtom)=0 then
Begin
GlobalAddAtom(iAtom);
Application.initialize;
Application.createForm(tForm1,form1);
Application.run;
GlobalDeleteAtom(globalFindAtom(iAtom));
End
else
showmessage('您已经运行了一个程序');
End.
 
如果,你要简单一点呢,有一个vcl 叫justone,可以完成你要的功能。
 
把以下代码代码加到工程文件里(选择Project-->view source)

var
WinHandle:THANDLE;
begin
WinHandle:=FindWindow(nil,'某某系统');
if WinHandle=0 then
Application.Initialize;
Application.CreateForm(TForm1,Form1);
Application.Run;
else
begin
showmessage('程序已经运行!') //这句可去掉,直接切换到已运行的实例
windows.setfocus(WinHandle)
windows.setforeground(WinHandle)
end;
end.
 
先谢谢各位的解答,但结果都不是很完美,不知有没有办法解决?
用孟雯的findWindow()方式,出现明显的闪烁。
用Fyx,sbcnet的CreateMutex()方式,没有闪烁,但当应用程序处于最小化状态时,
再运行,其不能显示出来,仍为最小化状态。
用杜成福的消息方法,当程序处于当前激活状态时,再运行,其变为非激活状态。

请高手指点?
 
如果通过另一个应用程序,启动本程序,好象以上方法都不能把本程序窗口
激活,并显示出来!?
 
我测试过了,若程序已运行,则用原来的位置和大小恢复窗口并激活.假如是通过其他程序启动
本程序的话,注意区分判断的窗口句柄是那一个的就行了

把以下代码代码加到工程文件里(选择Project-->view source)
var
WinHandle:THANDLE;
begin
WinHandle:=FindWindow(nil,'test');

//判断程序是否已运行,并做相应处理
if WinHandle=0 then
begin
Application.Initialize;
Application.Title := 'test';
Application.CreateForm(TForm1, Form1);
Application.Run;
end
else
begin
//用原来的位置和大小恢复窗口并激活
ShowWindow(WinHandle,SW_RESTORE);
windows.setfocus(WinHandle);
windows.SetForegroundWindow(WinHandle);
end;

end.
 
接受答案了.
 
后退
顶部