• Visual C++基础 - 使用OLE/COM操作Excel类


    前言

    工作经常遇到的需求之一,将数据保存至Excel中,然后对Excel中的数据进行一系列操作,本篇文章简单记录这个个过程。

    本闻主要实现Excel的读写等一些基本操作,依赖于OLE/COM的Excel库实现,需要先对这些接口进行导入。接口主要是_Application、Workbooks、_Workbook、Worksheets、_Worksheet、Range、Interior、Cfond 类

    部分接口说明如图下:

    第一部分:导入excel库

    可以通过注册表或者文件的形式导入,注册表打开如果找不到对应的库,可以选择用文件,用everything全局搜索Excel.exe。在位置处搜索到该exe所在路径即可。

     需要导入的接口如下图:

    点击添加之后,进入各个头文件中注释掉 “#import "C:\\Program Files\\Microsoft Office\\root\\Office16\\EXCEL.EXE" no_namespace”这句话,VC的特性,不需要再次import。

    另外如果出现变量名重定义的话,可以对其做一个修改。具体修改方式可以自行百度,不太重要。

    至此接口就添加完毕,include对应的.h之后就可以直接对表格内进行读写操作了。

    第二部分:操作Excel

     1、初始化变量和Excel库:

    1. // 初始化Excel库
    2. bool CExcel_TestDlg::InitExcel()
    3. {
    4. HRESULT ht;
    5. ht = ::CoInitialize(NULL);
    6. if (ht == E_INVALIDARG)
    7. {
    8. MessageBox(_T("初始化COM失败"));
    9. }
    10. //创建Execel(启动Excel)
    11. if (!m_App.CreateDispatch(_T("Excel.application"), nullptr))
    12. {
    13. MessageBox(_T("Error!Creat Excel Application Sever Fail!"));
    14. exit(1);
    15. return FALSE;
    16. }
    17. m_App.put_Visible(FALSE);//是否显示EXCEL
    18. m_App.put_DisplayFullScreen(FALSE);//设置全屏显示
    19. m_App.put_DisplayAlerts(FALSE);//屏蔽警告
    20. return TRUE;
    21. }

    2、生成一个表格

    1. BOOL CExcel_TestDlg::CreatNewExcel(CString strPath)
    2. {
    3. //InitExcel();
    4. m_Books = m_App.get_Workbooks();
    5. try
    6. {
    7. m_WorkBook = m_Books.Add(_variant_t(strPath));//打开EXCEL文件
    8. }
    9. catch (CException* e)
    10. {
    11. m_WorkBook = m_Books.Add(vtMissing);//找不到就新建一个
    12. }
    13. m_OpenFileName = strPath;
    14. m_WorkSheet = m_WorkBook.get_ActiveSheet();//获取当前工作表
    15. //保存 定义变量//
    16. COleVariant covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR);
    17. m_WorkBook.SaveAs(COleVariant(strPath),
    18. covOptional,
    19. covOptional,
    20. covOptional,
    21. covOptional,
    22. covOptional,
    23. 0,
    24. covOptional,
    25. covOptional,
    26. covOptional,
    27. covOptional,
    28. covOptional,
    29. covOptional);
    30. //释放资源 - 演示用,如果需要对其操作,当然是先不用关闭了
    31. close();
    32. //关闭应用
    33. m_App.Quit();
    34. m_App.ReleaseDispatch();
    35. m_App = nullptr;
    36. return TRUE;
    37. }
    38. void CExcel_TestDlg::close(BOOL ifSave /*= FALSE*/)
    39. {
    40. COleVariant covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR);
    41. //如果文件已经打开,先关闭文件
    42. if (!m_OpenFileName.IsEmpty())
    43. {
    44. //如果保存,交给用户控制,让用户自己存,如果自己SAVE,会出现莫名的等待
    45. if (ifSave)
    46. {
    47. }
    48. else
    49. {
    50. m_WorkBook.Close(COleVariant(short(FALSE)), COleVariant(m_OpenFileName), covOptional);
    51. m_Books.Close();
    52. }
    53. //清空打开文件名称
    54. m_OpenFileName.Empty();
    55. }
    56. m_Sheets.ReleaseDispatch();
    57. m_WorkSheet.ReleaseDispatch();
    58. m_CurRange.ReleaseDispatch();
    59. m_WorkBook.ReleaseDispatch();
    60. m_Books.ReleaseDispatch();
    61. //m_App.Quit();
    62. return;
    63. }

    3、再次打开表格对其操作

    1. SYSTEMTIME sys;
    2. GetLocalTime(&sys);
    3. CString strFileName;
    4. strTmp.Format("%04d%02d%02d", sys.wYear, sys.wMonth, sys.wDay + 100);
    5. strFileName.Format("%s\\%s.xlsx", sPath, strTmp);
    6. CApplication app;
    7. CWorkbooks books;
    8. CWorkbook book;
    9. CWorksheets sheets;
    10. CWorksheet sheet;
    11. CRange range;
    12. LPDISPATCH lpDisp = NULL;
    13. COleVariant covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR);
    14. if (!app.CreateDispatch(_T("Excel.Application")))
    15. {
    16. MessageBox(_T("Error!Creat Excel Application Sever Fail!"));
    17. exit(1);
    18. }
    19. books.AttachDispatch(app.get_Workbooks());
    20. //获得所有工作表
    21. books.AttachDispatch(app.get_Workbooks());
    22. try
    23. {
    24. lpDisp = books.Open(strFileName, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional);
    25. }
    26. catch (CException* e)
    27. {
    28. // r如果该路径没有表格则生成一个表格
    29. CreatNewExcel(strFileName);
    30. // 再次打开
    31. lpDisp = books.Open(strFileName, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional);
    32. m_IsNewCreat = TRUE;
    33. }
    34. book.AttachDispatch(lpDisp);//得到Workbook
    35. sheets.AttachDispatch(book.get_Worksheets());//得到Worksheets
    36. lpDisp = book.get_ActiveSheet();//得到当前活跃sheet,如果有单元格正处于编辑状态中,此操作不能返回,会一直等待
    37. sheet.AttachDispatch(lpDisp);

    4、对表格数据进行填充 

    1. CString strTemp, strTemp1;
    2. CString str[] = { _T("时间(时分秒)") ,_T("结果"),"1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20" };
    3. vector HeadString(str, str + 22);
    4. for (int i = 0; i < HeadString.size(); ++i)
    5. {
    6. range = sheet.get_Range(COleVariant(_T("A1")), COleVariant(_T("A1")));
    7. range.put_ColumnWidth(_variant_t((long)20)); // 指定区域 设置列宽
    8. COleVariant covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR);
    9. range.AttachDispatch(sheet.get_Cells());
    10. range.AttachDispatch(range.get_Item(COleVariant((long)nRow), COleVariant((long)nCol)).pdispVal);
    11. // 给单元格写入值
    12. range.put_Value(covOptional, _variant_t(strValue));
    13. // 给单元格设置字体格式
    14. CFont0 ft;
    15. ft.AttachDispatch(range.get_Font());
    16. ft.put_Name(_variant_t(_T("宋体")));
    17. ft.put_Size(_variant_t(8));
    18. ft.put_Color(_variant_t(RGB(255, 0, 0)));
    19. // 给单元格设置底色
    20. interior.AttachDispatch(range.get_Interior());
    21. //将底色改为红色 44-对应浅黄色 具体数值对应颜色看这个链接 https://msdn.microsoft.com/en-us/library/cc296089.aspx
    22. interior.put_ColorIndex(_variant_t((long)44));
    23. }

    5、获取对应单元格的值,转为字符串输出

    1. int rows,cols; // 整数型行列,以获取指定单元格
    2. rows = 1;
    3. cols = 1;
    4. range.AttachDispatch(range.get_Item(COleVariant((long)rows), COleVariant((long)cols)).pdispVal);
    5. COleVariant vResult;
    6. vResult = range.get_Value2();
    7. CString data;
    8. if (vResult.vt == VT_BSTR) //字符串
    9. {
    10. data = vResult.bstrVal;
    11. }
    12. else if (vResult.vt == VT_R8) //8字节的数字
    13. {
    14. data.Format("%.0f", vResult.dblVal);
    15. }
    16. else if(vResult.vt==VT_EMPTY) //单元格空的
    17. {
    18. data = "";
    19. }

    6、获取用户区域,对该区域的数值设置对齐方式。

    1. CRange UseRange1;
    2. UseRange1.AttachDispatch(sheet.get_UsedRange(), true);
    3. range.AttachDispatch(UseRange1.get_Rows(), true);
    4. //设置合并单元格的文字的对齐方式【水平垂直居中、竖直垂直居中】
    5. //水平对齐:默认=1,居中=-4108,左=-4131,右=-4152
    6. //垂直对齐:默认=2,居中=-4108,左=-4160,右=-4107
    7. UseRange1.put_HorizontalAlignment(_variant_t((long)-4108));
    8. UseRange1.put_VerticalAlignment(_variant_t((long)-4108));
    9. UseRange1.ReleaseDispatch();

    7、结束别忘了保存数据然后关闭。不然再进程里会一直占用。

    1. book.Save();
    2. books.Close();
    3. range.ReleaseDispatch();
    4. sheet.ReleaseDispatch();
    5. sheets.ReleaseDispatch();
    6. book.ReleaseDispatch();
    7. books.ReleaseDispatch();
    8. app.ReleaseDispatch();
    9. app.Quit();

    至此就结束了excel的基本操作,其他的基本都是先找到单元格的位置,然后调用各自的接口进行想要的操作。接口不清楚只能去网上或者微软官网去查了。
    Workbook 对象 (Excel) | Microsoft Docs

    源码传送门:

  • 相关阅读:
    【软考】系统集成项目管理工程师(十)项目质量管理
    spring mvc:请求执行流程(一)之获取Handler
    兄弟组件通信context
    多线程、多进程同时操作MMAP,会怎么样?
    MySQL----(四)数据库CRUD,约束,存储引擎,事务超详细解读
    Spring Boot实践 --windows环境下 K8s 部署 Docker
    P1030 [NOIP2001 普及组] 求先序排列
    工业设计公司简要介绍了工业外观设计的三个原则
    MySQL什么情况下会导致索引失效?
    openSmile 在 Linux 下的安装教程与使用示例
  • 原文地址:https://blog.csdn.net/qq_40896597/article/details/126688399