基于MSCOMM32.OCX和MFC框架的串口调试助手的开发

跟着下文一步一步来,就能做出来整个可以运行的应用程序

准备工作:

->删去自带的确定取消等按钮;
->点击主对话框,在属性栏中找到Caption,修改为“串口调试助手”;
->摆放文本及下拉列表:Static Text和Comb Box控件,同样找到Caption,修改其名称,在Comb Box控件的属性列表中,将Sort改为False(填入数据之后不让系统给我们自动排序),将type改为下拉列表,同时为了方便起见将其ID改为IDC_COMBO_Port;
->选中这两个控件,按住CTRL向下拖拽,复制五份,只需修改控件名称和ID即可;
->在框里放一个按钮,将Caption设置为“打开”,ID修改为IDC_BUTTON_OPEN,在打开的左边有一个指示是否打开的Picture Control控件,将其ID设为IDC_PIC_INDICATOR,为了能让其加载图片,将其Type属性修改为Bitmap,接下来将两个状态图片的image文件夹保存到项目所在文件夹中,并在资源视图中右键Com.rc–添加资源–Bitmap–导入–image文件夹–最下面栏里选择所有文件–选中图片–打开,在资源视图中选择图片,将其ID修改为IDB_BITMAP_GREEN和IDB_BITMAP_RED,接下来选择Picture Control控件的Image属性,选择IDB_BITMAP_RED(串口未打开之前为红灯)
->为了便于美观便于紧凑,放置一个Group Box,将上面几组控件框起来,并将Caption写为“串口设置”;
->接下来对接收区进行布局:首先是16进制的显示,选择Check Box控件,将其ID修改为IDC_CHECK_HEX_RECEIVE,Caption设置为“十六进制显示”,两个按钮:保存数据 IDC_BUTTON_SAVE_FILE和IDC_BUTTON_CLEAR_RECEIVE,为了美观,同样用一个Group Box控件,并将其Caption修改为接受区设置;
->接下来对发送区进行布局:先CTRL接收区向下拖动,修改对应的ID和Caption,之后再添加一个定时发送的Check Box,将其ID修改为IDC_CHECK_TIMER,再选择一个Edit Control控件及Static Text控件设置名字为ms,ID为IDC_EDIT_TIMER。
->接下来设置Comb Box控件中的值,点击控件–属性中选择Data–以第一个为例,输入:COM1;COM2;COM3;COM4;COM5;COM6;COM7;COM8;之后依次类推;
->放置发送区和接收区:选择两个Edit Control,把属性中的Multiline(多行显示,不可能只显示一行)设为TRUE,Want Return设置为TRUE,Vertical Scrollbar(滚动条)设置为TRUE,ID分别为IDC_EDIT_SEND和IDC_EDIT_REVEIVE;再选择一个按钮,ID为IDC_BUTTON_SEND,Caption设为发送,为了美观同样再添加两个Group Box即数据接收区和数据发送区。

布局完成的界面如图所示:
在这里插入图片描述

显示默认设置

通俗点说,control就是对应这个控件的,value只对应这个控件的值

->选中串口号对应的下拉列表右键->添加变量->变量名:m_cboPort,默认类型都为CComboBox
->选中波特率对应的下拉列表右键->添加变量->变量名:m_cboBaudRate ,类型为CComboBox,类别为Control的变量,除此之外还要添加一个CString类型,Value类别的变量,变量名:m_strBaudRate(直接操纵这个变量可以获取控件的值)
->选中校验位对应的下拉列表右键->添加变量->变量名:m_cboCheckBit,类型为CComboBox,类别为Control的变量,除此之外还要添加一个CString类型,Value类别的变量,变量名:m_strCheckBit
->选中数据位对应的下拉列表右键->添加变量->变量名:m_cboDateBit,类型为CComboBox,类别为Control的变量,除此之外还要添加一个CString类型,Value类别的变量,变量名:m_strDataBit
->选中停止位对应的下拉列表右键->添加变量->变量名:m_cboStopBit,类型为CComboBox,类别为Control的变量,除此之外还要添加一个CString类型,Value类别的变量,变量名:m_strStopBit

->之后打开Dlg.cpp文件找到初始化函数OnInitDialog(),添加如下代码,在对话框一加载出来的时候就显示默认的值:

 // TODO: 在此添加额外的初始化代码
 m_cboPort.SetCurSel(0);//cursel默认选择 set 设置  参数:索引第几个 COM1
 m_cboBaudRate.SetCurSel(2);//9600
 m_cboCheckBit.SetCurSel(0);//NONE
 m_cboDateBit.SetCurSel(3);//8
 m_cboStopBit.SetCurSel(0);//1

->给两个收发的Edit Control添加变量,变量名为m_editSend,类别为Control,变量名为m_strSend,类别为value,和已有选项的下拉列表控件不一样,在Dlg.cpp文件中的CComDlg::CComDlg写入一条语句,操作m_strSend这个变量就代表操作这个控件当中的数据:
在这里插入图片描述

->将剩余控件全部添加变量:
右键红灯–添加变量–变量名m_picIndicator,类型Control;
打开 按钮–添加变量–变量名m_btnOpen,类型Control;
十六进制显示–添加变量–变量名m_chkHexReceive,类型Control;
十六进制发送–添加变量–变量名m_chkHexSend,类型Control;
定时发送–添加变量–变量名m_chkTimer,类型Control;
毫秒旁边的文本框–添加变量–变量名m_editTimer,类型Control,变量名m_uiSec,类型Value,变量类型UINT;
接受框–添加变量–变量名m_editReceive,类型Control,变量名m_strReceive,类型Value,变量类型CString;

接下来添加串口类型的控件

在这之前你需要在度娘上下载一个64位的MSCOMM32.OCX文件,把下载的MSCOMM32.OCX拷贝到C:\Windows\SysWOW64目录,以管理员权限打开DOS命令行窗口:
regsvr32 C:\Windows\SysWOW64\MSCOMM32.OCX

注意:一定要以管理员身份运行cmd,否则成功不了

在这里插入图片描述

在主对话框空白地方右击,插入ActiveX控件,选择Microsoft Communications Control,version 6.0(SP6).将其ID修改为IDC_MSCOMM,为控件添加变量,类型 CMscomm,变量名 m_mscomm,类别Control,当变量名添加完之后,就会多一个头文件和.cpp文件。

为“打开”按钮添加消息响应函数

选择上方项目–属性–配置属性(常规)–字符集改为多字节这样就不会在程序中遇到中文之后,插件提示你报错了
首先,在Dlg.cpp文件中插入一个对话框类的函数并在.h文件中声明:

//因为校验位是字符串数据,而我们需要读一位字符,做一个数据转换函数
CString CComDlg::getCheckBit()
{
    
    
 CString strCheckBit;
 switch(m_cboCheckBit.GetCurSel)//获得控件当前的选择索引
 {
    
    
 case 0:strCheckBit = "n"; break;
 case 1:strCheckBit = "o"; break;
 case 2:strCheckBit = "e"; break;
 }
 return strCheckBit;
}

在打开按钮的响应函数中写如下代码:

扫描二维码关注公众号,回复: 12499755 查看本文章
void CComDlg::OnBnClickedButtonOpen()
{
    
    
 // TODO: 在此添加控件通知处理程序代码
 UpdateData(TRUE);//将控件中的数据更新到变量中 这样的话操作变量就相当于操作控件
 CString strOpen;
 GetDlgItemText(IDC_BUTTON_OPEN,strOpen);//把打开按钮的值获取到字符串当中
 if (strOpen == "打开")
 {
    
    
  //执行打开串口操作
  m_mscomm.put_InBufferSize(1024);//设置接收缓冲区大小
  m_mscomm.put_OutBufferSize(1024);//设置发送缓冲区大小
  m_mscomm.put_InputLen(0);//全部读取接收缓冲区的数据
  m_mscomm.put_InputMode(CMscomm::comInputModeBinary);//二进制方式读写数据
  m_mscomm.put_RThreshold(1);//接收缓冲区中有1个或1个以上字符时读取
  //获取我们界面中的设置
  CString strCheckBit = getCheckBit();
  CString strSettings = m_strBaudRate + strCheckBit + m_strDataBit + m_strStopBit;
  //"9600 无校验位 8位 1位停止位"
  m_mscomm.put_Settings(strSettings);//串口通信时串口参数的设置
  m_mscomm.put_CommPort(m_cboPort.GetCurSel()+1);//获取串口号 索引时是从0开始的 所以要加上1
  //真正的打开串口
  try
  {
    
    
   m_mscomm.put_PortOpen(TRUE);
  }
  catch (CException* e)
  {
    
    
   MessageBox("端口不存在","打开串口",MB_ICONERROR);//内容 标题 弹出对话框样式
   return;//不让程序继续向下走
  }
  SetDlgItemText(IDC_BUTTON_OPEN,"关闭");//串口打开之后设置按钮显示为“关闭”
  CBitmap bitmap;//加载位图
  bitmap.LoadBitmap(IDB_BITMAP_GREEN);//打开绿色的图标
  HBITMAP  hBmp;
  hBmp = (HBITMAP)bitmap.GetSafeHandle();//获取句柄
  m_picIndicator.SetBitmap(hBmp);//将红灯改为绿灯
 }
 else
 {
    
    //执行关闭串口操作
  m_mscomm.put_PortOpen(FALSE);//关闭串口
  SetDlgItemText(IDC_BUTTON_OPEN,"打开");//将按钮改为打开
  CBitmap bitmap;//加载位图
  bitmap.LoadBitmap(IDB_BITMAP_RED);
  HBITMAP  hBmp;
  hBmp = (HBITMAP)bitmap.GetSafeHandle();//获取句柄
  m_picIndicator.SetBitmap(hBmp);//将绿灯改为红灯
 } 
}

碰到这种情况怎么办:
在这里插入图片描述
解决办法:在对话框中点击一下该控件右边的向下的小箭头,会弹出几个顶点,用鼠标点住下面最中间的那个向下拖动即可,尽量把对话框中的都拖一下。

注:在C++中,当函数抛出一个返回值时,即使不用try和catch语句,异常还是会被处理的,系统会自动调用默认处理函数unexpected来执行

处理发送和接受

先处理接受:添加事件处理函数
选中MSComm控件–右侧属性选择控件事件(闪电符号)–再OnComm中选择addOnCommMSComm,事件响应函数如下:

void CComDlg::OnCommMscomm()//事件相应函数,任何一个事件都会调用(当接受到数据,自动执行)
{
    
    
 // TODO: 在此处添加消息处理程序代码
 UpdateData(TRUE);
 byte rxdata[1024];//char 和BYTE 一个是无符号的,一个是有符号的,占用空间一样大
 switch (m_mscomm.get_CommEvent())//获取串口控件上的事件
 {
    
    
 case CMscomm::comEvReceive://如果是我们接收到了数据就执行下面的操作
  //1.从串口缓冲区读取数据
  m_mscomm.put_InputMode(CMscomm::comInputModeBinary);//以二进制格式读取
  VARIANT  variant_inp = m_mscomm.get_Input();//将数据读出来
  COleSafeArray safearray_inp = variant_inp;//进行变量类型的转换 这两句是固定写法,这么用就行
  //2.获取数据的有效长度
  long len = safearray_inp.GetOneDimSize();
  for (long i = 0;i < len;i++)
  {
    
    //3.将读取数据的每一个字符放入到rxdata数组中
   safearray_inp.GetElement(&i,rxdata + i);
   //将数据显示到接收区的文本框里面
   CString strtemp = "";
   if (m_chkHexReceive.GetCheck() == 1)//如果十六进制选中
   {
    
    //以十六进制显示
    strtemp.Format("%02X",rxdata[i]);
       m_strReceive = m_strReceive + strtemp + " ";//加个空格
   } 
   else
   {
    
    
       strtemp.Format("%c",rxdata[i]);//以字符格式接收
       m_strReceive = m_strReceive + strtemp;
   }
  }
   break;
 }
 UpdateData(FALSE);//将变量中的数据更新到控件显示
 m_editReceive.LineScroll(m_editReceive.GetLineCount());//实现显示窗自动滚动到最后一行
}

发送按钮响应函数如下:

void CComDlg::OnBnClickedButtonSend()
{
    
    
 // TODO: 在此添加控件通知处理程序代码
 UpdateData(TRUE);//将控件中的数据更新到变量中
 CString  strSend;
 GetDlgItemText(IDC_BUTTON_SEND,strSend);
 if (strSend == "发送")
 {
    
    //执行串口发送操作
  try
  {
    
    
   if(m_chkHexSend.GetCheck() == 1)//看十六进制有没有被选中
   {
    
    
    //以十六进制发送
    CByteArray hexToSend;//定义一个byte数组
    hexToSend.RemoveAll();//清空一下
    //十六进制格式41 42 43 44
    for (int i = 0; i < m_strSend.GetLength(); i+=3)// 41空格为一组
    {
    
    
     CString strtemp = m_strSend.Mid(i,2);//只有前两个才代表十六进制
     char *p=strtemp.GetBuffer(2);//CString转char * 
     hexToSend.Add(strtol(p,NULL,16));//add的是如 41转换为十六进制的一个数
    }
    m_mscomm.put_Output((COleVariant)hexToSend);
   }
   else
   {
    
    
    //以字符格式发送
    m_mscomm.put_Output((COleVariant)m_strSend);//字符格式发送
   }    
  }
  catch (CException* e)
  {
    
    
   MessageBox("端口未打开","发送",MB_ICONERROR);
   return;
  }
 }

如此就可以执行发送功能,我们找到一个USB转RS232的接口,将输入输出两个引脚用杜邦线短接,之后再设备管理器查找到系统自动分配的端口,在我们的软件里打开,执行发送任务
在这里插入图片描述

选择十六进制发送 自动转换对话框的数据

双击十六进制发送控件:

void CComDlg::OnBnClickedCheckHexSend()
{
    
    
 // TODO: 在此添加控件通知处理程序代码
 UpdateData(TRUE);//把控件数据更新到变量
 if (m_chkHexSend.GetCheck() == 1)//判断有没有被选中
 {
    
    
  //将字符格式转换为十六进制
  //为什么使用GetBuffer: vc开发中,在进行字符串参数传递的时候,经常需要使用非常量指针 
  //而我们通常得到的mfc字符串是CString,之后后需要先进行转换才能进行传递。
  char *p = m_strSend.GetBuffer(m_strSend.GetLength());//指向字符串当前内容的指针 移交控制权 参数:修改指针指向的缓冲区长度
  m_strSend.ReleaseBuffer();//CString字符串收回控制权
   //ReleaseBuffer函数是用来告诉CString对象,你的GetBuffer所引用的内存已经使用完毕,现在必须对它进行封口,
  //否则 CString将不会知道它现在所包含的字符串的长度
  int length = m_strSend.GetLength();
  CString str = "";
  for (int i = 0; i < length ; i++)
  {
    
    
   CString strtemp;
   strtemp.Format("%02X",p[i]);//转换为十六进制 不足两位,,前面补0输出,如果超过两位,则以实际输出
   str = str + strtemp + " ";
  }
  m_strSend = str.TrimRight(" ");//把最右侧的空格去掉
 } 
 else
 {
    
    //将十六进制转换为字符格式
  int length = m_strSend.GetLength();
  CString str;
  for (int i = 0;i < length; i+=3)
  {
    
    
    CString strtemp = m_strSend.Mid(i,2);//空格不取 从第i个索引位置开始,取两个字符
    char *p = strtemp.GetBuffer(2);
    int num = strtol(p,NULL,16);//把十六进制转换成长整数的形式  参数二:为第一个不能转换的字符的指针
    strtemp.Format("%c",num);
    str += strtemp;
  }
  m_strSend = str;
 }
 UpdateData(FALSE);//把变量数据更新到控件
}

双击十六进制显示控件:

void CComDlg::OnBnClickedCheckHexReceive()
{
    
    
 // TODO: 在此添加控件通知处理程序代码
 UpdateData(TRUE);//把控件数据更新到变量
 if (m_chkHexReceive.GetCheck() == 1)//判断有没有被选中
 {
    
    
  //将字符格式转换为十六进制
  //为什么使用GetBuffer: vc开发中,在进行字符串参数传递的时候,经常需要使用非常量指针 
  //而我们通常得到的mfc字符串是CString,之后后需要先进行转换才能进行传递。
  char *p = m_strReceive.GetBuffer(m_strReceive.GetLength());//指向字符串当前内容的指针 移交控制权 参数:修改指针指向的缓冲区长度
  m_strReceive.ReleaseBuffer();//CString字符串收回控制权
  //ReleaseBuffer函数是用来告诉CString对象,你的GetBuffer所引用的内存已经使用完毕,现在必须对它进行封口,
  //否则 CString将不会知道它现在所包含的字符串的长度
  int length = m_strReceive.GetLength();
  CString str = "";
  for (int i = 0; i < length ; i++)
  {
    
    
   CString strtemp;
   strtemp.Format("%02X",p[i]);//转换为十六进制 不足两位,,前面补0输出,如果超过两位,则以实际输出
   str = str + strtemp + " ";
  }
  m_strReceive = str.TrimRight(" ");//把最右侧的空格去掉
 } 
 else
 {
    
    //将十六进制转换为字符格式
  int length = m_strReceive.GetLength();
  CString str;
  for (int i = 0;i < length; i+=3)
  {
    
    
   CString strtemp = m_strReceive.Mid(i,2);//空格不取 从第i个索引位置开始,取两个字符
   char *p = strtemp.GetBuffer(2);
   int num = strtol(p,NULL,16);//把十六进制转换成长整数的形式  参数二:为第一个不能转换的字符的指针
   strtemp.Format("%c",num);
   str += strtemp;
  }
  m_strReceive = str;
 }
 UpdateData(FALSE);//把变量数据更新到控件
}

实现定时发送功能

添加定时器:

类视图–单击CComDlg–属性中选择消息–WM_TIMER–ADD
定时的时间一到,就会执行该函数

void CComDlg::OnTimer(UINT_PTR nIDEvent)
{
    
    
 // TODO: 在此添加消息处理程序代码和/或调用默认值
 switch(nIDEvent)
 {
    
    
 case 1:                  //如果是定时器1
  if (m_chkHexSend.GetCheck() == 1)//判断是十六进制定时发送还是字符格式定时发送
  {
    
    //十六进制定时发送
   m_mscomm.put_Output((COleVariant)hexToSend);
  } 
  else
  {
    
    //字符格式定时发送
   m_mscomm.put_Output((COleVariant)strToSend);
  }
  break;
 default:
  break;
 }
 CDialogEx::OnTimer(nIDEvent);
}

同时为了方便起见,我们在ComDlg.h文件里定义两个成员变量:
CByteArray hexToSend;
CString strToSend;
同时我们的发送按钮的响应函数进行修改:

void CComDlg::OnBnClickedButtonSend()
{
    
    
 // TODO: 在此添加控件通知处理程序代码
 UpdateData(TRUE);//将控件中的数据更新到变量中
 CString  strSend;
 GetDlgItemText(IDC_BUTTON_SEND,strSend);
 if (strSend == "发送")
 {
    
    //执行串口发送操作
  try
  {
    
    
   if(m_chkHexSend.GetCheck() == 1)//看十六进制有没有被选中
   {
    
    
    //以十六进制发送
   // CByteArray hexToSend;//定义一个byte数组
    hexToSend.RemoveAll();//清空一下
    //十六进制格式41 42 43 44
    for (int i = 0; i < m_strSend.GetLength(); i+=3)// 41空格为一组
    {
    
    
     CString strtemp = m_strSend.Mid(i,2);//只有前两个才代表十六进制
     char *p=strtemp.GetBuffer(2);//CString转char * 
     hexToSend.Add(strtol(p,NULL,16));//add的是如 41转换为十六进制的一个数
    }
    m_mscomm.put_Output((COleVariant)hexToSend);
   }
   else
   {
    
    
    //以字符格式发送
    strToSend = m_strSend;
    m_mscomm.put_Output((COleVariant)strToSend);//字符格式发送
   }    
   if (m_chkTimer.GetCheck() == 1)//判断定时发送按钮是否被选中
   {
    
    //开始定时发送
    SetTimer(1,m_uiSec,NULL);//启动ID为1的定时器 时间间隔为m_uiSec
    SetDlgItemText(IDC_BUTTON_SEND,"停止发送");//将发送按钮改为停止发送
    m_editSend.SetReadOnly(TRUE);//不允许点击了
    m_btnLoadFile.EnableWindow(FALSE);//不允许点击了
    m_btnClearSend.EnableWindow(FALSE);
    m_btnSaveFile.EnableWindow(FALSE);
    m_chkTimer.EnableWindow(FALSE);
    m_editTimer.EnableWindow(FALSE);
    m_cboPort.EnableWindow(FALSE);
    m_cboBaudRate.EnableWindow(FALSE);
    m_cboCheckBit.EnableWindow(FALSE);
    m_cboDateBit.EnableWindow(FALSE);
    m_cboStopBit.EnableWindow(FALSE);
   } 
  }
  catch (CException* e)
  {
    
    
   MessageBox("端口未打开","发送",MB_ICONERROR);
   return;
  }
 }
 else//不是发送
 {
    
    //停止定时发送
  KillTimer(1);//关闭定时器
  SetDlgItemText(IDC_BUTTON_SEND,"发送");//将发送按钮改为停止发送
  m_editSend.SetReadOnly(FALSE);//不允许点击了
  m_btnLoadFile.EnableWindow(TRUE);//不允许点击了
  m_btnClearSend.EnableWindow(TRUE);
  m_btnSaveFile.EnableWindow(TRUE);
  m_chkTimer.EnableWindow(TRUE);
  m_editTimer.EnableWindow(TRUE);
  m_cboPort.EnableWindow(TRUE);
  m_cboBaudRate.EnableWindow(TRUE);
  m_cboCheckBit.EnableWindow(TRUE);
  m_cboDateBit.EnableWindow(TRUE);
  m_cboStopBit.EnableWindow(TRUE);
 }
}

实时的显示发送和接受的字节数

在.h文件中定义变量 CStatusBarCtrl m_status;
unsigned long m_ulSendNum; 发送的数目
unsigned long m_ulReceiveNum; 接受的数目

在.cpp文件中的OnInitDialog函数里添加:

 m_status.Create(WS_CHILD | WS_VISIBLE | SBT_OWNERDRAW, CRect(0,0,0,0), this,0);//创建StatusBar
 int partDim[3] = {
    
    300,450,-1};//第一部分大小/第二部分右侧距离最左侧的大小/剩余控件分配给第三部分
 m_status.SetParts(3,partDim);//分的是三个部分
 m_status.SetText("",0,0);
 m_status.SetText("发送:0",1,0);
 m_status.SetText("接受:",2,0);

在发送按钮的响应函数中 catch上面添加代码端(截取一部分之前的方便定位):

    m_cboDateBit.EnableWindow(FALSE);
    m_cboStopBit.EnableWindow(FALSE);
   } 
   CString strSendNum;//发送的数目
   if (m_chkHexSend.GetCheck() == 1)
   {
    
    //16进制发送
    m_ulSendNum += hexToSend.GetCount();
   } 
   else
   {
    
    //字符发送
     m_ulSendNum += strToSend.GetLength();
   }
   strSendNum.Format("%d",m_ulSendNum);
   strSendNum = "发送:"+strSendNum;
   m_status.SetText(strSendNum,1,0);//显示到状态栏
  }

再将其拷贝到定时发送中:

void CComDlg::OnTimer(UINT_PTR nIDEvent)
{
    
    
 // TODO: 在此添加消息处理程序代码和/或调用默认值
 switch(nIDEvent)
 {
    
    
 case 1:                  //如果是定时器1
{
    
      if (m_chkHexSend.GetCheck() == 1)//判断是十六进制定时发送还是字符格式定时发送
  {
    
    //十六进制定时发送
   m_mscomm.put_Output((COleVariant)hexToSend);
  } 
  else
  {
    
    //字符格式定时发送
   m_mscomm.put_Output((COleVariant)strToSend);
  }
  CString strSendNum;//发送的数目
  if (m_chkHexSend.GetCheck() == 1)
  {
    
    //16进制发送
   m_ulSendNum += hexToSend.GetCount();
  } 
  else
  {
    
    //字符发送
   m_ulSendNum += strToSend.GetLength();
  }
  strSendNum.Format("%d",m_ulSendNum);
  strSendNum = "发送:"+strSendNum;
  m_status.SetText(strSendNum,1,0);//显示到状态栏
  break;
  }
 default:
  break;
 }
 CDialogEx::OnTimer(nIDEvent);
}

对接收的代码段添加:

 COleSafeArray safearray_inp = variant_inp;//进行变量类型的转换 这两句是固定写法,这么用就行
  //2.获取数据的有效长度
  long len = safearray_inp.GetOneDimSize();
  CString strReveiveNum;
  m_ulSendNum += len;
  strReveiveNum.Format("%d",m_ulReceiveNum);
  strReveiveNum = "接收:" + strReveiveNum;
  m_status.SetText(strReveiveNum,2,0);
  for (long i = 0;i < len;i++)
  {
    
    //3.将读取数据的每一个字符放入到rxdata数组中
   safearray_inp.GetElement(&i,rxdata + i);

运行结果如图:

在这里插入图片描述

文件载入功能的实现

双击文件载入按钮:

void CComDlg::OnBnClickedButtonLoadFile()
{
    
    
 // TODO: 在此添加控件通知处理程序代码
 m_strSend = "";//清空数据发送区
 TCHAR szFilter[] = _T("文本文件(*.txt) | *.txt | 所有文件(*.*) | *.*||");
 CFileDialog  fileDlg(FALSE, _T("txt"),NULL,0,szFilter,this);//创建一个打开文件的对话框 很好用
 //参数一:右上角为打开 参数二 默认打开txt扩展名文件 参数三 默认的文件名 参数四 风格默认0 参数五 参数五 打开所有文件 参数六 指向父窗口
 if (fileDlg.DoModal() == IDOK)//判断选择的是打开还是取消 domodal就是关闭的时候是选择的打开还是取消
 {
    
    //获取文件路径
  CString strFilePath = fileDlg.GetPathName();
  CFile file;
  char readBuffer[2048];
  if (file.Open(strFilePath,CFile ::modeRead))//以只读方式打开文件
  {
    
    
   int nRet = file.Read(readBuffer,2048);//接收数据的缓存区指针/从文件中读取的字节数
   for (int i = 0;i < nRet ; i++)
   {
    
    
    CString str;
    str.Format("%c",readBuffer[i]);
    m_strSend += str;
   }
  } 
  UpdateData(FALSE);//从变量更新到控件
 } 
}

实现保存文件的功能

双击保存数据:

void CComDlg::OnBnClickedButtonSaveFile()
{
    
    
 // TODO: 在此添加控件通知处理程序代码
 UpdateData(TRUE);
 TCHAR szFilter[] = _T("文本文件(*.txt) | *.txt | 所有文件(*.*) | *.*||");//设置一个文件过滤器
 CFileDialog  fileDlg(FALSE, _T("txt"),_T("InitFileName"),OFN_HIDEREADONLY  | OFN_OVERWRITEPROMPT,szFilter,this);//创建一个打开文件的对话框 很好用
 //参数一:右上角为打开 参数二 默认打开txt扩展名文件 参数三 默认的文件名 参数四 风格默认0 参数五 参数五 打开所有文件 参数六 指向父窗口
 if (fileDlg.DoModal() == IDOK)//判断选择的是打开还是取消 domodal就是关闭的时候是选择的打开还是取消
 {
    
    //获取文件路径
  CString strFilePath = fileDlg.GetPathName();
  CFile file;
  if (file.Open(strFilePath,CFile ::modeReadWrite| CFile :: modeCreate))//以读写方式打开文件 | 创建新文件
  {
    
    
   char *p = m_strReceive.GetBuffer(m_strReceive.GetLength());
   file.Write(p,m_strReceive.GetLength());//写入数据的指针/写入数据的长度
   file.Close();
  } 
 } 
}

猜你喜欢

转载自blog.csdn.net/qq_42308217/article/details/108793919