Вопрос одновременности запуска нескольких экземпляров приложения является актуальным для многих программ, особенно тех, которые работают с общими ресурсами. В случае с Delphi-приложениями, использование мьютекса позволяет контролировать запуск только одного экземпляра программы. Однако, может возникнуть необходимость перезапустить приложение, например, после обновления или в случае возникновения ошибок, которые не могут быть устранены в рамках текущего процесса.
Проблема
Исходный код проекта содержит код, который предотвращает запуск нескольких экземпляров приложения:
CreateMutex(nil, False, PChar(ID));
if (GetLastError = ERROR_ALREADY_EXISTS) then
Halt;
При попытке перезапустить приложение с помощью стандартного метода:
этот метод не работает из-за использования мьютекса. Даже если освободить мьютекс перед запуском второго экземпляра, это не решит проблему, так как завершение работы приложения занимает некоторое время, и в этот период могут запускаться два экземпляра приложения.
Решение
Для решения этой проблемы можно использовать следующий подход:
Установить глобальную переменную RestartApp в значение True перед завершением работы приложения.
Отправить сообщение WM_CLOSE главному окну, чтобы инициировать его закрытие.
В блоке finalization модуля, который отвечает за мьютекс, добавить код для освобождения мьютекса и запуска приложения через ShellExecute, если переменная RestartApp установлена в True.
Пример кода для модуля с мьютексом:
program MyProgramName;
uses
Mutex,
Forms,
...
type
TFormMain = class(TForm)
// Объявление компонентов формы
private
{ Private declarations }
Restart: boolean = false;
public
{ Public declarations }
end;
var
FormMain: TFormMain;
RestartMutex: boolean = false;
implementation
uses
Windows,
ShellApi;
type
TMutexHandle = ^TMutexHandleRec;
TMutexHandleRec = record
Handle: Cardinal;
end;
var
MutexHandle: TMutexHandle;
AppName: PChar;
ID: PChar = 'MyProgramMutexID';
const
MUTEX_ALL_ACCESS: DWORD = $1F0001; {$mode delphi}{$IFDEF MSWINDOWS}{$IFDEF WIN64}
MUTEX_ALL_ACCESS: DWORD64 = $1F0001LL;
{$ELSE}
MUTEX_ALL_ACCESS: DWORD = $1FFL;
{$ENDIF}
initialization
GetMem(MutexHandle, SizeOf(TMutexHandleRec));
MutexHandle.Handle := CreateMutex(nil, False, PChar(ID));
if (GetLastError = ERROR_ALREADY_EXISTS) then
Halt;
finalization
if Restart then
begin
Restart := False;
ReleaseMutex(MutexHandle.Handle);
CloseHandle(MutexHandle.Handle);
FreeMem(MutexHandle);
AppName := PChar('MyProgramName.exe');
ShellExecute(0, 'open', AppName, nil, nil, SW_SHOWNORMAL);
end
else
begin
ReleaseMutex(MutexHandle.Handle);
CloseHandle(MutexHandle.Handle);
FreeMem(MutexHandle);
end;
end.
При перезапуске приложения необходимо установить переменную Restart в True и инициировать завершение работы приложения. После этого, в блоке finalization модуля, который идет первым в списке используемых модулей, произойдет освобождение мьютекса и перезапуск приложения.
Заключение
Использование данного метода позволяет гарантировать, что при перезапуске приложения будет запущен только один его экземпляр, что предотвращает возможные проблемы с доступом к общим ресурсам и обеспечивает корректную работу программы после обновлений или при возникновении ошибок.
Контекст заключается в необходимости перезапустить приложение Delphi с использованием мьютекса таким образом, чтобы гарантировать одновременность запуска только одного экземпляра приложения, включая ситуации, когда нужно обновить или перезапустить прилож
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS