/***********************************************************************************************************************************
学习课程:孙鑫老师的VC++教程的第十五课《多线程编程》
遭遇问题:课程的源代码是在VC6.0中编写的,在VC++2010的Unicode(默认)编码的开发环境中不能通过,有的地方需要作出相应的改变。
****************************************************************************************************************************************/
改动1:课程中用到一个自写的消息映射,在头文件的声明与在源文件中添加的消息映射分别如下:
1.声明:afx_msg void OnRecvData(WPARAM wParam,LPARAM lParam);
2.消息映射:ON_MESSAGE(WM_RECVDATA,OnRecvData)
在VC++2010中,消息的检查更为严格,这样的消息映射在检查时不允许通过。在VC++2010中,OnMessage返回值必须为LRESULT,其形式为:
afx_msg LRESULT OnMessage(WPARAM, LPARAM);
相应的消息映射应改为:
ON_MESSAGE(WM_RECVDATA,&CChatRoomDlg::OnRecvData)
改动2:在发送按钮的消息相应函数中,有如下代码:
sendto(m_socket,strSend,strSend.GetLength()+1,0,
(SOCKADDR*)&addrTo,sizeof(SOCKADDR));
sreSend为CString对象,而sendto的第二个参数所要类型为char*,CString在多字节编码的开发环境中可以默认转换为char*类型,但在Unicode环境中便会报错。所以需要进行强制转换,改动后的代码如下:
sendto(m_socket,(char*)strSend.GetBuffer(),strSend.GetLength()*2+2,0,
//UNICODE下不支持(char*)strSend这样的强制转换
//发送的长度也应为原来的两倍
(SOCKADDR*)&addrTo,sizeof(SOCKADDR));
strSend.ReleaseBuffer(); //当调用GetBuffer后在合适的地方ReleaseBuffer是个好习惯
改动3:在线程函数RecvProc中,最后把相关数据用SetDlgItemText函数显示在编辑框中时,由于SetDlgItemText需要的是宽字符类型,接收到的IP信息与消息内容必须都转换为宽字符类型,详细请参考改动后的注释。
课程原来的代码如下:
DWORD WINAPI CChatDlg::RecvProc(LPVOID lpParameter)
{
SOCKET sock=((RECVPARAM*)lpParameter)->sock;
HWND hwnd=((RECVPARAM*)lpParameter)->hwnd;
delete lpParameter;
SOCKADDR_IN addrFrom;
int len=sizeof(SOCKADDR);
char recvBuf[200];
char tempBuf[300];
int retval;
while(TRUE)
{
retval=recvfrom(sock,recvBuf,200,0,(SOCKADDR*)&addrFrom,&len);
if(SOCKET_ERROR==retval)
break;
sprintf(tempBuf,"%s说: %s",inet_ntoa(addrFrom.sin_addr),recvBuf);
::PostMessage(hwnd,WM_RECVDATA,0,(LPARAM)tempBuf);
}
return 0;
}
改动后的代码如下:
DWORD WINAPI CChatRoomDlg::RecvProc(LPVOID lpParameter)
{
SOCKET sock=((RECVPARAM*)lpParameter)->sock;
HWND hwnd=((RECVPARAM*)lpParameter)->hwnd;
delete lpParameter;
SOCKADDR_IN addrFrom;
int len=sizeof(SOCKADDR);
wchar_t recvBuf[200];
wchar_t tempBuf[200];
//wchar_t ipstr[100];
//DWORD i=100;
int retval;
while(TRUE)
{
retval=recvfrom(sock,(char*)recvBuf,200,0,(SOCKADDR*)&addrFrom,&len);
if(SOCKET_ERROR==retval)
break;
//也可以用这个函数来获取发送端的地址信息,
//地址信息将保存在ipstr中,不仅包括ip地址,还有端口
//ipstr的类型为宽字符类型,在格式化输出的时候不需要做类型转换
//WSAAddressToString((SOCKADDR*)&addrFrom,len,NULL,ipstr,&i);
//因为inet_ntoa函数返回的ip地址是char*类型,
//需要转换成wchar_T*类型以便格式
//化输出,用函数MultiByteToWideChar来实现
char *ip=inet_ntoa(addrFrom.sin_addr);
wchar_t *wIp=new wchar_t[100]; //比如长度100
memset(wIp,0,sizeof(wchar_t*));
MultiByteToWideChar(CP_ACP,0,ip,-1,wIp,16); //点分10进制格式地址最长也就15
//位(如"192.233.156.256"),故最后一个参数传16足够
wsprintf(tempBuf,L"%s说:%s",wIp/*ipstr*/,recvBuf);
delete[] wIP; //注意释放空间
::PostMessageA(hwnd,WM_RECVDATA,0,(LPARAM)tempBuf);
}
return 0;
}
转载于:https://blog.51cto.com/8298926/1793316