为什么我的 MFC 应用程序在与两个滚动条交互后挂起?
Why is my MFC application hanging after interacting with both scroll-bars?
我正在开发一个 MFC 应用程序(运行ning 在 Win10 下),其中包括一个图形化 CAD 风格的编辑器 window。编辑器 window 包含用户可以重新定位和配置的图标。
在包含许多元素的布局中,我们发现编辑器 window 最多可以挂起 30 秒。当我们的大多数用户使用 Windows 7 时,未 报告此问题;似乎从 Windows 10 开始出现这种情况,但我还没有回到 Win7 进行确认。
触发挂起的确切操作顺序是:
- 水平滚动(使用水平滚动条)
- 垂直滚动(使用垂直滚动条)
- 应用程序挂起大约 20-30 秒,然后恢复
上述步骤的细微变化也会触发临时挂起;例如,用鼠标按钮垂直滚动,然后用滚动条水平滚动,也会触发挂起。
挂起或锁定总是会恢复。我还注意到 Windows 中的其他应用程序暂时变为 'frozen'(如:我无法拖动 window,并且 UI 更新变得非常缓慢,因为 所有 个应用程序 运行ning 发生此挂起时)。
我不确定从哪里开始调试,因为我感觉这是在 OS 级别发生的;我的第一个猜测是开始分析不同的代码行以针对导致延迟的确切 OS 调用,但我不确定如果导致挂起的元素不是函数,这种方法的效果如何-调用我的代码;例如,可能 OS 中的某个队列快满了,导致消息泵变慢,但没有任何特定的 OS 调用看起来很慢。
我的问题是:
- Windows10 w.r.t有什么变化吗?大 CWnd 计数,这可能与滚动交互导致挂起?
- Windows 提供了哪些工具来调试此场景?我应该看看 WinDbg 吗?我是否应该专注于分析问题而不使用任何专用调试工具?
我将从内部应用程序的角度处理这个问题(以排除我们的代码直接导致挂起的可能性),但我将不胜感激关于调试此问题的最佳方法的任何指导假设我们的代码中没有像 30 秒函数调用这样明显的东西。
感谢您的评论。这里有一些新信息:
- CPU 活动期间使用率低;徘徊在 1-3% 左右,所以我的代码没有受到 CPU.
的瓶颈
- 我在入口点和出口点都向我的 HSCROLL 和 VSCROLL 处理程序添加了 TRACE 语句。挂起似乎发生在进入我的 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 OS 问题。 Microsoft 支持提供了高级解释:较新的 Windows 功能正在干扰我的应用程序。
我的调查似乎指向了正确的方向:ntdll.dll
或 dwm.exe
是罪魁祸首,而不是我的可执行文件。
Spy++ 解决了我的问题这一事实很能说明问题。这表明我们 而不是 运行 遇到严格的性能限制,并且它还表明这不是我的应用程序停滞; OS 级别的东西正在干扰自身。
Microsoft 支持代表指示我使用应用程序兼容性工具下 Windows ADK 中包含的兼容性管理器工具。使用此向导,我生成了一个垫片数据库 (.sdb),其中包含 ScrollWindowsExFlags 的修复程序。
然后,我在提升的命令行中使用以下命令来安装 shim 数据库:
sdbinst -u <path to the sdb file>
来自 Microsoft 支持:
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 应用程序(运行ning 在 Win10 下),其中包括一个图形化 CAD 风格的编辑器 window。编辑器 window 包含用户可以重新定位和配置的图标。
在包含许多元素的布局中,我们发现编辑器 window 最多可以挂起 30 秒。当我们的大多数用户使用 Windows 7 时,未 报告此问题;似乎从 Windows 10 开始出现这种情况,但我还没有回到 Win7 进行确认。
触发挂起的确切操作顺序是:
- 水平滚动(使用水平滚动条)
- 垂直滚动(使用垂直滚动条)
- 应用程序挂起大约 20-30 秒,然后恢复
上述步骤的细微变化也会触发临时挂起;例如,用鼠标按钮垂直滚动,然后用滚动条水平滚动,也会触发挂起。
挂起或锁定总是会恢复。我还注意到 Windows 中的其他应用程序暂时变为 'frozen'(如:我无法拖动 window,并且 UI 更新变得非常缓慢,因为 所有 个应用程序 运行ning 发生此挂起时)。
我不确定从哪里开始调试,因为我感觉这是在 OS 级别发生的;我的第一个猜测是开始分析不同的代码行以针对导致延迟的确切 OS 调用,但我不确定如果导致挂起的元素不是函数,这种方法的效果如何-调用我的代码;例如,可能 OS 中的某个队列快满了,导致消息泵变慢,但没有任何特定的 OS 调用看起来很慢。
我的问题是:
- Windows10 w.r.t有什么变化吗?大 CWnd 计数,这可能与滚动交互导致挂起?
- Windows 提供了哪些工具来调试此场景?我应该看看 WinDbg 吗?我是否应该专注于分析问题而不使用任何专用调试工具?
我将从内部应用程序的角度处理这个问题(以排除我们的代码直接导致挂起的可能性),但我将不胜感激关于调试此问题的最佳方法的任何指导假设我们的代码中没有像 30 秒函数调用这样明显的东西。
感谢您的评论。这里有一些新信息:
- CPU 活动期间使用率低;徘徊在 1-3% 左右,所以我的代码没有受到 CPU. 的瓶颈
- 我在入口点和出口点都向我的 HSCROLL 和 VSCROLL 处理程序添加了 TRACE 语句。挂起似乎发生在进入我的 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 OS 问题。 Microsoft 支持提供了高级解释:较新的 Windows 功能正在干扰我的应用程序。
我的调查似乎指向了正确的方向:ntdll.dll
或 dwm.exe
是罪魁祸首,而不是我的可执行文件。
Spy++ 解决了我的问题这一事实很能说明问题。这表明我们 而不是 运行 遇到严格的性能限制,并且它还表明这不是我的应用程序停滞; OS 级别的东西正在干扰自身。
Microsoft 支持代表指示我使用应用程序兼容性工具下 Windows ADK 中包含的兼容性管理器工具。使用此向导,我生成了一个垫片数据库 (.sdb),其中包含 ScrollWindowsExFlags 的修复程序。
然后,我在提升的命令行中使用以下命令来安装 shim 数据库:
sdbinst -u <path to the sdb file>
来自 Microsoft 支持:
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.