gusucode.com > 基于VC++的局域网视频聊天系统源码程序 > 基于VC++的局域网视频聊天系统源码程序/code/ChatClient/ChatClientDlg.cpp
// ChatClientDlg.cpp : implementation file // #include "stdafx.h" #include "ChatClient.h" #include "ChatClientDlg.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #include "SocketClient.h" #include "Mesg.h" ///////////////////////////////////////////////////////////////////////////// // CChatClientDlg dialog CChatClientDlg::CChatClientDlg(CWnd* pParent /*=NULL*/) : CDialog(CChatClientDlg::IDD, pParent) { //{{AFX_DATA_INIT(CChatClientDlg) // NOTE: the ClassWizard will add member initialization here m_szServerIP = _T(""); m_szPWD = _T(""); m_szID = _T(""); m_bConnect = FALSE; //}}AFX_DATA_INIT // Note that LoadIcon does not require a subsequent DestroyIcon in Win32 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); } void CChatClientDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CChatClientDlg) DDX_Control(pDX, IDC_MESSAGEBOX, m_clMessageBox); //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CChatClientDlg, CDialog) //{{AFX_MSG_MAP(CChatClientDlg) ON_BN_CLICKED(IDC_CHAT_BT_SEND, OnChatBtSend) ON_LBN_SELCHANGE(IDC_USERLIST, OnSelchangeUserlist) ON_BN_CLICKED(IDC_CHAT_BT_SHIPI, OnChatBtShipi) ON_WM_TIMER() ON_MESSAGE(WM_TRAYNOTIFY,OnTrayNotify) //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CChatClientDlg message handlers BOOL CChatClientDlg::OnInitDialog() { CDialog::OnInitDialog(); // Set the icon for this dialog. The framework does this automatically // when the application's main window is not a dialog SetIcon(m_hIcon, TRUE); // Set big icon SetIcon(m_hIcon, FALSE); // Set small icon // TODO: Add extra initialization here //建立登陆对话框 m_dlgLogin = new CLoginDlg(this); int res = LoginDlgCtrl() ; if( res == -1 ) { EndDialog(1); return TRUE; } this->EnableWindow(FALSE); m_Retry = 0; m_bVidInit = FALSE; m_bStart = FALSE; m_bExitNow = FALSE; m_AFrames = 0; m_ABytesSent=0; m_VFrames = 0; m_VBytesSent = 0; // Setup the parent for differnt datagram sockets dcontrol.SetParent(this); dcontrol.CreateSocket(PORT_CONTROL,TYPE_CONTROL); m_VUnComped =NULL; m_VComped =NULL; m_AUnComped =NULL; m_AComped =NULL; m_vidcap = NULL; m_bmpinfo = NULL; hdib = NULL; // setup Video Codec m_VideoCodec.SetCodecType (MS_MPEG4V3); m_VideoCodec.SetParent (this); // m_LocalDlg.EnableWindow (FALSE); m_RemoteDlg.Create (IDD_REMTOE,this); m_RemoteDlg.SetParent (this); m_RemoteDlg.ShowWindow (SW_HIDE); m_LocalDlg.Create(IDD_LOCAL,this); m_LocalDlg.SetParent(this); m_LocalDlg.ShowWindow(SW_HIDE); m_AudioPlay=new CAudioPlay(this); m_AudioPlay->CreateThread(); if(m_AudioPlay) { m_AudioPlay->PostThreadMessage(WM_PLAYSOUND_STARTPLAYING,0,0); } m_AudioRec=new CAudioRec(this); m_AudioRec->CreateThread(); m_State=STATE_IDLE; SetWindowText(m_szID); SetTimer(1,2000,NULL); return TRUE; // return TRUE unless you set the focus to a control } //设置消息显示 void CChatClientDlg::SetMessageBox(CString mes) { m_clMessageBox.SetSel(m_clMessageBox.GetTextLength(), m_clMessageBox.GetTextLength()+1); m_clMessageBox.ReplaceSel(mes); m_clMessageBox.LineScroll(3); } //发送信息按键 void CChatClientDlg::OnChatBtSend() { // TODO: Add your control notification handler code here if( !m_bConnect) { SetMessageBox("请连接服务器!\r\n"); return ; } CString str; CString szUserName; CMesg msg; GetDlgItemText(IDC_MESSAGE,str); GetDlgItemText(IDC_USERNAME,szUserName); if( str.GetLength() <= 0 ) { SetMessageBox("请输入想要发送的信息!\r\n"); return ; } if ( szUserName.GetLength() <= 0) { SetMessageBox("请选择说话对象!\r\n"); return ; } //消息封装 msg.m_szCommand.Format("Message"); msg.m_szRecObject.Format(szUserName); msg.m_szText.Format(str); m_csClient->SendM(&msg); AddReceiver(szUserName , true); AddChatMessage(str); } //登陆窗口的操作 int CChatClientDlg::LoginDlgCtrl() { CMesg msg; while(1) { while (1) { //弹出登陆对话框,关闭时返回对应值 int cmd = m_dlgLogin->DoModal(); //点击了退出关闭程序 if(cmd == -1) { return -1; } else //点击了登陆的响应 break; } /*初始化客户套接字*/ m_csClient = new CSocketClient(); /*创建套接字*/ if ( !m_csClient->Create() ) { MessageBox("套接字创建失败!","提示"); continue; } /*连接服务器*/ if ( !m_csClient->Connect(m_szServerIP,8123) ) { delete m_csClient; m_csClient = NULL; MessageBox("连接服务器失败,请稍后重试。","提示"); continue; } m_bConnect = TRUE; m_csClient->Init(this); //初始化套接字 msg.m_szCommand.Format("Login"); msg.m_szRecObject.Format("Server"); msg.m_szID.Format(m_szID); msg.m_szPWD.Format(m_szPWD); msg.m_szIP.Format(m_szLocalIP); m_csClient->SendM(&msg); return 1; } return 1; } ////////////////////////////////////////////////////////////////////////// //保存用户ID和IP的相关信息到链表 void CChatClientDlg::AddUserInfoToChain(CString ID, CString IP) { USERINFO * newUser = new USERINFO; newUser->ID = ID; newUser->IP = IP; m_userInfo.AddTail(newUser); } //从链表中删除用户ID和IP的相关信息 void CChatClientDlg::DelUserInfoFromChain(CString ID) { POSITION pos,t_pos; for( pos=m_userInfo.GetHeadPosition() ; (t_pos = pos) != NULL ; ) { USERINFO * t= (USERINFO *)m_userInfo.GetNext(pos); if ( t->ID == ID ) { m_userInfo.RemoveAt(t_pos); } } } //用户连接后通过了服务器验证,加入到用户列表 void CChatClientDlg::AddUserToList(CString szNickName) { ((CListBox *)GetDlgItem(IDC_USERLIST))->AddString(szNickName); } //删除用户从列表中 void CChatClientDlg::DelUserFromList(CString szNickName) { int index; index = ((CListBox *)GetDlgItem(IDC_USERLIST))->FindString(0,szNickName); ((CListBox *)GetDlgItem(IDC_USERLIST))->DeleteString(index); } //更新在线人数 void CChatClientDlg::SetOnlineNum(int Num) { CString temp; temp.Format("用户(%d人)",Num); GetDlgItem(IDC_ONLINE_USRLIST)->SetWindowText(temp); } //将最近聊天的内容保存 void CChatClientDlg::AddChatMessage(CString Words) { CComboBox * ComboBox = (CComboBox *)GetDlgItem(IDC_MESSAGE); ComboBox->InsertString(0,Words); if(ComboBox->GetCount() >= 6) ComboBox->DeleteString(5); ComboBox->SetEditSel(0, -1); ComboBox->Clear(); } //定位现在的接收人 void CChatClientDlg::SetCurInComboxUserName(int index) { CComboBox * ComboBox = (CComboBox *)GetDlgItem(IDC_USERNAME); ComboBox->SetCurSel(index); } //改在现在接信人的函数 void CChatClientDlg::AddReceiver(CString NickName, bool Bool) { CComboBox * ComboBox = (CComboBox *)GetDlgItem(IDC_USERNAME); if( Bool ) { ComboBox->InsertString(0,NickName); if( ComboBox->GetCount() >= 7 ) { ComboBox->DeleteString(5); } SetCurInComboxUserName( 0 ); } else { ComboBox->DeleteString( ComboBox->GetCount()-1 ); ComboBox->AddString(NickName); SetCurInComboxUserName( ComboBox->GetCount()-1 ); } } //列表框中选项变化响应 void CChatClientDlg::OnSelchangeUserlist() { // TODO: Add your control notification handler code here int Index; CString NickName; CListBox * UserList = (CListBox *)GetDlgItem(IDC_USERLIST) ; Index = UserList->GetCurSel(); UserList->GetText(Index, NickName); AddReceiver(NickName , false); } //清空列表 void CChatClientDlg::SetListEmpty() { ((CListBox *)GetDlgItem(IDC_USERLIST))->ResetContent(); } //发送信息对象对话框的清空 void CChatClientDlg::SetUserNameEmpty() { CComboBox * ComboBox = (CComboBox *)GetDlgItem(IDC_USERNAME); ComboBox->ResetContent(); } void CChatClientDlg::OnChatBtShipi() { // TODO: Add your control notification handler code here CString temp,Ip; CString NickName; int index = ((CComboBox * )GetDlgItem(IDC_USERNAME))->GetCurSel(); ((CComboBox * )GetDlgItem(IDC_USERNAME))->GetLBText(index,temp); char hostname[200]; ZeroMemory(hostname,sizeof(hostname)); POSITION pos,t_pos; for( pos=m_userInfo.GetHeadPosition() ; (t_pos = pos) != NULL ; ) { USERINFO * t= (USERINFO *)m_userInfo.GetNext(pos); if ( t->ID == temp) { Ip=t->IP; break; } } strcpy(hostname,Ip); int ret=IDC_CHAT_BT_SHIPI; m_bStart=!m_bStart; if(m_bStart) { m_State=STATE_CALLOUT; if(ret!=IDC_CHAT_BT_SHIPI) return; UpdateData(TRUE); dcontrol.SendControlMessage(MESG_CONNECT,hostname); m_dwLastTime=GetTickCount(); } else { if(m_State) { INT ret=AfxMessageBox("退出视频聊天?",MB_OKCANCEL); // if(ret!=IDC_CHAT_BT_SHIPI) return; if(ret=IDOK) { // ShowWindow(SW_HIDE); m_bExitNow=TRUE; dcontrol.SendControlMessage (MESG_DISCONNECT,dcontrol.remoteaddress ); DestroyVideo(); if(m_AudioPlay) { m_AudioPlay->PostThreadMessage(WM_PLAYSOUND_STOPPLAYING,0,0); m_AudioPlay->PostThreadMessage(WM_RECORDSOUND_ENDTHREAD,0,0); Sleep(200); delete m_AudioPlay; } if(m_AudioRec) { m_AudioRec->PostThreadMessage(WM_PLAYSOUND_ENDTHREAD,0,0); Sleep(200); delete m_AudioRec; } m_LocalDlg.FreeSource(); m_RemoteDlg.FreeSource(); } } } } BOOL CChatClientDlg::InitCap() { TRACE("ChatClientDlg::InitCap\n"); if(m_bVidInit) return TRUE; m_vidcap=new VideoCapture; m_vidcap->SetDialog(this); if(m_vidcap->Initialize()) // success { m_bmpinfo=&(m_vidcap->m_bmpinfo); m_bVidInit =TRUE; } else { if(m_bmpinfo) delete m_bmpinfo; m_bVidInit = FALSE; m_bmpinfo=new BITMAPINFO; m_bmpinfo->bmiHeader.biSize=sizeof(BITMAPINFOHEADER); m_bmpinfo->bmiHeader.biWidth=IMAGE_WIDTH; m_bmpinfo->bmiHeader.biHeight=IMAGE_HEIGHT; m_bmpinfo->bmiHeader.biPlanes=1; m_bmpinfo->bmiHeader.biBitCount=24; m_bmpinfo->bmiHeader.biCompression=0; m_bmpinfo->bmiHeader.biSizeImage=IMAGE_WIDTH*IMAGE_HEIGHT*3; m_bmpinfo->bmiHeader.biXPelsPerMeter=0; m_bmpinfo->bmiHeader.biYPelsPerMeter=0; m_bmpinfo->bmiHeader.biClrUsed=0; m_bmpinfo->bmiHeader.biClrImportant=0; } return m_bVidInit; } void CChatClientDlg::DestroyCap() { TRACE("ChatClientDlg::DestroyCap\n"); if(m_vidcap) { m_vidcap->StopCapture (); m_vidcap->Destroy (); delete m_vidcap; m_vidcap=NULL; } if(m_bmpinfo ) { if(!m_bVidInit) delete m_bmpinfo; m_bmpinfo=NULL; } m_bVidInit=FALSE; } BOOL CChatClientDlg::InitDib() { TRACE("ChatClientDlg::InitDib\n"); if(!hdib) { if((hdib=DrawDibOpen())!=NULL) { DrawDibBegin(hdib, m_hdc, -1, // don't stretch -1, // don't stretch &m_bmpinfo->bmiHeader, IMAGE_WIDTH, // width of image IMAGE_HEIGHT, // height of image 0 ); return TRUE; } } return TRUE; } void CChatClientDlg::DestroyDib() { TRACE("ChatClientDlg::DestroyDib\n"); if(hdib!=NULL) { DrawDibEnd(hdib); DrawDibClose(hdib); hdib=NULL; } } BOOL CChatClientDlg::StartVideo() { BOOL ret=TRUE; if(m_State == STATE_IDLE || m_State == STATE_CONNECTED) return FALSE; //timeout and rejected or already started if(!m_VideoCodec.Init ()) return FALSE; daudio.SetParent(this); dvideo.SetParent(this); ret = InitCap(); ret = InitDib() && ret; if(!daudio.CreateSocket(PORT_AUDIO,TYPE_AUDIO) || !dvideo.CreateSocket(PORT_VIDEO,TYPE_VIDEO) ) { DestroyVideo(); return FALSE; } if(m_vidcap && m_bVidInit) ret = m_vidcap->StartCapture () && ret; m_VUnComped = new char[m_bmpinfo->bmiHeader .biSizeImage]; // m_VComped = new char[m_bmpinfo->bmiHeader .biWidth * m_bmpinfo->bmiHeader .biHeight ]; m_AUnComped = new char[SIZE_AUDIO_FRAME]; m_AComped = new char[SIZE_AUDIO_PACKED]; //if(!m_VUnComped || !m_VComped || !m_AUnComped || !m_AComped) if(!m_VUnComped || !m_AUnComped || !m_AComped) { AfxMessageBox("分配视频压缩/解压缩内存出错!"); if(m_VUnComped) delete []m_VUnComped; if(m_VComped) delete []m_VComped; if(m_AUnComped) delete []m_AUnComped; if(m_AComped) delete []m_AComped; DestroyVideo(); return FALSE; } ZeroMemory(m_VUnComped,m_bmpinfo->bmiHeader .biSizeImage ); // ZeroMemory(m_VComped,m_bmpinfo->bmiHeader .biWidth * m_bmpinfo->bmiHeader .biHeight ); ZeroMemory(m_AUnComped,SIZE_AUDIO_FRAME); ZeroMemory(m_AComped,SIZE_AUDIO_PACKED); if(m_AudioRec) m_AudioRec->PostThreadMessage(WM_RECORDSOUND_STARTRECORDING,0,0); m_bExitNow = FALSE; m_bStart = TRUE; m_LocalDlg.EnableWindow (TRUE); m_RemoteDlg.EnableWindow (TRUE); RECT rc,rcrd; m_LocalDlg.GetClientRect(&rc); m_LocalDlg.ClientToScreen (&rc); m_RemoteDlg.GetClientRect (&rcrd); if(rc.left <(rcrd.right -rcrd.left )) ::SetWindowPos (m_RemoteDlg.m_hWnd,HWND_TOP,rc.right+1 ,rc.top ,m_bmpinfo->bmiHeader.biWidth+8 ,m_bmpinfo->bmiHeader.biHeight +24 ,0); else ::SetWindowPos (m_RemoteDlg.m_hWnd,HWND_TOP,rc.left- m_bmpinfo->bmiHeader.biWidth-8,rc.top ,m_bmpinfo->bmiHeader.biWidth+8 ,m_bmpinfo->bmiHeader.biHeight +24,0); // SetTextColor((m_LocalDlg.GetDC ())->m_hDC,0x00662200); if(m_LocalDlg.m_VidLocal) { m_LocalDlg.SetWindowText (_T("本地视频")); m_RemoteDlg.SetWindowText (dcontrol.remotename ); m_LocalDlg.SetWindowText (_T("本地")); }else { m_RemoteDlg.SetWindowText (_T("本地视频")); SetWindowText (dcontrol.remotename ); m_LocalDlg.SetWindowText (_T("远程")); } m_State=STATE_CONNECTED; OnTrayNotify(IDR_MAINFRAME,WM_LBUTTONUP); Invalidate (TRUE); m_RemoteDlg.ShowWindow (SW_SHOW); m_Retry = 0; m_ConnectTime=CTime::GetCurrentTime(); return ret; } void CChatClientDlg::DestroyVideo() { m_RemoteDlg.ShowWindow (SW_HIDE); m_LocalDlg.ShowWindow(SW_HIDE); m_State=STATE_IDLE; m_Retry=0; m_bExitNow=TRUE; if(m_AudioRec) m_AudioRec->PostThreadMessage(WM_RECORDSOUND_STOPRECORDING,0,0); DestroyCap (); DestroyDib (); m_VideoCodec.Destroy (); daudio.SetParent(NULL); dvideo.SetParent(NULL); daudio.CloseSocket(); dvideo.CloseSocket(); if(m_VUnComped) delete []m_VUnComped; m_VUnComped =NULL; if(m_VComped) delete []m_VComped; m_VComped =NULL; if(m_AUnComped) delete []m_AUnComped; m_AUnComped =NULL; if(m_AComped) delete []m_AComped; m_AComped =NULL; m_LocalDlg.EnableWindow (FALSE); if(m_bStart) dcontrol.SendControlMessage(MESG_DISCONNECT,dcontrol.remoteaddress); m_bStart = FALSE; m_RemoteDlg.m_bVideoIn =FALSE; // SetWindowText(_T("视频聊天")); Invalidate (TRUE); } void CChatClientDlg::SendVideo(BYTE *data, int size) { int comp=0; if(m_bExitNow ) return; if(data==NULL || size<=0) return; m_VComped = new char[size + 1000]; m_VideoCodec.EncodeVideoData((char*)data,size,m_VComped,&comp,0); if(comp>0) dvideo.SendVideoData((unsigned char *)m_VComped,comp); //Add Roman if(m_VComped != NULL){ delete []m_VComped; m_VComped=NULL; } m_VFrames++; m_VBytesSent +=comp; if(m_LocalDlg.m_VidLocal) { ::DrawDibDraw( hdib, //在这里的hdc应该是显示视频的窗口的hdc,但m_hdc在此之前并没有在任何地方赋值 m_LocalDlg.GetDC()->m_hDC, m_LocalDlg.m_Video_x, // dest : left pos m_LocalDlg.m_Video_y, // dest : top pos 176, // don't zoom x 144, // don't zoom y &m_bmpinfo->bmiHeader, // bmp header info data, // bmp data 0, // src :left 0, // src :top IMAGE_WIDTH, // src : width IMAGE_HEIGHT, // src : height DDF_SAME_DRAW // use prev params.... ); } else if( !m_LocalDlg.m_VidLocal && m_RemoteDlg) m_RemoteDlg.DisplayRemoteFrame ((unsigned char*)data,size); } void CChatClientDlg::PlayWavFile(LPCTSTR filename) { CFile f; DWORD size=0; char *p; if(f.Open (filename,CFile::modeRead | CFile::typeBinary,NULL)) { f.Seek (58,CFile::begin); size=f.GetLength (); p=new char[size]; if(!p) return; size=f.Read (p ,size); m_AudioPlay->PostThreadMessage(WM_PLAYSOUND_PLAYBLOCK,size,(LPARAM)p); Sleep(100); delete []p; f.Close (); } } void CChatClientDlg::OnTimer(UINT nIDEvent) { // TODO: Add your message handler code here and/or call default char szFps[256]=""; DWORD NowTime; CTime t=CTime::GetCurrentTime(); CTimeSpan ts = t - m_ConnectTime; switch(m_State) { case STATE_IDLE: break; case STATE_CONNECTED: NowTime=GetTickCount(); if(NowTime - m_dwLastTime>=2000) { sprintf(szFps,"%d:%02d:%02d", ts.GetHours (),ts.GetMinutes (),ts.GetSeconds ()); m_dwLastTime = NowTime; m_VFrames = 0;m_VBytesSent=0; m_AFrames = 0;m_ABytesSent=0; // DisplayMesg(szFps); } break; case STATE_CALLIN: case STATE_CALLOUT: PlayWavFile(m_State==STATE_CALLIN?"callin.wav":"callout.wav"); m_Retry++; sprintf(szFps,"等待对方应答: %d",m_Retry); if(m_Retry > 100) //wait 10s { DestroyVideo (); AfxMessageBox("对方无人应答,连接超时"); } break; } CDialog::OnTimer(nIDEvent); } LRESULT CChatClientDlg::OnTrayNotify(WPARAM wParam, LPARAM lParam) { switch(lParam) { case WM_LBUTTONUP: { BOOL res; m_tnid.cbSize = sizeof(NOTIFYICONDATA); m_tnid.hWnd = m_hWnd; m_tnid.uID = IDR_MAINFRAME; res = Shell_NotifyIcon(NIM_DELETE, &m_tnid); ShowWindow(SW_SHOWNORMAL); SetForegroundWindow(); SetActiveWindow(); if( m_bStart) { m_LocalDlg.UpdateData(); m_RemoteDlg.UpdateData(); m_RemoteDlg.ShowWindow (SW_SHOW); m_LocalDlg.ShowWindow(SW_SHOW); } } break; } return TRUE; }