You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何这段C++代码中CWnd::UpdateWindow会出现冻结?

MFC老旧C++应用冻结问题排查

维护一个基于MFC的老旧C++应用,该应用自2018年以来一直正常运行,近期出现奇怪的冻结问题,经排查冻结源于以下代码中的CWnd::UpdateWindow方法:

void CVisBeregning::process_messages()
{
    MSG msg;
    if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    if (vb->GetSafeHwnd()) {
        vb->UpdateWindow();
    }
}
  • CVisBeregning是派生自CDialog的类,vb是其静态成员,定义如下:
static CVisBeregning * vb;
  • vb在类的构造函数中被赋值为this,用于外部代码的回调(需全局访问该类的唯一实例)。

冻结触发场景

冻结发生在第一个if判断返回false时,即无消息需要处理的场景。测试中该方法被调用十几次后,首次出现无消息情况时触发冻结。将第二个if块移至第一个if内可规避问题,但需明确冻结原因。

补充信息

  • if (vb->GetSafeHwnd())检查是必要的,因为应用有两种运行模式,其中一种模式下类未关联窗口,此时不会调用UpdateWindow。
  • 开发环境:Visual Studio 2019、Windows 10 x64。

2022-09-26补充细节

CVisBeregning对象在同一线程中调用外部优化求解程序Mosel,该程序的不同事件会触发CVisBeregning类的不同方法回调:

  • 每次Mosel找到新解时,会调用方法将解写入CVisBeregning对话框的文本控件;
  • 定期触发userinterrupt回调,对应方法检查用户是否尝试取消运行,若则终止Mosel执行。

添加process_messages()方法是为了避免Windows将对话框标记为“未响应”。

未冻结时的调用栈

>   Gassopt.exe!CVisBeregning::process_messages() Line 647  C++
    Gassopt.exe!CVisBeregning::mi_userinterrupt(Vimactx * ctx, void * libctx) Line 759  C++
    [External Code] 
    Gassopt.exe!CVisBeregning::RunMosel(ATL::CStringT<char,StrTraitMFC<char,ATL::ChTraitsCRT<char>>> parameters, CDialog * calling_dialog, int inBatchId) Line 448  C++
    Gassopt.exe!CVisBeregning::OnPaint() Line 155   C++

冻结前的调用栈

>   Gassopt.exe!CVisBeregning::process_messages() Line 653  C++
    Gassopt.exe!CVisBeregning::mi_userinterrupt(Vimactx * ctx, void * libctx) Line 759  C++
    [External Code] 

额外观察

外部程序的调用在CVisBeregning的OnPaint()方法中完成(该方法未执行任何绘制操作),虽已避免重复调用,但怀疑重写OnPaint()却不做绘制是否合理。原设计用DoModal()初始化对象,为确保RunMosel()在窗口激活后执行才采用此方案,或许应改用消息或定时器实现。


内容的提问来源于stack exchange,提问作者Michal Kaut

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 16:55:47