摘要
开发在 Office 文档中使用数据的应用程序时,将数据直接显示在 Visual Basic 应用程序中可能是有益的,这样用户就可以查看和编辑数据,而无需切换到 Office 应用程序。 可以使用 OLE 容器控件在 Visual Basic 中完成此操作。
本文演示如何使用 OLE 容器控件动态创建和自动化 Office 文档。
更多信息
Microsoft 的对象链接和嵌入 (OLE) 技术可以将 Office 文档插入到 Visual Basic 中。 OLE 旨在让一个应用程序以方便最终用户的方式托管属于另一个应用程序的对象,但不需要所涉及的应用程序知道另一个应用程序的内部详细信息。 Visual Basic 提供 OLE 容器控件,让 Visual Basic 程序员将 OLE 对象添加到窗体。
嵌入对象后,大多数 OLE 服务器都支持自动化,以允许主机应用程序以编程方式更改或操作代码中的对象。 若要获取对自动化对象的引用,请使用 OLE 容器的 Object 属性。 此属性返回与嵌入的特定项密切相关的 Automation 对象。
创建承载 Excel 工作簿的 Visual Basic 应用程序
启动 Visual Basic 并创建新的标准项目。 默认情况下会创建 Form1。
在控件工具箱中,将三个命令按钮添加到 Form1。 然后添加 OLE 容器控件的实例。 在窗体上放置 OLE 容器控件时,它会提示你输入要插入的对象的类型。 对于此示例,需要动态添加对象,因此单击“取消”以消除对话框,而无需添加对象。
在 Form1 的“代码”窗口中,添加以下代码:
Option Explicit Dim oBook As Object Dim oSheet As Object Private Sub Command1_Click() On Error GoTo Err_Handler ' Create a new Excel worksheet... OLE1.CreateEmbed vbNullString, "Excel.Sheet" ' Now, pre-fill it with some data you ' can use. The OLE.Object property returns a ' workbook object, and you can use Sheets(1) ' to get the first sheet. Dim arrData(1 To 5, 1 To 5) As Variant Dim i As Long, j As Long Set oBook = OLE1.object Set oSheet = oBook.Sheets(1) ' It is much more efficient to use an array to ' pass data to Excel than to push data over ' cell-by-cell, so you can use an array. ' Add some column headers to the array... arrData(1, 2) = "April" arrData(1, 3) = "May" arrData(1, 4) = "June" arrData(1, 5) = "July" ' Add some row headers... arrData(2, 1) = "John" arrData(3, 1) = "Sally" arrData(4, 1) = "Charles" arrData(5, 1) = "Toni" ' Now add some data... For i = 2 To 5 For j = 2 To 5 arrData(i, j) = 350 + ((i + j) Mod 3) Next j Next i ' Assign the data to Excel... oSheet.Range("A3:E7").Value = arrData oSheet.Cells(1, 1).Value = "Test Data" oSheet.Range("B9:E9").FormulaR1C1 = "=SUM(R[-5]C:R[-2]C)" ' Do some auto formatting... oSheet.Range("A1:E9").Select oBook.Application.Selection.AutoFormat Command1.Enabled = False Command2.Enabled = False Command3.Enabled = True Exit Sub Err_Handler: MsgBox "An error occurred: " & Err.Description, vbCritical End Sub Private Sub Command2_Click() On Error GoTo Err_Handler ' Create an embedded object using the data ' stored in Test.xls.<?xm-insertion_mark_start author="v-thomr" time="20070327T040420-0600"?> If this code is run in Microsoft Office ' Excel 2007, <?xm-insertion_mark_end?><?xm-deletion_mark author="v-thomr" time="20070327T040345-0600" data=".."?><?xm-insertion_mark_start author="v-thomr" time="20070327T040422-0600"?>change the file name to Test.xlsx.<?xm-insertion_mark_end?> OLE1.CreateEmbed "C:\Test.xls" Command1.Enabled = False Command2.Enabled = False Command3.Enabled = True Exit Sub Err_Handler: MsgBox "The file 'C:\Test.xls' does not exist" & _ " or cannot be opened.", vbCritical End Sub Private Sub Command3_Click() On Error Resume Next ' Delete the existing test file (if any)... Kill "C:\Test.xls" ' Save the file as a native XLS file... oBook.SaveAs "C:\Test.xls" Set oBook = Nothing Set oSheet = Nothing ' Close the OLE object and remove it... OLE1.Close OLE1.Delete Command1.Enabled = True Command2.Enabled = True Command3.Enabled = False End Sub Private Sub Form_Load() Command1.Caption = "Create" Command2.Caption = "Open" Command3.Caption = "Save" Command3.Enabled = False End Sub
按 F5 键运行程序。 单击“创建”按钮。 这会嵌入新的工作表和自动执行 Excel,以便将数据直接添加到工作表。 请注意,如果双击该对象,它将就地激活,并且用户可以直接编辑数据。 现在单击“保存”将数据保存到文件,并关闭 OLE 对象。 “打开”按钮允许你打开以前保存的文件的副本。
创建承载 Word 文档的 Visual Basic 应用程序
启动 Visual Basic 并创建新的标准项目。 默认情况下会创建 Form1。
在控件工具箱中,将三个命令按钮添加到 Form1。 然后添加 OLE 容器控件的实例。 在窗体上放置 OLE 容器控件时,它会提示你输入要插入的对象的类型。 对于此示例,我们需要动态添加对象,因此单击“取消”以消除对话框,而无需添加对象。
在 Form1 的“代码”窗口中,添加以下代码:
Option Explicit Dim oDocument As Object Private Sub Command1_Click() On Error GoTo Err_Handler ' Create a new Word Document... OLE1.CreateEmbed vbNullString, "Word.Document" ' Add some text to the document. The OLE.Object ' property returns the document object... Set oDocument = OLE1.object oDocument.Content.Select With oDocument.Application.Selection ' Add a heading at the top of the document... .Style = oDocument.Styles("Heading 1") .Font.Color = &HFF0000 .TypeText "Blue Sky Airlines" .ParagraphFormat.Alignment = 1 '[wdAlignParagraphCenter] .TypeParagraph .TypeParagraph ' Now add some text... .TypeText "Dear Mr. Smith," .TypeParagraph .TypeParagraph .TypeText "Thank you for your interest in our current fares " & _ "from Oakland to Sacramento. We guarantee to be " & _ "the lowest price for local flights, or we'll " & _ "offer to make your next flight FREE!" .TypeParagraph .TypeParagraph .TypeText "The current fare for a flight leaving Oakland " & _ "on October 4, 1999 and arriving in Sacramento " & _ "the same day is $54.00." .TypeParagraph .TypeParagraph .TypeText "We hope you will choose to fly Blue Sky Airlines." .TypeParagraph .TypeParagraph .TypeText "Sincerely," .TypeParagraph .TypeParagraph .TypeParagraph .TypeText "John Taylor" .TypeParagraph .Font.Italic = True .TypeText "Regional Sales Manager" .TypeParagraph End With ' Zoom to see entire document... OLE1.SizeMode = 3 OLE1.DoVerb -1 Command1.Enabled = False Command2.Enabled = False Command3.Enabled = True Exit Sub Err_Handler: MsgBox "An error occurred: " & Err.Description, vbCritical End Sub Private Sub Command2_Click() On Error GoTo Err_Handler ' Create an embedded object using the data ' stored in Test.doc.<?xm-insertion_mark_start author="v-thomr" time="20070327T040719-0600"?> If this code is run in Microsoft Office ' Word 2007, change the file name to Test.docx.<?xm-insertion_mark_end?><?xm-deletion_mark author="v-thomr" time="20070327T040717-0600" data=".."?> OLE1.CreateEmbed "C:\Test.doc" Command1.Enabled = False Command2.Enabled = False Command3.Enabled = True Exit Sub Err_Handler: MsgBox "The file 'C:\Test.doc' does not exist" & _ " or cannot be opened.", vbCritical End Sub Private Sub Command3_Click() On Error Resume Next ' Delete the existinf test file (if any)... Kill "C:\Test.doc" ' Save the file as a native Word DOC file... oDocument.SaveAs "C:\Test.doc" Set oDocument = Nothing ' Close the OLE object and remove it... OLE1.Close OLE1.Delete Command1.Enabled = True Command2.Enabled = True Command3.Enabled = False End Sub Private Sub Form_Load() Command1.Caption = "Create" Command2.Caption = "Open" Command3.Caption = "Save" Command3.Enabled = False End Sub
按 F5 键运行程序。 单击“创建”按钮。 这会嵌入新文档并自动执行 Word,以便将数据直接添加到文档。 请注意,如果双击该对象,它将就地激活,并且用户可以直接编辑数据。 现在单击“保存”将数据保存到文件,并关闭 OLE 对象。 “打开”按钮允许你打开以前保存的文件的副本。
使用 OLE 容器时的注意事项
如果要从现有文件嵌入,则在 OLE 容器内看到的数据是文件上数据的副本。 所做的任何更改不会自动保存到同一文件。 虽然可以使用与上述技术类似的技术将结果保存回特定文件,但并非所有 OLE 服务器都支持此功能。 它不被视为正常的 OLE 对象行为。
如果要“链接”到文件,则无法就地激活该对象。 相反,当用户双击对象时,该对象会在服务器应用程序的窗口中打开。 只能就地激活嵌入对象。
OLE 容器控件具有数据绑定感知。 如果有 Access 97 或 Access 2000 数据库,则可以将控件绑定到数据库中的 OLE 对象字段。 显示窗体时,数据将从数据库中拉取并显示供用户编辑。 关闭 OLE 对象时,用户所做的任何编辑更改都将自动保存回数据库。
若要绑定 OLE 容器控制数据,请添加 Visual Basic 数据控件并将其 DatabaseName 属性设置为数据库路径。 然后将 RecordSource 设置为数据库中的现有表。 使用 OLE 控件的 DataSource 属性将控件绑定到 Visual Basic 数据控件,然后将 DataField 属性设置为指向包含 OLE 对象的记录集中的特定字段。 Visual Basic 执行其余操作。
当容器处于活动状态时显示的已孵化边框的大小和位置取决于对象的大小以及为 OLE 控件选择的选项。 显示此边框以标记编辑窗口的边界。 编辑窗口的边界通常与 OLE 容器本身的边界不匹配;此行为对于 OLE 对象是正常的。 编辑窗口不能以编程方式从 Visual Basic 更改。
某些自动化方法可能无法正常工作,除非该对象已就地处于活动状态。 若要以编程方式激活 OLE 对象,请使用 DoVerb 方法并将 vbOLEShow (-1) 指定为谓词。
可以通过设置窗体的 NegotiateMenus 属性来确定链接或嵌入对象的菜单是否显示在容器窗体中。 如果子窗体的 NegotiateMenus 属性设置为 True,并且容器定义了菜单栏,则激活对象时,对象的菜单将放置在容器的菜单栏上。 如果容器没有菜单栏,或者 NegotiateMenus 属性设置为 False,则激活对象时不会显示该对象的菜单。 请注意,NegotiateMenus 属性不适用于 MDI 窗体,因此 MDI 窗体的菜单不能与已激活对象的菜单合并。 若要说明菜单协商,请尝试使用在上一部分中创建的示例应用程序:
- 运行应用程序并单击“创建”按钮以在 OLE 容器中嵌入新文档。
- 右键单击 OLE 容器,然后选择“编辑”以就地激活对象。 请注意,由于 Form1 的 NegotiateMenus 属性默认设置为 True,因此会显示对象应用程序的菜单。
- 关闭窗体以结束应用程序。
- 选择 Form1 后,单击“工具”菜单上的菜单编辑器。
- 使用标题文件和名称 mnuFile 创建新的顶级菜单。 将此菜单的 NegotiatePosition 属性设置为“1-Left”。创建标题为“打开”和“名称 mnuOpen”的菜单项。
- 单击“确定”关闭菜单编辑器。
- 再次运行应用程序,然后单击“创建”按钮,在 OLE 容器中嵌入新文档。
- 右键单击 OLE 容器,然后选择“编辑”以就地激活对象。 请注意,Form1 的菜单已与对象应用程序的菜单合并。
Visual Basic 不允许在添加时控制菜单合并过程或更改服务器的菜单项。 但是,可以使用类似于以下内容的代码,通过自动化更改或修改 Office 应用程序的菜单:
' This code disables the Insert|Object item on the merged menu... Dim oMenuBar As Object Set oMenuBar = oBook.Application.CommandBars("Worksheet Menu Bar") oMenuBar.Controls("&Insert").Controls("&Object...").Enabled = False
请注意,可能需要在对象处于活动状态之前进行一些更改,否则更改可能无法显示在合并的菜单中。
注意 此要点不适用于 Microsoft Office Excel 2007 或 Microsoft Office Word 2007。
Visual Basic 目前不支持分配工具栏空间。 因此,在激活对象时,通常不会显示停靠的工具栏。 但是,可以使用自动化显示浮动工具窗口:
OLE1.DoVerb -1 '[vbOLEShow] With oBook.Application.CommandBars("Standard") .Position = 4 '[msoBarFloating] .Visible = True End With
注意 此要点不适用于 Microsoft Office Excel 2007 或 Microsoft Office Word 2007。
对于要求对象始终保持就地处于活动状态的程序,Microsoft 提供了 ActiveX 文档技术。 并非所有 OLE 服务器都是 ActiveX 文档服务器;Microsoft Word、Microsoft Excel 和 Microsoft PowerPoint 是 ActiveX 文档服务器。
Visual Basic 不支持托管 ActiveX 文档的本机控件。 但是,Internet Explorer (版本 3.0 及更高版本) 附带的 WebBrowser 控件确实支持这种形式的就地控制。 可以使用此控件将 Office 文档作为 ActiveX 文档打开。 有关使用 WebBrowser 控件的详细信息,请参阅以下文章:
243058 如何使用 WebBrowser 控件打开 Office 文档
OLE 容器的 SaveToFile 方法创建可在 OLE 容器中打开的文件。 但是,使用 OLE 容器的 SaveToFile 方法保存的文件不能直接在相应的 Office 应用程序中打开。 如果要将嵌入的文档保存到磁盘,以便可以在目标应用程序中打开文档,请使用应用程序的文档 SaveAs 方法:
OLE1.object.SaveAs ("C:\MyNewFile.doc")