使用 Microsoft 登录
登录或创建帐户。
你好,
使用其他帐户。
你有多个帐户
选择要登录的帐户。

摘要

本文解答了有关从 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. 我不熟悉自动化,在哪里可以找到要了解详细信息的好资源? David Kruglinski 的“Visual C++内部” (ISBN:1-57231-565-2) 提供了一般概述和一些很好的示例。 此外,Microsoft 知识库是一个很好的信息来源。
    如果你更喜欢通过示例学习,请参阅 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++“智能指针”。 它非常强大,但通常不建议使用,因为与 Microsoft Office 应用程序一起使用时通常会发生引用计数问题。

    • C/C++ 自动化要困难得多,但有时需要避免 MFC 开销或#import问题。 基本上,可以使用 CoCreateInstance () 等 API 以及 IDispatch 和 IUnknown 等 COM 接口。

    请务必注意,与纯 C 相比,C++ 中的自动化之间存在一些细微差别,因为 COM 是围绕 C++ 类设计的。
     

  4. 什么是 COM?

    自动化基于组件对象模型 (COM) 。 COM 是基于接口的标准软件体系结构,旨在将代码分隔成独立的对象。 将其视为面向对象的编程 (OOP) 范例的扩展,但适用于单独的应用程序。 每个对象公开一组接口,与对象的所有通信(如初始化、通知和数据传输)都通过这些接口进行。

    COM 也是动态链接库提供的一组服务, (DLL) 随操作系统一起安装。 自动化使用其中许多服务。 一个示例是“封送”服务,该服务打包客户端应用程序对服务器应用程序接口成员函数的调用,并将这些调用及其参数传递给服务器应用程序。 它使服务器的接口似乎在客户端的内存空间中公开,当客户端是在其自己的进程空间中运行的.exe时,情况并非如此。 封送处理还会跨进程边界从服务器的方法获取返回值,并安全地交到客户端调用手中。 还有许多其他对自动化至关重要的服务,这些服务由各种 COM 库提供。 有关这些信息的来源包括 Kraig Brockschmidt 的“Inside Ole - 第二版”、ISBN 1-55615-843-2、戴尔·罗杰森的“Inside COM”-ISBN 1-57231-349-8 和“自动化程序员参考”,ISBN 1-57231-584-9。

  5. 如何实现附加到 Office 应用程序的正在运行的实例?

    使用 GetActiveObject () API。 自动化服务器通过 RegisterActiveObject () API 在 ROT (Running Object Table) 中注册自己。 自动化客户端可以使用以下代码访问正在运行的实例:

     

          // 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 中注册其文档,因此可以通过循环访问 ROT 查找特定文档、附加该文档,然后从中获取 Application 对象来成功附加到其他实例。
    无需为 PowerPoint 执行此操作,因为它是单实例应用程序;只能运行它的一个实例。

  6. 如何实现传递可选参数?

    某些方法具有“可选”参数。 在 Visual Basic 中,可以在调用 方法时随意省略它们。 但是,在使用 Visual C++ 调用时,必须传递一个特殊 VARIANT,该变量的 .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 应用程序公开的事件?

    基本上,实现要捕获 (“接收器”) 的事件接口,并 (“源”) 与应用程序建立咨询连接。

    通常,若要设置咨询连接,请获取服务器的 IConnectionPointContainer,并使用事件接口的 IID 调用 FindConnectionPoint () 。 这为你提供了一个 IConnectionPoint 接口,剩下的就是使用事件接口的实例调用 Advise () 。 然后,当发生这些事件时,服务器将通过此接口回调。

  8. 我的自动化代码太慢了。 如何加快速度?

    自动化速度问题的一个常见原因是重复读取和写入数据。 这是 Excel 自动化客户端的典型应用。 但是,大多数人不知道此数据通常可以使用 SAFEARRAY 一次性写入或读取。 有关详细信息和信息性示例,请参阅以下 Microsoft 知识库文章:

    179706 HOWTO:使用 MFC 自动执行 Excel 和创建新工作簿/设置新工作簿
    的格式 此外,请务必指出,使用剪贴板有时可以提高性能。 例如,可以将数据复制到剪贴板,然后使用自动化来告知服务器进行粘贴。 反之亦然;告知服务器复制到剪贴板,并粘贴到应用程序中。

  9. 这些巨大的错误值(如 -2147352573 或 0x80030002)是什么意思?

    这些值称为 HRESULT,在 winerror.h 中定义。 数字如此之大,因为第一个位表示它是否是错误结果。 可以使用 Visual C++ 附带的 ErrLook.Exe 实用工具将这些数字转换为有意义的说明。

    如果要以编程方式获取错误说明,可以使用 FormatMessage () API。

    注意:如果使用 Visual C++ 6.0 并在调试监视窗口中有一个包含此值的变量,请追加“, hr” (不带引号) ,以便 Visual C++ 为你翻译它!

  10. 什么是类型库?

    类型库类似于 C/C++ 头文件。 它包含服务器正在发布的接口、方法和属性。 可以使用 Visual C++ 附带的 OLE/COM 对象查看器 (Oleview.exe) 查看类型库。 下面是 Microsoft Office 95、97 和 2000 的类型库文件名列表:



    Office 应用程序|类型库
    ------------------------+----------------
    Word 95 和以前的|wb70en32.tlb
    Excel 95 及更早版本的|xl5en32.olb
    Powerpoint 95 和以前的|Powerpoint.tlb
    Access 95 及更早|msaccess.tlb
    Binder 95 |binder.tlb
    Schedule+ |sp7en32.olb
    项目|pj4en32.olb
    团队经理|mstmgr1.olb
    Word 97 |msword8.olb
    Excel 97 |excel8.olb
    Powerpoint 97 |msppt8.olb
    Access 97 |msacc8.olb
    Binder 97 |msbdr8.olb
    图 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 实现。 这意味着,如果从单独的对象 Y 从对象 X 请求方法或属性,则会收到错误0x80020003 -2147352573,“找不到成员”。 若要避免此错误,需要确保调用的基础 IDispatch 接口在语义上正确。
     

  2. 程序完成后,我自动执行的应用程序将保留在内存中。 发生了什么事情?

    很可能是因为你忘记了发布获取的接口,需要跟踪它。 下面是一些常规建议和要查找的事项:
     

    • 如果使用 #import,则很可能遇到与之关联的引用计数 bug 之一。 通常,可以解决 bug,但通常首选使用其他自动化方法之一。 #import不太适用于 Office 应用程序,因为它的类型库和用法相当复杂。 此外,此类引用计数问题很难跟踪,因为使用 #import 时,许多接口级 COM 调用都是幕后调用。

    • 检查是否调用任何方法(如 Open 或 New),这些方法返回 IDispatch * (LPDISPATCH) ,并忽略返回值。 如果是,则放弃此返回的接口,并且需要更改代码,以便在不再需要时将其释放。

    • 逐步注释掉代码的各部分,直到问题消失,然后明智地将其添加,以跟踪问题开始的位置。

    • 请注意,如果用户已“触摸”应用程序,某些应用程序将保持运行。 如果在自动化时发生这种情况,则应用程序可能会在之后继续运行。 Office 应用程序在 Application 对象上具有“UserControl”属性,可读写该属性来更改此行为。

    • 此外,如果发生了足够的用户界面“操作”,某些应用程序将决定继续运行。 如果打算退出应用程序,请在 Application 对象上调用其 Quit () 方法。 调用 Quit 时,无论 Word 的引用计数如何,Word 都将关闭。 这不是预期的 COM 行为。 但是,Excel 将正确隐藏自身,但会一直运行,直到释放所有未完成的接口。 通常,应释放所有未完成的引用,并且仅当打算退出应用程序时调用 Quit () 。

  3. 我知道作为 Office 应用程序用户我想做什么,但如何通过自动化以编程方式执行此操作?

    你感兴趣的是需要使用哪些对象、方法和属性。 若要了解如何根据用户需要执行的操作导航 Word、Excel 和 Powerpoint 的对象模型,最佳方法是使用宏录制器。 只需从“工具”菜单中选择“宏”“录制新宏”,执行感兴趣的任务,然后选择“宏”“停止录制”。 录制完成后,从“工具”菜单中选择“宏\宏”,选择录制的宏,然后单击“编辑”。 这会将你带到生成的 VBA 代码,该代码将完成你记录的任务。 请记住,在大多数情况下,录制的宏不是最好的代码,但对于快速示例来说,它非常有用。

  4. 是否可以自动执行嵌入式 Office 应用程序?

    绝对。 技巧在于获取 IDispatch 指针:Visual C++ 技术说明 39 (TN039) 中提供了此指针。
     

  5. 如何实现 Office 文档中访问我的文档属性?

    文档属性可通过自动化或直接通过 IPropertyStorage 进行访问。
     

需要更多帮助?

需要更多选项?

了解订阅权益、浏览培训课程、了解如何保护设备等。

社区可帮助你提出和回答问题、提供反馈,并听取经验丰富专家的意见。

此信息是否有帮助?

你对语言质量的满意程度如何?
哪些因素影响了你的体验?
按“提交”即表示你的反馈将用于改进 Microsoft 产品和服务。 你的 IT 管理员将能够收集此数据。 隐私声明。

谢谢您的反馈!

×