摘要:使用Microsoft Office所帶的控件來實作代碼操作excel表格。
開發環境:作業系統是Microsoft Windows7 32bit,Office辦公套裝是Microsoft Office 2003,程式設計環境是Microsoft Visual Studio 6.0。
使用背景:我最近有個項目中要生成報表,是将資料庫中的發證資料查詢出來導出到Excel表格中以便列印,是以上網找了這方面的内容,具體内容如下,如錯誤還請指證。
從平常我們操作一般檔案上來看,無非是打開檔案,操作檔案(讀取,寫入),然後關閉打開的檔案。 操作Excel也就是和操作普通檔案将其打開,然後寫入/讀出資料,然後關閉等操作哦。以下是個例子程式:
操作Excel具體如下:因為Excel格式是微軟固有的私有格式,如果我想自己操作Excel是完全不可能,是以隻有通過微軟給我們COM元件接口來操作。這些COM類型清單如下:
《VC++/MFC操作Office必需的類型庫參考》
說明:如果需要在VC++/MFC開發程式操作word/excel等office元素,那麼需要對必要的類型庫進行導入.下面是office系列的類型庫參考,導入類型庫時候請選擇正确的類型庫進行導入.
應用程式 | 類型庫 |
Microsoft Access 97 | Msacc8.olb |
Microsoft Jet Database 3.5 | DAO350.dll |
Microsoft Binder 97 | Msbdr8.olb |
Microsoft Excel 97 | Excel8.olb |
Microsoft Graph 97 | Graph8.olb |
Microsoft Office 97 | Mso97.dll |
Microsoft Outlook 97 | Msoutl97.olb |
Microsoft PowerPoint 97 | Msppt8.olb |
Microsoft Word 97 | Msword8.olb |
Microsoft Access 2000 | Msacc9.olb |
Microsoft Jet Database 3.51 | DAO360.dll |
Microsoft Binder 2000 | Msbdr9.olb |
Microsoft Excel 2000 | Excel9.olb |
Microsoft Graph 2000 | Graph9.olb |
Microsoft Office 2000 | Mso9.dll |
Microsoft Outlook 2000 | Msoutl9.olb |
Microsoft PowerPoint 2000 | Msppt9.olb |
Microsoft Word 2000 | Msword9.olb |
Microsoft Access 2002 | Msacc.olb |
Microsoft Excel 2002 | Excel.exe |
Microsoft Graph 2002 | Graph.exe |
Microsoft Office 2002 | MSO.dll |
Microsoft Outlook 2002 | MSOutl.olb |
Microsoft PowerPoint 2002 | MSPpt.olb |
Microsoft Word 2002 | MSWord.olb |
Microsoft Office Access 2003 | Msacc.olb |
Microsoft Office Excel 2003 | Excel.exe |
Microsoft Office Graph 2003 | Graph.exe |
Microsoft Office 2003 | MSO.dll |
Microsoft Office Outlook 2003 | MSOutl.olb |
Microsoft Office PowerPoint 2003 | MSPpt.olb |
Microsoft Office Word 2003 | MSWord.olb |
注意:這些類型庫的預設位置是:
Office 版本 | 路徑 |
Office 97 | C:/Program Files/Microsoft Office/Office |
Office 2000 | C:/Program Files/Microsoft Office/Office |
Office XP | C:/Program Files/Microsoft Office/Office10 |
Office 2003 | C:/Program Files/Microsoft Office/Office11 |
下面是例子的使用:
首先建立一個程式(我的例子是一個MFC的單文檔程式),在程式的入口處和出口處先作初始化COM庫,來加載我們需要COM的支援:
在程式入口處CXXXApp:: InitInstance()函數AfxEnableControlContainer();語句之後加入下面幾行:
if (CoInitialize(NULL) != 0)
{
AfxMessageBox(“初始化COM支援庫失敗!”);
exit(1);
}
假如這個條件不通過就不能運作起程式。
在程式的退出釋放資源處,也就是與初始化對應的地方:CXXXApp:: ExitInstance()函數return語句之前加入下面這句話:
CoUninitialize(); //來釋放COM支援庫。
{
CoUninitialize();
}
這樣我們就完成了對COM支援庫的代碼已經完成。
下面要從Office的安裝目錄中找到對VC操作excel檔案的動态庫,在某些版本下這個檔案是Excel8.olb或者Excel9.olb,在我的版本中是excel.exe這個exe也是動态庫的形式,是微軟公司主要的檔案結果之一。
(和使用普通的COM元件一樣)選擇VC++的View菜單裡面的ClassWizad指令,會彈出一個對話框;然後點選Add Class…按鈕選擇From a type library,會彈出一個打開對話框,從這裡打開Office安裝目錄下…/Office11/EXCEL.EXE檔案,從裡面選擇幾個要用到的類:_Application, Workbooks, _Wrokbook, Worksheets, _WorkSheet, Range,點選OK按鈕。會在程式中生成一個excel.h和excel.cpp檔案,這些檔案中包含了剛才我們選擇的幾個類的代碼。下面介紹一下這幾個類:
在VC++操縱Excel的exe動态庫裡面有好多個對象模型,就是剛才在建立過程中看到的那個清單,但是經常用到的有這麼幾個:_Application, Workbooks, _Wrokbook, Worksheets, _WorkSheet, Range,Charts和_Chart,最後面的兩個是用來操作圖表的,我沒有用到是以這裡也就不記錄了。
(a)._Application:這裡的Application就是Excel本身,衆所周知,一個Excel可以包含多個工作簿,每個工作簿又可以包含多個工作表,而每個工作表又可以包含多個區域或者圖表,是以這裡他們是樹型的結構關系,而application最基本的一個功能就是找到它的子項工作簿。果然,我們在引入我們程式的Application類中看到了這樣的成員函數:GetWorkbooks()。既然application就是excel,那麼打開程式,退出程式,顯示/隐藏程式這些基本的操作都可以在這個類的成員函數中找到,果不其然。
(b).Workbooks:這個對象是一個容器對象,它裡面存放着所有打開的工作簿。是以,我們可以猜測它一定有添加,查找,打開/關閉工作簿的功能。(本程式中使用excel的一個xlt模闆來生成一個xls檔案就是使用了這個容器對象的添加功能。)
(c)._Workbook:這是一個工作簿,也就相當于一個xls檔案。Excel可以同時打開多個工作簿,是以工作簿之間必定能夠互相切換,每個工作簿可以關聯工作表容器并獲得工作表的索引。
(d).Worksheets:也是一個容器對象,和Workbooks類似。
(e)._Worksheet:這個就是我們看到的工作表,比如Sheet1,sheet2等等。
(f).Rang:就是我們看到的能選中的方框的大小。而我們所要作的操作基本上是以區域為機關進行的。
介紹完這些,我們就來看看一個例子程式吧,就是使用使用微軟給我們提供的元件來操作Excel
<span style="white-space:pre"> </span>_Application _app;
_Workbook _workBook;
_Worksheet _workSheet;
Worksheets workSheets;
Workbooks workBooks;
Range range;
Range copyFrom;
Range copyTo;
if(!_app.CreateDispatch("Excel.Application", NULL))
{
MessageBox("建立Excel服務失敗!", "資訊提示", MB_OK);
return;
}
//利用模闆建立新文檔
workBooks.AttachDispatch(_app.GetWorkbooks());
_workBook.AttachDispatch(workBooks.Add(_variant_t(vFileName)));//你可以自己建立一個模闆,并自由設定目錄
//得到worksheets
workSheets.AttachDispatch(_workBook.GetWorksheets());
//得到workSheet
_workSheet.AttachDispatch(workSheets.GetItem(_variant_t("sheet1")));
//得到拷貝的主機闆
copyFrom.AttachDispatch(_workSheet.GetRange(_variant_t("A3"), _variant_t("Q6")));
copyTo.AttachDispatch(_workSheet.GetRange(_variant_t("A61"), _variant_t("A61")));
//得到全部的cells
range.AttachDispatch(_workSheet.GetCells());
///
// 上邊是頭
/*
中間要做的工作有這兩項:設定資料和拷貝格式
設定資料就是将資料庫中查詢出來的資料寫入表格,拷貝格式就是将表格拷貝到别的地方。
*/
//寫入資料
range.SetItem(_variant_t((long)3), _variant_t((long)1), _variant_t("寫入資料了"));
range.SetItem(_variant_t((long)5), _variant_t((long)1), _variant_t("重新寫入資料了"));
//拷貝一段區域到另外的一段區域
copyFrom.Copy(_variant_t(copyTo));
range.SetItem(_variant_t((long)61), _variant_t((long)1), _variant_t("123"));
//顯示excel表格
_app.SetVisible(TRUE);
//儲存為檔案
_app.SetDisplayAlerts(FALSE); //隐藏彈出的對話框
_workSheet.SaveAs("d://Test.xls",vtMissing,vtMissing,vtMissing,vtMissing,
vtMissing,vtMissing,vtMissing,vtMissing,vtMissing);
_app.Quit();
//下邊是尾
///
copyFrom.ReleaseDispatch();
copyTo.ReleaseDispatch();
range.ReleaseDispatch();
_workSheet.ReleaseDispatch();
workSheets.ReleaseDispatch();
_workBook.ReleaseDispatch();
workSheets.ReleaseDispatch();
_app.ReleaseDispatch();
<span style="white-space:pre"> </span>}
其它:下面是網上一個人封裝的一個類大家可以參考一下(當然不如BasicExcel了哈哈,下期講這個類哈)
<span style="white-space:pre"> </span>.h檔案:
<span style="white-space:pre"> </span>#include "comdef.h"
<span style="white-space:pre"> </span>#include "excel.h"
<span style="white-space:pre"> </span>class ExcelFile
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>public:
<span style="white-space:pre"> </span>void ShowInExcel(bool bShow);
<span style="white-space:pre"> </span>CString GetCell(int iRow, int iColumn);
<span style="white-space:pre"> </span>int GetCellInt(int iRow, int iColumn);
<span style="white-space:pre"> </span>int GetRowCount();
<span style="white-space:pre"> </span>int GetColumnCount();
<span style="white-space:pre"> </span>bool LoadSheet(int iIndex);
<span style="white-space:pre"> </span>CString GetSheetName(int iIndex);
<span style="white-space:pre"> </span>static void InitExcel();
<span style="white-space:pre"> </span>static void ReleaseExcel();
<span style="white-space:pre"> </span>int GetSheetCount();
<span style="white-space:pre"> </span>bool Open(CString FileName);
<span style="white-space:pre"> </span>ExcelFile();
<span style="white-space:pre"> </span>virtual ~ExcelFile();
<span style="white-space:pre"> </span>protected:
<span style="white-space:pre"> </span>private:
<span style="white-space:pre"> </span>static _Application m_ExcelApp;
<span style="white-space:pre"> </span>Workbooks m_Books;
<span style="white-space:pre"> </span>_Workbook m_Book;
<span style="white-space:pre"> </span>Worksheets m_sheets;
<span style="white-space:pre"> </span>_Worksheet m_sheet;
<span style="white-space:pre"> </span>Range m_Rge;
<span style="white-space:pre"> </span>};
<span style="white-space:pre"> </span>.cpp檔案:
<span style="white-space:pre"> </span>ExcelFile::ExcelFile()
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>ExcelFile::~ExcelFile()
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>m_Rge.ReleaseDispatch();
<span style="white-space:pre"> </span>m_sheet.ReleaseDispatch();
<span style="white-space:pre"> </span>m_sheets.ReleaseDispatch();
<span style="white-space:pre"> </span>m_Book.ReleaseDispatch();
<span style="white-space:pre"> </span>m_Books.ReleaseDispatch();
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>void ExcelFile::InitExcel()
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>//建立Excel 2000伺服器(啟動Excel)
<span style="white-space:pre"> </span>if (!m_ExcelApp.CreateDispatch("Excel.Application",NULL))
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>AfxMessageBox("建立Excel服務失敗!");
<span style="white-space:pre"> </span>exit(1);
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>void ExcelFile::ReleaseExcel()
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>m_ExcelApp.ReleaseDispatch();
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>bool ExcelFile::Open(CString FileName)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>//打開excel檔案
<span style="white-space:pre"> </span>//利用模闆檔案建立新文檔
<span style="white-space:pre"> </span>m_Books.AttachDispatch(m_ExcelApp.GetWorkbooks(),true);
<span style="white-space:pre"> </span>LPDISPATCH lpDis = NULL;
<span style="white-space:pre"> </span>lpDis = m_Books.Add(_variant_t(FileName)); // 如何判斷檔案是否打開?
<span style="white-space:pre"> </span>if (lpDis)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>m_Book.AttachDispatch(lpDis);
<span style="white-space:pre"> </span>//得到Worksheets
<span style="white-space:pre"> </span>m_sheets.AttachDispatch(m_Book.GetWorksheets(),true);
<span style="white-space:pre"> </span>return true;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>return false;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>int ExcelFile::GetSheetCount()
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>return m_sheets.GetCount();
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>CString ExcelFile::GetSheetName(int iIndex)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>_Worksheet sheet;
<span style="white-space:pre"> </span>sheet.AttachDispatch(m_sheets.GetItem(_variant_t((long)iIndex)),true);
<span style="white-space:pre"> </span>CString name = sheet.GetName();
<span style="white-space:pre"> </span>sheet.ReleaseDispatch();
<span style="white-space:pre"> </span>return name;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>bool ExcelFile::LoadSheet(int iIndex)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>LPDISPATCH lpDis = NULL;
<span style="white-space:pre"> </span>m_Rge.ReleaseDispatch();
<span style="white-space:pre"> </span>m_sheet.ReleaseDispatch();
<span style="white-space:pre"> </span>lpDis = m_sheets.GetItem(_variant_t((long)iIndex));
<span style="white-space:pre"> </span>if (lpDis)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>m_sheet.AttachDispatch(lpDis,true);
<span style="white-space:pre"> </span>m_Rge.AttachDispatch(m_sheet.GetCells(), true);
<span style="white-space:pre"> </span>return true;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>return false;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>int ExcelFile::GetColumnCount()
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>Range range;
<span style="white-space:pre"> </span>Range usedRange;
<span style="white-space:pre"> </span>usedRange.AttachDispatch(m_sheet.GetUsedRange(), true);
<span style="white-space:pre"> </span>range.AttachDispatch(usedRange.GetColumns(), true);
<span style="white-space:pre"> </span>int count = range.GetCount();
<span style="white-space:pre"> </span>usedRange.ReleaseDispatch();
<span style="white-space:pre"> </span>range.ReleaseDispatch();
<span style="white-space:pre"> </span>return count;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>int ExcelFile::GetRowCount()
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>Range range;
<span style="white-space:pre"> </span>Range usedRange;
<span style="white-space:pre"> </span>usedRange.AttachDispatch(m_sheet.GetUsedRange(), true);
<span style="white-space:pre"> </span>range.AttachDispatch(usedRange.GetRows(), true);
<span style="white-space:pre"> </span>int count = range.GetCount();
<span style="white-space:pre"> </span>usedRange.ReleaseDispatch();
<span style="white-space:pre"> </span>range.ReleaseDispatch();
<span style="white-space:pre"> </span>return count;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>CString ExcelFile::GetCell(int iRow, int iColumn)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>Range range;
<span style="white-space:pre"> </span>range.AttachDispatch(m_Rge.GetItem (COleVariant((long)iRow),COleVariant((long)iColumn)).pdispVal, true);
<span style="white-space:pre"> </span>COleVariant vResult =range.GetValue2();
<span style="white-space:pre"> </span>CString str;
<span style="white-space:pre"> </span>if(vResult.vt == VT_BSTR) //字元串
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>str=vResult.bstrVal;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>else if (vResult.vt==VT_INT)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>str.Format("%d",vResult.pintVal);
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>else if (vResult.vt==VT_R8) //8位元組的數字
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>str.Format("%f",vResult.dblVal);
<span style="white-space:pre"> </span>//str.Format("%.0f",vResult.dblVal);
<span style="white-space:pre"> </span>//str.Format("%1f",vResult.fltVal);
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>else if(vResult.vt==VT_DATE) //時間格式
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>SYSTEMTIME st;
<span style="white-space:pre"> </span>VariantTimeToSystemTime(vResult.date, &st);
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>else if(vResult.vt==VT_EMPTY) //單元格空的
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>str="(NULL)";
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>range.ReleaseDispatch();
<span style="white-space:pre"> </span>return str;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>int ExcelFile::GetCellInt(int iRow, int iColumn)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>Range range;
<span style="white-space:pre"> </span>range.AttachDispatch(m_Rge.GetItem(COleVariant((long)iRow),COleVariant((long)iColumn)).pdispVal, true);
<span style="white-space:pre"> </span>COleVariant vResult =range.GetValue2();
<span style="white-space:pre"> </span>int num;
<span style="white-space:pre"> </span>num = (int)vResult.date;
<span style="white-space:pre"> </span>range.ReleaseDispatch();
<span style="white-space:pre"> </span>return num;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>void ExcelFile::ShowInExcel(bool bShow)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>m_ExcelApp.SetVisible(bShow);
<span style="white-space:pre"> </span>}