【问题标题】:How to ensure only a single instance of my application runs?如何确保我的应用程序只有一个实例运行?
【发布时间】:2011-07-20 09:51:49
【问题描述】:

Delphi XE VCL 是否支持确保只有一个应用程序实例在运行?

过去,我使用库代码来控制 Mutex,这似乎总是很复杂。当我在 Delphi XE 中开始一个新项目时,我想知道我是否需要挖掘旧代码,或者是否已经内置了 XE 支持?或者是否有其他易于应用且美观且现代的代码?

【问题讨论】:

  • 是什么让您认为创建互斥锁不现代?
  • 我已经为以下跨多个用户会话工作的类型实现了实例化:TEAppSingleInstance = (siYes, siMultipleAcrossUsers, siNo)。是意味着所有用户的单个实例,不意味着每个用户可以运行多个实例,跨用户的多个意味着每个用户只能为其会话运行一个实例,但多个用户可以同时运行应用程序。

标签: delphi delphi-xe


【解决方案1】:

我就是这样做的。

closeProc(extractfilename(paramstr(0)));

function TForm1.closeProc(pname : string): integer;
const
PROCESS_TERMINATE = $0001;
var
ContinueLoop: BOOL;
FSnapshotHandle: THandle;
FProcessEntry32: TProcessEntry32;
i : integer;
pname2 : string;
begin
try
Result := 0;
i := 0;
FSnapshotHandle := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
FProcessEntry32.dwSize := SizeOf(FProcessEntry32);
ContinueLoop := Process32First(FSnapshotHandle, FProcessEntry32);
while Integer(ContinueLoop) <> 0 do
    begin
    pname2 := trim(UpperCase(ExtractFileName(FProcessEntry32.szExeFile)));
    if ( pname2 = uppercase(pname)) then
      if FProcessEntry32.th32ProcessID <> GetCurrentProcessId then
        begin
          Result := Integer(TerminateProcess(OpenProcess(PROCESS_TERMINATE, BOOL(0), FProcessEntry32.th32ProcessID), 0));
          inc(i);
        end;
    ContinueLoop := Process32Next(FSnapshotHandle, FProcessEntry32);
    if i > 50 then
      break;
    end;
CloseHandle(FSnapshotHandle);
except
end;
end;

【讨论】:

    【解决方案2】:

    您在启动应用程序时创建了一个名为 Mutex。检查GetLastError 以查看其他实例是否已在运行。

    将此代码放在 DPR 文件中的“开始”之后。将 GUID 替换为您自己的 GUID。当我需要一个不太可能用于其他任何内容的文本常量时,我​​通常只需按 Ctrl+G 即可获得 GUID!

    if CreateMutex(nil, True, '6EACD0BF-F3E0-44D9-91E7-47467B5A2B6A') = 0 then
      RaiseLastOSError;
    
    if GetLastError = ERROR_ALREADY_EXISTS then
      Exit;
    

    看起来代码泄漏了句柄,因为它没有保存CreateMutex 的返回值。它不是。当我们的应用程序终止时,Windows 会自动释放句柄,这对我们来说绝对没问题。

    【讨论】:

    • 您不需要对两行 Windows API 的特定 Delphi XE 支持。确保将 WindowsSysUtils 添加到 DPR 的使用子句中。
    • 这将在会话命名空间中创建互斥锁。不同会话中的进程(想想快速用户切换)将能够在另一个会话中的进程运行时启动一个新进程。您可以使用 Global\ 作为名称的前缀来获取全局命名空间中的互斥锁。
    • 好点大卫。然而,也许这种行为(会话命名空间)可能是一些开发人员真正想要的,即使他们没有考虑过。想象一下,您想部署一个可以使用 Windows 终端服务运行的富数据库客户端应用程序,您可能每个桌面一个应用程序而不是每台计算机一个应用程序。
    • 更简单的例子:想象一下你为你的下一个大聊天程序实现了这个;妻子来到电脑前,实际上做了“切换用户”(我妻子做了!)并登录到她的帐户,尝试启动下一个大聊天程序。哎呀!无论如何,大卫,好点子,无论如何,每个人都应该阅读文档。
    • +1 用于直接访问 VCL 和 Win API 而不是 JCL。 JCL 没有错,但为什么在不需要的时候使用外部工具呢?我们多年来一直在我们的商店中使用此解决方案,没有出现任何问题。至于不同的用户,正如您所提到的,通常这就是您想要的 - 不同的用户应该获得不同的会话/实例。
    【解决方案3】:

    我使用 JCL 来做到这一点:

    program MyProgram;
    
    uses
      JclAppInst;
    
    begin
      JclAppInstances.CheckSingleInstance; // Added instance checking
      Application.Initialize;
      Application.CreateForm(TMainForm, MainForm);
      Application.Run;
    end.
    

    这方面的文档和通知方案位于the JCL Wiki

    【讨论】:

    • +1 用于使用 JCL。经过测试,有朝一日,它甚至可以移植到不同的平台。
    • 谢谢 - 这也有通知。不是在 VCL 中,而是下一个最好的东西。
    猜你喜欢
    • 2012-05-17
    • 2010-09-27
    • 2010-09-28
    • 2013-03-01
    • 2011-05-10
    相关资源
    最近更新 更多