Art*_*hur 29 delphi persistence mutex semaphore instance
如何判断我的程序的一个实例是否正在运行?我以为我可以用数据文件做这个但它只是凌乱:(
我想这样做,因为我只希望一个实例在一个点上打开.
Rob*_*edy 39
正如Jon首先建议的那样,您可以尝试创建互斥锁.打电话CreateMutex.如果你得到一个非空句柄,那么调用GetLastError.它会告诉您是否是创建互斥锁的人或者互斥锁是否已经在(Error_Already_Exists)之前打开.请注意,没有必要获取互斥锁的所有权.互斥锁不会用于互斥.它正在被使用,因为它是一个命名的内核对象.事件或信号量也可以起作用.
互斥技术为您提供了一个布尔答案:是的,有另一个实例,或者没有,没有.
你经常想知道更多.例如,您可能想知道另一个实例的主窗口的句柄,这样您就可以告诉它来到前台代替您的其他实例.这就是内存映射文件可以派上用场的地方; 它可以保存有关第一个实例的信息,以便后面的实例可以引用它.
选择互斥锁的名称时要小心.请仔细阅读文档,并记住某些操作系统版本中不允许使用某些字符(如反斜杠),但其他操作系统版本中的某些功能则需要这些字符.
还要记住其他用户的问题.如果您的程序可以通过远程桌面或快速用户切换运行,那么可能有其他用户已在运行您的程序,您可能不想限制当前用户运行您的程序.在这种情况下,请勿使用全局名称.如果您确实要限制所有用户的访问权限,请确保互斥对象的安全属性使每个人都能够打开它的句柄.对lpSecurityAttributes参数使用空指针是不够的; MSDN提到的"默认安全描述符"提供对当前用户的完全访问权限,不允许访问其他用户.
您可以编辑程序的DPR文件.这通常是做这种事情的好地方.如果你等到OnCreate其中一个表单的事件,那么你的程序已经有一些正常运行的动力,所以在那时尝试终止程序是笨拙的.最好在UI工作太多之前终止.例如:
var
mutex: THandle;
mutexName: string;
begin
mutexName := ConstructMutexName();
mutex := CreateMutex(nil, False, PChar(mutexName));
if mutex = 0 then
RaiseLastOSError; // Couldn't open handle at all.
if GetLastError = Error_Already_Exists then begin
// We are not the first instance.
SendDataToPreviousInstance(...);
exit;
end;
// We are the first instance.
// Do NOT close the mutex handle here. It must
// remain open for the duration of your program,
// or else later instances won't be able to
// detect this instance.
Application.Initialize;
Application.CreateForm(...);
Application.Run;
end.
Run Code Online (Sandbox Code Playgroud)
有关何时关闭互斥锁手柄的问题.你不必关闭它.当您的进程最终终止时(即使它崩溃),操作系统将自动关闭任何未完成的句柄,当没有更多句柄打开时,互斥对象将被销毁(从而允许程序的另一个实例启动并考虑自己是第一个).
但是你可能想要关闭手柄.假设您选择实现SendDataToPreviousInstance我在代码中提到的功能.如果你想获得花哨,那么你可以解释前一个实例已经关闭并且无法接受新数据的情况.那么你真的不想关闭第二个实例.第一个实例可以在知道它正在关闭时关闭互斥锁句柄,实际上变成了"跛脚鸭"实例.第二个实例将尝试创建互斥锁句柄,成功,并认为自己是真正的第一个实例.前一个实例将不间断地关闭.使用CloseHandle关闭互斥; 例如,从主表单的OnClose事件处理程序或您调用的任何其他地方调用它Application.Terminate.
Dre*_*ejc 18
您可以创建信号量并停止执行(将代码放入*.dpr文件)并将运行的应用程序带到屏幕上.
var
Semafor: THandle;
begin
{ Don't start twice ... if already running bring this instance to front }
Semafor := CreateSemaphore(nil, 0, 1, 'MY_APPLICATION_IS_RUNNING');
if ((Semafor <> 0) and { application is already running }
(GetLastError = ERROR_ALREADY_EXISTS)) then
begin
RestoreWindow('TMyApplication');
CloseHandle(Semafor);
Halt;
end;
Application.CreateForm(....);
Application.Initialize;
Application.Run;
CloseHandle(Semafor);
end;
Run Code Online (Sandbox Code Playgroud)
编辑(添加RestoreWindow方法):
这aFormName是您的应用程序中的主窗体类的名称.
procedure RestoreWindow(aFormName: string);
var
Wnd,
App: HWND;
begin
Wnd := FindWindow(PChar(aFormName), nil);
if (Wnd <> 0) then
begin { Set Window to foreground }
App := GetWindowLong(Wnd, GWL_HWNDPARENT);
if IsIconic(App) then
ShowWindow(App, SW_RESTORE);
SetForegroundwindow(App);
end;
end;
Run Code Online (Sandbox Code Playgroud)
您创建一个系统 互斥锁.
我没有Delphi代码,但这里是C++代码:
HANDLE Mutex;
const char MutexName[] = "MyUniqueProgramName";
Mutex = OpenMutex(MUTEX_ALL_ACCESS, false, MutexName);
if (Mutex)
throw Exception("Program is already running.");
else
Mutex = CreateMutex(NULL, true, MutexName);
Run Code Online (Sandbox Code Playgroud)
通常的解决方案是创建一个命名的系统范围的 互斥锁.
我没有提供代码,因为我不知道Delphi.我可以提供C#代码,如果这会有所帮助.