以编程方式重新启动 Delphi 应用程序
应该不可能运行我的应用程序的多个实例。因此,项目源包含:
CreateMutex (nil, False, PChar (ID));
if (GetLastError = ERROR_ALREADY_EXISTS) then
Halt;
现在我想以编程方式重新启动我的应用程序。通常的方法是:
AppName := PChar(Application.ExeName) ;
ShellExecute(Handle,'open', AppName, nil, nil, SW_SHOWNORMAL) ;
Application.Terminate;
但由于互斥体的原因,这在我的情况下不起作用。即使我在启动第二个实例之前释放互斥体,它也不会工作,因为关闭需要一些时间并且两个实例无法并行运行(由于公共资源和其他影响)。
有没有办法重新启动具有此类特性的应用程序? (如果可能,无需额外的可执行文件)
提前致谢。
It should not be possible to run multiple instances of my application. Therefore the project source contains:
CreateMutex (nil, False, PChar (ID));
if (GetLastError = ERROR_ALREADY_EXISTS) then
Halt;
Now I want to restart my application programmatically. The usual way would be:
AppName := PChar(Application.ExeName) ;
ShellExecute(Handle,'open', AppName, nil, nil, SW_SHOWNORMAL) ;
Application.Terminate;
But this won't work in my case because of the mutex. Even if I release the mutex before starting the second instace it won't work because shutdown takes some time and two instance cannot run in parallel (because of common resources and other effects).
Is there a way to restart an application with such characteristics? (If possible without an additional executable)
Thanks in advance.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
也许你应该跳出框框思考。您可以简单地创建另一个可执行文件来等待您的应用程序关闭然后再次启动它,而不是使用互斥体/实例逻辑。作为额外的好处,您可以稍后使用此机制来更新某些主应用程序的二进制文件。提升运行速度也比在同一应用程序内维护不同的完整性级别等要容易得多。
Perhaps you should think outside the box. Instead of futzing with the mutex / instance logic, you could simply create another executable that waits for your app to close then starts it again. As an added bonus, you can later use this mechanism to, for example, update some of your main app's binaries. It's also much easier to run it elevated instead of maintaining different integrity levels inside the same app, etc.
为什么不能在尝试重新启动之前释放互斥体?如果有某种可能性,另一个实例在您通过重新启动显式调用的实例之前开始运行,这无关紧要,您仍然可以让您的应用程序重新启动并运行,无论影响需要重新启动的任何更改。我认为您不需要其他解决方案的任何复杂性。
Why can't you just release the mutex before attempting to restart? If by some chance another instance gets going before the one you explicitly invoke with the restart that doesn't matter, you'll still have your app up and running again with whatever changes effected that required the restart. I don't think you need any of the complexity of the other solutions.
在 ShellExecute 中包含一些参数(例如 /WaitForShutDown)并再创建一个互斥体。在您的程序中,在初始化之前,例如在其 .dpr 文件中,插入如下内容:
if (Pos('/WaitForShutDown', CmdLine) <> 0) then
WaitForSingleObject(ShutDownMutexHandle, 无限);
另外,在您的程序中,在完成所有最终确定并释放公共资源之后,请包含类似
ReleaseMutex(ShutDownMutexHandle); 的内容。
Include in your ShellExecute some parameter, for example, /WaitForShutDown and create one more mutex. In your program, before the initialization, for example, in its .dpr file, insert something like:
if (Pos('/WaitForShutDown', CmdLine) <> 0) then
WaitForSingleObject(ShutDownMutexHandle, INFINITE);
Also, in your program, after all the finalizations and releasing your common resources, include something like
ReleaseMutex(ShutDownMutexHandle);
编辑...
好的。现在我相信我知道你的问题出在哪里......
您在程序单元最终确定方面遇到问题!
尝试在程序部分添加作为第一个单元我的底部 RestartMutex 单元。
;
当您想要重新启动应用程序时,只需将变量重新启动设置为true,然后终止应用程序。
因此,由于 RestartMutex 在程序部分添加为第一个,这将导致 RestartMutex 单元的终结几乎在关闭应用程序结束时完成,并且所有其他单元将在 RestartMutex 单元之前完成终结,这意味着应用程序可以再次安全启动!
EDIT...
OK. Now I belive that I know where is your problem...
You have problems with program units finalization!
Try to add at program section as first unit my bottom RestartMutex unit.
;
When you want to restart application just set variable Restart to true and than terminate an application.
So, because is RestartMutex added as first in program section, this will couse that finalisation of unit RestartMutex will hepped nearly at the end of closing an application and all other units will do finalization before unit RestartMutex, that mean the Application can start safe again!
您可以传递诸如“重新启动”之类的命令行参数并在尝试获取互斥体之前运行 Sleep() 或尝试在休眠一段时间的循环中获取互斥体。
您也可以在两个进程之间建立通信,但这可能有点过头了。
You could pass a command line argument like "restart" and run a Sleep() before you try to acquire the Mutex or try to acquire the mutex in a loop that sleeps a while.
Also you could set up communication between both processes, but that might be overkill.
您好,请查看以下文章 Zarko Gajic - 在那里您会发现获取一些想法、示例代码甚至整个组件来使用。
哈,
莱因哈德
hi take a look a the following article by Zarko Gajic - there you will get some ideas, sample code and even a whole component to use.
hth,
reinhard
您的
ReleaseMutex
可能会失败,因为您在调用CreateMutex
。拥有互斥锁的初始所有权,或调用CloseHandle
而不是传递互斥体句柄的“ReleaseMutex”。Your
ReleaseMutex
is probably failing since you're passing 'False' for 'bInitialOwner' while callingCreateMutex
. Either have the initial ownership of the mutex, or callCloseHandle
instead of 'ReleaseMutex' passing your mutex handle.以这种方式结帐:
只需运行一个新应用程序并终止当前应用程序;
http://www.delphitricks.com/source-code/windows/restart_the_own_program.html
checkout this way:
Simply runs a new application and kills the currernt one;
http://www.delphitricks.com/source-code/windows/restart_the_own_program.html
(打败睡眠想法)
如果你想在创建互斥体之前确保原始进程确实终止/关闭,那么一个想法是将PID传递给新进程(命令行是最简单的,任何其他IPC方法都可以)以及),然后使用 OpenProcess(SYNCHRONIZE, false, pid) 和 WaitForSingleObject (我会使用一个带有超时的循环(100 毫秒是一个很好的值),如果原始进程需要太长时间才能关闭,则采取相应的行动)
我结束了除了上述之外,我们还在与互斥体相同的单元中创建一个 RestartSelf 过程,并在那里执行逻辑,以便将单个实例和重新启动逻辑保持在同一位置(参数是硬编码的,您不需要不希望硬编码的内容分散在您的应用程序中。
(beating the sleep idea)
if you want to make sure the original process is really terminated/closed before you create the mutex, then one idea is to pass the PID to the new process (command line is the easiest, any other IPC method works as well), then use OpenProcess(SYNCHRONIZE, false, pid) and WaitForSingleObject (I'd use a loop with a timeout (100 ms is a good value) and act accordingly if the original process takes too long to close)
What I ended up doing, beside the above, was to also create a RestartSelf procedure in the same unit with the mutex, and do the logic there, in order to keep the single instance and restart logic in the same place (the parameter being hardcoded, you don't want hardcoded stuff to be scattered around your application(s).