unionsoft 发表于 2003-10-28 11:58:00

[原创]在VC中彻底玩转Excel

本帖最后由 作者 于 2004-10-8 8:21:13 编辑 <br /><br />                                 如今Excel是越来越重要了,在我们自己开发的程序中不免要和Excel打交道了。利用Automation技术,我们可以在不去了解<BR>数据库的情况下玩转Excel,而且你会发现一切竟如此轻松!<BR>                                好了,咱们开始吧,我不喜欢用长篇累牍的代码来故弄玄虚,所以下面的代码都是切中要害的片段,总体上是个连贯的过程,<BR>包括启动Excel,读取数据,写入数据,以及最后的关闭Excel,其中还包括了很多人感兴趣的合并单元格的处理。<BR>                                特别说明以下代码需要MFC的支持,而且工程中还要包含EXCEL2000的定义文件:EXCEL9.H,EXCEL9.CPP<BR><BR>*****************************************************************************************************************<BR><BR>        //*****<BR>        //变量定义<BR>        _Application        app;                                <BR>        Workbooks        books;<BR>        _Workbook        book;<BR>        Worksheets        sheets;<BR>        _Worksheet        sheet;<BR>        Range        range;<BR>        Range        iCell;<BR>        LPDISPATCH        lpDisp;                                <BR>        COleVariant        vResult;<BR>        COleVariant<BR>                                                                covTrue((short)TRUE),<BR>                                                                covFalse((short)FALSE),<BR>                                                                covOptional((long)DISP_E_PARAMNOTFOUND,        VT_ERROR);                                <BR>        <BR>        <BR>        //*****<BR>        //初始化COM的动态连接库<BR>        if(!AfxOleInit())                <BR>        {<BR>                                                                AfxMessageBox("无法初始化COM的动态连接库!");<BR>                                                                return        ;<BR>                                        }                        <BR>        <BR>        <BR>        //*****<BR>        //创建Excel        2000服务器(启动Excel)<BR>        if(!app.CreateDispatch("Excel.Application"))        <BR>        {<BR>                AfxMessageBox("无法启动Excel服务器!");<BR>                                return;<BR>        }<BR>        <BR>        app.SetVisible(TRUE);                                                                                //使Excel可见<BR>        app.SetUserControl(TRUE);                                                //允许其它用户控制Excel<BR>        <BR><BR>        //*****                        <BR>        //打开c:\1.xls<BR>        books.AttachDispatch(app.GetWorkbooks());<BR>        lpDisp        =        books.Open("C:\\1.xls",                                                <BR>                        covOptional,        covOptional,        covOptional,        covOptional,        covOptional,<BR>                        covOptional,        covOptional,        covOptional,        covOptional,        covOptional,<BR>                        covOptional,        covOptional        );                                <BR>                <BR>                                        <BR>        //*****<BR>        //得到Workbook<BR>        book.AttachDispatch(lpDisp);<BR>        <BR>        <BR>        //*****<BR>        //得到Worksheets        <BR>        sheets.AttachDispatch(book.GetWorksheets());        <BR>        <BR>        <BR>        //*****<BR>        //得到当前活跃sheet<BR>        //如果有单元格正处于编辑状态中,此操作不能返回,会一直等待<BR>        lpDisp=book.GetActiveSheet();<BR>        sheet.AttachDispatch(lpDisp);        <BR>                <BR><BR>        //*****<BR>        //读取已经使用区域的信息,包括已经使用的行数、列数、起始行、起始列<BR>        Range        usedRange;<BR>        usedRange.AttachDispatch(sheet.GetUsedRange());<BR>        range.AttachDispatch(usedRange.GetRows());<BR>        long        iRowNum=range.GetCount();                                                                                                                                                        //已经使用的行数<BR>        <BR>        range.AttachDispatch(usedRange.GetColumns());<BR>        long        iColNum=range.GetCount();                                                                                                                                                        //已经使用的列数<BR>                <BR>        long        iStartRow=usedRange.GetRow();                                                                                                                        //已使用区域的起始行,从1开始<BR>        long        iStartCol=usedRange.GetColumn();                                                                                                //已使用区域的起始列,从1开始<BR>                <BR>                <BR>        //*****<BR>        //读取第一个单元格的值<BR>        range.AttachDispatch(sheet.GetCells());        <BR>        range.AttachDispatch(range.GetItem        (COleVariant((long)1),COleVariant((long)1)).pdispVal        );<BR>        COleVariant        vResult        =range.GetValue();<BR>        CString        str;<BR>        if(vResult.vt        ==        VT_BSTR)                                                        //字符串<BR>        {<BR>                str=vResult.bstrVal;<BR>        }<BR>        else        if        (vResult.vt==VT_R8)                                        //8字节的数字        <BR>        {<BR>                str.Format("%f",vResult.dblVal);<BR>        }<BR>        else        if(vResult.vt==VT_DATE)                                //时间格式<BR>        {<BR>                SYSTEMTIME        st;<BR>                                        VariantTimeToSystemTime(&amp;vResult.date,        &amp;st);<BR>        }<BR>        else        if(vResult.vt==VT_EMPTY)                        //单元格空的<BR>        {<BR>                str="";<BR>        }                <BR>        <BR>        <BR>        //*****<BR>        //读取第一个单元格的对齐方式,数据类型:VT_I4<BR>        //读取水平对齐方式<BR>        range.AttachDispatch(sheet.GetCells());<BR>        iCell.AttachDispatch((range.GetItem        (COleVariant(long(1)),        COleVariant(long(1)))).pdispVal);<BR>        vResult.lVal=0;<BR>        vResult=iCell.GetHorizontalAlignment();<BR>        if(vResult.lVal!=0)<BR>        {<BR>                switch        (vResult.lVal)<BR>                {<BR>                case        1:                                                //默认<BR>                        break;<BR>                case        -4108:                //居中<BR>                        break;<BR>                case        -4131        :        //靠左<BR>                        break;<BR>                case        -4152        :        //靠右<BR>                        break;<BR>                }<BR>        <BR>        }<BR>                <BR>        //垂直对齐方式<BR>        iCell.AttachDispatch((range.GetItem        (COleVariant(long(1)),        COleVariant(long(1)))).pdispVal);<BR>        vResult.lVal=0;<BR>        vResult=iCell.GetVerticalAlignment();<BR>        if(vResult.lVal!=0)<BR>        {<BR>                switch        (vResult.lVal)<BR>                {<BR>                case        -4160        :                //靠上<BR>                        break;<BR>                case        -4108        :                //居中<BR>                        break;<BR>                case        -4107        :                //靠下<BR>                        break;<BR>                }<BR>        <BR>        }<BR>        <BR>                <BR>        //*****<BR>        //设置第一个单元格的值"HI,EXCEL!"<BR>        range.SetItem(COleVariant(1),COleVariant(1),COleVariant("HI,EXCEL!"));        <BR>        <BR><BR>        //*****<BR>        //设置第一个单元格字体颜色:红色<BR>        Font        font;<BR>        range.AttachDispatch(sheet.GetCells());<BR>        range.AttachDispatch((range.GetItem        (COleVariant(long(1)),        COleVariant(long(1)))).pdispVal);<BR>        font.SetColor(COleVariant((long)0xFF0000));                <BR>        <BR>        <BR>        //*****<BR>        //合并单元格的处理<BR>        //包括判断第一个单元格是否为合并单元格,以及将第一个单元格进行合并<BR>        Range        unionRange;<BR>        range.AttachDispatch(sheet.GetCells());        <BR>        unionRange.AttachDispatch(range.GetItem        (COleVariant((long)1),COleVariant((long)1)).pdispVal        );<BR>                <BR>        vResult=unionRange.GetMergeCells();                                <BR>        if(vResult.boolVal==-1)                                                                                                        //是合并的单元格                                <BR>        {<BR>                //合并单元格的行数        <BR>                range.AttachDispatch        (unionRange.GetRows        ());<BR>                long        iUnionRowNum=range.GetCount        ();        <BR>                        <BR>                //合并单元格的列数<BR>                range.AttachDispatch        (unionRange.GetColumns        ());<BR>                long        iUnionColumnNum=range.GetCount        ();                        <BR>                <BR>                //合并区域的起始行,列<BR>                long        iUnionStartRow=unionRange.GetRow();                                                        //起始行,从1开始<BR>                long        iUnionStartCol=unionRange.GetColumn();                                //起始列,从1开始<BR>                <BR>        }<BR>        else        if(vResult.boolVal==0)                        <BR>        {//不是合并的单元格}<BR>        <BR>        //将第一个单元格合并成2行,3列<BR>        range.AttachDispatch(sheet.GetCells());        <BR>        unionRange.AttachDispatch(range.GetItem        (COleVariant((long)1),COleVariant((long)1)).pdispVal        );<BR>        unionRange.AttachDispatch(unionRange.GetResize(COleVariant((long)2),COleVariant((long)3)));<BR>        unionRange.Merge(COleVariant((long)0));                        //合并单元格<BR>        <BR>        <BR>        //*****<BR>        //将文件保存为2.xls        <BR>        book.SaveAs(COleVariant("C:\\2.xls"),covOptional,covOptional,        \<BR>                covOptional,covOptional,covOptional,0,\<BR>                covOptional,covOptional,covOptional,covOptional);                <BR>                <BR>                <BR>        //*****<BR>        //关闭所有的book,退出Excel        <BR>        book.Close        (covOptional,COleVariant(OutFilename),covOptional);<BR>        books.Close();                                                <BR>        app.Quit();                                                                        <BR>        <BR>*****************************************************************************************************************<BR>                                                                                                                                                                                                                                                                                                                        <BR>                                                                                                                                                                                                                                                                作者                :龚敏<BR>                                                                                                                                                                                                                                                                        Email        :        <A href="mailto:truetable@truetable.com" target="_blank" >truetable@truetable.com</A><BR>                                                                                                                                                                                                                                                                        主页                :<A href="http://www.truetable.com/" target="_blank" >http://www.truetable.com</A>                                                                                                                                                                                                                                                                       


                                                                                                                                                                                                                                                                                                                                                                                <BR><BR>

leeyeafu 发表于 2003-10-28 12:50:00

先给适当奖励,本想加入精华,但那样刚到明经的朋友就看不到了,过段时间再说吧。

goldenshin 发表于 2003-10-28 14:49:00

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

unionsoft 发表于 2003-11-29 11:00:00

修改字体颜色的那段漏了一句,应为:
//*****
//设置第一个单元格字体颜色:红色
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:00

请教高手,能否用vb控制excel做成dll,在arx中进行调用,因为毕竟vb与excel亲切

unionsoft 发表于 2004-1-30 11:06:00

zhengkuo发表于2003-12-2 10:50:00static/image/common/back.gif如果,程序既要安装在2000的计算机上,也可能安装在XP的机子上,有的用户还用97,(指的都是office),可能会出现版本问题------其中比较麻烦的是--在app.quit()后,仍旧存在excel进程,如果这样




兼容性问题:


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


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

easypower 发表于 2004-5-14 10:00:00

還是不明白如何得到excel.cpp和excel.h這兩個文件,請指教

jack1975 发表于 2004-6-24 16:43:00

有版本问题时,可以加一个判断:1、首先通过       exlApp得到版本,比如9.0,10.0,11.0,10.0以后的版本注意open函数的参数为15个,即最后在增加两个covOptional,即可,另外,补充一下,判断当前是否有excel应用程序在运行,使之更舒服一些:


::CLSIDFromProgID(L"Excel.Application",&amp;clsid); // from registry<BR>        if(::GetActiveObject(clsid, NULL,&amp;pUnk) == S_OK)


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


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

liuxinmin 发表于 2004-6-29 14:03:00

高手,真的厉害
页: [1] 2 3 4
查看完整版本: [原创]在VC中彻底玩转Excel