在 DOS/Win9x 時代,程式可直接透過 inport()/outport() 操作硬體 I/O 埠,擁有對串口的完全控制權。自 Windows 2000 起,作業系統實施硬體保護策略,所有硬體存取必須經過核心模式驅動程式中介。開發者必須使用 Windows 通訊 API,達成「裝置獨立性」:程式只需表達意圖(如設定鮑率、讀寫資料),由作業系統轉譯為具體硬體操作。
CreateFile() - 開啟串口HANDLE CreateFile(
LPCTSTR lpFileName, // "COM1", "COM2"...
DWORD dwDesiredAccess, // GENERIC_READ | GENERIC_WRITE
DWORD dwShareMode, // 0 (獨佔)
LPSECURITY_ATTRIBUTES lpSecurityAttributes, // NULL
DWORD dwCreationDisposition, // OPEN_EXISTING
DWORD dwFlagsAndAttributes, // FILE_FLAG_OVERLAPPED (非同步)
HANDLE hTemplateFile // NULL
);
範例:
HANDLE hComm = CreateFile("COM1",
GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING,
FILE_FLAG_OVERLAPPED, 0);
CloseHandle() - 關閉串口BOOL CloseHandle(HANDLE hObject);
GetCommState() / SetCommState() - 取得/設定裝置控制區塊 (DCB)DCB 結構包含鮑率、奇偶校驗、資料位、停止位等參數。標準流程:
DCB dcb;
GetCommState(hComm, &dcb); // 取得目前設定
dcb.BaudRate = 9600; // 修改參數
dcb.ByteSize = 8;
dcb.Parity = NOPARITY;
dcb.StopBits = ONESTOPBIT;
SetCommState(hComm, &dcb); // 套用設定
WriteFile() - 寫入資料(非同步)BOOL WriteFile(
HANDLE hFile,
LPCVOID lpBuffer,
DWORD nNumberOfBytesToWrite,
LPDWORD lpNumberOfBytesWritten,
LPOVERLAPPED lpOverlapped
);
範例:
OVERLAPPED ovWrite = {0};
ovWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
DWORD bytesSent;
BYTE sendBuf[5] = {1,2,3,4,5};
WriteFile(hComm, sendBuf, 5, &bytesSent, &ovWrite);
// 若非同步待決,需 GetOverlappedResult 等待完成
ReadFile() - 讀取資料(非同步)BOOL ReadFile(
HANDLE hFile,
LPVOID lpBuffer,
DWORD nNumberOfBytesToRead,
LPDWORD lpNumberOfBytesRead,
LPOVERLAPPED lpOverlapped
);
讀取前通常先呼叫 ClearCommError() 取得輸入緩衝區資料量:
COMSTAT comStat; DWORD dwError;
ClearCommError(hComm, &dwError, &comStat);
DWORD toRead = comStat.cbInQue;
ReadFile(hComm, buf, toRead, &bytesRead, &ovRead);
ClearCommError() - 清除錯誤/取得狀態回傳 COMSTAT 結構,關鍵欄位:cbInQue(接收緩衝區位元組數)、cbOutQue(發送緩衝區位元組數)。錯誤代碼包含 CE_FRAME、CE_OVERRUN、CE_RXPARITY 等。
PurgeComm() - 清除緩衝區PurgeComm(hComm,
PURGE_TXABORT | PURGE_RXABORT |
PURGE_TXCLEAR | PURGE_RXCLEAR);
SetCommMask() / WaitCommEvent() - 事件通知機制兩種讀取模式:
ClearCommError() 檢查 cbInQueWaitCommEvent() 等待事件發生,再通知主視窗處理SetCommMask(hComm, EV_RXCHAR | EV_TXEMPTY); // 監視接收字元、發送緩衝區空
// 監視執行緒
OVERLAPPED os = {0}; os.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
DWORD dwMask;
if (!WaitCommEvent(hComm, &dwMask, &os)) {
if (GetLastError() == ERROR_IO_PENDING) {
GetOverlappedResult(hComm, &os, &dwTrans, TRUE); // 等待事件
switch (dwMask) {
case EV_RXCHAR: PostMessage(hwnd, WM_COMM_RXCHAR, 0, 0); break;
case EV_TXEMPTY: PostMessage(hwnd, WM_COMM_TXEMPTY, 0, 0); break;
case EV_ERR: /* 處理錯誤 */ break;
}
}
}
WM_CREATECreateFile() 開啟串口SetCommMask() 設定監視事件CreateThread())WM_COMM_RXCHAR 等)WM_DESTROY → 清理資源WaitCommEvent() 進入等待狀態GetOverlappedResult() 確認完成dwMask 判斷事件類型PostMessage() 通知主視窗hEvent,否則非同步操作會失敗。Get/SetCommState 前務必設定 dcb.DCBlength = sizeof(DCB)。lpNumberOfBytesWritten/Read 與請求長度,處理部分完成情況。GetLastError() 診斷。CreateEvent()、CreateFile()、執行緒控制代碼必須在結束時 CloseHandle()。雖然 Win32 串口 API 仍是基礎,但現代專案建議考慮:
Windows 串口程式設計的核心在於掌握 DCB 參數設定、非同步 I/O 機制、事件驅動模型。透過 CreateFile 取得控制代碼、SetCommState 設定參數、SetCommMask+WaitCommEvent 實現高效事件通知、雙執行緒分離 UI 與通訊邏輯,即可建立穩定、高效的串口應用程式。本文涵蓋的 API 組合與架構模式,是 Win32 串口開發的標準範式。