news 2026/8/26 11:42:01

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

作者头像

张小明

前端开发工程师

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

使用函数指针(最简单明了)

//全局定义 void(*pLogMethod)(const char* strMsg,...);//定义一种函数指针类型 pLogMethod g_pLogMethod=nullptr;static void Log(const char* strMsg,...){char szBuf[3000]="";va_list varg;va_start(varg, strMsg);int iRet=vsprintf_s(szBuf, strMsg, varg);va_end(varg);pWnd->ShowInfo(szBuf);//这里可以直接操作edit控件显示。}CConfigDlg::CConfigDlg(CWnd* pParent /*=nullptr*/):CDialogEx(IDD_DIALOG_VersionCompareWriteConfig, pParent){pWnd=this;g_pLogMethod=Log;}

调用
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 回调(PostMessage)

1️⃣ 定义自定义消息

#defineWM_WORKER_LOG(WM_USER+100)

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(inti=0;i<5;i++){CString*pMsg=newCString;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️⃣ 回调类型

usingLogCallback=std::function<void(constCString&)>;

2️⃣ 线程参数

structWorkerCtx{LogCallback cb;};

3️⃣ 线程函数

UINTWorkerThread(LPVOID pParam){WorkerCtx*ctx=(WorkerCtx*)pParam;for(inti=0;i<3;i++){CString msg;msg.Format(_T("回调日志 %d"),i);ctx->cb(msg);Sleep(300);}deletectx;return0;}

4️⃣ UI 启动线程

voidCMainDlg::StartWorker(){autoctx=newWorkerCtx;ctx->cb=[this](constCString&s){// ⚠ 仍然不能直接操作 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*ctx=newWorkerCtx{this,&CMainDlg::ShowInfo};AfxBeginThread(WorkerThread,ctx);

⚠ 缺点

❌ UI 线程不安全
❌ 必须自己保证对象生命周期
不推荐直接操作 UI


🧠 选型建议(很重要)

场景推荐
UI 日志 / 进度✅ PostMessage
复杂回调链✅ std::function
老 C 接口⚠ LPVOID
跨线程 UI❌ 直接调用

🚀 最终“黄金组合”(我实际项目用)

工作线程 → std::function → PostMessage → UI

这套结构:

  • 跑 7x24 不炸
  • 易维护
  • 易扩展成任务系统 / 线程池

如果你愿意,下一步我可以直接帮你:

  • 封装一个CWorkerThread基类
  • 或给你一个线程池 + UI 日志模块
  • 或按你现在的工程(工具岗那种)直接定制

你这问题已经是架构级了,不是语法层 👍

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/20 17:45:47

Python 初级入门教程:从零开始掌握编程基础

目录 引言一、Python 简介与特点二、环境搭建与准备工作三、Python 基础语法详解3.1 变量与数据类型3.2 控制结构3.3 函数定义与使用 四、常用数据结构与操作4.1 列表操作4.2 字典操作 五、文件操作与异常处理5.1 文件操作5.2 异常处理 六、实用案例&#xff1a;学生成绩管理系…

作者头像 李华
网站建设 2026/8/22 20:14:35

AI产品经理转型指南:从零入行大模型产品经理的核心能力与实战路径_0经验如何快速转型AI产品经理?

文章分析了AI产品经理岗位的热门现状及转型难点&#xff0c;指出经验与岗位要求不匹配是主要问题。介绍了专业型和应用层两类AI产品经理能力模型&#xff0c;强调了产品建设能力、行业理解、技术理解和AI落地经验四大核心能力。最后推荐了产品经理私教陪跑实战营&#xff0c;提…

作者头像 李华
网站建设 2026/8/19 22:24:45

抖音商家如何快速精准的找到自己需要的达人?

从海量达人中锁定最适合的合作对象&#xff0c;抖音商家达人筛选全攻略在此。 在抖音电商生态中&#xff0c;达人合作已成为品牌获取流量、提升销量的重要途径。面对平台上数以万计的带货达人&#xff0c;许多商家却陷入“盲目寻找”或“选择困难”的困境。 如何从海量达人中找…

作者头像 李华