⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 netphonedlg.cpp

📁 具有异形窗口的网络电话的程序
💻 CPP
📖 第 1 页 / 共 2 页
字号:
  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 + -