CSerialPort 是針對 Win32 序列埠 API (CreateFile, ReadFile, WriteFile, SetCommState 等) 的 C++ MFC 風格封裝類,支援 Windows 9x/ME/NT/2000/XP,提供阻塞、重疊 (Overlapped) 及回調 (NT 專屬) 三種 I/O 模式,介面簡潔且以 C++ 異常 (CSerialException) 處理錯誤,程式碼在 Warning Level 4 下乾淨編譯,支援 Unicode 與 MFC 靜態連結。
核心類別結構
- CSerialException:序列埠專用異常類別,封裝系統錯誤碼
- CSerialPort:主要操作類別,涵蓋開啟/關閉、讀寫、設定、狀態查詢、事件等待、緩衝區控制等完整功能
CSerialException 介面
class CSerialException : public CException {
public:
CSerialException(DWORD dwError = 0); // 捕獲 GetLastError()
virtual BOOL GetErrorMessage(LPTSTR lpszError, UINT nMaxError, PUINT pnHelpContext = NULL);
CString GetErrorMessage(); // 直接取得錯誤描述字串
DWORD m_dwError; // 系統錯誤碼 (參考 WINERROR.H)
};
// 拋出輔助:AfxThrowSerialException(dwError)
CSerialPort 完整 API 分類速查
生命週期與附加
| 方法 | 說明 |
CSerialPort() | 建構子,初始化預設值 |
~CSerialPort() | 解構子,自動關閉已開啟埠 |
Open(nPort, baud, parity, dataBits, stopBits, flowCtrl, bOverlapped) | 開啟指定序列埠 (COM1~),完整參數設定 |
Close() | 關閉埠,與 Open 配對 |
Attach(hComm, bOverlapped) | 綁定現有 SDK Handle (類似 CWnd::Attach) |
Detach() | 分離並傳回 Handle (類似 CWnd::Detach) |
operator HANDLE() | 隱含轉換取得 SDK Handle,可直接呼叫 Win32 API |
IsOpen() | 檢查埠是否開啟 |
資料讀寫 (阻塞/重疊/非同步)
| 方法 | 模式 | 說明 |
Read(buf, count) | 阻塞 | 同步讀取,回傳實際位元組數 |
Read(buf, count, overlapped, pBytesRead) | 重疊 | 非同步讀取,立即回傳 BOOL |
ReadEx(buf, count) | 非同步回調 | 使用 ReadFileEx,完成時呼叫 OnCompletion |
Write(buf, count) | 阻塞 | 同步寫入,回傳實際位元組數 |
Write(buf, count, overlapped, pBytesWritten) | 重疊 | 非同步寫入 |
WriteEx(buf, count) | 非同步回調 | 使用 WriteFileEx |
TransmitChar(c) | 即時 | 傳送單一字元 (TransmitCommChar) |
重疊 I/O 輔助
void GetOverlappedResult(OVERLAPPED& ol, DWORD& bytesTransferred, BOOL bWait);
void CancelIo(); // 取消擱置 I/O (Win98+/NT4+)
序列埠參數設定 (DCB/COMMCONFIG)
| 方法 | 對應 SDK | 說明 |
GetConfig(COMMCONFIG&) | GetCommConfig | 取得完整設定 (含 UI 專屬資料) |
SetConfig(COMMCONFIG&) | SetCommConfig | 套用完整設定 |
GetDefaultConfig(nPort, COMMCONFIG&) | GetDefaultCommConfig | 取得系統預設設定 |
SetDefaultConfig(nPort, COMMCONFIG&) | SetDefaultCommConfig | 修改系統預設設定 |
GetState(DCB&) | GetCommState | 取得 DCB (鮑率、校驗、資料位、停止位等) |
SetState(DCB&) | SetCommState | 套用 DCB 設定 |
Setup(inQueue, outQueue) | SetupComm | 設定驅動程式輸入/輸出緩衝區大小 |
流控制與狀態線
enum FlowControl { NoFlowControl, CtsRtsFlowControl, CtsDtrFlowControl,
DsrRtsFlowControl, DsrDtrFlowControl, XonXoffFlowControl };
void ClearBreak() / SetBreak(); // 清除/設置中斷訊號
void ClearError(DWORD& errors); // 清除錯誤旗標
void GetStatus(COMSTAT& stat); // 取得通訊狀態 (接收/發送等待位元組數)
void Escape(DWORD func); // EscapeCommFunction 通用控制
void ClearDTR() / SetDTR(); // DTR 線控制
void ClearRTS() / SetRTS(); // RTS 線控制
void SetXOFF() / SetXON(); // 軟體流控 XOFF/XON 發送
Modem 狀態與事件等待
void GetModemStatus(DWORD& modemStatus); // CTS/DSR/RI/RLSD 狀態
void SetMask(DWORD mask); // 設定事件遮罩 (EV_RXCHAR, EV_TXEMPTY...)
void GetMask(DWORD& mask); // 取得目前事件遮罩
void WaitEvent(DWORD& mask); // 同步等待事件
BOOL WaitEvent(DWORD& mask, OVERLAPPED&); // 重疊等待事件
緩衝區清除與刷新
void Flush(); // FlushFileBuffers (硬體緩衝區寫入)
void Purge(DWORD flags); // PurgeComm 綜合清除
void TerminateOutstandingWrites(); // PURGE_TXABORT - 終止擱置寫入
void TerminateOutstandingReads(); // PURGE_RXABORT - 終止擱置讀取
void ClearWriteBuffer(); // PURGE_TXCLEAR - 清除輸出緩衝區
void ClearReadBuffer(); // PURGE_RXCLEAR - 清除輸入緩衝區
逾時設定
void SetTimeouts(COMMTIMEOUTS&); // 完整逾時結構
void GetTimeouts(COMMTIMEOUTS&);
void Set0Timeout(); // 讀寫逾時 = 0 (非阻塞輪詢模式)
void Set0WriteTimeout(); // 僅寫入逾時 = 0
void Set0ReadTimeout(); // 僅讀取逾時 = 0
非同步回調虛擬函數 (衍生類別覆寫)
virtual void OnCompletion(DWORD dwErrorCode, DWORD dwCount, LPOVERLAPPED lpOverlapped);
// dwErrorCode: 0=成功, ERROR_HANDLE_EOF=讀到檔尾
// dwCount: 傳輸位元組數
// lpOverlapped: 對應的 OVERLAPPED 結構
// 注意:清理 lpOverlapped 記憶體前必須呼叫基類 OnCompletion
狀態查詢便利函數
DWORD BytesWaiting(); // 輸入緩衝區待讀位元組數
BOOL DataWaiting(DWORD timeout); // 等待 timeout 毫秒檢查是否有資料到達
使用範例
CSerialPort port;
try {
port.Open(1, 9600, CSerialPort::NoParity, 8, CSerialPort::OneStopBit,
CSerialPort::NoFlowControl, FALSE); // 阻塞模式
char buf[256];
DWORD read = port.Read(buf, sizeof(buf));
port.Write("ACK", 3);
port.Close();
} catch (CSerialException* e) {
AfxMessageBox(e->GetErrorMessage());
e->Delete();
}
原始碼、範例專案與最新版本請參考作者個人網站。授權條款允許二進位制商業/免費產品內含,修改時保留模組頂部版權聲明,重發布源碼僅限作者最新版本。