如何在对话框失效时调试/跟踪?

时间:2009-12-11 16:21:36

标签: mfc view invalidation

我的MFC应用程序有一个CView和几个浮动的非模态对话框。我目前正在试图解释为什么我的视图的失效/重绘也会导致重绘对话框。如果对话框与视图不重叠,甚至会发生这种情况。

有人知道如何调试/跟踪请求特定对话框重绘?拦截对话框上的WM_PAINT消息似乎为时已晚。

提前感谢您的帮助!

祝福,

费边

4 个答案:

答案 0 :(得分:2)

我认为你的非模态对话框是WS_POPUP窗口,对吧? (即它们是浮动窗口,可以出现在屏幕上的任何位置,而不仅仅是在应用程序窗口内部。)。

如果它们是浮动窗口,那么从技术上讲它们不是框架窗口的子窗口,但是文档倾向于在应该真正使用所有者的地方使用术语 parent

只有具有WS_CHILD样式标志的窗口可以是子窗口,否则它们是拥有的窗口。

如果这些是拥有的窗口,它们将不会从主应用程序窗口继承失效,因此您需要在代码中查找有调用的位置:: InvalidateRect(),其中NULL句柄作为第一个参数。通常这是因为未初始化的变量。

当您致电::InvalidateRect(NULL, ...)时,这会告诉Windows使所有窗口无效。 (它实际上告诉Windows使桌面窗口无效,这是所有窗口的父窗口)。使用MFC,所有窗口的基类都有一个InvalidateRect方法,该方法转向并调用windows api但使用当前对象的窗口句柄。作为一阶近似,我认为你可以假设这个窗口句柄将被正确初始化。您应该首先在自己的代码中查找电话。

一旦你获得OnPaint,它就太迟了,无法知道失效请求的来源。因此,为了找到此错误,您将不得不检查代码或拦截InvalidateRect()并在第一个参数中查找NULL。

在一般情况下,这是一个很难的问题,因为有几种方法可以使窗口的全部或部分无效,并且头文件中的大量代码可以通过创建自动执行某些操作的此函数的变体来“帮助”您

您可能会尝试在InvalidateRect(它位于user32.dll中)的顶部设置断点,并使第一个参数为null的条件。但是根据调试器的设置方式,您可能无法执行此操作。

您也可以尝试强制编译所有代码,以便通过您控制的函数重定向对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
};

如果找不到,请对InvalidateRgnRedrawWindow

执行相同的操作

这些类型的bug很难找到。我不羡慕你。在我自己的代码中,我永远禁止直接调用InvalidateRect,它们必须始终通过包装函数,因此我总是可以在调试版本中检查NULL窗口句柄。但话说回来,我不使用MFC,因此更容易实施这种政策。

答案 1 :(得分:0)

看看这个:

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

您可以覆盖OnPaint并找出消息的来源......

编辑:

当Windows或应用程序请求重新绘制应用程序窗口的一部分时,框架会调用此成员函数。

因此,操作系统要求您重绘,或者从您的应用程序中完成。

另请参阅此论坛帖子的第一个答案: http://social.msdn.microsoft.com/Forums/en/vcgeneral/thread/3f53fce3-38dd-441b-b112-82eff4dafc9e

答案 2 :(得分:0)

我会像在MFC中调试任何东西一样,我不太明白 - 我试图通过在一个全新的项目中复制行为来隔离问题。

因此,创建一个全新的MFC应用程序,向其添加一个无模式对话框,在CView上调用Invalidate,看看它是否仍然存在。

如果它仍然发生,则必须是您的主机发送该绘制消息。那么你可以尝试在大型机的PreTranslateMessage中捕获它。

如果没有发生,那么您在应用程序中完成的任务就会导致它。如果是这样,您可以尝试通过消除应用程序中的复杂性来找出您已完成的工作,直到找到导致 not 的事情发生的事情为止。

答案 3 :(得分:0)

对话框接收WM_PAINT消息的原因是它们是卡里姆已经建议的CView的子窗口。

最有可能发生的是,在导致重绘视图的失效之后,WM_PAINT消息被发送到此窗口,并且此窗口的标准OnPaint()处理程序(CWnd的成员)发送{{1消息到其子窗口(对话框)。

WM_PAINT消息本身由Windows发送,以响应对WM_PAINTUpdateWindow()的调用,请参阅MSDN

  

WM_PAINT消息由。生成   系统,不应该发送   申请。

最接近消息处理机制后面的场景是覆盖从CWnd派生的CView类的WindowProc。这是收到WM_PAINT和任何其他消息的回调。

干杯 霍尔格