Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Ограничение числа экземпляров


Страницы:   1 2 3 4 5

TStas ©   (2006-03-20 14:51:00) 

Читал сегодня статью с форума на эту тему, много это обсуждалось. ОДно мне непонятно: чем вариант с инишкой плох. СПециально только что провери - все отлично работает.
Вот файл проекта:
program Project1;

uses
 Forms,
 Unit1 in 'Unit1.pas', {Form1}
 IniFiles, SysUtils;
{$R *.res}

var
 ini: TINiFile;
 b: Boolean;
begin

 ini:=TINiFile.Create(ExtractFilePath(Application.ExeName)+'Run.ini');
 B:=Ini.ReadBool('Runned', 'Already', false);
 Ini.WriteBool('Runned', 'Already', true);
 if b then
   begin
   Ini.Free;
   Halt;
   end;
 Ini.Free;

 Application.Initialize;
 Application.CreateForm(TForm1, Form1);
 Application.Run;

end. //В нем -то и чииается инишка
А вот файл формы, в нем инишка ставится на место
unit Unit1;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs;

type
 TForm1 = class(TForm)
   procedure FormDestroy(Sender: TObject);
 private
   { Private declarations }
 public
   { Public declarations }
 end;

var
 Form1: TForm1;

implementation
uses IniFiles;
{$R *.dfm}

procedure TForm1.FormDestroy(Sender: TObject);
var
 ini: TIniFile;
begin
ini:=TINiFile.Create(ExtractFilePath(Application.ExeName)+'Run.ini');
Ini.WriteBool('Runned', 'Already', false);
Ini.Free;
end;

end.
ВСе работает. МОжет, в каких-то сложных случаях что-то не так?


Defunct   (2006-03-31 09:10:00) [21]

>> Вообще-то чем выпендриваться с сочуствиями, лучше бы ответить
> Что мне лучше, я уж сам решу.
> И попрошу следить за речью.

И я сам решу каким тоном мне и с кем разговаривать.
Пост [54] заслуживает еще более грубого ответа.
Я люблю прямоту, а не общение с помощью намеков, которое только усложняет фильтрацию смысла из текста.

> Они есть там, IMHO, начиная с 99 года. Просто, в этой статье
> описаны коряво: мол, в 9x/Me, а на самом деле - и в NT5+.
> Поэтому, и говорил я, где надо читать более точный текст.

Кто они?
Если вы об этом:

This method allows SetForegroundWindow on Windows 98/Windows Me and Windows 2000/Windows XP to behave the same as Windows 95 and Windows NT 4.0, respectively, for all applications. The setup application should warn the user that this is being done so that the user isn't surprised by the changed behavior. On Windows Windows 2000 and Windows XP, the call fails unless the calling thread can change the foreground window, so this must be called from a setup or patch application. For more information, see Foreground and Background Windows.

A process that can set the foreground window can enable another process to set the foreground window by calling the AllowSetForegroundWindow function. The process specified by dwProcessId loses the ability to set the foreground window the next time the user generates input, unless the input is directed at that process, or the next time a process calls AllowSetForegroundWindow, unless that process is specified.

The foreground process can disable calls to SetForegroundWindow by calling the LockSetForegroundWindow function.


тогда либо вы, либо я неправильно понимаем написанное в MSDN. Конкретно мое приложение не использует LockSetForegroudWindow, соответственно никаких проблем на которые вы так упорно уже 4-й раз намекаете, но прямо ничего не говорите, быть не может.


Leonid Troyanovsky   (2006-03-31 08:50:00) [22]


> Eraser ©   (31.03.06 02:11) [69]


> Насчёт целесообразности запрета запуска второй копии. Есть
> ситуации когда это необходимо, например любой сервер, который
> слушает определённый порт.

Если необходимо, откроет его эксклюзивно - более ничего
и не требуется (в смысле ограничений). См. ранее по топику.

> разговоров тоже не было. Всё зависит от типа приложения.

Не только от типа, а и от поставленной задачи.
Т.е., если это поиски решений, искусственно ограничивающие
функциональность программы (типа: ваших денег хватило только на
одну копию), то эта постановка бредовая, ее и обсуждать нех.
 
> Если данное приложение имеет документо-ориентированную структуру
> (типа ворда/экселя/винэмпа), то следует применять подход,
>  при котором нам нужно каким то образом сообщить другому
> приложению о запуске второй копии.

Я недавно приводил ссылку на такое решение.

> юзеру (например через мессадж бокс). Иначе если первая копия
> повисла (и при этом не видно её окон), а вторая просто не
> будет запускаться - это приведет юзера в шок и панику :-

Если повисла, то, конечно, сообщить об этом юзеру,
запускать или запускать вторую копию - решать ему.

> замечу, что с окном первого экземпляра ничего не происходит,
>  т.е. его не пытаются переместить на первый план.

И почему же его не переместить? Может не умеют? :)

Юзер пускает приложение из проводника, комстроки и т.д., т.е.
из foreground приложения.
Приложение, запускаемое из foreground приложения будет foreground,
если не делать специальных усилий.
Поэтому юзер вправе рассчитывать, что ему покажут желаемое
именно foreground . Кстати, на совершенно законных основаниях.

--
Regards, LVT.


Leonid Troyanovsky   (2006-03-31 08:31:00) [23]


> Defunct ©   (30.03.06 19:28) [64]


> Вообще-то чем выпендриваться с сочуствиями, лучше бы ответить

Что мне лучше, я уж сам решу.
И попрошу следить за речью.

> MSDN (April 2003) который у меня установлен нет никаких
> restrictions на использование SetForegroundWindow.

Они есть там, IMHO, начиная с 99 года. Просто, в этой статье
описаны коряво: мол, в 9x/Me, а на самом деле - и в NT5+.
Поэтому, и говорил я, где надо читать более точный текст.

> > использованием mmf vs mutex, в который и писать нужный
> хендл.

> А какой смысл в этом? Если только ваши предрассудки, то

Потому, что это проще, чем использовать бродкаст.
Да и, еще, в дельфийских приложениях даже таймер
имеет окно верхнего уровня.

--
Regards, LVT.


Defunct   (2006-03-31 04:04:00) [24]

Alexander Panov ©   (31.03.06 02:05) [68]

Ваши вроде бы простые вопросы совсем сбили меня с толку..[71] Можете не читать, он был написан, когда я был на своей волне и подумал, что в вопросах тот же контекст, который закладывал Piter(C) выше...

> Не может быть так, что другое приложение ответит на Broadcast?

Нет не может, т.к. зарегистрированное сообщение задается уникальной строкой также как и mutex. Естественно, если Вы зарегистрируете сообщение с именем, которое уже кем-то используется, то тогда есть вероятность что ответит какое-то другое приложение. При этом если рассматривать [34], то это приложение точно не выполнит требуемую цепочку действий, необходимую для закрытия нашего приложения. Т.е. оно не пошлет сообщение WM_DONTINITIALIZE с Handle окна в WParam.


> Что если этим методом пользуются сразу 2 разных приложения?

Ничего, одно приложение работает с одним сообщением, другое - с другим. Друг-другу они мешать не будут.


Defunct   (2006-03-31 03:39:00) [25]

> Что если этим методом пользуются сразу 2 разных приложения?

Если речь о разных типах приложений.. Дык тогда разные сообщения пусть регистрируют.
RegisterWindowMessage('Тип программ 1')
RegisterWindowMessage('Тип программ 2')


Defunct   (2006-03-31 03:34:00) [26]

Alexander Panov ©   (31.03.06 02:05) [68]

Ничего страшного не произойдет.. Windows все равно один broadcast разошлет раньше другого, а дальше там сплошной блок (с помощью SendMessage). Одно приложение тихо удалится, и на второй броадкаст просто некому будет "отвечать".


Германн   (2006-03-31 02:31:00) [27]


> Eraser ©   (31.03.06 02:11) [69]
>
> хе-хе.. ну и раздули жи ветку )
> скажу и я своё imho )


А стоило ли влезать? Заклюют! Имхо.
И так-то была напряжёнка. Да ещё Саша Панов проснулся. :-) Извини Саша, но иного термина у меня не нашлось. :-(


Eraser   (2006-03-31 02:11:00) [28]

хе-хе.. ну и раздули жи ветку )
скажу и я своё imho )

Насчёт целесообразности запрета запуска второй копии. Есть ситуации когда это необходимо, например любой сервер, который слушает определённый порт.

Насчёт способа определения существования второй копии. Тут ессено единственно правильного варианта нету, иначе бы столько разговоров тоже не было. Всё зависит от типа приложения.
Если данное приложение имеет документо-ориентированную структуру (типа ворда/экселя/винэмпа), то следует применять подход, при котором нам нужно каким то образом сообщить другому приложению о запуске второй копии.
Если приложение не документо-ориентированное, то следует использовать простой именованый объект ядра, но при этом, если вторая копия существует обязательносообщить об этом юзеру (например через мессадж бокс). Иначе если первая копия повисла (и при этом не видно её окон), а вторая просто не будет запускаться - это приведет юзера в шок и панику :-)

В документо-ориентированных приложениях лучше, в данном случае, применять гибридную тактику, т.е. несколько разных подходов, как например это сделано в браузере Opera. Если браузер подвис, то при запуске второй копии, если не возможно передать адрес страницы в первую - высвечивается мессадж бокс, что мол одна копия проги уже запущена, если же первый экземпляр работает нормально, то в нём открывается нужная страница, а вторая копия спокойно уничтожается, при этом замечу, что с окном первого экземпляра ничего не происходит, т.е. его не пытаются переместить на первый план.


Alexander Panov   (2006-03-31 02:05:00) [29]


> Defunct ©   (31.03.06 01:42) [67]


По поводу кода в [34]:

Не может быть так, что другое приложение ответит на Broadcast?
Что если этим методом пользуются сразу 2 разных приложения?


Defunct   (2006-03-31 01:42:00) [30]

> Alexander Panov [65] & [66]

[34]...


Alexander Panov   (2006-03-30 22:18:00) [31]


> Defunct ©   (23.03.06 12:57) [27]
>
> Я для этой цели использую RegisterWindowMessage, при старте
> посылаю сообщение всем окнам, если в системе уже запущена
> копия программы, то словив это сообщение она выдвигает себя
> на передний план, и отсылает только что запущенной программе
> сообщение, чтобы та себя закрыла.


Вот критика этого метода:

1. Какой смысл в RegisterWindowMessage, если получающая программа не знает, какое сообщение обрабатывать?
2. Пример выдвижения программы самой себя тоже неплохо бы увидеть;)
3. Для того, чтобы только что запущенная вторая копия могла обработать сообщение, должно хотя бы быть создано хотя бы одно окно в приложении. Таковым является для VCL MainForm. Но в MainForm.OnCreate Может быть проделана масса предварительной работы до того, как окно получит и обработает сообщение, чего никак нельзя допускать.


Alexander Panov   (2006-03-30 21:54:00) [32]


> Defunct ©   (30.03.06 19:28) [64]
</I
> проще продолжать использовать HWND_BROADCAST.

>

Ну так приведи рабочий пример;)


Defunct   (2006-03-30 19:28:00) [33]

Leonid Troyanovsky ©   (30.03.06 09:08) [54]

Вообще-то чем выпендриваться с сочуствиями, лучше бы ответить на конкретный вопрос.

MSDN полный у меня установлен локально, и по инету мне шариться не приходится в поиске описания той или иной функции. В MSDN (April 2003) который у меня установлен нет никаких restrictions на использование SetForegroundWindow.

> Leonid Troyanovsky ©   (30.03.06 18:59) [63]
> Есть еще и класс. Кстати, ранее я предлагал, как это обходится -
> использованием mmf vs mutex, в который и писать нужный хендл.

А какой смысл в этом? Если только ваши предрассудки, то проще продолжать использовать HWND_BROADCAST.


Leonid Troyanovsky   (2006-03-30 18:59:00) [34]


> Alexander Panov ©   (30.03.06 16:31) [61]


> В этом варианте при не поднимется на передний план.
> Конечно, перед SetForegroundWindow можно выполнить ShowWindow(H,
> SW_SHOW),

Если речь про [58], то там не совсем точно, т.е. нужно SFW для
окна приложения.

procedure ActivatePrevInstance(wnd: HWND);
var
 h : HWND;
begin
 h := GetWindowLong(wnd, GWL_HWNDPARENT);
 if IsIconic(h) then
   ShowWindow(h, SW_RESTORE);
 SetForegroundWindow(h);
end;



> такой вариант исключает находждение окна:


Есть еще и класс. Кстати, ранее я предлагал, как это обходится -
использованием mmf vs mutex, в который и писать нужный хендл.

--
Regards, LVT.


Alexander Panov   (2006-03-30 16:32:00) [35]

>Leonid Troyanovsky ©   (30.03.06 15:14) [60]

А необходимость в динамическом изменении хинта к приложению возникает довольно часто для отображения нужной информации во всплывающем хинте приложения на панели задач.


Alexander Panov   (2006-03-30 16:31:00) [36]


> Leonid Troyanovsky ©   (30.03.06 14:37) [58


В этом варианте при не поднимется на передний план.
Конечно, перед SetForegroundWindow можно выполнить ShowWindow(H,SW_SHOW), но вот такой вариант исключает находждение окна:

procedure TForm1.FormCreate(Sender: TObject);
begin
 Application.Title := 'test';
end;


Leonid Troyanovsky   (2006-03-30 15:14:00) [37]


> Рафик ©   (30.03.06 14:56) [59]

> Винда позволяет запускать в одной сессии из под разных пользователей


И, что?

Окна, расположенные на однов десктопе, доступны для перечисления
EnumWindows, EnumThreadWindows & etc.
Объекты ядра могут иметь локальные имена (в пределах сессии),
а также и глобальные, с префиксом Global\, на все.

--
Regards, LVT.


Рафик   (2006-03-30 14:56:00) [38]


> Разные пользователи работают в разных сессиях.

Винда позволяет запускать в одной сессии из под разных пользователей


Leonid Troyanovsky   (2006-03-30 14:37:00) [39]


> Alexander Panov ©   (30.03.06 12:12) [57]

> А дальше уже можно критиковать.


Я уже привел, по-крайней мере, два варианта.
Если хочешь, вот и третий:

=== Вариант с Мьютексом ===
В файле проекта (.dpr) прямо можешь написать нечто вроде:

uses windows,...
var
 H: THandle;
begin
 H := CreateMutex(nil, True, 'уникальное_имя_для_твоей_проги');
 if GetLastError = ERROR_ALREADY_EXISTS then
 begin
   H := FindWindow(nil, 'название заголовка окна программы');
   SetForegroundWindow(H);
   Exit;
 end;
 Application.Initialize;
 Application.Title := 'название заголовка окна программы';
 Application.CreateForm(TAppData, AppData);
 Application.CreateForm(TMain, Main);
 Application.Run;
 CloseHandle(H);
end;


Прочко Денис Владимирович.
sysadmin@)farmeko.khv.ru

Для критики все готово.

--
Regards, LVT.


Alexander Panov   (2006-03-30 12:12:00) [40]

Что вы спорите?
Предлагаю корректно реализовать эту задачу с такими начальными условиями:

1. Возможен запуск только одной копии программы.
2. Если копия программы запущена, переместить запущенный экземпляр на передний план.
3. ОС - Windows 2000 и выше.
А дальше уже можно критиковать.

PS.
Приложение оконное.


Страницы:   1 2 3 4 5

Наверх

Титульная страница Поиск, карта сайта Написать письмо