Я полагаю, что ваши покадрово диалоги WS_POPUP окна, не так ли? (то есть они являются плавающими окнами, которые могут появляться в любом месте экрана, а не только внутри окна вашего приложения).
Если они плывут окна, то технически они не являются дочерними окнами окна рамы, но в документации, как правило, использовать термин родителя в тех местах, где он должен действительно использовать владелец так это легко запутаться около. Окна для детей не могут появляться за пределами клиентской области их родительских окон. Детское окно будет недействительным, когда его родительское окно будет признано недействительным. Но собственное окно не будет.
Только окна с флагом стиля WS_CHILD могут быть дочерними окнами, в противном случае они принадлежат окнам.
Если это принадлежащие окну, они не будут наследовать недействительность в главном окне приложения, поэтому вам нужно искать места в коде, где есть вызов :: InvalidateRect() с дескриптором NULL в качестве первого параметра , Обычно это происходит из-за неинициализированной переменной.
Когда вы вызываете ::InvalidateRect(NULL, ...)
, это говорит Windows о недействительности всех окон. (он фактически сообщает Windows о недействительности окна рабочего стола, который является родительским для всех окон). В MFC базовый класс для всех окон имеет метод InvalidateRect, который оборачивается и вызывает api windows, но с дескриптором окна текущего объекта. как приближение первого порядка, я думаю, вы можете предположить, что дескриптор этого окна будет инициализирован правильно. Вы должны начать с поиска вызовов в своем собственном коде.
Как только вы получаете OnPaint, слишком поздно знать, откуда пришел запрос о недействительности. Поэтому, чтобы найти эту ошибку, вам придется либо проверить свой код, либо перехватить InvalidateRect()
и искать NULL в первом параметре.
Это серьезная проблема в общем случае, поскольку существует несколько способов аннулирования всего или части окна, а также большого количества кода в файлах заголовков, чтобы «помочь» вам, создав варианты этих функций, которые делают некоторые вещи автоматически.
Возможно, вы попытаетесь установить точку останова в верхней части InvalidateRect
(она находится в user32.dll) и сделать это условным при первом значении параметра. Но в зависимости от того, как настроен ваш отладчик, вам не разрешается делать это.
Вы также можете попытаться скомпилировать весь свой код, чтобы вызовы InvalidateRect перенаправлялись через функцию, которую вы контролируете.
// in some header file that gets included early by all of your code
#define InvalidateRect my_InvalidateRect
// in one of your .cpp files.
BOOL WINAPI my_InvalidateRect(HWND hwnd, CONST RECT *prc, BOOL bErase)
{
#undef InvalidateRect
assert(hwnd != NULL);
InvalidateRect(hwnd, prc, bErase);
#define InvalidateRect my_InvalidateRect
};
Если не находит, а затем сделать то же самое InvalidateRgn
и RedrawWindow
Эти виды ошибок скверны найти. Я не завидую вам. В моем собственном коде у меня есть постоянный запрет на прямые вызовы InvalidateRect, они должны ВСЕГДА проходить через функцию-оболочку, поэтому я всегда могу проверить наличие оконных дескрипторов NULL в отладочных сборках. Но опять же, я не использую MFC, поэтому упростить такую политику проще.
Являются ли немодальные диалоги детьми CMainFrame или CView? – Karim
Хороший вопрос. Это дети из CMainFrame. – Fabian
Я не думаю, что вы сможете определить, кто отправил запрос изначально. Недействительные генерируют сообщение, которое хранится в очереди сообщений Windows, и несколько таких недействительных команд объединяются до момента, когда ваша очередь пуста из других сообщений, а затем ваше приложение получает WM_PAINT. Таким образом, отправка и прием сильно развязаны. Я бы подумал, что вам лучше понять, почему ваше родительское окно (представление) сообщает вашим окнам, чтобы их перекрасить. Детские окна имели бы смысл перерисовывать, но принадлежали окнам? Мне это кажется странным. – Mordachai