📄 modemdlg.cpp
字号:
case 5:
dcb.BaudRate=14400;
break;
case 6:
dcb.BaudRate=19200;
break;
case 7:
dcb.BaudRate=38400;
break;
case 8:
dcb.BaudRate=57600;
break;
default:
dcb.BaudRate=9600;
break;
}
switch(m_nDataBits) // 每字节位数
{
case 0:
dcb.ByteSize=5;
break;
case 1:
dcb.ByteSize=6;
break;
case 2:
dcb.ByteSize=7;
break;
case 3:
dcb.ByteSize=8;
break;
default:
dcb.ByteSize=8;
break;
}
dcb.fParity = TRUE;
switch(m_nParity) // 校验设置
{
case 0:
dcb.Parity=NOPARITY;
break;
case 1:
dcb.Parity=EVENPARITY;
break;
case 2:
dcb.Parity=ODDPARITY;
break;
default:
dcb.Parity=NOPARITY;
break;
}
switch(m_nStopBits) // 停止位
{
case 0:
dcb.StopBits=ONESTOPBIT;
break;
case 1:
dcb.StopBits=ONE5STOPBITS;
break;
case 2:
dcb.StopBits=TWOSTOPBITS;
break;
default:
dcb.StopBits=ONE5STOPBITS;
break;;
}
// 硬件流控制设置
dcb.fOutxCtsFlow = TRUE;
dcb.fRtsControl = TRUE;
// XON/XOFF流控制设置
dcb.fInX=dcb.fOutX = TRUE;
dcb.XonChar = XON;
dcb.XoffChar = XOFF;
dcb.XonLim = 50;
dcb.XoffLim = 50;
return SetCommState(m_hCom, &dcb);
}
//WM_COMMNOTIFY消息处理函数,只处理接收到数据消息,即EV_RXCHAR消息
LRESULT CModemDlg::OnCommNotify(WPARAM wParam, LPARAM lParam)
{
CString str;
int nLength, nTextLength;
DWORD dwModemStatus=0;
//如果不是EV_RXCHAR消息,该函数直接返回
if((m_bPortOpened==FALSE) || (wParam & EV_RXCHAR)!=EV_RXCHAR)
{
//使m_hPostMsgEvent成为有信号,即允许发送下一个WM_COMMNOTIFY消息
SetEvent(m_hPostMsgEvent);
return 0L;
}
//从串口读128字节数据
nLength=ReadComm(buf,128);
// 进入在线状态后,如果未设置定时器,则设置一个定时器
// 若超过定时器间隔时间没有串口事件,则WM_TIMER消息被触发,挂断连接
if(!m_bSetTimer&&m_bOnLine)
{
SetTimer(1,3000,0); // 设置定时器间隔为3000ms
m_bSetTimer=TRUE;
}
else if(m_bSetTimer&&m_bOnLine)
{
KillTimer(1); // 3000ms内有串口事件时,则清除上次所设定时器
SetTimer(1,3000,0); // 重新设置定时器为3000ms
}
if((m_bOnLine==FALSE)&&(m_bPortOpened==TRUE))
{
CString strTemp;
strTemp.Format("%s",buf);
//两个Modem建立连接后,会向串口返回“CONNECTXXXXX”字符串,
//若起始接收字符串中有“C”则判断Modem已处于在线状态
if(strTemp.Find("C")!=-1)
{
m_bOnLine=TRUE;
m_btnDial.SetWindowText(_T("挂断(&H)"));
m_btnOpenPort.EnableWindow(FALSE);
m_btnClosePort.EnableWindow(TRUE);
m_btnSend.EnableWindow(TRUE);
}
}
if(nLength)
{
nTextLength=m_editReceive.GetWindowTextLength();
m_editReceive.SetSel(nTextLength,nTextLength); //移动插入光标到正文末尾
for(int i=0;i<nLength;i++)
{
switch(buf[i])
{
case '\r': // 回车
if(!m_bNewLine)
break;
case '\n': // 换行
str+="\r\n";
break;
case '\b': // 退格
m_editReceive.SetSel(-1, 0);
m_editReceive.ReplaceSel(str);
nTextLength=m_editReceive.GetWindowTextLength();
m_editReceive.SetSel(nTextLength-1,nTextLength);
m_editReceive.ReplaceSel(""); //回退一个字符
str="";
break;
case '\a': // 振铃
MessageBeep((UINT)-1);
break;
default :
str+=buf[i];
}
}
m_editReceive.SetSel(-1, 0);
m_editReceive.ReplaceSel(str); // 向编辑视图中插入收到的字符
}
//使m_hPostMsgEvent成为有信号,即允许发送下一个WM_COMMNOTIFY消息
SetEvent(m_hPostMsgEvent);
return 0L;
}
// 从串行口输入缓冲区中读入指定数量的字符
DWORD CModemDlg::ReadComm(char *buf, DWORD dwLength)
{
DWORD length=0;
COMSTAT ComStat;
DWORD dwErrorFlags;
ClearCommError(m_hCom,&dwErrorFlags,&ComStat);
length=min(dwLength, ComStat.cbInQue);
ReadFile(m_hCom,buf,length,&length,&m_osRead);
return length;
}
// 将指定数量的字符从串行口输出
DWORD CModemDlg::WriteComm(char *buf, DWORD dwLength)
{
BOOL fState;
DWORD length=dwLength;
COMSTAT ComStat;
DWORD dwErrorFlags;
ClearCommError(m_hCom,&dwErrorFlags,&ComStat);
fState=WriteFile(m_hCom,buf,length,&length,&m_osWrite);
if(!fState)
{
if(GetLastError()==ERROR_IO_PENDING)
{
GetOverlappedResult(m_hCom,&m_osWrite,&length,TRUE);// 等待
}
else
length=0;
}
return length;
}
// 工作者线程,负责监视串行口
UINT CommProc(LPVOID pParam)
{
OVERLAPPED os;
DWORD dwMask, dwTrans;
COMSTAT ComStat;
DWORD dwErrorFlags;
CModemDlg *pModemDlg=(CModemDlg*)pParam;
memset(&os, 0, sizeof(OVERLAPPED));
os.hEvent=CreateEvent(NULL, TRUE, FALSE, NULL);
if(os.hEvent==NULL)
{
AfxMessageBox("Can't create event object!");
return (UINT)-1;
}
while(pModemDlg->m_bPortOpened)
{
dwMask=0;
// 异步操作,等待串口事件,事件结果在dwMask中
if(!WaitCommEvent(pModemDlg->m_hCom, &dwMask, &os))
{
if(GetLastError()==ERROR_IO_PENDING)
{
GetOverlappedResult(pModemDlg->m_hCom, &os, &dwTrans, TRUE);
}
else //等待串口事件时出错
{
CloseHandle(os.hEvent);
return (UINT)-1;
}
}
//清除串口可能发生的错误
ClearCommError(pModemDlg->m_hCom,&dwErrorFlags,&ComStat);
if(ComStat.cbInQue)
{
// 无限等待WM_COMMNOTIFY消息被处理完
WaitForSingleObject(pModemDlg->m_hPostMsgEvent, INFINITE);
ResetEvent(pModemDlg->m_hPostMsgEvent);
// 向对话框发送WM_COMMNOTIFY消息
PostMessage(pModemDlg->ghWnd, WM_COMMNOTIFY, dwMask, 0);
continue;
}
}
CloseHandle(os.hEvent);
return 0;
}
//“关闭串口”按钮处理函数
void CModemDlg::OnBtnClosePort()
{
if(!m_bPortOpened)
return;
else
{
m_bPortOpened=FALSE;
m_btnOpenPort.EnableWindow(TRUE);
m_btnClosePort.EnableWindow(FALSE);
m_btnDial.EnableWindow(FALSE);
m_btnSend.EnableWindow(FALSE);
//结束CommProc线程中WaitSingleObject函数的等待
SetEvent(m_hPostMsgEvent);
//结束CommProc线程中WaitCommEvent的等待
SetCommMask(m_hCom, 0);
//等待辅助线程终止
WaitForSingleObject(m_pThread->m_hThread, INFINITE);
m_pThread=NULL;
CloseHandle(m_hCom);
}
}
//“拨号”按钮处理函数
void CModemDlg::OnBtnDial()
{
int k=0;
CString strTemp;
//若Modem处于离线状态,则拨号
if(m_bOnLine==FALSE)
{
UpdateData(TRUE);
m_btnDial.SetWindowText(_T("挂 断(&H)"));
m_strPhoneNum="ATDT"+m_strPhoneNum+"\r";
nStrLen=m_strPhoneNum.GetLength();
for(k=0;k<nStrLen;k++)
{
buf[k]=m_strPhoneNum.GetAt(k);
}
WriteComm(buf,nStrLen);
}
//若Modem处于在线状态,则挂断
else
{
m_bOnLine=FALSE;
m_bSetTimer=FALSE;
m_btnDial.SetWindowText(_T("拨 号(&D)"));
m_btnSend.EnableWindow(FALSE);
//发送换码序列“+++”,切换到在线命令状态
Sleep(1000);
for(k=0;k<3;k++)
{
buf[k]='+';
}
Sleep(1000);
WriteComm(buf,3);
Sleep(5000);
//发送挂断命令
strTemp="ATH\r";
nStrLen=strTemp.GetLength();
for(k=0;k<nStrLen;k++)
{
buf[k]=strTemp.GetAt(k);
}
WriteComm(buf,nStrLen);
}
}
//“发送”按钮处理函数
void CModemDlg::OnBtnSend()
{
UpdateData(TRUE);
int k=0;
nStrLen=m_strSend.GetLength();
if(nStrLen>128)
{
AfxMessageBox(_T("发送数据超出接收缓冲区大小!"),MB_ICONINFORMATION | MB_OK,NULL);
return;
}
for(k=0;k<nStrLen;k++)
{
buf[k]=m_strSend.GetAt(k);
}
WriteComm(buf,nStrLen);
}
// WM_TIMER消息处理函数
void CModemDlg::OnTimer(UINT nIDEvent)
{
if(m_bSetTimer)
{
KillTimer(1); // 清除定时器1
OnBtnDial(); // 挂断
}
CDialog::OnTimer(nIDEvent);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -