前几日对软件“文件整理助手”进行了完善。该软件有文本文件合并,文本文件内容的替换、插入、删除、为特定行首尾添加字符、清理空行等,以及文件批量替换、改名等功能。一同事见后,希望能对Word文件进行合并。尽管Word的“插入文件”可以实现这个功能,但不能在插入文件时调整插入的顺序,也不能控制插入的新文件是否另起一页。Word虽然功能强大,但还是有一定的局限性。当然,通过VBA录入脚本、编写宏代码也许可以实现这些复杂的功能。但囿于其缺乏通用性和移植性,对于不善于编程的人来说,还是存在诸多不便。因此,打算做一个“Word文档合并器”。刚做出这个决定时,以为很简单,因为Delphi的Servers组件页有WordApplication、WordDocument等控件,通过它们来控制全不是那么回事!以前做过涉及到Excel的小程序,没觉得有多难。首次跟Word打交道,竟给我来了个大大的下马威。以前用过函数,用过过程,也用过带参数的函数、带参数的过程。见过参数多的,但没见过打开、保存Word时尽然要用多达15个、16个参数的函数、过程。而且这些参数青一色地被定义为OleVariant类型,哪些应该是字符串,哪些应该是布尔型,或者专门为Word程序和文档定义的变量类型,没有详细的、系统的资料,只好摸着石头过河,慢慢研究了。经过几翻碰壁、几翻查证、几翻试验,把要实现的功能一步步拆解,逐一进行调试,通过后再重新组合起来试验。经过拆解、调试、组装三步曲之后,总算是完成了“Word文档合并器”这样一个小小的软件。为避免下次还重复这种繁琐的基础工作,现将有关技术要点总结于下:(本程序在Word2003中调试通过,其他版本未进行测试。网上找的一些资料在过程调用、函数语句及参数个数上有出入,可能与Word版本不一样有关。)说明:主窗体中放置以下三个与Word有关的控件:Word:TWordAWord应用程序接口Document1:TWordDWord文档oleShowDoc:TOleC用以显示Word文档【一】相关Word组件这里仅整理Delphi通过自身所提供的Server组件连接Office(Word)的有关资料,其他方法暂不研究。Delphi中提供的与操作Word有关的组件有共有5个,常用的有4个:1、TWordApplication对象。对应于MicrosoftWord应用程序,主要用来在Delphi程序中直接启动或关闭Word应用程序,建立或断开与Word程序的连接。2、TWordDocument对象。对应于Word文档,主要用来实现创建、销毁一个Word文档,文档的连接和断开,文档中的字符匹配查询,拼写和语法检查以及文档打印等功能。3、TWordFont对象。对应于Word的字体对象,用来设置Word文档中的字体属性。4、TWordParagraphFormat对象。对应于Word的段落对象,用来设置文档中的段落格式。【二】启动Word程序建立与Word应用程序的连接tryWord:TWordApplication。Create(nil);必加此句,否则WORD。Quit后无法再启用提示:“RPC服务器不可用”。word。CexceptApplication。MessageBox(无法连接Word。13101310请确认已正确安装了Word,并关闭了Word中的对话框!,提醒:,MbOkMBICONSTOP);E 说明:不要“Word:TWordApplication。Create(nil);”也可建立与Word应用程序的连接,启动Word应用程序,但 如果用Word。Quit或Word。Destroy退出或注销Word后,便无法再次与Word建立连接,提示“RPC服务器不可用”。添加 此句后,便可随心所欲地启动、退出Word应用程序。【三】创建Word文件新建空白文档的函数原型:{Word。Documents。Add(varTemplate:OleVvarNewTemplate:OleVvarDocumentType:OleVvarVisible:OleVariant):WordD } 由于在程序中需要多次调用Add函数,而函数中又不能直接使用变量的值,必须通过OleVariant型的变量名进行传递, 为避免繁琐的变量定义和赋值,我将其简化为AddDoc过程:WordApplication建立空白文档过程procedureAddDoc(word:TWordADot:SNewDot,DocVisible:Boolean);打开文件varTemplate,NewTemplate,DocumentType,Visible:OleVbeginTemplate:D使用模板的名称,NewTemplate:NewD新建文档的类型,True表示为模板,False表示为文档DocumentType:EmptyP文档类型,默认为空白文档Visible:DocV打捞的窗口是否可见Word。Documents。Add(Template,NewTemplate,DocumentType,Visible);【四】打开Word文件打开文件的函数原型:{Word。Documents。Open(varFileName:OleVvarConfirmConversions:OleVvarReadOnly:OleVvarAddToRecentFiles:OleVvarPasswordDocument:OleVvarPasswordTemplate:OleVvarRevert:OleVvarWritePasswordDocument:OleVvarWritePasswordTemplate:OleVvarFormat:OleVvarEncoding:OleVvarVisible:OleVvarOpenAndRepair:OleVvarDocumentDirection:OleVvarNoEncodingDialog:OleVariant):WordD}由于在程序中需要多次调用Open函数,我将其简化只有2个参数的OpenDoc过程:WordApplication打开文件过程procedureOpenDoc(word:TWordAsFileName:string);var打开文件的参数FileName,CfCversions,ReadOnly,AddToRctFiles,PswDocument,PswTemplate,Revert,WPswDocument,WPswTemplate,Format,Encoding,Visible,OpenAndRepair,DocumentDirection,NoEncodingDialog:OleVbegin创建对象tryWord:TWordApplication。Create(nil);word。CexceptApplication。MessageBox(本机可能没有正确安装WORD!,提醒:,MbOkMBICONSTOP);E打开文件Word。Visible:FileName:sFileNCfCversions:ReadOnly:FAddToRctFiles:PswDocument:;PswTemplate:;Revert:WPswDocument:;文档密码WPswTemplate:;模板密码Format:EmptyPEncoding:;Visible:FOpenAndRepair:EmptyPDocumentDirection:EmptyPNoEncodingDialog:EmptyPWord。Documents。open(FileName,CfCversions,ReadOnly,AddToRctFiles,PswDocument,PswTemplate,Revert,WPswDocument,WPswTemplate,Format,Encoding,Visible,OpenAndRepair,DocumentDirection,NoEncodingDialog);【五】连接Word文件将新建的或打开的word文档通过TWordDocument对象的ConnectTo方法与TWordapplication实例建立关联。varDocInx:OleVbeginDocInx:1;Document1。ConnectTo(Word。ActiveDocument);Document1。ConnectTo(Word。Documents。Item(DocInx));【六】保存Word文件Word保存文件过程的原型:{Word。ActiveDocument。SaveAs(varFileName:OleVvarFileFormat:OleVvarLockComments:OleVvarPassword:OleVvarAddToRecentFiles:OleVvarWritePassword:OleVvarReadOnlyRecommended:OleVvarEmbedTrueTypeFonts:OleVvarSaveNativePictureFormat:OleVvarSaveFormsData:OleVvarSaveAsAOCELetter:OleVvarEncoding:OleVvarInsertLineBreaks:OleVvarAllowSubstitutions:OleVvarLineEnding:OleVvarAddBiDiMarks:OleVariant);}为避免繁琐地使用保存文件过程,精简为:WordApplication保存文件过程procedureSaveDoc(word:TWordAsFileName:string);var保存文件的参数FileName,FileFormat,LockComments,Password,AddToRecentFiles,WritePassword,ReadOnlyRecommended,EmbedTrueTypeFonts,SaveNativePictureFormat,SaveFormsData,SaveAsAOCELetter,Encoding,InsertLineBreaks,AllowSubstitutions,LineEnding,AddBiDiMarks:OleVbeginFileName:sFileNFileFormat:EmptyPLockComments:EmptyPPassword:EmptyPAddToRecentFiles:EmptyPWritePassword:EmptyPReadOnlyRecommended:EmptyPEmbedTrueTypeFonts:EmptyPSaveNativePictureFormat:EmptyPSaveFormsData:EmptyPSaveAsAOCELetter:EmptyPEncoding:EmptyPInsertLineBreaks:EmptyPAllowSubstitutions:EmptyPLineEnding:EmptyPAddBiDiMarks:EmptyPWord。ActiveDocument。SaveAs(FileName,FileFormat,LockComments,Password,AddToRecentFiles,WritePassword,ReadOnlyRecommended,EmbedTrueTypeFonts,SaveNativePictureFormat,SaveFormsData,SaveAsAOCELetter,Encoding,InsertLineBreaks,AllowSubstitutions,LineEnding,AddBiDiMarks);如果通过TWordDocument对象保存文件,则比较简单:Document1。SaveAs(newFileName);【七】插入Word文件Word插入文件过程的原型:{InsertFile(constFileName:WideSvarRange:OleVvarConfirmConversions:OleVvarLink:OleVvarAttachment:OleVariant);}向打开的Word文件中插入外部文件vari:ImyRange,CfCversions,Link,Attachment:OleVs:WideSbeginfori:0toList。Items。Count1dobeginmyRange:EmptyPCfCversions:EmptyPLink:EmptyPAttachment:EmptyPmyType:wdPageBif(chkAddNewPage。Checked)and(i0)thenWord。Selection。InsertBreak(myType);s:List。Items〔i〕;Word。Selection。InsertFile(s,myRange,CfCversions,Link,Attachment);如果在插入文件时,要另起一页,则可在插入文件前执行:varmyType:OleVmyType:wdPageBWord。Selection。InsertBreak(myType);插入“分隔符”的类型定义如下:constwdSectionBreakNextPage00000002;wdSectionBreakContinuous00000003;wdSectionBreakEvenPage00000004;wdSectionBreakOddPage00000005;wdLineBreak00000006;wdPageBreak00000007;wdColumnBreak00000008;wdLineBreakClearLeft00000009;wdLineBreakClearRight0000000A;wdTextWrappingBreak0000000B;如果要插入字符串,可以使用如下方法:Document1。Characters。Last。S选择最后字符Document1。Range。InseflAfter(要输入的文字13);【八】关闭Word文件关闭打开的Word文件{procedureClose(varSaveChanges:OleVvarOriginalFormat:OleVvarRouteDocument:OleVariant);}varSaveChanges,OriginalFormat,RouteDocument:OleVbeginDocument1。DDocument1。CSaveChanges:FOriginalFormat:EmptyPRouteDocument:EmptyPWord。Documents。Close(SaveChanges,OriginalFormat,RouteDocument);【九】退出Word程序退出WordbeginWord。DWord。D WORD。Q 【十】其他相关操作varWORDAPP:TWORDdocument:TWordDitemindex:OleVtemplate,newtemplate,documenttype,visible:currrange:Rrow,col:Idirection:OleVdefaulttablebehvior,autofitbehvior:OleVcurrtable:Tmyrange:OleVsavefile:OleVbegintrytryWORDAPP:TWordApplication。Create(nil);WORDdocument:TWordDocument。Create(nil);exceptShowMessage(本机可能没有装WORD!);Eitemindex:1;WORDAPP。CWORDAPP。Visible:WORDAPP。Documents。AddOld(EmptyParam,EmptyParam);WORDdocument。ConnectTo(WORDAPP。Documents。Item(itemindex)asdocument);关闭拼写检查,因为这会浪费较多时间WORDAPP。Options。CheckSpellingAsYouType:FWORDAPP。Options。CheckGrammarAsYouType:F页面设置withWORDdocument。PageSetupdobeginPaperSize:wdPaperA4;wdPaperA400000007;;LeftMargin:WORDAPP。CentimetersToPoints(2。0);RightMargin:WORDAPP。CentimetersToPoints(2。0);TopMargin:WORDAPP。CentimetersToPoints(2。0);BottomMargin:WORDAPP。CentimetersToPoints(2。0);Orientation:wdOrientL横向打印centerHorizontally:T水平对齐方式写标题currrange:WORDdocument。Rcurrrange。InsertAfter(插入标题文字1310);currrange。Font。Size:14;currrange。Bold:1;currrange。ParagraphFormat。Alignment:wdAlignPageNumberC居中对齐加入表格direction:wdCollapseE定位到标题的下一行加入表格currrange。Collapse(direction);defaulttablebehvior:wdWord10ListB画边框线autofitbehvior:wdAutoFitWcol:DBGridEh1。DataSource。DataSet。FieldCount1;列数row:DBGridEh1。DataSource。DataSet。RecordCount1;行数下面两种方式也能通过myrange:WORDdocument。Content。End1;定位到标题的下一行加入表格currtable:WORDdocument。Tables。AddOld(WORDdocument。Range(myrange),row,col);currtable:WORDdocument。Tables。Add(currrange,row,col,defaulttablebehvior,autofitbehvior);WORDdocument。Tables。AddOld(currrange,row,col);currtable。Range。Paragraphs。Alignment:wdAlignParagraphL对齐方式左对齐写字段名及值withDBGridEh1。DataSource。DataSetdobeginforcol:1toFieldCount1do写字段名begincurrtable。Cell(1,col)。Range。Font。Name:宋体;currtable。Cell(1,col)。Range。Font。Size:12;currtable。Cell(1,col)。Range。Font。Bold:Integer(False);ifcol1thencurrtable。Cell(1,col)。Range。Text:序号elsecurrtable。Cell(1,col)。Range。Text:Fields〔col1〕。FieldNcurrtable。Columns。AutoFrow:2;FwhilenotEofdo写值beginforcol:1toFieldCount1dobeginifcol1thencurrtable。Cell(row,col)。Range。Text:IntToStr(row1)elsebegin if(Fields〔COL1〕。FieldName开始时间)or(Fields〔COL1〕。FieldName终止时间)then currtable。Cell(row,col)。Range。Text:FormatDateTime(yyyyMMdd,Fields〔COL 1〕。AsDateTime)elsecurrtable。Cell(row,col)。Range。Text:Fields〔COL1〕。AsScurrtable。Cell(row,col)。Range。Font。Size:11;currtable。Cell(row,col)。Range。Font。Name:宋体;currtable。Cell(row,col)。Range。Font。Bold:Integer(False);inc(row);Ncurrtable。Columns。AutoFfinallyifTrim(savefilename)thenbeginsavefile:savefilename。WORDdocument。SaveAs(savefile);WORDdocument。DWORDAPP。DFreeAndNil(WORDdocument);FreeAndNil(WORDAPP);