【问题标题】:Restart Delphi Application Programmatically以编程方式重新启动 Delphi 应用程序
【发布时间】:2010-12-21 10:26:41
【问题描述】:

应该不可能运行我的应用程序的多个实例。因此项目源码包含:

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;

但是由于互斥锁,这在我的情况下不起作用。即使我在启动第二个实例之前释放了互斥锁,它也不会起作用,因为关闭需要一些时间并且两个实例不能并行运行(因为公共资源和其他影响)。

有没有办法重新启动具有这些特征的应用程序? (如果可能,无需额外的可执行文件)

提前致谢。

【问题讨论】:

  • 为什么要重新启动 - 只需激活已经运行的实例
  • 怎么一样?正在运行的实例已经处于活动状态,我希望它重新启动。
  • 你测试过'ReleaseMutex'的返回吗?
  • 释放 不是您需要对互斥体执行的操作。而是关闭它。

标签: delphi delphi-2010 application-restart


【解决方案1】:

也许您应该跳出框框思考。您可以简单地创建 另一个 可执行文件,等待您的应用关闭然后再次启动它,而不是使用互斥锁/实例逻辑。作为额外的奖励,您可以稍后使用此机制来更新某些主应用程序的二进制文件。提升运行它也更容易,而不是在同一个应用程序中维护不同的完整性级别等。

【讨论】:

  • +1;这是许多应用程序执行更新的一种机制。
【解决方案2】:

为什么您不能在尝试重新启动之前释放互斥锁?如果某个实例在您显式调用的实例之前启动并重新启动并不重要,那么您仍然可以让您的应用程序重新启动并再次运行,并且需要重新启动所需的任何更改。我认为您不需要其他解决方案的任何复杂性。

【讨论】:

  • 因为在有限的时间内两个实例将并行运行(关闭需要一些时间)。这就是我想要避免的。
  • 所以您需要关闭并重新启动,或者重新激活已经运行的应用程序就足够了(看看我发布的链接)?
  • @Smasher 在这种情况下会在单实例模式下执行您需要执行的所有关闭操作,然后在完成所有关闭工作后,释放互斥锁并调用 ShellExecute。
  • @Smasher 您需要做的就是将 ShellExecute 放在现有的互斥锁版本之后。大概您在释放现有互斥锁之前已经完成了所有关闭工作?
  • @David:不,我不这样做,这并不容易。但我想你是对的,这是最简单的解决方案。
【解决方案3】:

在您的 ShellExecute 中包含一些参数,例如 /WaitForShutDown 并再创建一个互斥锁。在您的程序中,在初始化之前,例如,在其 .dpr 文件中,插入如下内容:

if (Pos('/WaitForShutDown', CmdLine) 0) 那么 WaitForSingleObject(ShutDownMutexHandle, INFINITE);

此外,在您的程序中,在完成所有最终确定并释放您的公共资源之后,包括类似

ReleaseMutex(ShutDownMutexHandle);

【讨论】:

  • 谢谢!但是ShutdownMutexHandle 将在程序启动时未定义。你会如何定义它? CreateMutex 将失败并出现 ERROR_ALREADY_EXISTS 错误...
  • 好吧,我想我找到了:OpenMutex 应该是调用来获取句柄的正确方法。
【解决方案4】:

编辑...

好的。现在我相信我知道你的问题在哪里...... 您在完成程序单元时遇到问题!

尝试在程序部分添加作为第一个单元我的底部 RestartMutex 单元。

program MyProgramName;  
uses
  Mutex,
  Forms,
...

;

unit RestartMutex;
interface

var
  Restart: boolean = false;

implementation

uses
  windows,
  ShellApi;

var
  MutexHandle: cardinal;
  AppName: PChar;
const
  ID = 'MyProgram';

initialization
  MutexHandle := CreateMutex (nil, False, PChar (ID));
  if (GetLastError = ERROR_ALREADY_EXISTS) then
    Halt;

finalization
  ReleaseMutex(MutexHandle);
  if Restart then
  begin
    AppName := PChar('MyProgramName.exe') ;
    ShellExecute(0,'open', AppName, nil, nil, SW_SHOWNORMAL) ;
  end: 
end.

当您想重新启动应用程序时,只需将变量 Restart 设置为 true,然后终止应用程序。

所以,因为在程序部分首先添加了 RestartMutex,这将导致单元 RestartMutex 的最终确定将在关闭应用程序结束时完成,并且所有其他单元将在单元 RestartMutex 之前完成,这意味着应用程序可以启动再次安全!

【讨论】:

  • “即使我在开始第二个实例之前释放互斥锁,它也不起作用,因为关闭需要一些时间并且两个实例不能并行运行”......来自问题。
  • @Smasher:你的程序完成有问题!检查我改进的答案!
【解决方案5】:

在尝试获取互斥锁或尝试在休眠一段时间的循环中获取互斥锁之前,您可以传递一个命令行参数(如“restart”)并运行 Sleep()。

您也可以在两个进程之间建立通信,但这可能有点过头了。

【讨论】:

  • Sleep 的问题是无法找到合适的值。完全取决于计算机、加载的数据和其他东西。
【解决方案6】:

你好,看看下面的文章by Zarko Gajic - 你会得到一些想法,示例代码,甚至是一个完整的组件来使用。

hth, 莱因哈特

【讨论】:

【解决方案7】:

您的ReleaseMutex 可能失败,因为您在调用CreateMutex 时为“bInitialOwner”传递了“False”。要么拥有互斥锁的初始所有权,要么调用 CloseHandle 而不是传递您的互斥锁句柄的“ReleaseMutex”。

【讨论】:

  • 不,根本不用担心释放互斥体。互斥锁的所有权是完全不相关的。您需要做的是用CloseHandle销毁互斥锁。就这样。 (这当然需要存储来自CreateMutex 的返回值。)
【解决方案8】:

以这种方式结帐:

只需运行一个新应用程序并杀死当前应用程序;

http://www.delphitricks.com/source-code/windows/restart_the_own_program.html

【讨论】:

  • 为避免链接失效,请在此处发布链接中包含的相关信息。
【解决方案9】:

(打破睡眠的想法)

如果您想在创建互斥锁之前确保原始进程真正终止/关闭,那么一个想法是将 PID 传递给新进程(命令行是最简单的,任何其他 IPC 方法也可以) ,然后使用 OpenProcess(SYNCHRONIZE, false, pid) 和 WaitForSingleObject(我会使用一个有超时的循环(100 毫秒是一个很好的值),如果原始进程需要很长时间才能关闭,则采取相应的行动)

除了上述之外,我最终做的是在与互斥锁相同的单元中创建一个 RestartSelf 过程,并在那里执行逻辑,以便将单个实例和重新启动逻辑保持在同一个地方(参数被硬编码,你不希望硬编码的东西分散在你的应用程序周围。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-09-26
    • 1970-01-01
    • 2011-05-22
    • 1970-01-01
    • 1970-01-01
    • 2010-09-07
    相关资源
    最近更新 更多