假日快要结束了,带着沉重的心情写下之前关于MFC与Excel文件交互的总结。由于VS的版本不同可能在操作上有些差异,所以在此指明下本篇文章的工程环境为VS2013,也建议大家用最新的。
说到程序对于Excel的操作,应该不能算是什么新需求了,方法也有好几种,诸如利用office提供的接口、开源代码之类的。本文在查了一些资料之后选择了实现起来较为反便的一种。其实现的方法基本上完全照抄的这篇文章的,如果看本篇不大明白的可以去看看。
参考的文章说,“踏破铁鞋无觅处,得来费死了工夫”,然而进过了博主的努力,后人需要做的也就是看一看,抄一抄就完事了,开源的力量伟大至极,本篇将发扬博主的精神,在整理内容的同时,写出一个Demo工程提供下载,如果懒得做这些工作的人只需要下载了这个工程就可以直接用起来了(亲测可以),工程在最后面给出。
下面开始主要内容
第一步:创建一个空的MFC对话框工程
第二步:下拉VS菜单栏的“项目”项,选择添加类。在弹出对话框中选中“TypeLib中的MFC类”,点击添加,弹出“从类型库添加类向导”对话框。
第三步:弹出的对话框如下图,“从以下来源添加类”中有两个选项,如果选择的是“注册表”,在“可用的类型库”中选择“Microsoft Excel
15.0 Object Library<1.8>”(Office版本不同可能有些许差异,这个是Office2013)。如果选择的是“文件”,则"位置"选择Office安装路径下的EXCEL.EXE,本人32位Office的默认安装,路径为“C:\Program Files (x86)\Microsoft Office\Office15\EXCEL.EXE”。上面两个选项达到的效果是一样的,只是路径不同而已,做完效果如下:
第四步:选中“接口”中的“_Application”,“_WorkSheet”,“_WorkBook”,“WorkSheets”,“WorkBooks”,“Range”这几项,放到右边去,点击完成,如下图:
第五步:做完第四步后,工程中会多出几个导入类的头文件“CApplication.h”,“CWorkSheet.h”,“CWorkBook.h”,“CWorkSheets.h”,“CWorkBooks.h”,“CRange.h”,将每一个头文件里面的都有的第一句代码“#import
"C:\\Program Files (x86)\\Microsoft Office\\Office15\\EXCEL.EXE" no_namespace”(路径可能不同)都注释掉。如下图:
第六步:既然有头文件,自然就要包含这些头文件啦,在需要调用的文件头写入如下代码:
#include "CApplication.h" #include "CRange.h" #include "CWorkbook.h" #include "CWorkbooks.h" #include "CWorksheet.h" #include "CWorksheets.h"
第七步:这个时候按理说环境已经是搭建好了,但是点击编译还是会报出语法错误,幸好前文提到的博客也给出了解决方法,定位到"CRange,h",将
VARIANT DialogBox() { VARIANT result; InvokeHelper(0xf5, DISPATCH_METHOD, VT_VARIANT, (void*)&result, NULL); return result; }
中的DialogBox改为_DialogBox,现在编译就没有问题了,接下来调用就可以了,调用代码如下:
CApplication app; CWorkbooks books; CWorkbook book; CWorksheets sheets; CWorksheet sheet; CRange range; LPDISPATCH lpDisp; COleVariant vResult; COleVariant covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR); if (!app.CreateDispatch(L"Excel.Application")) { AfxMessageBox(L"无法启动Excel服务器!"); return; } books.AttachDispatch(app.get_Workbooks()); CString path = L"demo.xlsx";//文件路径 TCHAR szPath[MAX_PATH];//获得当前执行路径 GetModuleFileName(NULL, szPath, MAX_PATH); CString PathName(szPath); PathName=PathName.Left(PathName.ReverseFind(_T('\\')) + 1); lpDisp = books.Open(PathName+path, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional); book.AttachDispatch(lpDisp);//得到Workbook sheets.AttachDispatch(book.get_Worksheets());//得到Worksheets lpDisp = book.get_ActiveSheet();//得到当前活跃sheet,如果有单元格正处于编辑状态中,此操作不能返回,会一直等待 sheet.AttachDispatch(lpDisp); //读取第rows行、第cols列单元格的值 /*如果遍历则反复执行这段代码并判断界限*/ int rows = 1, cols = 2; range.AttachDispatch(sheet.get_Cells()); range.AttachDispatch(range.get_Item(COleVariant((long)rows), COleVariant((long)cols)).pdispVal); vResult = range.get_Value2(); CString data; if (vResult.vt == VT_BSTR)//字符串 { data = vResult.bstrVal; } else if (vResult.vt == VT_R8)//8字节的数字 { data.Format(L"%.0f", vResult.dblVal); } else if(vResult.vt==VT_EMPTY)//单元格空的 { data = ""; } MessageBox(data); /*如果遍历则反复执行这段代码并判断界限*/ //释放对象 books.Close(); app.Quit();// 退出 range.ReleaseDispatch(); sheet.ReleaseDispatch(); sheets.ReleaseDispatch(); book.ReleaseDispatch(); books.ReleaseDispatch(); app.ReleaseDispatch();
OK,到此便实现了Excel数据的读取,至于创建和写入也差不多,以后有用到再添加上来。
工程下载(VS2013)