C++通过COM操作EXCEL

**

C++通过COM操作EXCEL

**
  C++操作EXCEL网上有很多方法,我觉得通过微软自带的COM操作还是比较方便并且兼容性比较好的,总结了网上各个网页的博客分享,整理了一份我自己的理解。

一、封装Excel库

  1、环境配置:VS2013加EXCEL2013
  2、封装步骤
   1、新建一个MFC项目
MFC项目建立步骤1
MFC项目建立步骤2
   2、右击项目选址类向导
   这里写图片描述
   3、选择类型库中的MFC库
   这里写图片描述
   4、网上说可以在可用类型库中直接找到Microsoft Office Excel库,我的电脑上没找到
   这里写图片描述
   5、所以我选择文件,找到EXCEl的安装路径,找到EXCEL.EXE
   这里写图片描述
   6、添加:_Application、_Workbook、_Worksheet、Workbooks、Worksheets、Range这些常用接口。
   这里写图片描述
   7、点击完成确定,会生成6个对应的文件。
   8、删除每个文件的# import “D:\program\Office15\EXCEL.EXE” no_namespace添加#pragma once#include

9、按照上面操作再添加Validation、Interior、Font、Names四个类

三、编写操作类

   1、新建ExcelOperation.h, ExcelOperation.cpp两个文件添加刚刚建立的10个类
   这里写图片描述
   2、编写类,使用单例模式
   ExcelOperation.h:

#pragma once
#include "CRange.h"
#include "CApplication.h"
#include "CWorkbook.h"
#include "CWorkbooks.h"
#include "CWorksheet.h"
#include "CWorksheets.h"
#include "CValidation.h"
#include "Cnterior.h"
#include "CFont0.h"
#include "CNames.h"

class ExcelOperation
{
private:
    ExcelOperation();
    ~ExcelOperation();
    static ExcelOperation* excel;
public:
    static ExcelOperation* getInstance();
    static void destroyInstance();
private:
    CApplication ExcelApp;
    CWorkbooks books;
    CWorkbook book;
    CWorksheets sheets;
    CWorksheet sheet;
    CRange range;
    CValidation validation;
    Cnterior interior;
    CFont0 font;
    CNames names;
    //CString filePath;
    LPDISPATCH lpDisp;
    //伪造的ExcelApp
    CApplication ExcelApp_fake;
    CWorkbooks books_fake;
    int excelVer;
};

   ExcelOperation.cpp:
   

#include "ExcelOperation.h"

ExcelOperation* ExcelOperation::excel = nullptr;

ExcelOperation::ExcelOperation()
{
    lpDisp = NULL;
    excelVer = 0;
}

//获取对象
ExcelOperation* ExcelOperation::getInstance()
{
    if (excel == NULL)
    {
        excel = new ExcelOperation();
    }
    return excel;
}
//销毁对象
void ExcelOperation::destroyInstance()
{
    if (excel != NULL)
    {
        delete excel;
        excel = NULL;
    }
}

ExcelOperation::~ExcelOperation()
{
    try
    {
        sheet.ReleaseDispatch();
        sheets.ReleaseDispatch();
        book.ReleaseDispatch();
        books.ReleaseDispatch();
        ExcelApp.ReleaseDispatch();
        ExcelApp.Quit();
        //退出伪装的app
        if (!ExcelApp_fake.get_ActiveSheet())
        {
            books_fake.ReleaseDispatch();
            ExcelApp_fake.ReleaseDispatch();
            ExcelApp_fake.Quit();
        }
    }
    catch (COleDispatchException*)
    {
        //AfxMessageBox(Notice_get_by_id(IDS_POW_OFF_EXCEL_FAIL));
        AfxMessageBox(_T("关闭Excel服务出错。"));
    }
}
    3、判断Excel版本号    
BOOL ExcelOperation::judgeExcelVer(int Ver)
{
    HKEY hkey;
    int ret;
    CString str;
    LONG len;
    str.Format(_T("Excel.Application.%d"), Ver);
    str += _T("\\CLSID");
    ret = RegCreateKey(HKEY_CLASSES_ROOT, str, &hkey);
    if (ret == ERROR_SUCCESS)
    {
        RegQueryValue(HKEY_CLASSES_ROOT, str, NULL, &len);
        //如果注册表中 HKEY_CLASSES_ROOT\Excel.Application.x\CPLSID中的值为空,则读取到'\0',长度为2
        return len == 2 ? FALSE : TRUE;
    }
    else
    {
        return FALSE;
    }
}
    4、启动Excel服务 
BOOL ExcelProcess::createServer( CString officeVer )
{
    //去除前后空格
    officeVer.Trim();
    //获取版本号字符
    CString verNum = officeVer.Right(4);
    int ver = _ttoi(verNum);
    switch(ver)
    {
    case 2003:
        if(judgeExcelVer(11))
        {
            if(ExcelApp.CreateDispatch(_T("Excel.Application.11"), NULL))
            {
                excelVer = 2003;
            }
            else
            {
                return FALSE;
            }
        }
        else
        {
            return FALSE;
        }
        break;
    case 2007:
        if(judgeExcelVer(12))
        {
            if(ExcelApp.CreateDispatch(_T("Excel.Application.12"), NULL))
            {
                excelVer = 2007;
            }
            else
            {
                return FALSE;
            }
        }
        else
        {
            return FALSE;
        }
        break;
    case 2010:
        if(judgeExcelVer(14))
        {
            if(ExcelApp.CreateDispatch(_T("Excel.Application.14"), NULL))
            {
                excelVer = 2010;
            }
            else
            {
                return FALSE;
            }
        }
        else
        {
            return FALSE;
        }
        break;
    case 2013:
        if( judgeExcelVer(15))
        {
            if(ExcelApp.CreateDispatch(_T("Excel.Application.15"), NULL))
            {
                excelVer = 2013;
            }
            else
            {
                return FALSE;
            }
        }
        else
        {
            return FALSE;
        }
        break;
    case 2016:
        if( judgeExcelVer(16))
        {
            if(ExcelApp.CreateDispatch(_T("Excel.Application.16"), NULL))
            {
                excelVer = 2016;
            }
            else
            {
                return FALSE;
            }
        }
        else
        {
            return FALSE;
        }
        break;
    }
    return TRUE;
}
    5、初始化   
BOOL ExcelOperation::init()
{
    CString strOfficeVer[5] = { _T("office 2003"), _T("office 2007"), _T("office 2010"), _T("office 2013"), _T("office 2016") };
    BOOL result = FALSE;
    for (int i = 4; i >= 0; i--)
    {
        if (!createServer(strOfficeVer[i]))
            continue;
        else
        {
            result = TRUE;
        }
    }
    if (excelVer == 0)
    {
        result = FALSE;
    }
    return result;
}
    6、设置界面隐藏显示
//显示隐藏excel
void ExcelOperation::setView(bool show)
{
    ExcelApp.put_Visible(TRUE);
    ExcelApp.put_UserControl(FALSE);
}
7、另存为  
void ExcelOperation::saveExcelAs(const char* savePath)
{
    CString savePathCSt;
    ConstCharConver(savePath, savePathCSt);
    savePathCSt.Trim();
    book.SaveAs(_variant_t(savePathCSt),
        vtMissing, vtMissing, vtMissing, vtMissing, vtMissing, 0,
        vtMissing, vtMissing, vtMissing, vtMissing, vtMissing);
}
    7、打开工作簿 
BOOL ExcelOperation::openExcelFile(const char*path, const char* excleTemplate)
{
    lpDisp = NULL;

    /*判断当前Excel的版本*/
    CString strExcelVersion = ExcelApp.get_Version();
    int iStart = 0;
    strExcelVersion = strExcelVersion.Tokenize(_T("."), iStart);

    setView(false);

    /*得到工作簿容器*/
    books.AttachDispatch(ExcelApp.get_Workbooks());

    /*打开一个工作簿,如不存在,则新增一个工作簿*/
    CString strBookPath;
    ConstCharConver(path, strBookPath);
    try
    {
        /*打开一个工作簿*/
        lpDisp = books.Open(strBookPath,
            vtMissing, vtMissing, vtMissing, vtMissing, vtMissing,
            vtMissing, vtMissing, vtMissing, vtMissing, vtMissing,
            vtMissing, vtMissing, vtMissing, vtMissing);
        book.AttachDispatch(lpDisp);
    }
    catch (...)
    {
        /*增加一个新的工作簿*/
        if (excleTemplate == nullptr)
        {
            lpDisp = books.Add(vtMissing);
        }
        else
        {
            lpDisp = books.Add(_variant_t(excleTemplate));
        }
        book.AttachDispatch(lpDisp);
        saveExcelAs(path);
    }
    return true;
}
    8、打开Sheet   
void ExcelOperation::OpenSheet(const char* sheetName)
{
    LPDISPATCH lpDisp = NULL;
    /*得到工作簿中的Sheet的容器*/
    sheets.AttachDispatch(book.get_Sheets());
    /*打开一个Sheet,如不存在,就新增一个Sheet*/
    CString strSheetName(sheetName);
    try
    {
        /*打开一个已有的Sheet*/
        lpDisp = sheets.get_Item(_variant_t(strSheetName));
        sheet.AttachDispatch(lpDisp);
    }
    catch (...)
    {
        /*创建一个新的Sheet*/
        lpDisp = sheets.Add(vtMissing, vtMissing, _variant_t((long)1), vtMissing);
        sheet.AttachDispatch(lpDisp);
        sheet.put_Name(strSheetName);
    }
}
    9、设置单元格格式   
void ExcelOperation::setCellsFormat(const char* cellBeginChar, const char* cellBEndChar, const char* cellFormat)
{
    CString cellBegin, cellEnd, format;
    ConstCharConver(cellBeginChar, cellBegin);
    ConstCharConver(cellBEndChar, cellEnd);
    ConstCharConver(cellFormat, format);
    lpDisp = sheet.get_Range(_variant_t(cellBegin), _variant_t(cellEnd));
    range.AttachDispatch(lpDisp);
    range.put_NumberFormatLocal(_variant_t(format));
}
    10、设置单个单元格的值    
 void ExcelOperation::setCellValue(const char* ccellIndexChar, const char* valueChar)
{
    CString cellIndex , value;
    ConstCharConver(ccellIndexChar, cellIndex);
    ConstCharConver(valueChar, value);
    range = sheet.get_Range(_variant_t(cellIndex), _variant_t(cellIndex));
    range.put_Value2(_variant_t(value));
}
    11、设置单个单元格格式    
void ExcelOperation::setCellFormat(const char* ccellIndexChar, const char* cellFormat)
{
    CString cellIndex, cellFormatChar;
    ConstCharConver(ccellIndexChar, cellIndex);
    ConstCharConver(cellFormat, cellFormatChar);
    range = sheet.get_Range(_variant_t(cellIndex), _variant_t(cellIndex));
    range.put_NumberFormat(_variant_t(cellFormatChar));
}
    12、初始化界面    
非MFC项目使用*
void ExcelOperation::InitializeUI()
{
    if (S_OK != CoInitialize(NULL)){
        AfxMessageBox(_T("Initialize com failed..."));
        return;
    }
}
    13、 释放资源
void ExcelOperation::UnInitializeUI()
{
    CoUninitialize();
}
    14、保存   
void ExcelOperation::saveExcel()
{
    ExcelApp.put_DisplayAlerts(FALSE);
    //book.Close(vtMissing, vtMissing, vtMissing);
    book.Save();
}
    15、CString转const char*  
void ConstCharConver(const char* pFileName, CString &pWideChar)
    {
        //计算char *数组大小,以字节为单位,一个汉字占两个字节
        int charLen = strlen(pFileName);

        //计算多字节字符的大小,按字符计算。
        int len = MultiByteToWideChar(CP_ACP, 0, pFileName, charLen, NULL, 0);

        //为宽字节字符数组申请空间,数组大小为按字节计算的多字节字符大小
        TCHAR *buf = new TCHAR[len + 1];

        //多字节编码转换成宽字节编码
        MultiByteToWideChar(CP_ACP, 0, pFileName, charLen, buf, len);

        buf[len] = '\0';  //添加字符串结尾,注意不是len+1

        //将TCHAR数组转换为CString

        pWideChar.Append(buf);
    }

四、编译

1、编译出错
warning C4003: “DialogBoxW”宏的实参不足
error C2059: 语法错误:“,”
把DialogBox改成_DialogBox

在查找预编译头时遇到意外的文件结尾。是否忘记了向源中添加“#include "stdafx.h"
修改为不适应预编译头

这里写图片描述

五、使用类

1、添加一个按钮控件,双击。
2、添加如下代码
void CMFCApplication3Dlg::OnBnClickedButton1()
{
    // TODO:  在此添加控件通知处理程序代码
    ExcelOperation* excel = ExcelOperation::getInstance();
    excel->init();
    excel->openExcelFile("C:\\test.xlsx");
    excel->OpenSheet("NewSheet");
    excel->setCellFormat("A1", "@");
    excel->setCellValue("A1", "3342");
    excel->setCellFormat("A2", "0.00");
    excel->setCellValue("A2", "3342.5684");
    excel->setView(true);
    excel->saveExcel();
    excel->saveExcelAs("C:\\saveTest.xlsx");
    excel->Close();

    excel->destroyInstance();
}

运行之后会在C盘下生成test.xlsx和saveTest.xlsx文件,A1格式为文本,A2格式为0.00形

更多单元设置参考如下:
CRange write_range;
write_range.put_NumberFormat(_variant_t(“@”));//设置单元格为文本
来源:https://blog.csdn.net/zhanglidn013/article/details/38900191

文本类:
1、@ 指定内容按文本显示,主要用于编码、手机号等用数字表示的文本。设定该格式后,可以保证导出excel时,此类文本不会被转成数字显示。
数值类:
1、 0.00 表示两位小数,例如3.10367显示为3.10
2、 0.## 表示两位小数,当小数末位为0时,0将不显示。例如3.10显示为3.1
3、 “#,##0.00 “表示两位小数,且显示千份位
4、 #,##0.00;[Red]#,##0.00 表示负数红字
5、0.00;[Red]0.00;” ” 表示负数红字,且数据为0时不显示
6、0.00;Red;” “表示正数时两位小数,负数时两位小数并显示红色,0时不显示。0.00;Red只是一个示例,可以为任意的数字格式串,后边再加上;” “(空格)即表示数据为0时不显示。
日期类:
1、 yyyy-m-d
2、 yyyy-MM-dd
3、 yyyy-MM-dd hh:mm:ss
4、 yyyy年MM月dd日
百分比:
1、0%
2、0.00%
详细请打开Excel2003,单元格右键,设置单元格格式,选一种格式,点自定义即可看到该格式的格式串;有的Excel格式串后有带”_”,在使用时,必须去掉。

整个项目地址:https://download.csdn.net/download/littercooker/10593588

本文参考网上许多大神文章,链接如下:
https://www.cnblogs.com/ustclwx/p/4073423.html
https://wenku.baidu.com/view/aece6e42f4335a8102d276a20029bd64793e6254.html
https://blog.csdn.net/yukin_xue/article/details/11209283
https://blog.csdn.net/zhanglidn013/article/details/38900191
https://blog.csdn.net/GoForwardToStep/article/details/53079967

猜你喜欢

转载自blog.csdn.net/litterCooker/article/details/81538461