热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

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


推荐阅读
  • 在Delphi7下要制作系统托盘,只能制作一个比较简单的系统托盘,因为ShellAPI文件定义的TNotifyIconData结构体是比较早的版本。定义如下:1234 ... [详细]
  • 本文详细解析了使用C++实现的键盘输入记录程序的源代码,该程序在Windows应用程序开发中具有很高的实用价值。键盘记录功能不仅在远程控制软件中广泛应用,还为开发者提供了强大的调试和监控工具。通过具体实例,本文深入探讨了C++键盘记录程序的设计与实现,适合需要相关技术的开发者参考。 ... [详细]
  • 本文将介绍如何在混合开发(Hybrid)应用中实现Native与HTML5的交互,包括基本概念、学习目标以及具体的实现步骤。 ... [详细]
  • VB.net 进程通信中FindWindow、FindWindowEX、SendMessage函数的理解
    目录一、代码背景二、主要工具三、函数解析1、FindWindow:2、FindWindowEx:3、SendMessage: ... [详细]
  • WinMain 函数详解及示例
    本文详细介绍了 WinMain 函数的参数及其用途,并提供了一个具体的示例代码来解析 WinMain 函数的实现。 ... [详细]
  • 开机自启动的几种方式
    0x01快速自启动目录快速启动目录自启动方式源于Windows中的一个目录,这个目录一般叫启动或者Startup。位于该目录下的PE文件会在开机后进行自启动 ... [详细]
  • 利用REM实现移动端布局的高效适配技巧
    在移动设备上实现高效布局适配时,使用rem单位已成为一种流行且有效的技术。本文将分享过去一年中使用rem进行布局适配的经验和心得。rem作为一种相对单位,能够根据根元素的字体大小动态调整,从而确保不同屏幕尺寸下的布局一致性。通过合理设置根元素的字体大小,开发者可以轻松实现响应式设计,提高用户体验。此外,文章还将探讨一些常见的问题和解决方案,帮助开发者更好地掌握这一技术。 ... [详细]
  • 在尝试对 QQmlPropertyMap 类进行测试驱动开发时,发现其派生类中无法正常调用槽函数或 Q_INVOKABLE 方法。这可能是由于 QQmlPropertyMap 的内部实现机制导致的,需要进一步研究以找到解决方案。 ... [详细]
  • 本文详细介绍了如何在PHP中记录和管理行为日志,包括ThinkPHP框架中的日志记录方法、日志的用途、实现原理以及相关配置。 ... [详细]
  • 如何高效查看Java API和源码
    在Java学习过程中,查看API文档和源码是提高编程能力的重要手段。本文将详细介绍如何使用各种工具和方法高效地查看Java API和源码。 ... [详细]
  • 我在使用 AngularJS 的路由功能开发单页应用 (SPA),但需要支持 IE7(包括 IE8 的 IE7 兼容模式)。我希望浏览器的历史记录功能能够正常工作,即使需要使用 jQuery 插件。 ... [详细]
  • [转]doc,ppt,xls文件格式转PDF格式http:blog.csdn.netlee353086articledetails7920355确实好用。需要注意的是#import ... [详细]
  • 本文详细介绍了 PHP 中对象的生命周期、内存管理和魔术方法的使用,包括对象的自动销毁、析构函数的作用以及各种魔术方法的具体应用场景。 ... [详细]
  • 【实例简介】本文详细介绍了如何在PHP中实现微信支付的退款功能,并提供了订单创建类的完整代码及调用示例。在配置过程中,需确保正确设置相关参数,特别是证书路径应根据项目实际情况进行调整。为了保证系统的安全性,存放证书的目录需要设置为可读权限。值得注意的是,普通支付操作无需证书,但在执行退款操作时必须提供证书。此外,本文还对常见的错误处理和调试技巧进行了说明,帮助开发者快速定位和解决问题。 ... [详细]
  • 如何在PHP中准确获取服务器IP地址?
    如何在PHP中准确获取服务器IP地址? ... [详细]
author-avatar
mmmmmmmmmm0000
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有