Delphi与Word之间的融合技术

问题:Delphi与Word之间的融合技术 ( 积分:0, 回复:325, 阅读:37835 )
分类:OLE/Automation ( 版主:g622, satanmonkey )
来自:yzhshi, 时间:2001-11-18 17:52:00, ID:737517[显示:小字体 | 大字体]
          
Delphi与Word之间的融合技术
(yzhshi@263.net)
一、VBA代码含义 Microsoft Word是一个集成化环境,是美国微软公司的字处理系统,但是它决不仅仅是一个字处 理系统,它集成了Microsoft Visual Basic,可以通过编程来实现对Word功能的扩展。 Microsoft Visual Basic在word中的代码即Word的宏,通过编写Word宏,可实现一些文档处理的 自动化,如实现文档的自动备份、存盘等,可扩展Word文档的功能,因此,能够充分利用Word的 特性,甚至使Word成为自己软件的一部分。 Word的宏既有有利的一部分,因为它能够帮助我们实现文档的自动化,但是Word的宏也不是纯粹 的有利,有时它可能危害我们的文档、计算机系统甚至网络,从最开始的Taiwan NO1宏病毒到现 在的Melissa宏病毒,从最开始的简单的提示,耗尽系统资源到现在的乱发电子邮件,将个人的 信息发送到网络上,甚至向硬盘的Autoexec.bat(自动批处理文件)中添加Deltree C: -y,破坏 整个Windows系统。 二、Word中内嵌的Com技术 可以说Word是对Com技术支持最好的软件,这样说似乎是太极端了一点,但是Word提供的强大的编 程接口技术却能够是我们通过程序控制Word的任何一部分。无论是文件的打开、存盘、打印还是文 档中表格的自动绘制。 通过编程软件,可以灵活的操纵word,这里只以Borland Delphi为例,进行详细描述: 1、 在Delphi中调用Word软件/文件的方法 在Word中调用Word软件,归纳起来有三种方法: 。通过Delphi的控件TOleContainer 将Word嵌入 a.使用Delphi提供的Servers控件调用Word,使用Word的属性 b.通过真正的Com技术,将Office软件目录中文件MSWORD9.OLB中的类库全部导入Delphi中, 利用Com技术编程 c.使用CreateOleObject将启动Word,然后以Ole方式对Word进行控制。 2、 对几种方法的难易程度的判别 a.通过Delphi的控件TOleContainer 将Word嵌入 这是最简单的Ole嵌入,能够直接将Word文档调用,只需要使用ToleContainer.Run就可以将Word文 档直接启动。且这样启动的Word文档与Delphi程序是一个整体(从界面上看),但是它存在不可克 服的缺点,即不能通过Delphi控制Word文档,也就不能实现将灵活操纵Word的目的。 b.使用Delphi提供的Servers控件调用Word,使用Word的属性 使用Delphi的Servers控件来操纵Word,在编程时Delphi能够实现代码提示,总体上看能够较好的实 现Delphi对Word的控制,但是还有一些Word的功能不能在Delphi中调用(比如自己编写的VBA宏代码)。 且实现功能时本来在VBA代码中可选则参数在Delphi调用的时候必须添加,否则,连编译都不能通过。 本方式启动的Word与Delphi程序分属两个窗体。 此办法仅能作为一个参考。 c.通过真正的Com技术,将Office软件目录中文件MSWORD9.OLB中的类库全部导入Delphi中, 利用Com技术编程 利用真正的Com技术,将MsWord9.OLD文件类库导入,然后利用Com技术进行使用。 整体上类似使用Delphi的Servers控件,稍微比Servers控件麻烦,优缺点与Servers控件相同。 d.使用CreateOleObject将启动Word,然后以Ole方式对Word进行控制。 本办法是使用以CreateOleObjects方式调用Word,实际上还是Ole,但是这种方式能够真正做到完全 控制Word文件,能够使用Word的所有属性,包括自己编写的VBA宏代码。 与Servers控件和com技术相比,本方法能够真正地使用Word的各种属性,和在VBA中编写自己的代码 基本一样,可以缺省的代码也不需要使用。 本方式启动的Word与Delphi程序分属两个窗体。 缺点是使用本方法没有Delphi代码提示,所有异常处理均需要自己编写,可能编写时探索性知识比较多。 三、Word宏编辑器 Word能够真正地进行VBA代码的编辑,可以编写窗体、函数。 进入Word宏编辑器的方法:工具->宏->Visual Basic编辑器,可进入Visual Basic编辑器界面。 Word的Visual Basic编辑器界面和真正的Visual Basic编辑器基本相同,在此不再向详述。 在VBA代码中,可以添加用户窗体、模块、类模块。用户窗体、模块、类模块的概念和Visual Basic 完全相同。注释也与Visual Basic完全相同。 可以将光标停留在窗体、模块的任何一个子程序上,直接按“F5”运行当前子程序。 四、Word的宏的概述 Word充分地将文档编辑和VB结合起来,真正地实现文档的自动化。使用Word编程,类似于使用 Visual Basic,所不同的是,在Word中,能够直接运行某一个子程序,直接看见结果,Word的宏, 只能解释运行,而Visual Basic,现在已经能够编写成真正的机器码,从代码的保护上来说,应该尽 可能地减少Word的VBA代码数量,尤其是关键的代码。 VBA宏,可分成四种: 1、 和命令名相同的宏 如FileSave,FileOpen,如果在VBA代码中包含与Word同名的函数,则直接执行这些VBA代码,忽略Word 本身的命令。 2、 Word内特定的宏 这些宏包含AutoExec(启动 Word 或加载全局模板)、AutoNew(每次新建文档时)、AutoOpen(每次打 开已有文档时)、AutoClose(每次关闭文档时),AutoExit(退出 Word 或卸载全局模板时)。 如果VBA代码中含有这些名称的函数,则满足相应的条件,相应代码就自动执行。 3、 相应事件的VBA宏 这些宏是由事件触发的宏,如Document_Close在文档关闭的时候触发事件,Document_New在新建文档的时 候触发,Document_Open在打开文档的时候触发。 4、 独立的宏 自己编写的VBA代码,即不属于上面几种情况的VBA代码,可以被其他VBA代码调用,更重要的是,可以被 其他程序调用。 这样,我们就可以屏弃Word自动执行的宏,通过Delphi直接调用相应宏来达到目的。 五、Word命令宏的详细描述 Word本身的命令函数包含很多,但是无论是word联机帮助还是MSDN帮助,都没有这方面的介绍,因此只能 凭自己的实验取探索,初步探测的函数如下: 宏名 解释 注释 FileNew 新建 FileNewDefault 新建空白文档 FileSaveAs 另存为 FileOpen 打开 FileClose 关闭 FilePrint 打印 FilePrintPreview 打印预览 ToolsCustomize 工具栏里面的自定义 ToolsOptions 工具选项 ToolsRevisions 突出显示修订 ToolsReviewRevisions 接受或拒绝修订 ToolsRevisionMarksAccept 接受修订 ToolsRevisionMarksReject 拒绝修订 ToolsRevisionMarksToggle 修订 ToolsMacro 宏 ToolsRecordMacroToggle 录制新宏 ViewSecurity 安全性 ViewVBCode 查看VB编辑器环境 FileTemplates 模板和可加载项 ToolsProtectUnprotectDocument 解除对文档的保护 InsertHyperlink 插入超级链接 EditHyperlink 编辑超级链接 DeleteHyperlink 删除超级链接 EditLinks 查看、删除链接 EditPasteAsHyperlink 粘贴超级链接 FormatStyle 样式 EditBookMark 书签
来自:yzhshi, 时间:2001-11-18 17:54:00, ID:737522
这是我自己写的,结合自己的经验,在这里贡献出来,供大家共享。
里面有很多用词、观点也许不是特别确切,希望大家指出。
过几天再将一些具体的代码写出来(目前没有仔细整理)。
来自:yzhshi, 时间:2001-11-18 18:04:00, ID:737532
          
OleWord时一些用用的代码
yzhshi@263.net
一、Delphi程序启动Word 采用CreateOleObjects的方法来启动Word,调用VBA代码,具体实现过程为: 首先使用GetActiveOleObject('Word.Application')判断当前内存中是否存在Word程序,如果存在, 则直接连接,如果没有Word程序,则使用CreateOleObject('Word.Application')启动Word 二、Delphi程序新建Word文稿 格式:WordDocuments.Add(Template,NewTemplate,DocumentType,Visible) Template: 使用模板的名称, NewTemplate: 新建文档的类型,True表示为模板,False表示为文档 DocumentType: 文档类型,默认为空白文档 Visible: 打捞的窗口是否可见 举例:Doc_Handle:=Word_Ole.Documents.Add(Template:='C:/Temlate.dot',NewTemplate:=False); 三、Delphi程序打开Word文稿 格式:WordDocuments.Open(FileName,ConfirmConversions,ReadOnly,PassWordDocument, PasswordTemplate,Revent,WritePasswordDocument,WritePassWordTemplate, Format,Encoding,Visible) FileName: 文档名(包含路径) Confirmconversions: 是否显示文件转换对话框 ReadOnly: 是否以只读方式打开文档 AddToRecentFiles: 是否将文件添加到"文件"菜单底部的最近使用文件列表中 PassWordDocument: 打开此文档时所需要的密码 PasswordTemplate: 打开此模板时所需要的密码 Revert: 如果文档已经,是否重新打开文档 WritePasswordDocument: 保存对文档更改时所需要的密码 WritePasswordTemplate: 保存对模板进行更改时所需要的密码 Format: 打开文档时所需使用的文件转换器 Encoding: 所使用的文档代码页 Visible: 打开文档的窗口是否可见 举例: Doc_Handle:=Word_Ole.Documents.open(FileName:=Doc_File,ReadOnly:=False, AddToRecentFiles:=False); 四、Delphi程序保存Word文稿 格式:WordDocuments.SaveAs(FileName, FileFormat, LockComments, Password, AddToRecentFiles, WritePassword, ReadOnlyRecommended, EmbedTrueTypeFonts, SaveNativePictureFormat, SaveFormsData, SaveAsAOCELetter) FileName: 文件名。默认为当前文件夹和文件名。 FileFormat 文档保存的格式。 LockComments 如果为 True,则此文档只允许进行批注。 Password 打开文档时的口令。 AddToRecentFiles 如果为True,则将文档添至"文件"菜单中最近使用的文档列表中。 WritePassword 保存对文档的修改所需的口令。 ReadOnlyRecommended 如果为 True,在每次打开文档时,Word 将建议用户采用只读方式。 EmbedTrueTypeFonts 如果为 True,则将文档与 TrueType 字体一起保存。 SaveNativePictureFormat 如果为 True,则从其他系统平台(例如 Macintosh)导入的图形仅保存其 Windows 版本。 SaveFormsData 如果为 True,则将窗体中用户输入的数据存为一条数据记录。 SaveAsAOCELetter 如果文档包含一个附加,当此属性值为 True 时,将文档存为一篇 AOCE 信笺(同时保存邮件)。 举例: Word_Ole.Documents.SaveAs(FileName:=Doc_File,FileFormat=wdFormatDocument, AddToRecentFiles=False); 五、从数据库读取文件到本地硬盘和从本地硬盘读取文件到数据库 在数据库上使用Image二进制字段保存,使用Stream流的方式。 创建文件流: Word_FileStream:=TFileStream.Create(Target_Name,fmOpenWrite or fmCreate); Word_FileStream.Position:=0; 保存到数据库的Image字段: TBlobField(AdoQuery1.FieldByName(Column_Name)).SaveToStream(Word_FileStream); 从数据库读取文件到本地硬盘: TBlobField(ADOQuery1.FieldByName(Column_Name)).loadfromStream(Word_FileStream); 释放文件流: Word_FileStream.Free; 六、全局消息的定义 因为word和Delphi程序是两个软件,相互之间通讯比较麻烦,所以使用全局消息的方法进行。 全局消息必须首先注册,Windows返回系统空闲的消息号,当注册的消息相同时, Windows系统返回同一个值,这样就保证了使用这个消息号在两个程序之间通讯。 定义消息的办法: szMessageString: pchar = 'XIDIAN_11_Stone'; FMyJoinMessage := RegisterWindowMessage(szMessageString); 发送消息的方法: SendMessage(对方句柄,消息,消息附带短变量,消息附带长变量) 七、Delphi程序接收消息的方法 Delphi接收消息有两种,一是重载特定消息,二是重载WndProc函数,在里面选择相应消息进行处理。 法一,每次只能处理一条消息,而法二能够同时处理多条消息。 对于法二,声明如下: procedure WndProc(var Message: TMessage);override 必须注意,使用时需要在处理完自己消息处理后继承WndProc(Message)函数,否则系统会崩溃! 八、Word中Combo对话框的动态生成以及Change事件 建立类模块Combohander,在内部定义事件 Public WithEvents ComboBoxEvent As Office.CommandBarComboBox 定义Combo控件产生事件的模块 Dim ctlComboBoxHandler As New ComboBoxHandler 产生Combo对话框 Set Cbo_ChooseDoc = CommandBars("添加的菜单").Controls.Add(Type:=msoControlComboBox, Temporary:=True) 进行文件句柄设置,以产生Combo_Change事件 Set ctlComboBoxHandler.ComboBoxEvent = Cbo_ChooseDoc 产生事件后,在类模块Combohander内选择ComboBoxEvent的Change事件,即可书写事件代码 Sub ComboBoxEvent_Change(ByVal Ctrl As Office.CommandBarComboBox) 九、一些Word的事件 VBA代码中处理的Word事件有:Document_Close Application事件中需要处理的有:DocumentBeforeClose,DocumentChange。 Document_Close:事件在文档关闭时产生事件 DocumentBeforeClose:在文档被关闭以前先于Word判断文档是否保存,给出相应提示并进行相应处理。 DocumentChange:文档切换,在文档从自己修改的文稿和其他人修改的文稿之间切换产生事件, 主要处理设置文档权限等。
来自:meng9999, 时间:2001-11-18 18:04:00, ID:737535
自动化方面的知识
来自:blue_morning, 时间:2001-11-18 18:13:00, ID:737554
像你这样的好同志在DFW上已经是越来越少了。可惜DFW没有在一个贴子中给分的功能,
不然我一定给你加30分。

谢谢,收藏。
来自:yzhshi, 时间:2001-11-18 18:16:00, ID:737560
多谢。
其实对于技术问题,我从大富翁得到了许多,尤其是hubdog的葵花宝典,我也希望贡献自己
的一份力量,众人拾柴火焰高!
来自:zohzjf, 时间:2001-11-18 18:44:00, ID:737602
精神可嘉
来自:bluerain, 时间:2001-11-20 12:18:00, ID:741366
精神可嘉,不过有些观点是错误的.例如:
使用Delphi的Server控件,Com类型库的引用和Com对象生成这三种方法实现的功能是
一样的,只是实现的形式不同而已.
来自:ugvanxk, 时间:2001-11-20 13:05:00, ID:741473
你好,结合delphi 控件讲一下,有些参数还不明白
e-mail:jszmail@263.net
来自:askyer, 时间:2001-11-20 13:22:00, ID:741508
很好啊,若不用Server控件就不能够用delphi的code insight了.
来自:DragonPC_???, 时间:2001-12-1 21:44:00, ID:758037
写的不错,但是我想说一些不同的话,

CreateOLEObject创建的variant类型变量,运行期才通过IDispatch接口进行方法调用,所以没有Code Insight,
开发效率、运行效率都要差一点。(IDispatch接口是为适合Automation技术开发的,比COM更高级,更抽象)

http://www.delphibbs.com/delphibbs/dispq.asp?lid=680785
http://www.delphibbs.com/delphibbs/dispq.asp?lid=420919

Delphi Servers 组件和Import Library是一回事来着,使用Import Library会更加通用一点,除了Word,
其它的支持Automation的应用程序都可以使用,比如Autocad、IE等等。但是Import Library有很多的bug,
经常出错。这一点玩过COM编程的人都知道,但我还是推荐使用这套技术进行COM或者Automation工作,效
率高的多。hubdog是这方面的专家,你们可以等他来介绍介绍。

最后我推荐Binh Ly的站点,他是Borland的COM专家,如果经常逛Borland的Automation新闻组,你肯定认
识他,站点有很多介绍和工具下载,大家可以自己看看。Delphi 4编程技术内幕的作者Chris Clvert也是
个中好手,他的站点资料多多。

http://www.techvanguards.com/
http://www.delphibbs.com/delphibbs/dispq.asp?lid=738352
来自:DragonPC_???, 时间:2001-12-1 22:15:00, ID:758092
这里给出一个Excel的操作单元,函概了部分常用Excel操作,不是我写的,是从Experts-Exchange
看到后收藏起来的,给大家参考。

//  该文件操作单元封装了大部分的Excel操作
//  use to manipulate Excel xls File
//   Dragon P.C. <2000.05.10>
unit ExcelUnit;

interface

uses
 Dialogs, Messages, SysUtils, Grids, Cmp_Sec, ComObj, Ads_Misc;

 {!~Add a blank WorkSheet}
 Function ExcelAddWorkSheet(Excel : Variant): Boolean;

 {!~Close Excel}
 Function ExcelClose(Excel : Variant; SaveAll: Boolean): Boolean;

 {!~Returns the Column String Value from its integer equilavent.}
 Function ExcelColIntToStr(ColNum: Integer): ShortString;

 {!~Returns the Column Integer Value from its Alpha equilavent.}
 Function ExcelColStrToInt(ColStr: ShortString): Integer;

 {!~Close All Workbooks.  All workbooks can be saved or not.}
 Function ExcelCloseWorkBooks(Excel : Variant; SaveAll: Boolean): Boolean;

 {!~Copies a range of Excel Cells to a Delphi StringGrid.  If successful
 True is returned, False otherwise.  If SizeStringGridToFit is True
 then the StringGrid is resized to be exactly the correct dimensions to
 receive the input Excel cells, otherwise the StringGrid is not resized.
 If ClearStringGridFirst is true then any cells outside the input range
 are cleared, otherwise existing values are retained.  Please not that the
 Excel cell coordinates are "1" based and the Delphi StringGrid coordinates
 are zero based.}
 Function ExcelCopyToStringGrid(
   Excel                 : Variant;
   ExcelFirstRow         : Integer;
   ExcelFirstCol         : Integer;
   ExcelLastRow          : Integer;
   ExcelLastCol          : Integer;
   StringGrid            : TStringGrid;
   StringGridFirstRow    : Integer;
   StringGridFirstCol    : Integer;
   {Make the StringGrid the same size as the input range}
   SizeStringGridToFit   : Boolean;
   {cells outside input range in StringGrid are cleared}
   ClearStringGridFirst  : Boolean
   ): Boolean;

 {!~Delete a WorkSheet by Name}
 Function ExcelDeleteWorkSheet(
   Excel     : Variant;
   SheetName : ShortString): Boolean;

 {!~Moves the cursor to the last row and column}
 Function ExcelEnd(Excel : Variant): Boolean;

 {!~Finds A value and moves the cursor there.
 If the value is not found then the cursor does not move.
 If nothing is found then false is returned, True otherwise.}
 Function ExcelFind(
   Excel       : Variant;
   FindString  : ShortString): Boolean;

 {!~Finds A value in a range and moves the cursor there.
 If the value is not found then the cursor does not move.
 If nothing is found then false is returned, True otherwise.}
 Function ExcelFindInRange(
   Excel       : Variant;
   FindString  : ShortString;
   TopRow      : Integer;
   LeftCol     : Integer;
   LastRow     : Integer;
   LastCol     : Integer): Boolean;

 {!~Finds A value in a range and moves the cursor there.  If the value is
 not found then the cursor does not move.  If nothing is found then
 false is returned, True otherwise.  The search directions can be defined.
 If you want row searches to go from left to right then SearchRight should
 be set to true, False otherwise.  If you want column searches to go from
 top to bottom then SearchDown should be set to true, false otherwise.
 If RowsFirst is set to true then all the columns in a complete row will be
 searched.}
 Function ExcelFindValue(
   Excel       : Variant;
   FindString  : ShortString;
   TopRow      : Integer;
   LeftCol     : Integer;
   LastRow     : Integer;
   LastCol     : Integer;
   SearchRight : Boolean;
   SearchDown  : Boolean;
   RowsFirst   : Boolean
   ): Boolean;

 {!~Returns The First Col}
 Function ExcelFirstCol(Excel : Variant): Integer;

 {!~Returns The First Row}
 Function ExcelFirstRow(Excel : Variant): Integer;

 {!~Returns the name of the currently active worksheet
 as a shortstring}
 Function ExcelGetActiveSheetName(Excel : Variant): ShortString;

 {!~Gets the formula in a cell.}
 Function ExcelGetCellFormula(
   Excel         : Variant;
   RowNum, ColNum: Integer): ShortString;

 {!~Returns the contents of a cell as a shortstring}
 Function ExcelGetCellValue(Excel : Variant; RowNum, ColNum: Integer): ShortString;

 {!~Returns the the current column}
 Function ExcelGetCol(Excel : Variant): Integer;

 {!~Returns the the current row}
 Function ExcelGetRow(Excel : Variant): Integer;

 {!~Moves the cursor to the last column}
 Function ExcelGoToLastCol(Excel : Variant): Boolean;

 {!~Moves the cursor to the last row}
 Function ExcelGoToLastRow(Excel : Variant): Boolean;

 {!~Moves the cursor to the Leftmost Column}
 Function ExcelGoToLeftmostCol(Excel : Variant): Boolean;

 {!~Moves the cursor to the Top row}
 Function ExcelGoToTopRow(Excel : Variant): Boolean;

 {!~Moves the cursor to Home position, i.e., A1}
 Function ExcelHome(Excel : Variant): Boolean;

 {!~Returns The Last Column}
 Function ExcelLastCol(Excel : Variant): Integer;

 {!~Returns The Last Row}
 Function ExcelLastRow(Excel : Variant): Integer;

 {!~Open the file you want to work within Excel.  If you want to
 take advantage of optional parameters then you should use
 ExcelOpenFileComplex}
 Function ExcelOpenFile(Excel : Variant; FileName : String): Boolean;

 {!~Open the file you want to work within Excel.  If you want to
 take advantage of optional parameters then you should use
 ExcelOpenFileComplex}
 Function ExcelOpenFileComplex(
   Excel        : Variant;
   FileName     : String;
   UpdateLinks  : Integer;
   ReadOnly     : Boolean;
   Format       : Integer;
   Password     : ShortString): Boolean;

 {!~Saves the range on the currently active sheet
 to to values only.}
 Function ExcelPasteValuesOnly(
   Excel         : Variant;
   ExcelFirstRow : Integer;
   ExcelFirstCol : Integer;
   ExcelLastRow  : Integer;
   ExcelLastCol  : Integer): Boolean;

 {!~Renames a worksheet.}
 Function ExcelRenameSheet(
   Excel         : Variant;
   OldName       : ShortString;
   NewName       : ShortString): Boolean;

 {!~Saves the range on the currently active sheet
 to a DBase 4 table.}
 Function ExcelSaveAsDBase4(
   Excel         : Variant;
   ExcelFirstRow : Integer;
   ExcelFirstCol : Integer;
   ExcelLastRow  : Integer;
   ExcelLastCol  : Integer;
   OutFilePath   : ShortString;
   OutFileName   : ShortString): Boolean;

 {!~Saves the range on the currently active sheet
 to a text file.}
 Function ExcelSaveAsText(
   Excel         : Variant;
   ExcelFirstRow : Integer;
   ExcelFirstCol : Integer;
   ExcelLastRow  : Integer;
   ExcelLastCol  : Integer;
   OutFilePath   : ShortString;
   OutFileName   : ShortString): Boolean;

 {!~Selects a range on the currently active sheet.  From the
 current cursor position a block is selected down and to the right.
 The block proceeds down until an empty row is encountered.  The
 block proceeds right until an empty column is encountered.}
 Function ExcelSelectBlock(
     Excel    : Variant;
     FirstRow : Integer;
     FirstCol : Integer): Boolean;

 {!~Selects a range on the currently active sheet.  From the
 current cursor position a block is selected that contains
 the currently active cell.  The block proceeds in each
 direction until an empty row or column is encountered.}
 Function ExcelSelectBlockWhole(Excel: Variant): Boolean;

 {!~Selects a cell on the currently active sheet}
 Function ExcelSelectCell(Excel : Variant; RowNum, ColNum: Integer): Boolean;

 {!~Selects a range on the currently active sheet}
 Function ExcelSelectRange(
   Excel    : Variant;
   FirstRow : Integer;
   FirstCol : Integer;
   LastRow  : Integer;
   LastCol  : Integer): Boolean;

 {!~Selects an Excel Sheet By Name}
 Function ExcelSelectSheetByName(Excel : Variant; SheetName: String): Boolean;

 {!~Sets the formula in a cell.  Remember to include the equals sign "=".
 If the function fails False is returned, True otherwise.}
 Function ExcelSetCellFormula(
   Excel         : Variant;
   FormulaString : ShortString;
   RowNum, ColNum: Integer): Boolean;

 {!~Sets the contents of a cell as a shortstring}
 Function ExcelSetCellValue(
   Excel : Variant;
   RowNum, ColNum: Integer;
   Value : ShortString): Boolean;

 {!~Sets a Column Width on the currently active sheet}
 Function ExcelSetColumnWidth(
   Excel      : Variant;
   ColNum     : Integer;
   ColumnWidth: Integer): Boolean;

 {!~Set Excel Visibility}
 Function ExcelSetVisible(
   Excel : Variant;
   IsVisible: Boolean): Boolean;

 {!~Saves the range on the currently active sheet
 to values only.}
 Function ExcelValuesOnly(
   Excel         : Variant;
   ExcelFirstRow : Integer;
   ExcelFirstCol : Integer;
   ExcelLastRow  : Integer;
   ExcelLastCol  : Integer): Boolean;

 {!~Returns the Excel Version as a ShortString.}
 Function ExcelVersion(Excel: Variant): ShortString;

 Function IsBlockColSide(
   Excel : Variant;
   RowNum: Integer;
   ColNum: Integer): Boolean; Forward;
   
 Function IsBlockRowSide(
   Excel : Variant;
   RowNum: Integer;
   ColNum: Integer): Boolean; Forward;


implementation


type
 //Declare the constants used by Excel
 SourceType = (xlConsolidation, xlDatabase, xlExternal, xlPivotTable);
 Orientation = (xlHidden, xlRowField, xlColumnField, xlPageField, xlDataField);
 RangeEnd = (NoValue, xlToLeft, xlToRight, xlUp, xlDown);
 ExcelPasteType = (xlAllExceptBorders,xlNotes,xlFormats,xlValues,xlFormulas,xlAll);

 {CAUTION!!! THESE OUTPUTS ARE ALL GARBLED!  YOU SELECT xlDBF3 AND EXCEL
 OUTPUTS A xlCSV.}
 FileFormat = (xlAddIn, xlCSV, xlCSVMac, xlCSVMSDOS, xlCSVWindows, xlDBF2,
               xlDBF3, xlDBF4, xlDIF, xlExcel2, xlExcel3, xlExcel4,
               xlExcel4Workbook, xlIntlAddIn, xlIntlMacro, xlNormal,
               xlSYLK, xlTemplate, xlText, xlTextMac, xlTextMSDOS,
               xlTextWindows, xlTextPrinter, xlWK1, xlWK3, xlWKS,
               xlWQ1, xlWK3FM3, xlWK1FMT, xlWK1ALL);

{Add a blank WorkSheet}
Function ExcelAddWorkSheet(Excel : Variant): Boolean;
Begin
 Result := True;
 Try
   Excel.Worksheets.Add;
 Except
   MessageDlg('Unable to add a new worksheet', mtError, [mbOK], 0);
   Result := False;
 End;
End;

{Sets Excel Visibility}
Function ExcelSetVisible(Excel : Variant;IsVisible: Boolean): Boolean;
Begin
 Result := True;
 Try
   Excel.Visible := IsVisible;
 Except
   MessageDlg('Unable to Excel Visibility', mtError, [mbOK], 0);
   Result := False;
 End;
End;

{Close Excel}
Function ExcelClose(Excel : Variant; SaveAll: Boolean): Boolean;
Begin
 Result := True;
 Try
   ExcelCloseWorkBooks(Excel, SaveAll);
   Excel.Quit;
 Except
   MessageDlg('Unable to Close Excel', mtError, [mbOK], 0);
   Result := False;
 End;
End;

{Close All Workbooks.  All workbooks can be saved or not.}
Function ExcelCloseWorkBooks(Excel : Variant; SaveAll: Boolean): Boolean;
var
 loop: byte;
Begin
 Result := True;
 Try
   For loop := 1 to Excel.Workbooks.Count Do
     Excel.Workbooks[1].Close[SaveAll];
 Except
   Result := False;
 End;
End;

{Selects an Excel Sheet By Name}
Function ExcelSelectSheetByName(Excel : Variant; SheetName: String): Boolean;
Begin
 Result := True;
 Try
   Excel.Sheets[SheetName].Select;
 Except
   Result := False;
 End;
End;

{Selects a cell on the currently active sheet}
Function ExcelSelectCell(Excel : Variant; RowNum, ColNum: Integer): Boolean;
Begin
 Result := True;
 Try
   Excel.ActiveSheet.Cells[RowNum, ColNum].Select;
 Except
   Result := False;
 End;
End;

{Returns the contents of a cell as a shortstring}
Function ExcelGetCellValue(Excel : Variant; RowNum, ColNum: Integer): ShortString;
Begin
 Result := '';
 Try
   Result := Excel.Cells[RowNum, ColNum].Value;
 Except
   Result := '';
 End;
End;

{Returns the the current row}
Function ExcelGetRow(Excel : Variant): Integer;
Begin
 Result := 1;
 Try
   Result := Excel.ActiveCell.Row;
 Except
   Result := 1;
 End;
End;

{Returns the the current column}
Function ExcelGetCol(Excel : Variant): Integer;
Begin
 Result := 1;
 Try
   Result := Excel.ActiveCell.Column;
 Except
   Result := 1;
 End;
End;

{Moves the cursor to the last column}
Function ExcelGoToLastCol(Excel : Variant): Boolean;
Begin
 Result := True;
 Try
   Excel.Selection.End[xlToRight].Select;
 Except
   Result := False;
 End;
End;

{Moves the cursor to the last row}
Function ExcelGoToLastRow(Excel : Variant): Boolean;
Begin
 Result := True;
 Try
   Excel.Selection.End[xlDown].Select;
 Except
   Result := False;
 End;
End;

{Moves the cursor to the Top row}
Function ExcelGoToTopRow(Excel : Variant): Boolean;
Begin
 Result := True;
 Try
   Excel.Selection.End[xlUp].Select;
 Except
   Result := False;
 End;
End;

{Moves the cursor to the Leftmost Column}
Function ExcelGoToLeftmostCol(Excel : Variant): Boolean;
Begin
 Result := True;
 Try
   Excel.Selection.End[xlToLeft].Select;
 Except
   Result := False;
 End;
End;

{Moves the cursor to Home position}
Function ExcelHome(Excel : Variant): Boolean;
Begin
 Result := True;
 Try
   Excel.ActiveSheet.Cells[1,1].Select;
 Except
   Result := False;
 End;
End;

{Moves the cursor to the last row and column}
Function ExcelEnd(Excel : Variant): Boolean;
Begin
 Result := True;
 Try
   Excel.Selection.End[xlDown].Select;
   Excel.Selection.End[xlToRight].Select;
 Except
   Result := False;
 End;
End;

{Returns The Last Column}
Function ExcelLastCol(Excel : Variant): Integer;
Var
 CurRow : Integer;
 CurCol : Integer;
Begin
 Result := 1;
 Try
   CurRow := Excel.ActiveCell.Row;
   CurCol := Excel.ActiveCell.Column;
   Result := CurCol;
   Excel.Selection.End[xlToRight].Select;
   Result := Excel.ActiveCell.Column;
   Excel.ActiveSheet.Cells[CurRow, CurCol].Select;
 Except
 End;
End;

{Returns The Last Row}
Function ExcelLastRow(Excel : Variant): Integer;
Var
 CurRow : Integer;
 CurCol : Integer;
Begin
 Result := 1;
 Try
   CurRow := Excel.ActiveCell.Row;
   CurCol := Excel.ActiveCell.Column;
   Result := CurRow;
   Excel.Selection.End[xlDown].Select;
   Result := Excel.ActiveCell.Row;
   Excel.ActiveSheet.Cells[CurRow, CurCol].Select;
 Except
 End;
End;

{Returns The First Row}
Function ExcelFirstRow(Excel : Variant): Integer;
Var
 CurRow : Integer;
 CurCol : Integer;
Begin
 Result := 1;
 Try
   CurRow := Excel.ActiveCell.Row;
   CurCol := Excel.ActiveCell.Column;
   Result := CurRow;
   Excel.Selection.End[xlUp].Select;
   Result := Excel.ActiveCell.Row;
   Excel.ActiveSheet.Cells[CurRow, CurCol].Select;
 Except
 End;
End;

{Returns The First Col}
Function ExcelFirstCol(Excel : Variant): Integer;
Var
 CurRow : Integer;
 CurCol : Integer;
Begin
 Result := 1;
 Try
   CurRow := Excel.ActiveCell.Row;
   CurCol := Excel.ActiveCell.Column;
   Result := CurRow;
   Excel.Selection.End[xlToLeft].Select;
   Result := Excel.ActiveCell.Column;
   Excel.ActiveSheet.Cells[CurRow, CurCol].Select;
 Except
 End;
End;

{Finds A value in a range and moves the cursor there.  If the value is
not found then the cursor does not move.  If nothing is found then
false is returned, True otherwise.}
Function ExcelFindValue(
 Excel       : Variant;
 FindString  : ShortString;
 TopRow      : Integer;
 LeftCol     : Integer;
 LastRow     : Integer;
 LastCol     : Integer;
 SearchRight : Boolean;
 SearchDown  : Boolean;
 RowsFirst   : Boolean
 ): Boolean;
Var
 CurRow    : Integer;
 CurCol    : Integer;
 TopRowN   : Integer;
 LeftColN  : Integer;
 LastRowN  : Integer;
 LastColN  : Integer;
 ColLoop   : Integer;
 RowLoop   : Integer;
 CellValue : ShortString;
 FoundRow  : Integer;
 FoundCol  : Integer;
 Found     : Boolean;
Begin
 Result := False;
 Try
   Found      := False;
   FindString := UpperCase(FindString);
   CurRow     := Excel.ActiveCell.Row;
   CurCol     := Excel.ActiveCell.Column;
   FoundRow   := CurRow;
   FoundCol   := CurCol;

   If SearchRight Then
   Begin
     LeftColN := LeftCol;
     LastColN := LastCol;
   End
   Else
   Begin
     LeftColN := LastCol;
     LastColN := LeftCol;
   End;

   If SearchDown Then
   Begin
     TopRowN  := TopRow;
     LastRowN := LastRow;
   End
   Else
   Begin
     TopRowN  := LastRow;
     LastRowN := TopRow;
   End;
   If RowsFirst Then
   Begin
     For ColLoop := LeftColN To LastColN Do
     Begin
       For RowLoop := TopRowN To LastRowN Do
       Begin
         CellValue := ExcelGetCellValue(Excel,RowLoop, ColLoop);
         If UpperCase(CellValue) = FindString Then
         Begin
           FoundRow := RowLoop;
           FoundCol := ColLoop;
           Found    := True;
           Break;
         End;
       End;
       If Found Then Break;
     End;
   End
   Else
   Begin
     For RowLoop := TopRowN To LastRowN Do
     Begin
       For ColLoop := LeftColN To LastColN Do
       Begin
         CellValue := ExcelGetCellValue(Excel,RowLoop, ColLoop);
         If UpperCase(CellValue) = FindString Then
         Begin
           FoundRow := RowLoop;
           FoundCol := ColLoop;
           Found    := True;
           Break;
         End;
       End;
       If Found Then Break;
     End;
   End;
   Excel.Cells[FoundRow, FoundCol].Activate;
   Result := Found;
 Except
   Result := False;
 End;
End;

{Finds A value in a range and moves the cursor there.  If the value is
not found then the cursor does not move.  If nothing is found then
false is returned, True otherwise.}
Function ExcelFindInRange(
 Excel       : Variant;
 FindString  : ShortString;
 TopRow      : Integer;
 LeftCol     : Integer;
 LastRow     : Integer;
 LastCol     : Integer): Boolean;
Begin
 Result :=
   ExcelFindValue(
     Excel,
     FindString,
     TopRow,
     LeftCol,
     LastRow,
     LastCol,
     True,
     True,
     True);
End;

{Finds A value and moves the cursor there.  If the value is
not found then the cursor does not move.  If nothing is found then
false is returned, True otherwise.}
Function ExcelFind(
 Excel       : Variant;
 FindString  : ShortString): Boolean;
Begin
 Result :=
   ExcelFindInRange(
     Excel,
     FindString,
     ExcelFirstRow(Excel),
     ExcelFirstCol(Excel),
     ExcelLastRow(Excel),
     ExcelLastCol(Excel));
End;

{!~Copies a range of Excel Cells to a Delphi StringGrid.  If successful
True is returned, False otherwise.  If SizeStringGridToFit is True
then the StringGrid is resized to be exactly the correct dimensions to
receive the input Excel cells, otherwise the StringGrid is not resized.
If ClearStringGridFirst is true then any cells outside the input range
are cleared, otherwise existing values are retained.  Please not that the
Excel cell coordinates are "1" based and the Delphi StringGrid coordinates
are zero based.}
Function ExcelCopyToStringGrid(
 Excel                 : Variant;
 ExcelFirstRow         : Integer;
 ExcelFirstCol         : Integer;
 ExcelLastRow          : Integer;
 ExcelLastCol          : Integer;
 StringGrid            : TStringGrid;
 StringGridFirstRow    : Integer;
 StringGridFirstCol    : Integer;
 SizeStringGridToFit   : Boolean; {Make the StringGrid the same size as the input range}
 ClearStringGridFirst  : Boolean  {cells outside input range in StringGrid are cleared}
 ): Boolean;
Var
 C,R : Integer;
Begin
 Result := False;
 If ExcelLastCol < ExcelFirstCol Then Exit;
 If ExcelLastRow < ExcelFirstRow Then Exit;
 If (ExcelFirstRow < 1) Or (ExcelFirstRow > 255)   Then Exit;
 If (ExcelFirstCol < 1) Or (ExcelFirstCol > 30000) Then Exit;
 If (ExcelLastRow  < 1) Or (ExcelLastRow > 255)    Then Exit;
 If (ExcelLastCol  < 1) Or (ExcelLastCol > 30000)  Then Exit;
 If StringGrid = nil   Then Exit;
 If SizeStringGridToFit Then
 Begin
   StringGrid.ColCount := ExcelLastCol - ExcelFirstCol + StringGridFirstCol + 1;
   StringGrid.RowCount := ExcelLastRow - ExcelFirstRow + StringGridFirstRow + 1;
 End;
 If ClearStringGridFirst Then
 Begin
   C := StringGrid.ColCount;
   R := StringGrid.RowCount;
   StringGrid.ColCount := 1;
   StringGrid.RowCount := 1;
   StringGrid.Cells[0,0] := '';
   StringGrid.ColCount := C;
   StringGrid.RowCount := R;
 End;

 Result := True;
 For R := ExcelFirstRow To ExcelLastRow Do
 Begin
   For C := ExcelFirstCol To ExcelLastCol Do
   Begin
     Try
       StringGrid.Cells[
         C - ExcelFirstCol + StringGridFirstCol,
         R - ExcelFirstRow + StringGridFirstRow] :=
           Excel.Cells[R, C];
     Except
       Result := False;
     End;
   End;
 End;
End;

{!~Sets the formula in a cell.  Remember to include the equals sign "=".
If the function fails False is returned, True otherwise.}
Function ExcelSetCellFormula(
 Excel         : Variant;
 FormulaString : ShortString;
 RowNum, ColNum: Integer): Boolean;
Begin
 Result := True;
 Try
   Excel.
     ActiveSheet.
       Cells[RowNum, ColNum].
         Formula := FormulaString;
 Except
   Result := False;
 End;
End;

{!~Returns the Column String Value from its integer equilavent.}
Function ExcelColIntToStr(ColNum: Integer): ShortString;
Var
 ColStr    : ShortString;
 Multiplier: Integer;
 Remainder : Integer;
Begin
 Result := '';
 If ColNum < 1   Then Exit;
 If ColNum > 256 Then Exit;
 Multiplier := ColNum div 26;
 Remainder  := ColNum Mod 26;
 If ColNum <= 26 Then
 Begin
   ColStr[1] := ' ';
   If Remainder = 0 Then
   Begin
     ColStr[2] := 'Z';
   End
   Else
   Begin
     ColStr[2] := Chr(Remainder+64);
   End;
 End
 Else
 Begin
   If Remainder = 0 Then
   Begin
     If Multiplier = 1 Then
     Begin
       ColStr[1] := ' ';
       ColStr[2] := 'Z';
     End
     Else
     Begin
       ColStr[1] := Chr(Multiplier+64-1);
       ColStr[2] := 'Z';
     End;
   End
   Else
   Begin
     ColStr[1] := Chr(Multiplier+64);
     ColStr[2] := Chr(Remainder+64);
   End;
 End;
 If ColStr[1] = ' ' Then
 Begin
   Result := Result + ColStr[2];
 End
 Else
 Begin
   Result := Result + ColStr[1] + ColStr[2];
 End;
 Result := Result;
End;

{!~Returns the Column Integer Value from its Alpha equilavent.}
Function ExcelColStrToInt(ColStr: ShortString): Integer;
Var
 ColStrNew  : ShortString;
 i          : Integer;
 RetVal     : Integer;
 Multiplier : Integer;
 Remainder  : Integer;
Begin
 RetVal := 1;
 Result := RetVal;
 ColStrNew := '';
 For i := 1 To Length(ColStr) Do
 Begin
   If ((Ord(ColStr[i]) >=  65)  And
      ( Ord(ColStr[i]) <=  90)) Or
      ((Ord(ColStr[i]) >=  97)  And
      ( Ord(ColStr[i]) <= 122)) Then
   Begin
     ColStrNew := ColStrNew + UpperCase(ColStr[i]);
   End;
 End;
 If Length(ColStrNew) < 1 Then Exit;
 If Length(ColStrNew) < 2 Then
 Begin
   RetVal := Ord(ColStrNew[1])-64;
 End
 Else
 Begin
   Multiplier := Ord(ColStrNew[1])-64;
   Remainder  := Ord(ColStrNew[2])-64;
   Retval     := (Multiplier * 26) + Remainder;
 End;
 Result := RetVal;
End;

{!~Sets the contents of a cell as a shortstring}
Function ExcelSetCellValue(
 Excel : Variant;
 RowNum, ColNum: Integer;
 Value : ShortString): Boolean;
Begin
 Result   := False;
 Try
   Excel.Cells[RowNum, ColNum].Value := Value;
   Result := True;
 Except
   Result := False;
 End;
End;

{!~Open the file you want to work within Excel.  If you want to
take advantage of optional parameters then you should use
ExcelOpenFileComplex}
Function ExcelOpenFile(Excel : Variant; FileName : String): Boolean;
Begin
 Result := True;
 try
   //Open the database that we want to work with
   Excel.Workbooks.Open[FileName];
 except
   MessageDlg('Unable to locate '+FileName, mtError, [mbOK], 0);
   Result := False;
 end;
End;

{!~Open the file you want to work within Excel.

Excel
 The OLEObject passed as an argument.

FileName
 Required. Specifies the filename of the workbook to open.

UpdateLinks
 Specifies how links in the file are updated. If this
 argument is omitted, the user is prompted to determine
 how to update links. Otherwise, this argument is one of
 the values shown in the following table.
 Value     Meaning
 0     No updates
 1     Updates external but not remote references
 2     Updates remote but not external references
 3     Updates both remote and external references

 If Microsoft Excel is opening a file in the WKS, WK1, or
 WK3 format and the updateLinks argument is 2, Microsoft
 Excel generates charts from the graphs attached to the file.
 If the argument is 0, no charts are created.

ReadOnly
 If True, the workbook is opened in read-only mode.

Format
 If Microsoft Excel is opening a text file, this argument
 specifies the delimiter character, as shown in the following
 table. If this argument is omitted, the current delimiter
 is used.

 Value     Delimiter
 1     Tabs
 2     Commas
 3     Spaces
 4     Semicolons
 5     Nothing
 6     Custom character, see the delimiter argument.

Password
 A string containing the password required to open a
 protected workbook. If omitted and the workbook requires
 a password, the user is prompted for the password.
}

Function ExcelOpenFileComplex(
 Excel        : Variant;
 FileName     : String;
 UpdateLinks  : Integer;
 ReadOnly     : Boolean;
 Format       : Integer;
 Password     : ShortString): Boolean;
Begin
 Result := True;
 try
   //Open the database that we want to work with
   Excel.
     Workbooks.
       Open[
         FileName,
         UpdateLinks,
         ReadOnly,
         Format,
         Password];
 except
   MessageDlg('Unable to locate '+FileName, mtError, [mbOK], 0);
   Result := False;
 end;
End;

{!~Saves the range on the currently active sheet
to a DBase 4 table.}
Function ExcelSaveAsDBase4(
 Excel         : Variant;
 ExcelFirstRow : Integer;
 ExcelFirstCol : Integer;
 ExcelLastRow  : Integer;
 ExcelLastCol  : Integer;
 OutFilePath   : ShortString;
 OutFileName   : ShortString): Boolean;
{
OutFileFormat: Use one of the following
xlAddIn      xlExcel3         xlTextMSDOS
xlCSV        xlExcel4         xlTextWindows
xlCSVMac     xlExcel4Workbook xlTextPrinter
xlCSVMSDOS   xlIntlAddIn      xlWK1
xlCSVWindows xlIntlMacro      xlWK3
xlDBF2       xlNormal         xlWKS
xlDBF3       xlSYLK           xlWQ1
xlDBF4       xlTemplate       xlWK3FM3
xlDIF        xlText           xlWK1FMT
xlExcel2     xlTextMac        xlWK1ALL
}
Begin
 Result := False;
 Try
   If IsTable(
        OutFilePath,
        OutFileName+'.dbf')
   Then
   Begin
     If Not DBDeleteTable(
              OutFilePath,
              OutFileName+'.dbf')
     Then
     Begin
       Msg('Could not delete the '+
            OutFilePath+OutFileName+'.dbf'+' Table');
       Msg('Process Aborted');
       Exit;
     End;
   End;
   If ExcelVersion(Excel) = '8.0' Then
   Begin
     ExcelSelectCell(Excel,ExcelFirstRow,ExcelFirstCol);
     ExcelSelectBlockWhole(Excel);
     //Excel.SendKeys('^+{END}');
   End
   Else
   Begin
     Excel.
       Range(
         ExcelColIntToStr(ExcelFirstCol)+
         IntToStr(ExcelFirstRow)+
         ':'+
         ExcelColIntToStr(ExcelLastCol)+
         IntToStr(ExcelLastRow)
             ).
         Select;
   End;
{
 FileFormat = (xlAddIn, xlCSV, xlCSVMac, xlCSVMSDOS, xlCSVWindows, xlDBF2,
               xlDBF3, xlDBF4, xlDIF, xlExcel2, xlExcel3, xlExcel4,
               xlExcel4Workbook, xlIntlAddIn, xlIntlMacro, xlNormal,
               xlSYLK, xlTemplate, xlText, xlTextMac, xlTextMSDOS,
               xlTextWindows, xlTextPrinter, xlWK1, xlWK3, xlWKS,
               xlWQ1, xlWK3FM3, xlWK1FMT, xlWK1ALL);
}
{
   //CHECKING OUT THE GARBLED OUTPUT
   //  Produces an *.xls
   Excel.
     ActiveSheet.
     SaveAs(
       OutFilePath+OutFileName+'02',xlCSV);

   //  Produces an *.txt
   Excel.
     ActiveSheet.
     SaveAs(
       OutFilePath+OutFileName+'04',xlCSVMSDOS);

   //  Produces nothing
   Excel.
     ActiveSheet.
     SaveAs(
       OutFilePath+OutFileName+'05',xlCSVWindows);

   //  Produces nothing
   Excel.
     ActiveSheet.
     SaveAs(
       OutFilePath+OutFileName+'06',xlDBF2);

   //  Produces an *.txt
   Excel.
     ActiveSheet.
     SaveAs(
       OutFilePath+OutFileName+'07',xlDBF3);

   //  Produces an *.dbf
   Excel.
     ActiveSheet.
     SaveAs(
       OutFilePath+OutFileName+'08',xlDBF4);
   //  Produces an *.dbf
   Excel.
     ActiveSheet.
     SaveAs(
       OutFilePath+OutFileName+'09',xlDIF);
   //  Produces an *.dif
   Excel.
     ActiveSheet.
     SaveAs(
       OutFilePath+OutFileName+'10',xlExcel2);
   //  Produces an *.slk
   Excel.
     ActiveSheet.
     SaveAs(
       OutFilePath+OutFileName+'11',xlExcel3);
   //  Produces an *.dbf
   Excel.
     ActiveSheet.
     SaveAs(
       OutFilePath+OutFileName+'12',xlExcel4);
}
   Excel.
     ActiveSheet.
     SaveAs(
       OutFilePath+OutFileName,xlExcel4);
   Result := True;
 Except
   Result := False;
 End;
End;

{!~Saves the range on the currently active sheet
to a text file.}
Function ExcelSaveAsText(
 Excel         : Variant;
 ExcelFirstRow : Integer;
 ExcelFirstCol : Integer;
 ExcelLastRow  : Integer;
 ExcelLastCol  : Integer;
 OutFilePath   : ShortString;
 OutFileName   : ShortString): Boolean;
{
OutFileFormat: Use one of the following
xlAddIn      xlExcel3         xlTextMSDOS
xlCSV        xlExcel4         xlTextWindows
xlCSVMac     xlExcel4Workbook xlTextPrinter
xlCSVMSDOS   xlIntlAddIn      xlWK1
xlCSVWindows xlIntlMacro      xlWK3
xlDBF2       xlNormal         xlWKS
xlDBF3       xlSYLK           xlWQ1
xlDBF4       xlTemplate       xlWK3FM3
xlDIF        xlText           xlWK1FMT
xlExcel2     xlTextMac        xlWK1ALL
}
Var
 FullOutName : String;
Begin
 Result := False;
 Try
   If OutFilePath <> '' Then
   Begin
     If Not (Copy(OutFilePath,Length(OutFilePath),1) = '/') Then
     Begin
       OutFilePath := OutFilePath + '/';
     End;
   End;
   FullOutName := OutFilePath + OutFileName;
   If FileExists(FullOutName) Then DeleteFile(FullOutName);

   If ExcelVersion(Excel) = '8.0' Then
   Begin
     ExcelSelectCell(Excel,ExcelFirstRow,ExcelFirstCol);
     ExcelSelectBlockWhole(Excel);
     //Excel.SendKeys('^+{END}');
   End
   Else
   Begin
     Excel.
       Range(
         ExcelColIntToStr(ExcelFirstCol)+
         IntToStr(ExcelFirstRow)+
         ':'+
         ExcelColIntToStr(ExcelLastCol)+
         IntToStr(ExcelLastRow)
             ).
         Select;
   End;
{
 FileFormat = (xlAddIn, xlCSV, xlCSVMac, xlCSVMSDOS, xlCSVWindows, xlDBF2,
               xlDBF3, xlDBF4, xlDIF, xlExcel2, xlExcel3, xlExcel4,
               xlExcel4Workbook, xlIntlAddIn, xlIntlMacro, xlNormal,
               xlSYLK, xlTemplate, xlText, xlTextMac, xlTextMSDOS,
               xlTextWindows, xlTextPrinter, xlWK1, xlWK3, xlWKS,
               xlWQ1, xlWK3FM3, xlWK1FMT, xlWK1ALL);
}
(*
   //CHECKING OUT THE GARBLED OUTPUT
   //  Produces an *.xls
   Excel.
     ActiveSheet.
     SaveAs(
       OutFilePath+OutFileName+'02',xlCSV);
*)
   //  Produces an *.txt
//    Excel.
//      ActiveSheet.
//      SaveAs(
//        FullOutName,xlCSVMSDOS);
(*
   //  Produces nothing
   Excel.
     ActiveSheet.
     SaveAs(
       OutFilePath+OutFileName+'05',xlCSVWindows);

   //  Produces nothing
   Excel.
     ActiveSheet.
     SaveAs(
       OutFilePath+OutFileName+'06',xlDBF2);

   //  Produces an *.txt comma separated
   Excel.
     ActiveSheet.
     SaveAs(
       FullOutName,xlDBF3);
*)
   //  Produces an *.txt 
   Excel.
     ActiveSheet.
     SaveAs(
       FullOutName,xlTextMSDOS);
(*
   //  Produces an *.dbf
   Excel.
     ActiveSheet.
     SaveAs(
       OutFilePath+OutFileName+'08',xlDBF4);
   //  Produces an *.dbf
   Excel.
     ActiveSheet.
     SaveAs(
       OutFilePath+OutFileName+'09',xlDIF);
   //  Produces an *.dif
   Excel.
     ActiveSheet.
     SaveAs(
       OutFilePath+OutFileName+'10',xlExcel2);
   //  Produces an *.slk
   Excel.
     ActiveSheet.
     SaveAs(
       OutFilePath+OutFileName+'11',xlExcel3);
   //  Produces an *.dbf
   Excel.
     ActiveSheet.
     SaveAs(
       OutFilePath+OutFileName+'12',xlExcel4);

*)
   Result := True;
 Except
   Result := False;
 End;
End;



{!~Saves the range on the currently active sheet
to to values only.}
Function ExcelPasteValuesOnly(
 Excel         : Variant;
 ExcelFirstRow : Integer;
 ExcelFirstCol : Integer;
 ExcelLastRow  : Integer;
 ExcelLastCol  : Integer): Boolean;
Var
 RangeString : ShortString;
 SheetName   : ShortString;
 SheetTemp   : ShortString;
Begin
 Result := True;
 try
   If ExcelVersion(Excel) = '8.0' Then
   Begin
     If Not ExcelSelectRange(
              Excel,
              ExcelFirstRow,
              ExcelFirstCol,
              ExcelLastRow,
              ExcelLastCol)
     Then
     Begin
       Result := False;
       Msg('Unable to select the range to paste as values.');
       Exit;
     End;
     Excel.Selection.Copy;
     Excel.Selection.PasteSpecial(xlValues);
     Excel.Application.CutCopyMode := False;
   End
   Else
   Begin
     Excel.Range(
       ExcelColIntToStr(ExcelFirstCol)+IntToStr(ExcelFirstRow)+
       ':'+
       ExcelColIntToStr(ExcelLastCol)+IntToStr(ExcelLastRow)).Select;
     Excel.Selection.Copy;
     Excel.Selection.PasteSpecial(xlValues);
     Excel.Application.CutCopyMode := False;
     Excel.Selection.Replace('#N/A','0');
   End;
 except
   Msg('Unable to paste range as values');
   Result := False;
 end;
End;

{!~Sets a Column Width on the currently active sheet}
Function ExcelSetColumnWidth(Excel : Variant; ColNum, ColumnWidth: Integer): Boolean;
Var
 RowWas : Integer;
 ColWas : Integer;
Begin
 Result := False;
 Try
   RowWas := ExcelGetRow(Excel);
   ColWas := ExcelGetCol(Excel);
   ExcelSelectCell(Excel,1,ColNum);
   Excel.Selection.ColumnWidth := ColumnWidth;
   ExcelSelectCell(Excel,RowWas,ColWas);
   Result := True;
 Except
   Result := False;
 End;
End;

{!~Selects a range on the currently active sheet}
Function ExcelSelectRange(
   Excel    : Variant;
   FirstRow : Integer;
   FirstCol : Integer;
   LastRow  : Integer;
   LastCol  : Integer): Boolean;
Var
 r,c : Integer;
 RowString : ShortString;
 ColString : ShortString;
Begin
 Result := False;
 Try
   If FirstRow <   1 Then Exit;
   If FirstCol <   1 Then Exit;
   If LastRow  <   1 Then Exit;
   If LastCol  <   1 Then Exit;
   If FirstCol > 255 Then Exit;
   If LastCol  > 255 Then Exit;

   If Not ExcelSelectCell(
            Excel,
            FirstRow,
            FirstCol)
   Then
   Begin
     Exit;
   End;
   {Check for strange number combinations}
   If FirstRow = LastRow Then
   Begin
     {Don't need to do anything}
   End
   Else
   Begin
     If FirstRow < LastRow Then
     Begin
       For r := FirstRow To LastRow - 1 Do
       Begin
         Excel.SendKeys('+{DOWN}');
       End;
     End
     Else
     Begin
       For r := LastRow To FirstRow - 1 Do
       Begin
         Excel.SendKeys('+{UP}');
       End;
     End;
   End;
   If FirstCol = LastCol Then
   Begin
     {Don't need to do anything}
   End
   Else
   Begin
     If FirstCol < LastCol Then
     Begin
       For c := FirstCol To LastCol - 1 Do
       Begin
         Excel.SendKeys('+{RIGHT}');
       End;
     End
     Else
     Begin
       For c := LastCol To FirstCol - 1 Do
       Begin
         Excel.SendKeys('+{LEFT}');
       End;
     End;
   End;
   Result := True;
 Except
   Result := False;
 End;
End;

{!~Selects a range on the currently active sheet.  From the
current cursor position a block is selected down and to the right.
The block proceeds down until an empty row is encountered.  The
block proceeds right until an empty column is encountered.}
Function ExcelSelectBlock(
   Excel    : Variant;
   FirstRow : Integer;
   FirstCol : Integer): Boolean;
Begin
 Result := False;
 Try
   ExcelSelectCell(Excel,FirstRow,FirstCol);
   Excel.SendKeys('+{END}+{RIGHT}');
   Excel.SendKeys('+{END}+{DOWN}');
   Result := True;
 Except
   Result := False;
 End;
End;

{!~Selects a range on the currently active sheet.  From the
current cursor position a block is selected that contains
the currently active cell.  The block proceeds in each
direction until an empty row or column is encountered.}
Function ExcelSelectBlockWhole(Excel: Variant): Boolean;
Var
 FirstRow : Integer;
 FirstCol : Integer;
 LastRow  : Integer;
 LastCol  : Integer;
 RowWas   : Integer;
 ColWas   : Integer;
Begin
 Result   := False;
 Try
   RowWas   := ExcelGetRow(Excel);
   ColWas   := ExcelGetCol(Excel);

   {If the base cell is on a side of the block, the block
   will not be created properly.}

   {View From Original Cell}
   FirstRow := ExcelFirstRow(Excel);
   FirstCol := ExcelFirstCol(Excel);
   LastRow  := ExcelLastRow(Excel);
   LastCol  := ExcelLastCol(Excel);
   If (Not IsBlockColSide(Excel,RowWas,ColWas)) And
      (Not IsBlockRowSide(Excel,RowWas,ColWas)) Then
   Begin
     {Cell is not on a side of the block}
     ExcelSelectCell(Excel,FirstRow,FirstCol);
     Excel.SendKeys('+{END}+{RIGHT}');
     Excel.SendKeys('+{END}+{DOWN}');
     Result := True;
     Exit;
   End;
   {Row Only problem}
   If (Not IsBlockColSide(Excel,RowWas,ColWas)) And
      (IsBlockRowSide(Excel,RowWas,ColWas)) Then
   Begin
     {DEFAULT TO ASSUMING SELECTED CELLS ARE NEAR TOP LEFT AND
     BLOCK IS TOWARD BOTTOM RIGHT}
     ExcelSelectCell(Excel,RowWas,FirstCol);
     Excel.SendKeys('+{END}+{RIGHT}');
     Excel.SendKeys('+{END}+{DOWN}');
     Result := True;
     Exit;
   End;
   {Column Only problem}
   If (IsBlockColSide(Excel,RowWas,ColWas)) And
      (Not IsBlockRowSide(Excel,RowWas,ColWas)) Then
   Begin
     {DEFAULT TO ASSUMING SELECTED CELLS ARE NEAR TOP LEFT AND
     BLOCK IS TOWARD BOTTOM RIGHT}
     ExcelSelectCell(Excel,FirstRow,ColWas);
     Excel.SendKeys('+{END}+{RIGHT}');
     Excel.SendKeys('+{END}+{DOWN}');
     Result := True;
     Exit;
   End;
   {DEFAULT TO ASSUMING SELECTED CELLS ARE NEAR TOP LEFT AND
   BLOCK IS TOWARD BOTTOM RIGHT}
   ExcelSelectCell(Excel,RowWas,ColWas);
   Excel.SendKeys('+{END}+{RIGHT}');
   Excel.SendKeys('+{END}+{DOWN}');
   Result := True;
 Except
   Result := False;
 End;
End;

Function IsBlockColSide(Excel : Variant; RowNum, ColNum: Integer): Boolean;
Var
 RowWas            : Integer;
 ColWas            : Integer;
 CellFirstSide     : Integer;
 CellLastSide      : Integer;
 FirstSideLastSide : Integer;
 LastSideFirstSide : Integer;
Begin
 ExcelSelectCell(Excel,RowNum,ColNum);
 CellFirstSide := ExcelFirstCol(Excel);
 CellLastSide  := ExcelLastCol(Excel);
 ExcelSelectCell(Excel,RowNum,CellFirstSide);
 FirstSideLastSide := ExcelLastCol(Excel);
 ExcelSelectCell(Excel,RowNum,CellLastSide);
 LastSideFirstSide := ExcelFirstCol(Excel);
 ExcelSelectCell(Excel,RowNum,ColNum);
 If (LastSideFirstSide = ColNum) Or
    (FirstSideLastSide = ColNum) Then
 Begin
   Result := True;
 End
 Else
 Begin
   Result := False;
 End;
End;

Function IsBlockRowSide(Excel : Variant; RowNum, ColNum: Integer): Boolean;
Var
 RowWas            : Integer;
 ColWas            : Integer;
 CellFirstSide     : Integer;
 CellLastSide      : Integer;
 FirstSideLastSide : Integer;
 LastSideFirstSide : Integer;
Begin
 ExcelSelectCell(Excel,RowNum,ColNum);
 CellFirstSide := ExcelFirstRow(Excel);
 CellLastSide  := ExcelLastRow(Excel);
 ExcelSelectCell(Excel,CellFirstSide,ColNum);
 FirstSideLastSide := ExcelLastRow(Excel);
 ExcelSelectCell(Excel,CellLastSide,ColNum);
 LastSideFirstSide := ExcelFirstRow(Excel);
 ExcelSelectCell(Excel,RowNum,ColNum);
 If (LastSideFirstSide = RowNum) Or
    (FirstSideLastSide = RowNum) Then
 Begin
   Result := True;
 End
 Else
 Begin
   Result := False;
 End;
End;

{!~Renames a worksheet.}
Function ExcelRenameSheet(
 Excel         : Variant;
 OldName       : ShortString;
 NewName       : ShortString): Boolean;
Begin
 Result := False;
 Try
   Excel.Sheets(OldName).Name := NewName;
   Result := True;
 Except
   Result := False;
 End;
End;

{!~Delete a WorkSheet by Name}
Function ExcelDeleteWorkSheet(
 Excel     : Variant;
 SheetName : ShortString): Boolean;
Begin
 Result := False;
 Try
   If Not ExcelSelectSheetByName(Excel,SheetName) Then
   Begin
     Msg('Could not select the '+SheetName+' WorkSheet');
     Exit;
   End;
   Excel.ActiveWindow.SelectedSheets.Delete;
   Result := True;
 Finally
   Result := False;
 End;
End;

{!~Returns the name of the currently active worksheet as a shortstring}
Function ExcelGetActiveSheetName(Excel : Variant): ShortString;
Begin
 Result := '';
 Try
   Result := Excel.ActiveSheet.Name;
 Except
   Result := '';
 End;
End;

{!~Saves the range on the currently active sheet to values only.}
Function ExcelValuesOnly(
 Excel         : Variant;
 ExcelFirstRow : Integer;
 ExcelFirstCol : Integer;
 ExcelLastRow  : Integer;
 ExcelLastCol  : Integer): Boolean;
Var
 r,c : Integer;
 s   : ShortString;
Begin
 Result := False;
 Try
   If ExcelVersion(Excel) = '8.0' Then
   Begin
     For r := ExcelFirstRow To ExcelLastRow Do
     Begin
       For c := ExcelFirstCol To ExcelLastCol Do
       Begin
         s := Excel.Cells[r,c].Value;
         Excel.Cells[r, c].Value := s;
       End;
     End;
   End
   Else
   Begin
     ExcelPasteValuesOnly(
       Excel,
       ExcelFirstRow,
       ExcelFirstCol,
       ExcelLastRow,
       ExcelLastCol);
   End;
   Result := True;;
 Except
   Result := False;
 End;
End;

{!~Gets the formula in a cell.}
Function ExcelGetCellFormula(
 Excel         : Variant;
 RowNum, ColNum: Integer): ShortString;
Begin
 Result := ' ';
 Try
   Result := Excel.
               ActiveSheet.
               Cells[RowNum, ColNum].
               Formula;
 Except
   Result := ' ';
 End;
End;

{!~Returns the Excel Version as a ShortString.}
Function ExcelVersion(Excel: Variant): ShortString;
Var
 Version : ShortString;
Begin
 Result := '';
 Try
   Version := Excel.Version;
   Result := Version;
 Except
   Result := '';
 End;
End;

Initialization
 DelphiChecker(
   RunOutsideIDE_ads,
   'Advanced Delphi Systems Code',
   RunOutsideIDECompany_ads,
   RunOutsideIDEPhone_ads,
   RunOutsideIDEDate_ads);
End.
来自:yzhshi, 时间:2001-12-2 10:04:00, ID:758347
既然大家都在这里将自己的东西贴出来,那我就再贴一个,将DBGrid中的文件转换到Excel中或者转换到Txt中的控件。
我自己编写的,希望大家讨论一下。
unit DBGridExport;

interface

uses
  SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, Db, DBGrids, Comobj, extctrls, comctrls, ActiveX;

type
  TSpaceMark = (csComma, csSemicolon, csTab, csBlank, csEnter);

  TDBGridExport = class(TComponent)
  private
    FDB_Grid: TDBGrid;                                      {读取DBGrid的源}

    FTxtFileName: string;                                   {文本文件名}
    FSpaceMark: TSpaceMark;                                 {间隔符号}
    FSpace_Ord: Integer;                                    {间隔符号的Asc数值}
    FTitle: string;                                         {显示的标题}
    FSheetName: string;                                     {工作表标题}
    FExcel_Handle: OleVariant;                              {Excel的句柄}

    FWorkbook_Handle: OleVariant;                           {书签的句柄}

    FShow_Progress: Boolean;                                {是否显示插入进度}

    FProgress_Form: TForm;                                  {进度窗体}
    FRun_Excel_Form: TForm;                                 {启动Excel提示窗口}
    FProgressBar: TProgressBar;                             {进度条}

    function Connect_Excel: Boolean;                        {启动Excel}
    function New_Workbook: Boolean;                         {插入新的工作博}
    function InsertData_To_Excel: Boolean;                  {插入数据}
    procedure Create_ProgressForm(AOwner: TComponent);      {创建进度显示窗口}
    procedure Create_Run_Excel_Form(AOwner: TComponent);    {创建启动Excel窗口}
    procedure SetSpaceMark(Value: TSpaceMark);              {设置导出时的间隔符号}
  protected
  public
    constructor Create(AOwner: TComponent); override;       {新建}
    destructor Destroy; override;                           {销毁}
    function Export_To_Excel: Boolean; overload;            {导出到Excel中}
    function Export_To_Excel(DB_Grid: TDBGrid): Boolean; overload;

    function Export_To_Txt(NewFile: Boolean = True): Boolean; overload; {导出到文本文件中}
    function Export_To_Txt(FileName: string; NewFile: Boolean = True): Boolean; overload;
    function Export_To_Txt(DB_Grid: TDBGrid; NewFile: Boolean = True): Boolean; overload;
    function Export_To_Txt(FileName: string; DB_Grid: TDBGrid; NewFile: Boolean = True): Boolean; overload;

  published
    property DB_Grid: TDBGrid read FDB_Grid write FDB_Grid;
    property Show_Progress: Boolean read FShow_Progress write FShow_Progress;
    property TxtFileName: string read FTxtFileName write FTxtFileName;
    property SpaceMark: TSpaceMark read FSpaceMark write SetSpaceMark;
    property Title: string read FTitle write FTitle;
    property SheetName: string read FSheetName write FSheetName;
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('Stone', [TDBGridExport]);
end;

{-------------------------------------------------------------------------------}
{新建}
constructor TDBGridExport.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FShow_Progress := True;
  FSpaceMark := csTab;
end;

{销毁}
destructor TDBGridExport.Destroy;
begin
  varClear(FExcel_Handle);
  varClear(FWorkbook_Handle);
  inherited Destroy;
end;

{===============================================================================}
{导出到文本文件中}
function TDBGridExport.Export_To_Txt(NewFile: Boolean = True): Boolean;
var
  Txt: TStrings;
  Tmp_Str: string;
  data_Str: string;
  i, j: Integer;
  Column_name: string;
  Data_Set: TDataSet;

  bookmark: pointer;
  Before_Scroll, Afrer_Scroll: TDataSetNotifyEvent;
begin
  Result := False;

  if NewFile = True then
    FTxtFileName := '';
  if FTxtFileName = '' then
  begin
    with TSaveDialog.Create(nil) do
    begin
      Title := '请选择输出文件名';
      DefaultExt := 'txt';
      Filter := '文本文件(*.Txt)|*.txt';
      Options := [ofOverwritePrompt, ofHideReadOnly, ofPathMustExist, ofNoReadOnlyReturn, ofEnableSizing];
      if Execute then
        FTxtFileName := FileName;
      Free;
      if FTxtFileName = '' then                             {如果没有选中文件,则直接推出}
        exit;
    end;

    if FTxtFileName = '' then
    begin
      raise exception.Create('没有指定输出文件');
      Exit;
    end;

  end;

  if FDB_Grid = nil then
    raise exception.Create('请输入DBGrid名称');

  Txt := TStringList.Create;
  try
    {显示插入进度}
    if FShow_Progress = True then
    begin
      Create_ProgressForm(nil);
      FProgress_Form.Show;
    end;

    {第一行,插入标题}
    Tmp_Str := '';                                          //FDB_Grid.Columns[0].Title.Caption;
    for i := 1 to FDB_Grid.Columns.Count do
      if FDB_Grid.Columns[i - 1].Visible = True then
        Tmp_Str := Tmp_Str + FDB_Grid.Columns[i - 1].Title.Caption + Chr(FSpace_Ord);

    Tmp_Str := Copy(Tmp_Str, 1, Length(Tmp_Str) - 1);

    Txt.Add(Tmp_Str);

   {插入DBGrid中的数据}
    Data_Set := FDB_Grid.DataSource.DataSet;
   {记忆当前位置并取消任何事件}
//  new(bookmark);
    bookmark := Data_Set.GetBookmark;

    Data_Set.DisableControls;
    Before_Scroll := Data_Set.BeforeScroll;
    Afrer_Scroll := Data_Set.AfterScroll;
    Data_Set.BeforeScroll := nil;
    Data_Set.AfterScroll := nil;

    if FShow_Progress = True then
    begin
      Data_Set.Last;
      FProgress_Form.Refresh;
      FProgressBar.Max := Data_Set.RecordCount;
    end;

    {插入DBGrid中的所有字段}
    Data_Set.First;

    j := 2;
    while not Data_Set.Eof do
    begin
      if FShow_Progress = True then
        FProgressBar.Position := j - 2;

      Column_name := FDB_Grid.Columns[0].FieldName;
      Tmp_Str := '';                                        //Data_Set.FieldByName(Column_name).AsString;
      for i := 1 to FDB_Grid.Columns.Count do
        if FDB_Grid.Columns[i - 1].Visible = True then
        begin
          data_Str := FDB_Grid.Fields[i - 1].DisplayText;
          Tmp_Str := Tmp_Str + data_Str + Chr(FSpace_Ord);
        end;

      Tmp_Str := Copy(Tmp_Str, 1, Length(Tmp_Str) - 1);
      Txt.Add(Tmp_Str);

      j := j + 1;
      Data_Set.Next;
    end;

    {恢复原始事件以及标志位置}
    Data_Set.GotoBookmark(bookmark);
    Data_Set.FreeBookmark(bookmark);
//  dispose(bookmark);
    Data_Set.EnableControls;
    Data_Set.BeforeScroll := Before_Scroll;
    Data_Set.AfterScroll := Afrer_Scroll;

    {写到文件}
    Txt.SaveToFile(FTxtFileName);
    Result := True;
  finally
    Txt.Free;
    if FShow_Progress = True then
    begin
      FProgress_Form.Free;
      FProgress_Form := nil;
    end;
  end;
end;

function TDBGridExport.Export_To_Txt(FileName: string; NewFile: Boolean = True): Boolean;
begin
  FTxtFileName := FileName;
  Result := Export_To_Txt(NewFile);
end;

function TDBGridExport.Export_To_Txt(DB_Grid: TDBGrid; NewFile: Boolean = True): Boolean;
begin
  FDB_Grid := DB_Grid;
  Result := Export_To_Txt(NewFile);
end;

function TDBGridExport.Export_To_Txt(FileName: string; DB_Grid: TDBGrid; NewFile: Boolean = True): Boolean;
begin
  FTxtFileName := FileName;
  FDB_Grid := DB_Grid;
  Result := Export_To_Txt(NewFile);
end;

{-------------------------------------------------------------------------------}
{设置导出时的间隔符号}
procedure TDBGridExport.SetSpaceMark(Value: TSpaceMark);
begin
  FSpaceMark := Value;
  case Value of
    csComma: FSpace_Ord := ord(',');
    csSemicolon: FSpace_Ord := ord(';');
    csTab: FSpace_Ord := 9;
    csBlank: FSpace_Ord := 32;
    csEnter: FSpace_Ord := 13;
  end;
end;


{===============================================================================}
{导出到Excel中}
function TDBGridExport.Export_To_Excel: Boolean;
begin
  if FDB_Grid = nil then
    raise exception.Create('请输入DBGrid名称');

  Result := False;
  if Connect_Excel = True then
    if New_Workbook = True then
      if InsertData_To_Excel = True then
        Result := True;
end;

function TDBGridExport.Export_To_Excel(DB_Grid: TDBGrid): Boolean;
begin
  FDB_Grid := DB_Grid;
  Result := Export_To_Excel;
end;


{-------------------------------------------------------------------------------}
{启动Excel}
function TDBGridExport.Connect_Excel: Boolean;
  {连接Ole对象}
  function My_GetActiveOleObject(const ClassName: string; out Ole_Handle: IDispatch): Boolean;
  var                                                       //IDispatch
    ClassID: TCLSID;
    Unknown: IUnknown;
    l_Result: HResult;
  begin
    Result := False;

    l_Result := CLSIDFromProgID(PWideChar(WideString(ClassName)), ClassID);
    if (l_Result and $80000000) = 0 then
    begin
      l_Result := GetActiveObject(ClassID, nil, Unknown);
      if (l_Result and $80000000) = 0 then
      begin
        l_Result := Unknown.QueryInterface(IDispatch, Ole_Handle);
        if (l_Result and $80000000) = 0 then
          Result := True;
      end;
    end;
  end;

  {创建OLE对象}
  function My_CreateOleObject(const ClassName: string; out Ole_Handle: IDispatch): Boolean;
  var
    ClassID: TCLSID;
    l_Result: HResult;
  begin
    Result := False;

    l_Result := CLSIDFromProgID(PWideChar(WideString(ClassName)), ClassID);
    if (l_Result and $80000000) = 0 then
    begin
      l_Result := CoCreateInstance(ClassID, nil, CLSCTX_INPROC_SERVER or
        CLSCTX_LOCAL_SERVER, IDispatch, Ole_Handle);
      if (l_Result and $80000000) = 0 then
        Result := True;
    end;
  end;

var
  l_Excel_Handle: IDispatch;
begin
  if FShow_Progress = True then
  begin
    Create_Run_Excel_Form(nil);
    FRun_Excel_Form.Show;
  end;

  if My_GetActiveOleObject('Excel.Application', l_Excel_Handle) = False then
    if My_CreateOleObject('Excel.Application', l_Excel_Handle) = False then
    begin
      FRun_Excel_Form.Free;
      FRun_Excel_Form := nil;

      raise exception.Create('启动Excel失败,可能没有安装Excel!');
      Result := False;
      Exit;
    end;
  FExcel_Handle := l_Excel_Handle;

  if FShow_Progress = True then
  begin
    FRun_Excel_Form.Free;
    FRun_Excel_Form := nil;
  end;
  Result := True;
end;

{插入新的工作博}
function TDBGridExport.New_Workbook: Boolean;
var
  i: Integer;
begin
  Result := True;
  try
    FWorkbook_Handle := FExcel_Handle.Workbooks.Add;
  except
    raise exception.Create('新建Excel工作表出错!');
    Result := False;
    Exit;
  end;

  if FTitle <> '' then
    FWorkbook_Handle.Application.ActiveWindow.Caption := FTitle;
  if FSheetName <> '' then
  begin
    for i := 2 to FWorkbook_Handle.Sheets.Count do
      if FSheetName = FWorkbook_Handle.Sheets[i].Name then
      begin
        raise exception.Create('工作表命名重复!');
        Result := False;
        exit;
      end;
    try
      FWorkbook_Handle.Sheets[1].Name := FSheetName;
    except
      raise exception.Create('工作表命名错误!');
      Result := False;
      exit;
    end;
  end;
end;

{插入数据}
function TDBGridExport.InsertData_To_Excel: Boolean;
var
  i, j, k: Integer;
  data_Str: string;
  Column_name: string;
  Data_Set: TDataSet;

  bookmark: pointer;
  Before_Scroll, Afrer_Scroll: TDataSetNotifyEvent;
begin
  try
    {显示插入进度}
    if FShow_Progress = True then
    begin
      Create_ProgressForm(nil);
      FProgress_Form.Show;
    end;

    {第一行,插入标题}{仅仅插入可见数据}
    j := 1;
    for i := 1 to FDB_Grid.Columns.Count do
      if FDB_Grid.Columns[i - 1].Visible = True then
      begin
        FWorkbook_Handle.WorkSheets[1].Cells[1, j].Value := FDB_Grid.Columns[i - 1].Title.Caption;
        FWorkbook_Handle.WorkSheets[1].Columns[j].ColumnWidth := FDB_Grid.Columns[i - 1].Width div 6;
        j := j + 1
      end;

   {插入DBGrid中的数据}
    Data_Set := FDB_Grid.DataSource.DataSet;
   {记忆当前位置并取消任何事件}
//  new(bookmark);
    bookmark := Data_Set.GetBookmark;

    Data_Set.DisableControls;
    Before_Scroll := Data_Set.BeforeScroll;
    Afrer_Scroll := Data_Set.AfterScroll;
    Data_Set.BeforeScroll := nil;
    Data_Set.AfterScroll := nil;

    if FShow_Progress = True then
    begin
      Data_Set.Last;
      FProgress_Form.Refresh;
      FProgressBar.Max := Data_Set.RecordCount;
    end;

    Data_Set.First;

    k := 2;
    while not Data_Set.Eof do
    begin
      if FShow_Progress = True then
        FProgressBar.Position := k;

      j := 1;
      for i := 1 to FDB_Grid.Columns.Count do
      begin
        if FDB_Grid.Columns[i - 1].Visible = True then
        begin
          Column_name := FDB_Grid.Columns[i - 1].FieldName;
          data_Str := FDB_Grid.Fields[i - 1].DisplayText;
          FWorkbook_Handle.WorkSheets[1].Cells[k, j].Value := data_Str;
          j := j + 1;
        end;
      end;
      k := k + 1;
      Data_Set.Next;
    end;

    {恢复原始事件以及标志位置}
    Data_Set.GotoBookmark(bookmark);
    Data_Set.FreeBookmark(bookmark);
//  dispose(bookmark);
    Data_Set.EnableControls;
    Data_Set.BeforeScroll := Before_Scroll;
    Data_Set.AfterScroll := Afrer_Scroll;

    Result := True;
  finally
    FExcel_Handle.Visible := True;
    FExcel_Handle.Application.ScreenUpdating := True;

    if FShow_Progress = True then
    begin
      FProgress_Form.Free;
      FProgress_Form := nil;
    end;
  end;
end;

{===============================================================================}
{启动Excel时给出进度显示}
procedure TDBGridExport.Create_Run_Excel_Form(AOwner: TComponent);
var
  Panel: TPanel;
  Prompt: TLabel;                                           {提示的标签}
begin
  if assigned(FRun_Excel_Form) then exit;

  FRun_Excel_Form := TForm.Create(AOwner);
  with FRun_Excel_Form do
  begin
    try
      Font.Name := '宋体';                                  {设置字体}
      Font.Size := 9;
      BorderStyle := bsNone;
      Width := 300;
      Height := 100;
      BorderWidth := 2;
      Color := clBlue;
      Position := poScreenCenter;

      Panel := TPanel.Create(FRun_Excel_Form);
      with Panel do
      begin
        Parent := FRun_Excel_Form;
        Align := alClient;
        BevelInner := bvNone;
        BevelOuter := bvRaised;
        Caption := '';
      end;

      Prompt := TLabel.Create(Panel);
      with Prompt do
      begin
        Parent := panel;
        AutoSize := True;
        Left := 25;
        Top := 25;
        Caption := '正在导出数据,请稍候……';
      end;
    except
    end;
  end;
end;


{===============================================================================}
{创建进度显示窗口}
procedure TDBGridExport.Create_ProgressForm(AOwner: TComponent);
var
  Panel: TPanel;
  Prompt: TLabel;                                           {提示的标签}
begin
  if assigned(FProgress_Form) then exit;

  FProgress_Form := TForm.Create(AOwner);
  with FProgress_Form do
  begin
    try
      Font.Name := '宋体';                                  {设置字体}
      Font.Size := 9;
      BorderStyle := bsNone;
      Width := 300;
      Height := 100;
      BorderWidth := 2;
      Color := clBlue;
      Position := poScreenCenter;
      Panel := TPanel.Create(FProgress_Form);
      with Panel do
      begin
        Parent := FProgress_Form;
        Align := alClient;
        BevelInner := bvNone;
        BevelOuter := bvRaised;
        Caption := '';
      end;

      Prompt := TLabel.Create(Panel);
      with Prompt do
      begin
        Parent := panel;
        AutoSize := True;
        Left := 25;
        Top := 25;
        Caption := '正在导出数据,请稍候……';
      end;

      FProgressBar := TProgressBar.Create(panel);
      with FProgressBar do
      begin
        Parent := panel;
        Left := 20;
        Top := 50;
        Height := 18;
        Width := 260;
      end;
    except
    end;
  end;
end;


end.
来自:饿饱鹅, 时间:2001-12-3 14:59:00, ID:760596
听君一席话,胜读十年书!
来自:yzhshi, 时间:2001-12-3 17:40:00, ID:761141
如何取消Word2000中的宏病毒提示

Word采用了宏作为其字处理系统的补充,是用户能够自己编写一部分代码来实现自己特定
的功能,大大方便了其他系统和Word之间的连接,但是同时也带来了负面的问题,人们可
以编写一些恶意的代码,危害系统的安全,从台湾No.1病毒开始到现在的美丽沙病毒,无
一不对系统造成一定危害。
为了避免这个缺点,微软提供了防病毒防护的功能,在Word97的《工具》->《选项》->《常规》
中有宏病毒防护的选项,在Word2000提供了高、中、低三种宏病毒安全级别。在Word97中
可以使用Options.VirusProtection = False来取消宏病毒防护,这样就给宏病毒提供了
机会,只要你运行过一个宏病毒,它就自动将宏病毒防护关闭,因此防护宏病毒的能力
不是太强。
在Word2000中,微软提供了宏认证的解决方案,根据证书认证机制来实现,如果宏不含有数字
签名整数,那么如果安全级别设置为高,则直接禁用宏,如果安全级别是中,则提示用户是否
启用宏,如果安全级别是无,则任何宏都能够能够运行了。
如果宏提供了认证证书,则Word将检查认证证书,判断其有效性,并提示用户是否接受该证书,
如果用户接受了该证书,则以后就不再显示使用该证书签名的宏警告。

现在问题出来了,我们自己编写的宏,如何进行认证呢?怎么进行认证呢?
通常人们会去找宏病毒安全性里面,但是在它的可靠来源列表中就是不能添加,只能删除,那么
从那里添加呢?
其实,Word提供了添加的途径,就是在Word的Visual Basic编辑器里面《工具》->《数字签名》,
选择相应证书即可.但是问题又有了,如何能够添加证书呢,通常我们打开的时候发觉可选择证书
空空的。
有两种途径可以解决这个问题,一是向证书颁发机构申请数字签名,申请的时候选择用途为代码的
数字签名就可以了,然后安装上申请下来的Cer文件直接安装就可以了,但是在打开含有此数字签
名的宏的时候,计算机必须和证书办法机构联网,否则会提示证书无效.
另一种途径是自己创建证书,Word2000提供了一个自己进行数字签名的工具:SelfCert.exe,路径
为《Office安装路径》/Office/SELFCERT.EXE,运行此文件,输入名字即可产生。
至此我们可以生成证书了,也就可以进行数字签名了。
来自:yzhshi, 时间:2001-12-3 17:45:00, ID:761147
就这些了!到今天为止,将我摸索Ole的所有心得都写出来了。供大家讨论吧。
帖子太长了,打开速度慢了许多。
来自:hpretty, 时间:2001-12-3 18:20:00, ID:761211
多谢!!
来自:sandy suen, 时间:2001-12-4 8:54:00, ID:761862
这页的好资料真多,我也跟贴在这里吧。

Delphi 5 控制Excel

            作者:吴晓勇,孙唏瑜
            时间:2001年11月20日

(一) 使用动态创建的方法

首先创建 Excel 对象,使用ComObj:
var ExcelApp: Variant;
ExcelApp := CreateOleObject( 'Excel.Application' );

1) 显示当前窗口:
ExcelApp.Visible := True;

2) 更改 Excel 标题栏:
ExcelApp.Caption := '应用程序调用 Microsoft Excel';

3) 添加新工作簿:
ExcelApp.WorkBooks.Add;

4) 打开已存在的工作簿:
ExcelApp.WorkBooks.Open( 'C:/Excel/Demo.xls' );

5) 设置第2个工作表为活动工作表:
ExcelApp.WorkSheets[2].Activate;  
或 
ExcelApp.WorksSheets[ 'Sheet2' ].Activate;

6) 给单元格赋值:
ExcelApp.Cells[1,4].Value := '第一行第四列';

7) 设置指定列的宽度(单位:字符个数),以第一列为例:
ExcelApp.ActiveSheet.Columns[1].ColumnsWidth := 5;

8) 设置指定行的高度(单位:磅)(1磅=0.035厘米),以第二行为例:
ExcelApp.ActiveSheet.Rows[2].RowHeight := 1/0.035; // 1厘米

9) 在第8行之前插入分页符:
ExcelApp.WorkSheets[1].Rows.PageBreak := 1;

10) 在第8列之前删除分页符:
ExcelApp.ActiveSheet.Columns[4].PageBreak := 0;

11) 指定边框线宽度:
ExcelApp.ActiveSheet.Range[ 'B3:D4' ].Borders[2].Weight := 3;
1-左    2-右   3-顶    4-底   5-斜( / )     6-斜( / )

12) 清除第一行第四列单元格公式:
ExcelApp.ActiveSheet.Cells[1,4].ClearContents;

13) 设置第一行字体属性:
ExcelApp.ActiveSheet.Rows[1].Font.Name := '隶书';
ExcelApp.ActiveSheet.Rows[1].Font.Color  := clBlue;
ExcelApp.ActiveSheet.Rows[1].Font.Bold   := True;
ExcelApp.ActiveSheet.Rows[1].Font.UnderLine := True;

14) 进行页面设置:

a.页眉:
    ExcelApp.ActiveSheet.PageSetup.CenterHeader := '报表演示';
b.页脚:
    ExcelApp.ActiveSheet.PageSetup.CenterFooter := '第&P页';
c.页眉到顶端边距2cm:
    ExcelApp.ActiveSheet.PageSetup.HeaderMargin := 2/0.035;
d.页脚到底端边距3cm:
    ExcelApp.ActiveSheet.PageSetup.HeaderMargin := 3/0.035;
e.顶边距2cm:
    ExcelApp.ActiveSheet.PageSetup.TopMargin := 2/0.035;
f.底边距2cm:
    ExcelApp.ActiveSheet.PageSetup.BottomMargin := 2/0.035;
g.左边距2cm:
    ExcelApp.ActiveSheet.PageSetup.LeftMargin := 2/0.035;
h.右边距2cm:
    ExcelApp.ActiveSheet.PageSetup.RightMargin := 2/0.035;
i.页面水平居中:
    ExcelApp.ActiveSheet.PageSetup.CenterHorizontally := 2/0.035;
j.页面垂直居中:
    ExcelApp.ActiveSheet.PageSetup.CenterVertically := 2/0.035;
k.打印单元格网线:
    ExcelApp.ActiveSheet.PageSetup.PrintGridLines := True;

15) 拷贝操作:

a.拷贝整个工作表:
    ExcelApp.ActiveSheet.Used.Range.Copy;
b.拷贝指定区域:
    ExcelApp.ActiveSheet.Range[ 'A1:E2' ].Copy;
c.从A1位置开始粘贴:
    ExcelApp.ActiveSheet.Range.[ 'A1' ].PasteSpecial;
d.从文件尾部开始粘贴:
    ExcelApp.ActiveSheet.Range.PasteSpecial;

16) 插入一行或一列:
a. ExcelApp.ActiveSheet.Rows[2].Insert;
b. ExcelApp.ActiveSheet.Columns[1].Insert;

17) 删除一行或一列:
a. ExcelApp.ActiveSheet.Rows[2].Delete;
b. ExcelApp.ActiveSheet.Columns[1].Delete;

18) 打印预览工作表:
ExcelApp.ActiveSheet.PrintPreview;

19) 打印输出工作表:
ExcelApp.ActiveSheet.PrintOut;

20) 工作表保存:
if not ExcelApp.ActiveWorkBook.Saved then
   ExcelApp.ActiveSheet.PrintPreview;

21) 工作表另存为:
ExcelApp.SaveAs( 'C:/Excel/Demo1.xls' );

22) 放弃存盘:
ExcelApp.ActiveWorkBook.Saved := True;

23) 关闭工作簿:
ExcelApp.WorkBooks.Close;

24) 退出 Excel:
ExcelApp.Quit;

(二) 使用Delphi 控件方法
在Form中分别放入ExcelApplication, ExcelWorkbook和ExcelWorksheet。 

1)  打开Excel 
ExcelApplication1.Connect;

2) 显示当前窗口:
ExcelApplication1.Visible[0]:=True;

3) 更改 Excel 标题栏:
ExcelApplication1.Caption := '应用程序调用 Microsoft Excel';

4) 添加新工作簿:
ExcelWorkbook1.ConnectTo(ExcelApplication1.Workbooks.Add(EmptyParam,0));
 
5) 添加新工作表:
var Temp_Worksheet: _WorkSheet;
begin
Temp_Worksheet:=ExcelWorkbook1.
WorkSheets.Add(EmptyParam,EmptyParam,EmptyParam,EmptyParam,0) as _WorkSheet;
ExcelWorkSheet1.ConnectTo(Temp_WorkSheet);
End;
 
6) 打开已存在的工作簿:
ExcelApplication1.Workbooks.Open (c:/a.xls
EmptyParam,EmptyParam,EmptyParam,EmptyParam,
EmptyParam,EmptyParam,EmptyParam,EmptyParam,
    EmptyParam,EmptyParam,EmptyParam,EmptyParam,0)

7) 设置第2个工作表为活动工作表:
ExcelApplication1.WorkSheets[2].Activate;  或
ExcelApplication1.WorksSheets[ 'Sheet2' ].Activate;

8) 给单元格赋值:
ExcelApplication1.Cells[1,4].Value := '第一行第四列';

9) 设置指定列的宽度(单位:字符个数),以第一列为例:
ExcelApplication1.ActiveSheet.Columns[1].ColumnsWidth := 5;

10) 设置指定行的高度(单位:磅)(1磅=0.035厘米),以第二行为例:
ExcelApplication1.ActiveSheet.Rows[2].RowHeight := 1/0.035; // 1厘米

11) 在第8行之前插入分页符:
ExcelApplication1.WorkSheets[1].Rows.PageBreak := 1;

12) 在第8列之前删除分页符:
ExcelApplication1.ActiveSheet.Columns[4].PageBreak := 0;

13) 指定边框线宽度:
ExcelApplication1.ActiveSheet.Range[ 'B3:D4' ].Borders[2].Weight := 3;
1-左    2-右   3-顶    4-底   5-斜( / )     6-斜( / )

14) 清除第一行第四列单元格公式:
ExcelApplication1.ActiveSheet.Cells[1,4].ClearContents;

15) 设置第一行字体属性:
ExcelApplication1.ActiveSheet.Rows[1].Font.Name := '隶书';
ExcelApplication1.ActiveSheet.Rows[1].Font.Color  := clBlue;
ExcelApplication1.ActiveSheet.Rows[1].Font.Bold   := True;
ExcelApplication1.ActiveSheet.Rows[1].Font.UnderLine := True;

16) 进行页面设置:
 a.页眉:
    ExcelApplication1.ActiveSheet.PageSetup.CenterHeader := '报表演示';
b.页脚:
    ExcelApplication1.ActiveSheet.PageSetup.CenterFooter := '第&P页';
c.页眉到顶端边距2cm:
    ExcelApplication1.ActiveSheet.PageSetup.HeaderMargin := 2/0.035;
d.页脚到底端边距3cm:
    ExcelApplication1.ActiveSheet.PageSetup.HeaderMargin := 3/0.035;
e.顶边距2cm:
    ExcelApplication1.ActiveSheet.PageSetup.TopMargin := 2/0.035;
f.底边距2cm:
    ExcelApplication1.ActiveSheet.PageSetup.BottomMargin := 2/0.035;
g.左边距2cm:
    ExcelApplication1.ActiveSheet.PageSetup.LeftMargin := 2/0.035;
h.右边距2cm:
    ExcelApplication1.ActiveSheet.PageSetup.RightMargin := 2/0.035;
i.页面水平居中:
    ExcelApplication1.ActiveSheet.PageSetup.CenterHorizontally := 2/0.035;
j.页面垂直居中:
    ExcelApplication1.ActiveSheet.PageSetup.CenterVertically := 2/0.035;
k.打印单元格网线:
    ExcelApplication1.ActiveSheet.PageSetup.PrintGridLines := True;

17) 拷贝操作:

a.拷贝整个工作表:
    ExcelApplication1.ActiveSheet.Used.Range.Copy;

b.拷贝指定区域:
    ExcelApplication1.ActiveSheet.Range[ 'A1:E2' ].Copy;

c.从A1位置开始粘贴:
    ExcelApplication1.ActiveSheet.Range.[ 'A1' ].PasteSpecial;

d.从文件尾部开始粘贴:
    ExcelApplication1.ActiveSheet.Range.PasteSpecial;

18) 插入一行或一列:
a. ExcelApplication1.ActiveSheet.Rows[2].Insert;
b. ExcelApplication1.ActiveSheet.Columns[1].Insert;

19) 删除一行或一列:
a. ExcelApplication1.ActiveSheet.Rows[2].Delete;
b. ExcelApplication1.ActiveSheet.Columns[1].Delete;

20) 打印预览工作表:
ExcelApplication1.ActiveSheet.PrintPreview;

21) 打印输出工作表:
ExcelApplication1.ActiveSheet.PrintOut;

22) 工作表保存:
if not ExcelApplication1.ActiveWorkBook.Saved then
   ExcelApplication1.ActiveSheet.PrintPreview;

23) 工作表另存为:
ExcelApplication1.SaveAs( 'C:/Excel/Demo1.xls' );

24) 放弃存盘:
ExcelApplication1.ActiveWorkBook.Saved := True;

25) 关闭工作簿:
ExcelApplication1.WorkBooks.Close;

26) 退出 Excel:
ExcelApplication1.Quit;
ExcelApplication1.Disconnect;

(三) 使用Delphi 控制Excle二维图
在Form中分别放入ExcelApplication, ExcelWorkbook和ExcelWorksheet
var asheet1,achart, range:variant;

1)选择当第一个工作薄第一个工作表
asheet1:=ExcelApplication1.Workbooks[1].Worksheets[1];

2)增加一个二维图
achart:=asheet1.chartobjects.add(100,100,200,200);

3)选择二维图的形态
achart.chart.charttype:=4;

4)给二维图赋值
series:=achart.chart.seriescollection;
range:=sheet1!r2c3:r3c9;
series.add(range,true);
 
5)加上二维图的标题
achart.Chart.HasTitle:=True;
achart.Chart.ChartTitle.Characters.Text:=’ Excle二维图’          

6)改变二维图的标题字体大小
achart.Chart.ChartTitle.Font.size:=6;

7)给二维图加下标说明
achart.Chart.Axes(xlCategory, xlPrimary).HasTitle := True;
achart.Chart.Axes(xlCategory, xlPrimary).AxisTitle.Characters.Text := '下标说明';

8)给二维图加左标说明
achart.Chart.Axes(xlValue, xlPrimary).HasTitle := True;
achart.Chart.Axes(xlValue, xlPrimary).AxisTitle.Characters.Text := '左标说明';

9)给二维图加右标说明
achart.Chart.Axes(xlValue, xlSecondary).HasTitle := True;
achart.Chart.Axes(xlValue, xlSecondary).AxisTitle.Characters.Text := '右标说明';

10)改变二维图的显示区大小
achart.Chart.PlotArea.Left := 5;
achart.Chart.PlotArea.Width := 223;
achart.Chart.PlotArea.Height := 108;

11)给二维图坐标轴加上说明
achart.chart.seriescollection[1].NAME:='坐标轴说明';
 
E-Mail: sunxiyu@gd-soft.net
           wuxy@gd-soft.net

声明:转载本文内容请与作者联系。
来自:sandy suen, 时间:2001-12-4 9:18:00, ID:761937
RE:yzhshi
其实对于技术问题,我从大富翁得到了许多,尤其是hubdog的葵花宝典,我也希望贡献自己
的一份力量,众人拾柴火焰高!
    请问能不能把“hubdog的葵花宝典”贴在这里,让我们能一次性的打印出来?
来自:FeiDao, 时间:2001-12-4 11:56:00, ID:762461
 to sandy suen:
  hubdog的葵花宝典类似于一个帮助,没办法贴的。很多地方有下载
来自:sandy suen, 时间:2001-12-4 12:25:00, ID:762536
请问哪里有“hubdog的葵花宝典”下载,Google里能找到吗?
来自:yzhshi, 时间:2001-12-4 12:36:00, ID:762566
Delphi开发者资源交流社区。
http://delphi.mychangshu.com/
在下面链接
http://delphi.mychangshu.com/dispdoc.asp?id=168

来自:jqw, 时间:2001-12-4 13:08:00, ID:762677
thx
来自:xeen, 时间:2001-12-4 17:13:00, ID:763451
收藏
来自:zqwzz, 时间:2001-12-4 20:00:00, ID:763772
那有关于access操作的。
在D6中的Severs中关于ACCESS操作的几个控件如何用?
来自:红颜笑, 时间:2001-12-5 19:13:00, ID:766259
宝贝呀~
来自:初学者1, 时间:2001-12-5 20:13:00, ID:766385
好人
来自:yzhshi, 时间:2001-12-5 20:33:00, ID:766436
我觉得对于知识,我们Open一些是最好的。
记得很久以前(2000-9-16)象一位讲Usb的大侠请教,以下是他的回信:

谢谢您的来信,虽然您的信是对我的工作的一种肯定,也从另外一个方面说明目前中国
的技术开发领域的问题,很多的问题不是中国人自己搞不定,很多的时候是工程师的心
目中还没有形成一种和别人share idea的思想。
欢迎来信交流,谢谢!
ferric

我很受感触,很多的时候,我觉得找资料,中文的太少了,尤其是比较专业的,我觉得E文的
最多,BIG5的其次,中文GB的,仅仅能够有些介绍性的(可能太偏激)。
所以,我想以后如果有研究成果,一定Share出来,和大家分享。
而且,我觉得DelphiBBS真的不错!希望大家都能够知无不言,言无不尽!
来自:newsweep, 时间:2001-12-6 12:35:00, ID:767620
Thanks
来自:g622, 时间:2001-12-6 14:48:00, ID:767996
请问有人知道如何在不同语言版本的word里产生文档结构吗?
来自:红颜笑, 时间:2001-12-6 18:42:00, ID:768697
兄台
  如何把msword9.olb中的类导入到delphi中呀~您忘记写了(我问的不会太弱智吧[)
来自:yzhshi, 时间:2001-12-8 12:06:00, ID:772329
直接用Delphi打开那个文件就可以了。
在Office Xp里面文件名为MSWORD.OLB,在/Program Files/Microsoft Office/Office10里面。
来自:风中的沙粒, 时间:2001-12-9 9:33:00, ID:773765
如何使用倒入的库文件呢;能不能给出一个简单例子的详细代码。
怎样才能有代码提示呢;我在一个dll中控制automation,因为要频繁调用这个dll
感觉很慢,1,要不要在主程序中线创建实例化,再用参数传递到dll,(这种参数如何传递呢)
2,creatoleobject与类库导入有什么不同,类库导入的话对象的创建和实例化难道不用
ceratoleobject,还能用别的么。这是不是影响速度的原因之一呢
来自:风中的沙粒, 时间:2001-12-9 9:41:00, ID:773919
我现在想想应该是用getobject进行连结吧,具体参数应是什么,该怎么用呢
来自:yzhshi, 时间:2001-12-9 9:52:00, ID:773931
首先判断内存中是否存在Word,可以使用GetActiveOleObject('Word.Application')来判断。
如果为了避免产生异常,可以看GetActiveOleObject的代码,从其中摘出需要的。
其实,我个人感觉使用CreateOleObject速度不是问题,问题是不能使用Delphi的语法提示了。
一切都需要自己去写。但是一旦熟悉以后,就基本上一样了。
正如bluerain所说的,都只是实现方式不同。
当初我也是在这三个之间选择的,最后选择了上面写的方式,原因呢,是因为方便。它不需要将
所有的参数都添上,写起来几乎和VBA一样,没有语法加亮,我们可以先在VBA里面实验,成功后
再移植过来,其实操作Word所需要的语法并不是特别多,主要的是我上面列出的,一旦掌握了,那么
就很容易了。
来自:yzhshi, 时间:2001-12-9 9:56:00, ID:773934
如果对于一些比较简单的automation,我到建议你直接导入olb文件,这样可以在编码的时候就
直接能够知道是否有此对象,使用我上面讲的方法有一个缺点就是代码必须在执行的时候才判断是否正确。
Delphi不会对此进行检查。
其实Delphi提供的Service控件本身就是帮助我们把Ole文件导入,再以控件的方式提供给我们。
来自:风中的沙粒, 时间:2001-12-9 10:16:00, ID:773956
导入库后,具体与应用程序连结应是什么,
如果用getactiveoleobject,他会提示你dipath,与你实际定义的变量类型(即库中定义的)
不匹配,而且我摘译本美国人编的书中看到,这几种方法,速度确有很大差别
来自:yzhshi, 时间:2001-12-9 10:43:00, ID:774017
对于自己导入msword*.olb文件,可以这样做:
在Delphi中选择Project->Import Type Library,将msword.olb文件添加进来。
然后改变ClasName里面的类名(因为Delphi5以上已经提供了Servers组件)。
在选择Install就可以了。
这样在ActiveX里面就生成了几个控件,直接操作这些控件就可以了。
如打开Word(我这里将WordApplication类重新命名为WordApplication2):
WordApplication21.Connect;
WordApplication21.Visible:=True;
来自:Celestial dog, 时间:2001-12-9 11:28:00, ID:774083
hi yzhshi!
hubdog的葵花宝典是什么好东东??哪里有下载??
我也要!!!
jiangsu_hy@21cn.com
来自:yzhshi, 时间:2001-12-9 11:32:00, ID:774090
再贴一次吧。
Delphi开发者资源交流社区。
http://delphi.mychangshu.com/
在下面链接
http://delphi.mychangshu.com/dispdoc.asp?id=168
来自:Celestial dog, 时间:2001-12-9 11:45:00, ID:774108
谢谢 yzhshi
来自:风中的沙粒, 时间:2001-12-10 22:19:00, ID:778252
我用你上面讲的方法,去倒入autocad.tlb,在insatall的时候居然没有类名,用vb中的引用时
到是类中的方法,属性,事件都看得到,就是连接msword.olb想你一样改了名字install时,却告诉我
msfont类有重名,明明没显这个类名,结果什么都没倒入
来自:yzhshi, 时间:2001-12-11 13:06:00, ID:779545
出现Import Type Library界面后,
下面有ClassName的列表,将其中改名。
难道ClassName中没有列表吗?注意Font那一行没有显示出来,拉动滚动条就看见了。
来自:DragonPC_???, 时间:2001-12-12 14:27:00, ID:782400
>> 风中的沙粒,
Import TypeLibrary的时候,你为什么非得Install呢?为什么不用Create Unit呢,直接
引用这些单元动态生成Automation对象不好吗,你有没有到我推荐的网站研究过呢?有问
题是好事,但是你也应该主动的解决问题,不是走一步,问一步吗。

http://www.techvanguards.com/
看看他的step by step,他逐步教导你了解Automation,看看他调用DOM来解析XML的单元。
来自:yzhshi, 时间:2001-12-12 14:45:00, ID:782456
说实话,我到没有到那个网站去看一下,因为已经有一阶段没有用这些了。刚刚我将它添到
收藏夹里面了,稍微有空我会仔细看的。呵呵。
谢谢DragonPC_???!
来自:风中的沙粒, 时间:2001-12-17 20:54:00, ID:794850
其实是这样的,我所要连结的是autocad14,的类库,你讲的create unit我当然是过
其实和在use中加autocad_tlb效果是一样的,我当然试过,最大的问题是,word,你这样输入类库
后连结可以用object.connect,autocad不行他根本没这样的方法,所以最后一样要用createoleobject
来连结,这样一样看不到提示。你在var ac后看提示,发现它的对象类形式idispatch,这到底是什么?
来自:yzhshi, 时间:2001-12-18 17:01:00, ID:796879
对于Word,或者说Office系列,很多属性、方法我们并不,也不必都知道,实际
使用中可以这样详细了解:
1、查找帮助,D:/Program Files/Microsoft Office/Office10/2052/VBA*.CHM
2、可以在工具->宏->录制新宏,然后去做你想用代码实现的东西,做完后,
到工具->宏->Visual Basic 编辑器里面里面查看相应的宏,就知道如何实现了,
然后在录制的宏中就可以看到你需要的命令了,当然,可能并不都是需要的,取其
中的核心就可以了。
对于Delphi调用,一般也是直接使用即可。
来自:wlmmlw, 时间:2001-12-24 21:06:00, ID:809223
nice
i like it
来自:shineya, 时间:2001-12-28 17:17:00, ID:819435
Pretty good.
来自:Kisber, 时间:2001-12-31 18:10:00, ID:827754
我忘不了饿人谷,到处找她, 不料掉进这...没有恶人的地方。
来自:Jaline, 时间:2002-1-3 14:30:00, ID:832184
Very good
来自:ddntyz, 时间:2002-1-8 17:06:00, ID:843115
yzhshi你好,我有一个问题:
我用OLEContainer打开一个Word文挡,然后把它存为几幅.bmp的图片。这些功能已经实现,但是
我无法控制图片的背景颜色,始终是默认的灰色。能在Word里控制它的颜色吗?
来自:ably, 时间:2002-1-13 22:40:00, ID:854909
gz
来自:zbwsh, 时间:2002-1-14 2:13:00, ID:855086
好东西
来自:jiangxiancheng, 时间:2002-1-14 13:13:00, ID:856098
>>a.通过Delphi的控件TOleContainer 将Word嵌入

>>这是最简单的Ole嵌入,能够直接将Word文档调用,只需要使用ToleContainer.Run就可以将Word文
>>档直接启动。且这样启动的Word文档与Delphi程序是一个整体(从界面上看),但是它存在不可克
>>服的缺点,即不能通过Delphi控制Word文档,也就不能实现将灵活操纵Word的目的。

错误!!
一样可以。
来自:yzhshi, 时间:2002-1-14 13:57:00, ID:856322
是的,当初形成上面文章的时候,对ToleContainer摸的不是特别清楚,所以就下了这个错误结论。
其实,里面的观点还有很多错误的,不过,也有一定的可取之处,所有的都是我的认识吧。
认识事务的层次肯定是在不断增长的。
欢迎提出!
来自:ydfq, 时间:2002-1-14 14:39:00, ID:856442
楼上两位大侠,如何控制oleContainer呢?我正在做这方面的事,正不知如何呢。
先谢谢了。
来自:jrq, 时间:2002-1-14 14:58:00, ID:856506
收藏
来自:yzhshi, 时间:2002-1-14 15:00:00, ID:856509
我只是看了一点关于oleContainer的帖子,真的没有做过。也就没有发言权了。
来自:zhaohai9, 时间:2002-1-14 15:07:00, ID:856543
yzhshi的精神,王寒松的精神,我们应该发扬光大!
来自:yzhshi, 时间:2002-1-14 15:16:00, ID:856582
老兄,不要夸了,好不?我已经被你吹的找不到北了。
来自:SeaHawk, 时间:2002-1-15 8:35:00, ID:858185
最近在用,所以说说。控制OLEContrainter主要是通过OleContainer.OleObject来进行,可以
直接用Ole的方式控制,例如:var WordDocvar:olevariant;worddoc:=OleContainer.OleObject;
如果想取得Word.Application,就必须先Olecontainer.doverb(-1)来产生Word.Application。
然后WordAppvar:=WordDoc.Application。如果想用Servers上的控件,可以加一句:
        WordDoc:=IUnknown(WordDocVar) as TWordDocument; 
不过我的经验是最好直接用接口,不要用TWordDocument,问题多多,而且最好将OleContainer
单独放在一个Form里,Form里最好不要有TEdit、TComboBox这样的具有输入焦点的控件,这样
界面很直观,而且少了很多问题。
      一点经验,欢迎指正。
来自:蛐蛐, 时间:2002-1-15 8:45:00, ID:858209
go on...
来自:yzhshi, 时间:2002-1-15 8:45:00, ID:858210
不错,这样Word和自己的程序就更加融合了。欢迎继续探讨!
来自:winslow, 时间:2002-1-15 13:51:00, ID:859265
大开眼界,发现自己虽也算是搞软件的却什么都不懂,真是惭愧。
真希望能有一位这样的良师益友,可惜....
还有大富翁论坛,真是不错
来自:llh_lily, 时间:2002-1-15 13:58:00, ID:859301
能否说一些控制word中菜单项的方法;如下的vba代码执行后为何菜单项依然存在
Sub Lock_SavetySet()
Dim Bar As CommandBar
Dim DisabelControl As CommandBarControl
Dim i As Integer
  Application.DisplayExcel4Menus = False
  For Each Bar In Application.CommandBars
     If Bar.NameLocal = "Visual Basic" Then
      For i = 1 To Bar.Controls.Count
       If Bar.Controls.Item(i).Caption = "安全..." Then
          Bar.Controls.Item(i).visible = false
          Exit Sub
       End If
      Next
     End If     
  Next
End Sub
来自:yzhshi, 时间:2002-1-15 14:06:00, ID:859327
1、可以使用VBA屏蔽掉相应功能的Office事件,如下,屏蔽了FileSave(保存)选项
Sub FileSave()
'里面什么都不需要加,如果你需要他执行保存的时候还执行别的,那么添加,同时加上下面这句话
' Word.ActiveDocument.Save
End Sub

2、使用Delete方法,可以删除此属性,Visible还可以再次显示,而Delete就……

3、对于实现特定功能,没有必要这么做,你可以将所有VBA代码生成一个dot模板,其他文档
建立/打开的时候以他为基本模板就可以了。
来自:ably, 时间:2002-1-20 19:01:00, ID:872460
gz
来自:完颜康, 时间:2002-1-20 19:04:00, ID:872466
gz
来自:dty129, 时间:2002-1-25 17:05:00, ID:884992
各位大虾,能否教小弟如何实现在EXCEL中导入DELHI中TCHART的图象,(要能分组)
万分感谢!!!
来自:寻找, 时间:2002-1-26 10:31:00, ID:886041
听课
来自:ably, 时间:2002-1-26 12:06:00, ID:886242
我用olecontainer 并WordDoc:=IUnknown(WordDocVar) as TWordDocument; 
但不能预览,不能设置页面,可以打印,请问如何操作
wordapplication.printpreview或worddocument.printpreview不能预览
用server能控制不要它自己关闭,新建,存储吗?
来自:yzhshi, 时间:2002-1-26 12:17:00, ID:886262
这个我没有做过,估计还需要SeaHawk帮忙说一下。
同时,控制他不让他关闭、新建、存储,可以使用函数将那些按钮Disable,然后删除。
但是应付快捷键还需要使用VBA,具体的VBA代码如上。
同时,对于OlE技术,微软本身的说法是仅仅推荐使用浏览,而不推荐修改、保存、打印等。
所以可能实现打印还有一定难度。但是只要努力尝试,应该没问题的。
比如,可以充分利用VBA代码。
来自:ably, 时间:2002-1-26 13:14:00, ID:886351
我用olecontainer ,可以打印,加如字符图形等操作,这是比server的优点,对不对
有时我却时觉得ole会比server功能强大,但不方便
不知如何预览,与页面设置??? 请教高手!!!! 谢谢
用server能控制不要它自己关闭,新建,存储吗?

来自:jiangxiancheng, 时间:2002-1-26 13:35:00, ID:886388
http://www.delphibbs.com/delphibbs/dispq.asp?lid=874308
这个问题谁能解决。
来自:SeaHawk, 时间:2002-1-26 22:45:00, ID:887456
重装了系统,居然收不到大富翁邮件,只好重新激活一次:(
先更正一下,WordDoc:=IUnknown(WordDocVar) as _Document才对。
在Olecontainer确实无法预览和调节打印设置,直接用操作Word对象也不可以保存文件,
但是你可以用Olecontainer自己的SaveToDocument保存文件。
来自:ydfq, 时间:2002-1-26 23:01:00, ID:887478
在Olecontainer中能不能实现滚动?请指教。
来自:HORNEY, 时间:2002-1-26 23:04:00, ID:887484
大家都这么涌跃,我也说两句吧,我是搞OLE自动化的,用过IDISPATCH接口,在DELPHI下
面其用来封装IDispach.Invoke的函数DispachInvoke有BUG,或者可以说这是由于缺少此函
数的帮助所致,所以只能绕过个函数,自己接触IDispach.Invoke,还有,如果是参数是
BSTR的话,对于OFFICE软件是可以通得过的,但是对于ADO却要将参数类型设为
Var_BSTR or Var_ByRef = 8 + 16384 = 16392,这是我三个月的经验总结。。。
来自:SeaHawk, 时间:2002-1-27 17:22:00, ID:888393
搞了我两天,终于摸索出怎样在Word里头添加按钮和相应的处理事件(不是用宏)。
不知道能骗多少分呢?:)
来自:ably, 时间:2002-1-27 17:37:00, ID:888411
>来自:SeaHawk, 时间:2002-1-27 17:22:00, ID:888393 
>搞了我两天,终于摸索出怎样在Word里头添加按钮和相应的处理事件(不是用宏)。
>不知道能骗多少分呢?:)
不是OLE 怎么加按钮和菜单?怎么预览与页面设置?
我送分200,
另,ole或sever怎么加宏,怎么调用,
 
来自:yzhshi, 时间:2002-1-27 17:56:00, ID:888428
是这里了,可惜我不会呀!

示例向命令栏“Custom”添加一个命令栏控件。COM 加载项“FinanceAddIn”将在
每次单击该控件时运行。

Set myBar = CommandBars("Custom")
Set myControl = myBar.Controls _
    .Add(Type:=msocontrolButton)
With myControl
    .FaceId = 2
    .OnAction = "!<FinanceAddIn>"
End With
myBar.Visible = True
来自:yzhshi, 时间:2002-1-27 17:59:00, ID:888431
实验代码如下,希望那位能够将Com部分不上,我对这个是根本不懂。
uses Comobj,Word2000;

var
  Word_Handle, Doc_Handle: OleVariant;
  Word_Button: OleVariant;

procedure TForm1.Button1Click(Sender: TObject);
begin
  try
    Word_Handle := GetActiveOleObject('Word.Application');
  except
    try
      Word_Handle := CreateOleObject('Word.Application');
    except
      Exit;
    end;
  end;
  Word_Handle.Visible := True;

  Doc_Handle := Word_Handle.Documents.open(FileName := 'C:/1.doc');
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  Word_menubar: OleVariant;
begin
  Word_menubar := Doc_Handle.CommandBars[2];//默认添加到了Formating上面

  Word_Button := Word_menubar.Controls.Add(type := 1, Temporary := False);
  Word_Button.Caption := '测试按钮';
  Word_Button.Visible := True;
  Word_Button.OnAction :='!<BtnEvent>';
end;
来自:SeaHawk, 时间:2002-1-27 21:24:00, ID:888705
公布我的研究结果,有不正确的地方请指正:
    要调用Office里面的按钮事件,实际上是需要连接到按钮事件的IDispatch接口。按钮接口
的定义在Office2000.pas文件中。要连接到这些接口,你须自己编写Invoke方法。但是有些难
度,我曾经试了一下,但是不成功。但是今天在http://www.techvanguards.com/看到有一个软
件叫eventsinkimp,可以自动生成连接Com事件的组件,立马下载了一个(现在是2.0版)。
    安装完了运行,发现可以Import Type Library,和Delphi一样,但是下面可以选择跟踪
那一个COM的事件。于是选择:MicroSoft Office Object Library9.0,然后选择一个相应的
接口。生成三个文件:Office_TLB,OfficeEvents和Office_TLB.dcr。
    然后回到delphi,Install Component,在ACTIVEX里面出现了几个控件:
TOfficeCommandBarButtonEvents等,这就是我们想要的!!!里面有click事件。
    接下来就简单了,先建立一个Bar然后建立一个Commandbarbutton,然后调用
TOfficeCommandBarButtonEvents.connect方法把我们刚才建立的Commandbarbutton
连接起来,这样就可以了!!!
    注意:安装了windows installer 2.0的同志恐怕麻烦一点,安装不上去,害得我
重装了系统,哪位解决了的通知我一声。这是我为了安装XML4.0装的,没办法。
    Ably:给分!!:)   
    
来自:kuangwenwei, 时间:2002-1-27 21:29:00, ID:888711
求教各位大侠,在Delphi6中自定义的Menu怎样才能嵌入Word2000中?
小弟搞了很久了,还是不行。不知道哪位大侠有没有这方面代码。
在下将会感激不尽。
来自:yzhshi, 时间:2002-1-27 21:36:00, ID:888718
很好!谢谢SeaHawk!
不知道使用这个办法生成的事件在其他版本的Word里面会如何?
Word目前常用的有Word 97 /word 2000/word xp呀。
to SeaHawk,你有条件实验一下吗?
还有,那个控件是什么原理呢?对了,不知道那位大虾能够使用我上面提供的使用Com的思路实现一下?
我想那个能够更好一些,至少能够让我们更深入的了解Com,了解Word!
来自:SeaHawk, 时间:2002-1-27 21:37:00, ID:888721
   用Servers上的控件和OLE方式各有千秋,有些方法在Servers控件上不可用,比如控制
button和BAR显示的visible属性在servers里就是只读的:(这是后只好用OLE方式。
(不过你直接把源代码里属性改成可写的也行)。
   但是Servers的效率高一些,还可以调用用一些事件。我现在是两种办法一起用:)
来自:SeaHawk, 时间:2002-1-27 22:01:00, ID:888754
你可以针对的版本生成相应的组件:)
我看了一下代码,只要接口不变,办法就可以。
来自:yzhshi, 时间:2002-1-27 22:03:00, ID:888757
我的意思是一个可执行文件,是否使用所有版本(至少是Word 2000/Xp)
来自:SeaHawk, 时间:2002-1-27 22:13:00, ID:888773
yzhshi:
我知道,我没用过XP,所以不敢说。但是我估计90%是可以的,除非微软把按钮的接口改了
(连GUID都换了)才会有问题。迟一点可以试一试,现在没时间。不过到底有没有BUG,我
还没有仔细测试。小心一点用总是好的。我看要方便的调用COM里面的事件,这是最通用的
办法了。
来自:yzhshi, 时间:2002-1-27 22:17:00, ID:888778
是的,至少这是一种自己产生事件的最简单、最使用的方法!
我想会适合于Xp的,当然仅仅是设想。
来自:ably, 时间:2002-1-28 23:28:00, ID:890880
1.OLE中,word实现预览与页面设置?
to seahawk 有这么复杂吗? 我反编译那个程序后,发现就是一个word.tlb,但不知道他怎么做

2.我有个想法,向word写宏,也可提供在word中造个按钮,用宏来预览或页面设置,这个不难.
怎么做?
来自:SeaHawk, 时间:2002-1-28 21:15:00, ID:890944
 ABLY:
   差不多吧。从服务器中接受事件是很模式化的,基本上都是采用一个通用的事件接收器
,然后在Invoke完以后调用相应的方法。他做的上面那个CommandBarButton基本上正常,但是
CommandBarComBoBox不行,如果在事件处理过程里直接访问那个控件就会出错,如果不,就完
全没有问题。我现在还没有明白是什么回事。希望熟悉COM的同志看看。
  什么是海文标书?

来自:testnet, 时间:2002-1-28 21:39:00, ID:890988
珍藏中。。。。。。
来自:ably, 时间:2002-1-28 21:43:00, ID:890994
一种方法是OLE中有一个COOLBAR,上面加button,通过DELPHI控制预览,页面设置
二种方法是通过word的button,通过VBA控制ole,来预览与页面设置
第二种方法是不是好一些???
来自:ably, 时间:2002-1-28 23:33:00, ID:891218
向word写宏,也可提供在word中造个按钮,怎么做?
来自:SeaHawk, 时间:2002-1-29 15:38:00, ID:892928
触发CommandBarComBoBox事件时读取相应的CommandBarComBoBox属性值的时候会出现一个
错误:“OFFice安装错误....”然后是“需要加载一个DLL”,不知道是什么原因?重装
过系统都不行。但是,不在事件中读取的话就没有问题。我听说有OFFICE系列有一个“开
发版”,不知道是否有关。我现在的解决办法是:发送一个消息,然后处理,不知道各位
有什么高招。
来自:SeaHawk, 时间:2002-1-29 22:50:00, ID:893959
对于CommandBarComBoBox事件的错误的讨论请见:
http://www.delphibbs.com/delphibbs/dispq.asp?lid=893449;
有一个不是办法的办法,希望能给各位一些启示。
  
来自:ndch, 时间:2002-1-29 23:19:00, ID:893994
超级好资料,收藏!!
来自:nineyimo, 时间:2002-2-1 9:22:00, ID:899872
关注
来自:yzhshi, 时间:2002-2-2 14:24:00, ID:902680
前面我就Delphi中调用Word写了一些,比较注重于具体实现,对于研究的方法则说的比较片面。
今天晚上,我静下心来,总结了一下怎样在Delphi中生成操作Word的代码。如果说前面我写的
是金子,那么下面这篇文章就是点石成金的手指(太自夸了,呵呵)。毕竟已经有半年多没有研
究这些了,只能零碎的写一些心得了。

使用CreateOleObject方式调用Word相比Service控件的最大缺点就是不支持代码的自动生成,
但是我们充分的利用VBA代码就可以弥补这个功能。
Word作为一个功能强大的Com,可以很容易被编程工具调用,成为办公自动化系统中处理文档
的强有力的嵌套工具,尤其是充分Word本身的录制宏的功能,更进一步减轻了编程的负担。
下面就如何在Delphi里面利用Word的VBA代码进行一些总结。
1、	生成VBA代码。Word本身具有很强的可扩展性,尤其是支持用户自定义功能,其实现
的主要方式就是通过VBA代码来实现的。在“工具->宏->Visual Basic编辑器”里面就可以看
到具体的宏代码,可以直接进行编辑。而且还可以使用录制宏的功能自动生成宏代码。方法是
选择“工具->宏->录制新宏”,然后执行自己想通过程序实现的功能,如存盘、打印等功能,
此时Word一边执行你要实现功能,一边将你的操作生成了一个宏,在实现功能后,可以选择
“工具->宏->VisualBasic编辑器”,查看生成的宏代码。

例如:我们要将文档中的“讨论”全部替换成“研讨”。
a.	点击“工具->宏->录制新宏”,直接点击确定,默认的宏保存到了Normal.dot系统公
用模板里面。
b.	点击“编辑->查找”,出现弹出对话框,输入查找和替换的字,点确定。进行替换。
c.	结束宏的录制,点击结束按钮。
d.	按F11或者“工具->宏->Visual Basic 编辑器”,查看宏代码。缺省查看Normal里面
的模块里面的NewMacros模块。
以下是生成的宏代码:
Sub Macro1()
'
' Macro1 Macro
' 宏在 2002-2-1 由 yzhshi 录制
'
    Selection.Find.ClearFormatting
    Selection.Find.Replacement.ClearFormatting
    With Selection.Find
        .Text = "讨论"
        .Replacement.Text = "研讨"
        .Forward = True
        .Wrap = wdFindContinue
        .Format = False
        .MatchCase = False
        .MatchWholeWord = False
        .MatchByte = True
        .MatchWildcards = False
        .MatchSoundsLike = False
        .MatchAllWordForms = False
    End With
    Selection.Find.Execute Replace:=wdReplaceAll
End Sub
2、	精简宏代码。通常,生成的宏代码有很多语句对你要实现的功能来说都是多余的。我们要
做的就是如何找到我们需要的代码。此时我们查看具体的代码,剔除明显没有用途的代码,然后光
标停留在宏上面,按F5执行,看是否实现功能,逐步精简,得到最小代码。此步骤可参考Word的
VBA帮助来判断代码是否有用。

如上例,精简下来,剩下以下代码。
Sub Macro1()
    Selection.Find.ClearFormatting
    Selection.Find.Replacement.ClearFormatting
    With Selection.Find
        .Text = "讨论"
        .Replacement.Text = "研讨"
    End With
    Selection.Find.Execute Replace:=wdReplaceAll
End Sub

3、	转换成Delphi代码。这一步其实很简单,对于VBA代码,只需要在前面添加Word的句柄或者
文档的句柄或者文档的句柄.Application就可以直接操作了。
例:逐句翻译:(Word_Handle是Word的句柄)
(VB)     Selection.Find.ClearFormatting
(Delphi)  Word_Handle.Selection.Find.ClearFormatting;

(VB)     Selection.Find.Replacement.ClearFormatting
(Delphi)  Word_Handle.Selection.Find.Replacement.ClearFormatting;
以上两句简单添加上Word的句柄就可以了。

(VB)     With Selection.Find
              Text = "讨论"
              Replacement.Text = "研讨"
End With
(Delphi)  Word_Handle.Selection.Find.Text := '讨论';
  Word_Handle.Selection.Find.Replacement.Text := '研讨';
以上几句因为Delphi不支持Variant的With结构,所以分开写。同时转换成Delphi语法。

(VB)    Selection.Find.Execute Replace:=wdReplaceAll
(Delphi) Word_Handle.Selection.Find.Execute(Replace:=2);
上面一句存在一个小技巧,如何找到常量wdReplaceAll的数值为2?
这里有几个办法,
一:直接use Word2000或者word97单元,那么直接使用常量wdReplaceAll就可以了;
二:到Word2000.pas或者Word97.pas里面查找wdReplaceAll的数值;
三:直接使用VBA代码见wdReplaceAll的数值显示出来。办法是写一个小过程,然后执行,如下:
Sub ShowValue()
  MsgBox wdReplaceAll
End Sub

最后补充一下,很多关于Word的东西可以从Word的VBA帮助里面获得。具体文件在
?:/Program files/Microsoft Office/Office10/2052(XP)下,VBAWD10.CHM,其他版本路径基本类似。
来自:脸谱, 时间:2002-2-3 17:29:00, ID:904233
请问怎么实现:
通过真正的Com技术,将Office软件目录中文件MSWORD9.OLB中的类库全部导入Delphi中,
利用Com技术编程
来自:JJams_King, 时间:2002-2-3 17:57:00, ID:904269
好东西
鼓励
来自:yccai, 时间:2002-2-3 18:06:00, ID:904274
谢谢大家,真是好东西!!
来自:lsys, 时间:2002-2-24 18:31:00, ID:939537
1
来自:Zhejiang_Knight, 时间:2002-3-3 15:49:00, ID:956291
555......
相见恨晚
来自:peng_2002, 时间:2002-3-12 15:31:00, ID:978356
yzhshi前辈,我不能帮你。我来这里是为了向您表示我真诚的感谢,您真是太好了
,你帮我解决了哪个保存错误的问题,谢谢
我想和你交朋友,也想时常让您教导我,我想知道您的QQ和电子信箱。
如果前辈高人是神龙见头不见尾,哪我也只好对着苍天高呼:
谢谢您,YZHSHI。

我的QQ是:47292664
我的信箱是:zhento3@sohu.com
来自:SeaHawk, 时间:2002-3-14 12:06:00, ID:982533
正在把Office控件封装成Delphi的对应控件,包括PopupMenu,ToolBar,ToolButton等,
可以在Delphi内设计界面和事件,然后放到Office里面去,有人愿意测试吗?请留EMail!
                                
                           我的EMail:  jack_Lee@163.net
来自:liuyaook1166, 时间:2002-3-14 20:56:00, ID:983912
我愿意测试学习
MAIL:liuyaook1166@163.com
谢谢!
来自:liuyaook1166, 时间:2002-3-14 21:03:00, ID:983929
前面讨论了在DELPHI界面外控制OFFICE,各位大侠能不能讨论如何在
OleContainer中,究竟目前能不能作到对它的控制。
来自:yzhshi, 时间:2002-3-15 14:27:00, ID:985302
呵呵,SeaHawk做的不错!给我发一份吧。my Mail:yzhshi@263.net

to peng_2002
   我们一起学习,一起进步吧!
to all
   对使用Com调用 Word的问题,欢迎给我来信探讨,但是,对于其他方式的调用,我真的涉猎太少。
只能说尽力而为了。
来自:hq_pan, 时间:2002-3-15 18:30:00, ID:985862
能帮我看看这个问题吗?
http://www.delphibbs.com/delphibbs/dispq.asp?lid=981573
来自:nite, 时间:2002-3-18 15:33:00, ID:990132
SeaHawk,我愿意测试,给我发一份吧。
MAIL:nite.huang@msa.hinet.net
谢谢!
来自:卷起千堆雪tyn, 时间:2002-3-18 22:30:00, ID:991086
这么好的东东,拿来用就是。
来自:net_donkey, 时间:2002-3-23 13:31:00, ID:998460
相间狠晚啊!
谁还能细说一下控制word表格(比如每列宽度等)的详细方法吗?
来自:dason2u, 时间:2002-3-23 16:01:00, ID:998702
乖乖听课。收藏。
来自:wk_knife, 时间:2002-3-25 7:47:00, ID:1000438
//设置列宽
Document.Tables.Item(x){第几个表格}.Columns.item(y){第几列}.SetWidth(24,'wdAdjustNone');





来自:jlcsx, 时间:2002-3-25 8:56:00, ID:1000514
关注
来自:mirik joyce, 时间:2002-3-30 13:07:00, ID:1012178
t
来自:linsb, 时间:2002-3-30 16:53:00, ID:1012587
To SeaHawk
   我愿意测试,给我发一份。
   EMAIL:linsb3031@0451.com
             谢谢!
来自:HAPPYBAB, 时间:2002-4-1 10:36:00, ID:1015576
在delphi 打开word 后,word窗口是最小化的,如何让word直接最大化显示?
来自:gophie, 时间:2002-4-1 10:56:00, ID:1015628
珍藏,
希望有一天能与各位共同探讨!
来自:liuyaook1166, 时间:2002-4-2 0:42:00, ID:1017373
To SeaHawk:

你的控件VERY COOL  向你学习,好同志啊。
可否将OFFICE菜单选项设置封装在你的控件中。(可随意屏蔽)
另:如果你有什么改进的话能mail me吗?
emial:liuyaook1166@163.com
   
来自:wind2000, 时间:2002-4-2 1:06:00, ID:1017397
To SeaHawk:
   请给我发一个,谢谢!如果好的话我可以放到我的主页(http://ph11.126.com)上去!
wind2000@21cn.com
来自:jrq, 时间:2002-4-5 13:36:00, ID:1025369
收藏!
来自:HAPPYBAB, 时间:2002-4-11 14:54:00, ID:1037083
to hubdog:
我照着你的葵花宝典中那篇delphi+word=办公自动化,调用word,程序运行后,第一次调用,没问题,第二次调用,就出现
如下错误:
project cffczx.exe raised exception class eoleexception with message 'RPC服务器不可用',process stopped,
use step or run t continue;
请问这是为什么?
来自:xuejian, 时间:2002-4-11 19:42:00, ID:1038382
To SeaHawk:
   请给我发一个,谢谢!
mail to : 
   xue.jian@2911.net
来自:yzhshi, 时间:2002-4-13 10:50:00, ID:1041311
to HAPPYBAB:
你是否将Word给关闭了,没有通过Delphi关闭,出这个典型的错误原因是Word被关闭了。
来自:cfx, 时间:2002-4-17 16:25:00, ID:1049701
好人一个,高手一个,
共享, 开放,交流!!
来自:HAPPYBAB, 时间:2002-4-18 15:28:00, ID:1052102
to hubdog:
我利用filecreate('文件名.doc')命令,想通过delphi创建一个新文件,可是程序运行后,
文件是被创建了,可是点击打开时,总是出现如下提示:
文档的名称或路径无效,请使用如下建议:
* 监察文件或驱动器的权限;
*使用文件菜单中的打开命令来定位文档;
恳请指教,不胜感激!!!
来自:sljfw, 时间:2002-4-19 12:54:00, ID:1053920
使用CreateOleObject将启动Word,然后以Ole方式对Word进行控制。如果用这种方式,那怎么截获word的消息呢,比如说当文档关闭时我想在自己的程序中处理一些事情?
来自:SeaHawk, 时间:2002-4-19 14:20:00, ID:1054154
sljfw:
  请看我前面的帖子,就有解答了。用OLEContrainter的那个。
来自:ndust, 时间:2002-4-19 23:07:00, ID:1055233
我用delphi调有word生成word文档,在win2000和有的98下,office2000下正常,但是在有的
机器win98下运行程序被告知,不能启动服务,有的说数值超出范围,不能调有word,不知哪位高手遇到过这类情况,如何解决?
调用代码:
var
  wapp, wdoc: variant;
  tempj: integer;
begin
  try
    wapp := getactiveoleobject('word.application');
  except
    wapp := createoleobject('word.application');
  end;
  wapp.Documents.add;
......


另:如何能够让office97也好使,运行在office97下告知不支持automatic.

来自:yzhshi, 时间:2002-4-20 13:07:00, ID:1055947
很眼熟的问题,呵呵,你应该单独开帖子提问过,我好像也回答过。
>>wapp, wdoc: variant;
改成wapp, wdoc: OleVariant;
来自:sljfw, 时间:2002-4-21 14:32:00, ID:1057842
SeaHawk
我现在不是用的olecontainer呀,
来自:SeaHawk, 时间:2002-4-21 20:10:00, ID:1058604
一样的处理方式。
来自:zyf23, 时间:2002-4-22 21:36:00, ID:1061368
gz
来自:zyf23, 时间:2002-4-22 21:39:00, ID:1061385
gz
来自:qq, 时间:2002-4-26 9:56:00, ID:1069102
受益非浅的同时各位老兄请恕在下贪心的提个问题
帖子中讨论的均是对文件的操作,但是否可以对流进行直接操作呢
比如我将DOC文件存到数据库中,现在想查看但不想生存临时文件,而是想直接利用流不知如何处理
来自:dfs, 时间:2002-4-26 20:55:00, ID:1070613
FileTemplates	模板和可加载项	
怎么使用,比如我想在NORMAL.DOT中添加一个bbb.dot作为加载项?
谢谢!希望各位能帮帮我,最好有DELPHI的代码。
来自:yzhshi, 时间:2002-4-27 8:17:00, ID:1071017
注意,以下不少都是自己定义的,主要就是使用AttachedTemplate。具体还可以参考VBA帮助
  Doc_Handle := Word_Ole.Documents.open(FileName := Doc_File, ReadOnly := False, AddToRecentFiles := False);
  {使用代码模板替换格式模板}
  Doc_Handle.AttachedTemplate := Macro_File;
来自:qq, 时间:2002-4-27 8:36:00, ID:1071058
OleContainer1.CreateLinkToFile(FileName, False);
时OleContainer1没有滚动条,不知道如何处理,同时如何可以做到象
OleContainer1.InsertObjectDialog;
with OleContainer1 do
  if NewInserted then DoVerb(PrimaryVerb);
时的效果;  我另有帖子,150,望指教
来自:小小武, 时间:2002-5-13 21:24:00, ID:1099001
好,好
这么多,有的我消化了!
来自:小小武, 时间:2002-5-13 21:33:00, ID:1099025
SeaHawk
能把你的控件发给我看看
chuanwuzh2740_cn.sina.com
来自:孔明.net, 时间:2002-5-13 21:37:00, ID:1099034
收藏了。
来自:kkyy, 时间:2002-6-7 21:26:00, ID:1149883
http://www.delphibbs.com/delphibbs/dispq.asp?lid=1144133
来自:yzhshi, 时间:2002-6-7 21:28:00, ID:1149888
老兄,别这样跟贴呀,我以为你有什么好的建议呢,赶紧来看一下,谁知道你在做你的广告:-)
就算你的东西再好,这种做法似乎是不可取的呀。希望下不为例!
来自:小小武, 时间:2002-6-11 16:52:00, ID:1157071
1,用server的话,生成的菜单调用delphi程序除了SeaHawk说的办法,不知还有没有别的办法!
2,用olecontainer,自己的添加菜单和excel的菜单同时存在,但是,excel的file菜单和window
菜单没了!不知如何让这两个菜单(最重要的是file菜单)保存不被替换掉
来自:ldehai, 时间:2002-6-16 11:35:00, ID:1166315
感觉受益非浅。yzhishi,我想知道你是如何懂得这么多的,我学Delphi好久了,总觉得还没有入门
希望指教!
来自:小小武, 时间:2002-6-24 11:16:00, ID:1179282
SeaHawk, >>
你说的eventsinkimp在2000下可以,98不行,更本安装不起来,是不是98不可以呀
我在那网站上也没看见说明,是不是要启动什么服务?谢谢
来自:yixin, 时间:2002-6-27 9:41:00, ID:1183740
用OleContainer打开Word文档时出现“无法找到指定模块”的错误,为什么呢?
使用的语句是  OleContainer1.CreateObjectFromFile('C:/1.doc',False);

谢谢。
来自:topsuper, 时间:2002-6-27 10:14:00, ID:1183788
好好,谢谢谢谢!
建议大家都来贴出自己的心得体会,这才是真正网络带给我们的。
斑竹应把每个贴贴的人奖400大洋。
资源共享!!!
来自:littley, 时间:2002-6-28 15:23:00, ID:1186080
yzhishi和其他各位办公自动化方面的专家:
我有一个帖子,愿意出600分求解,如果各位大侠哪天心情好,请拔刀相助,小弟在此先谢过了!
http://www.delphibbs.com/delphibbs/dispq.asp?lid=1168869
1、在rxlib的rxRichedit中插入WORD或MS GRAPH文档,如何能不借助
rxRichedit.insertObjectDialog达到目的? 
2、将windows的画图程序直接OLE到rxRichedit中,不调用insertObject方法的对话框。
使我的编辑器提供用户画图的功能。成功后另外加600分! 

因为小弟以前提过类似的帖子,但最终没有得到直接的解决办法。因此我不敢一下子加太多
分,准备得到直接的答案后再加分。我以这种方式送出去过近2000分,信用没得说,大家可以
查得到的。
来自:wangny, 时间:2002-7-15 22:16:00, ID:1204190
看来和我一样对这个问题感兴趣的人还真多呀!大家有什么好的拿出来吧,谢谢各位前辈的指点!
来自:Delphi之旅, 时间:2002-7-28 14:57:00, ID:1227709
关于对word的操作,还少了word的关闭实现,我添上。
var
  SaveChanges,
  OriginalFormat,
  RouteDocument: OleVariant;

begin
  SaveChanges := WdDoNotSaveChanges;
  OriginalFormat := UnAssigned;
  RouteDocument := UnAssigned;
  try
    WordApplication.Quit(SaveChanges, OriginalFormat, RouteDocument);
    WordApplication.Disconnect;
    BtnCloseWord.Enabled := False;
    BtnPrint.Enabled := False;
    BtnPreview.Enabled := False;
  except
    on E: Exception do
    begin
      Showmessage(E.Message);
      WordApplication.Disconnect;
    end;
  end;
来自:wangny, 时间:2002-7-28 23:27:00, ID:1228431
Delphi之旅前辈:
    很感谢你加入到这个问题中来,但我不知道你可否提供一下有关WordApplication
的所有函数或参数的说明呢,我对这些实在是太需要了。常常编一半时被这些问题所挡住的。

小弟先谢过了!!也谢谢各位加入这问题的前辈们
来自:zcm1975117, 时间:2002-7-29 8:18:00, ID:1228685
大家帮忙看一下这个问题
http://211.101.4.25/delphibbs/dispq.asp?lid=1224886
来自:LiZhongYu, 时间:2002-8-7 22:02:00, ID:1249870
yzhshi,SeaHawk...各位大侠:
  用server来控制WORD,因为和应用程序不在一个窗口中,看起来好像是两套程序,或者
说连接的不紧密,不像自己应用程序里的东西,看着也不舒服。至少有的客户会这样认为。
所以我更愿意用OleContainer来控制。
  小弟最近正在作一个与数据库有关的程序,想要实现一下功能:开头部分内容几乎
雷同,依次为 供货商代吗,供货商名称,联系人,电话等。 下面是供货情况:货物1:
货物1的描述,也可能有货物的图片。货物2:货物2的描述。。。。
值班操作员可能会有如下纪录:
 供货商代码: 1234567
 供货商名称:xxxxxxxxxx
 联系人:张三
 电话: 1380xxxxxxxx
货物1:
abcdefg...........1000斤
 货物1 的图片.
货物2:
xyzzzzzzzzz.......1500斤
。。。。
供货商代码, 供货商名称,电话对应数据库的一个表,打开时我如何将将这该表的这些
信息添加到word中?加入操作员又修改了供货商电话,我如何能使另外一个表的信息与
之同步呢?
小弟先谢了。我可以再开贴给各位加分,分数有的是。






来自:MichaelZhu, 时间:2002-9-5 15:38:00, ID:1308118
如何在Delphi中设置Excel单元格的背景色?
好像这里没有提到!
来自:南宫慕容, 时间:2002-9-11 10:55:00, ID:1318409
如何在Delphi中设置Excel每个单元格的格式,比如说让它是文本格式,
或者数字格式(00。00),或者日期格式(yyyy-mm-dd)等
来自:zyf23, 时间:2002-9-24 10:07:00, ID:1342467
管足于8 
来自:小雨哥, 时间:2002-10-9 21:25:00, ID:1366651
原来 yzhshi 兄还有这样一个社区啊  :-)
http://digest.tencent.com/cgi-bin/wenji_content?id=132913
大家参观参观哦。
来自:yzhshi, 时间:2002-10-10 8:31:00, ID:1366984
哈哈,初始我也吓了一跳,我不用QQ的,怎么跑到腾讯的网站上去了,呵呵。仔细一看,呵呵。
谢谢小雨哥。资源共享,大家共同进步最好!

(商万贾[808366]在大作中提到:) 
> 兄弟,最少也请说明是谁写的吧? 
> 作者:yzhshi 邮箱:yzhshi@263.net 
版权声明:本文为 星落→水[81710972] 转载的他人文章!!! 
看清楚呀老大,,最后俺不是有说明了吗!! 
来自:darnis, 时间:2002-10-10 15:41:00, ID:1368061
鉴于用 CreateOleObject 创建的 Automation 服务器在编程时不大方便,
我有个小经验是,
 var
   wordApp : _Application;
 begin
  ...
  WordAppp := CreateOleObject('Word.Application') as _Application;
  ..
 end;
    这种方式,GetActiveOleObject 和 CreateOleObject 得到的是 OleVariant 
转换成指定的接口就可以了。。
    风中的沙粒   提到的问题,可以用这种方式解决
   
   ACad : IAcadApplication;

   try
     acad := GetActiveOleObject('AutoCAD.Application') as IAcadApplication;
   except
     try
        acad := CreateOleObject('AutoCAD.Application') as IAcadApplication;
     except
        raise Exception.Create('AutoCAD Error!');
     end;
   end;
   这样就可以用 Acad 来控制AutoCAD 了(如果正常驱动),而且在写代码时,也可以
利用代码提示了。。:)
来自:yzhshi, 时间:2002-10-10 17:59:00, ID:1368358
一个好的方法,但是你这样一改变,编程就CodeInsight有了,但是很多不需要的参数也必须输入了。
word2000.pas等文件将很多原来可以省略的参数都设置成了VAR的,必须输入,且需要定义一个oleVariant,就是因为这,我最初才决定不用Servers控件的。
来自:drmy, 时间:2002-10-16 10:21:00, ID:1377267
学习
来自:zhang_yz6666, 时间:2002-10-24 14:04:00, ID:1392358
gz
来自:pine, 时间:2002-10-24 14:21:00, ID:1392406
非常感谢所有对delphi与word融合技术问题给出解答的朋友。

delphi与word融合虽然我没有做过,但我非常关心,能得到这么多的经验和技术,不枉在
大富翁上花费时间。
来自:晓毛, 时间:2002-11-3 2:13:00, ID:1410002
怎样得到ExcelApplication1所在的单元格?
来自:山泉, 时间:2002-11-3 7:06:00, ID:1410018
办公自动化
http://www.djpate.freeserve.co.uk/Automation.htm
目录
Automation with Delphi
If you have any helpful tips, examples etc of automation with Delphi, please send them to me and I'll include them, with credits. I'm creating 'Automating with...' pages for each automatable program that I have access to, but I'd love to add more - so if there's a program that you use that you can add help for, please email me.

Contents:
Introduction to automation in Delphi
Delphi 5's server components 

Automating particular programs 
Microsoft Office

Introduction
Access
Binder
Excel
Outlook
PowerPoint
Word 

来自:jshen, 时间:2002-11-5 8:38:00, ID:1413338
楼上关于EXCEL的CHART的问题提到了对于CHART的数据区域赋值的写法,
4)给二维图赋值
series:=achart.chart.seriescollection;
range:=sheet1!r2c3:r3c9;
series.add(range,true);
这样是可以的,但是我现在需要读取二维图的值,好像怎么改都不行,各位
高手能够见教一二?谢谢

来自:Ruth, 时间:2002-11-5 9:27:00, ID:1413516
这一帖让我受益非浅,多谢!但我在打开和存储word文件时,
使用olecontainer,createoleobject()最后一个参数为true,
程序执行时,出现‘消息筛选程序正忙’的提示,按‘确定’后通过,
而olecontainer总是不显示文件图标,双击olecontainer控件也没有
文件打开,怎么回事?
来自:mphst, 时间:2002-11-5 15:18:00, ID:1414418
mark
来自:8qing, 时间:2002-11-8 22:38:00, ID:1422396
SeaHawk,能发个控件给我吗? afeng@zj165.com
来自:杨深, 时间:2002-11-22 9:47:00, ID:1450314
前面讨论了在DELPHI界面外控制OFFICE,各位大侠能不能讨论如何在
OleContainer中,究竟目前能不能作到对它
实现多文档
比如 Application.Documents.Open
Application.Documents.Add
之类的的控制。
有分给,谢谢了

http://www.delphibbs.com/delphibbs/dispq.asp?lid=1449645
来自:信念依旧, 时间:2002-11-22 15:58:00, ID:1451766
大侠指点:那里能载到hubdog的葵花宝典??
来自:信念依旧, 时间:2002-11-22 16:00:00, ID:1451770
大侠指点:那里能载到hubdog的葵花宝典??
来自:shuszj, 时间:2002-11-25 10:10:00, ID:1456781
各位高手, 我想问一下,在创建 Word or Excel 时,大家都知道,
只有安装过Word or Excel 后再用 Delphi 创建出来,否则是创建不出来的,应该说是找不
到一些注册的共享文件,哪位高手知道是哪些文件吗? 这样在不安装该软件的时候,只要
打包在你的安装文件中,也能创建,不知哪位高手能提供一下,再次谢过了。
来自:阿当, 时间:2002-12-20 16:27:00, ID:1525199
to ddntyz:
   设置OLEContainer的背景不管用,这是一个Bug,你可以TOLEContainer.Paint中的
   DrawEdge(Canvas.Handle, CR, EDGE_SUNKEN, Flags or BF_MIDDLE);的后面加上:
   Canvas.FillRect(CR);

   重新编译后即可。在运行期有效。
来自:journer, 时间:2002-12-29 19:13:00, ID:1546735
关注
来自:landina, 时间:2003-1-2 22:41:00, ID:1556632
好东西,受益非浅。
另外:我再问问,能否在应用服务器中将word or Excel转换成网页,有没有具体的代码?
来自:awu306, 时间:2003-1-6 15:11:00, ID:1563870
能帮我解决这个难题吗???
http://www.delphibbs.com/delphibbs/dispq.asp?lid=1518415
来自:fanglintao, 时间:2003-2-14 1:40:00, ID:1620835
各位大虾:最近我在用word宏替换时,如果替换字数超过350个时,就会报错。请问一下
word宏替换时有什么限制,怎样解决。十分感谢!!
还有在word2000。pas中ActiveDocument.Range.Find.Execute(var FindText: OleVariant; var MatchCase: OleVariant; 
                      var MatchWholeWord: OleVariant; var MatchWildcards: OleVariant; 
                      var MatchSoundsLike: OleVariant; var MatchAllWordForms: OleVariant; 
                      var Forward: OleVariant; var Wrap: OleVariant; var Format: OleVariant; 
                      var ReplaceWith: OleVariant; var Replace: OleVariant; 
                      var MatchKashida: OleVariant; var MatchDiacritics: OleVariant; 
                      var MatchAlefHamza: OleVariant; var MatchControl: OleVariant):;各参数的意义分别是什么,如果用这个函数解决上面的那个替换问题,应该怎样设置
来自:dsmiao, 时间:2003-2-14 8:02:00, ID:1620877
感谢
来自:langdx, 时间:2003-2-14 9:55:00, ID:1621168
very good
i like it
来自:china_hj, 时间:2003-2-19 17:28:00, ID:1632463
请教yzhshi兄和众位自动化高手!WORD的activex控件问题
http://www.delphibbs.com/delphibbs/dispq.asp?lid=1595376
来自:花园风味, 时间:2003-2-24 9:20:00, ID:1640165
请教各位高~~手
http://www.delphibbs.com/delphibbs/dispq.asp?lid=1630837
来自:wujiangok_2001, 时间:2003-3-5 14:21:00, ID:1657085
hubdog的葵花宝典的地址不行啊!那位高手给一个可以的地址啊!:急!!
http://delphi.mychangshu.com/
来自:duxbin, 时间:2003-3-6 11:23:00, ID:1659501
http://www.playicq.com/dispdocnew.php?t=&id=3334

要注册登录的
来自:iamcfr, 时间:2003-3-6 13:18:00, ID:1659986
gz
来自:firnwolf, 时间:2003-3-10 11:51:00, ID:1668373
贴一个打印的功能,功能类似word和excel中ctr+p的功能,有选择打印机的界面
var
   PrinterSetupDialog1:TPrinterSetupDialog;
begin
  PrinterSetupDialog1:=TPrinterSetupDialog.create(nil);
  if PrinterSetupDialog1.Execute then
  begin
     excel.application.ActivePrinter:=printer.Printers[printer.PrinterIndex];
     excel.printout;
  end;
  PrinterSetupDialog1.free;
end;

来自:xh416, 时间:2003-3-13 8:55:00, ID:1677244
请问下面的VBA(EXCEL) 宏代码如何翻译成DELPHI 的过程?
Sub SortTable(top, left, right, bottom, Col)
    Range(Cells(top, left), Cells(bottom, right)).Select
    Selection.Sort Key1:=Columns(Col), Order1:=xlAscending, Header:=xlGuess, _
        OrderCustom:=1, MatchCase:=False, Orientation:=xlTopToBottom, SortMethod _
        :=xlPinYin
End Sub
来自:Tsir222, 时间:2003-3-28 9:37:00, ID:1716776
看了上面的内容,受益匪浅。我正在写一个ocx组件,需要嵌入IE中,实现对word的操作,
但考虑到正版的问题,客户不一定都装office,所以想把控制word的功能打包进来。
请问大家一下,如果在机器不装office的情况下,象ole一样控制word!当然word不能另外
一个窗体。
来自:vfphome, 时间:2003-4-27 15:50:00, ID:1807348
ok
来自:里斯, 时间:2003-5-13 14:16:00, ID:1856376
当我把Table中的数据汇出到Excel时,若数据类似“00123”,
即前面有“0”时汇到Excel中前面的“0”就没有了,
当一连串的字符都是数字,如身份证号,汇出来后也变样了(成了3,456E+17),
请问这些问题怎么解决?能不能在汇出前先指定某列的格式为文本?如何设置,各位高人请帮忙。
谢了。
来自:hawk.jiang, 时间:2003-6-2 12:43:00, ID:1916722
to 里斯
你可以右键菜单>单元格格式>数字设置单元格的类型,具体类型自己确定,当然也可以写代码实现,使用录制宏功能可以看到VBA代码,然后改写成Delphi代码

我要强调的是office的录制宏功能非常有用
来自:hawk.jiang, 时间:2003-6-2 13:06:00, ID:1916805
to Tsir222
基本上不可能
来自:caili314, 时间:2003-6-8 10:21:00, ID:1934128
MDIForm中定义了主菜单,其菜单项的GroupIndex分别是0,1,2,3,4,5,6,7,8,9,10,254,255
MDIChildForm中使用了
with OleContainer1 do
begin
  CreateObjectFrom('xxx.doc',false);
  DoVerb(PrimaryVerb)
end
结果MDIForm中只有GroupIndex 0,2,4的被保留,其他的全部被替换.Delphi帮助中说OLE SERVER只使用1,3,5的GroupIndex(help:search for GroupIndex property (TMenuItem)).
谁能告诉我WORD到底使用了哪些GroupIndex?
谢了在先
来自:大漠孤鸿, 时间:2003-6-9 0:54:00, ID:1935526
各位大侠!
请教,能将Delphi中得DBchart创建得图表直接加入word吗?
来自:likongxu, 时间:2003-6-9 10:51:00, ID:1936061
缁濆鍊煎緱鏀惰棌锛佺湅浜嗕竴涓笂鍗堝晩锛?
璇烽棶yzhshi涓撳锛屾垜鍋氫竴涓鏂囩鐞嗙郴缁燂紝鎴戞兂鍦ㄧ▼搴忎腑璁╃敤鎴锋祻瑙堣鏂囩殑姝f枃锛屽簲璇ユ槸鐢ㄤ粈涔堟柟娉曟潵瀹炵幇鐨勩€傚洜涓哄彧鏄祻瑙堬細鎵€浠ユ槸鐢╮ichedit鏉ユ樉绀猴紙浣嗘槸杩欐牱璁烘枃鐨勬牸寮忓氨娌′簡锛夎繕鏄敤TOleContainer鏉ュ疄鐜帮紵褰撶劧Servers鎺т欢鍜宑omm鏂归潰鐨勫氨绠椾簡锛侊紒锛
来自:vfphome, 时间:2003-6-16 13:16:00, ID:1955660
在Dephi 5中提供了一组Servers组件,实现了与Office的无缝结合,但有关这一方面的资料却很少,最近笔者接触了一个用户案例,要求最终将数据库中的结果总结成一份Word文档,Word文档中对于标题、正文的字体、字号,文档的纸张大小都有一定的要求,而且还要求以表格的形式体现一部分数据库中的数据。

  笔者通过查找VBA的说明,再对照Dephi的VCL,终于实现了全部功能,现将有关的内容总结如下:


  1、在当前程序目录下建立以标题字段命名的Word文件


  exepath:=application.ExeName;

  for index:=1 to length(exepath) do

  if exepath[index]='/' then

  i:=index;

  exepath:=copy(exepath,1,i);

  doc_file:=exepath+mc+'.doc'; 

  以标题字段“mc”命名Word文件

  try

  Wordapplication1.connect;

  except

  messagedlg('没有安装Word',mterror,[mbok],0);

  abort;

  end;

  Wordapplication1.Caption := 'XX计划书';

  Wordapplication1.visible := true;

  Worddocument1.activate;


  2、设置纸张大小


  Wordapplication1.ActiveDocument.PageSetup.PageWidth:=XXX;

  Wordapplication1.ActiveDocument.PageSetup.PageHeight:=XXX; 

  Wordapplication1.ActiveDocument.PageSetup.LeftMargin := XX;

  //设置左边距

  Wordapplication1.ActiveDocument.PageSetup.rightMargin := XX; 

  //设置右边距


  3、插入页码


  var fpage,pagea:olevariant;

  fpage:=true;

  pagea:=wdAlignPageNumberCenter;

  Wordapplication1.activedocument.sections.item(1).Footers.item(1).PageNumbers.Add(pagea,fpage);


  4、设置页面横向打印


  s:=Wordapplication1.selection.start;

  e:=Wordapplication1.selection.start;

  aa:=wdSectionBreakNextPage;

  Wordapplication1.ActiveDocument.Range(s,e).InsertBreak(aa);

  Wordapplication1.Selection.Start:=Wordapplication1.Selection.Start + 1;

  s:=Wordapplication1.Selection.start;

  e:=Wordapplication1.ActiveDocument.Content.End_;

  Wordapplication1.ActiveDocument.Range(S,e).PageSetup.Orientation:=wdOrientLandscape;


  5、设置字体、字号


  Wordapplication1.Selection.Font.Size:=18;

  Wordapplication1.Selection.Font.Name := '黑体';

  Wordapplication1.Selection.TypeParagraph;

  Wordapplication1.Selection.ParagraphFormat.Alignment:= wdAlignParagraphCenter;

  Wordapplication1.Selection.TypeParagraph;

  Wordapplication1.Selection.TypeText(dbedit4.text); 

  //标题 

  Wordapplication1.Selection.Font.Size := 14;

  Wordapplication1.Selection.Font.Name := '宋体';

  Wordapplication1.Selection.TypeParagraph;

  Wordapplication1.Selection.TypeParagraph;

  Wordapplication1.Selection.ParagraphFormat.Alignment := wdAlignParagraphJustify;

  Wordapplication1.Selection.TypeText(' '+trim(dbmemo1.text));

  //正文

   ... ...


  6、插入表格


  Wordapplication1.Selection.Font.Size :=10;

  adoquery2.Active:=false;

  adoquery2.active:=true;

  doc:=Wordapplication1.activedocument;

  counts:=adoquery2.RecordCount;

  //记录数决定表格的行数

  t:=doc.tables.Add(Wordapplication1.selection.range,counts+1,5);//5列

  t.cell(1,1).range.text:= '单位';

  t.Cell(1,1).Width:=120;

  t.cell(1,1).range.Paragraphs.Alignment:= wdAlignParagraphCenter;

  t.cell(1,2).range.text:= '姓名';

   ... ...

  //依次写入其他字段的表头

  for i:=2 to counts+1 do

  begin

  t.cell(i,1).range.text:=adoquery2.field

  byname('dw').asstring;

  t.Cell(i,1).Width:=120;

  t.cell(i,1).range.Paragraphs.Alignment:=

   wdAlignParagraphCenter;

  t.cell(i,2).range.text:=adoquery2.field

  byname('xm').asstring;

  ... ...

  Adoquery2.next;

  End;

  使用Dephi将Word与数据库结合,实现了用户文档的自动生成,大大地方便了用户。
来自:阿当, 时间:2003-6-25 16:49:00, ID:1980253
    这是一篇非常好的讨论!yzhshi是这方面的专家,在此我有一个问题请yzhshi帮忙,我想在我的程序中显示Word文档,不要Word的菜单及其它,只有文档,逐页上移、下移、左移,甚至逐字等。请问该如何做?请各位大虾指点。(我最初的思路是得到并控制文档的每一页,然后PaintTo当前页面,以前用的是OLEContainer,但有很多缺点)
    一百分相送,不够再加。
来自:hawk.jiang, 时间:2003-6-26 8:49:00, ID:1981331
用WebBrowser控件,打开Word文档,缺点是速度比较慢(不比打开Word慢),功能一如Word
来自:caili314, 时间:2003-6-26 9:19:00, ID:1981454
让WORD服务器先运行起来, 再打开文档时就会快很多. 有没有感觉在打开第一个WORD文档时慢, 打开第二个时就快了?
来自:hawk.jiang, 时间:2003-6-26 9:29:00, ID:1981504
to caili314:
  这个我知道,但是没有实际意义。如果是在客户端,没有理由要求用户常驻一个word进程,而且总有第一次吧,第一次打开不是一样慢。如果在服务器端,可以考虑创建一个对像池。其实如果机器不是特别破(P3 256M以上),速度还是可以认可的。
来自:guojundeng, 时间:2003-6-30 15:21:00, ID:1990979
真是一个好话题
来自:nanami, 时间:2003-6-30 15:26:00, ID:1990995
To:SeaHawk
我对OleContainer,取得Application,以及使用Server控件联合编程很感兴趣。不知道你有没有什么这方面的示例?
另外你说: 在Olecontainer确实无法预览和调节打印设置,直接用操作Word对象也不可以保存文件,但是你可以用Olecontainer自己的SaveToDocument保存文件。
如果可以取得Application,那不是可以利用Application的方法来实现预览打印保存么?
来自:wfzha, 时间:2003-7-23 18:17:00, ID:2053845
收藏
来自:dreamstill, 时间:2003-7-23 18:31:00, ID:2053874
很用的,谢谢
来自:babyrun, 时间:2003-7-30 9:35:00, ID:2069926
不单单有hubdog的葵花宝典的下载

http://www.emouze.com/download.htm
来自:anzi311, 时间:2003-8-3 18:00:00, ID:2080869
虚心向各位学习!!
来自:flybug, 时间:2003-8-5 15:46:00, ID:2085885
受益!!!谢谢各位,正在发愁word+delphi的问题,就上来看看,果然收获不小。
加一个问题:delphi如何把存在数据库中的图片直接写到word中的指定位置?
来自:liuzhi, 时间:2003-8-9 18:30:00, ID:2097344
建议每人给楼主30分
来自:crazyangel, 时间:2003-8-29 17:14:00, ID:2143266
学习不是目的!超越才是理想!我要不断的向楼主学习!又要不断的超越楼主!

为中华之崛起而~~~~~~~~~~编程~~~~~~~~  !!!!
来自:chen_gxing, 时间:2003-8-30 16:33:00, ID:2145104
太厉害了,我也要
来自:txz123, 时间:2003-9-18 8:38:00, ID:2184183
good
来自:archonwang, 时间:2003-11-11 16:55:00, ID:2287055
很好的咚咚,收下了,谢谢高手
来自:anneduan, 时间:2003-11-11 20:58:00, ID:2287590
我想请教一个问题,用上述在delphi 中使用VBA的方法和在delphi 中直接运行宏代码的方法有什么区别呢?各有什么利弊?还有,如何在delphi中直接运行已有的宏代码(带有参数的)?
来自:Lonestar, 时间:2003-11-15 19:13:00, ID:2296736
我要是早看到这个贴子就可以省下很多自已去摸索的时间~~~~~~~~~~~~~~~~~~~~
我现在有个问题想请教各位高手:我用Delphi调用Word后,Word打开一指定的文档,在打开该文档后,要让Word执行一段VBA代码,怎么样把这段VBA代码传递给Word?????
请大虾赐教!!!!!!!!!!!!!!!!!
来自:Lonestar, 时间:2003-11-15 19:43:00, ID:2296763
还有一个问题:当用下面代码设置纸张大小时,
  Wordapplication1.ActiveDocument.PageSetup.PageWidth:=500;
  Wordapplication1.ActiveDocument.PageSetup.PageHeight:=400; 
使用的单位是象素点,但在Word中一般使用的单位都是厘米呀,怎么样把“象素点”单位转换为“厘米”单位????
来自:dtu_ysxk, 时间:2003-11-15 19:52:00, ID:2296779
虚心向各位Del侠学习,受益匪浅!!!!
来自:redleaf_wgm, 时间:2003-11-19 14:27:00, ID:2302665
OK!不过这些从宏中都能找到!
来自:menxin, 时间:2003-11-22 0:01:00, ID:2309449
比较全的宏 (原创:menxin) 呵呵

文件类

fileclose 关闭活动文档窗口
filecloseall 
filecloseorcloseall
filecloseorexit
fileexit
filefind
filenew
fileopen
fileopenfile
filepagesetup
fileprint
fileprintpreview
fileprintsetup
fileproperties
filesave
filesaveall
filesaveas
filesaveaswebpage
filesaveframeas
filesavehtml
filesaveversion
filetemplates
fileversions
organizer
savetemplate
sendtofax
webpagepreview

编辑

atuotext
browsenext
browseprev
copyformat
createautotext
deleteannotation
editautotext
editbookmark
editclear
editcopy
editcopyaspicture
editcut
editfind
editgoto
editlinks
editobject
editpaste
editpasteashyperlink
editpasteasnestedtable
editpastespecial
editredoorrepeat
editreplace
editselectall
editundo
goback
gotonextcomment
gotonextendnote
gotonextfootnote
gotonextpage
gotonextsection
gotopreviouscomment
gotopreviousendnote
gotopreviousfootnote
gotopreviouspage
gotoprevioussection
insertautotext
insertspike
lockfields
nextinsert
pasteformat
repeatfind
selectcuralignment
selectcurcolor
selectcurfont
selectcurindent
selectcurspacing
selectcurtabs
spike
unlinkfields
unlockfields
updatesource

其它部分待续..太多了
来自:swordshadow, 时间:2003-11-24 1:56:00, ID:2312266
谢谢各位,正在发愁word+delphi的参数传递问题,就上来看看,看了DragonPC_???兄的例子终于茅舍顿开。谢谢,太谢谢了!
幸好找到了,呵呵,要不然刚注册不满两天还不给我发问,郁闷阿郁闷!
来自:yzhshi, 时间:2003-11-24 12:26:00, ID:2313205
victor7780,我想问一下,您羞不羞?
这里是一个程序员讨论技术的论坛,请您应该自重一些!
人或者要有骨气,赚钱的方法有很多,不要仅仅看着这些不切实际的东西!

看看你的待答问题和你的参与问题。请扪心自问一下,你到这里来到底为了什么?
请珍惜你的也珍惜大家的美好光阴!

http://www.delphibbs.com/delphibbs/listq.asp?type=1&userfrom=victor7780
http://www.delphibbs.com/delphibbs/listq.asp?type=1&expert=victor7780
来自:yzhshi, 时间:2003-11-24 13:00:00, ID:2313305
刚才试验了一下,给大家再贴出一点有用的VBA代码。
上面的可以获得一些命令的信息;
下面的代码可以获得对话框的函数名称,但是不是所有函数的名称。
希望对大家有用。

Sub ListCommands()
    Application.ListCommands (True)
End Sub

Sub ListDialogs()
  On Error Resume Next

  Dim aa As String
  aa = ""
  
   For i = 1 To Dialogs.Count
       aa = aa + Str(i) + " " + Dialogs(i).CommandName + Chr(13)
   Next i
   Selection.TypeText aa
End Sub
来自:MicoInNet, 时间:2003-11-25 10:24:00, ID:2315194
太好了,收藏,谢谢!
来自:zhuoyin, 时间:2003-11-25 13:16:00, ID:2315695
收藏,谢谢
来自:nofault, 时间:2003-12-3 14:53:00, ID:2331187
收藏!
来自:2180001, 时间:2004-3-7 12:06:06, ID:2489056
测试一下。
来自:2180001, 时间:2004-3-7 12:19:13, ID:2489077
哈哈,可以发贴子了!!!(偶已经很久不能发贴子了)
看了各位的讨论,发现大家都忽视了一点:在你控制word时,如何才能不影响用户自己打开的word的正常操作?
    大家自己用word作为编辑器,当然希望完全控制,比如用宏,用OLE什么的,无论如何,你在对word进行控制的时候,你怎么样才可以不影响到用户自己打开的word呢?
比如说,你打开一个doc, 将某些功能禁止,这时用户自己又打开了一个word编辑自己的文件,这个word窗口的那些你禁止的功能同样也没有了,怎么办?
    在你控制word时,如何才能不影响用户自己打开的word的正常操作?
    1 如何建立一个word实例,只给你自己的程序使用,不让用户使用?
    2 如何在内存一个实例的范围控制word,并不影响其它实例?

这个问题有解吗?
来自:maxtool, 时间:2004-3-12 8:48:03, ID:2495676
to 2180001:

如果你使用createoleobject
wDoc:=wApp.Documents.add;
的话,是新建一个word文档不影响别的word文档的
来自:xychun, 时间:2004-3-10 19:51:11, ID:2496181
收藏! 
来自:xiaobinic, 时间:2004-3-17 17:13:21, ID:2507618
太丰富了,有得我消化的了,谢谢各位!
来自:w_anghe, 时间:2004-3-22 12:05:43, ID:2514984
各位大侠,有没有把word文档变成只读的方法,不能修改,不能复制粘贴?
来自:w_anghe, 时间:2004-3-22 12:07:27, ID:2514987
各位大侠,有没有把word文档变成只读的方法,不能修改,不能复制粘贴?
来自:cdtsky, 时间:2004-3-24 14:49:25, ID:2519539
使用olecontainer  调用word
word的菜下拉菜单怎么没有了
    怎么让他显示出来
工具栏为什么不在olecontainer里
   怎么把它放进去

难道非要用vb脚本?
来自:jakersen, 时间:2004-3-30 22:13:20, ID:2530633
to cdtsky:
  在该form中放一个TMainMenu就可以显示word菜单了!
来自:gamepower111, 时间:2004-4-2 9:31:27, ID:2535013
delphi 操作 excel 问题,很不错呀。
但大家始终没有对速度慢这个问题提供好的解决方法。
来自:pat, 时间:2004-4-2 22:11:50, ID:2536960
没有很好的解决速度的方法,就是慢!
来自:jfyes, 时间:2004-4-2 22:24:28, ID:2536982
阅读:17408 
===============
he!he!打破纪录的阅读次数;
再顶
来自:maomaoyu810201, 时间:2004-4-7 10:30:15, ID:2544317
各位真牛!!!
请帮忙看看下面问题出在何处?我用的是OleContainer,照SeaHawk讲的方法想做一个
activex。
var
  worddoc:olevariant;
  v:olevariant;
begin
  OleContainer1.CreateObjectFromFile('d:/temp/temp.doc',false);
  OleContainer1.DoVerb(OleContainer1.PrimaryVerb );
  worddoc:=OleContainer1.OleObject;
  v:=worddoc.Application;
  //v.Insert('hhhhhh');      ----这两句报错“不支持此方法”,为什么???
  //v.FileSaveAs('d:/temp/temp.doc');
 end;


SeaHawk,能发个控件给我吗? shh_mao@yahoo.com.cn
来自:qqggch, 时间:2004-5-5 15:14:18, ID:2594578
我的问题是WORD和数据库问题

我现在要对数据库进行查找NO , NAME ,STREAM; 通过 NAME 来查询 STREAM

把查询出来的STREAM(可能有多个结果哦),都保存到WORD文档中(最好是在OLE中)?

请问各位大侠,我该怎么实现?数据库用的是ACCESS
来自:workjie, 时间:2004-5-11 11:58:41, ID:2603998
Application.ActiveDocument.Protect(2);

文档不能修改,不能复制 
来自:duhai_lee, 时间:2004-5-11 17:22:09, ID:2604730
看了半天,就是没有可以解决我的问题的方法,不过先对楼上各位大侠致敬。
    我的问题是这样的:http://www.delphibbs.com/delphibbs/dispq.asp?lid=2604145
    200分还没有送出去。
来自:noah, 时间:2004-5-17 9:46:53, ID:2613553
WordApp.Selection.ParagraphFormat.Alignment:=wdAlignParagraphCenter;提示wdAlignParagraphCenter没有定义,why?谢谢
来自:xuxiaohan, 时间:2004-5-17 10:13:07, ID:2613622
上面的内容我看了n次,没有谈但oleContainer的速度问题,如果能解决下面的问题,也就解决的oleContainer的速度问题
http://www.delphibbs.com/delphibbs/dispq.asp?lid=2530945
来自:bzm131313, 时间:2004-5-24 11:24:06, ID:2624406
菜鸟的2个问题
1:有时 调用word函数会提示 "被呼叫方拒绝接受呼叫",请问什么原因造成 ,怎么解决??
2:怎么加快word 打开文档的速度??
来自:56427256, 时间:2004-5-24 17:13:09, ID:2625253
To SeaHawk
   我愿意测试,给我发一份。
   EMAIL:bie_zm@163.com
             谢谢!
来自:luofs, 时间:2004-5-25 9:37:11, ID:2626126
偶像
来自:rgwfeng, 时间:2004-6-7 0:20:53, ID:2649267
好人多
来自:xzfyes2, 时间:2004-6-25 18:38:28, ID:2681712
to maomaoyu810201
还差好几句
v:=worddoc.Application;
  //v.Selection.TypeText;
   v.Text:="ggfdgfdgfdgdf";
  //v.FileSaveAs('d:/temp/temp.doc');
 end;

来自:dirace, 时间:2004-6-27 16:35:00, ID:2683616
六、全局消息的定义
因为word和Delphi程序是两个软件,相互之间通讯比较麻烦,所以使用全局消息的方法进行。
全局消息必须首先注册,Windows返回系统空闲的消息号,当注册的消息相同时,
Windows系统返回同一个值,这样就保证了使用这个消息号在两个程序之间通讯。

定义消息的办法:
    szMessageString: pchar = 'XIDIAN_11_Stone';
    FMyJoinMessage := RegisterWindowMessage(szMessageString);

发送消息的方法:
    SendMessage(对方句柄,消息,消息附带短变量,消息附带长变量)

这个方面,能否给出个例子?谢谢
来自:uiit, 时间:2004-6-29 19:55:28, ID:2687458
感谢
来自:qiaodong2, 时间:2004-7-1 12:32:31, ID:2690276
各位大虾:有谁知道给word插入图后,如何使图衬于文字下?
来自:mmdberwin, 时间:2004-8-11 3:00:49, ID:2758540
请教一个问题:
  OleContainer1.CreateObjectFromFile('d:/2.xls',true);
  OleContainer1.doVerb(ovShow);//显示文档
  Cur_WorkBook:=OleContainer1.OleObject.Application.WorkBooks[1];
  Cur_WorkSheet:=Cur_WorkBook.WorkSheets[1];
 ¥ Cur_WorkSheet.printPreview;
 为什么这么做的话带¥那一句会出错呢?
 为什么如果我不用OleContainer 而是直接 createoleobject的话就可以呢?
 用OleContainer又怎么预览呢?
来自:guan_2000, 时间:2004-9-26 1:31:18, ID:2825034
长见识,好好看看,请问各位:如何选中DOC文件的第一页?
来自:kai2003, 时间:2004-9-26 22:08:33, ID:2825799
最近遇到一个麻烦的要求,叫我将原来别人作的一个ACCESS数据库中以OLE对象存储的EXCEL文件转出来(记录好多啊,想用程序转),希望各位高手多多帮忙!!!!!
用在数据库上使用Image二进制字段,使用Stream流(loadfromStream,TBlobField)的方式无法读取以在ACCESS数据库中直接插入对象存储的EXCEL文件!
来自:zyxip, 时间:2004-9-28 0:37:17, ID:2827645
  yzhshi  yzhshi  yzhshi 请注意:

  你上面发的给Word 添加按钮的代码可以成功,只是如何给它添加操作呢?

  请教一下关于 Delphi 和 Word ,Excel等的互相发送消息问题,请给个提示。
来自:wzds_2000, 时间:2004-9-30 10:38:22, ID:2831341
收藏
来自:chinaxzx, 时间:2004-10-8 16:12:56, ID:2838617
收藏
来自:crossbannyli, 时间:2004-10-25 16:38:12, ID:2865091
好长,都几年了

可惜我还是不会
来自:aus, 时间:2004-10-25 16:53:19, ID:2865134
看了各位强人贴的,汗如雨下。
收藏!
来自:cchenbo, 时间:2004-11-12 14:05:42, ID:2889207
谢谢 正在学这东西 
来自:rchen, 时间:2004-12-21 22:29:15, ID:2939742
非常感谢,这个帖子让我学到不少:P
不过我最近碰到这样一个问题:

1. 在进程A中启动一个线程Aa, 在这个线程Aa中嵌套word, 通过CreateFromFile打开doc文档, 然后这个线程Aa在进程A结束前一直没有退出(也就是说没有调用CoUninitialize)
2. 这时候启动进程B, 也是内嵌word, 通过CreateFromFile打开doc文档, 但是会停留在::OleRun不动, 一直等到进程A的线程Aa 调用了CoUninitialize后才能继续往下跑.
3. 现在的问题是, 由于需求, Aa 线程不能退出,而B进程也必须能够打开doc文档.
 
有哪位大侠能够提供解决方法,,不胜感激:P
来自:windshow, 时间:2005-2-20 21:12:35, ID:2992464
使用delphi才一天,已经被它吸引了,不过看玩了还是不会,哪个好心人发的范例源码让我学习一下 activeform 做的word控件
email:6144010@qq.com
拜谢了,我只有几百w mp,谁要拿去
来自:bryantd, 时间:2005-3-7 17:13:33, ID:3006353
四、Delphi程序保存Word文稿
格式:WordDocuments.SaveAs(FileName, FileFormat, LockComments, Password,AddToRecentFiles, WritePassword, ReadOnlyRecommended, 
EmbedTrueTypeFonts, SaveNativePictureFormat, SaveFormsData, SaveAsAOCELetter)

楼主能给个具体的例子吗????比如我有一个DOC文件:'e:/test.doc',我想将它转存为一个纯文本文档:'e:/test.doc.txt'。VB代码如下:

Sub 测试保存()
'' 测试保存 Macro
' 宏在 2005-3-7 由 Bryantd 录制
'  ChangeFileOpenDirectory "E:/"ActiveDocument.SaveAs FileName:="test.txt", FileFormat:=wdFormatText, _LockComments:=False, Password:="", AddToRecentFiles:=True, WritePassword _:="", ReadOnlyRecommended:=False, EmbedTrueTypeFonts:=False, _ SaveNativePictureFormat:=False, SaveFormsData:=False, SaveAsAOCELetter:= _False, Encoding:=936, InsertLineBreaks:=False, AllowSubstitutions:=False, _LineEnding:=wdCRLF
End Sub

用OLE在Delphi中应该怎样实现?我是这样写的:
WordApp:=CreateOleObject('Word.Application');
WordApp.Visible:=False;
WordApp.Documents.Open('e:/test.doc');
中间这句怎么写?????????????????????????????????
WordApp.Documents.Close;
WordApp.Quit;
ShowMessage('转存完毕!')
来自:windlin, 时间:2005-3-10 10:52:55, ID:3009987
资料一大堆,可惜还是不会对word有好的控制,真是遗憾
我需要的是在delphi里显示word文档,再对它添加一些资料就可以了....
来自:小角色, 时间:2005-3-11 12:59:05, ID:3011597
大家都没有说到点子上,为什么要避开打印预览这个话题上?
据我所知,要想解决ole的打印预览必须要它的.pas文件才行
来自:寻路, 时间:2005-3-11 21:30:28, ID:3011807
我也觉得如此,关键的打印预览问题,在这里一直没有说明,这个问题如果能够解决,这个贴子就完美了!
来自:cumtwhs, 时间:2005-7-3 9:04:22, ID:3122334
大虾们,有delphi控制word,在word表格中画图的代码没,如画个矩形。
谢谢,cumt-whs@163.com
来自:mfksoft, 时间:2005-7-8 6:07:10, ID:3127617
[推荐]新开最新99B+套装 9999B经验 售套装/+1~+5宝箱,现在即可进入体验全新套装
游戏主页:http://www.tzmu.net
注册网址:http://www.tzmu.net/reg.asp
游戏版本:0.99B+
游戏经验:5000倍,100%防复制外挂,(加入圣导师职业、已提高圣导师攻击力,赤色要塞、卡利玛神庙地图[/卡利玛]和结婚,攻城,开心答题活动)

开服之际:注册就送MU币10亿,前两天经验提高到9999B、商店出售套装、提高掉宝率,为了让你在套装奇迹玩的"爽,爽,爽"。 达到30转愿意留在套装奇迹的玩家就可以跟客服联系领取精美装备一套! 这么好的机会你还犹豫什么?? 

商店物品:套装、祝福、灵魂、转职道具、血城广场物品,+1~+5宝箱,小翅膀及圣导师专用物品;+9追16幸运火麒麟级别防具与大天使武器。

游戏掉宝:卓越暴率1/200,黄金宝箱卓越装备暴率100% 天空宝箱丢出玛雅、生命宝石、金银勋章、暴竹,红心随机丢出+1到+5宝箱。+5宝箱丢出卓越火麒麟、奔雷、圣灵、黑凤套装;破坏、圣灵、毁灭、大天使武器;火龙、精灵、麒麟盾。

游戏设置:限制法师守护之魂最高70%防御,新建人物赠送点数300点,每分钟系统自动发送5万MU币(离线自动发送到帐号仓库)。

升级点数:魔剑士和圣导士每级14点,220级以下其他职业每级10点,220级以上每级12点
来自:dunleesy, 时间:2005-8-17 9:39:13, ID:3169553
有哪位大侠知道如何将word文档转换成图片,且图片的大小可以设置的。
来自:tiesjm, 时间:2005-11-4 9:06:16, ID:3253867
实现该功能的软件请参考:
www.knowehow.com
中下载<计算机辅助写作系统>。我觉得做的不错。
来自:atheney, 时间:2005-11-4 16:02:40, ID:3254489

    如果没有安装Word,只有Word viewer,如果要在Delphi程序中打开包含图片的复杂的文档,并控制其浏览和打印的功能,各位高手,请指教!!!
多谢!!!
来自:SiWeiLiuLang, 时间:2006-1-6 14:35:27, ID:3320477
收藏
来自:bbhorse, 时间:2006-2-12 13:28:26, ID:3351424
我看了好多次了,但是都没有办法解决我的问题。
http://www.delphibbs.com/delphibbs/dispq.asp?lid=3351134
来自:dinglj1760, 时间:2006-2-12 14:01:26, ID:3351430
路过
来自:rgbigeiq, 时间:2006-2-12 16:40:46, ID:3351485
谢谢楼上各位大侠的信息,OFFICE里的各个程序编写代码 和上面的类似,要记得模仿学习,再次谢谢大家
来自:xiaozhixiang, 时间:2006-2-12 17:26:50, ID:3351499
这么多人.但我是看不懂.
来自:gzrvt, 时间:2006-2-22 14:35:09, ID:3360864
好啊,那么多年了!很有帮助!
来自:fly2003, 时间:2006-4-18 16:30:30, ID:3419022
我目前正在搞这个
多谢各位老大
感觉有些东西深入探讨一下就是好
我调用excel的时候发现 ,菜单显示出来但是不能用
还有就是excel好像是独占的 ole打开excel 其他就打不开了
还有就是word进程关闭时候不检查有没有ole调用word,如果word和ole调用word同时打开,关闭word后,ole中的就没有响应了。
初用,见笑了!请指点
来自:大器晚成, 时间:2006-4-21 11:49:45, ID:3422624
看到各位大侠的大作,受益匪浅。请帮忙看一下这段代码:
     mstream:=TMemoryStream.Create;
....
     oleWord.SaveToStream(mstream);
     mstream.Position:=0;
     TBlobField(qryDoc.FieldByName('content')).LoadFromStream(mstream);
     qryDoc.Post;
存到数据库后,读出修改:
        TblobField(FieldbyName('content')).SaveToStream(mstream);
         mstream.Position:=0;
         oleword.LoadFromStream(mstream);
         oleword.DoVerb(ovShow);
word 打开后是空白的,没有数据,为什么?用oleword.close;可以关闭word,不能清空ole中的内容,怎么办呢?请大侠指点!
来自:dsmiao, 时间:2006-5-1 21:56:17, ID:3432547
收下了,好贴。
来自:Alongsun, 时间:2006-5-1 22:48:43, ID:3432581
1。准备一台计算机,安装WINDOWS 2003专业版,配置IIS,配置它的父目录功能,在它的文档中要写入WebForm1.aspx这个文件是我们要编写的程序,所以这里先做好工作了。OK!~。去MS升级所有可用补丁。重启系统。
2。安装delphi 2005,注册,不要安装其它不是DELPHI的组件或者是第三方控件。
2.安装数据库SQL 2003 SERVER,新建一个数据库名称为:netmanger,建立几个表,其中一个表为:UserTable, 字段有5个,为:userID(主键,要求为INT形) UserName(Nchar形长度16) UserPassword(Nchar形长度16) UserProterty (INT形长度4)Others(Nchar形长度250)
配置你的数据库SA密码为:webAppSQLSAPassword2005
3。打开DELPHI2005,然后。。。file-new-> Asp.net web application delphi for .net
配置你的IIS目录到你的程序开发的目录,如果不是就选当前的就可以了。不用理会。
4。把DBGRID控件拖进来你的WEB页中,选SQLCONNECTION,SqlDataAdapter,Dataset一个一个分别放进来。你这时会在下面看到三个组件。放一个BUTTON进来,放一个TEXTBOX进来,这里是用来写SQL的,你可以查询各各东西数据了呀!!!!!!改它的名为:TEXTSQL
下面是配置你的SQL连接或者是在程序中写均可。
我是写到它的BUTTON中的,目的就是当用户访问我的网站时,点按扭就可以看到数据库中的USERTABLE的数据了。
代码如下://这里是增加BUTTON的点击功能
procedure TWebForm1.Button1_Click(sender: System.Object; e: System.EventArgs);
var
  strConn,strSQL : String;
begin
  strConn:='user id=sa;data source="127.0.0.1";persist security info=True;initial catalog=netmanager;password="webAppSQLSAPassword2005"';
  Self.SQLConn.Close;
  Self.SQLConn.ConnectionString:=strConn;
  Self.SQLConn.Open;
  Self.SqlDataAdapter.SelectCommand.Connection:= Self.SQLConn;
  strSQL:=TextSQL.Text;
  self.SqlDataAdapter.SelectCommand.CommandText:=strSQL;
  self.SqlDataAdapter.Fill(self.DataSet);
  self.DG.DataSource:=self.DataSet;
  self.DG.DataBind;
  self.SQLConn.Close;
//用完你不关等于浪费,这个就是ASP.net与ASP不同之处,速度会更快,尤其是当多用户访问时效果明显。
end;

本程序经过我的测试,没问题。IIS+DELPH2005写的.net技术。

最近看到好多朋友说DELPHI2005,2006不好用之类的说法,我感觉如果还是用DELPHI的朋友大可不必转行,用MS的VS也好,用DELPHI也好,都一样,它的书也差不多,我今天去了购书中心,看了一下午,也没找到合适的书买,最后还是自己研究一下,搞定了!
如果有朋友要源码的,可以发邮件给我,共同学习,我在这里只是写了极其简单的程序,目的在于引导大家使用这个DELPHI2005去开发基于.net技术的东东。应该比在DREAMWARE或者是FRONTPAGE中+ASP去开发写程序有更大的方便与乐趣,你只是要放几个控件就搞定了。真的好轻松,速度也很快。

羊城绅士(草于广州)
电话:020-88270969
邮件:alongsun@sina.com
地址:广州市天河区
QQ:65466700
来自:kkkchenA, 时间:2006-5-2 1:06:32, ID:3432634
收下了,好贴。
来自:cdstc, 时间:2006-5-16 22:19:36, ID:3444336
  首先先向楼上各位达人致敬,本人刚学delphi不久,翻了好多书,写了一个简单的查询小软件,用的是access数据库,在listview组件中显示查询出来的数据,现在就缺打印这个功能了,我想直接通过一个按钮把在listview中显示的数据写在跳出来的excel中,再通过直接操作excel 进行设置、打印等,不知道哪位前辈能写一个这样的范例发到我的邮箱让我模仿学习一下?直接看代码实在太抽象了,一头雾水,麻烦你实在很抱歉
  我的邮箱:chendu417@163.com
  QQ : 28232546
来自:gongdazhen, 时间:2006-5-24 19:30:03, ID:3452273
各位好,我想在一个word模板上
读取数据库信息并显示如下
第一题:(共4道,每题4分)
1、
2、
第二题:(共4道,每题4分)
1、
2、
第三题:(共4道,每题4分)
希望能有人给我指教,万分感激。
gongdazhen686@163.com
来自:lemontree2004, 时间:2006-5-31 11:23:25, ID:3458005
就象http://www.dbstep.com/Products/Demo/iweboffice2000/ocxasp/documentlist.asp
里那样,打开word文档是嵌入在网页中的,我知道这个肯定是要用axtiveX完成,这个对word的控制,并保留修改痕迹就不知道是怎么弄的啦,是不是放在OLEcontainer里?有大哥帮忙指点吗 
来自:ranyang, 时间:2006-5-31 11:38:22, ID:3458042
仔细看代码!cdstc的问题很快就能解决!
来自:xiexbb, 时间:2006-7-19 21:12:54, ID:3510785
向大虾们请教一个问题:
   我用CreateOleObject方法创建了一个excel 对象,当我打印的时候,怎么给它的sheet设置纸张的大小呢?我找了好长时间都没有找到呢!
  当然如果使用server中的VCL,则直接可以调用Wordapplication1.ActiveDocument.PageSetup.PageWidth:=XXX;
那位大虾自己,请指点一下啊,谢谢了!

来自:tybb, 时间:2006-8-20 21:30:42, ID:3540241
请教各位大虾delphi编写coreldraw插件,如何实现?
我写有一段vba的程序
但总要在工具菜单里运行才能用, 不方便
想做成插件式的程序(exe),直接运行,请教有什么好方法?
来自:xounter, 时间:2006-8-20 22:07:43, ID:3540262
好文章,学习,收藏了,辛苦lz了
来自:sunde11, 时间:2006-8-20 22:39:16, ID:3540277
谢谢 收藏
来自:创意人生, 时间:2006-9-30 12:16:16, ID:3586433
还是调用VBA的问题,yzhshi说只要在前面加上句柄就可以了,而程序却老是提示我错误。请看:
下面是调整一个图片高度的VBA代码,当然其他不需要的我都删掉了:
Sub a111()
  Selection.InlineShapes(1).Height = 113.4 ;
End Sub
=============================
在Delphi里:
  WordApp.Selection.InlineShapes(1).Height := 113.4 ;

程序却提示错误:"InlineShapes"不是一种方法。
来自:newsmile, 时间:2006-9-30 12:31:48, ID:3586451
WordApp.activedocument.InlineShapes(1).select;
WordApp.activedocument.InlineShapes(1).Height = 113.4;
来自:cjs_5210, 时间:2006-9-30 13:04:01, ID:3586498
精贴,顶
来自:创意人生, 时间:2006-9-30 13:24:50, ID:3586543
To newsmile:
提示错误依旧是:"InlineShapes"不是一种方法。
来自:newsmile, 时间:2006-9-30 13:36:11, ID:3586561
 这里你要注意你文档中的图形是否是嵌入式的(在版式中),嵌入式的是inlineshape其它版式都是shape,另外有可能指定文档中的图形时要用item而不能直接用InlineShapes(1),设置图形的高度时是可以不选中的(即第一行可以不要)。
来自:创意人生, 时间:2006-9-30 14:23:57, ID:3586637
To newsmil:
最后是这样搞定的,把InlineShapes(1)改成InlineShapes.item(1)。
FWord.Selection.InlineShapes.item(1).Height := 150;
非常感谢,我要给你加分,呵呵。怎么加呀?
来自:sxwy, 时间:2006-10-30 10:50:05, ID:3609512
没有结帖,我再问一下,上面的代码是否在D6下使用的,现在我用D7好像不能用.
我用OLE和EXCELAPPLICATION都不能打开一个存在的EXCEL表.
var Temp_Worksheet: _WorkSheet;
begin
    ExcelApplication1.Connect;
    ExcelApplication1.Visible[0]:=True;
    ExcelApplication1.Caption := '应用程序调用 Microsoft Excel';
    ExcelWorkbook1.ConnectTo(ExcelApplication1.Workbooks.Add(EmptyParam,0));

    Temp_Worksheet:=ExcelWorkbook1.
    WorkSheets.Add(EmptyParam,EmptyParam,EmptyParam,EmptyParam,0) as _WorkSheet;
    ExcelWorkSheet1.ConnectTo(Temp_WorkSheet);
    ExcelApplication1.Workbooks.Open('C:/Book1.xls',Emptyparam,Emptyparam,Emptyparam,Emptyparam,Emptyparam,Emptyparam,Emptyparam,Emptyparam,Emptyparam,Emptyparam,Emptyparam,Emptyparam,Emptyparam,Emptyparam,0);//这里会出错.
    //ExcelApplication1.ActiveCell.CopyPicture()//我想把打开的EXCEL拷贝到系统粘贴板.可是参数不知道,哪位朋友帮一下.谢.
来自:newsmile, 时间:2006-10-30 11:02:33, ID:3609530
注意office的版本。知道参数的最好办法是录制宏。
来自:sxwy, 时间:2006-10-30 11:12:23, ID:3609550
唉,我用的是OFFICE2000
来自:lingb, 时间:2006-11-15 14:41:19, ID:3623751
ding:)
来自:dgl_9981, 时间:2006-11-15 19:26:06, ID:3624099
碰到一伙高手,我幸运!
来自:dreamfly1024, 时间:2006-11-15 20:12:54, ID:3624117
有关 CreateOleObject,对 Ole 对象的事件接受,不好处理,大伙一起来讨论讨论!
来自:fly2003, 时间:2007-1-4 16:35:09, ID:3651900
来自:fly2003, 时间:2006-4-18 16:30:30, ID:3419022 | 编辑 
我目前正在搞这个
多谢各位老大
感觉有些东西深入探讨一下就是好
我调用excel的时候发现 ,菜单显示出来但是不能用
还有就是excel好像是独占的 ole打开excel 其他就打不开了
还有就是word进程关闭时候不检查有没有ole调用word,如果word和ole调用word同时打开,关闭word后,ole中的就没有响应了。
初用,见笑了!请指点
 

没有人回答这么低级的问题么
来自:唐宗, 时间:2007-1-4 18:11:55, ID:3651992
实用!谢谢各位,我也来顶一下
来自:Arcan, 时间:2007-1-5 0:16:26, ID:3652127
我一般都用CreateOleObject方法来调用word,不过确实存在上面有人说的对事件支持的不好。
来自:damoyc, 时间:2007-1-16 22:45:43, ID:3660294
这个话题讨论了这么多年,看来很实用,谢谢了!!
来自:lcmlhs, 时间:2007-3-12 10:41:40, ID:3680167
我有一个简单的问题,就是把已知word模板里的所有内容全部读取(或者复制)到delphi新打开的word文档里,怎样实现呀??
来自:hwljerry, 时间:2007-3-13 10:00:33, ID:3680755
 收藏
来自:大器晚成, 时间:2007-3-19 14:39:12, ID:3684199
to lcmlhs:
word的模板是以文件的形式保存的,只要delphi新打开word加载它就可以了
来自:quickchen, 时间:2007-4-2 21:32:20, ID:3694016
to:来自:DragonPC_???, 时间:2001-12-1 22:15:00, ID:758092
dragonpc兄,你给的那个单元里面 uses Ads_Misc,Cmp_Sec,这2个东西是哪里来的啊?
来自:quickchen, 时间:2007-4-2 21:32:22, ID:3694017
to:来自:DragonPC_???, 时间:2001-12-1 22:15:00, ID:758092
dragonpc兄,你给的那个单元里面 uses Ads_Misc,Cmp_Sec,这2个东西是哪里来的啊?
来自:lh2752, 时间:2007-4-7 10:19:24, ID:3696488
经典,收藏了!
来自:wach_wach_wach, 时间:2007-4-11 15:16:21, ID:3698736
请问各路大侠:
    再OLEContainer中显示的Word文档,怎样通过显示一个滚动条来浏览!!!

    小弟不甚感激!!!!!!!!!!!!
来自:howwell, 时间:2007-7-13 17:40:37, ID:3810355
超级好资料,收藏
来自:peakocean, 时间:2007-7-29 0:26:06, ID:3816255
正在研究的好东东。
来自:beij, 时间:2007-11-15 10:20:40, ID:3851893
正在做关于这方面的程序:在MS SQL 中哪种类型的字段可以保存WORD文件?
来自:tshh001, 时间:2007-11-26 12:50:53, ID:3854839
对mssql存word文件感兴趣,关注!!
来自:bjyplbx, 时间:2007-12-12 0:25:51, ID:3859001
http://www.delphibbs.com/delphibbs/dispq.asp?lid=3858991
璋佺粰鐪嬬湅杩欎釜
来自:hegyi, 时间:2008-1-12 22:58:09, ID:3867001
2008年第一个顶的
顶
顶
来自:beij, 时间:2008-5-12 16:29:17, ID:3892776
有人知道如何操作word中的表格吗?
  • 0
    点赞
  • 1
    评论
  • 1
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值