| 層級 | 技術棧 | 關鍵特性 |
|---|---|---|
| 伺服器 | Win32 IOCP (I/O Completion Ports) + 多執行緒 + ODBC API | 高併發、線性擴展 (CPU 核心數 × 2 + 2 執行緒池) |
| 客戶端 | 純 Win32 API (無 MFC) + 動態記憶體佈局 | 800×600 / 1024×768 自適應、試卷動態分頁、倒計時同步 |
| 資料庫 | ODBC 連線 (SQL Server / Access 等) | 試卷、題目、作答、成績集中管理 |
CPU核心數 × 2 + 2),無上下文切換風暴CreateIoCompletionPort 綁定 Socket + 檔案控制代碼
[Accept 執行緒] → accept() → CreateIoCompletionPort(socket, hIOCP, CompletionKey, 0)
↓
[Worker 執行緒池 (N=CPU*2+2)] ← GetQueuedCompletionStatus(hIOCP, ...)
↓
處理 Overlapped I/O 完成事件
↓
邏輯處理 (登入/試卷/作答/成績)
↓
PostQueuedCompletionStatus (如需後續非同步操作)

CreateWindowEx 建立主視窗、Static/Edit/Button/ScrollBar 等標準控制項GetClientRect 計算相對位置,支援雙解析度自適應
// 題目結構
struct Question {
BOOL state; // 作答狀態
char Text[512]; // 題幹
};
struct Option {
BOOL state;
char Text[256];
};
struct TestItem {
Question Title;
Option Choose[4];
};
// 動態配置
TestItem* g_pTestPaper = NULL;
int g_nQuestionNum = 0;
// 畫面行緩衝 (處理自動換行)
struct Line {
int earmark; // 對應按鈕 ID
BOOL color1, color2;
char Text[512];
};
Line* g_pScreenLines = NULL;
int g_nTotalLines = 0;
GetNum 取得總題數 → new TestItem[n]GetQue 逐題取得內容 → 填充 g_pTestPaper
TextOut 寬度計算,將長行拆分,產生 g_pScreenLinesHWND* g_hBtns = new HWND[n*4],ID = 題號*10 + 選項
int nLineWidth = clientWidth / charWidth; // 偶數
int nHanChar = 0; // 雙位元組字元計數
for (each char in text) {
if (IsDBCSLeadByte(c)) nHanChar++; // 簡易判斷漢字
// ... 累加寬度
if (exceeds lineWidth) {
if (nHanChar % 2 == 1) lineWidth--; // 避免漢字被切半
// 換行邏輯
nHanChar = 0;
}
}
WM_PAINT:遍歷 g_pScreenLines 呼叫 TextOut,依 earmark 顯示/隱藏對應單選按鈕WM_COMMAND (按鈕點擊):解析 ID → 更新 g_pTestPaper 狀態 → InvalidateRect 重繪
login:username,subject,password → 登入驗證
Srecv:ScanTm → 取得伺服器時間/倒計時
Srecv:GetSta → 取得試卷狀態
Srecv:GetRlt → 取得上次作答 (斷點續作)
Srecv:GetNum → 取得總題數/時間
Srecv:GetQue → 取得題目內容
Srecv:SaveDt → 儲存作答
Srecv:ChanST → 修改試卷狀態 (鎖定/交卷)

姚明1981922完整原始碼 (伺服器/客戶端/資料庫腳本) 請參考本文配套下載。此專案為大型作業答辯作品,展示了從網路模型到 UI 繪製的全棧實作能力。