在VC中使用智能指针操作Excel(转载)

48 篇文章 0 订阅

最近的一个工程中,需要将数据导入Excel表格中,项目经理知道我以前没有接触过操作Excel的经验,于是给了一段小程序给我,让我参考着做。

这段程序是使用智能指针操作Excel,在网络上找了一个星期,居然没有一片关于智能指针操作Excel的文章,只有Automation技术,而且所有介绍Automation技术的文章都是大同小异,并且代码多,说明少。没有任何帮助,光有一堆代码,对于理解和使用没有太大的帮助。在这样一个艰苦的条件下,我决定利用手中仅有的工具:Microsoft Excel Visual Basic 参考 Microsoft Visual Studio 2005的提示功能,摸索出一些利用智能指针操作Excel的心得,写出来,既是一次总结,也是一种分享,并且摸索还在继续,心得也还陆续会有。

 

一、背景说明

1Microsoft Excel Visual Basic 参考是提供给VB程序员的一个操作Excel的帮助,帮助中的对象、集合、方法、常量都已经在COM中实现,在VC中可以找到对应的实体。

2.既然是智能指针,那么绝大多数的操作都是“->”,然而,如果安装了Visual Assist X,使用“->”操作符的时候,是得不到任何提示的。这个时候,如果需要查看提示,则可以先使用“.”操作符,编译时再将“.”改成“->”。

 

二、Excel概念介绍

MFC工程结构的角度来看,Excel属于多文档视图结构,一个应用程序包含若干个文档,称作工作簿,每个文档中包含若干个工作表。从智能指针对象模型来看可以做如下划分:

1_ApplicationPtr :该对象即表示一个Excel应用程序。

2 WorkbooksPtr :在一个_ApplicationPtr对象中,包含一个工作簿集合。

3 _WorkbookPtr :在工作簿集合中包含若干的工作簿对象。一个工作簿对象对应一个xls文件。

4 WorksheetsPtr :在一个工作簿对象中,包含一个工作表集合。

5 _WorksheetPtr :在工作表集合中包含若干个工作表对象,工作表对象是操作Excel的基本单位。

6 Range :这是一个集合,工作表中单元格的集合,控制对单元格的操作。

 

三、准备工作

1 加载动态库。

#define OFFICEXP 1

#define OFFICE2000 2

 

// 如果使用OFFICE2000的内核,手动将此处改为#define OFFICE_VER OFFICE2000

#define OFFICE_VER OFFICEXP

 

#define USE_PROGID 1

#define USE_LIBID 0

 

#define _M2STR(x) #x

#define M2STR(x) _M2STR(x)

 

#ifndef MSDLL_PATH

          #if OFFICE_VER == OFFICEXP

              #define _MSDLL_PATH "C:/Program Files/Common Files/Microsoft Shared/Office11/MSO.DLL"

          #elif  OFFICE_VER == OFFICE2000

              #define   _MSDLL_PATH "C:/Program Files/Microsoft Office/Office/MSO9.dll"

          #endif

#else

          #define _MSDLL_PATH M2STR(MSDLL_PATH)

#endif

 

#import _MSDLL_PATH rename("RGB", "MSRGB")

 

#ifdef VBE6EXT_PATH

          #import M2STR(VBE6EXT_PATH)

#else

          #import "C:/Program Files/Common Files/Microsoft Shared/VBA/VBA6/VBE6EXT.OLB"

#endif

 

#if USE_PROGID

          #import "progid:Excel.Sheet" auto_search auto_rename rename_search_namespace("Office10")

#elif USE_LIBID

#import "libid:{00020813-0000-0000-C000-000000000046}" auto_search auto_rename version(1.3) lcid(0) no_search_namespace

#else

          #ifndef MSEXCEL_PATH

               #if  OFFICE_VER == OFFICEXP

                   #define   _MSEXCEL_PATH "C:/Program Files/Microsoft Office/Office11/excel.exe"

               #elif  OFFICE_VER == OFFICE2000

                   #define   _MSEXCEL_PATH "C:/Program Files/Microsoft Office/Office/excel.exe"

               #endif

          #else

               #define _MSEXCEL_PATH  M2STR(MSEXCEL_PATH)

          #endif

          #import _MSEXCEL_PATH auto_search auto_rename dual_interfaces

#endif

 

using namespace Excel;

 

2.初始化COM组件。

CoInitialize(NULL);

程序结束时记得释放资源CoUninitialize();

 

四、正式开始

1.操作Excel,首先要初始化一个应用程序实例,代码如下:

_ApplicationPtr pApp;

pApp.CreateInstance(L"Excel.Application");

pApp->PutVisible(0,VARIANT_TRUE);

使用ADO操作过数据库的人对代码的前两句不会感到陌生,初始化的实例不同而已,而第三句,则是使Excel应用程序显示出来,就像在“开始”菜单中运行Excel一样,可以看到一个打开的Excel程序,如果赋值VARIANT_FALSE则看不到应用程序,但是在任务管理器中已经创建了一个EXCEL进程,这是前两句的功劳。

程序结束前退出应用程序:

pBook.PutSaved(0,VARIANT_TRUE);

pApp->Quit();

 

2.在这个空白的应用实例中,需要创建一个工作簿(即文档)。代码如下:

WorkbooksPtr pBooks = pApp->GetWorkbooks();

_WorkbookPtr pBook  = pBooks->Add((long)xlWorkbook);

前面讲过,在应用实例中有一个工作簿集合,就算初始时集合是空的,它也是存在的,要创建一个工作簿,实际就是在这个集合中添加一个工作簿而已,第一句代码获得工作簿集合,第二句添加一个工作簿,并返回新创建工作簿的指针。由于一个工作簿对应一个“xls”文件,所以,大部分情况下我们在一个应用实例中都只会创建一个工作簿,这和习惯有关,但不是绝对,如果添加了多个,可以使用_WorkbookPtr Workbooks::GetItem(const _variant_t & Index)这个函数来获得每个工作簿的指针。

通过Studio的提示功能,我们看到Add函数的原型:

Excel::_WorkbookPtr Excel::Workbooks::Add(const _variant_t & Template,long lcid = 0)

Microsoft Excel帮助中,从“方法”,“A”,“Add”找到“应用于 Workbooks 对象的 Add 方法”,我们可以看到对第一个参数的说明(前面说过,由于VC缺少这类函数的说明,我们只能借助VB了),这个说明对VC同样适用。小弟水平有限,没有弄清第二个参数的所以然,姑且使用默认值,在这里不影响对Excel的操作,这个参数大概是与COM机制有关的某个东西吧。

 

3.上一步使用xlWorkbook参数添加了一个工作簿,因此,这个工作簿中默认有一个工作表,同样的道理,在工作簿中有一个工作表集合,要操作工作表,首先得到工作表集合。

SheetsPtr pSheets = pBook->GetWorksheets();

可以这样_WorksheetPtr pSheet = pSheets->GetItem(1);

也可以这样_WorksheetPtr pSheet = pBook->GetActiveSheet();

来得到默认创建的那个工作表。这是因为当前只有一个工组表,所以这个工组表就默认为激活的工作表(在工作簿中只会有一个工作表处于激活状态,就是当前操作的这个工作簿)。如果工作簿中有多个工组表,还是需要通过pSheets->GetItem函数获得工作表对象。补充,有些操作可以在工作表处于非激活状态下进行,这样,使用pSheets->GetItem获得工作表对象即可对工作表操作,但是有些操作必须是工作表处于激活状态下进行,因此,获得工作表对象后,还需要pSheet->Activate();激活它。

给工作表重命名吧:

pSheet->PutName("Exp One Sheet");//如果运行有错,可以pSheet->PutName(L"Exp One Sheet")

插入一个工作表,函数原型:

_WorksheetPtr Worksheets::Add(

const _variant_t &Before = vtMissing,     //在哪个工作表前插入

const _variant_t &After = vtMissing,      //在哪个工作表后插入

const _variant_t &Count = vtMissing,      //插入工组表个数

const _variant_t &Type = vtMissing)       //插入工作表类型

有意思的是,不光这个函数,其他的有默认值的参数的默认值都是vtMissing 。遗憾的是我没能找到vtMissing的具体说明,姑且先用着。

看下面的代码:

_WorksheetPtr pSheet = pSheets->GetItem(2);

VARIANT var;

     var.vt = VT_DISPATCH;

var.pdispVal = pSheet;

pSheets->Add();                  //在第一个工作表之前插入一个空白工作表

pSheets->Add(var);               //pSheet工作表之前插入一个空白工作表

pSheets->Add(vtMissing,var);     //pSheet工作表之后插入一个空白工作表

pSheets->Add(vtMissing,var,2);   //pSheet工作表之后插入两个空白工作表

这里仅仅涉及到_variant_t类型的使用,将不做说明。注意前两个参数的使用即可,其他类型的参数将报错。

 

4.下面将让你看到不同于C风格的代码操作工作表中的单元格。

pSheet->Range["A1"][vtMissing]->Value2 = "EXP A1";

pSheet->Range["A1"][vtMissing]->Interior->Color = RGB(255,0,0);

pSheet->Range["A1"][vtMissing]->Font->Name = L"隶书";

pSheet->Range["A1"][vtMissing]->Font->FontStyle = L"Bold Italic";

pSheet->Range["A1"][vtMissing]->Font->Size = 10;

如何?是不是有点像VB?只需要赋值就能改变对象的属性,以上代码等价于:

RangePtr range = pSheet->GetRange("A3",vtMissing);

range->PutValue2("EXP A3");

InteriorPtr interior = range->GetInterior();

interior->PutColor(RGB(255,0,0));

Excel::FontPtr font = range->GetFont();

font->PutName(L"隶书");

font->PutFontStyle(L"Bold Italic");

font->PutSize(10);

VC的程序员看到这段代码是不是就觉得亲切了,这是COM技术的魔力,要想知道为何,自己研究COM技术吧。

对上面的代码只做两点说明:

1Range["A1"][vtMissing]GetRange("A3",vtMissing)表示获得A3表示的单元格(用过Excel的人都知道A3表示什么),通过集合的形式表现出来,该集合只有一个单元格。如果把vtMissing换成B5,那么将获得一个由A3B5之间左右单元组成的集合。

2FontPtr之前的Excel::是必须的,缺少Excel::编译器会报错,提示不能确定是哪一个FontPtr,因为在不同的命名空间中存在若干个FontPtr。也许还存在其他的类型会有这样的情况,因此,要特别留意命名空间的限制。

 

五、小经验

1.基于COM技术,一般的,

I = A->GetP()可以等价成I = A->P

A->PutP(I)可以等价成A->P = I

2.在Microsoft Excel Visual Basic 参考中查找对象,方法和属性的时候,可以基于第一点将VB转换成VC。根据VB提供的参数类型,在VC中使用VARIANT类型承载。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值