首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

MFC 自動化操作 Excel 完整教程:COM 初始化、類型庫導入、讀寫單元格與資源釋放

     編輯:關於C語言

MFC 操作 Excel:OLE 自動化容器模式

通過 COM 接口控制 Excel.Application,實現報表生成、數據導入導出。核心流程:初始化 COM → 創建 Excel 對象 → 獲取 Workbooks/Worksheets/Range → 讀寫數據 → 釋放資源退出。

一、環境準備:導入 Excel 類型庫

  1. 打開 ClassWizard (Ctrl+W)。
  2. Add Class → From a type library。
  3. 選擇 Excel 類型庫:
    • Excel 97 (8.0):C:\Program Files\Microsoft Office\Office\Excel8.olb
    • Excel 2000 (9.0):...Office\Excel9.olb
    • Excel 2002/2003 (10.0/11.0):...Office10/11\Excel.exe (內嵌類型庫)
  4. 勾選關鍵類:_Application、Workbooks、_Workbook、Worksheets、_Worksheet、Range。
  5. 生成的包裝類放入項目,如 CApplication、CWorkbooks 等。

二、核心代碼實現

1. 頭文件包含與成員變量


// Stdafx.h 或對話框頭文件
#include         // _variant_t, _bstr_t
#include "excel.h"         // 生成的包裝類頭文件

// 對話框類成員
CApplication m_excelApp;      // Excel.Application
CWorkbooks m_books;           // Workbooks 集合
CWorkbook m_book;             // 單個 Workbook
CWorksheets m_sheets;         // Worksheets 集合
CWorksheet m_sheet;           // 單個 Worksheet
CRange m_range;               // Range (單元格區域)

2. 初始化 COM 並啟動 Excel


BOOL CMyDlg::OnInitDialog() {
    CDialog::OnInitDialog();

    // 1. 初始化 COM 庫
    if (FAILED(::CoInitialize(NULL))) {
        AfxMessageBox(_T("COM 初始化失敗"));
        return FALSE;
    }

    // 2. 創建 Excel.Application 對象
    if (!m_excelApp.CreateDispatch(_T("Excel.Application"))) {
        AfxMessageBox(_T("無法啟動 Excel,請確認已安裝"));
        ::CoUninitialize();
        return FALSE;
    }

    // 3. 可選:顯示/隱藏 Excel 窗口
    m_excelApp.put_Visible(TRUE); // FALSE 後台運行

    // 4. 獲取 Workbooks 集合
    m_books.AttachDispatch(m_excelApp.GetWorkbooks(), TRUE);

    // 5. 打開或新建工作簿
    // 打開現有文件
    m_book.AttachDispatch(m_books.Add(_variant_t(_T("C:\\Report.xls"))), TRUE);
    // 或新建空白
    // m_book.AttachDispatch(m_books.Add(vtMissing), TRUE);

    // 6. 獲取工作表集合與第一張表
    m_sheets.AttachDispatch(m_book.GetWorksheets(), TRUE);
    m_sheet.AttachDispatch(m_sheets.GetItem(_variant_t(_T("Sheet1"))), TRUE);

    // 7. 獲取 Cells 範圍對象 (用於單元格讀寫)
    m_range.AttachDispatch(m_sheet.GetCells(), TRUE);

    return TRUE;
}

3. 讀寫單元格


// 寫入單元格 (行, 列 從 1 開始)
void WriteCell(long row, long col, const CString& value) {
    _variant_t vRow(row), vCol(col), vVal(value);
    m_range.SetItem(vRow, vCol, vVal);
}

// 讀取單元格
CString ReadCell(long row, long col) {
    _variant_t vRow(row), vCol(col);
    _variant_t result = m_range.GetItem(vRow, vCol);
    if (result.vt == VT_BSTR)
        return CString((LPCTSTR)(_bstr_t)result);
    else if (result.vt == VT_R8) // 數值
        return CString().Format(_T("%.2f"), result.dblVal);
    return _T("");
}

// 批量寫入範圍 (高效)
void WriteRange(long r1, long c1, long r2, long c2, const COleSafeArray& data) {
    CRange range;
    range.AttachDispatch(m_sheet.GetRange(
        _variant_t(_T("A1")), _variant_t(_T(""))), TRUE); // 需計算地址
    range.SetValue(_variant_t(data));
}

4. 關鍵類型轉換:_variant_t 與 _bstr_t

  • Excel COM 方法參數/返回值多為 VARIANT。
  • _variant_t 封裝 VARIANT,支持隱式構造/轉換。
  • _bstr_t 封裝 BSTR (COM 字符串),支持與 CString 互轉。
  • vtMissing (定義於 afxdisp.h) 表示可選參數省略。

5. 完整資源釋放與退出 (逆序!)


void CleanupExcel() {
    // 1. 釋放 Range
    if (m_range.m_lpDispatch) {
        m_range.ReleaseDispatch();
    }
    // 2. 釋放 Worksheet
    if (m_sheet.m_lpDispatch) {
        m_sheet.ReleaseDispatch();
    }
    // 3. 釋放 Worksheets 集合
    if (m_sheets.m_lpDispatch) {
        m_sheets.ReleaseDispatch();
    }
    // 4. 關閉並釋放 Workbook
    if (m_book.m_lpDispatch) {
        m_book.Close(COleVariant((short)FALSE), // 不保存修改
                     COleVariant((short)FALSE),
                     vtMissing);
        m_book.ReleaseDispatch();
    }
    // 5. 釋放 Workbooks 集合
    if (m_books.m_lpDispatch) {
        m_books.ReleaseDispatch(); // 無 Close 方法
    }
    // 6. 退出 Excel 應用程序
    if (m_excelApp.m_lpDispatch) {
        m_excelApp.Quit();         // 關鍵:否則進程殘留
        m_excelApp.ReleaseDispatch();
    }
    // 7. 反初始化 COM
    ::CoUninitialize();
}

⚠️ 必須調用 Quit(),否則 Excel 進程將在後台殘留 (任務管理器可見 EXCEL.EXE)。

三、常見問題與解決

問題原因解決
編譯錯誤:找不到 excel.h類型庫導入路徑錯誤ClassWizard 重新導入,確認生成路徑
運行時 "類未註冊"Excel 未安裝或版本不匹配檢查註冊表 HKCR\Excel.Application\CLSID
中文亂碼字符集不匹配項目設置 Unicode,用 _variant_t(CString) 自動轉 BSTR
寫入數值顯示為科學計數法單元格格式為常規設置 Range.NumberFormat = _T("@") (文本) 或 0.00
大量數據寫入極慢逐單元格 COM 呼叫開銷大用 SafeArray 批量寫入 Range.Value = array

四、完整示例:導出數據到 Excel


void CMyDlg::OnExportExcel() {
    // ... 初始化同上 ...

    // 寫入表頭
    WriteCell(1, 1, _T("ID"));
    WriteCell(1, 2, _T("Name"));
    WriteCell(1, 3, _T("Score"));

    // 模擬數據
    for (int i = 0; i < 100; i++) {
        WriteCell(i+2, 1, CString().Format(_T("%d"), i+1));
        WriteCell(i+2, 2, CString().Format(_T("User%d"), i+1));
        WriteCell(i+2, 3, CString().Format(_T("%.1f"), 60.0 + rand()%40));
    }

    // 保存並可選打開
    m_book.SaveAs(_variant_t(_T("C:\\Export.xls")), vtMissing, vtMissing, vtMissing,
                  vtMissing, vtMissing, 0, 1, vtMissing, vtMissing);
    AfxMessageBox(_T("導出完成!"));

    CleanupExcel();
}

總結

MFC 操作 Excel 核心是 COM 自動化:CoInitialize → CreateDispatch → 獲取層級對象 → _variant_t 讀寫 → 逆序 ReleaseDispatch → Quit → CoUninitialize。關鍵點:類型庫正確導入、_variant_t 類型轉換、必須調用 Quit() 避免進程殘留、大數據用 SafeArray 批量操作。掌握此模式,可構建強大的 Office 文檔自動化功能。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved