7

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

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;

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

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

提前致谢。

4

9 回答 9

15

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

于 2010-12-21T13:47:40.100 回答
2

为什么您不能在尝试重新启动之前释放互斥锁?如果有机会在您明确调用的实例之前启动另一个实例并重新启动无关紧要,您仍然可以让您的应用程序重新启动并再次运行,无论发生什么需要重新启动的更改。我认为您不需要其他解决方案的任何复杂性。

于 2010-12-21T10:51:26.163 回答
1

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

if (Pos('/WaitForShutDown', CmdLine) <> 0) 然后 WaitForSingleObject(ShutDownMutexHandle, INFINITE);

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

ReleaseMutex(ShutDownMutexHandle);

于 2010-12-21T10:44:39.247 回答
1

编辑...

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

尝试在程序部分添加我的底部 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 之前完成,这意味着应用程序可以再次安全启动!

于 2010-12-21T11:13:16.037 回答
0

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

于 2010-12-21T11:47:26.300 回答
0

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

您也可以在两个进程之间建立通信,但这可能是矫枉过正。

于 2010-12-21T10:35:57.527 回答
0

以这种方式结帐:

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

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

于 2015-02-11T20:25:15.443 回答
0

嗨,看看Zarko Gajic的以下文章- 在那里你会得到一些想法、示例代码,甚至是一个完整的组件来使用。

hth,莱因哈特

于 2010-12-21T10:50:54.847 回答
0

(打破睡眠的想法)

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

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

于 2016-01-23T13:44:58.057 回答