与两个滚动条交互后,为什么我的MFC应用程序挂起? [英] Why is my MFC application hanging after interacting with both scroll-bars?

查看:47
本文介绍了与两个滚动条交互后,为什么我的MFC应用程序挂起?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用MFC应用程序(在Win10下运行),该应用程序包含图形化的CAD样式编辑器窗口.编辑器窗口包含用户可以重新定位和配置的图标.

I'm working on an MFC application (running under Win10) which includes a graphical CAD-style editor window. The editor window contains icons which the user can re-position and configure.

在包含许多元素的布局中,我们发现编辑器窗口最多可挂起30秒.当我们的大多数用户使用Windows 7时,没有报告此问题.Windows 10似乎开始出现这种情况,但我还没有回到Win7进行确认.

In layouts with many elements, we're finding that the editor window can hang for up to 30 seconds. This issue was not reported when most of our users were on Windows 7; it seems that this started to happen with Windows 10, but I haven't gone back to Win7 to confirm.

触发挂起的确切动作顺序是:

The exact sequence of actions triggering the hang is:

  1. 水平滚动(使用水平滚动条)
  2. 垂直滚动(使用垂直滚动条)
  3. 应用程序挂起大约20-30秒,然后恢复

上述步骤的微小变化也会触发暂时的挂起;例如,使用鼠标按钮垂直滚动,然后使用滚动条水平滚动,也会触发挂起.

Minor variations of the steps above also trigger a temporary hang; for example, scrolling vertically with the mouse button, and then scrolling horizontally with the scroll-bar, also triggers the hang.

挂起或锁定始终会恢复.我还注意到Windows中的其他应用程序暂时被冻结"(例如:当出现此挂起时,由于 all 应用程序正在运行,我无法拖动窗口,并且UI更新变得非常缓慢)..

The hang or lock-up always recovers. I have also noticed that other applications in Windows become temporarily 'frozen' (as in: I can't drag the window around, and UI updates become very slow, for all applications running when this hang occurs).

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

I'm unsure where to start debugging, because I have a feeling that this is happening at the OS level; my first guess would be to start profiling different lines of code to target the exact OS call causing the delay, but I'm not sure how well this approach will work if the element causing the hang is something other than a function-call in my code; for example, maybe some queue is nearly full in the OS, causing the message-pump to slow down without any particular OS call appearing to be slow.

我的问题是:

  1. Windows 10 w.r.t.中是否有任何更改?大的CWnd计数,这可能与滚动相互作用而导致挂起?
  2. Windows提供了哪些工具来调试此方案?我应该看WinDbg吗?我应该专注于解决问题而不使用任何专用调试工具吗?

我将从内部应用程序的角度来研究此问题(以排除我们的代码直接导致挂起的可能性),但我希望您能获得关于调试此问题的最佳方法的任何指导,前提是我们假设在我们的代码中没有像30秒的函数调用那样明显的事情.

I'm going to work on this issue from the internal application perspective (to rule out the possibility that our code is directly causing the hang), but I would appreciate any guidance on the best approach for debugging this issue assuming that we don't have something obvious like a 30-second function call in our code.

感谢您的评论.这是一些新信息:

Thank you for the comments. Here's some new information:

    在此事件期间,
  • CPU使用率较低;徘徊在1-3%左右,因此我的代码没有受到CPU的瓶颈.
  • 我在入口点和出口点向我的HSCROLL和VSCROLL处理程序中添加了TRACE语句.在用我的鼠标左键单击滚动条之后, 进入我的VSCROLL处理程序之前,该挂起似乎正在发生.
  • 该代码具有LButtonDown的处理程序,但单击滚动条时似乎没有被击中
  • 该应用程序有208个GDI对象和66个User对象,所以我认为我们远远低于限制
  • 此问题在所有经过测试的Win10 PC上均已观察到,不是一台计算机唯一的问题.
  • CPU usage is low during this event; hovering around 1-3%, so my code is not being bottlenecked by CPU.
  • I added TRACE statements to my HSCROLL and VSCROLL handlers at both the entry-point and exit-point. The hang appears to be happening before the entry to my VSCROLL handler, immediately after clicking the scroll bar with my left mouse-button.
  • The code has a handler for LButtonDown, but it does not appear to be hit when the scroll-bar is clicked
  • The application has 208 GDI objects and 66 User objects, so I think we are well below the limit
  • This issue has been observed on all tested Win10 PCs, it is not unique to a single machine

现在要尝试Spy ++.

Going to try Spy++ now.

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

I don't see any obvious issues with the handlers, and my debug output seems to rule out them as the culprit, but here they are for completeness:

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 ++的唯一作用就是放慢速度.


Ok, Spy++ has yielded some interesting results. When I run Spy++, I am unable to reproduce this issue!. I wonder if this suggests a race condition in my handlers, because the only effect that I can imagine Spy++ having is to slow things down.

推荐答案

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

This turned out to be a Windows OS issue. Microsoft Support provided a high-level explanation: newer Windows features are interfering with my application.

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

It seems that my investigation was pointing in the correct direction: ntdll.dll or dwm.exe being the culprit, not my executable.

Spy ++解决了我的问题,这很明显.这表明我们不是正在严格的性能限制下运行,也表明这不是我的应用程序停顿;操作系统级别的某些事物正在干扰自身.

The fact that Spy++ smooths out my issue is pretty telling. This indicates that we are not running up against a strict performance limitation, and it also shows that it's not my application stalling; something at the OS level is interfering with itself.

Microsoft支持代表指示我使用Windows ADK中应用程序兼容性工具"下的Compatibility Administrator工具.使用此向导,我生成了一个填充数据库(.sdb),其中包含针对 ScrollWindowsExFlags 的修复程序.

The Microsoft Support rep directed me to use the Compatibility Administrator tool included in the Windows ADK under Application Compatibility Tools. Using this wizard, I generated a shim database (.sdb) containing a fix for ScrollWindowsExFlags.

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

Then, I used the following command in an elevated command-line to install the shim database:

sdbinst -u <path to the sdb file>

来自Microsoft支持部门:

From Microsoft Support:

原因是要滚动许多子窗口.当他们是滚动,DWM必须更新每个窗口的内部数据感动.其中太多会使DWM不堪重负.

Having many child windows to scroll is the cause. When they are scrolled, DWM has to update the internal data for each window that is moved. Having too many of them overwhelms DWM.

这篇关于与两个滚动条交互后,为什么我的MFC应用程序挂起?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆