univers1314 2026-01-16 16:23 采纳率: 41.7%
浏览 4
已采纳

MFC的状态栏 更新文字时会抛异常。

MFC的状态栏 更新文字时会抛异常。我找了一天也找不出原因啊。
我写了一个MFC的小程序,其它功能一切正常。之后我加了一个状态栏,有4格。见下图:
主程序初始化时后,分离了一个程线程,这个线程是用于长时间接收信息用的,功能正常。
我在其它按钮里调用 wndStatusBar.SetPaneText(3, _T("7777")); 是一切正常的。
但是在 LRESULT WINAPI Thread1() 线程里,调用更改状态栏显示文字时,就抛异常。
难到是要构造别的东西才行嘛?

img

img

img

img

//***********************************************************************//
LRESULT WINAPI Thread1()    //分离多线程函数 接收   这里要引用指针 pSxDlg->
{
    while (true)
    {
    //    m_wndStatusBar.SetPaneText(3, _T("7777"));            //不引用指针不行
        pSxDlg->m_wndStatusBar.SetPaneText(3, _T("7777"));    //到这时就会抛异常
        pSxDlg->m_wndStatusBar.SetPaneText(3, _T("8888"));    //到这时就会抛异常
    }
}
//***********************************************************************//


  • 写回答

3条回答 默认 最新

  • 檀越@新空间 2026-01-16 16:24
    关注

    下午好🌅🌅🌅
    本答案参考通义千问

    你遇到的问题是在多线程中直接访问 MFC 状态栏控件时抛出异常。这通常是因为 MFC 控件(如 CStatusBar)不是线程安全的,不能在非主线程中直接调用其成员函数。


    ✅ 问题原因分析:

    1. MFC 控件不是线程安全的
      MFC 的控件(如 CStatusBar)是在主线程中创建和管理的,它们依赖于主线程的消息循环和 UI 上下文。
      在子线程中直接调用 SetPaneText 是不合法的,会导致未定义行为或异常。

    2. 线程间通信问题
      在子线程中修改 UI 元素,必须通过某种方式将请求发送到主线程,由主线程来执行 UI 操作。

    3. 指针有效性问题
      如果 pSxDlg 是一个指向对话框类的指针,它可能在子线程运行时已经被释放或无效,导致访问非法内存。


    ✅ 解决方案(详细步骤):

    1. 使用主线程消息机制进行跨线程通信

    你可以通过向主线程发送自定义消息,让主线程负责更新状态栏。

    步骤如下:

    a. 定义自定义消息

    在你的对话框类头文件(如 MyDlg.h)中定义一个自定义消息:

    #define WM_UPDATE_STATUSBAR (WM_USER + 1)
    

    b. 声明消息处理函数

    在对话框类中声明消息处理函数:

    afx_msg LRESULT OnUpdateStatusBar(WPARAM wParam, LPARAM lParam);
    

    c. 添加消息映射

    .cpp 文件中添加消息映射:

    BEGIN_MESSAGE_MAP(CMyDlg, CDialogEx)
        ON_MESSAGE(WM_UPDATE_STATUSBAR, OnUpdateStatusBar)
    END_MESSAGE_MAP()
    

    d. 实现消息处理函数

    LRESULT CMyDlg::OnUpdateStatusBar(WPARAM wParam, LPARAM lParam)
    {
        int nPane = (int)wParam;
        LPCTSTR pText = (LPCTSTR)lParam;
    
        m_wndStatusBar.SetPaneText(nPane, pText);
    
        return 0;
    }
    

    e. 在子线程中发送消息

    在你的子线程函数中,不要直接调用 SetPaneText,而是通过 PostMessage 发送消息给主线程:

    LRESULT WINAPI Thread1()
    {
        while (true)
        {
            // 向主线程发送消息
            ::PostMessage(pSxDlg->m_hWnd, WM_UPDATE_STATUSBAR, (WPARAM)3, (LPARAM)_T("7777"));
            ::PostMessage(pSxDlg->m_hWnd, WM_UPDATE_STATUSBAR, (WPARAM)3, (LPARAM)_T("8888"));
    
            Sleep(1000); // 模拟延时
        }
    
        return 0;
    }
    

    ⚠️ 注意:pSxDlg->m_hWnd 是主窗口的句柄,确保 pSxDlg 在子线程中仍然有效。


    2. 确保 pSxDlg 指针的有效性

    如果你在子线程中使用了 pSxDlg,请确保:

    • 它是一个有效的指针。
    • 在子线程运行期间,该对象没有被销毁。
    • 避免在子线程中使用局部变量或临时对象。

    3. 使用 SendMessagePostMessage 的注意事项

    • SendMessage 是同步调用,会阻塞当前线程直到消息处理完成。
    • PostMessage 是异步调用,不会阻塞当前线程。

    根据你的需求选择合适的方式。


    ✅ 总结(重点总结)

    核心问题:
    你在子线程中直接操作 MFC 控件(如 CStatusBar),这是不允许的,会导致异常。

    解决方案:

    1. 使用自定义消息机制,通过 PostMessage 将更新请求发送到主线程。
    2. 避免在子线程中直接操作 UI 控件,始终通过主线程处理 UI 操作。
    3. 确保 pSxDlg 指针在子线程中有效且未被释放

    ✅ 示例代码修改(完整版)

    对话框类头文件(MyDlg.h)

    class CMyDlg : public CDialogEx
    {
        ...
        afx_msg LRESULT OnUpdateStatusBar(WPARAM wParam, LPARAM lParam);
        #define WM_UPDATE_STATUSBAR (WM_USER + 1)
    };
    

    对话框类实现文件(MyDlg.cpp)

    BEGIN_MESSAGE_MAP(CMyDlg, CDialogEx)
        ON_MESSAGE(WM_UPDATE_STATUSBAR, OnUpdateStatusBar)
    END_MESSAGE_MAP()
    
    LRESULT CMyDlg::OnUpdateStatusBar(WPARAM wParam, LPARAM lParam)
    {
        int nPane = (int)wParam;
        LPCTSTR pText = (LPCTSTR)lParam;
    
        m_wndStatusBar.SetPaneText(nPane, pText);
    
        return 0;
    }
    

    子线程函数(Thread1)

    LRESULT WINAPI Thread1()
    {
        while (true)
        {
            ::PostMessage(pSxDlg->m_hWnd, WM_UPDATE_STATUSBAR, (WPARAM)3, (LPARAM)_T("7777"));
            ::PostMessage(pSxDlg->m_hWnd, WM_UPDATE_STATUSBAR, (WPARAM)3, (LPARAM)_T("8888"));
    
            Sleep(1000);
        }
    
        return 0;
    }
    

    如果你还有其他关于线程、消息机制或 MFC 控件的问题,欢迎继续提问!

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(2条)

报告相同问题?

问题事件

  • 已采纳回答 1月16日
  • 创建了问题 1月16日