首页 > 代码库 > 使用MFC操作EXCEL文件

使用MFC操作EXCEL文件

一、加载

1、 在VC6.0里创建一个MFC工程

2、打开MFCClassWizard窗口(查看—>建立类向导),选择Automation,单击AddClass按钮,选择Froma type library...,弹出文件选择对话框,之后定位到C:\Program Files\MicrosoftOffice\OFFICE11\EXCEL.EXE,在生成类中添加所有的对象(其实添加需要的即可,为了简便,不出错保留了冗余),如下图。

 

技术分享

 

 

 

 
 


3、返回编辑器,查看工程文件,可发现多了EXCEL.9H及EXCEL9.CPP两个文件,拷贝出来,放在VS2005需要使用excel的工程文件中。

4. 打开stdafx.h头文件确保包含如下头文件:

#include <afxdisp.h>(这个一般有了)

#include "excel.h" (手动添加这个即可)

5. 打开TestExcel.cpp文件,修改CTestExcelApp::InitInstance(),加入如下代码:

if(!AfxOleInit() ){

AfxMessageBox("初始化Ole出错!");

return FALSE;

}

为保证编译时不产生重复定义错误(可以验证一下是否成功加载,没有也能正常执行),我编译时出现了很多“类重复定义”异常,打开excel.h文件,在文件开始位置加入如下代码:

#if !defined _HEAD_FILE_EXCEL9_

#define _HEAD_FILE_EXCEL9_

相应的,在文件末尾加入:

#endif

成功

 

Excel接口

导入类

头文件

说明

_Application

CApplicaton

Application.h

Excel应用程序。

Workbooks

CWorkbooks

Workbooks.h

工作簿的容器,里面包括了Excel应用程序打开的所有工作簿。

_Workbook

CWorkbook

Workbook.h

单个工作簿。

Worksheets

CWorksheets

Worksheets.h

单个工作簿中的Sheet表格的容器,包括该工作簿中的所有Sheet。

_Worksheet

CWorksheet

Worksheet.h

单个Sheet表格。

Range

CRange

Range.h

一定数量的单元格,可对单元格进行单个或多个单元格进行操作。

 

 

在MSDN中,很少有excel方面的资料,但是在http://msdn.microsoft.com/zh-cn/ms348103.aspx中可以找到C#控制EXCEL方面的说明

 

二、操作EXCEL文件

 

1. 新建一个excel表,并填充两个单元格的实例

 

[cpp] view plain copy
 
 技术分享技术分享
  1. void CTestExcelDlg::OnButton1()  
  2. {  
  3. //Workbooks—>Workbook —>Worksheets—>Worksheet —>Range  
  4. _Application app;       //Excel应用程序接口  
  5. Workbooks books;        //工作薄集合  
  6. _Workbook book;     //工作薄  
  7. Worksheets sheets;      //工作表集合  
  8. _Worksheet sheet;       //工作表  
  9. Range range;            //Excel中针对单元格的操作都应先获取其对应的Range对象  
  10. Font font;  
  11. Range cols;  
  12. /* 
  13. COleVariant类为VARIANT数据类型的包装,在自动化程序中,通常都使用 
  14. VARIANT数据类型进行参数传递。故下列程序中,函数参数都是通过COleVariant 
  15. 类来转换了的。 
  16. */  
  17. //covOptional 可选参数的VARIANT类型  
  18. COleVariant covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR);  
  19. if( !app.CreateDispatch("Excel.Application") ){  
  20. this->MessageBox("无法创建Excel应用!");  
  21. return;  
  22. }  
  23. //获取工作薄集合  
  24. books=app.GetWorkbooks();  
  25. //添加一个工作薄  
  26. book=books.Add(covOptional);  
  27. //获取工作表集合  
  28. sheets=book.GetSheets();  
  29. //获取第一个工作表  
  30. sheet=sheets.GetItem(COleVariant((short)1));  
  31. //选择工作表中A1:A1单元格区域  
  32. range=sheet.GetRange(COleVariant("A1"),COleVariant("A1"));  
  33. //设置A1=HELLO EXCEL!"  
  34. range.SetValue(COleVariant("HELLO EXCEL!"));  
  35. //调整格式,设置粗体  
  36. font=range.GetFont();  
  37. font.SetBold(COleVariant((short)TRUE));  
  38. //选择A2单元格,插入一个公式"=RAND()*100000",并设置A2数字格式为货币形  
  39. 式  
  40. range=sheet.GetRange(COleVariant("A2"),COleVariant("A2"));  
  41. range.SetFormula(COleVariant("=RAND()*100000"));  
  42. range.SetNumberFormat(COleVariant("$0.00"));  
  43. //选择A:A列,设置宽度为自动适应  
  44. cols=range.GetEntireColumn();  
  45. cols.AutoFit();  
  46. //显示Excel表格,并设置状态为用户可控制  
  47. app.SetVisible(TRUE);  
  48. app.SetUserControl(TRUE);  

 

 

2. 打开一个已有的excel表格实例

[cpp] view plain copy
 
 技术分享技术分享
  1. CString strPath;   
  2. strPath += "C:\\template.xlt"; // 模板的路径   
  3. CFileFind filefind;   
  4. if( !filefind.FindFile( strPath ) )   
  5. {   
  6. AfxMessageBox( "没有找到模版文档,请其查找" );   
  7.     return;  
  8. }   
  9. LPDISPATCH lpDisp;  //接口指针  
  10. books=app.GetWorkbooks();  
  11. lpDisp = books.Open(m_filepath,  
  12.     covOptional, covOptional, covOptional, covOptional,  
  13.     covOptional, covOptional, covOptional, covOptional,  
  14.     covOptional, covOptional, covOptional, covOptional,  
  15.     covOptional, covOptional  
  16.     );                  //与的不同,是个参数的,直接在后面加了两个covOptional成功了  
  17. book.AttachDispatch(lpDisp);  

 

3. 保存一个excel文件实例

 

[cpp] view plain copy
 
 技术分享技术分享
  1. book.SetSaved(TRUE);  

 

 

4. 另存一个excel文件实例

[cpp] view plain copy
 
 技术分享技术分享
  1. book.SaveAs(COleVariant(m_filename),covOptional,  
  2.     covOptional,covOptional,  
  3.     covOptional,covOptional,(long)0,  
  4. covOptional,covOptional,covOptional,  
  5. covOptional,covOptional); //与的不同,是个参数的,直接在后面加了两个covOptional成功了  

 

5. 释放一个excel文件实例

经试验证实,不释放第二次使用excel时会中断,放在类的析构里面有时调用不到,主动调用最保险。(有没有AttachDispatch()过都要释放,否则报错)

[cpp] view plain copy
 
 技术分享技术分享
  1. //释放对象(相当重要!)   
  2. Rang.ReleaseDispatch();   
  3. sheet.ReleaseDispatch();   
  4. sheets.ReleaseDispatch();   
  5. book.ReleaseDispatch();   
  6. books.ReleaseDispatch();   
  7. //退出程序   
  8. app.Quit();  
  9. //m_ExlApp一定要释放,否则程序结束后还会有一个Excel进程驻留在内存中,而且程序重复运行的时候会出错   
  10. app.ReleaseDispatch();   

 

6. 修改一个excel单元格

[cpp] view plain copy
 
 技术分享技术分享
  1. range=sheet.GetRange(COleVariant(IndexToString(row,col)),COleVariant(IndexToString(row,col)));  
  2. range.SetValue2(COleVariant(value));  

 

7. 取出一个excel单元格

实现Variant数据类型转换为CString类,这个只是一个示例,转换较为简单。

[cpp] view plain copy
 
 技术分享技术分享
  1. range=sheet.GetRange(COleVariant(IndexToString(row,col)),COleVariant(IndexToString(row,col)));  
  2. COleVariant rValue;  
  3. rValue=http://www.mamicode.com/COleVariant(range.GetValue2());
  4. rValue.ChangeType(VT_BSTR);  
  5. return CString(rValue.bstrVal);  

 

8. 还有释放问题是最重要的问题:

   首先变量必须全释放,无论当初是否绑定过;

   其次,程序释放和程序关闭的顺序必须是

[cpp] view plain copy
 
 技术分享技术分享
  1. app.Quit();  
  2. app.ReleaseDispatch();  
  3. 如果顺如颠倒如下:  
  4. app.ReleaseDispatch();  
  5. app.Quit();  
  6. 出现的后果是程序关闭后,excel进程仍然运行,所以无法正常打开程序曾经打开excel表格。  

 

附录(操作类源码):

 

[cpp] view plain copy
 
 技术分享技术分享
    1. #include "../Stdafx.h"  
    2. #include "OptExcel.h"  
    3. #include "excel.h"  
    4. #include "comdef.h"  
    5.          
    6.   
    7. _Application app;  
    8. Workbooks books;  
    9. _Workbook book;  
    10. Worksheets sheets;  
    11. _Worksheet sheet;  
    12. Range range;  
    13. Range cell;  
    14. Font font;  
    15.   
    16. COleVariant covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR);  
    17.   
    18.   
    19. ////////////////////////////////////////////////////////////////////////  
    20. ///Function:    COptExcel  
    21. ///Description: 初始化函数,初始化中附加excel应用程序  
    22. ///Call:        app.CreateDispatch(_T("Excel.Application")  
    23. ////////////////////////////////////////////////////////////////////////  
    24. COptExcel::COptExcel(void)  
    25. {  
    26.     if (::CoInitialize( NULL ) == E_INVALIDARG)   
    27.     {   
    28.         AfxMessageBox(_T("初始化Com失败!"));   
    29.         return;  
    30.     }  
    31.   
    32.     //验证office文件是否可以正确运行  
    33.   
    34.     if( !app.CreateDispatch(_T("Excel.Application")) )  
    35.     {  
    36.         AfxMessageBox(_T("无法创建Excel应用!"));  
    37.         return;  
    38.     }  
    39.     //在程序执行文件路径名中,剪掉执行文件名,得到程序路径,追加模板文件名,得到模板完整路径  
    40.       
    41.   
    42. }  
    43.   
    44.   
    45. ////////////////////////////////////////////////////////////////////////  
    46. ///Function:    ~COptExcel  
    47. ///Description: 析构函数,释放对象,非常重要,不全部释放,占用内存,下  
    48. ///             一次使用此类时会中断  
    49. ///Call:        ReleaseDispatch()  
    50. ////////////////////////////////////////////////////////////////////////  
    51. COptExcel::~COptExcel(void)  
    52. {  
    53.       
    54.   
    55.       
    56.     books.ReleaseDispatch();  
    57.     book.ReleaseDispatch();  
    58.     sheets.ReleaseDispatch();  
    59.     sheet.ReleaseDispatch();  
    60.     range.ReleaseDispatch();  
    61.     font.ReleaseDispatch();  
    62.     cell.ReleaseDispatch();  
    63.   
    64.     app.Quit();  
    65.   
    66.     app.ReleaseDispatch();  
    67.     ::CoUninitialize();  
    68. }  
    69.   
    70.   
    71. ////////////////////////////////////////////////////////////////////////  
    72. ///Function:    OpenExcelBook  
    73. ///Description: 打开表名为filename的文件,注意,文件路径非自动生成,以后  
    74. ///             考虑从下处理方法  
    75. ///Call:        GetAppPath()  
    76. ///Input:       CString filename 文件名  
    77. ////////////////////////////////////////////////////////////////////////  
    78. bool COptExcel::OpenExcelBook(CString filename)  
    79. {  
    80.     CFileFind filefind;   
    81.     if( !filefind.FindFile(filename) )   
    82.     {   
    83.         AfxMessageBox(_T("文件不存在"));  
    84.         return false;  
    85.     }  
    86.     LPDISPATCH lpDisp; //接口指针  
    87.     books=app.GetWorkbooks();  
    88.     lpDisp = books.Open(filename,  
    89.         covOptional, covOptional, covOptional, covOptional,  
    90.         covOptional, covOptional, covOptional, covOptional,  
    91.         covOptional, covOptional, covOptional, covOptional,  
    92.         covOptional, covOptional  
    93.         );                                      //与office 2000的不同,是个参数的,直接在后面加了两个covOptional成功了  
    94.     book.AttachDispatch(lpDisp);  
    95.     sheets=book.GetSheets();  
    96.     sheet=sheets.GetItem(COleVariant((short)1));        //与的不同,是个参数的,直接在后面加了两个covOptional成功了  
    97.     return true;  
    98. }  
    99. void COptExcel::NewExcelBook()  
    100. {  
    101.     books=app.GetWorkbooks();  
    102.     book=books.Add(covOptional);  
    103.     sheets=book.GetSheets();  
    104.     sheet=sheets.GetItem(COleVariant((short)1));        //与的不同,是个参数的,直接在后面加了两个covOptional成功了  
    105. }  
    106.   
    107. ////////////////////////////////////////////////////////////////////////  
    108. ///Function:    OpenExcelApp  
    109. ///Description: 打开应用程序(要注意以后如何识别用户要打开的是哪个文件)  
    110. ////////////////////////////////////////////////////////////////////////  
    111. void COptExcel::OpenExcelApp(void)  
    112. {  
    113.     app.SetVisible(TRUE);  
    114.     app.SetUserControl(TRUE);  
    115. }  
    116.   
    117. ////////////////////////////////////////////////////////////////////////  
    118. ///Function:    SaveExcel  
    119. ///Description: 用于打开数据文件,续存数据后直接保存  
    120. ////////////////////////////////////////////////////////////////////////  
    121. void COptExcel::SaveExcel(void)  
    122. {  
    123.     book.SetSaved(TRUE);  
    124. }  
    125.   
    126. ////////////////////////////////////////////////////////////////////////  
    127. ///Function:    SaveAsExcel  
    128. ///Description: 保存excel文件  
    129. ////////////////////////////////////////////////////////////////////////  
    130. void COptExcel::SaveAsExcel(CString filename)  
    131. {  
    132.     book.SaveAs(COleVariant(filename),covOptional,  
    133.     covOptional,covOptional,  
    134.     covOptional,covOptional,(long)0,covOptional,covOptional,covOptional,  
    135.     covOptional,covOptional);                     
    136. }  
    137.   
    138.   
    139. ////////////////////////////////////////////////////////////////////////  
    140. ///Function:    SetCellValue  
    141. ///Description: 修改单元格内的值  
    142. ///Call:        IndexToString() 从(x,y)坐标形式转化为“A1”格式字符串  
    143. ///Input:       int row 单元格所在行  
    144. ///             int col 单元格所在列  
    145. ///             int Align       对齐方式默认为居中  
    146. ////////////////////////////////////////////////////////////////////////  
    147. void COptExcel::SetCellValue(int row, int col,int Align)  
    148. {  
    149.     range=sheet.GetRange(COleVariant(IndexToString(row,col)),COleVariant(IndexToString(row,col)));  
    150.     range.SetValue2(COleVariant(value));  
    151.     cell.AttachDispatch((range.GetItem (COleVariant(long(1)), COleVariant(long(1)))).pdispVal);  
    152.     cell.SetHorizontalAlignment(COleVariant((short)Align));  
    153. }  
    154.   
    155. ////////////////////////////////////////////////////////////////////////  
    156. ///Function:    GetCellValue  
    157. ///Description: 得到的单元格中的值  
    158. ///Call:        IndexToString() 从(x,y)坐标形式转化为“A1”格式字符串  
    159. ///Input:       int row 单元格所在行  
    160. ///             int col 单元格所在列  
    161. ///Return:      CString 单元格中的值  
    162. ////////////////////////////////////////////////////////////////////////  
    163. CString COptExcel::GetCellValue(int row, int col)  
    164. {  
    165.     range=sheet.GetRange(COleVariant(IndexToString(row,col)),COleVariant(IndexToString(row,col)));  
    166.     COleVariant rValue;  
    167.     rValue=http://www.mamicode.com/COleVariant(range.GetValue2());
    168.     rValue.ChangeType(VT_BSTR);  
    169.     return CString(rValue.bstrVal);  
    170. }  
    171. ////////////////////////////////////////////////////////////////////////  
    172. ///Function:    SetRowHeight  
    173. ///Description: 设置行高  
    174. ///Call:        IndexToString() 从(x,y)坐标形式转化为“A1”格式字符串  
    175. ///Input:       int row 单元格所在行  
    176. ////////////////////////////////////////////////////////////////////////  
    177. void COptExcel::SetRowHeight(int row, CString height)  
    178. {  
    179.     int col = 1;  
    180.     range=sheet.GetRange(COleVariant(IndexToString(row,col)),COleVariant(IndexToString(row,col)));  
    181.     range.SetRowHeight(COleVariant(height));  
    182. }  
    183. ////////////////////////////////////////////////////////////////////////  
    184. ///Function:    SetColumnWidth  
    185. ///Description: 设置列宽  
    186. ///Call:        IndexToString() 从(x,y)坐标形式转化为“A1”格式字符串  
    187. ///Input:       int col 要设置列宽的列  
    188. ///             CString 宽值  
    189. ////////////////////////////////////////////////////////////////////////  
    190. void COptExcel::SetColumnWidth(int col,CString width)  
    191. {  
    192.     int row = 1;  
    193.     range=sheet.GetRange(COleVariant(IndexToString(row,col)),COleVariant(IndexToString(row,col)));  
    194.     range.SetColumnWidth(COleVariant(width));  
    195. }  
    196.   
    197. ////////////////////////////////////////////////////////////////////////  
    198. ///Function:    SetRowHeight  
    199. ///Description: 设置行高  
    200. ///Call:        IndexToString() 从(x,y)坐标形式转化为“A1”格式字符串  
    201. ///Input:       int row 单元格所在行  
    202. ////////////////////////////////////////////////////////////////////////  
    203. CString COptExcel::GetColumnWidth(int col)  
    204. {  
    205.     int row = 1;  
    206.     range=sheet.GetRange(COleVariant(IndexToString(row,col)),COleVariant(IndexToString(row,col)));  
    207.     VARIANT width = range.GetColumnWidth();  
    208.     CString strwidth;  
    209.     strwidth.Format(CString((LPCSTR)(_bstr_t)(_variant_t)width));  
    210.     return strwidth;  
    211. }  
    212.   
    213. ////////////////////////////////////////////////////////////////////////  
    214. ///Function:    GetRowHeight  
    215. ///Description: 设置行高  
    216. ///Call:        IndexToString() 从(x,y)坐标形式转化为“A1”格式字符串  
    217. ///Input:       int row 要设置行高的行  
    218. ///             CString 宽值  
    219. ////////////////////////////////////////////////////////////////////////  
    220. CString COptExcel::GetRowHeight(int row)  
    221. {  
    222.     int col = 1;  
    223.     range=sheet.GetRange(COleVariant(IndexToString(row,col)),COleVariant(IndexToString(row,col)));  
    224.     VARIANT height = range.GetRowHeight();  
    225.     CString strheight;  
    226.     strheight.Format(CString((LPCSTR)(_bstr_t)(_variant_t)height));  
    227.     return strheight;  
    228. }  
    229.   
    230.   
    231. ////////////////////////////////////////////////////////////////////////  
    232. ///Function:    IndexToString  
    233. ///Description: 得到的单元格在EXCEL中的定位名称字符串  
    234. ///Input:       int row 单元格所在行  
    235. ///             int col 单元格所在列  
    236. ///Return:      CString 单元格在EXCEL中的定位名称字符串  
    237. ////////////////////////////////////////////////////////////////////////  
    238. CString COptExcel::IndexToString( int row, int col )   
    239. {   
    240.     CString strResult;  
    241.     if( col > 26 )   
    242.     {   
    243.         strResult.Format(_T("%c%c%d"),‘A‘ + (col-1)/26-1,‘A‘ + (col-1)%26,row);  
    244.     }   
    245.     else   
    246.     {   
    247.         strResult.Format(_T("%c%d"), ‘A‘ + (col-1)%26,row);  
    248.     }   
    249.     return strResult;  
    250. }   
    251.   
    252. ////////////////////////////////////////////////////////////////////////  
    253. ///Function:    LastLineIndex  
    254. ///Description: 得到表格总第一个空行的索引  
    255. ///Return:      int 空行的索引号  
    256. ////////////////////////////////////////////////////////////////////////  
    257. int COptExcel::LastLineIndex()   
    258. {   
    259.     int i,j,flag=0;  
    260.     CString str;  
    261.     for(i=1;;i++)  
    262.     {  
    263.         flag = 0;  
    264.         //粗略统计,认为前列都没有数据即为空行  
    265.         for(j=1;j<=5;j++)  
    266.         {  
    267.             str.Format(_T("%s"),this->GetCellValue(i,j).Trim());  
    268.             if(str.Compare(_T(""))!=0)  
    269.             {  
    270.                 flag = 1;  
    271.                 break;  
    272.             }  
    273.               
    274.         }  
    275.         if(flag==0)  
    276.             return i;  
    277.           
    278.     }  
    279. }  
    280.    

使用MFC操作EXCEL文件