互斥对象:使用互斥对象让程序只运行一次




使用互斥对象让只运行

“如何让我在运行时不能重复打开?”经常在论坛上看到有朋友问这方面问题本文将比较详细介绍说明这问题并给出个较为完善解决方案
尽管这已经不是个新问题了但这里还是简要介绍说明下这种技术:这确是个相当有用技术可能你经常会注意到相当多在运行的后当你再次点击运行时它只是会回到原来窗口而不会运行两个就如同你在运行delphi时在外部点开另个工程文件时delphi只是会简单将你当前工程置换而不是运行两个delphi这样好处是显而易见:你不必担心你在某些情况下被别软件Software恶意运行多次而吃光内存造成当机下面我们做进介绍说明:
熟悉win32编程朋友(特别是多线程编程)相信对互斥对象已经相当熟悉了它常被用做线程间同步技术手段这里我们使用它来防止重复运行我们只是简要下互斥对象并不做深入研究:互斥对象把第次建立它作为主这样我们只用检测互斥对象是否已经有主就判断是否已经运行过这里需要涉及到个api:WaitForSingleObject该个参数为用以检测互斥对象第2个参数表示返回结果前滞留时间如果改返回wait_TimeOut就表明互斥对象已经有了个主修改了工程文件代码如下:(注意:以下代码都出现在工程文件中而不是单元文件中并且这里都在最简单delphi默认建立工程基础上修改)
var
 myMutex:HWND;
begin
  myMutex:=CreateMutex(nil,false,\'hkOneCopy\');// CreateMutex建立互斥对象并且给互斥对象起个唯名字
  WaitForSingleObject(myMutex,0)<>wait_TimeOut then//没有被运行过
  begin
   Application.Initialize;
   Application.CreateForm(TForm1, Form1);
   Application.Run;
  End;
End;
下面工作是来完善这个我们不仅希望可以不被重复运行而且我们也希望当用户再次点击可执行文件时已经运行能够做出些响应在这里我们希望它能够变为最上层活动窗口以提醒用户已经被运行为了达到这个目我们必须先获得已经运行窗口句柄以便使用SetForeGroundWindow(handle)来使窗口最前并激活为了得到这个句柄我们必须使用windows枚举EnumWindows来遍历windows窗口列表可以使用个回调作为参数并用这个回调来对每个系统中窗口进行直到最后个窗口或回调返回false为止这个回调规定有两个参数(handle,Cardinal只用注意第个handle参数它表示由枚举当前遍历到窗口句柄)我们只要编写这个并在其中不断比较当前遍历到窗口类名和我们主窗口类名以及比较窗口可执行文件名称和我们名称直到找到相同为止将这时窗口句柄保存下来就可以了下面代码加上了适当注释:
function EnumWndProc(hwnd:Thandle;param:Cardinal):bool;stdcall;
//由于用于api回调请使用windows传统参数传递方式stdcall
var
 ClassName,WinMoudleName:;
 WinInstance:THandle;
begin
 result:=true;
 SetLength(ClassName,100);
 GetClassName(hwnd,pchar(ClassName),length(ClassName));//获得当前遍历窗口类名
 ClassName:=pchar(ClassName);//在串后加结束符确定串结束
  ClassName=TForm1.ClassName then//比较
 begin
  WinInstance:=GetWindowLong(hwnd,GWL_HINSTANCE);//获得当前遍历窗口例子
  length(WinMoudleName,100);
  GetModuleFileName(WinInstance,pchar(WinMoudleName),length(WinMoudleName));
  //获得当前遍历窗口文件名
  WinMoudleName:=pchar(WinMoudleName);
  WinMoudleName=MoudleName then//MoudleName为工程全局变量自身文件名
  begin
   FindHid:=hwnd;//FindHid为工程全局变量保存找到句炳
   result:=false;//找到以后就结束遍历
  end;
 end;
end;
下面是全部工程文件:
var
 hMutex,FindHid:HWND;
 MoudleName:;
begin
  hMutex:=CreateMutex(nil,false,\'hkOneCopy\');
  WaitForSingleObject(hMutex,0)<>wait_TimeOut then
  begin
   ……//略去代码在前文
  end
 
  begin
   SetLength(MoudleName,100);
   GetModuleFileName(HInstance,pchar(MoudleName),length(MoudleName));
   //获得自己文件名
   MoudleName:=pchar(MoudleName);
   EnumWindows(@EnumWndProc,0);//枚举
   FindHid<>0 then
    SetForegroundWindow(FindHid);
  end;
end.

Tags:  互斥量 进程互斥 互斥事件 互斥对象

延伸阅读

最新评论

发表评论