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

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

Вторая копия программы ! [D7, NT4, Win2k, WinXP]


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

Конопелька ©   (2005-12-07 00:12:00) 

Здравтвуйте !
Подскажите пожалуйста исключение варианта запуска второй копии программы !! и что б при повторном запуске программы открывалось уже запущеное мое приложение ! у меня есть несколько примеров но они не совсем меня устраивают ! И подскажите обязательно ли для этого нужно знать название программы !и если его изменить получиться ли исключить запуск второй копии !
И тут же еще один вопрос к этой теме ! есть два приложение - первое простое с двумя кнопками (к примеру ) а второе имеет две формы ! и вот нужно что б по нажатию той или иной кнопки открывалось то или иное окно второй программы (уже запущеной) !
Заранее огромное спасибо за помощь ! ))


gdaujk   (2005-12-08 14:09:00) [1]

Plotnick   (08.12.05 13:07) [70]

Просто мне кажется, что у меня написано покороче.


У кого "короче", тот сидит дома и методически наращивает. Помни: размер имеет значение :-)))

PS: кстати, на счёт "политики M$" и обидчивости некоторых юзеров (Владислав ©   (08.12.05 11:21) [62]). Проанализируйте действия в подобной ситуации Windows Media Player'а (8)...


Leonid Troyanovsky   (2005-12-08 13:46:00) [2]


> Plotnick   (08.12.05 13:07) [70]
> Также, извиняюсь, если повтор. Просто мне кажется, что у


Читать топик c самого начала.
Вдумчиво, внимательно.

--
Regards, LVT.


Plotnick   (2005-12-08 13:07:00) [3]

Также, извиняюсь, если повтор. Просто мне кажется, что у меня написано покороче.

В dpr проекта.


var
 g_hAppMutex: THandle;

function OneInstance: boolean;
begin
 g_hAppMutex:=CreateMutex(nil,false,PChar('MyCoolProga'+IntToStr(GetDesktopWindow)));
 Result:=(WaitForSingleObject(g_hAppMutex,0)<>WAIT_TIMEOUT);
end;

begin
 if OneInstance then begin
   // Здесь код по созданию окон и запуска приложения
 end;
end.


Что касается того, можно ли вытащить приложение на передний экран, то в MSDN я где-то читал, что этого сделать нельзя. То есть в 2000 и ХР приложение будет мигать в таскбаре, но на передний план не выйдет.
Однако есть способ обойти эту проблему - одно приложение может вытащить другое приложение на передний план.  Для этого создается утиля со следующим кодом:


var
 PrevInstHandle: THandle;
 dw: DWord;
 hCurrWnd: HWnd;
 iMyTID,iCurrTID: Integer;

 S: String;
 c: Integer;
begin
 S := ParamStr(1);
 val(S,PrevInstHandle,C);

 SendMessage(PrevInstHandle, WM_SYSCOMMAND, SC_RESTORE, 0);

 SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, @dw, 0);
 SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, nil, 0);
 SetForegroundWindow(PrevInsthandle);
 SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, Pointer(dw), 0);

 hCurrWnd := GetForegroundWindow();
 iMyTID   := GetCurrentThreadId();
 iCurrTID := GetWindowThreadProcessId(hCurrWnd,nil);

 AttachThreadInput(iMyTID, iCurrTID, TRUE);
 SetForegroundWindow(PrevInsthandle);
 AttachThreadInput(iMyTID, iCurrTID, FALSE);
end.


При запуске этой утилиты ей надо в параметрах передать Hanlde гавного окна того приложения, которое надо вытащить на передний план (в строковом виде, ессно). И все. Это работает с гарантией.

ЗЫ. В случае, когда второй экземпляр программы должен поднять первый экземпляр программы и завершить свою работу отдельную утилиту создавать не надо. Это надо только тогда, когда прога должна вытащить саму себя.


Leonid Troyanovsky   (2005-12-08 12:27:00) [4]


> Defunct ©   (08.12.05 11:56) [66]

> Пример с мьютексом в FAQ-Q142 вообще imho недостоин внимания,
>  т.к. возможны сбои в работе из-за проверки по "заголовку
> программы".


Он вполне достоин.
Просто выбор имени оставлен заинтересованным лицам.
Бо, пусть каждый решает оную проблему сам.

--
Regards, LVT.


Leonid Troyanovsky   (2005-12-08 12:18:00) [5]


> RegisterMessage+broadcast будет хуже связки "FindGUID
>  Хотелось бы услышать обоснованный ответ.


В общем: SendMessage vs SendMessageTimeout.
В частности: в приложениях Delphi даже таймеры имеют top-level окно.
И каждое должно ответить, т.е., с переключением контекста.

Т.е., FindWindow лучше, хотя, возможно, еще лучше - EnumWindows.

--
Regards, LVT.


Владислав   (2005-12-08 12:02:00) [6]


> Leonid Troyanovsky ©   (08.12.05 11:36) [65]


Да живите, чего уж там :) Я танком управлять не умею :о)

Останусь при своем, все таки...


Defunct   (2005-12-08 11:56:00) [7]

Leonid Troyanovsky ©   (08.12.05 11:28) [63]

Поясните пожалуйста Вашу точку зрения, а именно чем связка RegisterMessage+broadcast будет хуже связки "FindGUID(FindWindow+GetProp/SetProp)? Хотелось бы услышать обоснованный ответ.

Пример с мьютексом в FAQ-Q142 вообще imho недостоин внимания, т.к. возможны сбои в работе из-за проверки по "заголовку программы".


Leonid Troyanovsky   (2005-12-08 11:36:00) [8]


> Владислав ©   (08.12.05 11:21) [62]

> > А вот народу нифига непонятно, почему, собстна нельзя
> просто
> > вызвать SetForegroundWindow ?

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


Надеюсь, пару минут у нас еще есть? ;)

Позволю себе заметить, что в контексте данного обсуждения,
передача фокуса другому приложению не является преступным,
бо начинается сие деянием юзера по запуску приложения.

Ну, а мы, вполне правы в том, что если юзер хочет приложения,
причем, ожидая его foreground, то он получит его (пусть даже это
будет первый экземпляр, тихо сидевший в бекграунде).
Я бы например, на подмигивание в таком случае просто бы обиделся.

--
Regards, LVT.


Defunct   (2005-12-08 11:35:00) [9]

Владислав ©   (08.12.05 11:21) [62]

С бОльшим удовольствием можно переехать того программиста, чья программа при запуске не всплывет, а либо молчит либо просто "моргает в таскбаре".


Leonid Troyanovsky   (2005-12-08 11:28:00) [10]


> Defunct ©   (08.12.05 10:50) [61]
> > Во-вторых, никаких бродкастов.

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


Я и высказался о конкретно этой задаче.
Особенно в конкретном исполнении.

--
Regards, LVT.


Владислав   (2005-12-08 11:21:00) [11]


> Игорь Шевченко ©   (07.12.05 18:27) [32]
> А вот народу нифига непонятно, почему, собстна нельзя просто
> вызвать SetForegroundWindow ?


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


Defunct   (2005-12-08 10:50:00) [12]

Leonid Troyanovsky ©   (08.12.05 10:33) [60]

> Во-первых, ничего регистрировать не надо.
> Во-вторых, никаких бродкастов.

это во-первых на любителя, а во-вторых зависит от конкретной задачи..

> В-третьих, на сайте Анатолия Подгорецкого есть фак fido7.delphi,
в котором все подробно разложено, какое д.б. окно, как его
искать, как послать WM_COPYDATA и т.д., все в одном юните.

Этот FAQ я читал, очень полезный и занимательный (у меня на него ссылка на рабочем столе лежит), однако, для решения второй стороны сабжевого вопроса - взаимодействие между двумя различными приложениями, мой пример очень даже может пригодиться.

Вам тоже Regards


Leonid Troyanovsky   (2005-12-08 10:33:00) [13]


> Defunct ©   (08.12.05 10:14) [58]


> "Механизм прост как Мир" (C) Ордынская

Простота мира зависит от простоты наблюдателя.
Скажем, слабый антропный принцип (в моем упрощении).

> Регистрируется сообщение с уникальной идентификационной
> строкой, и отправляется всем окнам. Если в системе присутствует
> Ваша программа, то она ловит это сообщение и шлет

Ну, видимо, почитать предыдущее следовало бы.
Во-первых, ничего регистрировать не надо.
Во-вторых, никаких бродкастов.
В-третьих, на сайте Анатолия Подгорецкого есть фак fido7.delphi,
в котором все подробно разложено, какое д.б. окно, как его
искать, как послать WM_COPYDATA и т.д., все в одном юните.

Q-142: Как избежать повторного запуска моего приложения?

--
Regards, LVT.


Defunct   (2005-12-08 10:24:00) [14]

Defunct ©   (08.12.05 10:14) [58]

Пример можно значительно сократить, выбросив переменную CanInitialize и все что с ней связано, если Application.Terminate вставить непосредственно в обработчик WM_DONTINITIALIZE.


Defunct   (2005-12-08 10:14:00) [15]

Извините если повторю чей-то ответ, всю ветку не читал.

> Подскажите пожалуйста исключение варианта запуска второй копии программы

"Механизм прост как Мир" (C) Ордынская
Регистрируется сообщение с уникальной идентификационной строкой, и отправляется всем окнам. Если в системе присутствует Ваша программа, то она ловит это сообщение и шлет ответ, мы получаем этот ответ, шлем назад конкретному окну требование "всплыть", а сами потихому уходим (Application.Terminate либо Halt). Пример:

unit unit1;

interface

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

const
 WM_DONTINITIALIZE = WM_USER + 0;
 WM_BRINGTOFRONT = WM_USER + 1;

type
 TForm1 = class(TForm)
   procedure FormCreate(Sender: TObject);
 protected
   procedure WndProc(var Message: TMessage);override;
 end;

implementation

{$R *.dfm}

var
 STARTUP_MSG : Integer;
 CanInitialize : boolean;

procedure TForm1.FormCreate(Sender: TObject);
begin
 CanInitialize := true;
 STARTUP_MSG := RegisterWindowMessage('SAT_SERVER StartUP message');

 if STARTUP_MSG = 0 then
    ShowMessage('Не удалось зарегистрировать сообщение'+#13+#10+
                'для пресечения повторного запуска программы');
 SendMessage(HWND_BROADCAST, STARTUP_MSG, Handle, 0);

 if CanInitialize then
    begin
       ShowMEssage('запуск программы возможен');
       //Initializing
    end
 else
    begin
       ShowMessage('Обнаружена ранее запущенная копия программы, фокус передан ей');
       Application.Terminate;
    end;
end;

procedure TForm1.WndProc(var Message: TMessage);
begin
 if Handle <> Message.WParam then
 if Message.Msg = STARTUP_MSG then
       SendMessage(Message.WParam , WM_DONTINITIALIZE, Handle, 0)
 else
 case Message.MSG of
    WM_DONTINITIALIZE:
       begin
          CanInitialize := False;
          SendMessage( Message.WParam, WM_BRINGTOFRONT, Handle, 0);
       end;
    WM_BRINGTOFRONT:
       begin
          Show;
          Application.BringToFront;
       end;
 end;
 inherited WndProc(Message);
end;

end.


Leonid Troyanovsky   (2005-12-08 09:18:00) [16]


> gdaujk ©   (07.12.05 22:47) [52]

> PS: Зачем
> SendMessage(h, WM_COPYDATA, ..);


Кста,  я хотел написать ahwnd, т.е., то, что сохранялось в мапинге.
Ну и SetForeground, видимо, ему же.

--
Regards, LVT.


Leonid Troyanovsky   (2005-12-08 09:15:00) [17]


> gdaujk ©   (07.12.05 18:52) [37]

> А говорили: "... ни с кем не поделюсь" :-)



Я имел ввиду только реализации ForceForeground.
И даже обосновал :)

--
Regards, LVT.


Leonid Troyanovsky   (2005-12-08 09:12:00) [18]


> gdaujk ©   (07.12.05 21:01) [48]
> А с семафорами точно намного лучше, вроде полная независимость
> от версии Windows!!! Хотя пробовал только на XP.
>
> Выкладывать не стану, кто хочет - сам напишет. А написать
> очень советую...


С семафором я пошутил.
Дело в том, что параметр там LONG >= 0.
А хендлы, скажем, в 98, могут иметь значения и больше $7FFFFFFF.
Насчет XP, w2k не уверен, но и про гарантии ничего не слышал.

Кроме того, семафор неудобен тем, что обращение к нему
придется синхронизировать тем же мьютексом, для того,
чтобы избежать разрыва между wait & release.

Ну, а вариант с маппингом я бы советовал выложить.
Во-первых, взгляд со стороны в нашем деле не лишний.
А, во-вторых, это, IMHO, довольно частый вопрос.

--
Regards, LVT.


gdaujk   (2005-12-08 06:46:00) [19]

>Eraser ©   (07.12.05 23:40) [53]

Вобщем-то да, я об этом не подумал.

>gdaujk ©   (07.12.05 22:47) [52]

>А кусок ... под Win98/ME точно будет работать?

С учётом Leonid Troyanovsky ©   (07.12.05 18:48) [36]вопрос снимается, ибо "The process was started by the foreground process" => "A process can set the foreground window"...


Eraser   (2005-12-07 23:40:00) [20]


> gdaujk ©   (07.12.05 22:47) [52]


> PS: Зачем
>
> SendMessage(h, WM_COPYDATA, ..);

Чтобы, например, передать параметр командной строки в существующую копию программы.


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

Наверх

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