利用 MFC CDatabase + ODBC Excel 驅動,將 CListCtrl 所有數據 (含列標題) 直接寫入 `.xls` 文件,無需 Excel COM 自動化,無需安裝 Office,速度快、部署輕量。
LVCOLUMN columnData;
columnData.mask = LVCF_TEXT;
columnData.cchTextMax = 100; // 必須設置!否則 GetColumn 不返回文本
columnData.pszText = columnName.GetBuffer(100);
for (int i = 0; pList->GetColumn(i, &columnData); i++) {
// columnData.pszText 即列標題
}
columnName.ReleaseBuffer();
常見錯誤:只設置 `mask = LVCF_TEXT` 卻忘記 `cchTextMax` 和 `pszText` 緩衝區,導致列名為空。
無直接 API,需從 0 開始遞增 `nCol` 直到 `GetColumn` 返回 FALSE。
CString sSql;
sSql.Format(_T("DRIVER={%s};DSN='';FIRSTROWHASNAMES=1;READONLY=FALSE;CREATE_DB=\"%s\";DBQ=%s"),
sDriver, sExcelFile, sExcelFile);
void ExportListToExcel(CListCtrl* pList, CString strTitle) {
if (pList->GetItemCount() == 0) return;
CDatabase database;
CString sDriver = GetExcelDriver(); // 註冊表查找 "Microsoft Excel Driver (*.xls)"
if (sDriver.IsEmpty()) {
AfxMessageBox(_T("未安裝 Excel 驅動!"));
return;
}
CString sExcelFile;
if (!GetDefaultXlsFileName(sExcelFile)) return; // "另存為" 對話框
CString sSql = _T("");
CString tableName = strTitle;
CString strH, strV;
// 1. 打開/創建數據庫 (即 .xls 文件)
if (database.OpenEx(sSql, CDatabase::noOdbcDialog)) {
// 2. 構建 CREATE TABLE 語句
LVCOLUMN columnData;
CString columnName;
columnData.mask = LVCF_TEXT;
columnData.cchTextMax = 100;
columnData.pszText = columnName.GetBuffer(100);
int columnNum = 0;
for (int i = 0; pList->GetColumn(i, &columnData); i++) {
if (i != 0) { sSql += _T(", "); strH += _T(", "); }
sSql += _T(" ") + columnData.pszText + _T(" TEXT");
strH += _T(" ") + columnData.pszText + _T(" ");
columnNum = i + 1;
}
columnName.ReleaseBuffer();
sSql = _T("CREATE TABLE ") + tableName + _T(" (") + sSql + _T(" )");
database.ExecuteSQL(sSql);
// 3. 插入數據行
for (int nItemIndex = 0; nItemIndex < pList->GetItemCount(); nItemIndex++) {
strV = _T("");
for (int i = 0; i < columnNum; i++) {
if (i != 0) strV += _T(", ");
CString cellText = pList->GetItemText(nItemIndex, i);
cellText.Replace(_T("'"), _T("''")); // 轉義單引號
strV += _T("'") + cellText + _T("'");
}
sSql = _T("INSERT INTO ") + tableName + _T(" (") + strH + _T(") VALUES (") + strV + _T(")");
database.ExecuteSQL(sSql);
}
database.Close();
AfxMessageBox(_T("導出成功:") + sExcelFile);
}
}
CString GetExcelDriver() {
CString strDriver;
// 遍歷 ODBC 驅動註冊表項
// HKEY_LOCAL_MACHINE\SOFTWARE\ODBC\ODBCINST.INI\ODBC Drivers
// 查找包含 "Excel" 的驅動名稱
return strDriver; // 如 "Microsoft Excel Driver (*.xls)"
}
BOOL GetDefaultXlsFileName(CString& sFile) {
CFileDialog dlg(FALSE, _T("xls"), _T("Export.xls"),
OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
_T("Excel 文件 (*.xls)|*.xls||"));
if (dlg.DoModal() == IDOK) {
sFile = dlg.GetPathName();
return TRUE;
}
return FALSE;
}
| 優點 | 缺點 |
|---|---|
| 無需安裝 Office/Excel | 僅支持 .xls (Excel 97-2003),不支持 .xlsx |
| 純數據導出,速度極快 | 無法設置單元格格式 (顏色、字體、寬度、公式) |
| 部署簡單,只需 ODBC 驅動 (Windows 內建) | 大數據量時 INSERT 逐條執行較慢,可批次優化 |
| 代碼純 C++/MFC,無 COM 依賴 | 64 位程序需 64 位 Excel 驅動 (Office 64位或 Access Database Engine) |
此方案適合「純數據導出、無 Office 環境、追求簡單部署」的場景。代碼結構清晰,封裝為通用函數即可在專案中複用。若需專業報表功能,建議遷移至 COM 自動化或第三方庫 (如 libxl, OpenXLSX)。