如何确保我的应用程序只有一个实例运行?
Posted
技术标签:
【中文标题】如何确保我的应用程序只有一个实例运行?【英文标题】: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)。是意味着所有用户的单个实例,不意味着每个用户可以运行多个实例,跨用户的多个意味着每个用户只能为其会话运行一个实例,但多个用户可以同时运行应用程序。 How can I tell if another instance of my program is already running?的可能重复 【参考方案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
支持。确保将 Windows
和 SysUtils
添加到 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 中,而是下一个最好的东西。以上是关于如何确保我的应用程序只有一个实例运行?的主要内容,如果未能解决你的问题,请参考以下文章
如何确保所有实例在 Elastic Beanstalk 应用程序中运行相同的版本?