Для
Delphi 1. Каждый экземпляр программы имеет ссылку на свою предыдущую копию -
hPrevInst: hWnd. Ее можно проверить перед созданием приложения и при
необходимости отреагировать соответствующим образом. Если запущена только
одна копия, то эта ссылка равна нулю.
Пример:
procedure TForm1.FormCreate(Sender: TObject);
begin
{Проверяем есть ли указатель на предыдущую копию приложения}
IF hPrevInst <> 0 THEN BEGIN
{Если есть, то выдаем сообщение и выходим}
MessageDlg('Программа уже запущена!', mtError, [mbOk], 0);
Halt;
END;
{Иначе - ничего не делаем (не мешаем созданию формы)}
end;
P.S. Для выхода необходимо использовать Halt, а не Close, как хотелось
бы, так как форма еще не создана и закрывать нечего.
Есть и другой способ
- по списку загруженных приложений
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;
Еще один интересный способ для Win32. Дело в том, что можно в памяти
создавать временные файлы. При перезагрузке они теряются, а так существуют.
Кстати, этот метод можно использовать и для обмена информацией между вашими
приложениями.
Пример:
program Project1;
uses
Windows, // Обязательно
Forms,
Unit1 in 'Unit1.pas' {Form1};
{$R *.RES}
Const
MemFileSize = 1024;
MemFileName = 'one_inst_demo_memfile';
Var
MemHnd : HWND;
begin
{ Попытаемся создать файл в памяти }
MemHnd := CreateFileMapping(HWND($FFFFFFFF),
nil,
PAGE_READWRITE,
0,
MemFileSize,
MemFileName);
{ Если файл не существовал запускаем приложение }
if GetLastError<>ERROR_ALREADY_EXISTS then
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end;
CloseHandle(MemHnd);
end.
Часто при работе у пользователя может быть открыто 5-20 окон и сообщение
о том, что программа уже запущено приводит к тому, что он вынужден полчаса
искать ранее запущенную копию. Выход из положения - найдя копию программы
активировать ее, для чего в последнем примере перед HALT необходимо добавить
строку :
SetForegroundWindow(Wnd);
Например так:
program Project0;
uses
Windows, // !!!
Forms,
Unit0 in 'Unit0.pas' {Form1};
var
Handle1 : LongInt;
Handle2 : LongInt;
{$R *.RES}
begin
Application.Initialize;
Handle1 := FindWindow('TForm1',nil);
if handle1 = 0 then
begin
Application.CreateForm(TForm1, Form1);
Application.Run;
end
else
begin
Handle2 := GetWindow(Handle1,GW_OWNER);
//Чтоб заметили :)
ShowWindow(Handle2,SW_HIDE); ShowWindow(Handle2,SW_RESTORE);
SetForegroundWindow(Handle1); // Активизируем
end;
end.
Комментарий от "Vladimir" (damageinc@e-mail.ru)
Лучше всего
использовать именованные мутексы. Главное,
придумать
уникальное имя для этого мутекса. Вот
пример вполне работоспособной
программы:
program My1;
uses
Forms, Windows, Dialogs, SysUtils,
var
g_hAppMutex: THandle;
Wnd : hWnd;
buff: array [0..127] of Char;
s:string;
i:integer;
function OneInstance: boolean;
begin
g_hAppMutex:=CreateMutex(nil,false,PChar('AnUniqueString'+IntToStr(GetDesktopWindow)));
Result:=(WaitForSingleObject(g_hAppMutex,0)<>WAIT_TIMEOUT);
end;
begin
Application.Initialize;
Application.Title := 'SmartDecoder';
Application.HelpFile := 'Decoder.hlp';
//создаём инстанс, если его ещё нету на текущем рабочем столе
g_hAppMutex:=0;
if OneInstance then
begin
Application.CreateForm(TMainFrm, MainFrm);
Application.Run;
end;
if LongBool(g_hAppMutex) then //если уже есть
begin
ReleaseMutex(g_hAppMutex);
CloseHandle(g_hAppMutex);
if ParamStr(1)='' then ShowMessage('Программа уже запущена на
этом рабочем столе. Нажмите кнопку "OK" для передачи управления
уже запущенной копии программы.');
Wnd:=GetWindow(GetTopWindow(0),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 Copy(StrPas(buff),1,12)='SmartDecoder' then
if Wnd=GetWindowLong(Wnd,GWL_USERDATA) then
begin
ShowWindow(Wnd,SW_ShowNormal);
SetForegroundWindow(Wnd);
i:=1;
while ParamStr(i)<>'' do
begin
s:=ParamStr(i);
PostMessage(Wnd,WM_OPEN_FILE,GlobalAddAtom(PChar(s)),0);
inc(i);
end;
Application.Terminate;
Exit;
end;
end;
Wnd:=GetWindow(Wnd,gw_hWndNext);
end;
end;
end.
Если
программа уже запущена, управление будет передано
существующей
копии.
|
Copyright ©
"Мастера DELPHI" E-mail:
delphi@mastak.com
http://www.delphimaster.ru |
Источник получения информации: http://www.delphimaster.ru
|