代码之家  ›  专栏  ›  技术社区  ›  Fabian

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

  •  0
  • Fabian  · 技术社区  · 16 年前

    我的MFC应用程序有一个cView和两个浮动的非模态对话框。我目前正在试图弄清楚为什么视图的无效/重新绘制也会导致重新绘制对话框。即使对话框没有与视图重叠,也会发生这种情况。

    有人知道如何调试/跟踪吗 谁 请求重新绘制特定对话框?在对话框上截取wm_paint消息似乎为时已晚。

    提前感谢您的帮助!

    最美好的祝福,

    费边

    4 回复  |  直到 16 年前
        1
  •  2
  •   John Knoeller    16 年前

    我假设您的非模态对话框是ws撊popup窗口,对吗?(也就是说,它们是浮动窗口,可以出现在屏幕上的任何位置,而不只是在应用程序窗口中)。

    如果它们是浮动窗口,那么从技术上讲,它们不是框架窗口的子窗口,但是文档往往使用这个术语 起源 在它真正应该使用的地方 主人 所以这很容易让人困惑。子窗口不能出现在其父窗口的工作区之外,拥有的窗口可以。当子窗口的父窗口失效时,子窗口将失效。但拥有的窗口不会。

    只有具有ws_child-style标志的窗口可以是子窗口,否则它们是属于自己的窗口。

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

    当你打电话 ::InvalidateRect(NULL, ...) 这会告诉Windows使所有窗口无效。(它实际上告诉Windows使桌面窗口失效,桌面窗口是所有窗口的父窗口)。对于MFC,所有窗口的基类都有一个invalidRect方法,该方法可以返回并调用Windows API,但使用当前对象的窗口句柄。作为一阶近似,我认为您可以假定窗口句柄将被正确初始化。您应该从用自己的代码查找调用开始。

    一旦你得到了onpaint,现在知道无效请求来自何处为时已晚。所以为了找到这个bug,你必须检查你的代码或者拦截 InvalidateRect() 在第一个参数中查找空值。

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

    您可以尝试在 InvalidateRect (它在user32.dll中)并以第一个参数为空为条件。但是,根据调试器的设置方式,可能不允许这样做。

    您还可以尝试强制编译所有代码,以便通过您控制的函数重定向对invalidrect的调用。

    // 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

    这些虫子很难找。我不羡慕你。在我自己的代码中,我永久禁止直接调用invalidrect,它们必须始终通过包装函数,以便我可以始终检查调试版本中的空窗口句柄。但是,同样,我不使用MFC,所以执行这种策略更容易。

        2
  •  0
  •   Tony The Lion    16 年前

    看看这个:

    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

        3
  •  0
  •   demoncodemonkey    16 年前

    我会像在MFC中调试任何我不太理解的东西那样做——我试图通过在一个全新的项目中复制行为来隔离问题。

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

    如果它仍然发生,那么它必须是您的主机发送油漆消息。然后你可以尝试在你的主机的预传输消息中捕获它。

    如果它没有发生,那么您在应用程序中所做的一些事情就是导致它发生的原因。如果是这样的话,您可以尝试通过消除应用程序中的复杂性来解决您所做的工作,直到找到导致此问题发生的原因为止。 不 不再发生了。

        4
  •  0
  •   codencandy    16 年前

    对话框也接收到wm_paint消息的原因是它们是cView的子窗口,正如karim已经建议的那样。

    最可能发生的情况是,在导致重新绘制视图的无效声明之后 WM_PAINT 消息将发送到此窗口,此窗口的标准onpaint()处理程序(cwnd成员)将发送 水彩画 发送到其子窗口(对话框)的消息。

    wm_paint消息本身由Windows发送,以响应调用 UpdateWindow() 或 RedrawWindow() 见 MSDN

    wm_paint消息由 系统,不应发送 一个应用程序。

    最接近消息处理机制背后的场景的是重写cView类的windowproc,该类是从cwnd派生的。这是收到wm_paint和任何其他消息的回调。

    干杯 霍格尔