Parent/Owner Window Relationships

Тема в разделе "WASM.PROJECTS", создана пользователем kero, 13 авг 2006.

  1. kero

    kero Модератор SOURCES & 2LZ Команда форума

    Публикаций:
    0
    Регистрация:
    4 апр 2006
    Сообщения:
    1.074
    Адрес:
    Москва
    ##### Далее - древний текст и древний аттач ######################################

    Эта заметка - поначалу реакция на "КАК УБРАТЬ ОКНО ИЗ STATUS BAR" (http://www.wasm.ru/forum/viewtopic.php?id=15541), а отдельной веткой - потому как утянуло на более широкую тему...

    ---

    cresta:

    > интересно, как удалось вставить окно в статус-бар?
    > Если это всё-таки таск-бар, то удалить кнопку программы из него можно так:
    > 1.создать невидимое окно. 2.это окно сделать парентом видимому окну. 3.всё.

    Вы вот подшучиваете над путаницей, неизбежной у начинающих, а ведь и в Вашем ответе есть, к чему придраться :)

    1) Вставить окно и в статус-бар, и куда угодно - просто, но об этом чуть позже.

    2) СОЗДАВАТЬ невидимое окно - не обязательно, можно воспользоваться и уже существующим в системе.

    3) Ну, а фраза "это окно сделать парентом видимому окну" - вполне способна запутать вконец...

    Поэтому проясним цель: видимое top-level окно с невидимым Owner-ом, именно Owner-ом, а не Parent-ом !

    А установить отношения Owned/Owner можно лишь через СОЗДАНИЕ (CreateWindow*, CreateDialog*, DialogBox*)
    top-level окна с привязкой в поле hWndParent к существующему top-level окну.

    Кстати, в отличие от хрупких отношений Child/Parent - отношения Owned/Owner нерушимы.

    rmn :

    >> как изменить парента у окна
    > SetParent(hwndChild, hwndNewParent);

    Хотя окна с hwndChild и hwndNewParent могут быть top-level без WS_CHILD, -
    SetParent устанавливает отношения Child/Parent, а не Owned/Owner.
    Для отношения Child/Parent ключевое понятие - клиентская область Parent-а:
    Child (у него может и не быть WS_CHILD) отображается только в пределах этой области.
    И если Parent не имеет WS_VISIBLE, то и Child невидим, даже если имеет WS_VISIBLE.

    Что для нашего случая категорически не подходит.

    А подойти может другое: через SetParent установить нашему окну Parent-ом - окно Progman ("Program Manager").

    ---

    Итак, SetParent очень умеет творить чудеса с иерархией окон.
    Но с SetParent надо быть очень аккуратным, и прежде всего - обязательно изучить описание SetParent в MSDN.
    Там серьезные ограничения. Которые небесполезно проверить, хотя бы в учебных целях :)

    Посему прикладываю набросок учебной утилитки с примером:

    [Вставить окно в статус-бар]
    - запускаем ParentOwner.exe (исходник приложен),
    - запускаем блокнот со строкой состояния,
    - наводим курсор на часики (TrayClockWClass) и шлепаем F8,
    - наводим курсор на статусбар (msctls_statusbar32) блокнота и шлепаем F9,
    - убеждаемся, что в строках "Window..." и "Parent..." - то, что надо,
    - нажимаем кнопку "WS_CLIPCHILDREN...", чтобы статусбар получил (+) этот стиль,
    - нажимаем кнопку "SetParent..."
    - и видим живые часики на новом месте.

    Вообще-то утилитка может кое-что еще и расчитана на большее :)

    Вернуть назад - кнопка "Undo", глубина Undo/Redo - 64, при закрытии окна утилитки
    все проводившиеся SetParent автоматом отыгрываются назад (если не надо другого).
    Короткий хелп - в системном меню, а вообще - все в исходнике (masm32).

    Проверено только на XP pro SP2.

    ---

    18.08.06 - поправки в утилитке (заменен .rar)
     
  2. kero

    kero Модератор SOURCES & 2LZ Команда форума

    Публикаций:
    0
    Регистрация:
    4 апр 2006
    Сообщения:
    1.074
    Адрес:
    Москва
    А вот и практический пример модификации чужой программы.

    В очень симпатичном Spy by Kobi (v.2.70) одно неудобно: Finder Tool лежит на закладке.
    Но это легко поправить, вставив SetParent в предварительный loader (см. исходник spy_loader).

    Возможно, это оценит автор Sign-0f-Misery :)
     
  3. kero

    kero Модератор SOURCES & 2LZ Команда форума

    Публикаций:
    0
    Регистрация:
    4 апр 2006
    Сообщения:
    1.074
    Адрес:
    Москва
    Более продуманная версия учебной утилитки ParentOwner.

    1) Добавлен комбобокс, в который загружается дерево окон через один из следующих фильтров (нажатием одной из кнопок):
    - все окна (включая все message-only окна),
    - все окна процесса выбранного парента/оунера,
    - все окна потока выбранного парента/оунера,
    - все top-level окна (включая все верхние message-only окна).

    Выбор окна - правым, а выбор парента/оунера - левым кликом по строке листа комбобокса.
    Или же наведением курсора + F8 (окно) или F9 (парент). Причем при F9 -
    координаты курсора относительно парента задают будущую позицию (дочернего) окна.

    (О message-only окнах - http://www.wasm.ru/forum/viewtopic.php?id=14302&p=1 , пост #24).

    2) Добавлена кнопка "sWaP" для перестановки строк Window и Parent|Owner (при отмеченном чекбоксе "lock").

    3) Теперь при нажатии кнопки "SetParent" сохраняются не только хендл окна и хендл его прежнего парента,
    но и style, exstyle и клиентские координаты окна относительно прежнего парента (не более 64 таких структур).

    4) Добавлена кнопка "CreateWindowEx", с помощью которой легко построить цепочки окон с любыми комбинациями отношений парент/оунер
    (старые кнопки "CreateDialog" и "DialogBox" для этого не годятся).

    5) Добавлено раздвоение/объединение интерфейса по двойному клику, просто как пример применения SetParent.

    ------

    Ну, и несколько экспериментов.

    1)
    Жмем кнопку "All",
    где-то внизу открывшегося листа комбобокса находим строчку с "#32774",
    угощаем ее левым кликом,
    после чего жмем кнопку "min/".

    А теперь наведите курсор на любую из стандартных кнопок заголовка любого окна... Ничего-ничего, кнопка "min/" все поправит :)

    2)
    Попробуйте назначить этому же message-only #32774 парентом десктоп (т.е. HWND_DESKTOP или #32769 из комбобокса)...

    3)
    Spy++ сообщает, что у окна "О программе "Калькулятор"" и парент, и оунер - это "главное" окно "Калькулятор".
    Но это враки. Парент - это десктоп (#32769), гляньте-ка в ParentOwner :)

    Чтобы построить окно, у которого на самом деле парент = оунеру, -

    запускаем ParentOwner,
    жмем кнопку "CreateWindowEx",
    жмем кнопку "sWaP",
    жмем кнопку "CreateWindowEx",
    жмем кнопку "SetParent".

    Искомое окно - "Window 2".

    4)
    А теперь самое занятное.

    В только что построенном окне "Window 2" жмем кнопку "WS_POPUP",
    после чего текст кнопки меняется на "not WS_POPUP", а окно "Window 2" лишается стиля WS_POPUP.
    Нажатие на кнопку "not WS_POPUP" все восстановит.

    Так вот: понажимайте эту кнопку и одновременно понаблюдайте за строкой "GetParent" в окне ParentOwner...

    Вам не кажется, что с функцией GetParent не все в порядке ? :)

    --------
    2011-12-08
    хехе, вот и R.Chen, наконец, высказался по этому вопросу:

    GetParent, just as confusing as EnumClaw, but it's an actual function!
     
  4. kero

    kero Модератор SOURCES & 2LZ Команда форума

    Публикаций:
    0
    Регистрация:
    4 апр 2006
    Сообщения:
    1.074
    Адрес:
    Москва
    Updated: ParentOwner v.2007-03-27 (exe + asm + help)
     
  5. kero

    kero Модератор SOURCES & 2LZ Команда форума

    Публикаций:
    0
    Регистрация:
    4 апр 2006
    Сообщения:
    1.074
    Адрес:
    Москва
    + screenshot
     
  6. kero

    kero Модератор SOURCES & 2LZ Команда форума

    Публикаций:
    0
    Регистрация:
    4 апр 2006
    Сообщения:
    1.074
    Адрес:
    Москва
    Updated: v.2009-06-04

    1) Устранен баг с текст.буффером и
    2) добавлен чекбокс для настройки внутреннего оконного искателя:
    использовать в нем RealChildWindowFromPoint или же ChildWindowFromPointEx
    (т.е. теперь учтен случай предка с чудовищным WS_EX_LAYOUTRTL).