![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Вторая копия программы ! [D7, NT4, Win2k, WinXP]
Конопелька © (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, ..);
Чтобы, например, передать параметр командной строки в существующую копию программы.