1、第 1 页 共 37 页VC(MFC)编写串口调试助手1. 序确定基本功能:1.自动寻找串口,并自动添加到下拉框中共选择;2.有波特率、数据位、停止位、校验位的选择设置;3.串口打开控制按钮;4.发送、清除按钮;5.接收是自动实现的;6.有定时自动发送功能;7.有传送文件功能;8.有状态栏显示,指示串口状态,设置参数和发送接收显示。下面就一步步实现,本人纯业余,只是记录下来这个学习过程,请勿拍砖。开发平台 Visual C+6.0 英文版,电脑是 i7-2670Q 四核 8G 内存 1G 独显的笔记本,装的 win7 64 位旗舰版,因此 VC6 兼容不是太好,有些小毛病,不过不影响编写。2.
2、 创建 MFC 项目File - New - Projects 选择 MFC AppWizard(exe),项目名称 commassist第 2 页 共 37 页选择 OK选中 Dialog based,点击 Next 。第 3 页 共 37 页默认选项,点击 Next ,继续默认选项,点击 Next ,如果选中 As a statically linked library,生产的 EXE 可直接在第 4 页 共 37 页没装 VC 的机器上运行。可以在项目中进行更改。选择第二个 CCommassistDlg,点击 Finish第 5 页 共 37 页点击 OK。项目创建完毕,进入项目。删除界
3、面上确定和取消按钮以及静态文字。第 6 页 共 37 页3. 创建界面保存后便可以开始创建界面了。参考界面仿照设计的界面,具体添加按钮或编辑框等的布局步骤就不用细说了。4. 图标修改在资源视图中选择 Icon 右键 InsertIcon 加入打开和关闭的 Icon 图标或自行绘制,如下图第 7 页 共 37 页IDR_MAINFRAME 原为 MFC 提供的图标,这里我直接改成自己的,生成 EXE 后将会显示这个图标。下面将帮助页面图标也改为自绘图标。在打开按钮旁边加入自绘的打开和关闭图标:先加入工具条中的 Picture,然后选中右键看属性,并如图将 Image 选为默认的 IDI_ICON
4、_CLOSE。如下图第 8 页 共 37 页5. 基本设置下面对各个按钮及编辑框设置进行描述右键串口对应的 Combo Box,ID 设置为 IDC_COMLIST,Type 设置为 Drop List,Sort 不选择(我系统是 WIN7 64 位,不选中反而自动排序,至于 XP 得试试看了,以下的选择相同)。右键波特率对应的 Combo Box,ID 设置为 IDC_BAUD,Type 及 Sort 同上。右键数据位对应的 Combo Box,ID 设置为 IDC_BDATA,Type 及 Sort 同上。右键停止位对应的 Combo Box,ID 设置为 IDC_BSTOP,Type 及
5、 Sort 同上。右键校验位对应的 Combo Box,ID 设置为 IDC_CAL,Type 及 Sort 同上。每个下拉框要点击右边的小箭头,然后将其拉长,不然显示不出内容。接收 EDIT 框 ID 设置为 IDC_EDIT_RX。发送 EDIT 框 ID 设置为 IDC_EDIT_TX。自动发送时间间隔的 EDIT 框 ID 设置为 IDC_EDIT_TIMER。选择文件后面的 EDIT 框 ID 设置为 IDC_EDIT_FILEPATH。接收区的十六进制显示的 Check Box 复选框 ID 设置为 IDC_CHECK_HEXRX。发送区的十六进制发送的 Check Box 复选框
6、 ID 设置为 IDC_CHECK_HEXTX。按钮“打开串口”ID 设置为 IDC_COMCONTROL。按钮“清空显示区”ID 设置为 IDC_BTN_CLRRX。按钮“手动发送”ID 设置为 IDC_BTN_HANDSEND。按钮“清空发送区”ID 设置为 IDC_BTN_CLRTX。按钮“自动发送”ID 设置为 IDC_BTN_AUTOSEND。按钮“选择文件”ID 设置为 IDC_BTN_SELCTFILE。按钮“发送文件”ID 设置为 IDC_BTN_SENDFILE。6. 开始写代码6.1. 基本思路:因为串口通信部分代码我可能用在以后的单片机上位机上,因此考虑单独形成 CPP
7、和 H 文件,定义为 comm.cpp 和 comm.h。在 comm.cpp 中编写串口创建、打开、关闭以及串口监听线程(用于自动接收)的代码,同时加入进制转换或显示的函数,这些在 comm.h 文件中申明,在主对话框中包含 comm.h 即可。想修改按钮样式,在网上搜了一圈,结果不轻松,最后确定创建新类来实现。第 9 页 共 37 页6.2. 创建自定义按钮类:View - Class Wizard 选择 Add Class - New,名字 MyButton,基类选择 CButton。在头文件 MyButton.h 中加入以下变量和函数定义:private:int m_Style; /按
8、钮形状(0-正常,1- 当前,2-按下, 3-锁定) bool b_InRect;/鼠标进入标志CString m_strText; /按钮文字COLORREF m_ForeColor;/文本颜色COLORREF m_MouseInColor;/鼠标进入时文本颜色COLORREF m_BackColor;/背景颜色COLORREF m_LockForeColor; /锁定按钮的文字颜色CRect m_ButRect; /按钮尺寸CFont* p_Font; /字体void DrawButton(CDC *pDC); /画正常按钮/ 接口函数public:MyButton();void SetT
9、ext(CString str); /设置文字void SetForeColor(COLORREF color);/设置文本颜色void SetBkColor(COLORREF color); /设置背景颜色void SetTextFont(int FontHight,LPCTSTR FontName); /设置字体在 MyButton.cpp 的构造函数中初始化变量:m_Style = 1; /m_Style = 0; /按钮形状风格b_InRect = false; /鼠标进入标志m_strText = _T(“); /按钮文字(使用默认文字)m_ForeColor = RGB(0,0,0
10、); /文字颜色(黑色)m_MouseInColor = RGB(0,0,255); /鼠标进入时文字颜色 (蓝色)m_BackColor = RGB(230,230,230); /m_BackColor = RGB(243,243,243); /背景色(灰白色)m_LockForeColor = GetSysColor(COLOR_GRAYTEXT);/锁定按钮的文字颜色p_Font = NULL; /字体指针用 ClassWizard 添加下列消息函数:PreSubclassWindow();DrawItem();onMouseMove();OnLButtonDown();OnLButto
11、nUp();在各函数内加入代码:第 10 页 共 37 页void MyButton:PreSubclassWindow() / TODO: Add your specialized code here and/or call the base classModifyStyle( 0, BS_OWNERDRAW ); /设置按钮属性为自画式/PreSubclassWindow()在按钮创建前自动执行,所以我们可以在其中做一些初始工作。/这里只做了一项工作,就是为按钮设置属性为“自绘 ”式,这样,用户在添加按钮后,就不需设置“Owner draw”属性了。CButton:PreSubclassW
12、indow();void MyButton:DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) / TODO: Add your code to draw the specified itemCDC *pDC = CDC:FromHandle( lpDrawItemStruct-hDC );m_ButRect = lpDrawItemStruct-rcItem; /获取按钮尺寸if( m_strText.IsEmpty() )GetWindowText( m_strText ); /获取按钮文本int nSavedDC = pDC-SaveDC();VERI
13、FY( pDC );DrawButton( pDC ); /绘制按钮pDC-RestoreDC( nSavedDC );/DrawItem()函数是一个关键函数,按钮的绘制工作就在这里进行,它的作用相当于对话框中的 OnPaint()函数和视图中的 OnDraw()函数。/这里我做了三项工作:获取按钮尺寸、获取按钮文本、绘制按钮。其中绘制工作在自定义函数 DrawButton()中完成。以下就是绘制过程:void MyButton:DrawButton(CDC *pDC)/调整状态if( m_Style=3 ) m_Style = 0;if( GetStyle() /禁止状态/根据状态调整边框
14、颜色和文字颜色COLORREF bColor, fColor; /bColor 为边框颜色, fColor 为文字颜色switch( m_Style )case 0: bColor = RGB(192,192,192); fColor = m_ForeColor; break; /正常按钮case 1: bColor = RGB(255,255,255); fColor = m_ForeColor; break; /鼠标进入时按钮case 2: bColor = RGB(192,192,192); fColor = m_MouseInColor; break; /按下的按钮case 3: bC
15、olor = m_BackColor; fColor = m_LockForeColor; break; /锁定的按钮第 11 页 共 37 页/绘制按钮背景CBrush Brush;Brush.CreateSolidBrush( m_BackColor ); /背景刷pDC-SelectObject( CPen Pen;Pen.CreatePen(PS_SOLID, 3, bColor );pDC-SelectObject( pDC-RoundRect( /画圆角矩形/绘制按钮按下时的边框if( m_Style!=2 )CRect Rect;Rect.SetRect( m_ButRect.l
16、eft+1, m_ButRect.top+1, m_ButRect.right, m_ButRect.bottom );pDC-DrawEdge( /画边框/绘制按钮文字pDC-SetTextColor( fColor ); /画文字pDC-SetBkMode( TRANSPARENT );pDC-DrawText( m_strText, /绘制拥有焦点按钮的虚线框if( GetFocus()=this )CRect Rect;Rect.SetRect( m_ButRect.left+3, m_ButRect.top+2, m_ButRect.right-3, m_ButRect.bottom
17、-2 );pDC-DrawFocusRect( /画拥有焦点的虚线框 /变量 m_Style 表征当前按钮状态,它的取值为:0- 正常, 1-当前,2-按下,3- 锁定。不同状态下按钮的边框颜色和文字颜色有所不同。/m_Style 的值在鼠标响应函数中进行修改。/绘制工作主要利用 CDC 类的绘图函数完成,主要注意在 m_Style 不同取值下表现出来的差别。void MyButton:OnLButtonDown(UINT nFlags, CPoint point) / TODO: Add your message handler code here and/or call defaultm_
18、Style = 2;Invalidate(); /重绘按钮CButton:OnLButtonDown(nFlags, point);第 12 页 共 37 页/OnLButtonDown()函数是单击鼠标左键时的消息函数。这里只是重新绘制按钮,具体的单击响应应该在拥有按钮的对话框或视图中进行。void MyButton:OnMouseMove(UINT nFlags, CPoint point) / TODO: Add your message handler code here and/or call defaultif( !b_InRect | GetCapture()!=this ) /
19、鼠标进入按钮b_InRect = true; /设置进入标志SetCapture(); /捕获鼠标m_Style = 2; /m_Style = 1; /设置按钮状态Invalidate(); /重绘按钮elseif ( !m_ButRect.PtInRect(point) ) /鼠标离开按钮b_InRect = false; /清除进入标志ReleaseCapture(); /释放捕获的鼠标m_Style = 1; /m_Style = 0; /设置按钮状态Invalidate(); /重绘按钮CButton:OnMouseMove(nFlags, point);/onMouseMove()
20、函数是鼠标移动消息函数,用于判定当前鼠标指针是否在按钮上。b_InRect 是个标志,为 true 表示鼠标指针进入了按钮区域,/此时要捕获鼠标,让鼠标命令传送给按钮。当鼠标指针离开按钮时,要清除 b_InRect 标志,并且释放捕获的鼠标,让其它窗口可以接收鼠标命令。/Invalidate()函数用于更新按钮,它会自动调用 DrawItem()函数重新绘制按钮。/设置条件的目的是仅在鼠标指针进入按钮和离开按钮时更新按钮,这样可以防止鼠标在按钮上移动时发生闪烁。void MyButton:OnLButtonUp(UINT nFlags, CPoint point) / TODO: Add yo
21、ur message handler code here and/or call defaultm_Style = 1;Invalidate(); /重绘按钮CButton:OnLButtonUp(nFlags, point);/OnLButtonUp()函数是单击鼠标左键后弹起时的消息函数。这里也只是重绘按钮,这样能使按钮在按下和弹起时有所不同,使按钮看上去有动态效果。第 13 页 共 37 页/接口函数是用 CMyButton 类 定义的按钮修改颜色、字体和按钮文字的接口,由以下函数组成:/设置按钮文本void MyButton:SetText(CString str)m_strText
22、= _T(“);SetWindowText(str); /设置文本颜色void MyButton:SetForeColor(COLORREF color)m_ForeColor = color;Invalidate(); /设置背景颜色void MyButton:SetBkColor(COLORREF color)m_BackColor = color;Invalidate(); /设置字体(字体高度、字体名)void MyButton:SetTextFont(int FontHight,LPCTSTR FontName)if ( p_Font ) delete p_Font; /删除旧字体p
23、_Font = new CFont;p_Font-CreatePointFont( FontHight, FontName ); /创建新字体SetFont( p_Font ); /设置字体 /由于新字体由 new 生成,必须显式回收,这项工作可以在 CMyButton 类 的析构函数中进行:/*CMyButton:CMyButton()if ( p_Font ) delete p_Font; /删除字体 */这样一个可设置颜色、字体的按钮类就做好了。使用时,先在对话框中放置好按钮,再第 14 页 共 37 页用 ClassWizard 为按钮添加控制变量,/并且将变量的类型设置为 CMyBu
24、tton。之后,可以用该变量调用接口函数设置按钮颜色和字体。OK,自定义按钮完成。6.3. 实现过程及代码:现在可以对按钮,EDIT 框等控件添加变量,文字描述麻烦,上图。comm.cpp 编写内容如下#include “stdafx.h“#include “commassist.h“#include “commassistDlg.h“#include “comm.h“char ConvertHexChar(char ch);HANDLE hCom; /串口句柄CString strcomname; /串口名,如“COM1“bool ComIsOK; /串口打开状态标识,为真表示已打开 ,否则
25、未打开/=自动寻找串口函数=/函数功能:通过扫描注册表来找出当前所有物理串口第 15 页 共 37 页/输入参数:无/返回类型:无/说 明:若搜索成功,则每搜到一个串口便发送消息通知主对话框,并将串口号以WPARAM 传递void FindComm()/枚举当前系统中的串口LONG result = 0;HKEY key = NULL;result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, /需要打开的主键的名称“HARDWAREDEVICEMAPSERIALCOMM“, /需要打开的子键的名称,设备串口0, /保留,必须设置为 0KEY_READ, /安全访问标记
26、,也就是权限/得到的将要打开键的句柄,当不再需要句柄,/必须调用 RegCloseKey 关闭它if( result )AfxMessageBox(“无法获取串口,请确认是否安装并连接串口!“);return;TCHAR portname250; /串口名TCHAR data250;DWORD portnamelen = 0; /串口名长度DWORD datalen = 0;int index = 0;while(1) /找完 COM 后跳出portnamelen = 255;datalen = 255;result = RegEnumValue(key, /Long,一个已打开项的句柄,或者
27、指定一个标准项名index+, /Long,欲获取值的索引。注意第一个值的索引编号为零portname, /String,用于装载位于指定索引处值名的一个缓冲区/Long,用于装载 lpData 缓冲区长度的一个变量。/一旦返回,它会设为实际载入缓冲区的字符数量if( result ) break;/发送消息,WM_USER+1 为自定义消息,即找到串口的 ,并将串口号“COMx“通过WPARAM 参数传送给主对话框窗口/:AfxGetMainWnd()-m_hWnd,获得主对话框句柄/(WPARAM)(LPCTSTR)data,类型转换:SendMessage(:AfxGetMainWnd(
28、)-m_hWnd,WM_FOUNDCOMM,(WPARAM)(LPCTSTR)data,0);RegCloseKey(key); /调用 RegCloseKey 关闭打开键的句柄/=自动寻找串口函数结束=/=串口打开函数=/功 能:打开串口,将已打开的串口句柄赋值给 hCom,给出串口打开状态 ComIsOK,完成串口状态设置/输入参数:波特率,数据位,停止位,校验位/返回类型:无void OpenComm(int nBaud, int nData, int nStop, int nCal)hCom = CreateFile ( strcomname, /串口号GENERIC_READ | G
29、ENERIC_WRITE, /允许读或写0, /独占方式NULL,OPEN_EXISTING, /打开而不是创建FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,/重叠方式,用于异步通信NULL );if(hCom = INVALID_HANDLE_VALUE)AfxMessageBox(“打开 COM 失败,串口不存在或已被占用 !“);ComIsOK = false;return;ComIsOK = true;SetCommMask(hCom, EV_TXEMPTY | EV_RXCHAR ); /设置事件掩码,暂时没用上SetupComm(hCom
30、,1024,1024); /设置输入缓冲区和输出缓冲区的大小都是 1024COMMTIMEOUTS TimeOuts;/设定读超时第 17 页 共 37 页TimeOuts.ReadIntervalTimeout = MAXDWORD;TimeOuts.ReadTotalTimeoutConstant = 0;TimeOuts.ReadTotalTimeoutMultiplier = 0;/设定写超时TimeOuts.WriteTotalTimeoutConstant = 500;TimeOuts.WriteTotalTimeoutMultiplier = 100;if(SetCommTime
31、outs(hCom,ComIsOK = false;return;/串口属性配置DCB dcb; GetCommState(hCom, dcb.BaudRate=nBaud; /dcb.BaudRate=9600; /波特率为 9600dcb.ByteSize=nData; /dcb.ByteSize=8; /每个字节为 8 位dcb.StopBits=nStop; /dcb.StopBits=ONESTOPBIT; /1 位停止位dcb.Parity=nCal; /dcb.Parity=NOPARITY; /无奇偶检验位 SetCommState(hCom, PurgeComm(hCom,P
32、URGE_TXCLEAR|PURGE_RXCLEAR);if(SetCommState(hCom,ComIsOK = false;return;return;/=串口打开函数结束=/=串口关闭控制函数=void CloseComm()CloseHandle(hCom);hCom = NULL;ComIsOK = false;/=串口关闭控制函数结束=/=串口监听线程函数=UINT ThreadFunc(LPVOID pParam)第 18 页 共 37 页/ CCommassistDlg* pdlg = (CCommassistDlg*)pParam; /定义指针指向主对话框COMSTAT C
33、omStat;DWORD dwErrorFlags;while(ComIsOK)DWORD dwBytesRead = 100;ClearCommError(hCom,dwBytesRead = min(dwBytesRead,(DWORD)ComStat.cbInQue);if(!dwBytesRead) Sleep(10);/continue;/使用 continue 时,打开串口后 CPU 占用率非常高else :SendMessage(:AfxGetMainWnd()-m_hWnd,WM_READCOMM,1,0); /发送消息,已读到return 0;/=串口监听线程函数结束=/=字
34、符串转 16 进制显示=/字符串转 16 进制显示的函数/传入参数 Data 为字符串/Blank_allow 为空格允许标志,为真则代表允许加入空格/函数返回为 CString 的结果 sResultCString DisplayCString2Hex(CString Data, bool Blank_allow)CString sResult;CString sTemp;int Data_Length;Data_Length = Data.GetLength();if (Data_Length = 0) return “;char *pchar = new charData_Length;
35、 /用了 new 分配内存空间,要记得释放strncpy(pchar,Data,Data_Length);for(int i=0; i= 0) 第 22 页 共 37 页void ShowStatus();int m_intTxCnt;int m_intRxCnt;BOOL m_bAutoSend;DWORD ReadComm();在 commassistDlg.cpp 中加入头文件 comm.h#include “comm.h“加入全局变量CString strIn;CString strOut;CString m_strFile;变量初始化如/ CCommassistDlg dialogC
36、CommassistDlg:CCommassistDlg(CWnd* pParent /*=NULL*/): CDialog(CCommassistDlg:IDD, pParent)/AFX_DATA_INIT(CCommassistDlg)m_strTimer = _T(“);m_strFilePath = _T(“);m_strOut = _T(“);m_strStatus = _T(“);m_check_hexrx = FALSE;m_check_hextx = FALSE;/AFX_DATA_INIT/ Note that LoadIcon does not require a sub
37、sequent DestroyIcon in Win32m_hIcon = AfxGetApp()-LoadIcon(IDR_MAINFRAME);/下面就是自己添加的变量初始化m_strTimer = “1000“;m_strFilePath = “请选择要发送的文件“;m_intTxCnt = 0;m_intRxCnt = 0;m_bAutoSend = 0;strIn = “;strOut = “;在 OnInitDialog 函数中添加代码如下第 23 页 共 37 页/ TODO: Add extra initialization herem_comcontrol.SetForeCo
38、lor(RGB(255,0,0);FindComm(); /调用自动找串口函数m_comlist.SetCurSel(0); /设置串口号下拉框默认值为第一个m_baud.SetCurSel(6); /设置波特率下拉框默认值为 9600m_bdata.SetCurSel(3); /设置数据位下拉框默认值为 8 位m_bstop.SetCurSel(0); /设置停止位下拉框默认值为 1m_cal.SetCurSel(0); /设置校验位下拉框默认值为 None 无GetDlgItem(IDC_BTN_HANDSEND)-EnableWindow(false); /设置手动发送按钮不可用GetD
39、lgItem(IDC_BTN_AUTOSEND)-EnableWindow(false); /设置自动发送按钮不可用GetDlgItem(IDC_EDIT_TIMER)-EnableWindow(false); /设置发送间隔按钮不可用GetDlgItem(IDC_BTN_SELCTFILE)-EnableWindow(false); /设置选择文件按钮不可用GetDlgItem(IDC_BTN_SENDFILE)-EnableWindow(false); /设置发送文件按钮不可用ShowStatus();/下面语句用于解决程序运行后初始化 EDIT 框内容被默认自动选中状态/返回值需更改为
40、FALSEGetFocus(); /获取焦点SetFocus(); /设置焦点m_CEditStatus.SetSel(-1,-1,FALSE); /设置/ PostMessage(EM_SETSEL,-1,0); return FALSE; / return TRUE unless you set the focus to a control用 ClassWizard 添加 WindowProc 函数来处理自定义消息第 24 页 共 37 页函数内容如下:/=消息处理函数=/功能:处理自定义消息=LRESULT CCommassistDlg:WindowProc(UINT message,
41、WPARAM wParam, LPARAM lParam) / TODO: Add your specialized code here and/or call the base classswitch(message)case WM_FOUNDCOMM : /已找到串口,串口号以字符串形式由 wParam 传递m_comlist.AddString(LPCTSTR)wParam); /用 AddString 添加一个字符串即 COM号到 m_comlist 列表框中break;case WM_READCOMM : /读串口消息ReadComm();break;return CDialog:W
42、indowProc(message, wParam, lParam);/=消息处理函数结束=双击“打开串口”按钮编辑代码如下:void CCommassistDlg:OnComcontrol() / TODO: Add your control notification handler code hereint nBaud,nData,nStop,nCal,nTemp;CString sTemp,siTemp;/波特率下拉框设置=nTemp=m_baud.GetCurSel();switch(nTemp)case 0:nBaud = CBR_110; break;case 1:nBaud =
43、CBR_300; break;case 2:nBaud = CBR_600; break;case 3:nBaud = CBR_1200; break;case 4:nBaud = CBR_2400; break;case 5:nBaud = CBR_4800; break;case 6:nBaud = CBR_9600; break;第 25 页 共 37 页case 7:nBaud = CBR_14400; break;case 8:nBaud = CBR_19200; break;case 9:nBaud = CBR_38400; break;case 10:nBaud = CBR_56
44、000; break;case 11:nBaud = CBR_57600; break;case 12:nBaud = CBR_115200; break;case 13:nBaud = CBR_128000; break;case 14:nBaud = CBR_256000; break;/数据位下拉框设置=nTemp=m_bdata.GetCurSel();switch(nTemp)case 0:nData = 5; break;case 1:nData = 6; break;case 2:nData = 7; break;case 3:nData = 8; break;/停止位下拉框设置
45、=nTemp=m_bstop.GetCurSel();switch(nTemp)case 0:nStop = ONESTOPBIT; break;case 1:nStop = ONE5STOPBITS; break;case 2:nStop = TWOSTOPBITS; break;/校验位下拉框设置=nTemp=m_cal.GetCurSel();switch(nTemp)第 26 页 共 37 页case 0:nCal = NOPARITY; break;case 1:nCal = ODDPARITY; break;case 2:nCal = EVENPARITY; break;case
46、3:nCal = MARKPARITY; break;case 4:nCal = SPACEPARITY;break;int commnum_buf;commnum_buf = m_comlist.GetCurSel();if(commnum_buf m_hInstance,MAKEINTRESOURCE(IDI_ICON_OPEN),IMAGE_ICON,GetSystemMetrics(SM_CXICON),GetSystemMetrics(SM_CXICON),0); /显示打开 iconm_comlist.EnableWindow(false); /设置串口号下拉框不可用m_baud.EnableWindow(false); /设置波特率下拉框不可用m_bdata.EnableWindow(false); /设置数据位下拉框不可用m_bstop.EnableWindow(false); /设置停止位下拉框不可用第 27 页 共 37 页m_cal.EnableWindow(false); /设置校验位下拉框不可用GetDlgItem(IDC_BTN_HANDSEND)- EnableWindow(true); /设置手动发送按钮不可用GetDlgIt