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

2024-01-27

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

在包含许多元素的布局中,我们发现编辑器窗口可能会挂起长达 30 秒。这个问题是not当我们的大多数用户使用 Windows 7 时报告;看来Windows 10开始出现这种情况,但我还没有回到Win7确认。

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

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

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

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

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

我的问题是:

  1. Windows 10 中是否有任何变化? CWnd 计数较大,这可能会与滚动交互导致挂起?
  2. Windows 提供了哪些工具来调试这种情况?我应该看看 WinDbg 吗?我是否应该专注于分析问题而不使用任何专用调试工具?

我将从内部应用程序的角度来解决这个问题(以排除我们的代码直接导致挂起的可能性),但如果我们不这样做,我将不胜感激有关调试此问题的最佳方法的任何指导我们的代码中有一些明显的东西,比如 30 秒的函数调用。


谢谢你的意见。以下是一些新信息:

  • 活动期间CPU使用率较低;徘徊在 1-3% 左右,所以我的代码没有受到 CPU 的瓶颈。
  • 我在入口点和出口点将 TRACE 语句添加到 HSCROLL 和 VSCROLL 处理程序中。似乎正在发生挂起before用鼠标左键单击滚动条后立即进入我的 VSCROLL 处理程序。
  • 该代码有一个 LButtonDown 的处理程序,但当单击滚动条时它似乎没有被点击
  • 该应用程序有 208 个 GDI 对象和 66 个 User 对象,所以我认为我们远远低于限制
  • 所有测试的 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 or dwm.exe是罪魁祸首,而不是我的可执行文件。

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

Microsoft 支持代表指示我使用 Windows ADK 中应用程序兼容性工具下包含的兼容性管理工具。使用此向导,我生成了一个 shim 数据库 (.sdb),其中包含以下问题的修复程序:滚动WindowsExFlags.

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

sdbinst -u <path to the sdb file>

来自微软支持:

原因是有许多子窗口需要滚动。当他们在 滚动后,DWM 必须更新每个窗口的内部数据 感动了。太多会导致 DWM 不堪重负。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

随机推荐

  • 指南针 SCSS 颜色代码小写

    在我的团队中 我们有相同版本的 Compass Compass 0 12 2 Alnilam 当 Compass 编译我的 SCSS 时 SCSS 中的颜色代码从大写 A0CAE3 更改为小写 a0cae3 只有我有这个问题 其他开发人员都
  • 为什么 Rust 编译器要求我限制泛型类型参数的生命周期(错误 E0309)?

    为什么 Rust 编译器会发出错误 要求我限制以下结构中泛型参数的生命周期 pub struct NewType lt a T gt x a T error E0309 the parameter type T may not live l
  • Android 推送通知的自定义声音不起作用 (FCM)

    我有使用云功能中的 FCM 工作的推送通知 这适用于 iOS 和 Android 并在 iOS 上显示相应的图标并播放自定义声音 除了 Android 的自定义声音外 一切正常 它只是播放默认声音 我创建了一个文件夹并将声音文件添加到其中
  • Marionette 布局和区域有什么区别?

    Marionette 提供了两个名为Regions http derickbailey github com backbone marionette marionette region and Layouts http derickbail
  • 如何解析以字符串形式给出的数学表达式并返回一个数字? [复制]

    这个问题在这里已经有答案了 Java 有没有办法从这个数学表达式中得到结果 String code 5 4 7 15 另一方面 解析算术表达式的最佳方法是什么 您可以将其传递给豆壳 http www beanshell org bsh In
  • 如何以本地用户身份(无管理员权限)在 Windows 上安装 NodeJS LTS

    我以简单用户身份使用 Windows 我没有任何管理员权限 并且想要安装 NodeJS LTS On the 下载站点 https nodejs org en download 我可以选择仅下载二进制文件node exe 其中不包括npm
  • 打开文件的命令按钮 - 位于同一单元格按钮中的文件路径对齐到

    我正在尝试获取一个可以分配给命令按钮的宏 我有多个按钮可以打开不同的文件 因此在每个单元格中我都包含不同的文件路径 目前 我的命令按钮正在寻找特定的单元格引用并打开该值 有什么方法可以让宏在与其对齐的单元格中查找值 我目前正在使用两个宏 一
  • 没有这样的目的地

    我在我的网站中使用 Stripe 方法 用户从我的网站购买产品并通过 stripe 完成付款 我想收取佣金并将剩余的钱发送给服务提供商 当我尝试在条纹中使用传输方法时 它会显示错误消息 message No such destination
  • 如何使用 jq 获取两个 JSON 数组的交集

    给定数组 X 和 Y 最好都作为输入 但否则 一个作为输入 另一个硬编码 如何使用 jq 输出包含两者共有的所有元素的数组 例如f 的值是多少 使得 echo 1 2 3 4 jq f 2 4 6 8 10 会输出 2 4 我尝试过以下方法
  • 你能在 jQuery 中扩展 val() 函数吗?

    有没有办法扩展 jQuery 中的 val 函数 基本上 我想要做的是如果有内容被动态输入到输入中 则设置一个类变量 通常会是这样的 var thisVal Hello World myInput val thisVal addClass
  • Javascript parseFloat 和 null

    我对 javascript 非常陌生 因为我目前正在 jQuery Mobile 中制作跨平台 Web 应用程序 我已经使用了 XML 解析到 HighCharts 图表的示例 但是当我在系列数据中遇到 null 时 它无法绘制任何线条并使
  • 颜色逐渐变化

    屏幕左上角的标志如何随着鼠标滑过而逐渐改变颜色 我认为它是用 jquery 完成的 如果您不知道代码 您能给我指点可以的教程吗 谢谢 http www shopdev co uk blog http www shopdev co uk bl
  • 即使进行所有优化,Android 模拟器也会出现延迟

    HAXM 启用版本 7 1 0 我验证了它在模拟器运行时正常工作 模拟器使用 Nvidia GPU 但在任何给定时间它仅使用最多 7 的 GPU 我有 27 3 1 的模拟器版本 最新 尝试过 x86 图像和 x86 x64 图像 我尝试过
  • 多个按钮上的 javascript 函数

    我有三个按钮 我希望它们在按下时改变颜色 并在再次按下时恢复为无颜色 我在 stackoverflow 上找到了这段代码 它几乎可以让我做到这一点 但是它只适用于一个按钮 其他两个不受影响 另外 当我按下另外两个按钮中的一个时 第一个按钮会
  • 如何在 mongodb 中更新多个数组元素

    我有一个 Mongo 文档 其中包含一个元素数组 我想重置 handled数组中所有对象的属性 其中 profile XX 该文件的形式如下 id ObjectId 4d2d8deff4e6c1d71fc29a07 user id 7146
  • 发帖后查看未更新

    我有一个控制器方法 CreateOrUpdate 该方法应该将汽车保存到数据库 然后正常返回 public ActionResult CreateOrUpdate int ID 0 Car car new Car ID HttpPost p
  • 如何测试 JSONObject 是否为空或不存在

    我有一套JSONObject我从服务器接收并操作的值 大多数时候我得到一个JSONObject带有一个值 比如说统计数据 有时 它返回一个Error带有代码和错误描述的对象 如何构建我的代码 使其在返回错误时不会中断 我以为我可以做到这一点
  • 非规范化是为了理智还是为了性能?

    我开始了一个新项目 他们有一个非常标准化的数据库 所有可以查找的内容都存储为查找表的外键 这是规范化的并且很好 但我最终为最简单的查询执行了 5 个表连接 from va in VehicleActions join vat in Vehi
  • 未找到 Laravel Passport 安装类

    我正在尝试配置我的 Laravel 应用程序以使用 Passport 但在加载 AppServiceProvider php 中的类时遇到了困难 这是我所做的
  • 为什么我的 MFC 应用程序在与两个滚动条交互后挂起?

    我正在开发一个 MFC 应用程序 在 Win10 下运行 其中包含一个图形 CAD 样式编辑器窗口 编辑器窗口包含用户可以重新定位和配置的图标 在包含许多元素的布局中 我们发现编辑器窗口可能会挂起长达 30 秒 这个问题是not当我们的大多