在VC中彻底玩转Excel(转)

    技术2022-05-20  40

    在VC中彻底玩转Excel    如今Excel是越来越重要了,在我们自己开发的程序中不免要和Excel打交道了。利用Automation技术,我们可以在不去了解数据库的情况下玩转Excel,而且你会发现一切竟如此轻松!    好了,咱们开始吧,我不喜欢用长篇累牍的代码来故弄玄虚,所以下面的代码都是切中要害的片段,总体上是个连贯的过程,包括启动Excel,读取数据,写入数据,以及最后的关闭Excel,其中还包括了很多人感兴趣的合并单元格的处理。    特别说明以下代码需要MFC的支持,而且工程中还要包含EXCEL2000的定义文件:EXCEL9.H,EXCEL9.CPP

    *****************************************************************************************************************

     //***** //变量定义 _Application app;     Workbooks books; _Workbook book; Worksheets sheets; _Worksheet sheet; Range range; Range iCell; LPDISPATCH lpDisp;     COleVariant vResult; COleVariant        covTrue((short)TRUE),        covFalse((short)FALSE),        covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR);       //***** //初始化COM的动态连接库 if(!AfxOleInit())   {        AfxMessageBox("无法初始化COM的动态连接库!");        return ;     }      //***** //创建Excel 2000服务器(启动Excel) if(!app.CreateDispatch("Excel.Application"))  {  AfxMessageBox("无法启动Excel服务器!");    return; }  app.SetVisible(TRUE);          //使Excel可见 app.SetUserControl(TRUE);      //允许其它用户控制Excel 

     //*****    //打开c://1.xls books.AttachDispatch(app.GetWorkbooks()); lpDisp = books.Open("C:1.xls",         covOptional, covOptional, covOptional, covOptional, covOptional,   covOptional, covOptional, covOptional, covOptional, covOptional,   covOptional, covOptional );            //***** //得到Workbook book.AttachDispatch(lpDisp);   //***** //得到Worksheets  sheets.AttachDispatch(book.GetWorksheets());    //***** //得到当前活跃sheet //如果有单元格正处于编辑状态中,此操作不能返回,会一直等待 lpDisp=book.GetActiveSheet(); sheet.AttachDispatch(lpDisp);  

     //***** //读取已经使用区域的信息,包括已经使用的行数、列数、起始行、起始列 Range usedRange; usedRange.AttachDispatch(sheet.GetUsedRange()); range.AttachDispatch(usedRange.GetRows()); long iRowNum=range.GetCount();                   //已经使用的行数  range.AttachDispatch(usedRange.GetColumns()); long iColNum=range.GetCount();                   //已经使用的列数   long iStartRow=usedRange.GetRow();               //已使用区域的起始行,从1开始 long iStartCol=usedRange.GetColumn();            //已使用区域的起始列,从1开始     //***** //读取第一个单元格的值 range.AttachDispatch(sheet.GetCells());  range.AttachDispatch(range.GetItem (COleVariant((long)1),COleVariant((long)1)).pdispVal ); COleVariant vResult =range.GetValue(); CString str; if(vResult.vt == VT_BSTR)       //字符串 {  str=vResult.bstrVal; } else if (vResult.vt==VT_R8)     //8字节的数字  {  str.Format("%f",vResult.dblVal); } else if(vResult.vt==VT_DATE)    //时间格式 {  SYSTEMTIME st;     VariantTimeToSystemTime(&vResult.date, &st); } else if(vResult.vt==VT_EMPTY)   //单元格空的 {  str=""; }     //***** //读取第一个单元格的对齐方式,数据类型:VT_I4 //读取水平对齐方式 range.AttachDispatch(sheet.GetCells()); iCell.AttachDispatch((range.GetItem (COleVariant(long(1)), COleVariant(long(1)))).pdispVal); vResult.lVal=0; vResult=iCell.GetHorizontalAlignment(); if(vResult.lVal!=0) {  switch (vResult.lVal)  {  case 1:      //默认   break;  case -4108:  //居中   break;  case -4131 : //靠左   break;  case -4152 : //靠右   break;  }  }   //垂直对齐方式 iCell.AttachDispatch((range.GetItem (COleVariant(long(1)), COleVariant(long(1)))).pdispVal); vResult.lVal=0; vResult=iCell.GetVerticalAlignment(); if(vResult.lVal!=0) {  switch (vResult.lVal)  {  case -4160 :  //靠上   break;  case -4108 :  //居中   break;  case -4107 :  //靠下   break;  }  }    //***** //设置第一个单元格的值"HI,EXCEL!" range.SetItem(COleVariant(1),COleVariant(1),COleVariant("HI,EXCEL!"));  

     //***** //设置第一个单元格字体颜色:红色 Font font; range.AttachDispatch(sheet.GetCells()); range.AttachDispatch((range.GetItem (COleVariant(long(1)), COleVariant(long(1)))).pdispVal); font.SetColor(COleVariant((long)0xFF0000));     //***** //合并单元格的处理 //包括判断第一个单元格是否为合并单元格,以及将第一个单元格进行合并 Range unionRange; range.AttachDispatch(sheet.GetCells());  unionRange.AttachDispatch(range.GetItem (COleVariant((long)1),COleVariant((long)1)).pdispVal );   vResult=unionRange.GetMergeCells();     if(vResult.boolVal==-1)             //是合并的单元格     {  //合并单元格的行数   range.AttachDispatch (unionRange.GetRows ());  long iUnionRowNum=range.GetCount ();      //合并单元格的列数  range.AttachDispatch (unionRange.GetColumns ());  long iUnionColumnNum=range.GetCount ();       //合并区域的起始行,列  long iUnionStartRow=unionRange.GetRow();       //起始行,从1开始  long iUnionStartCol=unionRange.GetColumn();    //起始列,从1开始   } else if(vResult.boolVal==0)    {//不是合并的单元格}  //将第一个单元格合并成2行,3列 range.AttachDispatch(sheet.GetCells());  unionRange.AttachDispatch(range.GetItem (COleVariant((long)1),COleVariant((long)1)).pdispVal ); unionRange.AttachDispatch(unionRange.GetResize(COleVariant((long)2),COleVariant((long)3))); unionRange.Merge(COleVariant((long)0));   //合并单元格   //***** //将文件保存为2.xls  book.SaveAs(COleVariant("C:2.xls"),covOptional,covOptional, //  covOptional,covOptional,covOptional,0,//  covOptional,covOptional,covOptional,covOptional);       //***** //关闭所有的book,退出Excel  book.Close (covOptional,COleVariant(OutFilename),covOptional); books.Close();       app.Quit();    

    关于excel.h和excel.cpp,要注意版本问题.比如对excel xp, 类库是直接包含在excel.exe中. 因此你只要用加入类(add class)的方法,直接选中excel.exe,并选择对话框中的常用的几个类(如Rang)就可以编程了. 千万不要选所有的类,否则太大了.

    作者:unionsoft 2003-11-29 11:00:34)

    修改字体颜色的那段漏了一句,应为:   //*****   //设置第一个单元格字体颜色:红色   Font font;   range.AttachDispatch(sheet.GetCells());   range.AttachDispatch((range.GetItem (COleVariant(long(1)), COleVariant(long(1)))).pdispVal);   font.AttachDispatch (range.GetFont ());   font.SetColor(COleVariant((long)0xFF0000));

    作者:zhengkuo 2003-12-2 10:50:00)

    如果,程序既要安装在2000的计算机上,也可能安装在XP的机子上,有的用户还用97,(指的都是office),可能会出现版本问题------其中比较麻烦的是--在app.quit()后,仍旧存在excel进程,如果这样?怎么解决?作者:zhengkuo 2003-12-2 10:51:50)

    请教高手,能否用vb控制excel做成dll,在arx中进行调用,因为毕竟vb与excel亲切作者:unionsoft 2004-1-30 11:06:58)

     

    以下是引用zhengkuo在2003-12-2 10:50:00的发言:如果,程序既要安装在2000的计算机上,也可能安装在XP的机子上,有的用户还用97,(指的都是office),可能会出现版本问题------其中比较麻烦的是--在app.quit()后,仍旧存在excel进程,如果这样?怎么解决?兼容性问题:

            office2002-office97是向下兼容的,只要你不使用office2002中的新特性,程序在这些office版本中都好用

    Excel程序不能退出的问题:      1 . 不要使用#import导入类型库,如:#import "c://excel//excel.olb"      2 . 程序结束时,确保所有IDispatch都释放了,如:app.ReleaseDispatch (); 

    作者:easypower 2004-5-14 10:00:39)

    還是不明白如何得到excel.cpp和excel.h這兩個文件,請指教 作者:jack1975 2004-6-24 16:43:03)

    有版本问题时,可以加一个判断:1、首先通过  exlApp得到版本,比如9.0,10.0,11.0,10.0以后的版本注意open函数的参数为15个,即最后在增加两个covOptional,即可,另外,补充一下,判断当前是否有excel应用程序在运行,使之更舒服一些: ::CLSIDFromProgID(L"Excel.Application",&clsid); // from registry if(::GetActiveObject(clsid, NULL,&pUnk) == S_OK)

    {  VERIFY(pUnk->QueryInterface(IID_IDispatch,(void**) &pDisp) == S_OK);  ExcelApp.AttachDispatch(pDisp);  pUnk->Release();  } else

     {  if(!ExcelApp.CreateDispatch("Excel.Application")) {   AfxMessageBox("Excel program not found");   return 0;  }

     }

     

    作者:unionsoft 2004-12-13 12:36:09)

     

    以下是引用zhmary在2004-12-10 11:30:10的发言:请问各位高手,从哪里得οnclick=Cswf() height=22 alt=Flash图片 src="skins/default/ubb/swf.gif" width=23 border=0>到Excel.cp...

    Excel.cpp和Excel.h是从Excel的类型库中获取的,类型库类似C++中的头文件,包括接口,方法,属性的定义;类型库在Excel的安装目录可以找到,Excel的版本不同,这个类型库也不一样,如下所示: Excel 95 and prior   :   xl5en32.olb Excel 97             :   excel8.olb Excel 2000           :   excel9.olb Excel 2002           :   excel.exe

    具体的获取方法:

    1 . 使用VC++新建立一个基于MFC的EXE工程

    2 . 点击菜单"查看"-->"建立类向导",此时会弹全"MFC ClassWizard"对话框

    3 . 点击"Add Class"-->"From a type libray",指定Excel的type libray,在Excel的安装目录下可以找到,如:"D://Microsoft Office//Office//EXCEL9.OLB"

    4 . 在弹出的对话框中选择所需的类,按"确定",Excel.cpp和Excel.h就产生了。

    作者:yfy2003 2004-12-23 17:41:57)

    lpDisp = books.Open("C:1.xls",         covOptional, covOptional, covOptional, covOptional, covOptional,   covOptional, covOptional, covOptional, covOptional, covOptional,   covOptional, covOptional );   

    编译显示错误:

    error C2660: 'Open' : function does not take 13 parameters

    作者:xux4618 2005-4-6 8:48:51)

    请问怎样才能增加一个工作表?作者:梦幻神话 2005-4-6 15:50:40)

     Workbooks.AttachDispatch(ExcelApp.GetWorkbooks());  Workbook.AttachDispatch(Workbooks.Open(FileName,covOptional, covOptional,covOptional, covOptional,covOptional, covOptional,covOptional, covOptional,covOptional, covOptional,covOptional, covOptional)); Worksheets.AttachDispatch(Workbook.GetWorksheets()); Worksheet.AttachDispatch(Worksheets.GetItem((COleVariant((long)1))));  Range.AttachDispatch(Worksheet.GetCells()); iCell.AttachDispatch(Range.GetItem(COleVariant((long)2),COleVariant((long)2)).pdispVal);

     vResult = iCell.GetMergeCells();

     if(vResult.boolVal == -1) {  AfxMessageBox("Yes");    Range.AttachDispatch(iCell.GetRows());  long row_num = Range.GetCount();

      Range.AttachDispatch(iCell.GetColumns());  long col_num = Range.GetCount();

      CString str;  str.Format("%d×%d",row_num,col_num);  AfxMessageBox(str); }

    请教:为什么str得到的结果都是1×1?(求合并单元格的原始行数和列数)。

    谢谢。。。。。。。。。。

    作者:unionsoft 2005-4-9 10:13:25)

    首先你的Cells(2,2)是否处于合并单元格中 其次,你缺少了个关键语句:iCell.GetMergeArea()),你可以参考下面的语句

    Range UnionRange;

    UnionRange.AttachDispatch(iCell.GetMergeArea());  //先要获取合并区域

    range.AttachDispatch (UnionRange.GetRows ());

    long iRowNum = range.GetCount();             //合并单元格行数

    range.AttachDispatch (UnionRange.GetColumns ());

    long iColNum = Range.GetCount();            //合并单元格列数

       

    我就想在excel里 实现,第一行为标题(居中) 第二行为时间(左对齐),下面为9列数据.最后一行为签名(左对齐) 怎么办?  回复  更多评论  # re: [转]在VC中彻底玩转Excel2006-11-26 17:24 | 好学者

    修改字体颜色的那段漏了一句,应为: //***** //设置第一个单元格字体颜色:红色 Font font; range.AttachDispatch(sheet.GetCells()); range.AttachDispatch((range.GetItem (COleVariant(long(1)), COleVariant(long(1)))).pdispVal); font.AttachDispatch (range.GetFont ()); font.SetColor(COleVariant((long)0xFF0000));

    这样改了还是不能用,Font是哪儿来的哦!  回复  更多评论  # re: [转]在VC中彻底玩转Excel2007-10-19 15:11 | 唐特

    Font 和 _Application,Workbooks等等这些东西一样, 是打开excel.exe(excel9.olb) 的时候添加的class  回复  更多评论  # re: [转]在VC中彻底玩转Excel2008-01-16 11:19 | HU

    请教一个问题,现在出现了OFFICE 2007,在2000中做的程序,在2007下无法启动EXCEL服务,就是CreateDispatch失败。 但是,运行的环境既有2007,也会有老版本的EXCEL,这种情况下,怎么办?怎么让程序更有通用性?谢谢!!!!  回复  更多评论  # re: [转]在VC中彻底玩转Excel2008-01-25 10:55 | 想飞的星期

    请问怎么知道我createdispatch出来的excel已经关闭了??我还想每次重用同一个excel进程,怎么办?  回复  更多评论  # re: [转]在VC中彻底玩转Excel2008-03-28 14:56 | lamorak

    你好,请教一下,我在做数据导入到excel中的程序,将3个文件的数据导入没有问题,我为了做测试,将这3个文件复制了44次,就是145个文件的数据,总共有6702314行,200M的数据量,转换到75M数据的时候,Excel就不给转了,就弹出Excel中“value,range,GetIDsOfNames”函数出错,Excel大小有限制吗?我这个差不多就是做9×3文件循环数据插入,第10个循环就错了。我每次转一个文件后都加了Sleep(2000),能帮忙解决一下吗?  回复  更多评论

    本文来自博客,转载请标明出处:http://blog.csdn.net/vicozo/archive/2009/04/12/4067804.aspx


    最新回复(0)