在 Win32 組合語言中操作資料庫,透過 ODBC API 是最標準的路徑。本文完整解析一個基於對話框的 Access 資料庫應用程式,涵蓋連線管理、查詢執行、ListView 資料綁定、參數化查詢等企業級開發核心技術,採用 MASM32 SDK 風格,程式碼可直接用於實務專案。
.386
.model flat, stdcall
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\odbc32.inc
include \masm32\include\comctl32.inc
include \masm32\include\user32.inc
includelib \masm32\lib\odbc32.lib
includelib \masm32\lib\comctl32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\user32.lib
; 資源 ID
IDD_MAINDLG equ 101
IDR_MAINMENU equ 102
IDC_DATALIST equ 1000
IDM_CONNECT equ 40001
IDM_DISCONNECT equ 40002
IDM_QUERY equ 40003
IDM_CUSTOMQUERY equ 40004
IDD_QUERYDLG equ 102
start:
invoke GetModuleHandle, NULL
mov hInstance, eax
call GetProgramPath ; 取得執行檔目錄,預設 DB 同目錄
invoke DialogBoxParam, hInstance, IDD_MAINDLG, 0, addr DlgProc, 0
invoke ExitProcess, eax
GetProgramPath 使用 GetModuleFileName 取得完整路徑,再由尾部向前掃描 \ 截斷檔名,保留目錄供連線字串使用。
ODBCConnectSQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &hEnv)SQLSetEnvAttr(hEnv, SQL_ATTR_ODBC_VERSION, SQL_OV_ODBC3, 0)SQLAllocHandle(SQL_HANDLE_DBC, hEnv, &hConn)DRIVER={Microsoft Access Driver (*.mdb)};DBQ= + 程式目錄 + test.mdbSQLDriverConnect(..., SQL_DRIVER_COMPLETE),若 DB 不存在會彈出對話框讓使用者指定路徑。MessageBox 顯示驅動程式回傳的完整連線字串。RunQuery / FillData; 分配陳述式控制代碼
invoke SQLAllocHandle, SQL_HANDLE_STMT, hConn, addr hStmt
; 直接執行 SQL
invoke SQLExecDirect, hStmt, addr SQLStatement, sizeof SQLStatement
; SQLStatement = "select * from main"
; 綁定資料欄 → 緩衝區
invoke SQLBindCol, hStmt, 1, SQL_C_CHAR, addr TheName, sizeof TheName, addr NameLength
invoke SQLBindCol, hStmt, 2, SQL_C_CHAR, addr TheSurname, sizeof TheSurname, addr SurnameLength
invoke SQLBindCol, hStmt, 3, SQL_C_CHAR, addr TelNo, sizeof TelNo, addr TelNoLength
; 逐列擷取
mov row, 0
.while TRUE
; 清空緩衝區
mov byte ptr [TheName], 0
...
invoke SQLFetch, hStmt
.break .if ax != SQL_SUCCESS && ax != SQL_SUCCESS_WITH_INFO
; 插入 ListView 項目
mov lvi.imask, LVIF_TEXT+LVIF_PARAM
mov lvi.iItem, row
mov lvi.iSubItem, 0
mov lvi.pszText, offset TheName
invoke SendMessage, hList, LVM_INSERTITEM, 0, addr lvi
; 子項目
inc lvi.iSubItem
mov lvi.pszText, offset TheSurname
invoke SendMessage, hList, LVM_SETITEM, 0, addr lvi
inc lvi.iSubItem
mov lvi.pszText, offset TelNo
invoke SendMessage, hList, LVM_SETITEM, 0, addr lvi
inc row
.endw
QueryProc在 WM_INITDIALOG 預先準備:
; SQL: "select * from main where name=?"
invoke lstrcpy, addr Conn, addr SQLStatement
invoke lstrcat, addr Conn, addr WhereStatement
; 綁定參數 1 → SearchName 緩衝區
invoke SQLBindParameter, hStmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, 25, 0, addr SearchName, 25, addr StrLen
; 預編譯
invoke SQLPrepare, hStmt, addr Conn, sizeof Conn
使用者輸入名字按 OK 時:
invoke GetDlgItemText, hDlg, IDC_NAME, addr SearchName, 25
invoke lstrlen, addr SearchName
mov StrLen, eax
invoke SendMessage, hList, LVM_DELETEALLITEMS, 0, 0
invoke SQLExecute, hStmt ; 重複執行已預編譯陳述式
invoke FillData
invoke SQLCloseCursor, hStmt
| 階段 | API | 用途 |
|---|---|---|
| 連線失敗 | SQLFreeHandle(SQL_HANDLE_DBC/ENV) | 釋放已分配控制代碼 |
| 查詢失敗 | SQLFreeHandle(SQL_HANDLE_STMT) | 釋放陳述式控制代碼 |
| 關閉遊標 | SQLCloseCursor | 釋放結果集鎖定 |
| 視窗關閉 | ODBCDisconnect → SQLDisconnect + FreeHandle | 完整清理 |
test.mdb(含 main 資料表:Name, Surname, Telephone No.)SQLPrepare + SQLBindParameter + SQLExecute,防止 SQL Injection、提升重複查詢效能。DlgProc/QueryProc 分離,選單狀態集中管理(SwitchMenuState)。此範例展示了 Win32 組合語言開發資料庫應用的完整實力,結構清晰、資源管理嚴謹,是學習 MASM32 視窗程式設計與 ODBC 程式設計的極佳範本。