MFC应用程序,工作线程学习记录

如何在一个MFC应用程序中添加控制台输出(printf、cout)?

目标:在MFC应用程序中也可以使用cout,printf进行Debug

cpp 复制代码
在程序初始化时(InitInstance中,位于"工程名.cpp"中)调用
AllocConsole(); // 分配控制台
freopen("CONOUT$", "w", stdout); // 将stdout重定向到控制台


参数意义:
第一个参数 CONOUT$ : Windows 系统中的 "控制台输出设备"(Console Output)
是一个特殊的设备名(而非普通文件路径);
第二个参数 w :文件打开模式(Write,写入模式,还有其他模式)
第三个参数 stdout : 要重定向的标准流(Standard Output,标准输出)

freopen函数意义:
核心作用是重新关联标准流(如 stdin/stdout/stderr)与指定的文件或设备
简单说就是 "重定向输入 / 输出的目标"
示例:freopen("log.txt", "w", stdout);(后续 printf 内容会写入 log.txt)。

从属于C 标准库函数(头文件 <cstdio> 或 <stdio.h>)

这样操作以后,在启动MFC程序之后,会额外启动一个控制台窗口用来查看输出




如何简单实现多线程?(AfxBeginThread函数实现)

目标:使用多线程完成简单任务,并输出到控制台上

首先我们需要一个用于多线程执行的任务函数

cpp 复制代码
UINT MyWorkerThread(LPVOID pParam) 
{
    for (int i = 0; i < 100; i+=25) {
        printf("工作线程运行中%d%%\r\n", i);
        Sleep(1000);
    }
    printf("工作线程执行完毕!\n");
    return 0;
}

这里需要注意:

用 MFC 的 AfxBeginThread 或 Windows API 的 CreateThread必须符合 UINT/DWORD 返回值 + LPVOID 参数的原型。该函数的"格式"是十分严格 的,必须写成 "返回值为UINT、参数为LPVOID" 这样的格式

但是,如果:使用 C++ 标准库 std::thread:无强制原型限制,函数可以灵活定义。

或者:直接同步 调用(非线程):无任何限制,但也不是多线程


其次我们要设定启动该线程的方式方法,比如说启动应用程序即刻启动,还是点击某个按键后触发(这里我使用的是点击一个按钮触发该线程)

如何添加按钮这里不多赘述:

cpp 复制代码
void CTest24ThreadDlg::OnButtonStart()
{
	printf("线程即将启动\r\n");

	AfxBeginThread(MyWorkerThread,NULL);    //创建并启动多线程

	printf("线程结束了吗?\r\n");
}

最后观察运行结果,并进行测试。执行完,结果应该是:

cpp 复制代码
线程即将启动
线程结束了吗?
工作线程运行中:0%
工作线程运行中:25%
工作线程运行中:50%
工作线程运行中:75%
工作线程执行完毕!



工作线程与主线程(UI线程)通信及其交互

目标:通过工作线程,消息模式,来使得主线程完成反馈,而非单纯控制台反馈。

模式简述:

发送命令,准备工作:主线程(UI线程)通过发送指令令工作线程工作(或创建工作线程等)

受到命令,开始工作:工作线程完成自己的工作(UI线程仍可独立运行,不会阻塞)

完成工作,进行反馈:工作线程反馈完工信息等,反馈给主线程,令其有相应的反馈(弹窗等)

这就是一个消息模式流程。后续将围绕这几步骤进行实践


规定消息:无论是主界面还是工作界面都需要约定好的消息进行通信

这里采用宏定义进行定义消息:

cpp 复制代码
#define MESSAGE_A 8888

注意:宏定义的数值不可随便定义,因为有些数值已经被系统占用了
WM_USER + 100 是推荐的起始值,确保唯一性(据说)

处理函数:

在主线程窗口类中,声明并实现消息处理函数,用于接收工作线程的消息并更新 UI

cpp 复制代码
放在"工程名Dlg.h"位置,即主线程窗口类(c工程名Dlg 类)中Protected处

afx_msg LRESULT UpdateUI(WPARAM wParam, LPARAM lParam);


代码命名要求较为严苛:除函数名外几乎无法修改
afx_msg 关键字必须添加在函数声明前,用于告诉 MFC 消息映射机制:"这是一个消息处理函数"
返回值类型 LRESULT固定为 LRESULT(32 位整数类型),用于表示消息处理的结果
(大多数情况下返回 0 即可)
WPARAM wParam, LPARAM lParam,必须包含这两个参数:
WPARAM:传递短整数或指针(32/64 位系统中长度与平台一致)。
LPARAM:传递长整数或指针
(功能与 WPARAM 类似,历史上为区分长度设计。现在两者在 32/64 位系统中通常等价)。
这两个参数是 Windows 消息机制的标准设计,用于传递消息的附加数据(如进度值、指针等)。

在源文件(工程名Dlg.cpp)中绑定消息与处理函数(消息映射)

cpp 复制代码
在源文件(工程名Dlg.cpp)中绑定消息与处理函数(消息映射)

ON_MESSAGE(MESSAGE_A, &CMessageTestDlg::UpdateUI) 

ON_MESSAGE(消息ID, 消息处理函数指针)


要求放在
BEGIN_MESSAGE_MAP(C工程名Dlg, CDialog)  /(即你的主窗口类,其父类)
	//{{AFX_MSG_MAP(CMessageTestDlg)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_BUTTON1, MessageSend)
	//}}AFX_MSG_MAP

	ON_MESSAGE(MESSAGE_A, &C工程名Dlg::UpdateUI)

END_MESSAGE_MAP()
这里,也就是夹在begin和end中间
注意Begin后面的参数,要是自己主窗口那个类,其他的是其他窗口的
这串代码是一个消息映射宏,每一个界面都会有,只不过是有没有内容,内容一样不一样的区别

主线程消息处理函数:

cpp 复制代码
位于工程名Dlg.cpp中,信息映射后面

LRESULT CMessageTestDlg::UpdateUI(WPARAM wParam, LPARAM lParam) 
{
    MessageBox(_T("工作线程任务已完成!"), _T("提示"), MB_OK);
    return 0;
}

注意,定义同样严苛:LRESULT 类名::函数名(WPARAM wParam, LPARAM lParam);

发送消息:仍设计为点击按钮发送消息

未完待续

相关推荐
RuoZoe3 小时前
从 2026 年 3 月 1 日开源,到 26.10.9:Jalium UI 半年时间到底走了多远?
c语言·c++
鱼子星_4 小时前
【C++】继承和多态(上)
c++·笔记
郝学胜-神的一滴6 小时前
Qt 高级编程 045:坐标体系深度实战
开发语言·c++·windows·python·qt·程序人生
码匠许师傅6 小时前
【设计模式精讲】22.中介者模式(Mediator)
c++·设计模式·软件工程·uml·中介者模式
爱吃巧克力的程序媛8 小时前
main.cpp注册 C++ 类到 QML 元对象系统
c++·qt
YYYing.9 小时前
【C++进阶系列 (二)】关于线程堆栈的那些事——函数调用过程
开发语言·c++·函数·线程堆栈
键盘会跳舞10 小时前
【C++多线程】死锁诊断工具实战:从 Windows 到 Linux 的全链路排查
linux·c++·windows·死锁
HugoStudio_SWAN10 小时前
洛谷 P10719 \[GESP202406 五级] 黑白格——暴力美学与图像处理的最小外接矩形
c++·图像处理·人工智能·学习·程序人生·算法·目标跟踪
jimy110 小时前
C++ 的 “移动语义”——Move Semantics
开发语言·c++
励志不掉头发的内向程序员13 小时前
【LibreCAD 2D架构】从鼠标点击到图形创建:RS_ActionDrawLine交互流程与状态机解析
开发语言·c++·qt·学习·系统架构·计算机外设·交互