Может ли окно быть всегда над одним другим окном? - PullRequest
13 голосов
/ 01 мая 2009

В Windows возможно ли установить окно A таким образом, чтобы оно всегда находилось поверх окна B, но позволяло другим окнам работать в обычном режиме и появляться поверх обоих, когда оно активно.

Другими словами, я хочу отношения между родителями и детьми между двумя окнами. Можно ли это сделать, не делая окно A дочерним по отношению к окну B, в стиле MDI? Окно B не мое (Internet Explorer), и при попытке добиться этого с помощью SetParent.

винты моего диалогового окна А переплетаются.

Я думал, что взломал эту идею из сообщения на форуме MSDN , но, увы, окна A по-прежнему всегда располагаются поверх всего, не только окна B.

// Place window A on top
SetWindowPos(hWndWindow, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
// Place window B underneath it
SetWindowPos(hWndParent, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE);

Возможно ли это?

Ответы [ 7 ]

13 голосов
/ 07 мая 2009

Разве не поможет создание отношений собственности?

SetWindowLong(hwndChild, GWL_HWNDPARENT, hwndOwner)

Окна могут быть в разных процессах, и вы можете вызвать это из любого процесса. Это гарантирует, что дочернее окно всегда находится над окном владельца. Это отличается от SetParent, который фактически создает отношения Parent / Child. Прочитайте эту статью (это с 1993 года, но все еще в основном верно), чтобы увидеть различие между собственностью и воспитанием детей.

4 голосов
/ 04 мая 2009

Когда Z-порядок вашего окна (или размер или позиция) изменяется, он должен получить сообщение WM_WINDOWPOSCHANGING . Если вы обрабатываете это сообщение, у вас есть возможность изменить окончательный Z-порядок (или размер или позицию), в который перемещается окно.

Для иллюстрации в окне hWndA:

case WM_WINDOWPOSCHANGING:
    DefWindowProc(hWnd, msg, wParam, lParam);
    WINDOWPOS *p = (WINDOWPOS*)lParam;
    p->hwndInsertAfter = hWndB;
    p->flags &= ~SWP_NOZORDER;
    return 0;

должен вставлять hWndA после hWndB в Z-порядке каждый раз, когда позиция hWndA изменяется.

2 голосов
/ 04 мая 2009

До Vista одним из способов было бы использовать SetWindowsHookEx, перехватить WH_CBT или WH_CALLWNDPROC ловушку, а затем предпринять соответствующие действия при обнаружении изменения Z-порядка. Однако это не работает с Vista (насколько я могу судить по поиску в Google).

Единственное другое решение, которое я могу придумать, - настроить таймер на срабатывание каждые несколько секунд, а затем, когда вы получаете WM_TIMER, вы запрашиваете систему, используя GetNextWindow, чтобы выяснить, какое окно находится за вашим. Если это не IE, тогда вызовите SetWindowPos, чтобы расположить ваше окно над IE (я предполагаю, что у вас есть HWND для окна IE, которое вас волнует - помните, что может быть несколько окон IE).

Это вызовет проблемы, если люди попытаются вывести ваше окно на передний план - оно снова станет чуть выше IE. В этом случае в вашем коде вы можете обработать WM_ACTIVATE и попытаться изменить Z-порядок окна IE, чтобы он находился ниже вашего окна (вызовите SetWindowPos, чтобы переместить окно IE, чтобы оно находилось над окном, которое в данный момент находится под вашим окном) , Это решение может быть сопряжено с проблемами, поскольку Windows может попытаться предотвратить возникновение проблем с окнами другого процесса по соображениям безопасности. С другой стороны, документы MSDN для SetWindowPos явно не не упоминают, что вы не можете манипулировать окнами другого процесса. Там могут быть неясные ограничения, хотя.

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

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

NB Обратите особое внимание, что SetWindowsHookEx налагает штраф на производительность на уровне всей системы, если вы идете по этому маршруту.

1 голос
/ 08 января 2016

Если отношения родитель-потомок создаются вами самостоятельно с помощью функции SetWindowPos (), ваше желание может быть реализовано.

1 голос
/ 20 июля 2013

Ответ Мориса - лучший из того, что здесь есть, но он пропускает важный шаг. Когда вы вызываете show в своем окне, которое вы хотите использовать в качестве наложения, вам нужно вызвать метод show, у которого есть параметр. Вам нужно определить класс, который реализует интерфейс IWin32Window, и просто создать новый экземпляр этого. Единственное, что заботит интерфейс - это дескриптор, поэтому просто установите его в дескриптор окна IE, и он должен работать довольно хорошо

0 голосов
/ 01 мая 2009

Попробуйте это:

// Place window A on top of window B
SetWindowPos(hWndA, hWndB, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);

Второй параметр дескриптора окна указывает следующее окно вниз в порядке Z.

Обратите внимание, что это на самом деле не меняет оконные отношения родитель-потомок - но вы можете имитировать это.

0 голосов
/ 01 мая 2009

Можете ли вы получить доступ к Z-порядку окон?

Я не могу вспомнить z-порядок окон по умолчанию, но я думаю, что это 1. Возможно, вы сможете установить IE в -1, а ваше приложение в 0.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...