2010-02-12 3 views
4

Недавно я проверил графический интерфейс с Microsoft Spy ++ и заметил странную структуру; Выглядело это (предупреждение, ASCII искусства впереди):Как я могу обойти асимметрию GetParent/EnumChildWindows?

 
| 
+ 002004D6 "MyRootWindow1" FooClassName 
| | 
| + 001F052C "MyChildWindow" ClassOfChildWindow 
| 
\ 001D0A8C "MyRootWindow2" SomeOtherClassName 

Есть два корня окна, 002004D6 и 001D0A8c, бывший один из которых имеет одно дочернее окно, 001F052C.

Теперь, это было бы все хорошо, и найти, если это не было для одной вещи: вызов GetParent (или смотреть «Родительское окно» или поля «Владелец окна» в Spy ++) на дочернем окне (001F052C) дает 001D0A8C ,

Читайте: «MyChildWindow» является дочерним положением «MyRootWindow1», но «MyRootWindow1» не является родительским элементом «MyChildWindow». Вместо этого родителем «MyChildWindow» является «MyRootWindow2», но, чтобы сделать это полным, перечисление детей «MyRootWindow2» не дает «MyChildWindow».

Это совершенно статическое приложение графического интерфейса, поэтому здесь нет условий гонки.

Кто-нибудь знает, как это может произойти? Кто-нибудь знает, как я могу обойти это? До сейчас я использовал GetParent и EnumChildWindows, чтобы получить родительский (или дочерний) для данного HWND, и я предположил, что это соотношение является симметричным. Может быть, что-то еще я должен использовать?

EDIT: Вот код программы небольшой C++, который демонстрирует проблему:

const HINSTANCE thisModule = ::GetModuleHandle(NULL); 
HWND oldParent = ::CreateWindow(TEXT("STATIC"), 
           TEXT("Old parent"), 
           WS_VISIBLE | WS_BORDER, 
           0, 0, 850, 500, 
           NULL, 
           NULL, 
           thisModule, 
           NULL); 
HWND child = ::CreateWindow(TEXT("STATIC"), 
          TEXT("This is a sample dialog"), 
          WS_OVERLAPPED | WS_POPUP | WS_VISIBLE | WS_BORDER, 
          100, 100, 300, 300, 
          oldParent, 
          NULL, 
          thisModule, 
          NULL); 
HWND newParent = ::CreateWindow(TEXT("STATIC"), 
           TEXT("Fake main window"), 
           WS_VISIBLE | WS_BORDER, 
           0, 0, 850, 500, 
           NULL, 
           NULL, 
           thisModule, 
           NULL); 
::SetParent(child, newParent); 

Обратите внимание, как «ребенок» объект имеет WS_POPUPиWS_OVERLAPPED набор, но не WS_CHILD.

+0

Дочернее окно отсутствует 'WS_CHILD'. Кроме того, возможно (хотя и необычно) иметь родительское окно, отличное от окна вашего владельца. Похоже, вы можете настроить оба для дочернего окна. Можете ли вы дать более подробную информацию о том, что вы пытаетесь выполнить? –

+0

Да, WS_CHILD отсутствует. Я указал это в своем последнем предложении. :-) Показанный код, к сожалению, не под моим контролем. Это часть кода для приложения GUI, которое я хочу изучить. –

ответ

2

Документация GetParent объясняет: «Обратите внимание, что, несмотря на свое название, эта функция может возвращать окно владельца, а не родительского окна.»

Как вы не создаете дочернее окно Я угадываю вы хит этот случай.

Вы должны иметь возможность вызывать GetAncestor, передавая GA_PARENT, как указано в документации: «Извлекает родительское окно. Это не включает владельца, как в функции GetParent».

См Win32 window Owner vs window Parent?

+0

Это не работает в моем случае; GetAncestor (GA_PARENT) по-прежнему возвращает неверный родительский элемент («oldParent» в примере кода). Проблема в том, что вызов SetParent() не обновил ссылку. –

+0

Я в замешательстве относительно того, чего вы пытаетесь достичь - SetParent будет работать, только если вы установите флаг WS_CHILD в дочернем окне перед его вызовом. – morechilli

+0

Да, WS_CHILD отсутствует. Я указал это в своем последнем предложении. :-) Показанный код, к сожалению, не под моим контролем. Это часть кода для приложения GUI, которое я хочу изучить. То, что я пытаюсь достичь, - это возможность получить родителя (или ребенка) любого заданного HWND, даже если иерархия окон разбита, как показано в приведенном выше коде. Вероятно, это означает, что мне нужно эмулировать GetParent с помощью Enum (Child) Windows или наоборот. –

3

Ну, это не имеет большого значения, конечно. Пахнет, как дочернее окно перевоспитывает себя. Это обычная методика в .NET Windows Forms, у нее есть «окно парковки», где дочерние элементы управления могут находить временный дом, когда их окно контейнера необходимо воссоздать, потому что изменился стиль окна. Это не очень заметный эффект, он также временный.

Другой, удаленный, возможность SetParent(). У этого есть appcompat поведение для поддержки старых программ Windows 3.x. Это объясняется довольно хорошо в документах SDK для него, в двух словах окно может быть родительским, но не устанавливать флаг стиля WS_CHILD. Adobe Acrobat Reader является классическим примером программы, которая делает это. Какой эффект, который будет иметь для EnumChildWindows, неясен для меня.

Последнее, но не менее важное: не забывайте, что Spy ++ дает статический вид окон. Для отслеживания изменений важно нажать F5 для обновления списка окон.

Не большие объяснения. Попытайтесь выяснить, действительно ли важно, какое окно верхнего уровня активно, я подозреваю, что это так.

+0

Спасибо за ваш проницательный ответ! Я также рассмотрел проблему с репарацией, но я бы подумал, что это будет правильно обновлять все ссылки (так что действие reparenting уменьшает детей старого родителя на единицу и увеличивает число детей нового родителя на единицу). Я бы не подумал, что можно попасть в такое состояние. Идея с поведением совместимости очень интересная, я посмотрю, смогу ли я найти что-нибудь об этом! –

+0

Полу-релевантный вопрос - существует ли относительно простой способ воссоздать элемент управления или это единственный способ вручную реализовать его для каждого вида контроля? – Mehrdad

+0

Это не относится к афайну. Но что я знаю, зачем спрашивать меня? @morechilli получил одобренное понимание, я просто разместил «Whoa! Отвечает Кинье Ривз. –

Смежные вопросы