【MFC】底层类显示消息到多个界面上。 MFC + 线程 + 回调 的标准模板 C++函数指针

📅 发布时间:2026/7/11 13:30:16 👁️ 浏览次数:
【MFC】底层类显示消息到多个界面上。 MFC + 线程 + 回调 的标准模板 C++函数指针
使用函数指针最简单明了//全局定义 void(*pLogMethod)(const char* strMsg,...);//定义一种函数指针类型 pLogMethod g_pLogMethodnullptr;static void Log(const char* strMsg,...){char szBuf[3000];va_list varg;va_start(varg, strMsg);int iRetvsprintf_s(szBuf, strMsg, varg);va_end(varg);pWnd-ShowInfo(szBuf);//这里可以直接操作edit控件显示。}CConfigDlg::CConfigDlg(CWnd* pParent /*nullptr*/):CDialogEx(IDD_DIALOG_VersionCompareWriteConfig, pParent){pWndthis;g_pLogMethodLog;}调用if (g_pLogMethod ! nullptr) { g_pLogMethod(“Write %s:PASS %s”,key,cmd); }使用消息MFC 工作线程 UI 回调PostMessage也很麻烦。1.需要建消息。2.需要转递m_hWnd。好这个我直接给你一套**“工业级可用”的 MFC 线程 回调标准模板**。这是我给工具岗 / 自动化 / 生产工具里最常用的一套结构稳、不炸、好扩展。我会按三种层级给你✅推荐优先级1️⃣ UI 线程安全PostMessage【最稳】2️⃣ 回调解耦std::function【最舒服】3️⃣ Win32 兼容LPVOID struct【必须时用】你可以按需选不冲突。✅ 一、最稳方案强烈推荐MFC 工作线程 UI 回调PostMessage1️⃣ 定义自定义消息#defineWM_WORKER_LOG(WM_USER100)2️⃣ UI 窗口声明classCMainDlg:publicCDialogEx{public:voidStartWorker();protected:afx_msg LRESULTOnWorkerLog(WPARAM wParam,LPARAM lParam);DECLARE_MESSAGE_MAP()};3️⃣ 消息映射BEGIN_MESSAGE_MAP(CMainDlg,CDialogEx)ON_MESSAGE(WM_WORKER_LOG,CMainDlg::OnWorkerLog)END_MESSAGE_MAP()4️⃣ UI 线程处理回调安全LRESULTCMainDlg::OnWorkerLog(WPARAM,LPARAM lParam){CString*pStr(CString*)lParam;ShowInfo(*pStr);// UI 操作 ✔deletepStr;return0;}5️⃣ 线程函数UINTWorkerThread(LPVOID pParam){HWND hWnd(HWND)pParam;for(inti0;i5;i){CString*pMsgnewCString;pMsg-Format(_T(线程日志 %d),i);::PostMessage(hWnd,WM_WORKER_LOG,0,(LPARAM)pMsg);Sleep(500);}return0;}6️⃣ 启动线程voidCMainDlg::StartWorker(){AfxBeginThread(WorkerThread,m_hWnd);}✅ 这个方案为什么“工业级”✔ UI 操作永远在主线程✔ 不涉及 this / 成员函数指针✔ 崩溃概率 ≈ 0✔ 适合量产工具 / 老 MFC 项目✅ 二、现代方案解耦最好std::function lambda MFC 线程1️⃣ 回调类型usingLogCallbackstd::functionvoid(constCString);2️⃣ 线程参数structWorkerCtx{LogCallback cb;};3️⃣ 线程函数UINTWorkerThread(LPVOID pParam){WorkerCtx*ctx(WorkerCtx*)pParam;for(inti0;i3;i){CString msg;msg.Format(_T(回调日志 %d),i);ctx-cb(msg);Sleep(300);}deletectx;return0;}4️⃣ UI 启动线程voidCMainDlg::StartWorker(){autoctxnewWorkerCtx;ctx-cb[this](constCStrings){// ⚠ 仍然不能直接操作 UIPostMessage(WM_WORKER_LOG,0,(LPARAM)newCString(s));};AfxBeginThread(WorkerThread,ctx);}✅ 优点✔ 线程逻辑完全不知道 UI✔ 可以随意替换回调✔ 未来好迁移到 std::thread✔ 写起来舒服✅ 三、Win32 / 旧接口兼容方案LPVOID struct 成员函数1️⃣ 定义typedefvoid(CMainDlg::*LogMethod)(CString);structWorkerCtx{CMainDlg*obj;LogMethod method;};2️⃣ 线程函数UINTWorkerThread(LPVOID pParam){WorkerCtx*ctx(WorkerCtx*)pParam;(ctx-obj-*(ctx-method))(_T(成员函数回调));deletectx;return0;}3️⃣ 启动WorkerCtx*ctxnewWorkerCtx{this,CMainDlg::ShowInfo};AfxBeginThread(WorkerThread,ctx);⚠ 缺点❌ UI 线程不安全❌ 必须自己保证对象生命周期❌不推荐直接操作 UI 选型建议很重要场景推荐UI 日志 / 进度✅ PostMessage复杂回调链✅ std::function老 C 接口⚠ LPVOID跨线程 UI❌ 直接调用 最终“黄金组合”我实际项目用工作线程 → std::function → PostMessage → UI这套结构跑 7x24 不炸易维护易扩展成任务系统 / 线程池如果你愿意下一步我可以直接帮你封装一个CWorkerThread基类或给你一个线程池 UI 日志模块或按你现在的工程工具岗那种直接定制你这问题已经是架构级了不是语法层