📄 netphonedlg.cpp
字号:
COLORREF col;
CRect cRect;
UINT x,y;
CRgn wndRgn,rgnTemp;
// 取得窗口大小
GetWindowRect(&cRect);
// 背景位图资源ID
m_BackBitmapID = BackBitmapID;
// 装载模板位图
cBitmap.LoadBitmap(MaskBitmapID);
memDC.CreateCompatibleDC(pDC);
pOldMemBmp = memDC.SelectObject(&cBitmap);
// 首先创建默认的完整区域为完整的对话框窗口区域
wndRgn.CreateRectRgn(0,0,cRect.Width(),cRect.Height());
// 下面两层循环为检查背景位图像素颜色,
// 当像素颜色为指定的透明颜色时,将该点从区域中裁减掉
for(x=m_FrameWidth+m_MaskLeftOff;x<=cRect.Width()-m_FrameWidth-m_MaskRightOff;x++)
{
for(y=m_CaptionHeight+m_MaskTopOff;y<=cRect.Height()-m_FrameWidth-m_MaskBottomOff;y++)
{
// 取得坐标处像素的颜色值
col = memDC.GetPixel(x-m_FrameWidth-m_MaskLeftOff,y-m_CaptionHeight-m_MaskTopOff);
if(col==TransColor)
{
// 像素颜色为指定的透明颜色,创建透明的“微区域”
rgnTemp.CreateRectRgn(x,y,x+1,y+1);
// 从完整的区域中裁减掉透明的“微区域”
wndRgn.CombineRgn(&wndRgn,&rgnTemp,RGN_XOR);
// 删除刚创建的“微区域”,释放系统资源
rgnTemp.DeleteObject();
}
}
}
if(pOldMemBmp)
memDC.SelectObject(pOldMemBmp);
// 设定窗口为指定的区域,并且擦除窗口重绘
SetWindowRgn((HRGN)wndRgn,TRUE);
}
// WM_ERASEBKGND消息处理函数
BOOL CNetPhoneDlg::OnEraseBkgnd(CDC* pDC)
{
CRect rect;
CDC memDC;
CBitmap cBitmap;
CBitmap* pOldMemBmp=NULL;
// 得到窗口区域
GetWindowRect(&rect);
// 加载背景位图
cBitmap.LoadBitmap(m_BackBitmapID);
memDC.CreateCompatibleDC(pDC);
pOldMemBmp = memDC.SelectObject(&cBitmap);
// 将背景位图复制到窗口客户区
pDC->BitBlt(0,0,rect.Width(),rect.Height(),&memDC,0,0,SRCCOPY);
if(pOldMemBmp)
memDC.SelectObject(pOldMemBmp);
return TRUE;
// 删除系统缺省的OnEraseBkgnd()函数功能
// return CDialog::OnEraseBkgnd(pDC);
}
// WM_NCHITTEST消息响应函数,当鼠标移动、按下或者放开时此消息被发送给Window
UINT CNetPhoneDlg::OnNcHitTest(CPoint point)
{
UINT nHitTest = CDialog::OnNcHitTest(point);
return (nHitTest==HTCLIENT)?HTCAPTION:nHitTest;
// 删除系统缺省的OnNCHitTest()函数功能
// return CDialog::OnNcHitTest(point);
}
// 开始接收函数
void CNetPhoneDlg::OnReceive()
{
ON_MM_WOM_OPEN();
}
// “退出”按钮被按下消息处理函数
void CNetPhoneDlg::OnExit()
{
// 关闭套接字
Socket_Server.Close();
Socket_Listen.Close();
Socket_Client.Close();
// 释放缓冲区内存
for(int Exit=0;Exit<=1;Exit++)
{
delete pWaveHdrIn[Exit] ;
delete pWaveHdrOut[Exit] ;
free(pBufferIn[Exit]);
free(pBufferOut[Exit]) ;
waveInUnprepareHeader (hWaveIn, pWaveHdrIn[Exit], sizeof (WAVEHDR)) ;
waveOutUnprepareHeader (hWaveOut, pWaveHdrOut[Exit], sizeof (WAVEHDR)) ;
}
// 关闭音频设备
waveInClose (hWaveIn);
waveOutClose(hWaveOut);
// 释放按钮控件变量资源
delete m_pBtnCommunicate;
delete m_pBtnConnect;
delete m_pBtnDisconnect;
delete m_pBtnExit;
delete m_pBtnHelp;
delete m_pBtnMinimize;
// 清除托盘区图标
NOTIFYICONDATA nc;
nc.cbSize = sizeof(NOTIFYICONDATA);
nc.hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
nc.hWnd = m_hWnd;
nc.uCallbackMessage = WM_NC;
nc.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
nc.uID = IDC_NC;
Shell_NotifyIcon(NIM_DELETE, &nc);
CDialog::OnCancel();
}
// 初始化波形音频设备
BOOL CNetPhoneDlg::InitAudioDevice()
{
// 初始化waveform
waveform.wFormatTag = WAVE_FORMAT_PCM ; // 采样方式,PCM(脉冲编码调制)
waveform.nChannels = 2 ; // 双声道
waveform.nSamplesPerSec = 11025 ; // 采样率11.025KHz
waveform.nAvgBytesPerSec = 11025; // 数据率11.025KB/s
waveform.nBlockAlign = 2 ; // 最小块单元,wBitsPerSample×nChannels/8
waveform.wBitsPerSample = 8 ; // 样本大小为8bit
waveform.cbSize = 0 ; // 附加格式信息
// 准备pWaveHdrIn和pWaveHdrOut
for(int HdrNum=0;HdrNum<=1;HdrNum++)
{
// 为缓冲区分配内存
pBufferIn[HdrNum] = (PBYTE)malloc (INP_BUFFER_SIZE) ;
pBufferOut[HdrNum] = (PBYTE)malloc (INP_BUFFER_SIZE) ;
if (!pBufferIn[HdrNum] || !pBufferOut[HdrNum])
{
if (pBufferIn[HdrNum])
free (pBufferIn[HdrNum]) ;
if (pBufferOut[HdrNum])
free (pBufferIn[HdrNum]) ;
AfxMessageBox(_T("内存分配失败!"),MB_ICONINFORMATION|MB_OK,NULL);
}
pWaveHdrIn[HdrNum] =new WAVEHDR;
pWaveHdrOut[HdrNum]=new WAVEHDR;
pWaveHdrOut[HdrNum]->lpData = (char *)pBufferIn[HdrNum];
pWaveHdrOut[HdrNum]->dwBufferLength = INP_BUFFER_SIZE ;
pWaveHdrOut[HdrNum]->dwBytesRecorded = 0 ;
pWaveHdrOut[HdrNum]->dwUser = 0 ;
pWaveHdrOut[HdrNum]->dwFlags = WHDR_BEGINLOOP | WHDR_ENDLOOP ;
pWaveHdrOut[HdrNum]->dwLoops = 1;
pWaveHdrOut[HdrNum]->lpNext = NULL ;
pWaveHdrOut[HdrNum]->reserved = 0 ;
pWaveHdrIn[HdrNum]->lpData = (char *)pBufferOut[HdrNum] ;
pWaveHdrIn[HdrNum]->dwBufferLength = INP_BUFFER_SIZE ;
pWaveHdrIn[HdrNum]->dwBytesRecorded = 0 ;
pWaveHdrIn[HdrNum]->dwUser = 0 ;
pWaveHdrIn[HdrNum]->dwFlags = WHDR_BEGINLOOP | WHDR_ENDLOOP ;
pWaveHdrIn[HdrNum]->dwLoops = 1 ;
pWaveHdrIn[HdrNum]->lpNext = NULL ;
pWaveHdrIn[HdrNum]->reserved = 0 ;
}
// 打开播放波形音频设备
MMRESULT result;
result=waveOutOpen (&hWaveOut, WAVE_MAPPER, &waveform,
(DWORD) pDlg->m_hWnd, 0, CALLBACK_WINDOW);
// 打开录制波形音频设备
if(result==MMSYSERR_NOERROR)
result=waveInOpen (&hWaveIn, WAVE_MAPPER, &waveform,
(DWORD) pDlg->m_hWnd, 0, CALLBACK_WINDOW);
// 为播放和录音准备
for(int Prepare=0;Prepare<=1;Prepare++)
{
if(result==MMSYSERR_NOERROR)
result=waveOutPrepareHeader(hWaveOut, pWaveHdrOut[Prepare],
sizeof (WAVEHDR)) ;
if(result==MMSYSERR_NOERROR)
result=waveInPrepareHeader(hWaveIn, pWaveHdrIn[Prepare],
sizeof (WAVEHDR)) ;
}
// 设置音量为最大
if(result==MMSYSERR_NOERROR)
result=waveOutSetVolume(hWaveOut,65535);
// 成功返回TRUE
if(result==MMSYSERR_NOERROR)
{
return TRUE;
}
else
{
AfxMessageBox(_T("打开波形音频设备时发生错误!"),MB_ICONINFORMATION | MB_OK,NULL);
return FALSE;
}
}
// 开始录音
void CNetPhoneDlg::RecordBegin()
{
// 准备录音缓冲区
waveInAddBuffer (hWaveIn, pWaveHdrIn[nOut], sizeof (WAVEHDR)) ;
// 开始录音
waveInStart (hWaveIn) ;
}
// MM_WIM_OPEN消息处理函数,开始录音时产生
void CNetPhoneDlg::ON_MM_WIM_OPEN()
{
}
//MM_WIM_DATA消息处理函数,缓冲区满时产生
void CNetPhoneDlg::ON_MM_WIM_DATA()
{
// 发送缓冲区中录制的音频数据
Socket_Client.Send(pBufferOut[nOut],INP_BUFFER_SIZE);
// 缓冲区循环
nOut=1-nOut;
if (bDisconnectState==TRUE)
{
waveInClose (hWaveIn) ;
}
else
{
// 开始下一轮录音
RecordBegin();
}
}
//MM_WIM_CLOSE消息处理函数,关闭录音设备时产生
void CNetPhoneDlg::ON_MM_WIM_CLOSE()
{
waveInUnprepareHeader (hWaveIn, pWaveHdrIn[0], sizeof (WAVEHDR)) ;
waveInUnprepareHeader (hWaveIn, pWaveHdrIn[1], sizeof (WAVEHDR)) ;
waveInClose (hWaveIn);
hWaveIn=NULL; //clear it
}
//MM_WOM_OPEN消息处理函数,打开播放设备时产生
void CNetPhoneDlg::ON_MM_WOM_OPEN()
{
// 接收对方发送过来的音频数据
Socket_Server.Receive((void *)pBufferIn[nIn],INP_BUFFER_SIZE);
// 播放接收缓冲区中音频数据
waveOutWrite (hWaveOut, pWaveHdrOut[nIn], sizeof (WAVEHDR)) ;
nIn=1-nIn;
// 显示通话状态
if (nComState==1)
::SetDlgItemText(pDlg->m_hWnd,IDC_STATIC_INFORMATION,"通话中");
else
::SetDlgItemText(pDlg->m_hWnd,IDC_STATIC_INFORMATION,"");
nComState++;
if(nComState==10)
nComState=1;
}
// “连接”按钮被按下消息处理函数
void CNetPhoneDlg::OnButtonConnect()
{
UpdateData(TRUE);
// “连接”按钮被按下
bBtnConnectDown=TRUE;
bClientState=TRUE;
// 连接被呼叫主机,端口5000
Socket_Client.Connect(m_sServerIP,5000);
GetDlgItem(IDC_BUTTON_CONNECT)->EnableWindow(FALSE);
}
// “通话”按钮被按下消息处理函数,只有被呼叫时该按钮才有效
void CNetPhoneDlg::OnButtonCommunicate()
{
// 设置各个按钮状态
GetDlgItem(IDC_BUTTON_DISCONNECT)->EnableWindow(TRUE);
GetDlgItem(IDC_BUTTON_COMMUNICATE)->EnableWindow(FALSE);
GetDlgItem(IDC_BUTTON_CONNECT)->EnableWindow(FALSE);
// 处于连接状态,所以bDisconnectState=FALSE
bDisconnectState=FALSE;
// 程序运行后,只初始化一次音频设备
if(m_bFirstRunAudio==TRUE)
{
if(InitAudioDevice())
m_bFirstRunAudio=FALSE;
else
{
AfxMessageBox(_T("初始化波形音频设备失败!"),MB_ICONINFORMATION | MB_OK,NULL);
return;
}
}
// “通话”按钮按下之前,程序不处于客户端状态,即bClientState=FALSE
if(bClientState==FALSE)
{
// 连接呼叫主机,端口5000
Socket_Client.Connect(sRemoteIP,5000);
Sleep(100);
// 发送“ABCDEFGHIJKLMNO”给呼叫主机,表示同意通话
Socket_Client.Send("ABCDEFGHIJKLMNO",15);
::SetDlgItemText(pDlg->m_hWnd,IDC_STATIC_INFORMATION,sRemoteIP);
// 此时被呼叫端同意通话,进入通话状态(客户端状态+服务器端状态)
bClientState=TRUE;
bServerState=TRUE;
// 开始录音
RecordBegin();
}
else
{
RecordBegin();
}
}
// “断开”按钮被按下消息处理函数
void CNetPhoneDlg::OnButtonDisconnect()
{
// 被呼叫方发送“NO”给呼叫方,表示不接听电话
if(bBtnConnectDown==FALSE)
Socket_Client.Send("NO",15);
// 通话中一方断开电话
else
{
// 还原状态字
bDisconnectState=TRUE;
bServerState =FALSE;
bClientState =FALSE;
bBtnConnectDown =FALSE;
// 关闭套接字
Socket_Server.ShutDown();
Socket_Client.ShutDown();
Socket_Listen.ShutDown();
Socket_Server.Close();
Socket_Listen.Close();
Socket_Client.Close();
Sleep(100);
// 设置按钮状态
GetDlgItem(IDC_BUTTON_COMMUNICATE)->EnableWindow(FALSE) ;
GetDlgItem(IDC_BUTTON_DISCONNECT)->EnableWindow(FALSE) ;
GetDlgItem(IDC_BUTTON_CONNECT)->EnableWindow(TRUE) ;
GetDlgItem(IDC_BUTTON_CONNECT)->SetFocus();
//Socket 初始化
if (!AfxSocketInit())
{
AfxMessageBox("Windows sockets initialization failed.");
}
Socket_Listen.Create(5000,SOCK_STREAM);
Socket_Listen.Bind(5000,LocalIP);
Socket_Listen.Listen();
Socket_Client.Create(5001,SOCK_STREAM);
}
}
// “帮助”按钮被按下消息处理函数
void CNetPhoneDlg::OnHelp()
{
CAboutDlg Dlg;
Dlg.DoModal();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -