使用 Visual c + + 的 Office 自动化


摘要


本文解答了与 Visual c + + 中的 Microsoft Office 自动化有关的常见问题。

更多信息


目录

  1. 什么是自动化?
  2. 我是 "自动化" 新手,在哪里可以找到合适的资源来了解更多信息?
  3. 我可以使用不同的自动化方式吗?
  4. 什么是 COM?
  5. 如何附加到 Office 应用程序的运行实例?
  6. 如何传递可选参数?
  7. 如何捕获由 Office 应用程序公开的事件?
  8. 我的自动化代码太慢。 如何加速操作?
  9. 这些非常大的错误值(如-2147352573 或0x80030002)意味着什么?
  10. 什么是类型库?
  11. 我的自动化代码与 Microsoft Excel 95 一起工作,但无法使用 Microsoft Excel 97。 说明?
  12. 我的程序完成后,为什么应用程序自动保留在内存中?
  13. 我知道我希望作为 Microsoft Office 应用程序用户执行的操作,但如何使用自动化以编程方式执行此操作?
  14. 是否可以自动执行嵌入式 Microsoft Office 应用程序?
  15. 如何在 Microsoft Office 文档中访问我的文档属性?

问题和解答

  1. 什么是自动化? 自动化(以前称为 OLE 自动化)是一种技术,可让你利用现有程序的功能并将其并入你自己的应用程序。 例如,你可以将 Microsoft Word 拼写和语法检查功能用于你的应用程序,但不会向你的用户显示 Microsoft Word。 您甚至可以使用 Microsoft Excel 的所有图表、打印和数据分析工具。 此技术可以极大地简化和加速开发。
  2. 我是 "自动化" 新手,在哪里可以找到合适的资源来了解更多信息? 第 24 Kruglinski 的第24章 "Visual c + + 内部" (ISBN: 1-57231-565-2)提供一般概述以及一些极佳的示例。 另外,Microsoft 知识库是一个很好的信息来源。 本文本身是一种良好的开端,您可以在以下 Microsoft 知识库文章中找到更具体的参考资料:
    152023 查找资源以研究 OLE 自动化
    如果您喜欢通过示例学习,请参阅 Microsoft 知识库中的以下文章:
    179706 方法使用 MFC 自动处理 Excel & 创建/设置新工作簿的格式
  3. 我可以使用不同的自动化方式吗? 可以使用自动化的三种基本方法: MFC、#import 和 C/c + +:
    • 使用 MFC,使用 Visual c + + ClassWizard 从 Microsoft Office 类型库生成 "包装类"。 这些类以及其他 MFC 类(如 COleVariant、COleSafeArray、COleException)简化了自动化的任务。 此方法通常推荐其他方法使用,并且大多数 Microsoft 知识库示例都使用 MFC。
    • #import,Visual c + + 5.0 变为可用的新指令,从指定的类型库创建 VC + + "smart 指针"。 它非常强大,但通常不建议使用 Microsoft Office 应用程序时通常会出现的引用计数问题。
    • C/c + + 自动化的难度更大,但有时需要避免与 MFC 的开销或 #import 的问题。 基本上,你可以使用诸如 CoCreateInstance ()之类的 Api 和 COM 接口(如 IDispatch 和 IUnknown)。
    请务必注意,c + + 中的自动化与纯 C 的不同之处稍有不同,因为 COM 是围绕 c + + 类设计的。 有关详细信息,请参阅 Microsoft 知识库 for C 示例中的以下文章:
    181473 方法:使用来自 C 应用程序的 OLE 自动化
  4. 什么是 COM? 自动化基于组件对象模型(COM)。 COM 是基于接口的标准软件体系结构,设计用于将代码拆分为自包含的对象。 将它视为面向对象的编程(OOP)范例的扩展,但适用于单独的应用程序。 每个对象都公开一组接口,并且与某个对象(如初始化、通知和数据传输)的所有通信都将通过这些接口发生。 COM 也是随操作系统一起安装的动态链接库(Dll)提供的一组服务。 自动化使用其中许多服务。 一个示例是 "封送处理" 服务,它将客户端应用程序的调用打包到服务器应用程序接口的成员函数中,并将这些函数及其参数传递给服务器应用程序。 它使服务器的接口显示在客户端的内存空间中,当客户端在其自己的进程空间中运行时,这种情况并非如此。 封送处理还将从服务器的方法返回值返回到进程边界,并安全地进入客户端调用的手中。 不同 COM 库提供的自动化有许多其他服务。 Kraig Brockschmidt、ISBN 1-55615-843-2、"内部 COM"、Dale Rogerson-ISBN 1-57231-349-8 和 "Automation 程序员参考"、"ISBN 1-57231-584-9" 的相关信息来源。
  5. 如何附加到 Office 应用程序的运行实例? 使用 GetActiveObject () API。 自动化服务器通过 RegisterActiveObject () API 在 ROT (运行对象表)中注册自己。 自动化客户端可以使用以下代码获取运行实例:
          // Translate server ProgID into a CLSID. ClsidFromProgID      // gets this information from the registry.      CLSID clsid;      CLSIDFromProgID(L"Excel.Application", &clsid);        // Get an interface to the running instance, if any..      IUnknown *pUnk;      HRESULT hr = GetActiveObject(clsid, NULL, (IUnknown**)&pUnk);      ASSERT(!FAILED(hr));      // Get IDispatch interface for Automation...      IDispatch *pDisp;      hr = pUnk->QueryInterface(IID_IDispatch, (void **)&pDisp);      ASSERT(!FAILED(hr));      // Release the no-longer-needed IUnknown...      pUnk->Release();
    注意:如果有多个实例运行要附加的 Office 应用程序,你将只能附加到使用 GetActiveObject () API 启动的第一个实例。 理论上,你可以为每个单独实例循环访问 ROT,但如果另一个实例已存在于 ROT 中,则 Office 应用不会注册自己,因为名字对象的名字对象始终是相同的(但仍无法区分)。 这意味着您不能附加到除第一个实例之外的任何实例。 但是,由于 Office 应用还在 ROT 中注册其文档,因此你可以通过循环查找特定文档、连接到该文档,然后从该文档获取应用程序对象来成功附加到其他实例。 以下 Microsoft 知识库文章中有一些代码可用于迭代 ROT 和查找文档名称:
    190985 方法:从 OCX 中获取 Excel 或 Word 文档的 IDispatch
    您无需为 PowerPoint 执行此操作,因为它是单实例应用程序;只能有一个运行实例。
  6. 如何传递可选参数? 某些方法具有 "可选" 参数。 在 Visual Basic 中,你可以在调用该方法时随便省略它们。 但是,当使用 Visual c + + 进行调用时,你必须传递一个特殊的变体,其 vt 字段为 VT_ERROR,scode 字段为 DISP_E_PARAMNOTFOUND。 那是:
          // VARIANT used in place of optional-parameters.      VARIANT varOpt;      varOpt.vt = VT_ERROR;      varOpt.scode = DISP_E_PARAMNOTFOUND;
    这实际上是 Visual Basic 在后台执行的操作。
  7. 如何捕获由 Office 应用程序公开的事件? 基本上,你可以实现要捕获的事件接口("sink"),并设置与应用程序的通知连接("source")。 以下文章提供了 Microsoft Word 的分步示例:
    183599 方法:使用 VC + + 捕获 Microsoft Word97 应用程序事件
    通常,要设置通知连接,你可以获取服务器的 IConnectionPointContainer,并使用事件接口的 IID 调用 FindConnectionPoint ()。 这将为你提供一个 IConnectionPoint 接口,剩下的就是用你的事件接口的实例调用 Advise ()。 然后,在发生这些事件时,服务器将通过此接口回拨。
  8. 我的自动化代码太慢。 如何加速操作? 自动化的快速问题的常见原因是重复读取和写入数据。 这是 Excel 自动化客户端的典型操作。 但是,大多数人不知道这些数据通常可以使用 SAFEARRAY 一次性写入或读取。 有关详细信息和信息性示例,请参阅以下 Microsoft 知识库文章:
    186120 方法:使用 MFC 自动处理 Excel 并使用数组填充区域
    186122 方法:使用 MFC 自动处理 Excel & 从区域获取数组
    179706 方法:使用 MFC 自动处理 Excel 并创建/设置新工作簿的格式
    此外,还必须指出使用剪贴板有时可以提高性能。 例如,你可以将数据复制到剪贴板,然后使用自动化通知服务器粘贴。 反之亦然;告诉服务器复制到剪贴板,并粘贴到你的应用程序中。
  9. 这些非常大的错误值(如-2147352573 或0x80030002 意味着什么)? 这些值称为 Hresult,在 winerror.h 中定义。 由于第一个位表示它是否为错误结果,因此数字较大。 你可以使用 Visual c + + 附带的 ErrLook 实用工具将这些数字转换为有意义的说明。 若要以编程方式获取错误的说明,可以使用 FormatMessage () API。 有关详细信息和使用 FormatMessage ()的示例,请参阅以下 Microsoft 知识库文章:
    186063 信息:翻译 VB/VBA 的自动化错误
    122957 示例: Decode32 和 Decode16 OLE 错误代码解码器工具
    注意:如果你使用的是 Visual c + + 6.0,并且在调试监视窗口中有一个包含此值的变量,则将 ",hr" (不带引号)附加到它以使 Visual c + + 为你翻译!
  10. 什么是类型库? 类型库类似于 C/c + + 头文件。 它包含服务器正在发布的接口、方法和属性。 你可以通过 Visual c + + 附带的 OLE/COM 对象查看器(Oleview)查看类型库。 下面是 Microsoft Office 95、97和2000的类型库文件名的列表:
           Office Application      | Type library       ------------------------+----------------       Word 95 and prior       | wb70en32.tlb       Excel 95 and prior      | xl5en32.olb       Powerpoint 95 and prior | Powerpoint.tlb       Access 95 and prior     | msaccess.tlb       Binder 95               | binder.tlb       Schedule+               | sp7en32.olb       Project                 | pj4en32.olb       Team Manager            | mstmgr1.olb       Word 97                 | msword8.olb       Excel 97                | excel8.olb       Powerpoint 97           | msppt8.olb       Access 97               | msacc8.olb       Binder 97               | msbdr8.olb       Graph 97                | graph8.olb       Outlook 97              | msoutl8.olb       Outlook 98              | msoutl85.olb       Word 2000               | msword9.olb       Excel 2000              | excel9.olb       Powerpoint 2000         | msppt9.olb       Access 2000             | msacc9.olb       Outlook 2000            | msoutl9.olb       Word 2002               | msword.olb       Excel 2002              | excel.exe       Powerpoint 2002         | msppt.olb       Access 2002             | msacc.olb       Outlook 2002            | msoutl.olb  
  1. 我的自动化代码与 Excel 95 一起工作,但 Excel 97 失败。 发生了什么事情? Excel 的对象模型从版本95到97进行了重大更改。 Excel 95 在 IDispatch 的单个实现中实现了其所有方法和属性。 这意味着通常情况下,您可以从对象 Y 调用对象 X 所代表的方法。这不是一个好的设计,因此在 Office 97 中,每个对象都有其自己的独立的 Idispatch 实现。 这意味着,如果你从对象 X 的单个对象 Y 请求一个方法或属性,则会收到错误0x80020003,-2147352573,"找不到成员"。 若要避免此错误,你需要确保你正在进行调用的基础 IDispatch 接口是语义正确的。 有关详细信息,请参阅以下 Microsoft 知识库文章:
    172108 方法:疑难解答 "找不到成员"、0x80020003 错误
  2. 程序完成后,我的应用程序自动在内存中保留。 发生了什么事情? 这很可能是因为你忘记了释放已获取的接口,你需要对其进行跟踪。 下面是一些常规建议和要查找的内容:
    • 如果你使用 #import,很有可能会在与之关联的其中一个引用计数 bug 中运行。 通常情况下,可能会解决 bug,但通常最好使用其他自动化方法之一。 由于 Office 应用程序的类型库和使用非常复杂,因此 #import 不太适合 Office 应用程序。 此外,此类引用计数问题很难跟踪,因为许多接口级别的 COM 调用都在使用 #import 时位于幕后。
    • 检查以查看是否调用了任何方法(如 Open 或 New),这些方法返回 IDispatch * (LPDISPATCH),并忽略返回值。 如果是,则你将放弃此返回的接口,并且需要更改你的代码,以便在不再需要时将其释放。
    • 逐渐注释掉代码的各个部分,直到问题消失,然后再将其进一步添加,以跟踪问题的开始位置。
    • 请注意,如果用户已 "接触" 应用程序,则某些应用程序将保持运行。 如果在执行自动化时出现这种情况,则应用程序可能会随后保持运行。 Office 应用程序在应用程序对象上具有 "UserControl" 属性,您可以通过读取/写入来更改此行为。
    • 此外,某些应用程序将决定在出现足够的用户界面 "操作" 时保持运行。 如果要退出应用程序,请在应用程序对象上调用其 Quit ()方法。 当调用 Quit 时,Word 将关闭,而不考虑其引用计数。 这不是预期的 COM 行为。 但是,Excel 将正确地隐藏自己,但一直保持运行,直到释放所有未处理的接口。 通常,你应该释放所有未处理的引用,并且仅当你打算退出应用程序时,才会调用 Quit ()。
  3. 我知道我要作为 Office 应用程序用户执行的操作,但如何通过自动化以编程方式执行此操作? 你感兴趣的内容是你需要使用的对象、方法和属性。 了解如何使用宏录制器在 Word、Excel 和 Powerpoint 的对象模型之间导航的最佳方式是使用宏录制器。 只需从 "工具" 菜单中选择 "宏"、"录制新宏"、执行感兴趣的任务,然后选择 "宏" "停止录制"。 完成录制后,从 "工具" 菜单中选择 "Macro\Macros",选择录制的宏,然后单击 "编辑"。 这将向你转到生成的 VBA 代码,该代码将完成你录制的任务。 请记住,录制的宏在大多数情况下不是最可能的代码,但它非常适合于快速示例。
  4. 是否可以自动执行嵌入的 Office 应用程序? 方式. 秘诀是获取 IDispatch 指针:这在 Visual c + + 技术说明39(TN039)中提供。 有关分步示例,请参阅以下 Microsoft 知识库文章:
    184663 方法:使用 MFC 嵌入和自动化 Microsoft Excel 工作表
  5. 如何在 Office 文档中访问我的文档属性? 可通过自动化或直接通过 IPropertyStorage 访问文档属性。 以下 Microsoft 知识库文章演示了每种方法:
    179494 方法:使用自动化检索内置文档属性
    186898 方法:直接用 VC + + 读取复合文档属性