В программировании хорошим тоном считается предотвращение повторного запуска одной и той же программы. Если программа работает с какими-то файлами данных, то одновременный запуск двух ее копий приведет к тому, что обе они станут обращаться к одним и тем же файлам, что явно вызовет конфликт. Рекомендуемая реакция программы на попытку ее повторного запуска – разворачивание и вынесение на передний план окна уже запущенной программы и тихое "прибивание" второго экземпляра. Таким образом, задача распадается на две части: обнаружить факт повторного запуска и, если такое случилось, послать уже запущенному экземпляру сообщение "покажись!", а затем завершить работу.
Для установления факта запуска программы можно применить особый механизм, известный как Mutex (mutual exception – взаимное исключение). Mutex – это особый объект операционной системы, предназначенный, прежде всего, для синхронизации параллельных процессов. Но он вполне подходит и для фиксации факта запуска той или иной программы. Для этого программа при старте пытается создать взаимное исключение с уникальным именем и проверяет, удалось ли его создать. Если нет – значит, данная программа уже была запущена. При завершении работы программы ее mutex удаляется из памяти автоматически.
Проверку повторного запуска надо делать в самом начале работы, еще до создания форм, поэтому менять будем файл .dpr:
program test;
uses
Windows,
Forms,
Messages,
Dialogs,
SysUtils,
main in 'main.pas' {Form1};
{$R *.res}
VAR h:THandle;
begin
CreateMutex(nil, True, 'Test');
if GetLastError = ERROR_ALREADY_EXISTS then
BEGIN
H := FindWindow(NIL, 'Заголовок окна');
IF H<>0 THEN
BEGIN
PostMessage(H, wm_User, 0, 0);
EXIT
END
end;
Здесь создается взаимное исключение с именем 'Test'. Если функция GetLastError вернет константу ERROR_ALREADY_EXISTS, значит, такое исключение уже есть в памяти и программа уже запущена. Надо послать ей сообщение, что делается традиционным образом – поиском окна по заголовку (увы, без этого не обойтись). В описании же главной формы приложения добавляем обработчик сообщения WM_USER:
procedure WMUser(var msg: TMessage); message wm_User;
…
procedure TForm1.WMUser(var msg: TMessage);
BEGIN
Application.Restore;
APPLICATION.BringToFront;
Form1.Activate
END;