Перезапустите приложение Delphi программно - PullRequest
6 голосов
/ 21 декабря 2010

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

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;

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

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

Ответы [ 9 ]

15 голосов
/ 21 декабря 2010

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

2 голосов
/ 21 декабря 2010

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

1 голос
/ 21 декабря 2010

РЕДАКТИРОВАТЬ ...

ОК.Теперь я верю, что знаю, в чем ваша проблема ... У вас проблемы с завершением программных блоков!

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

1 голос
/ 21 декабря 2010

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

if (Pos ('/ WaitForShutDown', CmdLine) <> 0) затем WaitForSingleObject (ShutDownMutexHandle, INFINITE);

Кроме того, в вашей программе после всех финализаций и освобождения ваших общих ресурсов добавьте что-то вроде

ReleaseMutex (ShutDownMutexHandle);

0 голосов
/ 23 января 2016

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

если вы хотите убедиться, что исходный процесс действительно завершен / закрыт перед созданием мьютекса, то одна идея состоит в том, чтобы передать PID новому процессу (командная строка является самой простой, любой другой метод IPC также работает) , затем используйте OpenProcess (SYNCHRONIZE, false, pid) и WaitForSingleObject (я бы использовал цикл с тайм-аутом (100 мс - хорошее значение) и действовал бы соответственно, если исходный процесс слишком долго закрывался)

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

0 голосов
/ 11 февраля 2015

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

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

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

0 голосов
/ 21 декабря 2010

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

0 голосов
/ 21 декабря 2010

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

НТН, Reinhard

0 голосов
/ 21 декабря 2010

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...