2009-12-11 1 views
0

Приложение MFC имеет CView и пару плавающих немодальных диалогов. В настоящее время я пытаюсь понять, почему недействительность/перерисовка моего представления также вызывает перерисовки диалогов. Это даже происходит, если диалоги не перекрываются с представлением.Как отлаживать/отслеживать, когда диалог недействителен?

Кто-нибудь знает, как отлаживать/отслеживать , кто запрашивает конкретное изменение диалога? Перехват сообщения WM_PAINT в диалоговом окне кажется слишком запоздалым.

Заранее благодарим за любую помощь!

С наилучшими пожеланиями,

Fabian

+0

Являются ли немодальные диалоги детьми CMainFrame или CView? – Karim

+0

Хороший вопрос. Это дети из CMainFrame. – Fabian

+0

Я не думаю, что вы сможете определить, кто отправил запрос изначально. Недействительные генерируют сообщение, которое хранится в очереди сообщений Windows, и несколько таких недействительных команд объединяются до момента, когда ваша очередь пуста из других сообщений, а затем ваше приложение получает WM_PAINT. Таким образом, отправка и прием сильно развязаны. Я бы подумал, что вам лучше понять, почему ваше родительское окно (представление) сообщает вашим окнам, чтобы их перекрасить. Детские окна имели бы смысл перерисовывать, но принадлежали окнам? Мне это кажется странным. – Mordachai

ответ

2

Я полагаю, что ваши покадрово диалоги 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, поэтому упростить такую ​​политику проще.

+0

Отличный ответ, спасибо. Я буду следовать вашему предложению и, надеюсь, выследить проблему. – Fabian

0

Посмотрите на это:

http://msdn.microsoft.com/en-us/library/01c9aaty(VS.80).aspx

Вы могли бы переопределить OnPaint и выяснить, где сообщение приходит от ...

EDIT:

Структура вызывает эту функцию-член, когда Windows или приложение делает запрос на перерисовку части окна приложения.

Так что либо ОС запрашивает ваше перерисовку, либо это делается из вашего приложения.

также посмотреть на первый ответ на этот форум теме: http://social.msdn.microsoft.com/Forums/en/vcgeneral/thread/3f53fce3-38dd-441b-b112-82eff4dafc9e

+0

Спасибо за ссылку. Может быть, глупый вопрос, но как узнать, откуда приходит сообщение? Структура MSG, похоже, не содержит этой информации. – Fabian

+0

Дополнительное объяснение: вызов OnPaint инициируется очередью сообщений. Таким образом, этот звонок слишком поздно для предоставления мне какой-либо информации (по крайней мере, согласно моему пониманию). – Fabian

+0

Спасибо за редактирование. Позвольте мне уточнить. Я знаю, почему запускается WM_PAINT. Но как мне понять, изначально изначально возникла переиздание ВОЗ, а не сообщение WM_PAINT (это делается окнами), но недействительность, которая сообщает Windows, что WM_PAINT следует отправлять после того, как очередь сообщений пуста? – Fabian

0

Я хотел бы сделать это так же, как я отлаживать что-нибудь в MFC я не совсем понимаю, - я стараюсь, чтобы локализовать проблему путем воспроизведения поведения в совершенно новом проекте.

Итак, создайте новое приложение MFC, добавьте в него один немодальный диалог, вызовите Invalidate на вашем CView и посмотрите, все ли это происходит.

Если это все еще происходит, то это ваш мейнфрейм, отправляющий это сообщение с краской. Итак, вы можете попытаться зафиксировать это в PreTranslateMessage вашего мэйнфрейма.

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

0

Причина, по которой сообщение WM_PAINT также получено диалоговыми окнами, заключается в том, что они являются дочерними окнами CView, как уже было предложено Каримом.

Скорее всего, что происходит в том, что после того, как недействительности, который вызывает перерисовку Вашего взгляда, WM_PAINT сообщения отправляются в это окно и обработчик стандарт OnPaint() это окно (член CWnd) отправляет WM_PAINT сообщения его дочерние окна (диалоги).

WM_PAINT сообщение сам посылает окна в ответ на любой призыв к UpdateWindow() или RedrawWindow() см MSDN

сообщение WM_PAINT генерируется системы и не должны быть отправлены приложения.

Ближе всего вы можете попасть на сцену за механизмом обработки сообщений, чтобы переопределить WindowProc класса CView, который получен из CWnd. Это обратный вызов, в котором получено WM_PAINT и любое другое сообщение.

Приветствия Holger

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