Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2004.01.16;
Скачать: CL | DM;

Вниз

Эффективный способ предотвращения запуска второго экземпляра   Найти похожие ветки 

 
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;
Скачать: CL | DM;

Наверх




Память: 0.5 MB
Время: 0.036 c
3-49385
Rafe
2003-12-21 21:39
2004.01.16
Простой метод просчета сумм значений выделенных строк


1-49637
Duke DEE
2004-01-04 15:20
2004.01.16
C++ ==> Delphi


14-49729
Daemys
2003-12-24 17:52
2004.01.16
Кандидаты в президенты


1-49512
Rimd
2004-01-03 11:45
2004.01.16
StringGrid


1-49556
Prospector
2004-01-06 08:58
2004.01.16
StatusLine