MSComm控件


  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

MSComm控件 - 郎行拂曉 - 郎行拂曉的博客


  單擊其中的"Insert"按鈕,MSComm控件就被增長到工程中了。與此同時,類CMSComm的相關文件mscomm.h和mscomm.cpp也一併被加入Project的Header Files和Source Files中。固然,程序員能夠本身修改文件名,以下圖:

程序員

MSComm控件 - 郎行拂曉 - 郎行拂曉的博客


  直接分析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

MSComm控件 - 郎行拂曉 - 郎行拂曉的博客


  使用第1節的方法將控件添加入工程並添加mscomm.h和mscomm.cpp文件後,爲了使用控件,咱們將控件拖入對話框內任意一個位置(運行時"電話"圖標會隱藏),其操做以下圖:

框架

MSComm控件 - 郎行拂曉 - 郎行拂曉的博客


  有趣而極富人性化的是咱們能夠直接右鍵單擊這個"電話",來設置串口的屬性,以下圖:

less

MSComm控件 - 郎行拂曉 - 郎行拂曉的博客


  接着,咱們須要爲控件添加一個對應的成員變量m_mscom,其對應的變量類型爲CMSComm,以下圖:

函數

MSComm控件 - 郎行拂曉 - 郎行拂曉的博客 MSComm控件 - 郎行拂曉 - 郎行拂曉的博客


  這樣就創建了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;
}
}


  最後,與連載三相似,再次藉助"串口調試助手"以實例驗證了本程序的正確性,以下圖:

MSComm控件 - 郎行拂曉 - 郎行拂曉的博客


  最後,須要特別提示的是:若是要在基於"文檔/視圖"的框架結構程序而非對話框程序中使用串口控件,咱們不能輕鬆地使用"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控件成員變量。

相關文章
相關標籤/搜索