在实际应用中,编程者往往喜欢程序能自动生成word说明文档,说明程序运行的状况或运行的结果;或者程序能提取数据库的内容生成word表格,使用户能方便的查看和修改,打印。但是VC++中调用word的确不容易,特别是对word中各种函数的使用,本文以作者的工作经验详细介绍一下如何调用word和进行word表格的填写,有同样需求的编友也可查看一下MSDN中的Automation Microsoft Office 97 and Microsoft office 2000。下面介绍以Microsoft Office 2000 Word为例。
类型库
一个类型库是一个提供COM对象功能信息的文件或文件的一部分,而且类型库包含了有关类的信息。注意,类型库并不存储实际的对象,而只是存储有关这些对象的信息。类型库详细说明了一个自动化客户机为对象需要调用的方法和属性的信息,比如说它详细的描述了接受或返回的值。
每一个Microsoft Office应用程序都在一个dll文件中提供了多种类型库资源,这种dll文件叫做目标库(*.olb)。下面的表列出了Microsoft Office 97和Microsoft office 2000类型库文件的名字。
|
在VC++调用word中,我们需要导入msword9.olb才能使用word中的各种功能。
用VC++创建一个自动化客户机
The COleDispatchDriver Class
vc提供了一个COleDispatchDriver类来处理自动化对象的IDispatch接口,关于COleDispatchDrive类的属性和函数请读者自行查阅类库,这里就不再赘述。
1.创建一个新的Dialog-Base MFC AppWizard Exe工程名为"WordAutomation";注意在MFC AppWizard - Step 2 of 4中的Automaiton选项上打上勾,如下图所示:
图一 使用AppWizard生成基于对话框的的工程,如上所示选上Automation选项。
2.在View菜单中,点击ClassWizard,然后进入Automation标签中点击Add Class,选择From A Type Library。找到Microsoft Office 2000类型库msword.olb,选择_Application,_Document,_Documents,Selection四个类,如有其他需要(例如画表也可选择其他的类)。
图二 使用ClassWizard从类型库中创建所需的类
这个过程会在工程中创建两个新的文件:msword8.h和msword8.cpp,这些文件构成了word类型库的所选择的类和类的成员函数。在ClassView视图中查看从word类型库生成的所有的类,然后双击_Application类来查看它的定义,你就会注意到_Application类是来源于COleDispatchDriver。
// _Application wrapper class class _Application : public COleDispatchDriver { ...... }
至于这些类和成员函数的功能和用法,我有一个简便的方法,那就是使用word中工具菜单中的宏的录制功能,把你所想要进行的操作先用宏录制下来,然后查看这些宏代码,你就会清楚要使用哪个类,哪些成员函数和成员函数应该带些什么参数了。虽然这些代码都是用VB写的,但你可以很容易的转换成VC++中的代码。
图三 进行word写的VBA宏代码
VC++会自动地在WordAutomation.cpp中的CWordAutomationApp::InitInstance()中生成如下的代码,使得COM的服务能有效。
if (!AfxOleInit()) { AfxMessageBox(IDP_OLE_INIT_FAILED); return FALSE; }
3.接下来选择对话框资源IDD_WORDAUTOMATION_DIALOG,在对话框中增加一个按钮命名为IDC_WORD_NEW,在按钮的处理函数中增加如下的代码:
COleVariant vTrue((short)TRUE), vFalse((short)FALSE), vOpt((long)DISP_E_PARAMNOTFOUND, VT_ERROR); //开始一个新的Microsoft Word 2000实例 _Application oWordApp; if (!oWordApp.CreateDispatch("Word.Application", NULL)) { AfxMessageBox("CreateDispatch failed.", MB_OK | MB_SETFOREGROUND); return; } //创建一个新的word文档 Documents oDocs; _Document oDoc; oDocs = oWordApp.GetDocuments(); oDoc = oDocs.Add(vOpt, vOpt, vOpt, vOpt); //如果是word 98,则应该带两个参数,如oDocs.Add(vOpt, vOpt) //把文本添加到word文档 Selection oSel; oSel = oWordApp.GetSelection(); oSel.TypeText("one"); oSel.TypeParagraph(); oSel.TypeText("two"); oSel.TypeParagraph(); oSel.TypeText("three"); //保存word文档 _Document oActiveDoc; oActiveDoc = oWordApp.GetActiveDocument(); oActiveDoc.SaveAs(COleVariant("c://doc1.doc"), COleVariant((short)0), vFalse, COleVariant(""), vTrue, COleVariant(""), vFalse, vFalse, vFalse, vFalse, vFalse); //退出word应用程序 oWordApp.Quit(vOpt, vOpt, vOpt);
4.在WoreAutomation.cpp中增加包含头文件msword9.h。
#include "msword9.h" //或者在word98中是 "msword8.h"
注意:增加的头文件应该在stdafx.h文件之后,否则就会导致编译错误。
利用VC++进行word表格的填写
我们先利用word的宏的录制功能,把所要进行的表格填写的操作录制下来,查看VBA的代码如下所示:
图四 进行word表格填写的VBA宏代码
其中MoveDown为Selection类所定义对象的成员函数,Unit:=wdParagraph, Count:=1为其所带参数的值。wdParagraph宏的数值是多少,可使用宏的调试器在调试中查出。在VC++中MoveDown所带参数为三个,在VBA的帮助中我们可以查到第三个参数不写会有一个默认值,但在VC++中这个参数不能省略,怎么知道它数值是多少呢?我们可以照葫芦画瓜把它写进宏中,Extend:=wdMove,再在调试中查出,其余的类推。
再次选择对话框资源IDD_WORDAUTOMATION_DIALOG,在对话框中增加一个按钮命名为IDC_WORD_TABLEWRITE,在按钮的处理函数中增加如下的代码:
BeginWaitCursor(); COleVariant vTrue((short)TRUE), vFalse((short)FALSE), vOpt((long)DISP_E_PARAMNOTFOUND, VT_ERROR); _Application m_App;//定义Word提供的应用程序对象; Documents m_Docs;//定义Word提供的文档对象; Selection m_Sel;//定义Word提供的选择对象; m_Docs.ReleaseDispatch(); m_Sel.ReleaseDispatch(); m_App.m_bAutoRelease=true; if(!m_App.CreateDispatch("Word.Application")) { AfxMessageBox("创建Word2000服务失败!"); exit(1); } //下面是定义VARIANT变量; COleVariant varFilePath("word表格.doc"); COleVariant varstrNull(""); COleVariant varZero((short)0); COleVariant varTrue(short(1),VT_BOOL); COleVariant varFalse(short(0),VT_BOOL); m_Docs.AttachDispatch(m_App.GetDocuments());//将Documents类对象m_Docs和Idispatch接口关联起来; m_Docs.Open(varFilePath,varFalse,varFalse,varFalse, varstrNull,varstrNull,varFalse,varstrNull, varstrNull,varTrue,varTrue,varTrue); //打开Word文档; m_Sel.AttachDispatch(m_App.GetSelection());//将Selection类对象m_Sel和Idispatch接口关联起来; m_Sel.MoveDown(COleVariant((short)4),COleVariant((short)1),COleVariant((short)0)); m_Sel.MoveDown(COleVariant((short)5),COleVariant((short)1),COleVariant((short)0)); m_Sel.TypeText("123456789"); m_Sel.MoveRight(COleVariant((short)1),COleVariant((short)1),COleVariant((short)0)); m_Sel.TypeText("李明"); m_Sel.MoveRight(COleVariant((short)1),COleVariant((short)1),COleVariant((short)0)); m_Sel.TypeText("25"); m_Sel.MoveRight(COleVariant((short)1),COleVariant((short)1),COleVariant((short)0)); m_Sel.TypeText("技术员"); m_Sel.MoveRight(COleVariant((short)1),COleVariant((short)1),COleVariant((short)0)); m_Sel.TypeText("本科"); m_Sel.MoveRight(COleVariant((short)1),COleVariant((short)1),COleVariant((short)0)); m_Sel.TypeText("上海市虹口区民主路315号"); //save word file _Document oActiveDoc; oActiveDoc = m_App.GetActiveDocument(); oActiveDoc.SaveAs(COleVariant("c://填写后表格.doc"), COleVariant((short)0), vFalse, COleVariant(""), vTrue, COleVariant(""), vFalse, vFalse, vFalse, vFalse, vFalse); m_Docs.ReleaseDispatch();//断开关联; m_Sel.ReleaseDispatch(); //退出WORD m_App.Quit(vOpt, vOpt, vOpt); m_App.Quit(vOpt, vOpt, vOpt); m_App.ReleaseDispatch(); EndWaitCursor(); MessageBox("word表格填写完毕!","提示",MB_ICONEXCLAMATION);