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

尽管这已经不是一个新问题了,但这里还是简要的说明一下这种技术:这的确是一个相当有用的技术,可能你经常会注意到相当多的程序在运行之后当你再次点击运行时,它只是会回到原来的窗口,而不会运行两个程序。就如同你在运行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)的更多相关文章

  1. 让程序只运行一个实例(Delphi篇)(三种方法,其中使用全局原子的方法比较有意思)

    Windows 下一个典型的特征就是多任务,我们可以同时打开多个窗口进行操作,也可以同时运行程序的多个实例,比如可以打开许多个资源管理器进行文件的移动复制操作.但有时出于某种考虑(比如安全性),我们要 ...

  2. Delphi实现程序只运行一次并激活已打开的程序

    我们的程序有时候只允许运行一次,并且最好的情况是,如果程序第二次运行,就激活原来的程序.网上有很多的方法实现程序只运行一次,但对于激活原来的窗口却都不怎么好.关键就在于激活原来的程序,一般的做法是在工 ...

  3. 如何让Windows程序只运行一个程序实例?

    要实现VC++或者MFC只运行一个程序实例,一般采用互斥量来实现,即首先用互斥量封装一个只运行一个程序实例的函数接口: HANDLE hMutex = NULL; void MainDlg::RunS ...

  4. vc++高级班之窗口篇[4]---让程序只运行一个实例

      大家都看过或者使用过类似只运行一个实例的程序,比如:QQ游戏.部分浏览器 等等! 让一个程序只运行一个实例的方法有多种,但是原理都类似,也就是在程序创建后,有窗口的程序在窗口创建前, 检查系统中是 ...

  5. VC 实现程序只运行一个实例,并激活已运行的程序

    转载:http://blog.sina.com.cn/s/blog_4b44e1c00100bh69.html 进程的互斥运行:CreateMutex函数实现只运行一个程序实例 正常情况下,一个进程的 ...

  6. [转]Delphi中,让程序只运行一次的方法

    program onlyRunOne; uses Forms,Windows,SysUtils, Dialogs, Unit1 in 'Unit1.pas' {Form1}; {$R *.res} v ...

  7. Winform(C#)限制程序只运行一个实例

    C#控制只运行开启一个程序 在这个例子中不需要调用ReleaseMutex,mutex会在程序结束时自动释放.为了防止mutex过早释放,在程序的最后调用下GC.KeepAlive (mutex). ...

  8. C#让应用程序只运行一个实例的几种方法

    一 判断是否有相同的实例已经运行 1 根据“Mutex”判断是否有相同的实例在运行 /// <returns>已有实例运行返回true,否则为false</returns>pu ...

  9. [VC]在VC++中实现让程序只运行一个实例的方法且实现该实例

    方法一: 有时候在开发应用程序时,希望控制程序运行唯一的实例.例如,最常用的mp3播放软 件Winamp,由于它需要独占计算机中的音频设备,因此该程序只允许自身运行唯一的一个例程.在Visual C+ ...

随机推荐

  1. Javascript的字符串(String)操作学习

    1.bold() 方法用于把字符串显示为粗体.语法: stringObject.bold() 如下,对str进行bold操作之后,实际上时对这个字符串加了<b>标签,在文档中将以粗体进行展 ...

  2. luoguP4705 玩游戏 分治FFT

    \[ \begin{aligned} Ans(k) &= \sum \limits_{i = 1}^n \sum \limits_{j = 1}^m \sum \limits_{t = 0}^ ...

  3. JZYZOJ 2041 快速数论变换 NTT 多项式

    http://172.20.6.3/Problem_Show.asp?id=2041 https://blog.csdn.net/ggn_2015/article/details/68922404 代 ...

  4. 8、Redis中sort命令详解

    写在前面的话:读书破万卷,编码如有神 ------------------------------------------------- 1.排序 (1)sort:可以对List.Set.ZSet里面 ...

  5. Xtreme9.0 - Car Spark 动态规划

    Car Spark 题目连接: https://www.hackerrank.com/contests/ieeextreme-challenges/challenges/car-spark Descr ...

  6. j.u.c系列(06)---之锁条件:Condition

    写在前面 在没有Lock之前,我们使用synchronized来控制同步,配合Object的wait().notify()系列方法可以实现等待/通知模式.在Java SE5后,Java提供了Lock接 ...

  7. 让IIS支持10万并发

    适用的IIS版本:IIS 7.0, IIS 7.5, IIS 8.0 适用的Windows版本:Windows Server 2008, Windows Server 2008 R2, Windows ...

  8. How to create .gitignore file in Windows Explorer

    How to create .gitignore file I need to add some rules to my .gitignore file, however, I can't find ...

  9. spy++使用指南

    很多朋友都对窗口句柄比较迷糊,这篇短文就以spy++这个软件为主,介绍下窗体句柄和使用按键插件时,如果对这个句柄发送消息,即所谓的后台挂机.spy++这个软件来自VC++,装好VC后,就可以在工具中看 ...

  10. latex编写论文

    写给像我这样需要使用latex编写论文的小菜鸟,给出demo和注释,高级部分自己参透(默认你已经搭好环境). 1.搭论文架子 demo1 \documentclass[10pt,a4paper]{ar ...