如何自动使用 c + + 的嵌入的 Office ActiveX 文档

时间:2022-04-01 21:03:37

vc中嵌入excel的链接

http://support.microsoft.com/kb/307473

http://support.microsoft.com/kb/311546/en-us

解决问题的链接

http://support.microsoft.com/kb/316587

本逐步式指南可用于自动执行嵌入的 Microsoft Office 文档。按照下面的过程使用 VC + + MFC 容器作为 ActiveX 文档容器已激活的 Excel 工作表。该代码包含示例获取文档的服务器到一个 IDispatch 接口指针的方法,并演示如何自动嵌入的 Excel 工作表。

使用 Office 应用程序作为 ActiveX 文档服务器

ActiveX 文档容器可以包含多个 Office 文档中,但可以一次显示一个文档。当激活 Office 文档时,Office 文档的服务器应用程序的菜单合并到容器的菜单中。ActiveX 文档容器自动激活所显示的文档。这不同于常规的 OLE 文档嵌入。传统的嵌入或链接要求最终用户之前合并菜单激活的文档。

"新"的工作表中嵌入在容器中时则将它视为一个 ActiveX 对象。任何最终用户操作不需要 Excel 菜单与容器的菜单合并在一起。

创建 MFC 容器应用程序自动执行 ActiveX 文档

若要生成示例应用程序,可以自动嵌入的 Excel 工作表,请执行以下步骤:
  1. 启动 Microsoft Visual Studio.NET。文件菜单上,指向新建,然后单击项目项目类型下单击Visual C++ 项目,,并选择MFC 应用程序模板。AutomateEmbed为项目命名。对 C:\...root 文件夹中保存该项目。
  2. 在 MFC 应用程序向导,请按照下列步骤:
    1. 单击应用程序类型,然后选择单个文档
    2. 单击复合文档支持,然后选择容器
    3. 检查活动文档容器
    4. 单击完成接受剩余的默认设置。
  3. 从 Excel 对象库添加接口。若要执行此操作,请按照下列步骤操作:
    1. 项目菜单上,单击添加类
    2. 从模板列表中,选择从类型库的 MFC 类,然后单击打开此时将显示从类型库添加类向导。
    3. 在可用的类型库的列表中,找到Microsoft Excelversion对象库,其中version是 9.0 Excel 2000 或 Excel 2002 的 10.0。
    4. 添加下面的接口:_Application
      _Workbook
      _Worksheet
      范围
      工作表
      单击完成。
  4. 解决方案资源管理器的解决方案AutomateEmbed区域中,您将看到的树视图,其中包括以下:

    源代码文件
    头文件
    资源文件
    展开资源文件节点,然后双击AutomateEmbed.RC以将其打开。
  5. 双击要查看的两个菜单的菜单IDR_CNTR_INPLACEIDR_MAINFRAME
  6. 双击 IDR_CNTR_INPLACE。将打开图形 菜单设计器 窗口,显示在 文件 菜单。底部的 文件 菜单是一个空白 CommandBarButton 包含 此处输入 的图例。标题键入AutomateExcel
  7. 用鼠标右键单击新标题为 CommandBarButton 中,然后单击添加事件处理程序运行事件处理程序向导。
       Set this:                  To this:
    ---------------------------------------------------------

    Command Name ID_FILE_AUTOMATEEXCEL
    Message Type Command
    Function Handler Name OnFileAutomateExcel
    Class List CAutomateEmbedView

    处理程序说明的内容为:"调用后,选择菜单项或命令按钮"。
  8. 单击添加并编辑CAutomateEmbedView.cpp 文件的代码中插入主干处理程序。
  9. 解决方案资源管理器中,双击AutomateEmbedView.cpp在代码窗口中打开该文件。
  10. 键入或粘贴以下代码文件的顶部:
    // AutomateEmbedView.cpp : implementation of the CAutomateEmbedView class
    //

    #include "stdafx.h"
    #include "AutomateEmbed.h"

    #include "AutomateEmbedDoc.h"
    #include "CntrItem.h"
    #include "AutomateEmbedView.h"

    #include "CWorkbook.h"
    #include "CWorksheet.h"
    #include "CWorksheets.h"
    #include "CRange.h"

    #ifdef _DEBUG
    #define new DEBUG_NEW
    #endif

    // CAutomateEmbedView
  11. 在 AutomateEmbedView.h 文件中的 CAutomateEmbedView 中加入一个新的公共成员函数:
    HRESULT GetDocIDispatch( LPDISPATCH* ppDisp );
  12. 在 AutomateEmbedView.cpp 文件的底部,替换骨架的消息处理程序的 CAutomateEmbedView::OnFileAutomateExcel 用下面的代码:
    // CAutomateEmbedView message handlers

    void CAutomateEmbedView::OnFileAutomateExcel()
    {
    // Query for the IDispatch pointer for the embedded object.
    // In this case it is Excel worksheet.
    LPDISPATCH lpDisp;
    HRESULT hr = GetDocIDispatch(&lpDisp); // Your own new function.

    // If you got an IDispatch, then use it to Automate Excel
    if(SUCCEEDED(hr))
    {
    CWorkbook oBook;
    CWorksheets oSheets;
    CWorksheet oSheet;
    CRange oRange;

    // Set_Workbook oBook to use lpDisp, the IDispatch* of the
    // embedded/Embedded workbook.
    oBook.AttachDispatch(lpDisp);

    // Then, get the first worksheet in the workbook.
    oSheets = oBook.get_Worksheets();
    oSheet = oSheets.get_Item(COleVariant((long)1));

    // Get the Range object corresponding to Cell A1.
    oRange = oSheet.get_Range(COleVariant(TEXT("A1")), COleVariant(TEXT("A1")));

    // Fill the range with the string "Hello World".
    oRange.put_Value(COleVariant((long)DISP_E_PARAMNOTFOUND, VT_ERROR), COleVariant(TEXT("Hello World")));

    //NOTE: If you are automating Excel 2000 the Range.SetValue requires only one
    // argument. The first parameter in the Excel 2002 syntax in the line above is for the data type,
    // and is optional. It is not permitted by Excel 2000 or earlier versions of Excel.

    } // End if
    } // End of method

    /*****************************************************************************
    * *
    * GetDocIDispatch - This method determines if the document is embedded *
    * or linked, and acquires an IDispatch pointer to the embedded/linked *
    * document's server application for use in Automation. *
    * The document must be activated for this method to succeed. *
    * *
    * Parameters: ppDisp = The address of an LPDISPATCH to be filled with *
    * the IDispatch pointer of the embedded/linked document's server. *
    * *
    * Returns: S_OK if successful, otherwise an HRESULT reporting the error. *
    * *
    *****************************************************************************/
    HRESULT CAutomateEmbedView::GetDocIDispatch(LPDISPATCH* ppDisp)
    {
    //HRESULT hr = S_OK;
    HRESULT hr = E_UNEXPECTED; // If no document then return no ppDisp.
    IOleLink* lpLink = NULL;
    IMoniker* lpMoniker = NULL;
    IRunningObjectTable* lpROT = NULL;
    IUnknown* lpUnk = NULL;

    if(!m_pSelection)
    {
    return hr;
    }

    // First, try to get an IOleLink interface from the document.
    // If successful, this indicates that the document is linked as
    // opposed to embedded.
    hr = m_pSelection->m_lpObject->QueryInterface(IID_IOleLink, (void**)&lpLink);

    if(SUCCEEDED(hr))
    {
    // Get the moniker of the source document for this link.
    // You need this to find the ActiveX Document Server.
    hr = lpLink->GetSourceMoniker(&lpMoniker);

    if(SUCCEEDED(hr))
    {
    // For linked documents, search the Running Object Table
    // for the relevant server. Do this through the
    // IRunningObjectTable interfce, which you can get through
    // an API call.
    hr = GetRunningObjectTable(0,&lpROT);

    if(SUCCEEDED(hr))
    {
    // Search the Running Object Table for the ActiveX
    // Document Server of this document. You'll get back an
    // IUnknown pointer to the server.
    hr = lpROT->GetObject( lpMoniker, &lpUnk );

    if(SUCCEEDED(hr))
    {
    // Finally, get the IDispatch pointer from the
    // IUnknown pointer.
    hr = lpUnk->QueryInterface(IID_IDispatch, (void**)ppDisp);
    }
    }
    }
    }
    else
    {
    // If that fails, try for a direct IDispatch pointer. This
    // indicates that the document is embedded, not linked.
    hr = m_pSelection->m_lpObject->QueryInterface(IID_IDispatch, (void**)ppDisp);
    }
    // Clean up interface pointers you may have acquired along the way.
    if(lpLink)
    lpLink->Release();
    if(lpMoniker)
    lpMoniker->Release();
    if(lpROT)
    lpROT->Release();
    if(lpUnk)
    lpUnk->Release();
    return hr;
    }
  13. 编译并运行该应用程序。如果您收到编译器错误,请参阅"疑难解答"部分。
  14. 容器窗体上单击编辑,然后单击插入对象
  15. 插入新对象列表框中,选择一个新的 Excel 工作表。空容器中显示的 Excel 工作表,Excel 菜单将与容器的菜单合并。
  16. 从容器中的文件菜单上,单击AutomateExcel在单元格 A1 中显示字符串"Hello World"。
  17. 文件菜单上,单击新建以清除工作表。不保存该工作表。
  18. 在新文档中,将插入现有 Excel 工作簿 (由文件创建)。
  19. 文件菜单上,单击AutomateExcel"Hello World"将显示在工作表中的单元格 A1 中。