最近公司有个项目要用到Excel的操作,于是自己就对VC中关于Excel的操作进行整理了下。而这里我是直接做成DLL方便他人调用的。

  1. 创建一个MFC Dll项目。

  2. 选择MFC扩展DLL。
  3. 在“类视图”---“添加类”---在MFC中选择“TypeLib中的MFC类”,按如图所示选择,并添加对应的类PS:由于我电脑上安装的是office2010,所以对应的Excel版本号是14.0,各位可以根据自己的情况选择。
  4. 删除这六个类的头文件中的第一句,如图,并将头文件添加到“stdafx.h"中
  5. 修改字符集,vs2010默认生成的是使用unicode字符集,这里我们把它修改为”使用多字节字符集“,这样能避免很多不必要的麻烦。
  6. 接下来进行编译,正常情况下会出现如下错误:这时候定位到警告处,在函数名之前加上下划线就OK了。如图:这样编译就没什么问题了。
  7. 接下就是直接添加导出函数来,这里我偷个懒直接到dllmain.cpp这个文件里面加了,大家可以根据自己的习惯来。

     extern "C" _declspec(dllexport) void ReadExcel(const CString& strPath,const CString& strFlag, const vector<CString>& vTarget,vector<CString>& vOutTarget)
    {
    CApplication _app;
    CWorkbook _book;
    CWorkbooks _books; CWorksheet _sheet;
    CWorksheets _sheets;
    CRange _rang; if (!_app.CreateDispatch(_T("Excel.Application")))
    {
    MessageBox(NULL,_T("Error!Creat Excel Application Server Faile!"),_T("Creat Excel Application Server"),MB_ICONERROR);
    exit();
    }
    _books = _app.get_Workbooks();
    _book = _books.Add(_variant_t(strPath)); _sheets = _book.get_Worksheets();
    _sheet = _sheets.get_Item(_variant_t("电力电缆井")); //获取行列数
    CRange _usedRang;
    _usedRang.AttachDispatch(_sheet.get_UsedRange(),TRUE);
    _rang.AttachDispatch(_usedRang.get_Columns(),TRUE);
    long nColumn = _rang.get_Count();//列
    _rang.ReleaseDispatch();
    _rang.AttachDispatch(_usedRang.get_Rows(),TRUE);
    long nRow = _rang.get_Count();//行
    _rang.ReleaseDispatch();
    _usedRang.ReleaseDispatch();
    //遍历
    _rang.AttachDispatch(_sheet.get_Cells(),TRUE);//获取所有单元格
    CString str;
    long nCurRow = ;
    long nCurColumn = ;
    //获取关键字所在的行列号
    for (long i = ; i <= nRow; ++i)
    {
    for (long j = ; j <= nColumn; ++j)
    {
    CRange _currentRang;
    _currentRang.AttachDispatch(_rang.get_Item(COleVariant((long)i),COleVariant((long)j)).pdispVal,TRUE);
    COleVariant vResult = _currentRang.get_Value2(); if (VT_BSTR == vResult.vt)//字符串
    {
    str = vResult.bstrVal;
    }
    else if (VT_INT==vResult.vt)
    {
    str.Format(_T("%d"),vResult.pintVal);
    }
    else if (VT_R8==vResult.vt)//8字节数字
    {
    str.Format(_T("%f"),vResult.dblVal);
    }
    else if (VT_DATE==vResult.vt)//时间格式
    {
    SYSTEMTIME st;
    VariantTimeToSystemTime(vResult.date,&st);
    }
    else if (VT_EMPTY==vResult.vt)//空单元格
    {
    str = "(NULL)";
    }
    _currentRang.ReleaseDispatch();
    if (strFlag==str)//直接使用goto语句跳出双重循环
    {
    nCurRow = i;
    nCurColumn = j;
    goto LOOPOUT;
    }
    }
    } LOOPOUT:
    vector<long> vNTarget;//目标列所在的列号
    for (long i = ;i <= nColumn;++i)
    {
    CRange _currentRang;
    _currentRang.AttachDispatch(_rang.get_Item(COleVariant((long)),COleVariant((long)i)).pdispVal,TRUE);
    COleVariant vResult = _currentRang.get_Value2(); if (VT_BSTR == vResult.vt)//字符串
    {
    str = vResult.bstrVal;
    }
    else if (VT_INT==vResult.vt)
    {
    str.Format(_T("%d"),vResult.pintVal);
    }
    else if (VT_R8==vResult.vt)//8字节数字
    {
    str.Format(_T("%f"),vResult.dblVal);
    }
    else if (VT_DATE==vResult.vt)//时间格式
    {
    SYSTEMTIME st;
    VariantTimeToSystemTime(vResult.date,&st);
    }
    else if (VT_EMPTY==vResult.vt)//空单元格
    {
    str = "(NULL)";
    }
    _currentRang.ReleaseDispatch();
    //对取出来的str和目标str进行配对
    for (vector<CString>::size_type j = ;j != vTarget.size(); ++j)
    {
    if (vTarget.at(j)==str)
    {
    vNTarget.push_back(i);
    break;
    }
    }
    }
    //接下来根据获取的行号nCurRow和列号vNTarget来读取指定内容
    for (vector<CString>::size_type i = ; i != vTarget.size(); ++i)
    {
    CRange _currentRang;
    _currentRang.AttachDispatch(_rang.get_Item(COleVariant((long)nCurRow),COleVariant((long)vNTarget.at(i))).pdispVal,TRUE);
    COleVariant vResult = _currentRang.get_Value2(); if (VT_BSTR == vResult.vt)//字符串
    {
    str = vResult.bstrVal;
    }
    else if (VT_INT==vResult.vt)
    {
    str.Format(_T("%d"),vResult.pintVal);
    }
    else if (VT_R8==vResult.vt)//8字节数字
    {
    str.Format(_T("%f"),vResult.dblVal);
    }
    else if (VT_DATE==vResult.vt)//时间格式
    {
    SYSTEMTIME st;
    VariantTimeToSystemTime(vResult.date,&st);
    }
    else if (VT_EMPTY==vResult.vt)//空单元格
    {
    str = "(NULL)";
    }
    _currentRang.ReleaseDispatch();
    vOutTarget.push_back(str);
    } _book.ReleaseDispatch();
    _books.ReleaseDispatch();
    151 _app.Quit();
     _app.ReleaseDispatch();
     }
    上述函数就是打开路径strPath的Excel文件,并通过标志符strFlag找到要读取的行,通过vTarget找到要读取的列,将读取的内容输出到vOutTarget中。这里我是默认表格的第一行就是存放的表头,大家可以根据自己的实际情况进行调整。
  8. 接下来再添加一个关于更新(即写某个单元格的函数)
     extern "C" _declspec(dllexport) void UpdateExcel(const CString& strPath,const CString& strFlag,const vector<CString>& vTarget,const vector<CString>& vInTarget)
    {
    CApplication _app;
    CWorkbook _book;
    CWorkbooks _books; CWorksheet _sheet;
    CWorksheets _sheets;
    CRange _rang; if (!_app.CreateDispatch(_T("Excel.Application")))
    {
    MessageBox(NULL,_T("Error!Creat Excel Application Server Faile!"),_T("Creat Excel Application Server"),MB_ICONERROR);
    exit();
    }
    _books = _app.get_Workbooks();
    _book = _books.Add(_variant_t(strPath)); _sheets = _book.get_Worksheets();
    _sheet = _sheets.get_Item(_variant_t("电力电缆井")); //获取行列数
    CRange _usedRang;
    _usedRang.AttachDispatch(_sheet.get_UsedRange(),TRUE);
    _rang.AttachDispatch(_usedRang.get_Columns(),TRUE);
    long nColumn = _rang.get_Count();//列
    _rang.ReleaseDispatch();
    _rang.AttachDispatch(_usedRang.get_Rows(),TRUE);
    long nRow = _rang.get_Count();//行
    _rang.ReleaseDispatch();
    _usedRang.ReleaseDispatch();
    //遍历
    _rang.AttachDispatch(_sheet.get_Cells(),TRUE);//获取所有单元格
    CString str;
    long nCurRow = ;
    long nCurColumn = ;
    //获取关键字所在的行列号
    for (long i = ; i <= nRow; ++i)
    {
    for (long j = ; j <= nColumn; ++j)
    {
    CRange _currentRang;
    _currentRang.AttachDispatch(_rang.get_Item(COleVariant((long)i),COleVariant((long)j)).pdispVal,TRUE);
    COleVariant vResult = _currentRang.get_Value2(); if (VT_BSTR == vResult.vt)//字符串
    {
    str = vResult.bstrVal;
    }
    else if (VT_INT==vResult.vt)
    {
    str.Format(_T("%d"),vResult.pintVal);
    }
    else if (VT_R8==vResult.vt)//8字节数字
    {
    str.Format(_T("%f"),vResult.dblVal);
    }
    else if (VT_DATE==vResult.vt)//时间格式
    {
    SYSTEMTIME st;
    VariantTimeToSystemTime(vResult.date,&st);
    }
    else if (VT_EMPTY==vResult.vt)//空单元格
    {
    str = "(NULL)";
    }
    _currentRang.ReleaseDispatch();
    if (strFlag==str)//直接使用goto语句跳出双重循环
    {
    nCurRow = i;
    nCurColumn = j;
    goto LOOPOUT;
    }
    }
    } LOOPOUT:
    vector<long> vNTarget;//目标列所在的列号
    for (long i = ;i <= nColumn;++i)
    {
    CRange _currentRang;
    _currentRang.AttachDispatch(_rang.get_Item(COleVariant((long)),COleVariant((long)i)).pdispVal,TRUE);
    COleVariant vResult = _currentRang.get_Value2(); if (VT_BSTR == vResult.vt)//字符串
    {
    str = vResult.bstrVal;
    }
    else if (VT_INT==vResult.vt)
    {
    str.Format(_T("%d"),vResult.pintVal);
    }
    else if (VT_R8==vResult.vt)//8字节数字
    {
    str.Format(_T("%f"),vResult.dblVal);
    }
    else if (VT_DATE==vResult.vt)//时间格式
    {
    SYSTEMTIME st;
    VariantTimeToSystemTime(vResult.date,&st);
    }
    else if (VT_EMPTY==vResult.vt)//空单元格
    {
    str = "(NULL)";
    }
    _currentRang.ReleaseDispatch();
    //对取出来的str和目标str进行配对
    for (vector<CString>::size_type j = ;j != vTarget.size(); ++j)
    {
    if (vTarget.at(j)==str)
    {
    vNTarget.push_back(i);
    break;
    }
    }
    }
    //更新指定的单元格
    for (vector<CString>::size_type i = ; i != vInTarget.size(); ++i)
    {
    _rang.put_Item(COleVariant(nCurRow),COleVariant(vNTarget.at(i)),COleVariant(vInTarget.at(i)));
    }
     _book.SaveCopyAs(COleVariant(strPath));
    _book.put_Saved(TRUE);
    _app.put_Visible(FALSE);
    _book.ReleaseDispatch();
    _books.ReleaseDispatch(); _app.Quit()
    _app.ReleaseDispatch();
     }
    参数的设置和上一个函数差不多。
  9. 接下来编译的时候,正常情况下会有一点小问题。这个问题如果你是基于对话框的MFC程序貌似是不会出现的,只有创建DLL或者ActiveX控件才会出现。这个问题也是烦恼了我好久,解决方法是先在文件头导入一个lib在编译,运气好的话就没什么问题了。运气不好还会出下如下问题。这个时候我们修改下项目属性把我标出来的选项改为否应该就没什么问题了。
  10. 最后编译完成通过。这样dll和lib就都生成好了,大家可以尽情的使用了。
  11. 差不多就这样了,至于其他的问题,比如如果直接创建的是基于对话框的MFc程序的话就更简单了。跟着步骤走就完事了。最后我是一个菜鸟,如果有什么问题也欢迎大家指教。

VS2010对Excel操作---DLL向的更多相关文章

  1. Excel操作 Microsoft.Office.Interop.Excel.dll的使用

    ----转载: http://www.cnblogs.com/lanjun/archive/2012/06/17/2552920.html 先说说题外话,前段时间近一个月,我一直在做单据导入功能,其中 ...

  2. MFC -- Excel操作简介(基于VS2010)

    一.添加与 Excel 操作相关的头文件 项目 -> 类向导,在右上方有一个下拉栏,选择其中的 类型库中的MFC类(T),即可看到下图所示界面,选择“文件”选项,然后在下方的位置选项中添加本地文 ...

  3. Npoi导入导出Excel操作

    之前公司的一个物流商系统需要实现对订单的批量导入和导出,翻阅了一些资料,最后考虑使用NPOI实现这个需求. 在winform上面实现excel操作:http://www.cnblogs.com/Cal ...

  4. Excel 操作类

    转载:http://www.cnblogs.com/fellowcheng/archive/2010/08/21/1805158.html ExcelHelper(Excel2007) Code hi ...

  5. VS2010 EXCEL2010 表格操作的编程实现

    参考: http://blog.csdn.net/wxfy1977/article/details/3847450(另外一种实现方式,数据库方式) http://blog.csdn.net/evkj2 ...

  6. C#封装的VSTO Excel操作类

    自己在用的Excel操作类,因为经常在工作中要操作Excel文件,可是使用vba实现起来实在是不方便,而且编写也很困难,拼接一个字符串都看的眼花. 这个时候C#出现了,发现使用C#来操作Excel非常 ...

  7. Excel报表开发(本节主要讲述导出到Excel操作)

    一.Excel导入到GridView以及数据库操作比较简单,这儿不做过多讲解,需要注意的有二点: 1.设置IMEX=1将强制混合数据转换为文本. 2.解决Excel驱动程序默认读取8行:将" ...

  8. Delphi Excel 操作大全

    Delphi Excel 操作大全 (一) 使用动态创建的方法首先创建 Excel 对象,使用ComObj:var ExcelApp: Variant;ExcelApp := CreateOleObj ...

  9. VS2010 C++环境下DLL和LIB文件目录及名称修改

    VS2010 C++环境下DLL和LIB文件目录及名称修改 转自:http://blog.csdn.net/archielau/article/details/8507581 DLL工程,Debug版 ...

随机推荐

  1. 在Azure中使用Load Runner测试TCP最大并发连接数

    对于Azure中的每一台虚机,它所能支持的TCP最大并发连接数是50万(参考微软官网: http://azure.microsoft.com/en-us/documentation/articles/ ...

  2. CPU acceleration status:HAXM must be updated(version 1.1.1<6.0.1)

    终于上手as了,感觉很爽 但是感觉也特闹心啊 还好有stackoverflow(这特么才是一个神奇的网站好吗) 废话少说 记录一下: 前面历经的磨难暂时不说了,就这个CPU acceleration ...

  3. EF中执行存储过程,获取output返回值

    EF不能直接支持执行存储过程,于是使用转化成执行SQL语句的形式,却怎么也获取不到output的值,折腾的好久,终于解决了,分享下曲折的经历: public int AddVote(int title ...

  4. PHP中 magic_quotes_gpc 和 magic_quotes_runtime 区别及其反斜线转义问题

    php中关于反斜线转义: php中数据的魔法引用函数 magic_quotes_gpc  或 magic_quotes_runtime     设置为on时,当数据遇到 单引号' 和 双引号" ...

  5. jQuery 参考手册 - 文档操作

    上传图片时页面崩溃..全部付之东流 addClass() after() append() appendTo() attr() before() clone() detach() empty() ha ...

  6. /etc/init.d/syslog: No such file or directory

    centos 6 使用的是 rsyslog 而 centos5 使用 syslog ,兩個不同版本使用軟體不同.因此,你得要修訂 /etc/rsyslog.conf 才行!軟體也變成 /etc/ini ...

  7. web前端开源小案例:立方体旋转

    HTML部分: <body class="body"> <div class="rect-wrap">   <!-- //舞台元素 ...

  8. ArcEngine中使用上下左右键移动地图

    转自愿文ArcEngine中使用上下左右键移动地图 因项目需要,需对mapcontrol控件响应上下左右键,从网上找的方法都一样,都值提到了需要设置axMapControl1的KeyIntercept ...

  9. 关于PHP程序员解决问题的能力

    这个话题老生长谈了,在面试中必然考核的能力中,我个人认为解决问题能力是排第一位的,比学习能力优先级更高.解决问题的能力既能看出程序员的思维能力,应变能力,探索能力等,又可以看出他的经验.如果解决问题能 ...

  10. jvm内存GC详解

    一.相关概念  a. 基本回收算法 1. 引用计数(Reference Counting)  比较古老的回收算法.原理是此对象有一个引用,即增加一个计数,删除一个引用则减少一个计数.垃圾回收时,只用收 ...