在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
1,前言delphi程序运行经常需要采用单实例方式,以免多个实例相互影响。那么,如何防止多实例启动呢? 通常最为常用的是以下两种:
实践发现,无论以上哪种方式,都有坑需要避免。 2,互斥量检测互斥量检测法,是在delphi程序启动时,创建某个唯一标识的互斥量,如果创建返回的结果是“互斥量已存在”,那么就说明windows系统内存中已经运行了该程序,此时程序退出,就实现了单例运行。 伪代码如下: program RPMClient; uses Forms, dialogs, Ufunc in 'Ufunc.pas', Umain in 'uMain.pas' {fMain}; {$R *.res} begin Application.Initialize; if AppIsRunning then begin //showMessage('程序已经启动,请勿重复启动!'); application.Terminate; exit; end; Application.CreateForm(TfMain, fMain); Application.Run; end.
其中的函数AppIsRunning 是关键,实现代码如下: function AppIsRunning: Boolean; var hmutex:hwnd; errno:integer; begin Result := False; hmutex:=createmutex(nil,false,pchar('RPMClient')); errno:=getlasterror; if errno=error_already_exists then begin Result := True; end; end;
显然,以上代码非常常规,没有亮点。但是,如果不注意却可能留下隐患。 注意其中的createmutex函数的第三个参数,采用的是pchar('RPMClient'),一个指向字符串常量的指针。 如果将其改为指向变量的指针,则无法实现单例控制。如下述代码,采用Application.Title代替字符串常量,写法上似乎优雅一点,但是实践发现内存中会出现多实例。
hmutex:=createmutex(nil,false,pchar(Application.Title));
3,主窗口标题检测笔者也采用过FindWindow函数执行主窗口标题检测,来避免多实例启动。写法上,类似下面: function AppIsRunning: Boolean; var hWnd : THandle; begin hWnd:=FindWindow(nil,PChar('RPMClient'));//搜索窗口 API 在windows单元 Result := hWnd<>0; end;
该方法也很常规,在windows 7下运行正常,但是实践发现,在windows10操作系统中,内存中会出现多个实例。 4,总结最终,笔者采用了createmutex函数执行单例控制,注意第三个参数采用字符串常量即可。在windows7和10下,均正常。 为什么FindWindow在win10下不能正常检测呢?笔者不明白,猜测有可能是win10有时会把应用变为后台进程的缘故。 至于createmutex为什么第三个参数不能是变量指针,笔者也不明白,猜测有可能是变量指针比常量指针更耗时,导致启动时来不及控制?
总之,单例控制方法多且简单,但是如何使用还是有不少具体细节的,稍不注意就出现bug。笔者总结以上现象,以供同行借鉴。 |
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论