DAO(Data Access Objects)是 MFC 存取 Access 資料庫的經典介面,但 AppWizard 自動產生的程式碼往往無法滿足實際專案需求。本文分享三個高頻實戰技巧:在未勾選資料庫支援的專案中動態加入 DAO、手工實現控件靜態綁定、以及確保專案連同資料庫檔案可攜式部署。
情境:專案建立時未勾選「Database support」,後來需要存取 Access。
CMyDB,基底類別 CDaoRecordset,選擇正確 .mdb 與資料表。CMyDB.h 加 #include <afxdao.h>#include "MyDB.h"void CMyDlg::OnTest()
{
CMyDB db;
if (db.Open()) {
AfxMessageBox(db.m_strFieldName); // 假設資料表有此欄位
db.Close();
}
}
情境:未使用 AppWizard 資料庫支援,需手動將 Edit Control 綁定至記錄集欄位。
// MyDlg.h
//{{AFX_DATA(CMyDlg)
enum { IDD = IDD_MYDLG };
CMyDB* m_pRec; // 記錄集指標
CEdit m_editField;
//}}AFX_DATA
m_strField(型別 CString)。CMyDlg::CMyDlg(CWnd* pParent) : CDialog(IDD_MYDLG, pParent) {
m_pRec = new CMyDB;
m_pRec->Open();
}
void CMyDlg::OnClose() {
if (m_pRec) {
m_pRec->Close();
delete m_pRec; m_pRec = NULL;
}
CDialog::OnClose();
}
void CMyDlg::RefreshDisplay() {
if (m_pRec && !m_pRec->IsEOF()) {
m_strField = m_pRec->m_strFieldName; // 記錄集欄位
UpdateData(FALSE); // 類別 -> 控件
}
}
缺點:移動記錄指標後需手動呼叫 RefreshDisplay(),無 CRecordView 的自動同步。
問題:專案複製到他機器,硬編碼絕對路徑的 GetDefaultDBName() 導致找不到 .mdb。
解法:修改記錄集類別的 GetDefaultDBName() 動態解析執行目錄:
CString CMyDB::GetDefaultDBName()
{
TCHAR szPath[MAX_PATH];
GetModuleFileName(AfxGetInstanceHandle(), szPath, MAX_PATH);
PathRemoveFileSpec(szPath); // 移除 exe 檔名
PathAppend(szPath, _T("MyData.mdb")); // 資料庫檔放同目錄
return szPath;
}
<shlwapi.h> 並連結 shlwapi.lib(或用 CString 手工拆分路徑)。MyApp.exe、MyData.mdb 放同一資料夾即可執行。在 stdafx.h 中透過宏控制:
#define _DAO_VERSION_350 // 強制使用 DAO 3.5 (Access 97 相容)
// #define _DAO_VERSION_360 // DAO 3.6 (Access 2000)
#include <afxdao.h>
若專案需同時支援新舊格式,建議編譯兩組 DLL 分別載入,或改用 ADO (ACE OLEDB) 統一處理。
| 現象 | 原因 | 對策 |
|---|---|---|
| Open() 失敗,錯誤 3024/3044 | 路徑錯誤、檔案被佔用、格式不符 | 檢查 GetDefaultDBName 回傳值、確認 .mdb 非唯讀、轉存為 Access 97 |
| 欄位值為空/亂碼 | RFX 對應錯誤、Unicode/ANSI 不匹配 | 核對 DoFieldExchange 欄位名稱大小寫、專案字元集設定 |
| 刪除記錄後 MoveNext 崩潰 | 游標失效 | Delete() 後立即 MoveNext(),或 Requery() 重建游標 |
掌握「動態加入 DAO」「手工靜態綁定」「相對路徑部署」三大技巧,即可在不依賴 AppWizard 資料庫支援的前提下,靈活地在任何 MFC 專案中整合 Access 資料庫功能,並確保專案的可攜性與部署便利性。