Форум: "Основная";
Текущий архив: 2004.01.16;
Скачать: [xml.tar.bz2];
ВнизЭффективный способ предотвращения запуска второго экземпляра Найти похожие ветки
← →
A. Sonin (2004-01-05 21:50) [0]Здравствуйте, Мастера. Как вы считаете, какой из способов предотвращения запуска второго экземпляра приложения наиболее эффективен? Один знакомы программист использует следующий код:
В проекте:
program Any_program;
uses
Forms,
Windows,
SysUtils,
Unit1 in "Unit1.pas" {FrmMain},
Utils in "Utils.pas";
var
Previous:HWND;
ATOM:TAtom;
{$R *.res}
Function EnumWindowsCallback(Handle:HWND; Param:LPARAM):Boolean; Stdcall;
Function IsMyClass: Boolean;
Var
ClassName:Array[0..30] Of Char;
Begin
GetClassName(Handle, ClassName, 30);
Result:=(StrIComp(ClassName,"TFrmMain")=0) And
(SendMessage(Handle, WM_FINDINSTANCE,0,0)=MyUniqueConst);
End;
Begin
Result:=Not IsMyClass;
If Not Result Then
Previous:=Handle;
End;
Begin
Previous:=0;
ATOM:=0;
EnumWindows(@EnumWindowsCallback,0);
If Previous<>0 Then
Begin
PostMessage(Previous,WM_RESTOREAPP,0,0);
if (ParamCount>0) Then
Begin
ATOM:=GlobalAddAtom(PChar(ParamStr(1)));
SendMessage(Previous,WM_OPENAPP,ATOM,0);
GlobalDeleteAtom(ATOM);
End;
Exit;
End;
Application.Initialize;
Application.CreateForm(TFrmMain,FrmMain);
If ParamCount > 0 Then
...
Application.Run;
end.
Код unit"а главной формы:
...
Const
WM_OPENAPP=WM_USER + 1;
WM_RESTOREAPP=WM_USER + 3;
MyUniqueConst=$773338;
...
Var
WM_FINDINSTANCE:Integer;
...
Protected
Procedure DefaultHandler(Var Message); Override;
Procedure WMRestoreApp(Var Message:TMessage); Message WM_RESTOREAPP;
...
Procedure TFrmMain.WMRestoreApp(Var Message:TMessage);
Begin
SetActiveWindow(Application.Handle);
End;
Procedure TFrmMain.DefaultHandler(Var Message);
Var
S:String;
Begin
With TMessage(Message) Do
If Msg=WM_FINDINSTANCE Then
Begin
Result:=MyUniqueConst;
End
Else
If Msg=WM_OPENAPP Then
Begin
SetLength(S,MAX_PATH);
GlobalGetAtomName(WPARAM,PChar(S),MAX_PATH);
SetLength(S,StrLen(PChar(S)));
...
End
Else
Inherited
DefaultHandler(Message);
End;
...
Initialization
WM_FINDINSTANCE:=RegisterWindowMessage("Any_App: find previous instance");
If WM_FINDINSTANCE=0 Then
Raise Exception.Create("Initialization failed");
Я ему все время говорю, что лучше использовать Семафоры или Мутексы, а он стоит на своем, мол, всегда работало и будет работать. Как вы считаете, действительно ли данный код может обеспечить нормальное функционирование приложения? Возможно ли при аварийном завершении приложения, когда явно не вызывается GlobalFreeAtom, что Атом останется в системе до следующей перезагрузки? Как с этим бороться? Или все-таки лучше не заморачиваться и использовать вышеупомянутые Семафоры с Мутексами? Заранее благодарен всем.
← →
Ihor Osov'yak (2004-01-05 22:58) [1]Что-то код очень запутан... Поэтому ограничусь общими соображениями. Семафоры или Мутексы, етс - объекты ядра и они гарантировано уничтожаются, в случае если приложения, использующие их, закрыли соотв. хендлеры или завершили работу. Причем не важно как завершили - штатно, или аварийно.
В этом первое преимущество именованных объектов ядра для использования в сабжевой цели.
Второе. Есть такое понятие как терминал-сервер. Именованные объекты ядра можно делать и для каждой сессии независимо, и для системы в целом. То есть разработчик может принять оптимальное решение. Для user-обьектов такая гибкость недоступна.
Теперь относительно приведенного кода. Из-за его плохого форматирования нет желания его детально анализировать. Поэтому только то, что видно при беглом взгляде… Атом там все же несет не главную нагрузку - это как бы дополнительный критерий уже после поиска окна по имени класса. Оставлю в стороне несколько оригинальную строку, используемую при создании атома - ParamStr(1))) - может в конкретном случае так и надо.
Но. Поиск перечислением окон относительно медленный. Потом использование SendMessage как бы подразумевает, что уже существующее приложение уже успело запустить свой цикл выборки и находится пока не в “подвисшем” состоянии.. То есть очень много но..
Одним словом – “все-таки лучше не заморачиваться и использовать вышеупомянутые Семафоры с Мутексами”
← →
A. Sonin (2004-01-05 23:00) [2]Большое спасибо за развернутый ответ.
← →
Sir Alex (2004-01-06 03:36) [3]2 A. Sonin
Вот мой примерчик, ИМХО гораздо попроще приведенного:
Файл проекта:
begin
//Check for copy of running program and signalling to it
CheckEvent:= TEvent.Create( nil, false, true, "UFC_CHECKEXIST" );
If CheckEvent.WaitFor( 100 ) = wrSignaled then begin
Application.Initialize;
Application.CreateForm(TfmMain, fmMain);
end else
CheckEvent.SetEvent;
end.
На случай если первая копия программы должна отреагировать на запуск второй, то на главной форме лежит таймер (интервал 1000), и OnTimer:
If (CheckEvent.WaitFor( 100 ) = wrSignaled) then begin
// Например делаем Видимым, если приложение свернуто.
Application.Restore;
Application.BringToFront;
end;
--
Успехов!
← →
Johnmen (2004-01-06 09:28) [4]Пожалуй, самое простое :
...
const
StartEvent: string= "StartMySuperProgramm";
...
SetLastError(0);
CreateEvent(nil,True,True,PChar(StartEvent));
if GetLastError<>0 then ActivateOldInstance
else begin;
Application.Initialize;
...
где ActivateOldInstance процедура активизации уже запущенной копиии (можно опустить...).
← →
Ega23 (2004-01-06 09:38) [5]
var
hnd:THandle;
ss:string;
begin
ss:=ExtractFileName(paramstr(0) );
hnd:=CreateMutex(nil, false, PChar(ss) );
if GetLastError = ERROR_ALREADY_EXISTS then
begin
Beep(100,200); //MessageBeep ->in WinProcs
ReleaseMutex(hnd);
Exit;
end;
Application.Initialize;
........
end.
← →
Johnmen (2004-01-06 09:46) [6]>Ega23 © (06.01.04 09:38)
Небольшая неувязочка : если сделали копию exe-шника с другим именем, то .... :)
← →
Семен Сорокин (2004-01-06 09:51) [7]а я делал обычно через FileMapping
var
_hnd: THandle;
_hnd := CreateFileMapping($FFFFFFFF, nil, PAGE_READONLY, 0, 32, "bla-bla-bla");
if (_hnd <> 0) and (GetLastError = ERROR_ALREADY_EXISTS) then begin
CloseHandle(_hnd);
ExitCode := 1;
Application.Terminate;
Application.ShowMainForm := false;
Exit
end
← →
Ega23 (2004-01-06 09:53) [8]
> Небольшая неувязочка : если сделали копию exe-шника с другим
> именем, то .... :)
Да, забыл. Это специально и сознательно делалось.
Тогда вместо
hnd:=CreateMutex(nil, false, PChar(ss) );
надо
hnd:=CreateMutex(nil, false, PChar("МОЁ_КЛЮЧЕВОЕ_СЛОВО"));
← →
xli (2004-01-06 11:13) [9]А я пришел к выводу (плчитав Рихтера), что по большому счету все равно какой объект ядра (именованный) использовать. И отслеживать его присутствие в системе. Сам пользую FileMapping, больше из-за возможного потом совместного использования своими прогами (ессно до этого руки не дощли... :) )
Страницы: 1 вся ветка
Форум: "Основная";
Текущий архив: 2004.01.16;
Скачать: [xml.tar.bz2];
Память: 0.48 MB
Время: 0.01 c