How do i tell if one instance of my program is running? I thought I could do this with a data file but it would just be messy :(
我如何判断我的程序的一个实例是否正在运行?我以为我可以用数据文件来做这件事,但它只会是凌乱的:(
I want to do this as I only want 1 instance to ever be open at one point.
我想这样做,因为我只希望一个实例在一个点上打开。
12 个解决方案
#1
You can create a Semaphore and stop execution (put the code into your *.dpr file) and bring you running application to the screen.
您可以创建一个信号量并停止执行(将代码放入* .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;
EDIT (added the RestoreWindow
method):
编辑(添加了RestoreWindow方法):
The aFormName
is the name of your main form class in your application.
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;
#2
As Jon first suggested, you can try creating a mutex. Call CreateMutex
. If you get a non-null handle back, then call GetLastError
. It will tell you whether you were the one who created the mutex or whether the mutex was already open before (Error_Already_Exists
). Note that it is not necessary to acquire ownership of the mutex. The mutex is not being used for mutual exclusion. It's being used because it is a named kernel object. An event or semaphore could work, too.
正如Jon首先建议的那样,您可以尝试创建互斥锁。调用CreateMutex。如果返回非空句柄,则调用GetLastError。它会告诉您是否是创建互斥锁的人或者互斥锁之前是否已打开(Error_Already_Exists)。请注意,没有必要获取互斥锁的所有权。互斥锁不会用于互斥。它正在被使用,因为它是一个命名的内核对象。事件或信号量也可以起作用。
The mutex technique gives you a Boolean answer: Yes, there is another instance, or no, there is not.
互斥技术为您提供了一个布尔答案:是的,有另一个实例,或者没有,没有。
You frequently want to know more than just that. For instance, you might want to know the handle of the other instance's main window so you can tell it to come to the foreground in place of your other instance. That's where a memory-mapped file can come in handy; it can hold information about the first instance so later instances can refer to it.
你经常想知道更多。例如,您可能想知道另一个实例的主窗口的句柄,这样您就可以告诉它来到前台代替您的其他实例。这就是内存映射文件可以派上用场的地方;它可以保存有关第一个实例的信息,以便后面的实例可以引用它。
Be careful when choosing the name of the mutex. Read the documentation carefully, and keep in mind that some characters (such as backslash) are not allowed in some OS versions, but are required for certain features in other OS versions.
选择互斥锁的名称时要小心。请仔细阅读文档,并记住某些操作系统版本中不允许使用某些字符(如反斜杠),但其他操作系统版本中的某些功能则需要这些字符。
Also remember the problem of other users. If your program could be run via remote desktop or fast user switching, then there could be other users already running your program, and you might not really want to restrict the current user from running your program. In that case, don't use a global name. If you do want to restrict access for all users, then make sure the mutex object's security attributes are such that everyone will be able to open a handle to it. Using a null pointer for the lpSecurityAttributes
parameter is not sufficient for that; the "default security descriptor" that MSDN mentions gives full access to the current user and no access to others.
还要记住其他用户的问题。如果您的程序可以通过远程桌面或快速用户切换运行,那么可能有其他用户已在运行您的程序,您可能不想限制当前用户运行您的程序。在这种情况下,请勿使用全局名称。如果您确实要限制所有用户的访问权限,请确保互斥对象的安全属性使每个人都能够打开它的句柄。对lpSecurityAttributes参数使用空指针是不够的; MSDN提到的“默认安全描述符”提供对当前用户的完全访问权限,不允许访问其他用户。
You're allowed to edit the DPR file of your program. That's usually a good place to do this kind of thing. If you wait until the OnCreate
event of one of your forms, then your program already has a bit of momentum toward running normally, so it's clumsy to try to terminate the program at that point. Better to terminate before too much UI work has been done. For example:
您可以编辑程序的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.
There's a question of when to close the mutex handle. You don't have to close it. When your process finally terminates (even if it crashes), the OS will automatically close any outstanding handles, and when there are no more handles open, the mutex object will be destroyed (thus allowing another instance of your program to start and consider itself to be the first instance).
有关何时关闭互斥锁手柄的问题。你不必关闭它。当您的进程最终终止时(即使它崩溃),操作系统将自动关闭任何未完成的句柄,当没有更多句柄打开时,互斥对象将被销毁(从而允许程序的另一个实例启动并考虑自己是第一个)。
But you might want to close the handle anyway. Suppose you chose to implement the SendDataToPreviousInstance
function I mentioned in the code. If you want to get fancy, then you could account for the case that the previous instance is already shutting down and is unable to accept new data. Then you won't really want to close the second instance. The first instance could close the mutex handle as soon as it knows it's shutting down, in effect becoming a "lame duck" instance. The second instance will try to create the mutex handle, succeed, and consider itself the real first instance. The previous instance will close uninterrupted. Use CloseHandle
to close the mutex; call it from your main form's OnClose
event handler, or wherever else you call Application.Terminate
, for example.
但无论如何你可能想要关闭手柄。假设您选择实现我在代码中提到的SendDataToPreviousInstance函数。如果你想得到想象,那么你可以解释前一个实例已经关闭并且无法接受新数据的情况。那么你真的不想关闭第二个实例。第一个实例可以在知道它正在关闭时立即关闭互斥锁句柄,实际上变成了“跛脚鸭”实例。第二个实例将尝试创建互斥锁句柄,成功,并认为自己是真正的第一个实例。前一个实例将不间断地关闭。使用CloseHandle关闭互斥锁;例如,从主窗体的OnClose事件处理程序或您调用Application.Terminate的任何其他位置调用它。
#3
The all-mighty JVCL has a component for this purpose. See "TJvAppInstances".
强大的JVCL有一个用于此目的的组件。请参阅“TJvAppInstances”。
#4
You create a system mutex.
您创建一个系统互斥锁。
I don't have Delphi code, but here's C++ code:
我没有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);
#5
The normal solution is to create a named, system-wide mutex.
通常的解决方案是创建一个命名的系统范围的互斥锁。
- If you manage to create it, you're the one running application.
- If you don't, you know there's a different one.
如果您设法创建它,那么您就是正在运行的应用程序。
如果你不这样做,你知道有一个不同的。
EDIT:
I haven't provided code as I don't know Delphi. I can provide C# code if that would be helpful though.
我没有提供代码,因为我不知道Delphi。我可以提供C#代码,如果这会有所帮助。
#6
I'd like to add one point to the excellent answer by Rob Kennedy (apart from the fact that it would be best to make a function out of his code instead of copying everything into the DPR file. You only need two parameters, the name of the mutex, and a boolean whether the mutext should be per-user or system-wide).
我想为Rob Kennedy的优秀答案添加一点(除了最好是从他的代码中创建一个函数而不是将所有内容复制到DPR文件中。你只需要两个参数,名称互斥体和布尔值是否应该是按用户或系统范围的布尔值。
The answer does not give much consideration to the naming of the mutex. If you expect your program to be installed via Inno Setup (and maybe other setup tools too) you should choose the name carefully, as the mutex can be used to have the setup program check whether the application is currently running, and alert the user that they should close all instances of the application. If you choose to allow one instance of the program per user you may need to create a second system-wide mutex too, as the setup may need to have no running instances of the application at all in order to be able to replace files. The name that is to be used for synchronization with an InnoSetup installer must be hard-coded.
答案并未充分考虑互斥锁的命名。如果您希望通过Inno Setup(也可能是其他设置工具)安装您的程序,您应该仔细选择名称,因为可以使用互斥锁让安装程序检查应用程序当前是否正在运行,并提醒用户他们应该关闭应用程序的所有实例。如果您选择允许每个用户使用一个程序实例,则可能还需要创建第二个系统范围的互斥锁,因为设置可能需要根本没有应用程序的运行实例才能替换文件。用于与InnoSetup安装程序同步的名称必须是硬编码的。
#7
I would say that there are several different strategies that you can employ. But the easiest one (and not platform specific) is the one you yourself suggested, namely to, at the start of the program check to see if there is a lock file created in a set, specific location. If this lock file exists, then another instance is already running, if it doesn't exist, then there is not another instance running. When your program exits, you delete the lock file.
我想说你可以采用几种不同的策略。但最简单的(而不是平台特定的)是你自己建议的那个,即在程序开始时检查是否在一个特定的位置创建了一个锁文件。如果此锁定文件存在,则另一个实例已在运行,如果它不存在,则不会运行另一个实例。程序退出时,删除锁定文件。
However, employing this strategy you have another problem, what happens if your program crashes? The lock file still remains, and this specific case need to be handled.
但是,使用此策略还有另一个问题,如果程序崩溃会发生什么?锁定文件仍然存在,需要处理此特定情况。
Another strategy is the system-wide mutex solution, where you register your presence within the operating system (or it's also plausible that this is done automagically). When a second instance then tries to start, it checks if there's already a process active with a specific ID. If it already exists, the second process chooses not to start, and optionally brings the first process' window in focus (if the process in question owns a window that is).
另一种策略是系统范围的互斥解决方案,您可以在操作系统中注册您的存在(或者也可以自动完成此操作)。当第二个实例尝试启动时,它会检查是否已有一个具有特定ID的进程处于活动状态。如果它已经存在,则第二个进程选择不启动,并且可选地使第一个进程的窗口处于焦点(如果有问题的进程拥有一个窗口)。
However, this strategy is platform specific, and the implementation will differ from platform to platform.
但是,此策略是特定于平台的,并且实现将因平台而异。
#8
You can simply use FindWindow windows api function. In delphi class name of the window is the same as class name, you can redefine class name by overriding CreateParams function. To check if window exists add code before main window is created , before Application.Initialize;
您可以简单地使用FindWindow windows api函数。在delphi类窗口的名称与类名相同,您可以通过重写CreateParams函数重新定义类名。要检查窗口是否存在,请在Application.Initialize之前在创建主窗口之前添加代码;
Program test
var
handle :HWND;
begin
handle := FindWindow('TMySuperApp', nil);
if IsWindow(handle) then
begin
//app is running
exit;
end.
Application.Initialize;
Application.CreateForm(TMySuperApp, SuperApp);
Application.Run;
end;
#9
Controlling the number of application instances:
控制应用程序实例的数量:
#10
See this unit (using CreateMutex): UiApp
查看本单元(使用CreateMutex):UiApp
Additionally at this page, you can read the advantages and disadvantages for to this work with differents methods (mutex, FindWindows,...).
此外,在此页面中,您可以使用不同的方法(mutex,FindWindows,...)了解此工作的优缺点。
This unit have the solution to activate the previos instance of the application when this is detected.
当检测到该单元时,该单元具有激活应用程序的previos实例的解决方案。
Regards and excuse-me for my bad english.
对我糟糕的英语问候并原谅我。
Neftalí -Germán Estévez-
Neftalí-GermánEstévez-
#11
If You want to stop execution your app more then once in the same time (put the code into *.dpr file of the project). will show a message after second app will be running and stop it instantly .
如果您想要在同一时间停止执行您的应用程序(将代码放入项目的* .dpr文件中)。将在第二个应用程序运行后显示一条消息并立即停止。
Forms,
Unit1 in 'Unit1.pas' {Form1},
// add this units ....
TlHelp32,SysUtils,Windows,Dialogs;
{$R *.res}
function ProcessCount(const ExeName: String): Integer;
var
ContinueLoop: BOOL;
FSnapshotHandle: THandle;
FProcessEntry32: TProcessEntry32;
begin
FSnapshotHandle:= CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
FProcessEntry32.dwSize:= SizeOf(FProcessEntry32);
ContinueLoop:= Process32First(FSnapshotHandle, FProcessEntry32);
Result:= 0;
while Integer(ContinueLoop) <> 0 do begin
if ((UpperCase(ExtractFileName(FProcessEntry32.szExeFile)) =
UpperCase(ExeName)) or (UpperCase(FProcessEntry32.szExeFile) =
UpperCase(ExeName))) then Inc(Result);
ContinueLoop:= Process32Next(FSnapshotHandle, FProcessEntry32);
end;
CloseHandle(FSnapshotHandle);
end;
begin
if ProcessCount(ExtractFileName(Application.ExeName)) > 1 then begin
MessageDlg('Application is already running!', mtError, [mbOK], 0);
Application.Terminate;
end else begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end;
end.
#12
In the past, I've used a socket to prevent multiple instances from running at the same time. If the socket is in use, don't continue the program, if it's available let everything run as normal.
在过去,我使用套接字来防止多个实例同时运行。如果套接字正在使用中,请不要继续该程序,如果它可用则让一切正常运行。
#1
You can create a Semaphore and stop execution (put the code into your *.dpr file) and bring you running application to the screen.
您可以创建一个信号量并停止执行(将代码放入* .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;
EDIT (added the RestoreWindow
method):
编辑(添加了RestoreWindow方法):
The aFormName
is the name of your main form class in your application.
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;
#2
As Jon first suggested, you can try creating a mutex. Call CreateMutex
. If you get a non-null handle back, then call GetLastError
. It will tell you whether you were the one who created the mutex or whether the mutex was already open before (Error_Already_Exists
). Note that it is not necessary to acquire ownership of the mutex. The mutex is not being used for mutual exclusion. It's being used because it is a named kernel object. An event or semaphore could work, too.
正如Jon首先建议的那样,您可以尝试创建互斥锁。调用CreateMutex。如果返回非空句柄,则调用GetLastError。它会告诉您是否是创建互斥锁的人或者互斥锁之前是否已打开(Error_Already_Exists)。请注意,没有必要获取互斥锁的所有权。互斥锁不会用于互斥。它正在被使用,因为它是一个命名的内核对象。事件或信号量也可以起作用。
The mutex technique gives you a Boolean answer: Yes, there is another instance, or no, there is not.
互斥技术为您提供了一个布尔答案:是的,有另一个实例,或者没有,没有。
You frequently want to know more than just that. For instance, you might want to know the handle of the other instance's main window so you can tell it to come to the foreground in place of your other instance. That's where a memory-mapped file can come in handy; it can hold information about the first instance so later instances can refer to it.
你经常想知道更多。例如,您可能想知道另一个实例的主窗口的句柄,这样您就可以告诉它来到前台代替您的其他实例。这就是内存映射文件可以派上用场的地方;它可以保存有关第一个实例的信息,以便后面的实例可以引用它。
Be careful when choosing the name of the mutex. Read the documentation carefully, and keep in mind that some characters (such as backslash) are not allowed in some OS versions, but are required for certain features in other OS versions.
选择互斥锁的名称时要小心。请仔细阅读文档,并记住某些操作系统版本中不允许使用某些字符(如反斜杠),但其他操作系统版本中的某些功能则需要这些字符。
Also remember the problem of other users. If your program could be run via remote desktop or fast user switching, then there could be other users already running your program, and you might not really want to restrict the current user from running your program. In that case, don't use a global name. If you do want to restrict access for all users, then make sure the mutex object's security attributes are such that everyone will be able to open a handle to it. Using a null pointer for the lpSecurityAttributes
parameter is not sufficient for that; the "default security descriptor" that MSDN mentions gives full access to the current user and no access to others.
还要记住其他用户的问题。如果您的程序可以通过远程桌面或快速用户切换运行,那么可能有其他用户已在运行您的程序,您可能不想限制当前用户运行您的程序。在这种情况下,请勿使用全局名称。如果您确实要限制所有用户的访问权限,请确保互斥对象的安全属性使每个人都能够打开它的句柄。对lpSecurityAttributes参数使用空指针是不够的; MSDN提到的“默认安全描述符”提供对当前用户的完全访问权限,不允许访问其他用户。
You're allowed to edit the DPR file of your program. That's usually a good place to do this kind of thing. If you wait until the OnCreate
event of one of your forms, then your program already has a bit of momentum toward running normally, so it's clumsy to try to terminate the program at that point. Better to terminate before too much UI work has been done. For example:
您可以编辑程序的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.
There's a question of when to close the mutex handle. You don't have to close it. When your process finally terminates (even if it crashes), the OS will automatically close any outstanding handles, and when there are no more handles open, the mutex object will be destroyed (thus allowing another instance of your program to start and consider itself to be the first instance).
有关何时关闭互斥锁手柄的问题。你不必关闭它。当您的进程最终终止时(即使它崩溃),操作系统将自动关闭任何未完成的句柄,当没有更多句柄打开时,互斥对象将被销毁(从而允许程序的另一个实例启动并考虑自己是第一个)。
But you might want to close the handle anyway. Suppose you chose to implement the SendDataToPreviousInstance
function I mentioned in the code. If you want to get fancy, then you could account for the case that the previous instance is already shutting down and is unable to accept new data. Then you won't really want to close the second instance. The first instance could close the mutex handle as soon as it knows it's shutting down, in effect becoming a "lame duck" instance. The second instance will try to create the mutex handle, succeed, and consider itself the real first instance. The previous instance will close uninterrupted. Use CloseHandle
to close the mutex; call it from your main form's OnClose
event handler, or wherever else you call Application.Terminate
, for example.
但无论如何你可能想要关闭手柄。假设您选择实现我在代码中提到的SendDataToPreviousInstance函数。如果你想得到想象,那么你可以解释前一个实例已经关闭并且无法接受新数据的情况。那么你真的不想关闭第二个实例。第一个实例可以在知道它正在关闭时立即关闭互斥锁句柄,实际上变成了“跛脚鸭”实例。第二个实例将尝试创建互斥锁句柄,成功,并认为自己是真正的第一个实例。前一个实例将不间断地关闭。使用CloseHandle关闭互斥锁;例如,从主窗体的OnClose事件处理程序或您调用Application.Terminate的任何其他位置调用它。
#3
The all-mighty JVCL has a component for this purpose. See "TJvAppInstances".
强大的JVCL有一个用于此目的的组件。请参阅“TJvAppInstances”。
#4
You create a system mutex.
您创建一个系统互斥锁。
I don't have Delphi code, but here's C++ code:
我没有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);
#5
The normal solution is to create a named, system-wide mutex.
通常的解决方案是创建一个命名的系统范围的互斥锁。
- If you manage to create it, you're the one running application.
- If you don't, you know there's a different one.
如果您设法创建它,那么您就是正在运行的应用程序。
如果你不这样做,你知道有一个不同的。
EDIT:
I haven't provided code as I don't know Delphi. I can provide C# code if that would be helpful though.
我没有提供代码,因为我不知道Delphi。我可以提供C#代码,如果这会有所帮助。
#6
I'd like to add one point to the excellent answer by Rob Kennedy (apart from the fact that it would be best to make a function out of his code instead of copying everything into the DPR file. You only need two parameters, the name of the mutex, and a boolean whether the mutext should be per-user or system-wide).
我想为Rob Kennedy的优秀答案添加一点(除了最好是从他的代码中创建一个函数而不是将所有内容复制到DPR文件中。你只需要两个参数,名称互斥体和布尔值是否应该是按用户或系统范围的布尔值。
The answer does not give much consideration to the naming of the mutex. If you expect your program to be installed via Inno Setup (and maybe other setup tools too) you should choose the name carefully, as the mutex can be used to have the setup program check whether the application is currently running, and alert the user that they should close all instances of the application. If you choose to allow one instance of the program per user you may need to create a second system-wide mutex too, as the setup may need to have no running instances of the application at all in order to be able to replace files. The name that is to be used for synchronization with an InnoSetup installer must be hard-coded.
答案并未充分考虑互斥锁的命名。如果您希望通过Inno Setup(也可能是其他设置工具)安装您的程序,您应该仔细选择名称,因为可以使用互斥锁让安装程序检查应用程序当前是否正在运行,并提醒用户他们应该关闭应用程序的所有实例。如果您选择允许每个用户使用一个程序实例,则可能还需要创建第二个系统范围的互斥锁,因为设置可能需要根本没有应用程序的运行实例才能替换文件。用于与InnoSetup安装程序同步的名称必须是硬编码的。
#7
I would say that there are several different strategies that you can employ. But the easiest one (and not platform specific) is the one you yourself suggested, namely to, at the start of the program check to see if there is a lock file created in a set, specific location. If this lock file exists, then another instance is already running, if it doesn't exist, then there is not another instance running. When your program exits, you delete the lock file.
我想说你可以采用几种不同的策略。但最简单的(而不是平台特定的)是你自己建议的那个,即在程序开始时检查是否在一个特定的位置创建了一个锁文件。如果此锁定文件存在,则另一个实例已在运行,如果它不存在,则不会运行另一个实例。程序退出时,删除锁定文件。
However, employing this strategy you have another problem, what happens if your program crashes? The lock file still remains, and this specific case need to be handled.
但是,使用此策略还有另一个问题,如果程序崩溃会发生什么?锁定文件仍然存在,需要处理此特定情况。
Another strategy is the system-wide mutex solution, where you register your presence within the operating system (or it's also plausible that this is done automagically). When a second instance then tries to start, it checks if there's already a process active with a specific ID. If it already exists, the second process chooses not to start, and optionally brings the first process' window in focus (if the process in question owns a window that is).
另一种策略是系统范围的互斥解决方案,您可以在操作系统中注册您的存在(或者也可以自动完成此操作)。当第二个实例尝试启动时,它会检查是否已有一个具有特定ID的进程处于活动状态。如果它已经存在,则第二个进程选择不启动,并且可选地使第一个进程的窗口处于焦点(如果有问题的进程拥有一个窗口)。
However, this strategy is platform specific, and the implementation will differ from platform to platform.
但是,此策略是特定于平台的,并且实现将因平台而异。
#8
You can simply use FindWindow windows api function. In delphi class name of the window is the same as class name, you can redefine class name by overriding CreateParams function. To check if window exists add code before main window is created , before Application.Initialize;
您可以简单地使用FindWindow windows api函数。在delphi类窗口的名称与类名相同,您可以通过重写CreateParams函数重新定义类名。要检查窗口是否存在,请在Application.Initialize之前在创建主窗口之前添加代码;
Program test
var
handle :HWND;
begin
handle := FindWindow('TMySuperApp', nil);
if IsWindow(handle) then
begin
//app is running
exit;
end.
Application.Initialize;
Application.CreateForm(TMySuperApp, SuperApp);
Application.Run;
end;
#9
Controlling the number of application instances:
控制应用程序实例的数量:
#10
See this unit (using CreateMutex): UiApp
查看本单元(使用CreateMutex):UiApp
Additionally at this page, you can read the advantages and disadvantages for to this work with differents methods (mutex, FindWindows,...).
此外,在此页面中,您可以使用不同的方法(mutex,FindWindows,...)了解此工作的优缺点。
This unit have the solution to activate the previos instance of the application when this is detected.
当检测到该单元时,该单元具有激活应用程序的previos实例的解决方案。
Regards and excuse-me for my bad english.
对我糟糕的英语问候并原谅我。
Neftalí -Germán Estévez-
Neftalí-GermánEstévez-
#11
If You want to stop execution your app more then once in the same time (put the code into *.dpr file of the project). will show a message after second app will be running and stop it instantly .
如果您想要在同一时间停止执行您的应用程序(将代码放入项目的* .dpr文件中)。将在第二个应用程序运行后显示一条消息并立即停止。
Forms,
Unit1 in 'Unit1.pas' {Form1},
// add this units ....
TlHelp32,SysUtils,Windows,Dialogs;
{$R *.res}
function ProcessCount(const ExeName: String): Integer;
var
ContinueLoop: BOOL;
FSnapshotHandle: THandle;
FProcessEntry32: TProcessEntry32;
begin
FSnapshotHandle:= CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
FProcessEntry32.dwSize:= SizeOf(FProcessEntry32);
ContinueLoop:= Process32First(FSnapshotHandle, FProcessEntry32);
Result:= 0;
while Integer(ContinueLoop) <> 0 do begin
if ((UpperCase(ExtractFileName(FProcessEntry32.szExeFile)) =
UpperCase(ExeName)) or (UpperCase(FProcessEntry32.szExeFile) =
UpperCase(ExeName))) then Inc(Result);
ContinueLoop:= Process32Next(FSnapshotHandle, FProcessEntry32);
end;
CloseHandle(FSnapshotHandle);
end;
begin
if ProcessCount(ExtractFileName(Application.ExeName)) > 1 then begin
MessageDlg('Application is already running!', mtError, [mbOK], 0);
Application.Terminate;
end else begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end;
end.
#12
In the past, I've used a socket to prevent multiple instances from running at the same time. If the socket is in use, don't continue the program, if it's available let everything run as normal.
在过去,我使用套接字来防止多个实例同时运行。如果套接字正在使用中,请不要继续该程序,如果它可用则让一切正常运行。