PRB: Range::GetApplication Method Returns an Incorrect Interface Pointer (278949)



The information in this article applies to:

  • Microsoft Excel 2000 Service Release 1 (SR-1)
  • Microsoft Excel 2000
  • Microsoft Excel 97 for Windows

This article was previously published under Q278949

SYMPTOMS

When a developer uses the #import functionality of Microsoft Visual C++ to generate smart pointers for Excel and then uses those smart pointers to access the pointer returned by the Range::GetApplication property, an access violation occurs.

This problem does not occur in Microsoft Visual Basic applications, but can be observed in Component Object Model (COM) code that does not use #import.

CAUSE

The type library for Excel indicates that the CoClass "Application" is returned by the Range::GetApplication method. COM methods return only interface pointers, not CoClass pointers. Because of this, Microsoft Visual C++ concludes that the interface pointer returned must be for the default interface of the Application CoClass, _Application.

The _Application interface is dual, meaning that it can be called either through the IDispatch interface, or directly through the vtable. However, the interface returned from Range::GetApplication does not support vtable binding. When the wrappers generated by #import attempt to make a vtable call, an access violation results.

This problem is not seen elsewhere in Excel.

RESOLUTION

To work around the problem, call IUnknown::QueryInterface() on the interface pointer returned from Range::GetApplication() before using it. The following code demonstrates the workaround:
_ApplicationPtr appPtr2;
IUnknown* pUnk = NULL;
HRESULT hr = xlRange->GetApplication()->QueryInterface( __uuidof(_Application), (void**)&pUnk );
if (SUCCEEDED(hr)){
   appPtr2 = pUnk;
   appPtr2->PutVisible(0, TRUE );
}
				

MORE INFORMATION

Steps to Reproduce Behavior

  1. Create a new Microsoft Foundation Classes (MFC) AppWizard(exe) project. Name it ExcelDemo and make it a dialog-based application.
  2. In the project Wizard, the project displays the dialog box when you click Finish. Double-click the default OK CommandButton to edit the click handler for the button. Replace the default code with the following:
       using namespace Excel;
       _ApplicationPtr appPtr1;
       _ApplicationPtr appPtr2;
       WorkbooksPtr xlBooks;
       _WorkbookPtr xlBook;
       _WorksheetPtr xlSheet;
       RangePtr xlRange;
       if(!AfxOleInit())
         {
          AfxMessageBox("Failed to initialize COM");
          return;
         }
       appPtr1.CreateInstance( "Excel.Application" );
       xlBooks = appPtr1->GetWorkbooks();
       xlBook = xlBooks->Add();
       xlSheet = xlBook->GetActiveSheet();
    
       xlRange = xlSheet->GetRange( COleVariant("A1") );
    
       //This fails
       {
          appPtr2 = xlRange->GetApplication();
          appPtr2->PutVisible( 0, TRUE );
       }
    /*
       //This works
       {
          IUnknown* pUnk = NULL;
          xlRange->GetApplication()->QueryInterface( __uuidof(_Application), 
             (void**)&pUnk );
          appPtr2 = pUnk;
          appPtr2->PutVisible(0, TRUE );
       }
    */ 
    					
  3. Add the following code immediately above the click handler code of the CommandButton:
    /*
    // Use #import to generate smart pointers for Excel97...
    #import "C:\PROGRAM FILES\MICROSOFT OFFICE\OFFICE\MSO97.DLL" no_namespace \ 
       rename("DocumentProperties", "OfficeDocumentProperties")
    
    #import "C:\PROGRAM FILES\COMMON FILES\MICROSOFT SHARED\VBA\VBEEXT1.OLB" \ 
       no_namespace
    
    #import "C:\PROGRAM FILES\MICROSOFT OFFICE\OFFICE\Excel8.Olb" no_dual_interfaces \ 
       rename("DialogBox", "ExcelDialogBox") rename("RGB", "ExcelRGB") \ 
       rename("DocumentProperties", "ExcelDocumentProperties") \ 
       rename("ExitWindows", "ExcelExitWindows")
    */ 
    
    // Use #import to generate smart pointers for Excel2000...
    #import "C:\PROGRAM FILES\Microsoft Office\OFFICE\MSO9.DLL" no_namespace \ 
       rename("DocumentProperties", "OfficeDocumentProperties")
    
    #import "C:\PROGRAM FILES\COMMON FILES\MICROSOFT SHARED\VBA\VBA6\VBE6EXT.OLB" \ 
       no_namespace
    
    #import "C:\PROGRAM FILES\Microsoft Office\OFFICE\excel9.Olb" \ 
       rename("DialogBox", "ExcelDialogBox") rename("RGB", "ExcelRGB") \ 
       rename("DocumentProperties", "ExcelDocumentProperties") \ 
       rename("ExitWindows", "ExcelExitWindows")
    					
    NOTE: If you installed Microsoft Office to a custom location, you may need to modify the paths above to conform to your installation.

  4. Compile and run the application, click the CommandButton, and note that the application crashes with an access violation. You need to find Excel.exe in the process list of Microsoft Windows NT and end it manually.
  5. Comment out the block of code marked "This fails," and uncomment the block marked "This works."
  6. Recompile and run the code, and note that the application succeeds and no access violation occurs.

Modification Type:MajorLast Reviewed:12/12/2003
Keywords:kbAutomation kbprb kbProgramming KB278949