您的位置:首页 > 其它

在VC中使用智能指针操作Excel

2008-10-10 12:02 211 查看

VC
中使用智能指针操作
Excel

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

这段程序是使用智能指针操作
Excel
,在网络上找了一个星期,居然没有一片关于智能指针操作
Excel
的文章,只有
Automation
技术,而且所有介绍
Automation
技术的文章都是大同小异,并且代码多,说明少。没有任何帮助,光有一堆代码,对于理解和使用没有太大的帮助。在这样一个艰苦的条件下,我决定利用手中仅有的工具:
Microsoft Excel Visual Basic
参考



Microsoft Visual Studio 2005

的提示功能,摸索出一些利用智能指针操作

Excel

的心得,写出来,既是一次总结,也是一种分享,并且摸索还在继续,心得也还陆续会有。

一、背景说明

1

Microsoft 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
技术吧。

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


1


Range
[
"A1"
][
vtMissing
]



GetRange
(
"A3"
,
vtMissing
)

表示获得
A3
表示的单元格(用过
Excel
的人都知道
A3
表示什么),通过集合的形式表现出来,该集合只有一个单元格。如果把
vtMissing
换成
B5
,那么将获得一个由
A3

B5
之间左右单元组成的集合。


2

FontPtr
之前的
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

类型承载。

如果有讲的不对的地方,欢迎加
MSN
和我交流:

bwmwm@live.cn

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: