怎样才能禁止同一个程序同时运行
已经在运行的程序,在未退出之前又运行这个程序,给出警告。在正常退出之后才能再次运行该程序,这能做到吗?请指教 问题点数:50、回复次数:7Top
1 楼iceboy2000(不死鸟一辉)回复于 2002-04-11 10:45:08 得分 25
只要在工程文件中作下面的处理就搞定了
var
hmutex:hwnd;
ret:integer;
begin
Application.Initialize;
hmutex:=createmutex(nil,false,'project1');
ret:=getlasterror;
if ret<>error_already_exists then
begin
Application.CreateForm(TForm1, Form1);
end
else
begin
messagedlg('程序已运行。',mtinformation,[mbok],0);
releasemutex(hmutex);
end;Top
2 楼yuanjunjing(danny)回复于 2002-04-11 10:45:23 得分 0
var
hwnd:THandle;
hwnd:=findwindow('tfrm_main',nil);
if hwnd=0 then
begin
Application.Initialize;
Application.Title := '¹ã¶«Òç´ïÕëÖ¯ÓÐÏÞ¹«Ë¾Ô­É´²Ö¹ÜÀíϵͳ';
Application.Title := 'ÕëÖ¯¹ÜÀíÐÅϢϵͳ֮ɴ²Ö¹ÜÀí';
Application.CreateForm(TMainDataModule, MainDataModule);
Application.CreateForm(TMainForm, MainForm);
Application.Run;
end
else
setforegroundwindow(hwnd);Top
3 楼yuanjunjing(danny)回复于 2002-04-11 10:46:21 得分 25
var
hwnd:THandle;
hwnd:=findwindow('tfrm_main',nil);
if hwnd=0 then
begin
Application.Initialize;
Application.CreateForm(TMainDataModule, MainDataModule);
Application.CreateForm(TMainForm, MainForm);
Application.Run;
end
else
setforegroundwindow(hwnd);
Top
4 楼whycats(雪狐)回复于 2002-04-11 10:46:53 得分 0
或者用findform(),还有对象互斥。Top
5 楼errorcode(errorcode)回复于 2002-04-11 10:59:24 得分 0
good to 一楼Top
6 楼wind8bell(风之铃)回复于 2002-04-11 11:00:28 得分 0
转贴:
实现单实例运行的关键是判断前一实例是否存在,Win3.x中运行的程序能获知前一实
例的句柄,从而可以方便地进行判断,但 Windows 95 是抢先式多任务系统,其程序
的前一实例句柄恒为零,所以只有另寻其他办法。
据说有很多方法都可解决这个问题,不过我只知道两种,下面分别加以介绍。
★第一种方法:
通过查看是否有相同窗口类名的例程存在来进行判断。
API函数 FindWindow 按照指定类名和窗口名来找到窗口的句柄,该函数并不查找子窗口。
FindWindow的函数原型为:
HWND FindWindow(
LPCTSTR lpClassName, // address of class name
LPCTSTR lpWindowName // address of window name
);
参数:
lpClassName 欲查找窗口的类名。该变量的类型为以零结尾的字符串,也就是C/C++中
的字符串类型。
lpWindowName 窗口名。变量类型同上。
返回值:
若成功,返回指定窗口的句柄;否则返回NULL。如果希望得到更多的失败信息,可以调用
GetLastError 函数。
例:
var
PrevWindow:HWND; //定义一个句柄变量
begin
Application.Initialize; //程序初始化
PrevWindow:=FindWindow('TForm1','运行时实例测试');
//窗口的类名为'TForm1',窗口名为'运行时实例测试'
//在Delphi中,窗口的类名可以从程序的TYPE区域里看到,而窗口名就是窗口的Caption属性。
if PrevWindow<>0 then //如果找到此窗口,说明程序已经运行了一个实例
Begin
MessageBox(0,"已经运行了该程序!","警告",MB_ICONWARNING+MB_OK);
Application.Terminate; //程序终止运行以保证只有一个实例
end;
Application.CreateForm(TForm1, Form1); //否则程序继续运行
Application.Run;
end.
//以上程序在Delphi 3.0 中通过。FindWindow函数的详细用法参见Win32 Api Help。
WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
HWND PreWindows;
try
{
Application->Initialize();
PreWindows=FindWindow("TForm1","运行实例测试");
if(PreWindows)
{
MessageBox(0,"已经运行了该程序!","警告",MB_ICONWARNING+MB_OK);
Application->Terminate();
}
Application->CreateForm(__classid(TForm1), &Form1);
Application->Run();
}
catch (Exception &exception)
{
Application->ShowException(&exception);
}
return 0;
}
//以上程序在C++ Builder 1.0 中通过。
★第二种方法:
第二种方法就是利用API函数CreateMutex。
CreateMutex函数用来创建一个已命名或是未命名的互斥体。
CreateMutex的函数原型为:
HANDLE CreateMutex(
LPSECURITY_ATTRIBUTES lpMutexAttributes, // address of security attributes
BOOL bInitialOwner, // flag for initial ownership
LPCTSTR lpName // address of mutex-object name
);
参数说明:
lpMutexAttributes 此参数指向一个SECURITY_ATTRIBUTES结构,此结构指定该互斥体的安全
属性,如果该参数为NULL(即为空),则以缺省的安全描述符来创建互斥
体,并且该函数返回的句柄不能被继承。
(此参数好象不好理解,不过在此处你只需将其设为NULL就行了!)
bInitialOwner 指定互斥体对象的初始拥有者。在此处设为False。
lpName 此参数指定互斥体的名字。参数类型是以NULL结尾的字符串。
返回值:
如果函数成功则返回互斥体的句柄,如果指定的互斥体名已经存在,则GetLastError函数返回
ERROR_ALREADY_EXISTS。
例:
program DEL3test;
uses
Forms,Windows,SysUtils,
DEL3unit in 'DEL3unit.pas' {Form1};
{$R *.RES}
Var
hMutex:HWND;
Ret:Integer;
begin
Application.Initialize;
Application.Title := 'aaaaaa';
hMutex:=CreateMutex(nil,False,'aaaaaa');
Ret:=GetLastError;
If Ret<>ERROR_ALREADY_EXISTS Then
Begin
Application.CreateForm(TForm1, Form1);
Application.Run;
End
Else
Application.MessageBox('Run Twice!','Notes!',MB_OK);
ReleaseMutex(hMutex);
end.
//以上例子在Delphi 3.0中通过。
说明:
这两种方法一般来说并没有什么很大的区别,也没有在什么地方看到有关这两者的说明。
不过我在自己的程序中正好分别试过这两种方法,发现了这两者还是有一个区别。
如果程序中有一个启动画面,如Visual Foxpro,Delphi,wps97等等,当采用第一种方法
时,仍然会出现启动画面,尽管在程序中我是先判断有无实例存在,然后再显示启动画面。
为什么会这样,我也不清楚,而用第二种方法就不会出现这种情况,所以我一直都用第二
种方法。
Top
7 楼tanqth(青蛙)回复于 2002-04-11 11:01:48 得分 0
实现单实例运行的关键是判断前一实例是否存在,Win3.x中运行的程序能获知前 一实例的句柄,从而可以方便地进行判断,但 Windows 95 是抢先式多任务系统,其程序的前一实例句柄恒为零,所以只有另寻其他办法。目前最有效的办法是通过查看是否有相同窗口类名的例程存在来进行判断。下面介绍在Delphi中实现的方法。
1、对主窗口程序的改动:
在主窗口(即程序创建的第一个窗口)中interface节加入
const
CM_RESTORE = WM_USER + $1000; {自定义的“恢复”消息}
MYAPPNAME = "My Delphi Program";
并在Form的定义的public节中加入
procedure CreateParams(var Params: TCreateParams); override;
Procedure RestoreRequest(var message: TMessage); message CM_RESTORE;
在implementation节中加入
{指定窗口名称}
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;
经过以上修改,程序的主窗口的类名已经被指定了,这是进行判断的基础。一般在程 序刚开始运行的时候进行判断,所以还要对DPR文件进行修改。
2、对DPR文件的改动
在 uses 节中添加 windows、messages这两个单元加入下列语句,注意两个文件中常 量CM_RESTORE和MYAPPNAME的定义必须一致
const
CM_RESTORE = WM_USER + $1000; {自定义的“恢复”消息}
MYAPPNAME = "My Delphi Program";
var
RvHandle : hWnd;
将下列语句插到程序最前部(在Application.Initialize之前)
RvHandle := FindWindow(MYAPPNAME, NIL);
if RvHandle > 0 then
begin
PostMessage(RvHandle, CM_RESTORE, 0, 0);
Exit;
end;
这段程序的意思是如果找到一个类名相同的窗口,则向该窗口发送一个消息,并退 出,而本例中原窗口收到该消息后会自动激活或从图标还原,从而达到了避免二次运行.
Top




