使用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表,并填充两个单元格的实例
- void CTestExcelDlg::OnButton1()
- {
- //Workbooks—>Workbook —>Worksheets—>Worksheet —>Range
- _Application app; //Excel应用程序接口
- Workbooks books; //工作薄集合
- _Workbook book; //工作薄
- Worksheets sheets; //工作表集合
- _Worksheet sheet; //工作表
- Range range; //Excel中针对单元格的操作都应先获取其对应的Range对象
- Font font;
- Range cols;
- /*
- COleVariant类为VARIANT数据类型的包装,在自动化程序中,通常都使用
- VARIANT数据类型进行参数传递。故下列程序中,函数参数都是通过COleVariant
- 类来转换了的。
- */
- //covOptional 可选参数的VARIANT类型
- COleVariant covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR);
- if( !app.CreateDispatch("Excel.Application") ){
- this->MessageBox("无法创建Excel应用!");
- return;
- }
- //获取工作薄集合
- books=app.GetWorkbooks();
- //添加一个工作薄
- book=books.Add(covOptional);
- //获取工作表集合
- sheets=book.GetSheets();
- //获取第一个工作表
- sheet=sheets.GetItem(COleVariant((short)1));
- //选择工作表中A1:A1单元格区域
- range=sheet.GetRange(COleVariant("A1"),COleVariant("A1"));
- //设置A1=HELLO EXCEL!"
- range.SetValue(COleVariant("HELLO EXCEL!"));
- //调整格式,设置粗体
- font=range.GetFont();
- font.SetBold(COleVariant((short)TRUE));
- //选择A2单元格,插入一个公式"=RAND()*100000",并设置A2数字格式为货币形
- 式
- range=sheet.GetRange(COleVariant("A2"),COleVariant("A2"));
- range.SetFormula(COleVariant("=RAND()*100000"));
- range.SetNumberFormat(COleVariant("$0.00"));
- //选择A:A列,设置宽度为自动适应
- cols=range.GetEntireColumn();
- cols.AutoFit();
- //显示Excel表格,并设置状态为用户可控制
- app.SetVisible(TRUE);
- app.SetUserControl(TRUE);
2. 打开一个已有的excel表格实例
- CString strPath;
- strPath += "C:\\template.xlt"; // 模板的路径
- CFileFind filefind;
- if( !filefind.FindFile( strPath ) )
- {
- AfxMessageBox( "没有找到模版文档,请其查找" );
- return;
- }
- LPDISPATCH lpDisp; //接口指针
- books=app.GetWorkbooks();
- lpDisp = books.Open(m_filepath,
- covOptional, covOptional, covOptional, covOptional,
- covOptional, covOptional, covOptional, covOptional,
- covOptional, covOptional, covOptional, covOptional,
- covOptional, covOptional
- ); //与的不同,是个参数的,直接在后面加了两个covOptional成功了
- book.AttachDispatch(lpDisp);
3. 保存一个excel文件实例
- book.SetSaved(TRUE);
4. 另存一个excel文件实例
- book.SaveAs(COleVariant(m_filename),covOptional,
- covOptional,covOptional,
- covOptional,covOptional,(long)0,
- covOptional,covOptional,covOptional,
- covOptional,covOptional); //与的不同,是个参数的,直接在后面加了两个covOptional成功了
5. 释放一个excel文件实例
经试验证实,不释放第二次使用excel时会中断,放在类的析构里面有时调用不到,主动调用最保险。(有没有AttachDispatch()过都要释放,否则报错)
- //释放对象(相当重要!)
- Rang.ReleaseDispatch();
- sheet.ReleaseDispatch();
- sheets.ReleaseDispatch();
- book.ReleaseDispatch();
- books.ReleaseDispatch();
- //退出程序
- app.Quit();
- //m_ExlApp一定要释放,否则程序结束后还会有一个Excel进程驻留在内存中,而且程序重复运行的时候会出错
- app.ReleaseDispatch();
6. 修改一个excel单元格
- range=sheet.GetRange(COleVariant(IndexToString(row,col)),COleVariant(IndexToString(row,col)));
- range.SetValue2(COleVariant(value));
7. 取出一个excel单元格
实现Variant数据类型转换为CString类,这个只是一个示例,转换较为简单。
- range=sheet.GetRange(COleVariant(IndexToString(row,col)),COleVariant(IndexToString(row,col)));
- COleVariant rValue;
- rValue=COleVariant(range.GetValue2());
- rValue.ChangeType(VT_BSTR);
- return CString(rValue.bstrVal);
8. 还有释放问题是最重要的问题:
首先变量必须全释放,无论当初是否绑定过;
其次,程序释放和程序关闭的顺序必须是
- app.Quit();
- app.ReleaseDispatch();
- 如果顺如颠倒如下:
- app.ReleaseDispatch();
- app.Quit();
- 出现的后果是程序关闭后,excel进程仍然运行,所以无法正常打开程序曾经打开excel表格。
附录(操作类源码):
- #include "../Stdafx.h"
- #include "OptExcel.h"
- #include "excel.h"
- #include "comdef.h"
- _Application app;
- Workbooks books;
- _Workbook book;
- Worksheets sheets;
- _Worksheet sheet;
- Range range;
- Range cell;
- Font font;
- COleVariant covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR);
- ////////////////////////////////////////////////////////////////////////
- ///Function: COptExcel
- ///Description: 初始化函数,初始化中附加excel应用程序
- ///Call: app.CreateDispatch(_T("Excel.Application")
- ////////////////////////////////////////////////////////////////////////
- COptExcel::COptExcel(void)
- {
- if (::CoInitialize( NULL ) == E_INVALIDARG)
- {
- AfxMessageBox(_T("初始化Com失败!"));
- return;
- }
- //验证office文件是否可以正确运行
- if( !app.CreateDispatch(_T("Excel.Application")) )
- {
- AfxMessageBox(_T("无法创建Excel应用!"));
- return;
- }
- //在程序执行文件路径名中,剪掉执行文件名,得到程序路径,追加模板文件名,得到模板完整路径
- }
- ////////////////////////////////////////////////////////////////////////
- ///Function: ~COptExcel
- ///Description: 析构函数,释放对象,非常重要,不全部释放,占用内存,下
- /// 一次使用此类时会中断
- ///Call: ReleaseDispatch()
- ////////////////////////////////////////////////////////////////////////
- COptExcel::~COptExcel(void)
- {
- books.ReleaseDispatch();
- book.ReleaseDispatch();
- sheets.ReleaseDispatch();
- sheet.ReleaseDispatch();
- range.ReleaseDispatch();
- font.ReleaseDispatch();
- cell.ReleaseDispatch();
- app.Quit();
- app.ReleaseDispatch();
- ::CoUninitialize();
- }
- ////////////////////////////////////////////////////////////////////////
- ///Function: OpenExcelBook
- ///Description: 打开表名为filename的文件,注意,文件路径非自动生成,以后
- /// 考虑从下处理方法
- ///Call: GetAppPath()
- ///Input: CString filename 文件名
- ////////////////////////////////////////////////////////////////////////
- bool COptExcel::OpenExcelBook(CString filename)
- {
- CFileFind filefind;
- if( !filefind.FindFile(filename) )
- {
- AfxMessageBox(_T("文件不存在"));
- return false;
- }
- LPDISPATCH lpDisp; //接口指针
- books=app.GetWorkbooks();
- lpDisp = books.Open(filename,
- covOptional, covOptional, covOptional, covOptional,
- covOptional, covOptional, covOptional, covOptional,
- covOptional, covOptional, covOptional, covOptional,
- covOptional, covOptional
- ); //与office 2000的不同,是个参数的,直接在后面加了两个covOptional成功了
- book.AttachDispatch(lpDisp);
- sheets=book.GetSheets();
- sheet=sheets.GetItem(COleVariant((short)1)); //与的不同,是个参数的,直接在后面加了两个covOptional成功了
- return true;
- }
- void COptExcel::NewExcelBook()
- {
- books=app.GetWorkbooks();
- book=books.Add(covOptional);
- sheets=book.GetSheets();
- sheet=sheets.GetItem(COleVariant((short)1)); //与的不同,是个参数的,直接在后面加了两个covOptional成功了
- }
- ////////////////////////////////////////////////////////////////////////
- ///Function: OpenExcelApp
- ///Description: 打开应用程序(要注意以后如何识别用户要打开的是哪个文件)
- ////////////////////////////////////////////////////////////////////////
- void COptExcel::OpenExcelApp(void)
- {
- app.SetVisible(TRUE);
- app.SetUserControl(TRUE);
- }
- ////////////////////////////////////////////////////////////////////////
- ///Function: SaveExcel
- ///Description: 用于打开数据文件,续存数据后直接保存
- ////////////////////////////////////////////////////////////////////////
- void COptExcel::SaveExcel(void)
- {
- book.SetSaved(TRUE);
- }
- ////////////////////////////////////////////////////////////////////////
- ///Function: SaveAsExcel
- ///Description: 保存excel文件
- ////////////////////////////////////////////////////////////////////////
- void COptExcel::SaveAsExcel(CString filename)
- {
- book.SaveAs(COleVariant(filename),covOptional,
- covOptional,covOptional,
- covOptional,covOptional,(long)0,covOptional,covOptional,covOptional,
- covOptional,covOptional);
- }
- ////////////////////////////////////////////////////////////////////////
- ///Function: SetCellValue
- ///Description: 修改单元格内的值
- ///Call: IndexToString() 从(x,y)坐标形式转化为“A1”格式字符串
- ///Input: int row 单元格所在行
- /// int col 单元格所在列
- /// int Align 对齐方式默认为居中
- ////////////////////////////////////////////////////////////////////////
- void COptExcel::SetCellValue(int row, int col,int Align)
- {
- range=sheet.GetRange(COleVariant(IndexToString(row,col)),COleVariant(IndexToString(row,col)));
- range.SetValue2(COleVariant(value));
- cell.AttachDispatch((range.GetItem (COleVariant(long(1)), COleVariant(long(1)))).pdispVal);
- cell.SetHorizontalAlignment(COleVariant((short)Align));
- }
- ////////////////////////////////////////////////////////////////////////
- ///Function: GetCellValue
- ///Description: 得到的单元格中的值
- ///Call: IndexToString() 从(x,y)坐标形式转化为“A1”格式字符串
- ///Input: int row 单元格所在行
- /// int col 单元格所在列
- ///Return: CString 单元格中的值
- ////////////////////////////////////////////////////////////////////////
- CString COptExcel::GetCellValue(int row, int col)
- {
- range=sheet.GetRange(COleVariant(IndexToString(row,col)),COleVariant(IndexToString(row,col)));
- COleVariant rValue;
- rValue=COleVariant(range.GetValue2());
- rValue.ChangeType(VT_BSTR);
- return CString(rValue.bstrVal);
- }
- ////////////////////////////////////////////////////////////////////////
- ///Function: SetRowHeight
- ///Description: 设置行高
- ///Call: IndexToString() 从(x,y)坐标形式转化为“A1”格式字符串
- ///Input: int row 单元格所在行
- ////////////////////////////////////////////////////////////////////////
- void COptExcel::SetRowHeight(int row, CString height)
- {
- int col = 1;
- range=sheet.GetRange(COleVariant(IndexToString(row,col)),COleVariant(IndexToString(row,col)));
- range.SetRowHeight(COleVariant(height));
- }
- ////////////////////////////////////////////////////////////////////////
- ///Function: SetColumnWidth
- ///Description: 设置列宽
- ///Call: IndexToString() 从(x,y)坐标形式转化为“A1”格式字符串
- ///Input: int col 要设置列宽的列
- /// CString 宽值
- ////////////////////////////////////////////////////////////////////////
- void COptExcel::SetColumnWidth(int col,CString width)
- {
- int row = 1;
- range=sheet.GetRange(COleVariant(IndexToString(row,col)),COleVariant(IndexToString(row,col)));
- range.SetColumnWidth(COleVariant(width));
- }
- ////////////////////////////////////////////////////////////////////////
- ///Function: SetRowHeight
- ///Description: 设置行高
- ///Call: IndexToString() 从(x,y)坐标形式转化为“A1”格式字符串
- ///Input: int row 单元格所在行
- ////////////////////////////////////////////////////////////////////////
- CString COptExcel::GetColumnWidth(int col)
- {
- int row = 1;
- range=sheet.GetRange(COleVariant(IndexToString(row,col)),COleVariant(IndexToString(row,col)));
- VARIANT width = range.GetColumnWidth();
- CString strwidth;
- strwidth.Format(CString((LPCSTR)(_bstr_t)(_variant_t)width));
- return strwidth;
- }
- ////////////////////////////////////////////////////////////////////////
- ///Function: GetRowHeight
- ///Description: 设置行高
- ///Call: IndexToString() 从(x,y)坐标形式转化为“A1”格式字符串
- ///Input: int row 要设置行高的行
- /// CString 宽值
- ////////////////////////////////////////////////////////////////////////
- CString COptExcel::GetRowHeight(int row)
- {
- int col = 1;
- range=sheet.GetRange(COleVariant(IndexToString(row,col)),COleVariant(IndexToString(row,col)));
- VARIANT height = range.GetRowHeight();
- CString strheight;
- strheight.Format(CString((LPCSTR)(_bstr_t)(_variant_t)height));
- return strheight;
- }
- ////////////////////////////////////////////////////////////////////////
- ///Function: IndexToString
- ///Description: 得到的单元格在EXCEL中的定位名称字符串
- ///Input: int row 单元格所在行
- /// int col 单元格所在列
- ///Return: CString 单元格在EXCEL中的定位名称字符串
- ////////////////////////////////////////////////////////////////////////
- CString COptExcel::IndexToString( int row, int col )
- {
- CString strResult;
- if( col > 26 )
- {
- strResult.Format(_T("%c%c%d"),'A' + (col-1)/26-1,'A' + (col-1)%26,row);
- }
- else
- {
- strResult.Format(_T("%c%d"), 'A' + (col-1)%26,row);
- }
- return strResult;
- }
- ////////////////////////////////////////////////////////////////////////
- ///Function: LastLineIndex
- ///Description: 得到表格总第一个空行的索引
- ///Return: int 空行的索引号
- ////////////////////////////////////////////////////////////////////////
- int COptExcel::LastLineIndex()
- {
- int i,j,flag=0;
- CString str;
- for(i=1;;i++)
- {
- flag = 0;
- //粗略统计,认为前列都没有数据即为空行
- for(j=1;j<=5;j++)
- {
- str.Format(_T("%s"),this->GetCellValue(i,j).Trim());
- if(str.Compare(_T(""))!=0)
- {
- flag = 1;
- break;
- }
- }
- if(flag==0)
- return i;
- }
- }