Я уже давно решил не использовать 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, т.е. не так, как надо!
Когда я получил этот результат, то у меня
Читать далее...