MFC 子线程消息循环的实现

 这段时间要做一个工具要从服务器取一些数据,做一些处理后保存. 由于数据量大和服务器响应的问题, 所以准备用多线程的方式从服务器取数据. 程序逻辑很简单, 所以就用着复杂的同步机制了, 就每子线程向主线程发送windows消息报告一下状态就可以了. 主线程是个对话框程序. 本来一切都挺简单的, 可前两天领导跟我说:"我们准备尝试一下测驱动开发, 就从你这个小工具开始吧." 当时我说好, 可是后来想想一个对话框怎么用cpp unit去测呢. 所有子线程的消息都发到主线程去了, cpp unit又怎么测这个呢.

    后来我想了想, 有没有什么东西能代替界面接收这些消息呢? 我也有段时间没做过界面相关的工作了, 还记得<<深入浅出MFC>>提到过每个继承自CCmdTarget的类都有消息处理的能力, 而CWinThread正是它的子类, 我是不是可以另外建一个UI线程(但不显示任何窗口)来代替主线程接收这些消息呢? 于是我做准备试一下. 书上说的建一UI线程很简单, 可我实际操作的时候还是遇到了一些问题. 下面是我的实验过程,是在VC2010下做的,  希望能对遇到同样问题的朋友有点帮助.

     1. 从CWinThread继承一个自己的线程类

//MyWorkThread.h

#define WM_MYMESSAGE  (WM_USER + 1) // 自定义消息, 就是我要发送的消息

class CMyWorkThread : public CWinThread
{
    DECLARE_DYNCREATE(CMyWorkThread)
public:
    afx_msg LRESULT OnThreadMessage( LPARAM lparam ,WPARAM wparam);  // 自定消息的处理函数
    BOOL InitInstance();  // 重写这个函数, 很重要哦
    DECLARE_MESSAGE_MAP()   // 申明消息映射表, 这个也很重要, 因为你要处理消息嘛
}; 

// MyWorkThread.cpp

#include "stdafx.h" #include "MyWorkThread.h"

IMPLEMENT_DYNCREATE(CMyWorkThread, CWinThread)

BEGIN_MESSAGE_MAP(CMyWorkThread, CWinThread)     ON_THREAD_MESSAGE(WM_MYMESSAGE, OnThreadMessage) // 这里用的不是ON_MESSAGE, 而是ON_THREAD_MESSAGE END_MESSAGE_MAP()

LRESULT CMyWorkThread::OnThreadMessage(LPARAM lparam, WPARAM wparam) {

// 这个消息响应函数没干什么实事, 就是显示一下收到了什么参数     CString strMsg;     strMsg.Format(_T("Lparam is %d, wparam is %d"), lparam, wparam);     AfxMessageBox(strMsg);

return 0; }

BOOL CMyWorkThread::InitInstance() {     return TRUE; // 这个很重要哦, 返回false的话, 这个线程是不会有消息循环的 }

写完这段代码习惯性的先编译一下, 结果是编译报错了: error C2440: “static_cast”: 无法从“LRESULT (__thiscall CMyWorkThread::* )(LPARAM,WPARAM)”转换为“void (__thiscall CWinThread::* )(WPARAM,LPARAM)”  在匹配目标类型的范围内没有具有该名称的函数

原来OnThreadMessage(LPARAM lparam ,WPARAM wparam)参数写反了, 真是眼睛瞎啊, 应该是WPARAM在前, LPARAM在后啊.于是我把这个函数改成

afx_msg LRESULT OnThreadMessage( WPARAM Wparam ,LPARAM lparam);

再编译, 还是报错了, error C2440: “static_cast”: 无法从“LRESULT (__thiscall CMyWorkThread::* )(WPARAM,LPARAM)”转换为“void (__thiscall CWinThread::* )(WPARAM,LPARAM)”
唉, 我咋就这样不顺利呢, 咋还报这个错, 正常的ON_MESSAGE消息处理函数不都是这样写的吗. 我开始怀疑是不是基类的函数指针不能接受的子类的函数? 于是我回过头去看MFC自己生成的对话框的添加消息映射代码:

ON_BN_CLICKED(IDC_BTN_SEND_MSG, &CScanDirDlg::OnBnClickedBtnSendMsg)

没错啊, 它也是用子类自己的函数做处理函数的啊, 难道非得要用&CScanDirDlg::OnBnClickedBtnSendMsg这样的形式? 于是呼我又把添加消息映射的代码改成

ON_THREAD_MESSAGE(WM_MYMESSAGE, &CMyWorkThread::OnThreadMessage) 再重新编译. 天哪, 还是报同样的错误. 这个问题纠结我了一个晚上啊, 我去百度, google都没有找到上体什么原因. 我好歹也写了几年程序了, 就不信还解决不了这个问题 !! 于是今天继续奋斗, 朋友们可别笑我啊, 写几年程序的人连这样的错误都没发现? 我想很多朋友都跟我有过类似的经历吧. 今天我又看了一眼那个错误信息, 突然之间眼前一亮, 妈的, 原来是返回值类型不匹配啊. 惭愧啊, 看出了这个错误我差点没晕过去, 真是哭笑不得啊.

2 纠正了前面那错误后编译终于通过了. 接下来该创建线程并测一下能不能正常工作了, 于是我在对话框的OnOK函数里写下了下面这段代码:

m_pWorkThread = AfxBeginThread(RUNTIME_CLASS(CMyWorkThread)); // CWinThread* m_pWorkThread是对话框的一个成员
                                                              // 这个线程只用来接收消息, 不需要线程函数


 

又在另一个按钮响应函数写了下面这段代码:

m_pWorkThread->PostThreadMessage(WM_QUIT, 0, 0); //  不是PostMessage() 哦

期待的对话框出现了. 可是新的问题又产生了, 那就是当我调用
m_pWorkThread->PostThreadMessage(WM_QUIT, 0, 0); 想结束线程的时候程序出异常了. 而且这个异常是在threadcore.cpp是报出来的, 这是VC的库文件啊. 后我把InitInstance这函数下面这样

BOOL CMyWorkThread::InitInstance()
{
    m_pMainWnd = NULL;
    m_pActiveWnd = NULL;
    m_bAutoDelete = FALSE;
    return TRUE;
}

程序就可以正常工作, 至于这是为什么? 我也还没搞明白, 还得继续探索. 不过种情况下我们得自己去负责删除这个线程对象了.


已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页