l 问题描述
Tcp网络通信中,服务器端接收到来自客户端的连接请求并成功的建立连接,当收到来自客户端的数据时,对数据进行解析,并实现对应操作,有需要的话将在对话框中显示相应信息。通信过程中,在服务器端建立了三个线程完成主要工作,一个监听连接请求线程,另两个为来自两个客户端的数据接收监听。在接收数据解析时,将信息显示到编辑框时报错,(在线程中调用printfMsg()就出错,其他函数中调用不出错),如下所示:
显示部分调用了一个自定义函数:printfMsg()
l 报错原因分析
经查博文及资料得知问题出在线程中不能直接调用UpdateData()函数。
MFC对象不支持多线程操作,不能供多个线程进程使用。子线程调用pDlg-> UpdateData(FALSE)时主线程(界面线程)会阻塞,更新必须由它完成,这样就形成死锁。UpdateData()函数属于CDialog类的保护成员函数,在工作线程中不能使用UpdateData来更新主线程中的数据。更改界面的操作最好用主线程(界面线程),要想在子线程(工作线程)里执行界面线程的操作,可以通过向主线程发送消息来解决。
l 解决方法
方法有三:
1. 创建线程时使用AfxBeginThread创建CWinThread继承类,参数传递时最好传递窗口句柄(主线程向子线程传递对象不安全),使用PostMessage或SendMessage消息传递函数向主窗口发送自定义消息,在主窗口中对自定义消息进行处理并更新。
2. 使用control变量或直接获取控件指针进行更新:
dlg->m_editCtl.SetWindowText(dlg->m_value2);
dlg->GetDlgItem(IDC_EDIT2)->SetWindowText(dlg->m_value2);
3. 最简单的办法,将Debug改为Release正常运行。
l 具体操作
采用了方法一进行了修改,成功实现显示,(方法2、3未验证)步骤如下:
1. MFC添加自定义消息
由于MFC中无法通过类向导来自定义消息,所以需要手动添加,主要过程如下:
1)定义消息
在xxDlg.h文件中添加:#define WM_UPDATEDATA(WM_USER+100)
【由于很多新控件也会用到WM_USER消息,所以定义WM_USER+100或更高,避免冲突。看到有的博文说将消息定义到stdafx.h文件中(Resource.h文件由系统维护,经常出现自定义的消息丢失。),也有博文说直接加到xxDlg.h中,在此采用后者。】
2)声明消息响应函数
依然在当前xxDlg.h中,添加消息响应函数,在DECLARE_MESSAGE_MAP前面。
3)实现消息响应函数
参考博文中说明:由于在vs2008中未定义ON_MESSAGE_VOID,所以定义的消息响应函数必须有返回值,即LRESULT;而消息参数是WPARAMwParam和LPARAM lParam
在xxDlg.cpp中,添加如下程序:
4)将消息映射到消息处理函数
放在AFX_MSG_MAP之前,把WM_UPDATEDATA消息映射到消息响应函数OnUpdateData,作如下添加:
5)发送自定义消息
备注:将该步骤的添加注释掉之后不影响需要实现的功能,原因暂时未知。
以下函数是在一个新的线程中调用的,推荐使用SendMessageTimeout函数,PostMessage,SendMessage,SendMessageTimeout均可用。
在xxDlg.h下添加新线程:
static UINT SendMsgThread(LPVOIDlpParam);
在xxDlg.cpp下添加相应程序:
2. 在原工程中,将printfMsg()改动:
至此,改动添加完毕。
可接收到数据并显示对应信息:
另外,参考博文上说:
【如果用户需要一个定义整个系统唯一的消息,可以调用SDK函RegisterWindowMessage定义消息:在Resource.h中将代码#define WM_UPDATEDATA (WM_USER + 100)
修改为static UINT WM_UPDATEDATA=RegisterWindowMessage(_T("User"));并使用ON_REGISTERED_MESSAGE宏指令取代ON_MESSAGE宏指令,其余步骤同上。
注:如果仍然使用ON_MESSAGE宏指令,compile可以通过,但是无法响应消息。】
暂未验证该方法。