zoukankan      html  css  js  c++  java
  • delphi程序如何防止多实例启动

    1,前言

    delphi程序运行经常需要采用单实例方式,以免多个实例相互影响。那么,如何防止多实例启动呢?

    通常最为常用的是以下两种:

    • 采用mutex互斥量
    • 采用主窗口标题检测

    实践发现,无论以上哪种方式,都有坑需要避免。

    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。笔者总结以上现象,以供同行借鉴。

  • 相关阅读:
    n-1位数
    关于VC预定义常量_WIN32,WIN32,_WIN64
    python中的闭包
    TCP粘包, UDP丢包, nagle算法
    C++中 explicit的用法
    为什么mysql索引要使用B+树,而不是B树,红黑树
    屏障和屏障属性
    带有超时的读写锁
    pthread_mutex_timedlock
    段错误以及调试方式
  • 原文地址:https://www.cnblogs.com/jackkwok/p/15659950.html
Copyright © 2011-2022 走看看