【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 日志模块
  • 或按你现在的工程(工具岗那种)直接定制

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

相关推荐
兩尛2 小时前
c++遍历容器(vector、list、set、map
开发语言·c++
2301_790300962 小时前
C++与Docker集成开发
开发语言·c++·算法
AutumnorLiuu2 小时前
C++并发编程学习(二)—— 线程所有权和管控
java·c++·学习
一切尽在,你来2 小时前
C++ 零基础教程 - 第 5 讲 变量和数据类型
开发语言·c++
王老师青少年编程2 小时前
2022信奥赛C++提高组csp-s复赛真题及题解:假期计划
c++·真题·csp·信奥赛·csp-s·提高组·假期计划
阿猿收手吧!3 小时前
【C++】constexpr动态内存与双模式革命
开发语言·c++
云深处@3 小时前
【C++】哈希表
开发语言·c++
weixin_452159553 小时前
模板编译期条件分支
开发语言·c++·算法
啊我不会诶3 小时前
蓝桥杯练习 混乱的数组
c++·蓝桥杯