Microsoft KB Archive/311546

= How to embed and automate an Excel worksheet by using MFC and Visual C++ 2005 or Visual C++ .NET =

Article ID: 311546

Article Last Modified on 1/17/2007

-

APPLIES TO


 * Microsoft Visual C++ 2005 Express Edition
 * Microsoft Visual C++ .NET 2003 Standard Edition
 * Microsoft Visual C++ .NET 2002 Standard Edition
 * Microsoft Excel 2002 Standard Edition
 * Microsoft Excel 2000 Standard Edition

-



This article was previously published under Q311546





For a Microsoft Visual C++ 6.0 version of this article, see 184663.



Note Microsoft Visual C++ 2005, Microsoft Visual C++ .NET 2003, and Microsoft Visual C++ .NET 2002 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.



SUMMARY
This step-by-step article describes how to embed an Excel worksheet in a View object in a single-document interface (SDI) Microsoft Foundation Classes (MFC) application by using Visual C++ 2005 or Visual C++ .NET.

Create an MFC Application that Embeds an Excel Worksheet
The following steps describe how to embed a worksheet and automate the worksheet to add data to a cell.  Start Microsoft Visual Studio .NET. On the File menu, click New, and then click Project. Under Project types click Visual C++ Projects, and then click MFC Application under Templates. Name the project Embed_Excel.

Note In Visual C++ 2005, click Visual C++ instead of Visual C++ Projects. When the MFC Application Wizard appears, follow these steps:  Click Application Type and then select Single Document. Click Compound Document Support and then select Container. Click Finish to accept all other default settings.</ol> </li> Add interfaces from the Excel object library. To do this, follow these steps: <ol style="list-style-type: lower-alpha;"> On the Project menu, click Add Class.</li> Select MFC Class From TypeLib from the list of templates and click Open. The Add Class From TypeLib Wizard appears.

Note In Visual C++ 2005, click Add instead of Open.</li> In the list of available type libraries, locate Microsoft Excel  Object Library. For Excel 2000, the version is 9.0, for Excel 2002, the version is 10.0, and for Microsoft Office Excel 2003, the version is 11.0.</li> Add the following interfaces: <ul> _Application</li> _Workbook</li> _Worksheet</li> Range</li> Workbooks</li> Worksheets</li></ul> </li> Click Finish.</li></ol> </li>  Add the following line to Cntritem.h as a public member function of the CEmbed_ExcelCntrItem class: LPDISPATCH GetIDispatch; </li>  Add the GetIDispatch method to Cntritem.cpp, as follows: /******************************************************************* LPDISPATCH CEmbed_ExcelCntrItem::GetIDispatch {   //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);
 * This method returns the IDispatch* for the application linked to
 * this container.

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(&quot;Warning: Link is not connected!\n&quot;); 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(&quot;Warning: does not support IDispatch!\n&quot;); return NULL; }

//After you verify that it is valid, return the IDispatch //interface to the caller. ASSERT(lpDispatch != NULL); return lpDispatch; } Note In Visual C++ 2005, you must add the common language runtime support compiler option (/clr:oldSyntax) to successfully compile the previous code sample. To add the common language runtime support compiler option, follow these steps: <ol> Click Project, and then click  Properties.

Note  is a placeholder for the name of the project.</li> Expand Configuration Properties, and then click General.</li> <li>In the right pane, click to select Common Language Runtime Support, Old Syntax (/clr:oldSyntax) in the Common Language Runtime support project settings.</li> <li>Click Apply, and then click OK.</li></ol>

For more information about common language runtime support compiler options, visit the following Microsoft Developer Network (MSDN) Web site:

http://msdn2.microsoft.com/en-us/library/k8d11d4s.aspx

These steps apply to the whole article. </li> <li> Add the following line to Embed_excelview.h as a public method of the CEmbed_ExcelView class: void EmbedAutomateExcel; </li> <li> Add the following lines to Embed_excelview.cpp:
 * 1) include &quot;CApplication.h&quot;
 * 2) include &quot;CWorkbook.h&quot;
 * 3) include &quot;CWorksheet.h&quot;
 * 4) include &quot;CRange.h&quot;
 * 5) include &quot;CWorksheets.h&quot;
 * 6) include &quot;CWorkbooks.h&quot;

/******************************************************************** void CEmbed_ExcelView::EmbedAutomateExcel {   //Change the cursor so that the user knows that something exciting is going //on. BeginWaitCursor;
 * This method encapsulates the process of embedding an Excel
 * Worksheet in a View object and automating that worksheet to add
 * some text to cell A1.

CEmbed_ExcelCntrItem* pItem = NULL; TRY {       //Get the document associated with this view, and be sure that it is        //valid. CEmbed_ExcelDoc* pDoc = GetDocument; ASSERT_VALID(pDoc);

//Create a new item associated with this document, and be sure that //it is valid. pItem = new CEmbed_ExcelCntrItem(pDoc); ASSERT_VALID(pItem);

// Get a Class ID for the Excel sheet. // This is used in creation. CLSID clsid; if(FAILED(::CLSIDFromProgID(L&quot;Excel.sheet&quot;,&clsid))) //Any exception will do. You just need to break out of the //TRY statement. AfxThrowMemoryException;

// Create the Excel 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);

// Start 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 Excel worksheet. LPDISPATCH lpDisp; lpDisp = pItem->GetIDispatch;

//Add text in cell A1 of the embedded Excel sheet. CWorkbook wb; CWorksheets wsSet; CWorksheet ws; CRange CRange; CApplication app;

//Set CWorkbook wb to use lpDisp, the IDispatch* of the //actual workbook. wb.AttachDispatch(lpDisp);

//Get the application for the worksheet. app = wb.get_Application;

//Get the first worksheet in the workbook. wsSet = wb.get_Worksheets; ws = wsSet.get_Item(COleVariant((short)1));

//Get a CRange object that corresponds to cell A1. CRange = ws.get_Range(COleVariant(&quot;A1&quot;), COleVariant(&quot;A1&quot;));

//Fill A1 with the string &quot;Hello, World!&quot; CRange.put_Value2(COleVariant(&quot;Hello, World!&quot;));

//NOTE: If you are automating Excel 2002, the CRange.SetValue method has an        //additional optional parameter that specifies the data type. Because the //parameter is optional, existing code will still work correctly, but new //code should use the new convention. The call for Excel2002 should //resemble the following:

//CRange.SetValue( ColeVariant( (long)DISP_E_PARAMNOTFOUND, VT_ERROR ),        //                COleVariant(&quot;Hello, World!&quot;)); }

//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 that the user knows that exciting stuff //is no longer happening. EndWaitCursor; }                   </li> <li> Replace the code for CEmbed_ExcelView::OnInsertObject in Embed_excelview.cpp with the following: void CEmbed_ExcelView::OnInsertObject {   EmbedAutomateExcel; } NOTE: EmbedAutomateExcel is merely a special case of OnInsertObject, which allows the user to select from a list of available OLE objects to insert into the application. You will override this behavior because it is not needed for this demonstration. </li></ol>

Test the Application

 * 1) Press F5 to build and run the application.
 * 2) On the Edit menu of the application, click Insert New Object.
 * 3) Examine the results. A new Excel worksheet is embedded into the View object, with the text &quot;Hello, World!&quot; in cell A1.

Troubleshooting
<ul> <li>If you add class wrappers for the Excel object library by using the File option in the Add Class From TypeLib Wizard, you may receive an error message when you browse to the object library. To avoid this problem, type the full path and file name for the object library instead of browsing to the file.For additional information, click the article number below to view the article in the Microsoft Knowledge Base:

311408 BUG: 'Read-Only' Warning When Adding MFC Class From Library

</li> <li>If you receive the following error message when you build your sample application, change &quot;Variant DialogBox&quot; in CRange.h to &quot;Variant _DialogBox&quot;:

warning C4003: not enough actual parameters for macro 'DialogBoxA'

For more information on the cause of this error, see the following Knowledge Base article:

311407 BUG: MFC Wizard Doesn't Resolve Naming Conflicts with API Macros

</li></ul>

<div class="references_section">