VC++之Office自动化开发

去年底老板临时交给一个任务,为一个试验数据管理系统编写一个电子报告生成程序。因为老板也不怎么重视这个项目(钱少啊,呵呵),所以这个任务只好落在我这种小硕身上了。我也是两眼瞎,万事从头干。三个月的苦斗,还算圆满交差。用VC进行office自动化开发,网上有很多文章,我本不想在此画蛇添足。只是感于自己查资料时的苦痛,所以就厚着脸皮把一些心得拿出来见见阳光,有一些技术还是自己摸索出来的。最后,office自动化开发与我专业无丁点关系,希望此文不至于太班门弄斧让你看得难堪,如果尚有所帮助,那真是不胜荣幸(本文只涉及如何解决问题,没有原理,所以,Don’t ask me why)

1 前话  

本文中,只讲述如何使用VC++(就是MFC)进行WORD、EXCEL自动化开发。有几个问题先交待于此。
(1) office开发之VC与VB实现之比较。事实上,MFC实在不适合进行office自动化开发。相对VB而言,C++是一种强调类型的语言,这使得在实际编程时通常搞得你非常烦躁,不停地返回一些毫无意义的对象或指针(鸡肋啊!),而且整个程序会显得非常冗长。VB这种属性化的编程语言则非常适于自动化开发。
(2)office版本。在你提交帮助文档的时候,一定要说明你是针对哪个office版本开发的,否则不同的office版本可能会导致程序无法正常运行,因为不同版本的office提供的接口函数可能是不同的(特别是使用VC开发这个问题就比较明显,不知VB是否有同样的问题)。本文中所述的是office20003版本。
(3)两个重要的学习来源。初学office开发,两个不可忽视的学习来源是:word本身的VBA宏代码和微软官方网站。录制的VBA宏代码可以给我们提供非常有用的思路,而且通过调试可以获得很多所需的参数值(因为MFC通常并不支持很多VBA宏)。微软官方网提供了许多非常实用的技术文献(本文涉及的一些技术就来自于MSDN),如果英文基础还可以的话,建议到英文MSDN上去看看,那里的资料要比中国MSDN多。
(4)由于所有权的一些问题,所以不能提供源代码,也许会给阅读带来一些不便,这点希望谅解(而且那代码确实太臭,被我们的大师兄客气地批评得体无完肤,也就不敢拿出来献丑了)

2 自动化技术简述   

自动化(以前称为 OLE 自动化)是一种允许您利用现有程序的功能并将其合并到您自己的应用程序中的技术。自动化是建立在组件对象模型 (COM) 的基础上。IDipatch是自动化技术的核心。
VARIANT是另一个重要的概念。VARIANT结构是一个通用的数据类型,IDipatch利用它来传递参数和返回值。MFC小组创建了一个COleVariant类将VARIANT结构包装起来,并被很好地用于自动化客户和组件。需要注意的是COleVariant通常只支持short, long,float等数字类型,不支持int类型,使用时请注意强制转换。关于COleVariant类的更多信息可以参看MSDN。
关于COM技术和自动化技术更多信息请参看一些公开出版的书籍及微软官方网站资料。
另外提前交待的是:
(1)在进行自动化开发前,必须首先初始化COM库。通常一种便利的方法是在应用程序类的InitInstance()函数里添加以下语句:

if(!AfxOleInit())
     {
     AfxMessageBox("OLE Initialization Failed");
     return FALSE;
     }

(2)在自动化开发中,微软还提供了一个方便的COleVariant类型的数值,COleVariant((long)DISP_E_PARAMNOTFOUND,VT_ERROR)。通常,如果我们不清楚参数含义,均可用此值进行代替,系统会自动选择默认值传递给参数。以下行文中,我们以VarOpt代替这个COleVariant对象。

1  Word组件对象模型   
Microsoft Office Word 2003 对象是按层次顺序排列的,层次结构顶端的两个主类是 Application 类和 Document 类。这两个类非常重要,因为在大部分时间里,您要么是在使用 Word 应用程序本身,要么是以某种方式处理 Word 文档。Word 对象模型严格遵循用户界面。Application 对象提供整个应用程序的包装,每个 Document 对象表示单个 Word 文档。这些对象各自都有很多方法和属性,您可以使用这些方法和属性操作对象或与对象交互。
Application 对象。Application 对象表示 Word 应用程序,是其他所有对象的父级。它的所有成员通常作为一个整体应用于 Word。可以使用该对象的属性和方法来控制 Word 环境。
Document 对象。Document 对象是 Word 编程的中枢。当您打开文档或创建新文档时,就创建了新的 Document 对象,该对象被添加到 Word 的 Documents 集合中。焦点所在的文档叫做活动文档,由 Application 对象的 ActiveDocument 属性表示。
Selection 对象。Selection 对象表示当前选择的区域,Selection 对象只存在一个。在 Word 用户界面中执行某项操作(例如,对文本进行加粗)时,应首先选择或突出显示文本,然后应用格式设置。Selection 对象始终存在于文档中。如果未选中任何对象,它表示插入点。此外,该对象还可以表示多个不连续的文本块。
Range 对象。Range 对象表示文档中的一个连续的区域,由一个起始字符位置和一个结束字符位置定义。Range 对象的数量并不局限于一个。您可以在同一文档中定义多个 Range 对象。
Bookmark 对象。Bookmark 对象与 Range 对象类似,它也表示文档中的一个连续区域,并具有一个起始位置和一个结束位置。书签用于在文档中标记一个位置,或者用作文档中的文本容器。Bookmark 对象可以小到只有一个插入点,也可以大到整篇文档。您还可以在文档中定义多个书签。
对于Microsoft Office Word 2003,通常可以在..//Microsoft Office//OFFICE11// MSWORD.OLB获得相关接口类。常用的有_Application, Documents, _Document, Selection, Range等。此外,用于设置字体的_Font,段落格式的_ParagraphFormat,表格对象Tables及Table,目录对象TablesOfContents及TableOfContents等等也是常用的。

2  Word启动与退出     
使用Application 对象,关联接口、释放接口。具体代码如下:
_Application theExcelApp;
theExcelApp.CreateDispatch("word.application", NULL); //关联接口
退出
theExcelApp.Quit();  退出
theExcelApp.ReleaseDispatch();  //释放接口

3   Word表格操作    
使用单文档对象_Document,表格集合对象Tables,表格对象Table,行对象Rows,单元格对象Cell,列集合对象Columns,列对象Column,区域对象Range等可对表格进行操作。
插入表格。使用_Document:: GetTables返回一个Tables对象,使用Tables::Add在指定区域插入一个表格。
获取列对象。使用Table:: GetColumns返回一个Columns对象,使用Columns:: Item返回一个Column对象。从而可以列为对象进行操作。
单元格插入文字。使用Table:: Cell返回Cell对象,使用Cell:: GetRange返回区域对象,或者使用Cell::Select使得表格获得输入焦点,从而进行编辑。

4  文字转换为表格    
当需要把一个记事本(*.txt)文件转换为表格插入到Word文档中。最快捷的作法是将txt内容粘贴到word文档中,然后将内容转化为表格。步骤如下:
首先确定一个插入txt内容的Range对象。
使用Range::InsertFile函数。InsertFile函数声明为:
   void Range::InsertFile(LPCTSTR FileName, VARIANT* Range, VARIANT* ConfirmConversions, VARIANT* Link, VARIANT* Attachment)
参数说明如下:
FileName 插入文本路径。
Range 插入文本内容的Range对象,设为NULL
ConfirmConversions 确认转换,设为FALSE
Link 链接到文件,设为FALSE
Attachment 链接行为,设为FALSE
使用Range:: ConvertToTable转换文字为表格,返回一个Table对象。ConvertToTable函数声明为:
LPDISPATCH Range::ConvertToTable(VARIANT* Separator, VARIANT* NumRows, VARIANT* NumColumns, VARIANT* InitialColumnWidth, VARIANT* Format, VARIANT* ApplyBorders, VARIANT* ApplyShading, VARIANT* ApplyFont, VARIANT* ApplyColor, VARIANT* ApplyHeadingRows, VARIANT* ApplyLastRow, VARIANT* ApplyFirstColumn, VARIANT* ApplyLastColumn, VARIANT* AutoFit, VARIANT*, VARIANT* DefaultTableBehavior)
参数说明如下:
Separator 分隔符。通常设为1,即设置制表符为分隔符(如果采用其他分隔符,请适当修改)
NumRows 表格行数目
NumColumns 列数目
InitialColumnWidth,Format,ApplyBorders,ApplyShading,ApplyFont,ApplyColor,ApplyBorders,ApplyFirstColumn,ApplyLastColumn, DefaultTableBehavior,均可设为VarOpt,由系统默认
AutoFit 自动调整。设为0
也可利用Selection对象代替Range对象进行文本转换表格,调用函数与Range对象的函数名称一致,参数略有出入。

5 设置页码       
通常我们需要在任意指定页开始插入新页码。网上很多文章都是只能在第二页开始设置。以下介绍我通过观察VBA宏代码得到的一种插入页码的方法(实现方法当然可能不止一种,我曾在网上看到曾有一篇文章提及这个问题,但是他的代码不能正常运行,估计是作者发布文章的时候有些不小心有遗漏)。要点在于插入分节符和取消,并且要注意返回当前节。步骤如下:
0 在前一页使用Selection::InsertBreak插入分节符,参数值为2(参数值7为分页符)。
1 使用_Document::GetActiveWindow返回窗口Window对象。
2 使用Window:: GetActivePane返回当前活动Pane窗格对象
3 使用Pane::GetView返回View视图对象,View::SetType(long(3))。
4 使用SetSeekView(long(10))获得页眉页脚视图。
5 使用Selection::GetHeaderFooter()获得页眉页脚对象HeaderFooter。
6 使用HeaderFooter::SetLinkToPrevious(FALSE)取消“与上一节相同”。
7此时输入较点Selction停留在上一节的页脚处。使用View::SetSeekView(long(0))将返回到当前节的文字视图中。
8 使用View::SetSeekView(long(10))再次获得本节的页眉页脚视图。
9 使用Selection::GetHeaderFooter()获得页眉页脚对象HeaderFooter。
10 使用HeaderFooter::GetRange获得Range对象rangeheadfoot。
11 使用Range:: GetFields获得Fields对象。
12使用Fields:: Add获得Field对象,具体参数赋值为Add(rangeheadfoot,COleVariant(short(33)),varOpt,varOpt)。
13 使用Fields::GetPageNumbers()获得PageNumbers页码对象。
14使用PageNumbers对象的方法设置属性。特别要设置SetStartingNumber(long(1))。
PageNumbers对象的其他设置可参考如下:
SetNumberStyle(long(0));
 SetHeadingLevelForChapter(long(0));
 SetIncludeChapterNumber(FALSE);
 SetChapterPageSeparator(long(0));
 SetRestartNumberingAtSection(true);
15 通过Range对象rangeheadfoot设置页码居中及文字大小。
16 结束页码设置。使用View::SetSeekView(long(0))返回到文字视图。

6 插入Excel图表    
在Excel生成图表后,Word可将其嵌入文档中并改变其格式。用户可以通过双击图表对象激活,然后进行类似于Excel环境下的操作。具体操作如下:
使用Selection:: GetInlineShapes。获得内嵌区域集合对象InlineShapes。
使用InlineShapes::AddOLEObject插入表格,并获得内嵌区域对象InlineShape。AddOLEObject函数声明为:
LPDISPATCH AddOLEObject(VARIANT* ClassType, VARIANT* FileName, VARIANT* LinkToFile, VARIANT* DisplayAsIcon, VARIANT* IconFileName, VARIANT* IconIndex, VARIANT* IconLabel, VARIANT* Range)
参数说明如下:
ClassType 插入类型,若为Excel对象,设为COleVariant("Excel.Sheet.8")。
FileName 文件路径。
LinkToFile 链接到文件。设为FALSE。
DisplayAsIcon 显示为图标,设为FALSE。
IconFileName 文件名图标,设为VarOpt。
IconIndex 索引图标,设为VarOpt。
IconLabel 标签图标,设为VarOpt。
Range 区域,设为VarOpt。
使用InlineShape的方法SetHeight、SetWidth调整大小。这些方法的参数值都是打印格式下的英磅数值。

7 生成目录     
单文档对象_Document,目录集合对象TablesOfContents,目录对象TableOfContents及Range对象。操作流程如下:
使用_Document:: GetTablesOfContents返回TablesOfContents对象。
TablesOfContents::Add返回TableOfContents对象。
LPDISPATCH TablesOfContents::Add(LPDISPATCH Range, VARIANT* UseHeadingStyles, VARIANT* UpperHeadingLevel, VARIANT* LowerHeadingLevel, VARIANT* UseFields, VARIANT* TableID, VARIANT* RightAlignPageNumbers, VARIANT* IncludePageNumbers, VARIANT* AddedStyles, VARIANT* UseHyperlinks, VARIANT* HidePageNumbersInWeb, VARIANT* UseOutlineLevels)
参数说明如下:
Range 插入目录的Range对象。通常目录是文档生成结束时进行插入的,因此必须事先指定插入目录的区域Range对象。
UseHeadingStyles 使用制表符前导符,设为TRUE
UpperHeadingLevel 顶级目录,通常设为1
LowerHeadingLevel 底级目录,根据需要赋值
UseFields 使用区域,设为FALSE
TableID 目录索引,以1起始
RightAlignPageNumbers 页码右对齐,设为TRUE
IncludePageNumbers 包含页码,
AddedStyles 增加类型,设为NULL
UseHyperlinks 使用超链接,设为TRUE
HidePageNumbersInWeb Web页中隐藏页码,设为TRUE
UseOutlineLevels 使用大纲级别,设为TRUE
使用TableOfContents:: GetRange获取区域对象,进行其他例如文字大小控制等操作。
TableOfContents:: UpdatePageNumbers更新页码。


二 EXCEL篇及命名空间说明
1 Excel组件对象模型     
Microsoft Office Excel 2003文档中的数据是高度结构化的,因此Excel对象模型也具有层次结构并且简单明了。Excel 提供了数百个您可能需要与之交互的对象,但是最为重要的是以下四个对象:Application 对象、Workbook 对象、Worksheet 对象和Range 对象。很多工作都是围绕这四个对象进行的。
Application 对象。Application 对象表示 Excel 应用程序本身。Application 对象提供了大量有关正在运行的应用程序、应用于该实例的选项以及在该实例中打开的当前用户的对象的信息。
Workbook 对象。Workbook 类表示 Excel 应用程序内的单个工作簿。Application 类的许多成员同时也是 Workbook 类的成员。在这种情况下,属性应用于特定的工作簿(而非应用于活动工作簿)。
Worksheet 对象。虽然 Worksheet 类提供了大量成员,但大部分属性、方法和事件都与 Application 和/或 Workbook 类提供的成员相同或相似。Excel 提供 Sheets 集合作为 Workbook 对象的属性,但 Excel 中没有 Sheet 类。实际上,Sheets 集合的每个成员不是 Worksheet 对象就是 Chart 对象。
Range 对象。Range 对象是 Excel 应用程序中最常用的对象。在能够处理 Excel 内的任何范围之前,必须将它表示为 Range 对象,并处理该对象的方法和属性。Range 对象表示一个单元格、一行、一列、包含一个或多个单元格块(可以连续,也可以不连续)的单元格选定范围,甚至多个工作表中的一组单元格。
对于Microsoft Office Excel 2003,通常可以在..//Microsoft Office//OFFICE11// EXCEL.exe获得相关接口类。常用的有_Application, Workbooks, _Workbook, Worksheets, _Worksheet, Range,以及用于生成图表的_Chart等。

另外,使用MS Graph对象的技术同样可以生成数据图表。但是,对象写入大数据量非常缓慢的。MS Graph工作原理是每写入一个数据就要对图表进行更新,因此,MS Graph对于小数据制作图表是合适的(实现代码比EXCEL要少),但对于大数据这种工作原理是难以忍受的。尽管如此,EXCEL与MS Graph的接口函数却是非常相似的。

2 Excel启动与退出     
使用Application 对象,关联接口、释放接口。具体代码如下:
_Application theExcelApp;
theExcelApp.CreateDispatch("Excel.Application", NULL); //关联接口
退出
theExcelApp.Quit();  退出
theExcelApp.ReleaseDispatch();  //释放接口


3 Excel打开记事本(*.txt)         
通常,我们需要从文本(*.txt)文件中载入数据。Excel的Workbooks对象提供了打开文本的函数OpenText ()。OpenText()函数声明如下:
OpenText(LPCTSTR Filename, const VARIANT& Origin, const VARIANT& StartRow, const VARIANT& DataType, long TextQualifier, const VARIANT& ConsecutiveDelimiter, const VARIANT& Tab, const VARIANT& Semicolon, const VARIANT& Comma, const VARIANT& Space, const VARIANT& Other, const VARIANT& OtherChar, const VARIANT& FieldInfo, const VARIANT& TextVisualLayout, const VARIANT& DecimalSeparator, const VARIANT& ThousandsSeparator, const VARIANT& TrailingMinusNumbers, const VARIANT& Local)
参数说明如下:
Filename 文本路径。
Origin 文件原始格式。通常值为936,表示简体中文。
StartRow 导入起始始行。在本报告中第一行为标题行,导入起始行为2。
DataType 数据类型。值设为1。
TextQualifier 文本格式。值为1。
ConsecutiveDelimiter 连续分隔符。值为TRUE
Tab Tab分隔符。值为FALSE。
Semicolon 分号分隔符。值为FALSE。
Comma 逗号分隔符。值为FALSE。
Space 空格分隔符。本电子报告中通常以空格作为分隔符,因此值为TRUE。如若采用其他分隔符,请适当修改。
Other 其它分隔符。值为FALSE。
OtherChar 其他文本识别符号。值为NULL。
FieldInfo 区域信息。同载入文本列数据格式相关。设为VarOpt。
TextVisualLayout 文本可见版式。设为VarOpt。
DecimalSeparator 小数分隔符。设为VarOpt。
ThousandsSeparator 千位分隔符。设为VarOpt。
TrailingMinusNumbers 按负号跟踪负数。设为TRUE。
Local 本地数据。设为VarOpt。
以上各参数请根据适当需要修改,并根据调试VBA宏代码获得参数值。
要说明的是,这种方法载入数据将从B列往后分布。即,如果是TXT文本里有两列数据,那么载入EXCEL后,这两列数据将分布在B列与C列,而A列为空。这个原因我也一直不得其解(不知道是我们合作方提供的TXT文本本身设置问题还是别的问题)。这点请读者注意,也请高手指点。

4 获取Excel行数目      
载入记事本数据后,需要调用_Worksheet对象获得数据的行数目。具体代码如下:
_Worksheet ::GetUsedRange();
获得已用区域,返回Range对象。注意,这里不能调用_Worksheet ::GetRange();
Range:: GetRows(); 
获得行对象。返回Range对象。
Range:: GetCount();
获得行数目。
获得行数目在进行生成图表是很重要的。在生成图表时,载入源数据的区域时需要获得行数目。

5 生成Excel图表及格式          
使用对象。以下要设置其格式。
_Chart:: SetChartType 设置图表类型。如果使用无数据点平滑线散点图,值为73。其它图表类型请自己录制VBA宏然后调试获得参数值。
_Chart:: SetSourceData生成图表的原数据。传递一个Range对象。
_Chart:: SetHasLegend 标注。设为FALSE,不显示标注。
_Chart:: SetHasTitle 标题。设为TRUE,显示标题。
并假设获得行数目为432,则SetSourceData的参数值为Range(“B1”, “C432”)。

如果需要对网格线进行格式控制,需要调用以下函数:
_Char::Axes 返回Axis对象
Axis::SetHasMajorGridlines 设置主格线,TRUE
Axis::SetHasMinorGridlines 设置次格线,FALSE
Axis::GetMajorGridlines 获得主格线对象(前提是设置主格线为TRUE),返回Gridlines对象
Gridlines::GetBorder 获得边框对象,返回Borders对象
Borders::SetColorIndex 设置颜色,57表示黑色
Borders::SetLineStyle 设置线条格式,-4118表示虚线
Borders::SetWeight 设置粗细
以上Borders各参数值可根据需要适当修改。

Axis::SetCrossesAt 可设置坐标轴相交位置。通常需要Axis::GetMinimumScale获得最小刻度值,然后相交于最小刻度值。


6 设置标题文字及曲线格式    
使用AxisTitle ,,Font对象设置文字,包括设置文字上标等。注意,Excel并不提供类似于Word的Selection对象,要进行文字格式控制,通常需要用到Characters对象,即对指定文字进行格式控制。
使用Series,Borders对象可对曲线进行控制。可利用_Char:: SeriesCollection返回一个Series对象。

7 保存     
使用_Workbook:: SaveAs函数。具体参数值设置较为简单,参看VBA宏代码即可。此处略。

8 命名空间namespace     
由于许多Word的对象与Excel对象的名字是相同的,因此,必须使用名字空间将其区分。命名空间的使用方法很简单,在.h和.cpp文件分别添加
namespace mynamespace
{
   //Statement;
}
把名字有冲突的类的声明与实现放入namespace的作用域里。然后调用类是前面加命名空间作用符。
举例如下:Word和Excel都有_Application对象,如果不使用命名空间则会发生编译错误。
可在excel.h添加
namespace myExcel
{
     class _Application : public COleDispatchDriver
{
   //Statement;
}
}
在excel.cpp将所有_Application的方法放入到命名空间中。
namespace myExcel
{
(_Application的方法实现代码)
}
调用Excel的_Application对象类时,使用方法为
myExcel:: _Application _myExcelApp;
即声明该_Application属于myExcel命名空间作用域。
关于命名空间在C++教材的“高级主题部分”会有涉及。


  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值