• Авторизация


Скрытые возможности MFC 25-11-2009 12:16 к комментариям - к полной версии - понравилось!


Я уже давно решил не использовать MFC в своих программах. Новые программы пишу под чистым Windows API. Но иногда бывают моменты, когда нечто легко доступное с MFC, трудно сделать с помощью WinAPI. Как например, то, что будет описано ниже.

Предположим, MFC-приложение открыло какой-то модальный диалог, например About box. Как известно, при этом основное окно приложения блокируется до тех пор, пока диалог не будет закрыт. В том числе основное окно приложения нельзя минимизировать, переместить, закрыть. Пока что все просто и незатейливо.

Допустим, у этого модального диалога имеется кнопка "Minimize". И если ее нажать, то минимизируется не только диалог, но и все окно приложения. Это очень простая на первый взгляд, но очень полезная возможность. Потому что кнопка минимизации основного приложения при этом недоступна, и действие кнопки минимизации диалога на все приложение - это единственная фактически возможность для пользователя убрать приложение с экрана, не закрывая модальный диалог.

Важность этой маленькой функции особенно велика, когда модальный диалог используется для индикации прогресса какой-нибудь долгой операции. Пользователь может минимизировать диалог, а вместе с ним и все приложение, освободив экран для других занятий, пока на заднем плане выполняется долгая операция.

Так вот, при всей простоте этой функции, она доступна только с MFC!!! Если открыть модальный диалог, используя WinAPI, то нажатие кнопки минимизации этого диалога минимизирует только сам диалог, а заблокированное приложение остается на экране! Причем диалог минимизируется не в панель задач (как приложение), а в левый нижний угол экрана. Ужас. Не сразу и понятно, что нужно сделать, чтобы вернуть работоспособность приложению. Ведь нужно найти этот маленький прямоугольник внизу слева, развернуть его и потом уже закрыть модальный диалог.

Попытка решить задачу "в лоб" наткнулась на странное противодействие винды. Поначалу я решил обрабатывать сообщение "WM_SYSCOMMAND(SC_MINIMIZE)", и из обработчика слать то же самое сообщение родительскому окну диалога (т.е. окну приложения). Но как бы не так! Это действие не приводит ни к какому результату вообще. Обычное окно, получая вышеуказанное сообщение, минимизируется, а заблокированное под модальным диалогом окно - нет!

Можно схитрить и разблокировать находящееся под модальным диалогом окно приложения (EnableWindow). Тогда оно станет реагировать на WM_SYSCOMMAND, а также его собственная кнопка минимизации станет доступна. Но вместе с этим станут доступны и все остальные элементы родительского окна, а это противоречит идеологии модальных диалогов (родительское окно должно быть заблокировано).

Можно разблокировать родительское окно временно, послать ему сообщение, а потом снова заблокировать. Это работает, но что-то мне такой подход не нравится. Некрасиво. Модальный диалог при этом тоже не исчезает, как в MFC. Он по-прежнему минимизируется в левый нижний угол экрана. Также при нажатии правой кнопки мыши в панели задач на минимизированном приложении, не появляется того же оконного меню, как это бывало в MFC-приложениях.

Я пытался использовать немодальные диалоги. Собственно говоря, когда MFC-приложение хочет создать модальный диалог, то MFC вызывает функции API для создания немодального диалога, но при этом родительское окно искусственно блокируется и принимается ряд других мер, так что работает это все как обычный модальный диалог. В общем, я попытался сделать похожим образом. Но фиг там. Ничего не изменилось.

Можно, конечно, заткнуть все эти дыры, реализовав какой-нибудь сложный алгоритм обработки минимизации окон. Но меня интересовало не просто решение, а красивое решение. Потому что "просто решение" может неожиданно перестать работать в какой-нибудь следующей версии винды, если в фирме микрософт решат пересмотреть какие-то парадигмы обработки таких ситуаций. Поэтому я решил для начала поизучать исходники MFC.

Потратив пару часов на изучение исходников, я так и не нашел нужного места. Поэтому решил сделать простое приложение из двух модальных диалогов и потрассировать его из отладчика, поставить точки останова на обработчики сообщений и т.д. Пара часов этого занятия тоже не привела к результату. И мне так и не удалось поймать сообщения, которые шлются родительскому окну при минимизации дочернего. А при пошаговой трассировке сообщения WM_SYSCOMMAND к дочернему окну, все приложение вело себя как будто оно было не-MFC (т.е. родительское окно не минимизировалось).

Наконец, я присоединил к приложению "шпион сообщений", чтобы хотя бы посмотреть, какие сообщения шлются к каким окнам в момент минимизации. Данным "шпионом" я пользоваться не люблю, т.к. сообщений обычно шлется много. Чуть мышку двинул - и штук 50 сообщений валится. Потом разгребай их и ищи нужные. Так вот, поставил я шпика, и что вы думаете? Под шпионом приложение работает так же, как мои программы, написанные с использованием WinAPI, т.е. не так, как надо!

Когда я получил этот результат, то у меня закралось в душу подозрение, что такое поведение окон обеспечивается на уровне какого-то механизма совместимости винды со старыми программами, т.е. винда "чувствует" MFC-приложения и исполняет их как-то иначе, чем обычные. Если это в самом деле так, то в исходниках MFC я действительно ничего не найду. Придется, наверное, делать свой собственный сложный и потенциально несовместимый алгоритм.

Может кто-нибудь из читателей знает, в чем тут дело?
вверх^ к полной версии понравилось! в evernote
Комментарии (7):
V_exeR 25-11-2009-13:08 удалить
Увы, не в курсе... А ты на D7 или на чем пишешь?
Пчёлы 25-11-2009-18:49 удалить
А в борландовском VCL реализацию не смотрели? Я погляжу на досуге если что
Optical_Race 26-11-2009-02:07 удалить
V_exeR, а что такое D7? Delphi? Нет, я пишу на C++, использую STL и свою библиотеку классов, которая пополняется по мере необходимости.

Есть у меня один большой проект на MFC, так сложилось исторически, и "слезать" с MFC в нем я наверно уже не буду... Хотя MFC там довольно мало используется, только для реализации интерфейса пользователя.
Пчёлы 26-11-2009-23:44 удалить
Optical_Race, эффект с использованием VCL такой же как и в случае с WinAPI — модальная форма сворачивается влево-вниз, а родительская торчит неактивной, т.е. "правильное" сворачивание характерно только для MFC.
Пчёлы 26-11-2009-23:46 удалить
Так что скорее всего да — алгоритм сидит где-то на уровне самой виды, распознающей MFC приложения и организующих для них полный пансион.
Optical_Race 28-11-2009-06:44 удалить
Пчёлы, спасибо за исследования, теперь буду знать!

А у меня сейчас вообще творится цирк с этими модальными диалогами. Я поставил себе винду-7. Так вот, под ней в некоторых ситуациях в моем приложении, использующем WinAPI, кнопка минимизации дочернего диалога минимизирует и родительское окно! Для этого важно, чтобы никакое другое приложение не было активировано между открытием модального диалога и нажатием кнопки его минимизации.

С другой стороны, в MFC-приложении эта минимизация тоже иногда (почему-то реже) действует так же, как WinAPI. Например, если переместить все приложение на другой экран (у меня 2 экрана) и там открыть модальный диалог и минимизировать его - то минимизируется только он, а не все приложение.

Если различия в поведении связаны с активацией других приложений - то становится понятно, почему у меня шпионы сообщений (и даже SysInternals Process Monitor) влияли на работу MFC-приложения: ведь я активировал программы-шпионы как раз перед нажатием кнопки минимизации диалога.

Не исключено, что эти различия появились в 7-й винде, а в XP все работает несколько иначе. Но мне не на чем сейчас это проверить, нет компа с XP под рукой. А поскольку непредсказуемая работа наблюдается как на MFC-, так и на API-приложениях, то выход, я думаю, один: сделать требуемую функциональность "вручную" один раз и навсегда. И как следует сделать. Фиг с ним, если перестанет работать в будущих версиях винды. Во-первых, если хорошо сделать, грамотно - то не перестанет. А во-вторых, даже решения от Микрософт не очень совместимы с различными версиями винды, так что хуже, чем, есть, уже не будет наверно.
Пчёлы 04-12-2009-15:16 удалить
Optical_Race, возможно в 7ке довели до ума саму реализацию API функции


Комментарии (7): вверх^

Вы сейчас не можете прокомментировать это сообщение.

Дневник Скрытые возможности MFC | Optical_Race - Дневник Optical_Race | Лента друзей Optical_Race / Полная версия Добавить в друзья Страницы: раньше»