Parent-ы и Owner-ы
От: kero Россия  
Дата: 05.08.07 16:51
Оценка: 14 (4)
#Имя: FAQ.winapi.ParentOrOwner
Вчера (04.08.07 17:02) была внезапно перенесена модератором из 'MFC' в 'WIN API' ветка 4-х летней давности
Автор: Carc
Дата: 01.10.03
,
с одновременным включением ее (вместе с еще более древней на ту же тему
Автор: Долгов Сергей Сергеевич
Дата: 14.01.02
) в 'WIN API — Q&A'.

Это событие заставляет меня прервать бесконечное вынашивание одной идейки и разродиться ею незамедлительно.

Дело в том, что наряду с часто повторяющимися вопросами и ответами —
есть еще и часто повторяющиеся ошибки и неточности в этих вопросах и ответах.
И эту словесную муть следовало бы прикончить "весомо, грубо, зримо": специальными наглядными тулзами.

Т.е. вот оно, мое предложение: пристроить к 'WIN API — Q&A' тулзопарк.

И вот первый туда кандидат: ParentOwner, на тему перманентной путаницы с Parent и Owner окнами.



В известном смысле в этой путанице повинны GetParent и GetWindowLong/GWL_HWNDPARENT API:

MSDN> The GetParent function retrieves a handle to the specified window's parent or owner.

MSDN> GWL_HWNDPARENT Retrieves a handle to the parent window, if any. // но и здесь надо читать "parent or owner" !

По "противоположным" API (SetParent и SetWindowLong/GWL_HWNDPARENT) MSDN как будто имеет целью запутать окончательно:
справка противоречива и опровергается практикой самой MS, причем SetWindowLong/GWL_HWNDPARENT по сути рекомендовано не пользоваться...

Еще один момент, вносящий свой вклад в общую картину: в справке по Get* API "owner" фигурирует, а в справке по Set* API — о нем ни-гу-гу...
Зато сильно поотдаль объявляется, что Owner-а окно получает раз и навсегда: при своем зачатии.

Короче, однажды решил во всем этом разобраться, и пришел к следующим выводам:

1) Для точного разделения получаемых Parent и Owner надо пользоваться другими API: GetWindow/GW_OWNER и GetAncestor/GA_PARENT.

2) SetParent устанавливает именно отношения Parent/Child, причем речь не о WS_CHILD у Child-а, а о привязанности Child-а к клиентской области Parent-а.

3) GetWindowLong/GWL_HWNDPARENT, оказывается, на самом деле устанавливает отношения Owner/Owned, и ясен пень — как только, так сразу.
Так что согласен с VladD2 2002 года:
>Для SetWindowLong флаг GWL_HWNDPARENT вообще не документирован.
>Однако во всех версиях виндовс это работает (видимо MS сами пользуются этой фичей, ну а другим рекамендуют как безопаснее).

Все это (и кое-что еще, о чем скажу позже) и сконцентрировано в утилитке ParentOwner.
(Естественно, к exe прилагаются хелп и исходник, иначе это не было бы тулзой для WIN API — Q&A).

---
Касаемо вышеупомянутых веток — там указанная путаница налицо:

1)
Gurza>>Или просто указать окну отца, тогда кнопка пропадёт
Gurza>>::SetWindowLong(m_hWnd, GWL_HWNDPARENT, (LONG)::GetDesktopWindow());
Carc>Угу, но а обратно включить? Я вин98 пробовал обратно отца выключить (SetParent(NULL) или же просче ::SetParent((HWND)NULL)),
Carc>кнопичка не проявлялсь снова, может тескбар как-то перерисовать надо?

2)
VladD2>>>>
Приведенный ниже код скрывает/показывает первый попавшийся Notepad (т.е. можно скрывать любое окно... даже не свое).

HWND hWnd = ::FindWindow(_T("Notepad"), NULL);
if(!hWnd)
    return;
// Если окно уже имеет парента...
if(::GetWindowLong(hWnd, GWL_HWNDPARENT))
    // урать его, тем самым показав в таскбаре...
    ::SetWindowLong(hWnd, GWL_HWNDPARENT, NULL);
else
    // иначе ставим его парантом к DesktopWindow, тем самым убирая из таскбара.
    ::SetWindowLong(hWnd, GWL_HWNDPARENT, (LONG)::GetDesktopWindow());


Alexander>>>В МСДН написано, что вместо данной функции с параметром GWL_HWNDPARENT лучше (и желательно) использовать SetWindowParent (),
Alexander>>>но желаемый эффект от вызова последней почему-то не наблюдается, а с SetWindowLong () всё нормально... плз, объясните почему, если можно?

VladD2>>Вроде как SetParent работает только с чильд-окнами...

VladD2>[...] нам пнишлось повозиться с SetWindowLong. В том числе с динамической заменой парента у поуп-ап окон.

---
Между прочим, в коде VladD2 есть неточность.
Да, код будет работать с Notepad.exe, но, например, с Calc.exe — не будет.
Потому как Calc.exe имеет WS_EX_APPWINDOW, который надо предварительно удалить.

Кстати, на скриншоте запечатлен момент назначения легендарному подопытному кролику Owner-ом полу-message-only окна #32774, в результате чего Calc покидает таскбар.

[Продолжение следует...]
По всему, пашиным хозяевам позарез нужна война в Европе
(уверены — к ним не залетит, в предыдущих двух не залетало жеж)
Автор: kero
Дата: 21.07.14
parent owner
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.