Рассмотрим способ обнаружения запущенного экземпляра программы на Delphi / Rad Studio. В случае обнаружения передадим ему команду на разворачивание из области уведомлений Windows (трей) и завершим работу второй копии.
Задача часто встречается на практике. Например, приложение, которое при закрытии сварачива в «Tray», при повторном запуске должно разворачиваться, а не запускать ещё одну копию.
Приступим к реализации:
- Открываем «Project Source» — в главном меню «Project — View Source».
- В раздел «uses» добавляем модуль «Windows» и объявляем две переменные типа «THandle».
uses Forms, Windows, URealHoliday in ‘URealHoliday.pas’ ; 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». Другие аналогичные процессы должны при работе с файлом также становиться владельцем мутекса и если это невозможно, то ждать своей очереди.
Переходим ко второй части программы, в которой требуется отлавливать событие «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;
Такой вариант реализации взаимодействия процессов давно применяется не только в Delphi / Rad Studio.
Возможно есть и другие более современные способы, особенно это касается нахождения дескриптора первого экземпляра программы. Буду рад если поделитесь ими.
Источник: realadmin.ru
Программирование на Delphi
Как определить работает ли уже данное приложение или это его первая копия
Каждый экземпляр программы имеет ссылку на свою предыдущую копию — hPrevInst: hWnd. Ее можно проверить перед созданием приложения и при необходимости отреагировать соответствующим образом. Если запущена только одна копия, то эта ссылка равна нулю. Только для Delphi 1. Пример использования hPrevInst:
Гта 5 уже запущена Rockstar Launcher — решение проблемы
procedure TForm1.FormCreate(Sender: TObject); begin // Проверяем есть ли указатель на предыдущую копию приложения if hPrevInst <> 0 then begin // Если есть, то выдаем сообщение и выходим MessageDlg(‘Программа уже запущена!’, mtError, [mbOk], 0); Application.Terminate; end; // Иначе — ничего не делаем (не мешаем созданию формы) end;
Другой способ — по списку загруженных приложений
procedure TForm1.FormCreate(Sender: TObject); var Wnd : hWnd; buff : array[0.. 127] of Char; begin //Получили указатель на первое окно Wnd := GetWindow(Handle, gw_HWndFirst); // Поиск while Wnd <> 0 do begin // Это окно предыдущей копии ? if (Wnd <> Application.Handle) and (GetWindow(Wnd, gw_Owner) = 0) then begin GetWindowText (Wnd, buff, sizeof (buff )); if StrPas (buff) = Application.Title then begin MessageDlg(‘Приложение уже загружено’, mtWarning, [mbOk], 0); Halt; end; end; Wnd := GetWindow (Wnd, gw_hWndNext); end; end;
Как сделать исключение повторного запуска программы в Delphi?
Предположим, я нажал на ярлык программы, программа запустилась, второй раз нажимаю на ярлык и выдается сообщение, что программа уже запущена или если программа свернута, она при этом разворачивается и становится видимой на переднем плане, если запущено много окон?
Ответы (4 шт):
Вариантов несколько, но самый оптимальный — смотрите запущенные задачи, и если находите еще одну такую же, то посылаете ей сообщение развернуться, а себя убиваете. Это упрощенно, а реальный код получится весьма объемный.
Я обычно делаю так:
implementation var g_hAppMutex: THandle; function OneInstance: boolean; var g_hAppCritSecMutex: THandle; dw: Longint; begin g_hAppCritSecMutex := CreateMutex( nil, true, PChar(Application.Title + ‘.OneInstance32.CriticalSection’) ); g_hAppMutex := CreateMutex( nil, false, PChar(Application.Title + ‘OneInstance32.Default’) ); dw := WaitForSingleObject( g_hAppMutex, 0 ); Result := (dw <> WAIT_TIMEOUT); ReleaseMutex( g_hAppCritSecMutex ); CloseHandle( g_hAppCritSecMutex ); end; procedure TForm1.FormCreate(Sender: TObject); begin if not OneInstance then begin MessageBoxEx(Application.Handle, PChar(‘Приложение уже открыто! Запуск второго экземпляра запрещен.’), PChar(‘. ‘), MB_ICONSTOP + MB_OK, $0419); Application.Terminate; end end;
initialization g_hAppMutex := 0; finalization if LongBool( g_hAppMutex ) then begin ReleaseMutex( g_hAppMutex); CloseHandle( g_hAppMutex ); end; end.
Простой запрет повторного запуска — задача тривиальная. В код запуска программы нужно добавить проверку на то, что программа с таким же путем запуска ехе-файла в данный момент не работает. Если такая же программа уже есть, то просто выходим.
Реализовать же разворот уже имеющегося окна тоже можно двумя способами — искать нужный HWND и отправлять ему сообщение о том, чтобы он развернулся, или же поступить как сделано здесь.
Отмечу, что в методе по ссылке для одного запуска используется глобальный мьютекс, что тоже является вариантом решения первой подзадачи.
Пожалуй, один из самых простых, но, скорее всего не самый надёжный способ: использовать WinAPI. Есть такая функция FindWindow — принимает 2 параметра: первый — имя класса главного окна, второй — заголовок окна; сама функция возвращает 0, если такого окна нет, и дескриптор в противном случае. Код нужно писать в исходнике программы. Пример:
program Project1; uses Forms, Windows, // Этот модуль должен быть подключен! Unit1 in ‘Unit1.pas’ ; Var hWind: HWND; begin Application.Initialize; hWind:=FindWindow(‘TForm1’, ‘Form1’); hWind:=FindWindow(‘TForm1’, Nil); If (hWind<>0) Then Begin SetForegroundWindow(hWind); // выводит окно на первый план Application.Terminate; // завершает повторно запущенное приложение End; Application.CreateForm(TForm1, Form1); Application.Run; end.
Источник: husl.ru