Может ли окно всегда находиться над одним другим окном?
В 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);
Возможно ли это?
Ответы
Ответ 1
Не создавали бы отношения собственности, трюк?
SetWindowLong(hwndChild, GWL_HWNDPARENT, hwndOwner)
Окна могут быть в разных процессах, и вы можете вызывать это из любого процесса. Это гарантирует, что дочернее окно всегда находится над окном владельца. Это отличается от SetParent, который фактически создает отношения родителя/ребенка. Прочитайте эту статью (ее с 1993 года, но в основном правильнее), чтобы увидеть различие между владением и родительством.
Ответ 2
Когда ваш 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.
Ответ 3
До Vista одним из способов сделать это было бы использование SetWindowsHookEx
, и зацепить крюк WH_CBT
или WH_CALLWNDPROC
, а затем предпринять соответствующие действия при обнаружении изменения порядка Z. Однако это не работает с Vista (насколько я могу судить по googling).
Единственное другое решение, о котором я могу думать, - настроить таймер на огонь каждые несколько секунд, а затем, когда вы получите WM_TIMER
, вы допросите систему, используя GetNextWindow
, чтобы узнать, какое окно находится за вашим. Если это не IE, тогда позвоните SetWindowPos
, чтобы разместить ваше окно над IE (я предполагаю, что у вас есть HWND
для окна IE, о котором вы заботитесь, - помните, что может быть несколько окон IE).
Это вызовет проблемы, если люди попытаются вывести ваше окно на передний план - он вернется к тому, чтобы быть чуть выше IE. В этом случае в вашем коде вы можете обрабатывать WM_ACTIVATE
и попытаться изменить Z-порядок окна IE, чтобы он находился под вашим окном (вызовите SetWindowPos
, чтобы переместить окно IE, чтобы оно было выше окна, которое сейчас находится под вашим окном), Это решение может быть сопряжено с проблемами, поскольку Windows может попытаться помешать вам возиться с окнами другого процесса по соображениям безопасности. С другой стороны, в документах MSDN для SetWindowPos
явно не упоминается, что вы не можете манипулировать окнами другого процесса. Однако могут быть и неясные ограничения.
Даже при этом взломе таймера у вас будет эффективный цикл ожидания ожидания в приложении (с частыми сообщениями WM_TIMER), и это обычно означает bad, особенно для время автономной работы ноутбуков и т.д. (потому что вы не позволяете процессору перейти в состояние ожидания и т.д.).
Я бы сказал, что нет хорошего способа сделать это, и все, что вы, вероятно, получите, будет хрупким и вызовет проблемы. Я настоятельно рекомендую не пытаться это сделать. Возможно ли сделать вашу программу в виде своего плагина или панели инструментов для IE?
NB Особо следует знать, что SetWindowsHookEx
накладывает ограничение производительности на уровне всей системы, если вы идете по этому маршруту.
Ответ 4
Ответ Мориса - лучший из того, что здесь, но отсутствует важный шаг. Когда вы вызываете шоу в своем окне, которое вы хотите в качестве наложения, вам нужно вызвать метод show с параметром. Вам нужно определить класс, который реализует интерфейс IWin32Window, и просто создать новый экземпляр этого. Единственное, что касается интерфейса - это Handle, поэтому просто установите его в дескриптор окна IE, и он должен работать довольно хорошо.
Ответ 5
Можете ли вы получить доступ к Z-порядку окон?
Я не могу вспомнить по умолчанию z-порядок окон, но я думаю, что это 1. Вы могли бы установить IE в -1 и ваше приложение на 0.
Ответ 6
Попробуйте следующее:
// Place window A on top of window B
SetWindowPos(hWndA, hWndB, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
Второй параметр дескриптора окна указывает следующее окно в порядке Z.
Обратите внимание, что это фактически не изменяет отношения родитель-потомок окна, но вы можете имитировать его.
Ответ 7
Если отношения родитель-ребенок выполняются самостоятельно с помощью функции SetWindowPos(), ваше желание может быть реализовано.