Отправляет email-рассылки с помощью сервиса Sendsay

Программирование. Форум !!!

Вывод окна приложения на передний план.

Здравствуйте!
Проблема собственнов следующем:
Прога1 и Прога2 связаны внешним СОМ-сервером. В какой-то момент
работы в проге1 нужно безболезненно перейти в прогу2.
Используется следующий механизм: вызывается метод СОМ-сервере,
Старт_прога2. Который проверяет наличие такой проги среди загруженных
и если есть, то окно проги выводит на передний план
(SetForegroundWindow).
Один раз срабатывает, а потом уже не хотит. Может быть дело в том,
что СОМ-сервер используется обоими прогами и при выводе второй на
передний план система не может его вывести, т.к. используется что-то
общее?
Посоветуйте как сделать.

Ответить   Tue, 7 Feb 2006 14:24:59 +0500 (#511967)

 

Ответы:

Здравствуйте, Шистеров.

Tuesday, February 7, 2006, 11:24:59 AM, you wrote:

Не совсем понял сценарий. Значит, прога1 вызывает прогу2 через
СОМ-сервер, и эта прога2 становится "передней". То есть, ловится хэндл
главного окна проги2 и он передается в SetForegroundWindow. А что
потом происходит? В следствии чего окно проги2 перестает быть
передним?

Я два варианта вижу: 1) Какое-либо другое окно преобретает стиль
StayOnTop и 2) У вас хэндл окна проги2 вычисляется задолго до вызова
SetForegroundWindow. Ведь возможна такая модель:

Запустили прогу2
Нашли ее хэндл (h2)
Вывели окно проги2
.........................................
. какой-то вычислительный процесс, ..
.. во время которого прога2 вообще ..
.. могла закрыть и открыть вновь ..
.. свое окно ..
.........................................
Point1:
Пытаемся опять по хэндлу h2 вывести окно проги2 вперед.

Ну так в точке Point1 этой модели h2 корректно по значению, но окна с
таким хэндлом (читайте, номером) нет, если оно успело закрыться и
открыться.

Ответить   Вадим Шешунов Wed, 8 Feb 2006 13:22:09 +0200 (#512413)

 

Здравствуйте, Вадим,

СОМ-сервер нужен для связи прог + некие дополнительные фишки. Общий
случай, когда обе проги запущены и СОМ-сервер знает Хэндлы окон
приложений. В каждой проге есть кнопка "Перейти в соседнню прогу",
которае реализует метод СОМ-сервера. Сервер в свою очередь проверяет
наличие соседнего окна, и если есть, то должен просто вывести его на
передний план.

Обычные приложения. StayOnTop не балуются. Проверено на
приложениях-заглушках.

Верно. Как только прога запустилась, она соединяется с СОМ-сервером и
отдает ему свой Хэндл.

См. выше.

Ответить   Thu, 9 Feb 2006 10:50:31 +0500 (#512725)

 

Ну... более-менее ясно.

И никакие другие сторонние приложения в таком стиле не запускается,
так7 Тогда этот пункт отпадает.

Скажите, а Вы пишете саму серверную часть? Или знаете, как оно там
варится? Извините, если я этого не понял из предыдущих писем - у
самого тут запарка. Я к чему это говорю - такое поведение сервера
довольно странно. Ведь тот, кто выводит чужое окно, должен сам
определить хендл этого окна и без промедлений вывести это окно вперед
- пока нужное окно имеет этот хэндл. В Вашем случае было бы намного
лучше, если бы серверу передавали имя_класса и/или титульную строку
окна, а сервер сам находил хэндл этого окна, проверял бы его на
неравность нулю и тут же выводил это окно вперед.

Ответить   Вадим Шешунов Thu, 9 Feb 2006 12:45:42 +0200 (#512886)

 

Здравствуйте, Вадим,

Да.

Так прекрасно срабатывает без СОМ-сервера, правда на простеньких
тестерах.

Ну-у, на счет титульной строки не соглашусь. А проверку на наличие
окна сервер делает.

Меня терзают сомнения, что виной всему сервер, как промежуточное
звено, связанное с обоими процессами.

Ответить   Fri, 10 Feb 2006 08:39:51 +0500 (#513116)

 

Здравствуйте, Шистеров.

Friday, February 10, 2006, 5:39:51 AM, you wrote:

"Бесхитростных" - таких, которым "не приходит в голову" передать
серверу свой хэндл, а самим "смыться с места преступления"?-)))))

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

Убейте меня, но я уверен, что если SetForegroundWindow не выводит
вперед нужное окно (и вообще никакое), значит ему передан неактуальный
параметр.
В принципе, Вы можете написать для проверки этого такое себе проверочное
приложение, в котором будет тикать таймер и внутри обработчика тиков
это приложение будет следить за окном клиента (которое не хочет
показываться). Только частоту тиков выбирете побольше.

Ответить   Вадим Шешунов Fri, 10 Feb 2006 09:23:48 +0200 (#513159)

 

Здравствуйте, Вадим,

Именно :) Но и безхитростные при работе через СОМ-сервер ведут себя
плохо.

В том-то и дело, что сервер не ищет Хэндлы. Они у него есть. он только
проверяет на существование. если не существует, то запускает заново -
это другая задача и она работает нормально.

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

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

Ответить   Fri, 10 Feb 2006 13:19:00 +0500 (#513195)

 

Функция SetForegroundWindow довольно хитрая и в MSDN ей
посвящена обширная статья.

Если коротко, приложение не может заставить окно стать foreground,
если пользователь работает с другим окном или открыто меню.
В этом случае целевое окно станет активно и будет
мигать в панели задач, но не откроется.

Попробуйте BringWindowToTop.

Номер выпуска : 5185
Возраст листа : 873 (дней)
Количество подписчиков : 546
Адрес в архиве : http://subscribe.ru/archive/comp.soft.prog.prog/msg/513293
Получить правила : mailto:comp.soft.prog.prog-rules@subscribe.ru
Формат "дайджест" : mailto:comp.soft.prog.prog-digest@subscribe.ru
Формат "каждое письмо" : mailto:comp.soft.prog.prog-normal@subscribe.ru
Формат "читать с веба" : mailto:comp.soft.prog.prog-webonly@subscribe.ru

Ответить   Fri, 10 Feb 2006 13:52:08 +0300 (#513293)

 

И это правильно. Помню, как меня бесило в 95-й, когда сидишь,
программируешь или документируешь "вслепую", а потом бросаешь взгляд на
экран и видишь, что уже с полминуты твои клавиатурные танцы направляются
неизвестно кому. MicroSoft как раз и пошла навстречу многочисленным
"пожеланиям" (наверное, имелись ввиду "посылания") пользователей. Теперь,
начиная с 98-й и NT_какой-то_там_SP, SetForegroundWindow() может вынести на
передний план окна только своего же процесса (или нити, не помню точно), а
также специально указанных, как доверенные. Вот как "доверить" - не скажу,
забыл, но точно помню, что в MSDNе видел. И доверение должно было
отрабатывать на стороне того приложения, КОТОРОМУ - а не КОТОРОЕ - будет
делать SetForegroundWindow(). Т.е. приложение само решает, кому ещё, кроме
себя, оно доверит выносить свои окна на передний план.
Есть вариант, когда наоборот, окно выносится на передний план, но фокус
ввода не меняется. Когда отрабатывает так, когда иначе, не знаю. По-моему,
по второму сценарию ведут себя диалоговые окна, а по первому, все остальные,

но не уверен.

--
С уважением, boroda

Номер выпуска : 5187
Возраст листа : 873 (дней)
Количество подписчиков : 546
Адрес в архиве : http://subscribe.ru/archive/comp.soft.prog.prog/msg/513453
Получить правила : mailto:comp.soft.prog.prog-rules@subscribe.ru
Формат "дайджест" : mailto:comp.soft.prog.prog-digest@subscribe.ru
Формат "каждое письмо" : mailto:comp.soft.prog.prog-normal@subscribe.ru
Формат "читать с веба" : mailto:comp.soft.prog.prog-webonly@subscribe.ru

Ответить   Шматко А.А. Fri, 10 Feb 2006 20:26:48 +0300 (#513453)

 

Здравствуйте, Шистеров.

Ну тогда, действительно, остается попробовать BringWindowToTop.

Ответить   Вадим Шешунов Fri, 10 Feb 2006 18:18:23 +0200 (#513433)

 

Здравствуйте !

Попробуйте это (пояснения здесь
http://softmaker.com.ru/sources/functions/arts/bringwindowtoforeground.htm):

BOOL BringWindowToForeground(CWnd *pWnd)
{
if (pWnd == NULL)
return FALSE;

if(!::IsWindow(pWnd->GetSafeHwnd()))
return FALSE;

DWORD dwUserInputTimeout;

::SystemParametersInfo( SPI_GETFOREGROUNDLOCKTIMEOUT, 0,
&dwUserInputTimeout, 0);
::SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, 0, 0);

::SetWindowPos( pWnd->GetSafeHwnd(), HWND_TOPMOST, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE);

HWND hCurWnd;

while((hCurWnd = ::GetForegroundWindow()) != pWnd->GetSafeHwnd())
{
HWND hWndActive = ::GetForegroundWindow();

DWORD dwThreadID = ::GetCurrentThreadId();
DWORD dwCurThreadID = ::GetWindowThreadProcessId(hWndActive,
0);

AttachThreadInput(dwThreadID, dwCurThreadID, TRUE);

pWnd->SetForegroundWindow();

AttachThreadInput(dwThreadID, dwCurThreadID, FALSE);

Sleep(20);
}

::SetWindowPos( pWnd->GetSafeHwnd(), HWND_NOTOPMOST, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE);

::SystemParametersInfo( SPI_SETFOREGROUNDLOCKTIMEOUT, 0,
(LPVOID) dwUserInputTimeout, 0);

return TRUE;
}

Это старая версия функции.
Тут еще надо запоминать TOPMOST-состояние выкидываемого на передний план
окна,
и если оно уже было TOPMOST, то не убирать его. Тут MFC используется -
просто
мне так удобно было. Если что, надо просто вместо pWnd->GetSafeHwnd()
подставлять
дескриптор целевого окна (то, которое на передний план должно вылетать).

Ответить   Sat, 11 Feb 2006 02:03:36 +0300 (#513582)

 

Всем привет!

Значит так:
Шматко, написал, что я примерно и думал. Поскольку в связке участвуют
3 приложения (сом-сервер внешний и прога1 и прога2), то возможно и
происходит описываемое событие. Только немного практика в теорию не
упирается.
Делал так. Приложение с editом и кнопкой. В edit вводится хэндл.
Кнопка отрабатывает SetForegroundWindow. Все работает прекрасно.
А вот если это-же приложение запускать через СОМ-сервер внешний, то
только один раз отрабатывает.

Не знаю как объяснить и тем более не знаю где рыть. Но сдается мне,
что 2 приложения завязаны на 3-ем. Т.е. когда прога1 говорит: "Выведи
мне прогу2", то СОМ-сервере, честно отрабатывает вывод, но он связан с
прогой1 и возвращает результат функции, чем не дает вывести прогу2.

Чисто условно, но что-то такое смутно вращается.
Может как-то по хитрому запустить, например, в независимом потоке из
СОМ-сервера?

Ответить   Mon, 13 Feb 2006 08:52:39 +0500 (#514370)