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

原创 2003年08月12日 10:26:00

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

“怎么让我的程序在运行时不能重复打开?”经常在论坛上看到有朋友问这方面的问题。本文将比较详细的说明这一问题,并给出一个较为完善的解决方案。

尽管这已经不是一个新问题了,但这里还是简要的说明一下这种技术:这的确是一个相当有用的技术,可能你经常会注意到相当多的程序在运行之后当你再次点击运行时,它只是会回到原来的窗口,而不会运行两个程序。就如同你在运行delphi时,在外部点开另一个工程文件时,delphi只是会简单的将你的当前工程置换而不是运行两个delphi。这样的好处是显而易见的:你不必担心你的程序在某些情况下被别的软件恶意运行多次而吃光内存造成当机。下面我们做进一部的说明:

熟悉win32编程的朋友(特别是多线程编程),相信对互斥对象已经相当熟悉了,它常被用做线程间同步的技术手段。这里我们使用它来防止程序重复运行。我们只是简要的提一下互斥对象,并不做深入研究:互斥对象把第一次建立它的程序作为主程序,这样我们只用检测互斥对象是否已经有主程序就判断程序是否已经运行过,这里需要涉及到一个api函数:WaitForSingleObject该函数的第一个参数为用以检测的互斥对象,第2个参数的表示函数返回结果前的滞留时间,如果改函数返回wait_TimeOut就表明互斥对象已经有了一个主程序。修改了的工程文件代码如下:(注意:以下的代码都出现在工程文件中,而不是单元文件中,并且这里都在最简单的delphi默认建立的工程基础上修改)

var

 myMutex:HWND;

begin

  myMutex:=CreateMutex(nil,false,'hkOneCopy');// CreateMutex建立互斥对象,并且给互斥对象起一个唯一的名字。

  if 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:string;

 WinInstance:THandle;

begin

 result:=true;

 SetLength(ClassName,100);

 GetClassName(hwnd,pchar(ClassName),length(ClassName));//获得当前遍历窗口的类名

 ClassName:=pchar(ClassName);//在字符串后加结束符,确定字符串结束

 if ClassName=TForm1.ClassName then//比较

 begin

  WinInstance:=GetWindowLong(hwnd,GWL_HINSTANCE);//获得当前遍历窗口的实例

  setlength(WinMoudleName,100);

  GetModuleFileName(WinInstance,pchar(WinMoudleName),length(WinMoudleName));

  //获得当前遍历窗口的程序文件名

  WinMoudleName:=pchar(WinMoudleName);

  if WinMoudleName=MoudleName then//MoudleName为工程全局变量,自身程序的文件名

  begin

   FindHid:=hwnd;//FindHid为工程全局变量保存找到的句炳

   result:=false;//找到以后就结束遍历

  end;

 end;

end;

下面是全部的工程文件:

var

 hMutex,FindHid:HWND;

 MoudleName:string;

begin

  hMutex:=CreateMutex(nil,false,'hkOneCopy');

  if WaitForSingleObject(hMutex,0)<>wait_TimeOut then

  begin

   ……//略去的代码在前文

  end

  else

  begin

   SetLength(MoudleName,100);

   GetModuleFileName(HInstance,pchar(MoudleName),length(MoudleName));

   //获得自己程序文件名

   MoudleName:=pchar(MoudleName);

   EnumWindows(@EnumWndProc,0);//调用枚举函数

   if FindHid<>0 then

    SetForegroundWindow(FindHid);

  end;

end.

为了使我们的程序更完美,让它能在重复运行的时候展现更多的特性(如delphi中的置换工程文件为当前打开的工程),你还可以向找到的窗口句柄发送用户消息,再在窗口的消息处理函数中做相应的处理,你一定可以让我们的程序更眩!

参考文献:

   delphi开发者指南》

多线程同步互斥实例——多个线程共享数据

• 实例问题         设计4个线程,其中两个线程每次对j增加1,另外两个线程对j每次减少1,写出程序。这是一道java线程面试的面试题,这道题在网上有很多答案。那么,答案是如何来的呢? 简单来...
  • lu930124
  • lu930124
  • 2016年04月26日 17:14
  • 1745

RadioButton的使用(三个button,实现互斥,一次只能选中一个)

效果:只能选中一个radiobutton 实现的方法: 1.首先我们要将三个radiobutton的layout设置成可以点击的,然后我们将这三个radio设置成不可以点击的,我们通过点击...
  • Zuo_XP
  • Zuo_XP
  • 2016年10月27日 17:46
  • 3600

WPF 只允许运行一个程序(单例)

问题描述: 有时一个程序需要单例运行,因为涉及到上下位连接,数据库访问,安全性等问题,本博客来探讨如何实现WPF 程序的单例运行。 措施: 利用 System.Threading.Mutex ...
  • hit_rxz
  • hit_rxz
  • 2014年10月17日 15:34
  • 3876

Windows多线程程序设计之线程同步分析(结合互斥对象)(上)

Windows中的多线程程序设计一直是所有编程人员感到困难的一个地方,主要是在Windows多线程程序设计中,往往要考虑很多的东西,线程启用的多少,线程之间的同 步问题等等...   这里我将将我学...
  • CTO_51
  • CTO_51
  • 2013年06月23日 13:16
  • 1430

[VC网络编程笔记-使用API函数操作互斥对象实现线程同步

使用API函数操作事件对象实现线程同步
  • q357010621
  • q357010621
  • 2017年05月28日 18:28
  • 396

互斥对象使用CreateMutex

#include #include #include using namespace std; HANDLE hUp; CRITICAL_SECTION g_data; int ar...
  • sdyxidan
  • sdyxidan
  • 2014年08月21日 15:33
  • 369

Windows多线程总结(3)-- 线程同步(使用互斥对象实现线程同步)

上一篇说明了多线程是存在着问题的,起始就是多线程操作同一数据而不同步的问题。那么如果实现线程的同步呢?          线程的同步有多种实现方式:         互斥内核对象、事件内核对象、可等待...
  • oBuYiSeng
  • oBuYiSeng
  • 2015年11月27日 18:44
  • 720

使用互斥对象实现线程同步

使用互斥对象实现线程同步   互斥对象属于系统内核对象,它能够使线程拥有对某个资源的绝对访问权。互斥对象主要包含使用 数量,线程ID和递归计数器等信息。其中线程ID表示当前拥有互斥对象的线程,递归...
  • jin123wang
  • jin123wang
  • 2011年08月08日 13:40
  • 1356

互斥量的使用,是应用程序只运行一次

转载:http://hi.baidu.com/jenfmo/blog/item/d5a298543da5b35ad009060b.html 正常情况下,一个进程的运行一般是不会影响到其他正在运行的进...
  • Howard_Liu1314
  • Howard_Liu1314
  • 2012年09月18日 21:52
  • 1235

C#多线程学习(六) 互斥对象

http://kb.cnblogs.com/page/42533/如何控制好多个线程相互之间的联系,不产生冲突和重复,这需要用到互斥对象,即:System.Threading 命名空间中的 Mutex...
  • plean
  • plean
  • 2011年07月06日 16:09
  • 260
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:使用互斥对象让程序只运行一次
举报原因:
原因补充:

(最多只允许输入30个字)