Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 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
1-49494
Cash
2004-01-04 01:12
2004.01.16
Как запустить зарегистрированный файл.


1-49635
Ilg
2004-01-01 16:29
2004.01.16
Заголовок компонента


14-49709
Delirium
2003-12-25 19:01
2004.01.16
Забавный глюк IE


4-49799
Morpheus
2003-11-13 09:01
2004.01.16
Как считать инфу из консольного процесса ?


3-49470
ВК
2003-12-21 00:51
2004.01.16
Как получить индекс самой последней записи в таблице при использо





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский