基于MFC对Office Excel、INI文件的操作
环境:VS2017、Office2013、Windows10
本实例功能:从一个INI文件、一个现有的Office Excel中读取数据,写入到一个新的Excel中
效果:
1.新建一个基于对话框的MFC程序,本实例项目名为ExcelAndINI,如下
2. 新增Read、Write按钮的响应事件,如下
1 void CExcelAndINIDlg::OnBnClickedBtnRead() 2 3 { 4 5 // TODO: 在此添加控件通知处理程序代码 6 7 } 8 9 10 void CExcelAndINIDlg::OnBnClickedBtnWrite() 11 12 { 13 14 // TODO: 在此添加控件通知处理程序代码 15 16 }
3. 增加Excel _Application、Workbooks、_Workbook、Worksheets、_Worksheet、Range六个操作类,如下
4.在新增的六个OFFICE类的头文件中,做如下动作
//#import "D:\\Program Files\\office\\Office15\\EXCEL.EXE" no_namespace 注释掉此语句
// CRange 包装器类
#pragma once //增加此语句
5. 在ExcelAndINIDlg.cpp中增加六个OFFICE类的头文件
1 #include "CApplication.h" 2 3 #include "CWorkbooks.h" 4 5 #include "CWorkbook.h" 6 7 #include "CWorksheets.h" 8 9 #include "CWorksheet.h" 10 11 #include "CRange.h"
6.此时编译出现如下错误
解决方法:双击此error调到此方法实现处,在此方法名前增加下划线_,重新编译即OK
1 VARIANT _DialogBox() 2 3 { 4 5 VARIANT result; 6 7 InvokeHelper(0xf5, DISPATCH_METHOD, VT_VARIANT, (void*)&result, nullptr); 8 9 return result; 10 11 }
7. 在CExcelAndINIDlg类中新增三个Public方法
1 int CExcelAndINIDlg::ReadINIFile() 2 3 { 4 5 // TODO: 在此处添加实现代码. 6 7 return 0; 8 9 } 10 11 12 13 int CExcelAndINIDlg::ReadExcelFile() 14 15 { 16 17 // TODO: 在此处添加实现代码. 18 19 return 0; 20 21 } 22 23 24 25 int CExcelAndINIDlg::GetWorkDir() 26 27 { 28 29 // TODO: 在此处添加实现代码.用于获取程序所在路径 30 31 return 0; 32 33 }
8.在CExcelAndINIDlg新增如下Public变量
1 CString strINI1; //读取INI文件内容CString变量1 2 CString strINI2; //读取INI文件内容CString变量2 3 CString strINI3; //读取INI文件内容CString变量3 4 CString strINI4; //读取INI文件内容CString变量4 5 CString strExcel1; //读取Excel文件内容CString变量1 6 CString strExcel2; //读取Excel文件内容CString变量2 7 CString strINIFilePath; //用于保存数据源INI文件路径 8 CString strExcleFilePath; //用于保存数据源Excel文件路径 9 CString strOutputExcleFilePath; //用于保存输出Excel文件路径 10 CString strWorkDir; //用于保存exe所在路径
9. 在CExcelAndINIDlg::GetWorkDir()方法中增加如下代码
1 int CExcelAndINIDlg::GetWorkDir() 2 { 3 // TODO: 在此处添加实现代码. 4 TCHAR pFileName[MAX_PATH]; 5 GetCurrentDirectory(MAX_PATH, pFileName); 6 CString dir(pFileName); 7 strWorkDir = dir; 8 9 return 0; 10 }
10.在CExcelAndINIDlg::ReadINIFile()方法中增加如下代码
1 int CExcelAndINIDlg::ReadINIFile() 2 { 3 // TODO: 在此处添加实现代码. 4 strINIFilePath = strWorkDir + _T("\\INITest.ini"); //exe所在路径当前路径下的ini文件 5 GetPrivateProfileString(_T("Section1"), _T("Item1"), _T(""), strINI1.GetBuffer(MAX_PATH), MAX_PATH, strINIFilePath); //读取ini文件中Secton1节点下的Item1键下的键值,若不存在则给strINI1附一个空字符串,strINI最多读取和储存MAX_PATH个字符 6 GetPrivateProfileString(_T("Section1"), _T("Item2"), _T(""), strINI2.GetBuffer(MAX_PATH), MAX_PATH, strINIFilePath); 7 GetPrivateProfileString(_T("Section2"), _T("Item1"), _T(""), strINI3.GetBuffer(MAX_PATH), MAX_PATH, strINIFilePath); 8 GetPrivateProfileString(_T("Section2"), _T("Item2"), _T(""), strINI4.GetBuffer(MAX_PATH), MAX_PATH, strINIFilePath); 9 return 0; 10 }
11.在int CExcelAndINIDlg::ReadExcelFile()方法中增加如下代码
1 int CExcelAndINIDlg::ReadExcelFile() 2 { 3 // TODO: 在此处添加实现代码. 4 strExcleFilePath = strWorkDir + _T("\\ExcelTest.xlsx"); //exe所在路径当前路径下的Excel文件 5 CApplication app; 6 CWorkbooks books; 7 CWorkbook book; 8 CWorksheets sheets; 9 CWorksheet sheet; 10 CRange range; 11 LPDISPATCH lpDisp; 12 COleVariant vResult; 13 COleVariant 14 covTrue((short)TRUE), 15 covFalse((short)FALSE), 16 covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR); 17 if (!app.CreateDispatch(_T("Excel.Application"))) 18 { 19 MessageBox(_T("Error!Creat Excel Application Server Faile!")); 20 return -1; 21 } 22 books = app.get_Workbooks(); //获取工作薄集合 23 24 lpDisp = books.Open(strExcleFilePath, 25 covOptional, covOptional, covOptional, covOptional, 26 covOptional, covOptional, covOptional, covOptional, 27 covOptional, covOptional, covOptional, covOptional, 28 covOptional, covOptional); 29 book.AttachDispatch(lpDisp); 30 //book = books.Add(covOptional); //获取当前工作薄,若使用此语句,则为新建一个EXCEL表 31 sheets = book.get_Worksheets(); //获取当前工作薄页的集合 32 sheet = sheets.get_Item(COleVariant((short)1)); //获取当前活动页,第一页sheet1 33 34 //1.获取数据1 35 range = sheet.get_Range(COleVariant(_T("A1")), COleVariant(_T("A1"))); //获取单元格 36 vResult = COleVariant(range.get_Value2()); 37 strExcel1 = CString(vResult.bstrVal); 38 39 //1.获取数据2 40 range = sheet.get_Range(COleVariant(_T("B1")), COleVariant(_T("B1"))); //获取单元格 41 vResult = COleVariant(range.get_Value2()); 42 strExcel2 = CString(vResult.bstrVal); 43 MessageBox(strExcel1); 44 MessageBox(strExcel2); 45 46 //释放各对象,注意其顺序,若不执行以下步骤,Excel进程无法退出,打开任务管理器将会看到残留进程 47 range.ReleaseDispatch(); 48 sheet.ReleaseDispatch(); 49 sheets.ReleaseDispatch(); 50 book.ReleaseDispatch(); //释放当前工作薄 51 books.ReleaseDispatch(); //释放工作薄集 52 app.Quit(); //退出EXCEL程序 53 app.ReleaseDispatch(); //释放EXCEL程序 54 return 0; 55 }
12.在void CExcelAndINIDlg::OnBnClickedBtnRead()方法中增加如下代码
1 void CExcelAndINIDlg::OnBnClickedBtnRead() 2 { 3 // TODO: 在此添加控件通知处理程序代码 4 GetWorkDir(); 5 ReadINIFile(); 6 ReadExcelFile(); 7 8 }
13.在void CExcelAndINIDlg::OnBnClickedBtnWrite()方法中增加如下代码
1 void CExcelAndINIDlg::OnBnClickedBtnWrite() 2 { 3 // TODO: 在此添加控件通知处理程序代码 4 strOutputExcleFilePath = strWorkDir + _T("\\Result.xlsx"); //指定要写入的文件名及其路径,若存在则覆盖 5 6 CApplication app; 7 CWorkbooks books; 8 CWorkbook book; 9 CWorksheets sheets; 10 CWorksheet sheet; 11 CRange range; 12 COleVariant vResult; 13 CString strTemp; 14 COleVariant 15 covTrue((short)TRUE), 16 covFalse((short)FALSE), 17 covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR); 18 if (!app.CreateDispatch(_T("Excel.Application"))) 19 { 20 MessageBox(_T("Error!Creat Excel Application Server Faile!")); 21 return; 22 } 23 24 books = app.get_Workbooks(); //获取工作薄集合 25 26 book = books.Add(covOptional); //获取当前工作薄,若使用此语句,则为新建一个EXCEL表 27 sheets = book.get_Worksheets(); //获取当前工作薄页的集合 28 sheet = sheets.get_Item(COleVariant((short)1)); //获取当前活动页 29 30 //写入从ini文件中读取的键值 31 range = sheet.get_Range(COleVariant(_T("A1")), COleVariant(_T("A1"))); //获取单元格 32 strTemp.Format(_T("%s"), strINI1);//从ini文件中读取到的数据,需要用CString::Format()再次将字符串格式化一下才能正确写入到Excel中 33 range.put_Value2(COleVariant(strTemp)); //将内容填入单元格 34 range = sheet.get_Range(COleVariant(_T("A2")), COleVariant(_T("A2"))); //获取单元格 35 strTemp.Format(_T("%s"), strINI2); 36 range.put_Value2(COleVariant(strTemp)); 37 range = sheet.get_Range(COleVariant(_T("A3")), COleVariant(_T("A3"))); //获取单元格 38 strTemp.Format(_T("%s"), strINI3); 39 range.put_Value2(COleVariant(strTemp)); 40 range = sheet.get_Range(COleVariant(_T("A4")), COleVariant(_T("A4"))); //获取单元格 41 strTemp.Format(_T("%s"), strINI4); 42 range.put_Value2(COleVariant(strTemp)); 43 44 //写入从Excle表中读取的数据 45 range = sheet.get_Range(COleVariant(_T("A5")), COleVariant(_T("A5"))); //获取单元格 46 range.put_Value2(COleVariant(strExcel1)); 47 range = sheet.get_Range(COleVariant(_T("A6")), COleVariant(_T("A6"))); //获取单元格 48 range.put_Value2(COleVariant(strExcel2)); 49 50 book.SaveCopyAs(COleVariant(strOutputExcleFilePath)); 51 book.put_Saved(true); 52 app.put_Visible(FALSE); //FALSE表示操作完,不打开工作表,若此处为FALSE,则一定需要调用app.Quit(),以避免程序结束后,还有EXCEL进程 53 54 range.ReleaseDispatch(); 55 sheet.ReleaseDispatch(); 56 sheets.ReleaseDispatch(); 57 book.ReleaseDispatch(); //释放当前工作薄 58 books.ReleaseDispatch(); //释放工作薄集 59 app.Quit(); //退出EXCEL程序 60 app.ReleaseDispatch(); //释放EXCEL程序 61 62 }
说明:
1.对于有下拉菜单的Excel表项,其读写方式与普通单元格没有差别。
2.对于合并单元格的读写,可以按照普通单元格读写,如B1、C1为合并单元格,对B1按照普通单元格操作即可。
3.对从ini文件读取的内容写入到Excel表中前,一定要先使用Format方法格式化一下,不然写入到Excel为空。
实例代码链接:https://pan.baidu.com/s/1nS3t1n4HkkYdGXzJ1nxJNQ 提取码:kkjn