Как обнаружить запущенную копию программы Delphi
Рассмотрим способ обнаружения запущенного экземпляра программы на Delphi / Rad Studio. В случае обнаружения передадим ему команду на разворачивание из области уведомлений Windows (трей) и завершим работу второй копии.
Задача часто встречается на практике. Например, приложение, которое при закрытии сварачива в «Tray», при повторном запуске должно разворачиваться, а не запускать ещё одну копию.
Приступим к реализации:
- Открываем «Project Source» — в главном меню «Project - View Source».
-
В раздел «uses» добавляем модуль «Windows» и объявляем две переменные типа «THandle».
uses Forms, Windows, URealHoliday in 'URealHoliday.pas' {Form1}; var xHand: THandle; var wnd: THandle;
-
В тело вставляем код:
xHand := CreateMutex(nil, True, 'unique_phrase'); if (GetLastError = ERROR_ALREADY_EXISTS)or(GetLastError = ERROR_ACCESS_DENIED) then begin wnd := FindWindow('TForm1',nil); if wnd<>0 then begin SendMessage(wnd,WM_GOTOFOREGROUND,0,0); end; Application.Terminate; Exit; end; Application.Initialize; Application.CreateForm(TForm1, Form1); Application.Run;
Здесь сначала создаём «Mutex» с указанием какой-то уникальной фразы для приложения по которой сможем обращаться к ней. Если создание «Mutex» завершилось с ошибкой «ERROR_ALREADY_EXISTS» или «ERROR_ACCESS_DENIED», то почти наверняка экземпляр нашей программы уже запущен и можем текущий сеанс завершить. Но перед этим отправим запущенному процессу команду «WM_GOTOFOREGROUND», по которой основная форма должна разверуться поверх остальных окон Windows.
Мутекс – это объект синхронизации потоков разных процессов. С его помощью можно синхронизировать совместный доступ нескольких процессов к одному файлу. Это делается так — создаётся «Mutex». Затем один из процессов становится его владельцем и начинает работу с файлом. После действий осовобождает «Mutex». Другие аналогичные процессы должны при работе с файлом также становиться владельцем мутекса и если это невозможно, то ждать своей очереди.
«FindWindow» осуществляет поиск процесса по типу формы, поэтому вместо стандартного «TForm1» лучше использовать уникальное значение, но для примера оставим всё по-умолчанию.
Переходим ко второй части программы, в которой требуется отлавливать событие «WM_GOTOFOREGROUND» для совершения каких-то действий.
-
Переходим в код основной формы. Облявляем константу после блока «Uses».
const WM_GOTOFOREGROUND = WM_USER + 1;
-
Объявляем публичную процедуру:
public { Public declarations } procedure WMGotoForeground(var Msg:TMessage); message WM_GOTOFOREGROUND; end;
-
Прописываем её код:
procedure TForm1.WMGotoForeground(var Msg: TMessage); begin Form1.Visible := true; Application.Minimize; Application.Restore; end;
Здесь можно писать любые действия, которые будут происходить при получении сообщения. В нашем случае сделаем форму видимой, а затем свернём и восстановим, что позволит показать её поверх других окон Windows.
Такой вариант реализации взаимодействия процессов давно применяется не только в Delphi / Rad Studio. Возможно есть и другие более современные способы, особенно это касается нахождения дескриптора первого экземпляра программы. Буду рад если поделитесь ими.