This article was previously published under Q316587
Note Microsoft Visual C++ .NET, Microsoft Visual C++ .NET 2003, Microsoft Visual C++ 2005, and Microsoft Visual C++ 2008 support both the managed code model that is provided by the Microsoft .NET Framework and the unmanaged native Microsoft Windows code model. The information in this article applies only to unmanaged Visual C++ code.
Use this step-by-step guide to automate an embedded
Microsoft Office documents. The procedure that follows uses a VC++ MFC
container as an ActiveX Document Container for an activated Excel worksheet.
The code includes sample methods for acquiring an IDispatch interface pointer
to the document's server and demonstrates how to automate an embedded Excel
Use Office Applications as ActiveX Document Servers
An ActiveX document container can contain a number of Office
documents, but only one document can be displayed at a time. When the Office
document is activated, the menu for the Office document's server application
merges into the container's menu. An ActiveX document container automatically
activates the document being displayed. This varies from conventional OLE
document embedding. Conventional embedding or linking requires the end-user to
activate the document before the menus are merged.
When a "new"
worksheet is embedded in the container it is treated as an ActiveX object. No
end-user action is required to merge the Excel menu with the container's
Create an MFC Container Application that Automates an ActiveX Document
To generate the sample application that automates an embedded
Excel worksheet, follow these steps:
Start Microsoft Visual Studio .NET. On the File menu, point to New, and then click Project. Under Project types, click Visual C++ Projects, and select the MFC Application template. Name the project AutomateEmbed. Save the project to your C:\...root folder.
In the MFC Application Wizard, follow these steps:
Click Application Type and then select Single Document.
Click Compound Document Support and then select Container.
Check Active document container.
Click Finish to accept the remaining default settings.
Add interfaces from the Excel object library. To do this,
follow these steps:
On the Project menu, click Add Class.
From the list of templates, select MFC Class
From TypeLib, and then click Open. The Add Class From Typelib Wizard appears.
In the list of available type libraries, locate
Microsoft Excel version Object
Library, where version is 9.0 for Excel
2000 or 10.0 for Excel 2002.
Add the following interfaces:
In the Solution AutomateEmbed area in Solution Explorer, you will see a tree view that includes the following:
Expand the Resource Files node, and double-click AutomateEmbed.RC to open it.
Double-click Menu to see two menus: IDR_CNTR_INPLACE and IDR_MAINFRAME.
Double-click IDR_CNTR_INPLACE. A graphic Menu Designer window opens, showing the File menu. Near the bottom of the File menu is a blank CommandBarButton that contains the legend Type Here. Type AutomateExcel as the
Right-click the newly-captioned CommandBarButton, and then
click Add Event Handler to run the Event Handler Wizard. In the
wizard, set the following values:
Set this: To this:
Command Name ID_FILE_AUTOMATEEXCEL
Message Type Command
Function Handler Name OnFileAutomateExcel
Class List CAutomateEmbedView
The Handler description will say "Called after menu item or command button has been
Click Add and Edit to insert the skeleton handler into the code for the
In Solution Explorer, double-click the AutomateEmbedView.cpp to open the file in the code window.
Type or paste the following code at the top of the file:
// AutomateEmbedView.cpp : implementation of the CAutomateEmbedView class
#define new DEBUG_NEW
Add a new public member function to CAutomateEmbedView in
the AutomateEmbedView.h file:
HRESULT GetDocIDispatch( LPDISPATCH* ppDisp );
At the bottom of the AutomateEmbedView.cpp file, replace
the skeleton message handler for CAutomateEmbedView::OnFileAutomateExcel with
the following code:
// CAutomateEmbedView message handlers
// Query for the IDispatch pointer for the embedded object.
// In this case it is Excel worksheet.
HRESULT hr = GetDocIDispatch(&lpDisp); // Your own new function.
// If you got an IDispatch, then use it to Automate Excel
// Set_Workbook oBook to use lpDisp, the IDispatch* of the
// embedded/Embedded workbook.
// 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;
// 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);
// Get the moniker of the source document for this link.
// You need this to find the ActiveX Document Server.
hr = lpLink->GetSourceMoniker(&lpMoniker);
// 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);
// 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 );
// Finally, get the IDispatch pointer from the
// IUnknown pointer.
hr = lpUnk->QueryInterface(IID_IDispatch, (void**)ppDisp);
// 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.
Compile and run the application. If you receive compiler errors, see the "Troubleshooting" section.
On the Container form click Edit and then click Insert Object.
In the Insert New Object list box, select a new Excel Worksheet. The empty Excel Worksheet
appears in the container and the Excel menu merges with the menu of the
From the container's File menu, click AutomateExcel. The string "Hello World" appears in cell A1.
On the File menu, click New to clear the worksheet. Do not save the worksheet.
In the new document, insert an existing Excel Workbook (Create from File).
On the File menu, click AutomateExcel. "Hello World" appears in cell A1 of the
If you add class wrappers for the Excel object library by
using the File option in the Add Class From TypeLib Wizard, and browse the
object library, you may receive an error message. To avoid this problem, type
the full path and file name for the object library instead of browsing for the
For more information, click the following article number to view the article in the Microsoft Knowledge Base:
BUG: MFC class wizard does not resolve naming conflicts between Windows APIs and COM interface methods
If you receive a compiler error in Excel.tlh when you build by using Visual C++ 2005 or Visual C++ 2008:
Run "Find in Files" (CTRL+SHIFT+F), and then search for "#import." Comment or delete every line where the EXCEL.EXE import library has been imported by using #import. There will be approximately five instances in the five header files that are created by the type library import wizard.
Open the Stdafx.h source file. After each #include statement, add the following import statements together with the auto_rename modifier to import the Excel type library and its dependencies.