How to embed and automate a Word document with MFC

Summary

Documents that are embedded in other application documents, using OLE embedding, can be modified by automation without double-clicking the embedded document to activate it in "edit" or "open"' mode.

This article demonstrates how to embed and automate a Microsoft Office Word document in an MFC Single Document Interface application. The same approach works with any version of Word. The distinction is not which version of Word created the document, but rather, which version of Word you use in the automation process.

The Word type libraries are as follows:
  • For Microsoft Office Word 2007, the type library is Msword.olb and is located in the "C:\Program Files\Microsoft Office\Office12" folder.
  • For Microsoft Office Word 2003, the type library is Msword.olb and is located in the "C:\Program Files\Microsoft Office\Office11" folder.
  • For Microsoft Word 2002, the type library is Msword.olb and is located in the "C:\Program Files\Microsoft Office\Office10" folder.
  • For Microsoft Word 2000, the type library is Msword9.olb and is located in the "C:\Program Files\Microsoft Office\Office" folder.
  • For Microsoft Word 97, the type library is Msword8.olb and is located in the "C:\Program Files\Microsoft Office\Office" folder.

More Information

Create a Sample Project

  1. Using Microsoft Visual Studio, start a new MFC AppWizard (exe) project named EmbedWord. In AppWizard, choose "Single Document" as the application type in step 1 and choose "Container" as the type of compound document support in step 3. You can accept all other defaults.
  2. Press the CTRL+W key combination to invoke the Class Wizard. Select the Automation tab. Click the Add Class button and choose From a Type Library. Browse to locate the Word type library.
  3. In the Confirm Classes dialog box, select all of the members listed, and click OK.
  4. Click OK again to close ClassWizard.
  5. Modify EmbedWordView.cpp so that it includes the header file ClassWizard generated from the Word type library.

    For Word 2002 or for a later version of Word.
    #include "msword.h"
    For Word 97 or for Word 2000.
    #include "msword9.h"
  6. Replace the code in CEmbedWordView::OnInsertObject() with the following:
    void CEmbedWordView::OnInsertObject()
    {
    EmbedAutomateWord();
    }
  7. Add a CEmbedWordView::EmbedAutomateWord() member function to EmbedWordView.cpp:
    void CEmbedWordView::EmbedAutomateWord()
    {

    /*******************************************************************
    This method encapsulates the process of embedding a Word document
    in a View object and automating that document to add text.
    *******************************************************************/

    //Change the cursor so the user knows something exciting is going
    //on.
    BeginWaitCursor();

    CEmbedWordCntrItem* pItem = NULL;
    TRY
    {
    //Get the document associated with this view, and be sure it's
    //valid.
    CEmbedWordDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);

    //Create a new item associated with this document, and be sure
    //it's valid.
    pItem = new CEmbedWordCntrItem(pDoc);
    ASSERT_VALID(pItem);

    // Get Class ID for Word document.
    // This is used in creation.

    CLSID clsid;
    if(FAILED(::CLSIDFromProgID(L"Word.Document",&clsid)))
    //Any exception will do. You just need to break out of the
    //TRY statement.
    AfxThrowMemoryException();

    // Create the Word embedded item.
    if(!pItem->CreateNewItem(clsid))
    //Any exception will do. You just need to break out of the
    //TRY statement.
    AfxThrowMemoryException();

    //Make sure the new CContainerItem is valid.
    ASSERT_VALID(pItem);

    // Launch the server to edit the item.
    pItem->DoVerb(OLEIVERB_SHOW, this);

    // As an arbitrary user interface design, this sets the
    // selection to the last item inserted.
    m_pSelection = pItem; // set selection to last inserted item
    pDoc->UpdateAllViews(NULL);

    //Query for the dispatch pointer for the embedded object. In
    //this case, this is the Word document.
    LPDISPATCH lpDisp;
    lpDisp = pItem->GetIDispatch();

    //Add text to the first line of the document
    _Document doc;
    Selection selection;
    _Application app;
    PageSetup pagesetup;

    _Font font;

    //set _Document doc to use lpDisp, the IDispatch* of the
    //actual document.
    doc.AttachDispatch(lpDisp);

    //Then get the document's application object reference.
    app = doc.GetApplication();

    // From there, get a Selection object for the insertion point.
    selection = app.GetSelection();
    selection.SetText(
    "This is a good place to say \"Hello World\"");

    // Automate setting the values for various properties.
    font = selection.GetFont();
    font.SetName("Tahoma");
    font.SetSize(16);
    selection.SetFont(font);
    }

    //Here, you need to do clean up if something went wrong.
    CATCH(CException, e)
    {
    if (pItem != NULL)
    {
    ASSERT_VALID(pItem);
    pItem->Delete();
    }
    AfxMessageBox(IDP_FAILED_TO_CREATE);
    }
    END_CATCH

    //Set the cursor back to normal so the user knows exciting stuff
    //is no longer happening.
    EndWaitCursor();
    }
  8. Open EmbedWordView.h and add the declaration of this new method to the "implementation" region:
       void EmbedAutomateWord();
  9. Open CntrItem.cpp and add a new CEmbedWordCntrItem::GetIDispatch member function:
    LPDISPATCH CEmbedWordCntrItem::GetIDispatch()
    {

    /****************************************************************
    This method returns the IDispatch* for the application linked to
    this container.
    *****************************************************************/

    //The this and m_lpObject pointers must be valid for this function
    //to work correctly. The m_lpObject is the IUnknown pointer to
    // this object.
    ASSERT_VALID(this);
    ASSERT(m_lpObject != NULL);


    LPUNKNOWN lpUnk = m_lpObject;

    //The embedded application must be running in order for the rest
    //of the function to work.
    Run();

    //QI for the IOleLink interface of m_lpObject.
    LPOLELINK lpOleLink = NULL;
    if (m_lpObject->QueryInterface(IID_IOleLink,
    (LPVOID FAR*)&lpOleLink) == NOERROR)
    {
    ASSERT(lpOleLink != NULL);
    lpUnk = NULL;

    //Retrieve the IUnknown interface to the linked application.
    if (lpOleLink->GetBoundSource(&lpUnk) != NOERROR)
    {
    TRACE0("Warning: Link is not connected!\n");
    lpOleLink->Release();
    return NULL;
    }
    ASSERT(lpUnk != NULL);
    }

    //QI for the IDispatch interface of the linked application.
    LPDISPATCH lpDispatch = NULL;
    if (lpUnk->QueryInterface(IID_IDispatch, (LPVOID FAR*)&lpDispatch)
    !=NOERROR)
    {

    TRACE0("Warning: does not support IDispatch!\n");
    return NULL;
    }

    //After assuring yourself that it is valid, return the IDispatch

    //interface to the caller.
    ASSERT(lpDispatch != NULL);
    return lpDispatch;
    }
  10. Open CntrItem.h and add the following declaration to the "implementation" region:
    LPDISPATCH GetIDispatch();
  11. In CntrItem.cpp, change the last line of code in CEmbedWordCntrItem::OnGetItemPosition from:
    rPosition.SetRect(10, 10, 210, 210);
    to:
    rPosition.SetRect(20, 20, 630, 420);
  12. Press the F7 key to build EmbedWord.exe. Then press the CTRL+F5 key combination to run the application. When the frame Untitled - EmbedWord appears, click Insert New Object on the Edit menu. The new embedded Word document appears, and the Word menu and Command button bar are merged with the menu of the EmbedWord application.

    Your code embedded the new document, added text to it, and set the typeface and font size.

References

For more information about automating an embedded Office document, click the following article number to view the article in the Microsoft Knowledge Base:

184663 How to embed and automate a Microsoft Excel worksheet with MFC

Propriétés

ID d'article : 238611 - Dernière mise à jour : 23 mars 2009 - Révision : 1

Commentaires