Visual C++爲咱們提供了一種好用的ActiveX控件Microsoft Communications Control(即MSComm)來支持應用程序對串口的訪問,在應用程序中插入MSComm控件後就能夠較爲方便地實現對經過計算機串口收發數據。
要使用ActiveX控件MSComm,程序員必須將其添加入工程,其方法是:
(1)單擊主菜單project的子菜單Add To project的Components and Controls選項;
(2)在彈出的"Components and Controls Gallery"對話框中選擇Registered ActiveX Controls文件夾中的"Microsoft Communications Control,version 6.0"選項,以下圖:
html
![]() |
單擊其中的"Insert"按鈕,MSComm控件就被增長到工程中了。與此同時,類CMSComm的相關文件mscomm.h和mscomm.cpp也一併被加入Project的Header Files和Source Files中。固然,程序員能夠本身修改文件名,以下圖:
程序員
![]() |
直接分析mscomm.h頭文件就能夠完備地獲取這個控件的使用方法(主要是public類型的接口函數),下面咱們摘取了頭文件的主要代碼並對其關鍵部分給出了註釋:
編程
#if !defined(AFX_MSCOMM_H__) #define AFX_MSCOMM_H__ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 // Machine generated IDispatch wrapper class(es) created by Microsoft Visual C++ // NOTE: Do not modify the contents of this file. If this class is regenerated by // Microsoft Visual C++, your modifications will be overwritten. ///////////////////////////////////////////////////////////////////////////// // CMSComm wrapper class class CMSComm : public CWnd { protected: DECLARE_DYNCREATE(CMSComm) public: CLSID const& GetClsid() { static CLSID const clsid = { 0x648a5600, 0x2c6e, 0x101b, { 0x82, 0xb6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x14 } }; return clsid; } virtual BOOL Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext = NULL) { return CreateControl(GetClsid(), lpszWindowName, dwStyle, rect, pParentWnd, nID); } BOOL Create(LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CFile* pPersist = NULL, BOOL bStorage = FALSE, BSTR bstrLicKey = NULL) { return CreateControl(GetClsid(), lpszWindowName, dwStyle, rect, pParentWnd, nID, pPersist, bStorage, bstrLicKey); } // Attributes public: // Operations public: void SetCDHolding(BOOL bNewValue); BOOL GetCDHolding(); void SetCommID(long nNewValue); long GetCommID(); void SetCommPort(short nNewValue); //設置端口號,如nNewValue =1表示COM1 short GetCommPort(); void SetCTSHolding(BOOL bNewValue); BOOL GetCTSHolding(); void SetDSRHolding(BOOL bNewValue); BOOL GetDSRHolding(); void SetDTREnable(BOOL bNewValue); BOOL GetDTREnable(); void SetHandshaking(long nNewValue); long GetHandshaking(); void SetInBufferSize(short nNewValue); short GetInBufferSize(); void SetInBufferCount(short nNewValue); short GetInBufferCount(); void SetBreak(BOOL bNewValue); BOOL GetBreak(); void SetInputLen(short nNewValue); short GetInputLen(); void SetNullDiscard(BOOL bNewValue); BOOL GetNullDiscard(); void SetOutBufferSize(short nNewValue); short GetOutBufferSize(); void SetOutBufferCount(short nNewValue); short GetOutBufferCount(); void SetParityReplace(LPCTSTR lpszNewValue); CString GetParityReplace(); void SetPortOpen(BOOL bNewValue); //打開或關閉串口,TRUE:打開,FALSE:關閉 BOOL GetPortOpen(); //串口是否已打開,TRUE:打開,FALSE:關閉 void SetRThreshold(short nNewValue); //若是設置爲1,表示一接收到字符就發送2號事件 short GetRThreshold(); void SetRTSEnable(BOOL bNewValue); //硬件握手使能? BOOL GetRTSEnable(); void SetSettings(LPCTSTR lpszNewValue); //Settings由4部分組成,其格式爲:"BBBB,P,D,S",即"波特率,是否奇偶校驗,數據位 //個數,中止位",如設置爲:"9600,n,8,1" CString GetSettings(); void SetSThreshold(short nNewValue); //若是保持缺省值0不變,則表示發送數據的過程當中串口上不發生事件 short GetSThreshold(); void SetOutput(const VARIANT& newValue); //一個很是重要的函數,用於寫串口,注意其接收的輸入參數爲VARIANT類型對象, //咱們須要將字符串轉化爲VARIANT類型對象 VARIANT GetOutput(); void SetInput(const VARIANT& newValue); VARIANT GetInput(); //一個很是重要的函數,用於讀串口,注意其返回的是VARIANT類型對象,咱們須要 //將其轉化爲字符串 void SetCommEvent(short nNewValue); short GetCommEvent(); //一個很是重要的函數,得到串口上剛發生的事件("事件"能夠理解爲軟件意義上的 //"消息"或硬件意義上的"中斷"),事件的發送會致使OnComm消息的誕生! void SetEOFEnable(BOOL bNewValue); BOOL GetEOFEnable(); void SetInputMode(long nNewValue); long GetInputMode(); }; //{{AFX_INSERT_LOCATION}} // Microsoft Visual C++ will insert additional declarations immediately before the previous line. #endif |
分析上述源代碼可知,基本上,MSComm的諸多接口能夠分爲以下幾類:
(1)打開與設置串口接口函數;
(2)得到串口設置和串口狀態接口函數;
(3)設置串口發送數據方式、緩衝區接口及發送數據接口函數;
(4)設置串口接收數據方式、緩衝區接口及接收數據接口函數;
(5)設置與獲取串口上發生的事件接口函數。
2.例程
程序的功能和界面(以下圖)都與本文連載三中《基於WIN32 API的串口編程》相同,不一樣的只是連載三的串口通訊以API實現,而本節的串口通訊則以MSComm控件實現。
app
![]() |
使用第1節的方法將控件添加入工程並添加mscomm.h和mscomm.cpp文件後,爲了使用控件,咱們將控件拖入對話框內任意一個位置(運行時"電話"圖標會隱藏),其操做以下圖:
框架
![]() |
有趣而極富人性化的是咱們能夠直接右鍵單擊這個"電話",來設置串口的屬性,以下圖:
less
![]() |
接着,咱們須要爲控件添加一個對應的成員變量m_mscom,其對應的變量類型爲CMSComm,以下圖:
函數
![]() ![]() |
這樣就創建了m_mscom和IDC_MSCOMM1控件的相互映射:
this
void CSerialPortActivexDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CSerialPortActivexDlg) DDX_Text(pDX, IDC_RECV_EDIT, m_recv); DDX_Text(pDX, IDC_SEND_EDIT, m_send); DDX_Control(pDX, IDC_MSCOMM1, m_mscom); //}}AFX_DATA_MAP } |
同時,在對話框的頭文件也會由"MFC類嚮導"自動定義CSerialPortActivexDlg類的CMSComm型成員變量m_mscom:
spa
CMSComm m_mscom; |
在對話框初始化時(即在CSerialPortActivexDlg::OnInitDialog函數中)打開串口1:
調試
BOOL CSerialPortActivexDlg::OnInitDialog() { CDialog::OnInitDialog(); // Add "About..." menu item to system menu. // IDM_ABOUTBOX must be in the system command range. ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != NULL) { CString strAboutMenu; strAboutMenu.LoadString(IDS_ABOUTBOX); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } // Set the icon for this dialog. The framework does this automatically // when the application's main window is not a dialog SetIcon(m_hIcon, TRUE); // Set big icon SetIcon(m_hIcon, FALSE); // Set small icon // TODO: Add extra initialization here m_mscom.SetCommPort(1); //串口1 m_mscom.SetInBufferSize(1024); //設置輸入緩衝區的大小,Bytes m_mscom.SetOutBufferSize(512); //設置輸入緩衝區的大小,Bytes if(!m_mscom.GetPortOpen()) //打開串口 { m_mscom.SetPortOpen(true); } m_mscom.SetInputMode(1); //設置輸入方式爲二進制方式 m_mscom.SetSettings("9600,n,8,1"); //設置波特率等參數 m_mscom.SetRThreshold(1); //爲1表示有一個字符即引起事件 m_mscom.SetInputLen(0); return TRUE; // return TRUE unless you set the focus to a control } |
最核心的發送串口數據函數("發送"按鈕單擊事件)以下:
void CSerialPortActivexDlg::OnSendButton() { // TODO: Add your control notification handler code here UpdateData(true); CByteArray sendArr; WORD wLength; wLength = m_send.GetLength(); sendArr.SetSize(wLength); for(int i =0; i<wLength; i++) { sendArr.SetAt(i, m_send.GetAt(i)); } m_mscom.SetOutput(COleVariant(sendArr)); } |
爲了處理接收事件,咱們須要爲MScomm控件添加對應的消息處理函數。以下圖,咱們經過"MFC類嚮導"添加了CSerialPortActivexDlg 類的成員函數OnCommMscomm1():
這樣,在對話框的頭文件中就會自動增長下面兩句:
afx_msg void OnCommMscomm1();//函數聲明 DECLARE_EVENTSINK_MAP() |
來自AFX_MSG部分:
// Generated message map functions //{{AFX_MSG(CSerialPortActivexDlg) virtual BOOL OnInitDialog(); afx_msg void OnSysCommand(UINT nID, LPARAM lParam); afx_msg void OnPaint(); afx_msg HCURSOR OnQueryDragIcon(); afx_msg void OnClearButton(); afx_msg void OnSendButton(); afx_msg void OnCommMscomm1(); DECLARE_EVENTSINK_MAP() //}}AFX_MSG |
同時在對話框的.cpp文件中會增長下列代碼實現串口消息映射:
BEGIN_EVENTSINK_MAP(CSerialPortActivexDlg, CDialog) //{{AFX_EVENTSINK_MAP(CSerialPortActivexDlg) ON_EVENT(CSerialPortActivexDlg, IDC_MSCOMM1, 1 /* OnComm */, OnCommMscomm1, VTS_NONE) //}}AFX_EVENTSINK_MAP END_EVENTSINK_MAP() |
咱們定義CSerialPortActivexDlg::OnCommMscomm1()函數主要處理數據的接收,其源代碼爲:
void CSerialPortActivexDlg::OnCommMscomm1() { // TODO: Add your control notification handler code here UpdateData(true); VARIANT variant_inp; COleSafeArray safearray_inp; long i = 0; int len; char rxdata[1000]; CString tmp; switch (m_mscom.GetCommEvent()) { case 2: //表示接收緩衝區內有字符 { variant_inp = m_mscom.GetInput(); safearray_inp = variant_inp; len = safearray_inp.GetOneDimSize(); for (i = 0; i < len; i++) { safearray_inp.GetElement(&i, &rxdata[i]); } rxdata[i] = '\0'; } m_recv += rxdata; UpdateData(false); break; default: break; } } |
最後,與連載三相似,再次藉助"串口調試助手"以實例驗證了本程序的正確性,以下圖:
![]() |
最後,須要特別提示的是:若是要在基於"文檔/視圖"的框架結構程序而非對話框程序中使用串口控件,咱們不能輕鬆地使用"MFC類嚮導",這時候必須手動地添加相關代碼。
在MainFrm.h頭文件中加入:
afx_msg void OnCommMscomm(); DECLARE_EVENTSINK_MAP() |
並定義CMSComm成員變量:
CMSComm m_ComPort; |
在MainFrm.cpp文件中添加
BEGIN_EVENTSINK_MAP(CMainFrame, CFrameWnd) ON_EVENT(CMainFrame,ID_COMMCTRL,1,OnCommMscomm,VTS_NONE) //映射ACTIVEX控件的事件 END_EVENTSINK_MAP() |
在MainFrm.cpp文件的OnCreate(LPCREATESTRUCT lpCreateStruct)函數中添加:
ComPort.Create(NULL, WS_VISIBLE | WS_CHILD, CRect(0,0,0,0),this, ID_COMMCTRL); |
以建立CMSComm控件。
此後,咱們就能夠在CMainFrame類的函數中使用串口控件對應的ComPort控件成員變量。