Перезапустите Приложение Delphi Программно

невозможно запустить несколько экземпляров моего приложения. Поэтому источник проекта содержит:

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

теперь я хочу перезапустить приложение программно. Обычным способом было бы:--3-->

AppName := PChar(Application.ExeName) ;
ShellExecute(Handle,'open', AppName, nil, nil, SW_SHOWNORMAL) ;
Application.Terminate;

но это не будет работать в моем случае из-за мьютекса. Даже если я выпущу мьютекс перед запуском второго instace, он не будет работать, потому что завершение работы занимает некоторое время, и два экземпляра не могут работать параллельно (из-за общих ресурсов и других эффекты.)

есть ли способ перезапустить приложение с такими характеристиками? (Если возможно без дополнительного исполняемого файла)

спасибо заранее.

9 ответов


Возможно, вам следует думать нестандартно. Вместо futzing с логикой мьютекса / экземпляра, вы можете просто создать другое исполняемый файл, который ждет закрытия вашего приложения, а затем запускает его снова. В качестве дополнительного бонуса вы можете позже использовать этот механизм, например, для обновления некоторых двоичных файлов вашего основного приложения. Также намного проще запустить его повышенным, а не поддерживать разные уровни целостности внутри одного приложения и т. д.


Почему вы не можете просто освободить мьютекс перед попыткой перезапуска? Если по какой-то случайности другой экземпляр запускается перед тем, который вы явно вызываете с перезапуском, который не имеет значения, у вас все равно будет ваше приложение снова запущено с любыми изменениями, которые потребовали перезапуска. Я не думаю, что вам нужна какая-либо сложность других решений.


включите в свой ShellExecute некоторый параметр, например, /WaitForShutDown и создайте еще один мьютекс. В вашей программе, перед инициализацией, например, в its .dpr файл, вставьте что-то вроде:

if (Pos ('/WaitForShutDown', CmdLine) 0) тогда WaitForSingleObject (ShutDownMutexHandle, INFINITE);

кроме того, в вашей программе, после все завершения и выпуска своих общих ресурсов, включая как

ReleaseMutex (ShutDownMutexHandle);


правка...

OK. Теперь я понимаю, в чем твоя проблема... У вас проблемы с доработкой программных блоков!

попробуйте добавить в раздел программы как первый блок мой нижний блок 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.

когда вы хотите перезапустить приложение просто установить переменную перезагрузка true и чем завершить приложение.

Итак, потому что RestartMutex добавлен как во-первых, в разделе программы это будет означать, что финализация unit RestartMutex будет завершена почти в конце закрытия приложения, а все остальные подразделения завершат работу до unit RestartMutex, что означает, что приложение может начать безопасно снова!


вы можете передать аргумент командной строки, например "restart" и запустить Sleep (), прежде чем пытаться получить мьютекс или попытаться получить мьютекс в цикле, который спит некоторое время.

также вы можете настроить связь между обоими процессами, но это может быть излишним.


привет, взгляните на следующие статьи by Zarko Gajic - там вы получите некоторые идеи, примеры кода и даже целый компонент для использования.

hth, Рейнхард!--3-->


код ReleaseMutex вероятно, сбой, так как вы передаете "False" для "bInitialOwner" при вызове CreateMutex. Либо иметь начальное владение мьютексом, либо вызвать CloseHandle вместо "ReleaseMutex" передает ваш дескриптор мьютекса.


оформить заказ таким образом:

просто запускает новое приложение и убивает currernt;

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


(отбивая идею сна)

Если вы хотите, чтобы убедиться, что исходный процесс действительно прекращен/закрытые до создания мьютекса, то один из вариантов-передать PID нового процесса (командная строка-это самый простой, и любой другой МПК метод работает так же), а затем использовать для открытия процесса(синхронизация, ложь, пид) и waitforsingleobject (я бы использовать цикл с таймаутом (100 мс-это хорошее качество) и действовать соответственно, если исходный процесс занимает слишком много времени, чтобы закрыть)

Что я закончил помимо вышеизложенного, нужно было также создать процедуру RestartSelf в том же блоке с мьютексом и сделать логику там, чтобы сохранить один экземпляр и перезапустить логику в том же месте (параметр жестко закодирован, вы не хотите, чтобы жестко закодированные вещи были разбросаны вокруг вашего приложения(приложений).