VC读写EXCEL文件类(已安装excel)

以下是.h文件

#pragma once
class CReadWriteExcel
{
private:
 long CStringToLong(CString sStr);
 int GetColumnWidth(CString sA,CString sB);
 BOOL CheckString(CString str,CString &sLeft,CString &sRight,long &nRight);
 HRESULT AutoWrap(int autoType, VARIANT *pvResult, IDispatch *pDisp, LPOLESTR ptName, int cArgs...);
 
public:
 int ReadExcelStringArray(const CString strfilename,CStringArray &strArray,const CString sBeginCell,const CString sEndCell);
    BOOL WriteExcelStringArray(const CString strfilename,CStringArray &strArray,long nColumn);
 //BOOL SetRangValueType(int nType,const CString sBeginCell,const CString sEndCell);
};

//以下是.cpp文件

#include "stdafx.h"
#include "ReadWriteExcel.h"


//读取数据,返回列数
int CReadWriteExcel::ReadExcelStringArray(const CString strfilename,CStringArray &strArray,CString sBeginCell,CString sEndCell)
{
 //检查Range输入,并计算行列
 if(sBeginCell.IsEmpty()|| sEndCell.IsEmpty())
  return -1;
 //转成大写
 sBeginCell.MakeUpper();
 sEndCell.MakeUpper();
 
 CString sBL,sBR;
 long nB;
 if(!CheckString(sBeginCell,sBL,sBR,nB))
  return -1;
 CString sEL,sER;
 long nE;
 if(!CheckString(sEndCell,sEL,sER,nE))
  return -1;
 
 int col=GetColumnWidth(sBL,sEL);
 int row=nE-nB+1;
 strArray.RemoveAll();
 strArray.SetSize(row*col);
    //处理所有Excel数据,并把所有数据加入到一个二维数组中
    CoInitialize(NULL);
    int i,j;  //用来循环
    // 获得EXCEL的CLSID
    CLSID clsid;
    HRESULT hr = CLSIDFromProgID(L"Excel.Application", &clsid);

    if(FAILED(hr)) {
        AfxMessageBox(_T("CLSIDFromProgID() 函数调用失败!"));
        return -1;
    }

    // 创建实例
    IDispatch *pXlApp;
    hr = CoCreateInstance(clsid, NULL, CLSCTX_LOCAL_SERVER, IID_IDispatch, (void **)&pXlApp);
    if(FAILED(hr)) {
        AfxMessageBox(_T("请检查是否已经安装EXCEL!"));
        return -1;
    }

    // 显示,将Application.Visible属性置1
    VARIANT x;
    x.vt = VT_I4;
    x.lVal = 1;
    AutoWrap(DISPATCH_PROPERTYPUT, NULL, pXlApp, L"Visible", 1, x);

    // 获取Workbooks集合
    IDispatch *pXlBooks;
    {
        VARIANT result;
        VariantInit(&result);
        AutoWrap(DISPATCH_PROPERTYGET, &result, pXlApp, L"Workbooks", 0);
        pXlBooks = result.pdispVal;
    }

    CString strName;  //Excel表完整路径
    CString strTmp;   //临时变量,保存单元格数据中的CString型
    double dblTmp;   //临时变量,保存单元格数据中的double型
    //用来保存信息的数组
    VARIANT arr;
    arr.vt = VT_ARRAY | VT_VARIANT;
    SAFEARRAYBOUND sab[2];
    sab[0].lLbound = 1; sab[0].cElements = row;
    sab[1].lLbound = 1; sab[1].cElements = col;
    arr.parray = SafeArrayCreate(VT_VARIANT, 2, sab);
    int tableNum=0;
    int nCount=1;
   
    strName=strfilename;

    // 调用Workbooks.Open()方法,打开一个已经存在的Workbook
    IDispatch *pXlBook;
    {
        VARIANT parm;
        parm.vt = VT_BSTR;
        // parm.bstrVal = ::SysAllocString(L"'strName'");
        parm.bstrVal=strName.AllocSysString();
        VARIANT result;
        VariantInit(&result);
        AutoWrap(DISPATCH_PROPERTYGET, &result, pXlBooks, L"Open", 1,parm);
        pXlBook = result.pdispVal;
    }

    // 从Application.ActiveSheet属性获得Worksheet对象
    IDispatch *pXlSheet;
    {
        VARIANT result;
        VariantInit(&result);
        AutoWrap(DISPATCH_PROPERTYGET, &result, pXlApp, L"ActiveSheet", 0);
        pXlSheet = result.pdispVal;
    }

 CString strRange;
 strRange=sBeginCell+_T(":")+sEndCell;
 TCHAR* cRange=strRange.GetBuffer();
    // 选择一个16x40大小的Range
    IDispatch *pXlRange;
    {
        VARIANT parm;
        parm.vt = VT_BSTR;
        parm.bstrVal = ::SysAllocString(cRange);
        VARIANT result;
        VariantInit(&result);
        AutoWrap(DISPATCH_PROPERTYGET, &result, pXlSheet, L"Range", 1, parm);
        VariantClear(&parm);
        pXlRange = result.pdispVal;
    }
    // 用这个Range读取数据
    AutoWrap(DISPATCH_PROPERTYGET, &arr, pXlRange, L"Value",0);
    for(i=0; i<row; i++)
    {
        for(j=0; j<col; j++)
        {
            VARIANT tmp;
            //tmp.vt = VT_BSTR;
            // 添加数据到数组中
            long indices[] = {i+1,j+1};
            SafeArrayGetElement(arr.parray, indices, (void *)&tmp);
   
   strTmp=_T(""); 
            if(tmp.vt ==VT_BSTR)
            {
                strTmp=tmp.bstrVal;
            }
            else if(tmp.vt==VT_R8)
            {
                dblTmp=tmp.dblVal;
                //strTmp.Format(_T("%f"),dblTmp);
    //dblTmp=123;
    char buffer[_CVTBUFSIZE];
    _gcvt( dblTmp, 16, buffer );
    if((dblTmp-(int)dblTmp)==0 && strlen(buffer)>1)
     buffer[strlen(buffer)-1]=buffer[strlen(buffer)];
    int i=0;
    USES_CONVERSION;
    LPWSTR x=A2W(buffer);
    strTmp=x;
            }
   else if(tmp.vt==VT_DATE)
   {
    COleDateTime value;
    value=tmp.date;
    strTmp=value.Format(L"%Y-%m-%d");
   }
      else if(tmp.vt==VT_NULL)
            {
                strTmp="";
            }
            _bstr_t str1=strTmp;
            WCHAR *str2=str1;
            strArray[col*i+j]=str2;
        }
    }
    AutoWrap(DISPATCH_METHOD, NULL, pXlBook, L"Close", 0);
    VariantClear(&arr);
    pXlRange->Release();
    pXlSheet->Release();
    pXlBook->Release();
    // 退出,调用Application.Quit()方法
    // 释放所有的接口以及变量
    AutoWrap(DISPATCH_METHOD, NULL, pXlApp, L"Quit", 0);
    pXlBooks->Release();
    pXlApp->Release();

    // 注销COM库
    CoUninitialize();
 return col;
}

//**********************//
// AutoWrap 函数的正体
// 先声明:这个函数不是偶写的
// AutoWrap() - Automation helper function...
HRESULT CReadWriteExcel::AutoWrap(int autoType, VARIANT *pvResult, IDispatch *pDisp, LPOLESTR ptName, int cArgs...)
{
    // Begin variable-argument list...
    va_list marker;
    va_start(marker, cArgs);
    if(!pDisp) {   
        AfxMessageBox(_T("NULL IDispatch passed to AutoWrap()"));
        _exit(0);
    }
    // Variables used...
    DISPPARAMS dp = { NULL, NULL, 0, 0 };
    DISPID dispidNamed = DISPID_PROPERTYPUT;
    DISPID dispID;
    HRESULT hr;
    char buf[200];
    char szName[200];
    // Convert down to ANSI
    WideCharToMultiByte(CP_ACP, 0, ptName, -1, szName, 256, NULL, NULL);
    // Get DISPID for name passed...
    hr = pDisp->GetIDsOfNames(IID_NULL, &ptName, 1, LOCALE_USER_DEFAULT, &dispID);
    if(FAILED(hr)) {
        sprintf(buf, "IDispatch::GetIDsOfNames(/"%s/") failed w/err 0x%08lx", szName, hr);
        //AfxMessageBox(buf);
        _exit(0);
        return hr;
    }
    // Allocate memory for arguments...
    VARIANT *pArgs = new VARIANT[cArgs+1];
    // Extract arguments...
    for(int i=0; i<cArgs; i++) {
        pArgs[i] = va_arg(marker, VARIANT);
    }
    // Build DISPPARAMS
    dp.cArgs = cArgs;
    dp.rgvarg = pArgs;
    // Handle special-case for property-puts!
    if(autoType & DISPATCH_PROPERTYPUT) {
        dp.cNamedArgs = 1;
        dp.rgdispidNamedArgs = &dispidNamed;
    }
    // Make the call!
    hr = pDisp->Invoke(dispID, IID_NULL, LOCALE_SYSTEM_DEFAULT, autoType, &dp, pvResult, NULL, NULL);
    if(FAILED(hr)) {
        sprintf(buf, "IDispatch::Invoke(/"%s/"=%08lx) failed w/err 0x%08lx", szName, dispID, hr);
        //AfxMessageBox(buf);
        _exit(0);
        return hr;
    }
    // End variable-argument section...
    va_end(marker);
    delete [] pArgs;
    return hr;
}

//1、判断字符串是否是可输入字符
//2、判断字符串是否是合法顺序
//3、将字符和数字分开
//4、获取数字部分的值
//如A123
BOOL CReadWriteExcel::CheckString(CString str,CString &sLeft,CString &sRight,long &nRight)
{
 if(str.IsEmpty())
  return FALSE;
 CString sAllowStr;
 sAllowStr=_T("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
 int r=-1;//记住第一个数字字符
 for(int i=0;i<str.GetLength();i++)
 {
  int index=sAllowStr.Find(str[i]);
  if(index==-1)
   return FALSE;
  if(index<26)//最后一个字母字符
   r=i;
 }
 //没有数字字符
 if(r==-1)
  return FALSE;
 sLeft=str.Left(r+1);
 sRight=str.Right(str.GetLength()-(r+1));
 //字符串部分检查
 for(int i=0;i<sLeft.GetLength();i++)
 {
  int index=sAllowStr.Find(sLeft[i]);
  if(index==-1 || index>25)
   return FALSE;
 }
 //数字部分检查
 for(int i=0;i<sRight.GetLength();i++)
 {
  int index=sAllowStr.Find(sRight[i]);
  if(index==-1 || index<25)
   return FALSE;
 }
 //字符部分长度最大是2
 if(sLeft.GetLength()>2)
  return FALSE;
 //第一个数字如果是字符
 if(sAllowStr.Find(sRight[0])==0)
  return FALSE;
 //将字符串转成long
 nRight=CStringToLong(sRight);
 return TRUE;
}

//将字符串转成long
long CReadWriteExcel::CStringToLong(CString sStr)
{
 TCHAR c=sStr[sStr.GetLength()];
 TCHAR *cc=&c;
#ifdef UNICODE
 return wcstol(sStr.GetBuffer(),&cc,10);
#else
 return atol(sStr.GetBuffer());
#endif
}

//根据表头字母串差,计算表头长度
//如:AA BB
int CReadWriteExcel::GetColumnWidth(CString sA,CString sB)
{
 CString sAllowStr;
 sAllowStr=_T("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
 int a,b;
 if(sA.GetLength()==1)
  a=sAllowStr[sAllowStr.Find(sA[0])]-sAllowStr[0]+1;
 else
  a=(sAllowStr[sAllowStr.Find(sA[0])]-sAllowStr[0]+1)*26+(sAllowStr[sAllowStr.Find(sA[1])]-sAllowStr[0]+1);
 if(sB.GetLength()==1)
  b=sAllowStr[sAllowStr.Find(sB[0])]-sAllowStr[0]+1;
 else
  b=(sAllowStr[sAllowStr.Find(sB[0])]-sAllowStr[0]+1)*26+(sAllowStr[sAllowStr.Find(sB[1])]-sAllowStr[0]+1);
 return (b-a)+1;
}

BOOL CReadWriteExcel::WriteExcelStringArray(const CString strfilename,CStringArray &strArray,long nColumn)
{
    if(strArray.GetSize()<nColumn || nColumn==0)
        return FALSE;
    if(strArray.GetSize()%nColumn!=0)
        return FALSE;
 int col=nColumn;
    int row=(int)strArray.GetSize()/nColumn;
 
    //处理所有Excel数据,并把所有数据加入到一个二维数组中
    CoInitialize(NULL);
    int i,j;  //用来循环
    // 获得EXCEL的CLSID
    CLSID clsid;
    HRESULT hr = CLSIDFromProgID(L"Excel.Application", &clsid);

    if(FAILED(hr)) {
        AfxMessageBox(_T("CLSIDFromProgID() 函数调用失败!"));
        return -1;
    }

    // 创建实例
    IDispatch *pXlApp;
    hr = CoCreateInstance(clsid, NULL, CLSCTX_LOCAL_SERVER, IID_IDispatch, (void **)&pXlApp);
    if(FAILED(hr)) {
        AfxMessageBox(_T("请检查是否已经安装EXCEL!"));
        return -1;
    }

    // 显示,将Application.Visible属性置1
    VARIANT x;
    x.vt = VT_I4;
    x.lVal = 1;
    AutoWrap(DISPATCH_PROPERTYPUT, NULL, pXlApp, L"Visible", 1, x);

    // 获取Workbooks集合
    IDispatch *pXlBooks;
    {
        VARIANT result;
        VariantInit(&result);
        AutoWrap(DISPATCH_PROPERTYGET, &result, pXlApp, L"Workbooks", 0);
        pXlBooks = result.pdispVal;
    }

   
    //用来保存信息的数组
    VARIANT arr;
    arr.vt = VT_ARRAY | VT_VARIANT;
    SAFEARRAYBOUND sab[2];
    sab[0].lLbound = 1; sab[0].cElements = row;
    sab[1].lLbound = 1; sab[1].cElements = col;
    arr.parray = SafeArrayCreate(VT_VARIANT, 2, sab);
   
    CString strTmp;
    for(i=0; i<row; i++)
    {
        for(j=0; j<col; j++)
        {
            strTmp=strArray[i*nColumn+j];
            VARIANT tmp;
            tmp.vt = VT_BSTR;
            tmp.bstrVal=strTmp.AllocSysString();
            // 添加数据到数组中
            long indices[] = {i+1,j+1};
            SafeArrayPutElement(arr.parray, indices, (void *)&tmp);
        }
    }

    int tableNum=0;
    int nCount=1;
    CString strName;  //Excel表完整路径
    strName=strfilename;

    // 调用Workbooks.Open()方法,打开一个已经存在的Workbook
    IDispatch *pXlBook;
    {
        VARIANT parm;
        parm.vt = VT_BSTR;
        CString pathname=GetCurrentPath();
        pathname=pathname+_T("template.xls");
        parm.bstrVal=pathname.AllocSysString();
        VARIANT result;
        VariantInit(&result);
        AutoWrap(DISPATCH_PROPERTYGET, &result, pXlBooks, L"Open", 1,parm);
        //AutoWrap(DISPATCH_PROPERTYGET, &result, pXlBooks, L"Add", 1,parm);
        pXlBook = result.pdispVal;
    }

    // 从Application.ActiveSheet属性获得Worksheet对象
    IDispatch *pXlSheet;
    {
        VARIANT result;
        VariantInit(&result);
        AutoWrap(DISPATCH_PROPERTYGET, &result, pXlApp, L"ActiveSheet", 0);
        pXlSheet = result.pdispVal;
    }

 CString strRange,sBeginCell,sEndCell;
    sEndCell.Format(_T("%d"),row);
    sBeginCell=_T("A1");
    TCHAR c1,c2;
#ifndef UNICODE
    c1='A';
    c2='';
#else
    c1=L'A';
    c2=L'';
#endif
    if(row>26)
    {
        c2=c1+row%26;
        c1=c1+row/26;
    }
    sEndCell=c2+sEndCell;
    sEndCell=c1+sEndCell;
 strRange=sBeginCell+_T(":")+sEndCell;
 TCHAR* cRange=strRange.GetBuffer();
    // 选择一个colxrow大小的Range
    IDispatch *pXlRange;
    {
        VARIANT parm;
        parm.vt = VT_BSTR;
        parm.bstrVal = ::SysAllocString(cRange);
        VARIANT result;
        VariantInit(&result);
        AutoWrap(DISPATCH_PROPERTYGET, &result, pXlSheet, L"Range", 1, parm);
        VariantClear(&parm);
        pXlRange = result.pdispVal;
    }

    //设置Range数据类型为文本
    CString strT;
    strT=_T("@");
    VARIANT parm;
    parm.vt = VT_BSTR;
    parm.bstrVal=strT.AllocSysString();
    AutoWrap(DISPATCH_PROPERTYPUT, 0, pXlRange, L"NumberFormatLocal",1,parm);
    //设置Range值
    AutoWrap(DISPATCH_PROPERTYPUT, &arr, pXlRange, L"Value",1,arr);
    //保存
    VARIANT parmP;
    parmP.vt = VT_BSTR;
    parmP.bstrVal=strName.AllocSysString();
    AutoWrap(DISPATCH_METHOD, NULL, pXlBook, L"SaveAs", 1,parmP);
    //关闭
    AutoWrap(DISPATCH_METHOD, NULL, pXlBook, L"Close", 0);
    VariantClear(&arr);
    pXlRange->Release();
    pXlSheet->Release();
    pXlBook->Release();
   
    //AutoWrap(DISPATCH_METHOD, NULL, pXlApp, L"SaveAs", 1,parmP);
    // 退出,调用Application.Quit()方法
    // 释放所有的接口以及变量
    AutoWrap(DISPATCH_METHOD, NULL, pXlApp, L"Quit", 0);
    pXlBooks->Release();
    pXlApp->Release();

    // 注销COM库
    //CoUninitialize();
 return col;

  • 0
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
【前言】 工作或学习中可能需要实现基于VC读\写Excel文件的功能,本人最近也遇到了该问题。中间虽经波折,但是最终还是找到了解决问题的办法。 在此跟大家分享,希望对跟我同样迷茫过的同学们有所帮助。 1、程序功能 1)打开一个excel文件; 2)显示到CListCtrl上; 3)新建一个Excel文件。 以上均在对话框中实现。 2、平台 VC++2010 3、实现方法 常用的Excel打开方式有两种 1)通过数据库打开; 2)OLE方式打开。 由于方式1)操作繁琐,经常出现莫名的错误,这里选用方式2). 4、准备步骤 首先新建一个Dialog窗体程序,添加list control和两个按钮 1)将ExcelLib文件夹拷贝到程序目录下; 2)将Export2Excel.h,Export2Excel.cpp两个文件添加到项目; 3)包含头文件,#include "ExcelLib/Export2Excel.h" 通过以上步骤在程序中引入了可以读取Excle文件的CExport2Excel; 5、打开excel文件 通过按钮点击打开 void CExcelTestDlg::OnBnClickedButtonOpenExcel() { //获取文件路径 CFileDialog* lpszOpenFile; CString szGetName; lpszOpenFile = new CFileDialog(TRUE,"","",OFN_FILEMUSTEXIST|OFN_HIDEREADONLY,"Excel File(*.xlsx;*.xls)|*.xls;*.xlsx",NULL); if (lpszOpenFile->DoModal()==IDOK) { szGetName = lpszOpenFile->GetPathName(); SetWindowText(szGetName); delete lpszOpenFile; } else return; //打开文件 //文件中包含多个sheet时,默认打开第一个sheet CExport2Excel Excel_example; Excel_example.OpenExcel(szGetName); //获取sheet个数 int iSheetNum = Excel_example.GetSheetsNumber(); //获取已使用表格行列数 int iRows = Excel_example.GetRowCount(); int iCols = Excel_example.GetColCount(); //获取单元格的内容 CString cs_temp = Excel_example.GetText(1,1); //AfxMessageBox(cs_temp); //List control上显示 //获取工作表列名(第一行) CStringArray m_HeadName; m_HeadName.Add(_T("ID")); for (int i=1;iGetItemCount()>0) { m_list.DeleteColumn(0); } //初始化ClistCtrl,加入列名 InitList(m_list,m_HeadName); //填入内容 //第一行是标题,所以从第2行开始 CString num; int pos; for (int row = 2;row<=iRows; row++) { pos = m_list.GetItemCount(); num.Format(_T("%d"),pos +1); m_list.InsertItem(pos,num); for (int colum=1;columDoModal()==IDOK) { szGetName = lpszOpenFile->GetPathName(); SetWindowText(szGetName); delete lpszOpenFile; } else return; //文件全名称 CString csFileName = szGetName; //需要添加的两个sheet的名称 CString csSheetName = "newSheet"; CString csSheetName2 = "newSheet2"; // 新建一个excel文件,自己写入文字 CExport2Excel Excel_example; //新建excel文件 Excel_example.CreateExcel(csFileName); //添加sheet,新加的sheet在前,也就是序号为1 Excel_example.CreateSheet(csSheetName); Excel_example.CreateSheet(csSheetName2); //操作最开始添加的sheet:(newSheet) Excel_example.SetSheet(2); //添加表头 Excel_example.WriteHeader(1,"第一列"); Excel_example.WriteHeader(2,"第二列"); //添加核心数据 Excel_example.WriteData(1,1,"数据1"); Excel_example.WriteData(1,2,"数据2"); //保存文件 Excel_example.Save(); //关闭文件 Excel_example.Close(); } 7、注意事项 1)一般单个Excel文件包含多个sheet,程序默认打开第一个; 2)指定操作sheet,使用Excel_example.SetSheet(2)函数; 3)打开文件时最左侧的sheet序号为1,新建excel时最新添加的sheet序号为1. 【后记】 本程序主要基于网络CSDN中---“Excel封装库V2.0”---完成,下载地址是:http://download.csdn.net/detail/yeah2000/3576494,在此表示感谢!同时, 1)在其基础上作了小改动,改正了几个小错误,添加了几个小接口; 2)添加了如何使用的例子,原程序是没有的; 3)详细的注释 发现不足之处,还请大家多多指教!
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值