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

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

bash 复制代码
//全局定义
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️⃣ 定义自定义消息

cpp 复制代码
#define WM_WORKER_LOG (WM_USER + 100)

2️⃣ UI 窗口声明

cpp 复制代码
class CMainDlg : public CDialogEx
{
public:
    void StartWorker();

protected:
    afx_msg LRESULT OnWorkerLog(WPARAM wParam, LPARAM lParam);
    DECLARE_MESSAGE_MAP()
};

3️⃣ 消息映射

cpp 复制代码
BEGIN_MESSAGE_MAP(CMainDlg, CDialogEx)
    ON_MESSAGE(WM_WORKER_LOG, &CMainDlg::OnWorkerLog)
END_MESSAGE_MAP()

4️⃣ UI 线程处理回调(安全)

cpp 复制代码
LRESULT CMainDlg::OnWorkerLog(WPARAM, LPARAM lParam)
{
    CString* pStr = (CString*)lParam;
    ShowInfo(*pStr);   // UI 操作 ✔
    delete pStr;
    return 0;
}

5️⃣ 线程函数

cpp 复制代码
UINT WorkerThread(LPVOID pParam)
{
    HWND hWnd = (HWND)pParam;

    for (int i = 0; i < 5; i++)
    {
        CString* pMsg = new CString;
        pMsg->Format(_T("线程日志 %d"), i);

        ::PostMessage(hWnd, WM_WORKER_LOG, 0, (LPARAM)pMsg);
        Sleep(500);
    }
    return 0;
}

6️⃣ 启动线程

cpp 复制代码
void CMainDlg::StartWorker()
{
    AfxBeginThread(WorkerThread, m_hWnd);
}

✅ 这个方案为什么"工业级"

✔ UI 操作永远在主线程

✔ 不涉及 this / 成员函数指针

✔ 崩溃概率 ≈ 0

✔ 适合 量产工具 / 老 MFC 项目


✅ 二、现代方案(解耦最好)

std::function + lambda + MFC 线程

1️⃣ 回调类型

cpp 复制代码
using LogCallback = std::function<void(const CString&)>;

2️⃣ 线程参数

cpp 复制代码
struct WorkerCtx
{
    LogCallback cb;
};

3️⃣ 线程函数

cpp 复制代码
UINT WorkerThread(LPVOID pParam)
{
    WorkerCtx* ctx = (WorkerCtx*)pParam;

    for (int i = 0; i < 3; i++)
    {
        CString msg;
        msg.Format(_T("回调日志 %d"), i);
        ctx->cb(msg);
        Sleep(300);
    }

    delete ctx;
    return 0;
}

4️⃣ UI 启动线程

cpp 复制代码
void CMainDlg::StartWorker()
{
    auto ctx = new WorkerCtx;

    ctx->cb = [this](const CString& s)
    {
        // ⚠ 仍然不能直接操作 UI
        PostMessage(WM_WORKER_LOG, 0, (LPARAM)new CString(s));
    };

    AfxBeginThread(WorkerThread, ctx);
}

✅ 优点

✔ 线程逻辑完全不知道 UI

✔ 可以随意替换回调

✔ 未来好迁移到 std::thread

✔ 写起来舒服


✅ 三、Win32 / 旧接口兼容方案

LPVOID + struct + 成员函数

1️⃣ 定义

cpp 复制代码
typedef void (CMainDlg::*LogMethod)(CString);

struct WorkerCtx
{
    CMainDlg* obj;
    LogMethod method;
};

2️⃣ 线程函数

cpp 复制代码
UINT WorkerThread(LPVOID pParam)
{
    WorkerCtx* ctx = (WorkerCtx*)pParam;

    (ctx->obj->*(ctx->method))(_T("成员函数回调"));

    delete ctx;
    return 0;
}

3️⃣ 启动

cpp 复制代码
WorkerCtx* ctx = new WorkerCtx{ this, &CMainDlg::ShowInfo };
AfxBeginThread(WorkerThread, ctx);

⚠ 缺点

❌ UI 线程不安全

❌ 必须自己保证对象生命周期

不推荐直接操作 UI


🧠 选型建议(很重要)

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

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

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

这套结构:

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

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

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

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

相关推荐
萌动的小火苗20 小时前
嵌入式开发中的栈与队列:任务调度为什么依赖数据结构
数据结构·c++·单片机·嵌入式硬件
txzrxz20 小时前
单调队列讲解
数据结构·c++·算法·单调队列
WWTYYDS_66621 小时前
JsonCpp超详细使用教程
c++
Joey_friends21 小时前
指纹authenticate流程图
android·java·c++
小小晓.21 小时前
C++小白记:C风格字符串和数组用法
c语言·开发语言·c++
cpp_25011 天前
P1540 [NOIP 2010 提高组] 机器翻译
数据结构·c++·算法·队列·noip·洛谷题解
咕白m6251 天前
通过 C++ 写入数据到 Excel 文档
c++·后端
qz5zwangzihan11 天前
题解:Atcoder Beginner Contest abc467 F - Email Scheduling Optimization
c++·贪心·atcoder·平衡树·abc467·abc467_f·fhq-treap
郝学胜-神的一滴1 天前
中级OpenGL教程 023:Assimp模型加载全解——从源码到架构的骈文探秘
c++·unity·游戏引擎·cmake·unreal engine·opengl
星恒随风1 天前
C++ STL 详解:list 的使用、迭代器失效、模拟实现与 vector 对比
开发语言·数据结构·c++·笔记·学习·list