Windows 为什么我的MFC应用程序在与两个滚动条交互后挂起?

Windows 为什么我的MFC应用程序在与两个滚动条交互后挂起?,windows,debugging,mfc,Windows,Debugging,Mfc,我正在开发一个MFC应用程序(在Win10下运行),其中包括一个图形化CAD样式编辑器窗口。编辑器窗口包含用户可以重新定位和配置的图标 在包含许多元素的布局中,我们发现编辑器窗口最多可以挂起30秒。当我们的大多数用户都在Windows 7上时,没有报告此问题;这似乎是Windows10开始出现的,但我还没有回到Win7来确认 触发挂起的确切操作顺序为: 水平滚动(使用水平滚动条) 垂直滚动(使用垂直滚动条) 应用程序挂起约20-30秒,然后恢复 上述步骤的微小变化也会触发临时挂起;例如,使用鼠标

我正在开发一个MFC应用程序(在Win10下运行),其中包括一个图形化CAD样式编辑器窗口。编辑器窗口包含用户可以重新定位和配置的图标

在包含许多元素的布局中,我们发现编辑器窗口最多可以挂起30秒。当我们的大多数用户都在Windows 7上时,没有报告此问题;这似乎是Windows10开始出现的,但我还没有回到Win7来确认

触发挂起的确切操作顺序为:

  • 水平滚动(使用水平滚动条)
  • 垂直滚动(使用垂直滚动条)
  • 应用程序挂起约20-30秒,然后恢复
  • 上述步骤的微小变化也会触发临时挂起;例如,使用鼠标按钮垂直滚动,然后使用滚动条水平滚动,也会触发挂起

    挂起或锁定始终会恢复。我还注意到,Windows中的其他应用程序会暂时“冻结”(例如:对于发生此挂起时运行的所有应用程序,我无法拖动窗口,UI更新会变得非常慢)

    我不确定从哪里开始调试,因为我感觉这是在操作系统级别发生的;我的第一个猜测是开始分析不同的代码行,以确定导致延迟的确切操作系统调用,但如果导致挂起的元素不是我代码中的函数调用,我不确定这种方法的效果如何;例如,可能操作系统中的某个队列几乎已满,导致消息泵速度减慢,而没有任何特定的操作系统调用看起来很慢

    我的问题是:

  • Windows 10 w.r.t.大CWnd计数是否有任何变化,这些变化可能与滚动交互导致挂起
  • Windows为调试此方案提供了哪些工具?我应该看看WinDbg吗?我是否应该在不使用任何专用调试工具的情况下专注于分析问题
  • 我将从内部应用程序的角度来解决这个问题(排除我们的代码直接导致挂起的可能性),但如果我们的代码中没有明显的30秒函数调用,我将非常感谢您提供关于调试这个问题的最佳方法的指导


    谢谢你的评论。以下是一些新信息:

    • 此事件期间CPU使用率低;徘徊在1-3%左右,所以我的代码不会受到CPU的限制
    • 我在入口点和出口点向HSCROLL和VSCROLL处理程序添加了跟踪语句。挂起似乎发生在输入我的VSCROLL处理程序之前,即用鼠标左键单击滚动条之后
    • 该代码有一个用于LButtonDown的处理程序,但当单击滚动条时,它似乎没有被点击
    • 该应用程序有208个GDI对象和66个用户对象,因此我认为我们远远低于限制
    • 在所有已测试的Win10 PC上都观察到了此问题,它不是单一机器所独有的
    现在要尝试Spy++了

    我看不到处理程序有任何明显的问题,我的调试输出似乎排除了它们是罪魁祸首,但为了完整性,这里是它们:

    void CDrawing60View::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
    {
        TRACE("OnHScroll:Begin\r\n");
    
        int i = 1;
        switch ( nSBCode )
        {
        case SB_LEFT :  //   Scroll to far left.
            i = 2 ;
            break ;
        case SB_ENDSCROLL : //   End scroll.
            i = 3 ;
            break ;
    
        case SB_LINELEFT :  //   Scroll left.  left arrow on left side of scroll bar
            i = 4 ;
            break ;
    
        case SB_LINERIGHT : //   Scroll right.  right arrow on right side of scroll bar
            i = 5 ;
            break ;
    
        case SB_PAGELEFT :  //   Scroll one page left.
            i = 6 ;
            break ;
    
        case SB_PAGERIGHT : //   Scroll one page right.
            i = 7 ;
            break ;
    
        case SB_RIGHT : //   Scroll to far right.
            i = 8 ;
            break ;
    
        case SB_THUMBPOSITION : //   Scroll to absolute position. The current position is specified by the nPos parameter.
            i = 9 ;
            break ;
    
        case SB_THUMBTRACK :    //   Drag scroll box to specified position. 
            i = 10;
            break ;
        }
    
        CFormView::OnHScroll(nSBCode, nPos, pScrollBar);
    
        CPoint p = GetScrollPosition(); // p = how much we have scrolled in the horizontal/vertical directions
    
        SNAP_TO_8_PIXELS (p.x);
        SNAP_TO_8_PIXELS  ( p.y)
        ScrollToPosition ( p ) ;
    
        MoveDrawing . LastScrollPositionX = p . x ; // used when saving the drawing
        MoveDrawing . LastScrollPositionY = p . y ;
    
        TRACE("OnHScroll:End\r\n");
    }
    
    void CDrawing60View::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
    {
        TRACE("OnVScroll:Begin\r\n");
    
        int i = 0;
        switch ( nSBCode )
        {
        case SB_BOTTOM :    //   Scroll to bottom.
            i = 2 ;
            break ;
        case SB_ENDSCROLL : //   End scroll.
            break ;
        case SB_LINEDOWN :  //   Scroll one line down.
            i = 2 ;
            break ;
        case SB_LINEUP :    //   Scroll one line up.
            i = 2 ;
            break ;
        case SB_PAGEDOWN :  //   Scroll one page down.
            i = 2 ;
            break ;
        case SB_PAGEUP :    //   Scroll one page up.
            i = 2 ;
            break ;
        case SB_THUMBPOSITION : //   Scroll to the absolute position. The current position is provided in nPos.
            i = 2 ;
            break ;
        case SB_THUMBTRACK :    //   Drag scroll box to specified position. The current position is provided in nPos.
            i = 2 ;
            break ;
        case SB_TOP :   //   Scroll to top. 
            i = 2 ;
            break ;
        }
    
        CFormView::OnVScroll(nSBCode, nPos, pScrollBar);
        CPoint p = GetScrollPosition(); // p = how much we have scrolled in the horizontal/vertical directions
    
        SNAP_TO_8_PIXELS (p.x);
        SNAP_TO_8_PIXELS ( p.y)
        ScrollToPosition ( p ) ;
    
        MoveDrawing . LastScrollPositionX = p . x ; // used when saving the drawing
        MoveDrawing . LastScrollPositionY = p . y ;
    
        TRACE("OnVScroll:End\r\n");
    }
    


    好的,Spy++已经产生了一些有趣的结果。当我运行Spy++时,我无法重现此问题!。我想知道这是否表明我的处理程序中存在竞争条件,因为我能想象Spy++的唯一效果是减慢速度。

    这是Windows操作系统的问题。Microsoft支持提供了一个高级解释:较新的Windows功能正在干扰我的应用程序

    看来我的调查指向了正确的方向:
    ntdll.dll
    dwm.exe
    是罪魁祸首,而不是我的可执行文件

    Spy++解决了我的问题,这一事实很能说明问题。这表明我们没有遇到严格的性能限制,也表明这不是我的应用程序停滞;操作系统级别的某些东西正在自我干扰

    Microsoft支持代表指示我使用Windows ADK中“应用程序兼容性工具”下的“兼容性管理员”工具。使用此向导,我生成了一个垫片数据库(.sdb),其中包含对ScrollWindowsExFlags的修复

    然后,我在提升的命令行中使用以下命令来安装垫片数据库:

    sdbinst -u <path to the sdb file>
    
    sdbinst-u
    
    来自Microsoft支持:

    有许多子窗口可滚动是原因。当他们 滚动时,DWM必须更新每个窗口的内部数据 感动的它们太多了,让DWM不知所措


    >>我还注意到,Windows中的其他应用程序会暂时“冻结”(例如:对于发生此挂起时运行的所有应用程序,我无法拖动窗口,UI更新会变得非常慢)。这可能意味着您的应用程序占用了大量CPU时间,请在task manager中查看CPU使用情况。如果是这样的话,那么研究代码中的哪些函数会导致这种情况。可能会考虑发布(一些)处理滚动请求的代码:在<代码> HRONG和<代码> VRONG处理程序之间可能会发生无意间的数据竞争。在Windows 10中,我还没有看到这种冻结问题。您的Windows设置可能有问题,或者您正在运行资源密集型应用程序。使用任务管理器检查应用程序使用了多少GDI句柄,或者其他应用程序是否正在使用资源。某些Windows后台任务(Defender、Cortana、User Experience等)确实会导致UI延迟,并使系统看起来冻结。也许可以检查一下这些是否会干扰你,给你带来麻烦。对于应用程序,上面@AdrianMole的评论可能就是答案。使用跟踪(非调试)t