KnowledgeBase Archive

An Archive of Early Microsoft KnowledgeBase Articles

View on GitHub

Q138414: PRB: FromIDispatch Returns NULL for OLE Control

Article: Q138414
Product(s): Microsoft C Compiler
Version(s): 2.00 2.10 | 1.50 1.51 1.52 1.52
Operating System(s): 
Keyword(s): kbprb
Last Modified: 30-JUL-2001

-------------------------------------------------------------------------------
The information in this article applies to:

- The Microsoft Foundation Classes (MFC), included with:
   - Microsoft Visual C++, 32-bit Editions, versions 2.0, 4.1 
   - Microsoft Visual C++ for Windows, 16-bit edition, versions 1.5, 1.51, 1.52, 1.52a 
-------------------------------------------------------------------------------

SYMPTOMS
========

Calling CCmdTarget::FromIDispatch() inside a member function of a class derived
from COleControl or attempting to call FromIDispatch() passing an IDispatch
pointer belonging to an OLE Control, will always return NULL.

CAUSE
=====

CCmdTarget::FromIDispatch() does the following test to determine if the passed
IDispatch pointer belongs to a CCmdTarget-derived class or not:

      COleDispatchImpl dispatch;

      ASSERT(*(DWORD*)&dispatch != 0);    // null vtable ptr?
      if (*(DWORD*)lpDispatch != *(DWORD*)&dispatch)
          return NULL;    // not our Idispatch*

The problem here is that classes derived from COleControl don't use the
COleDispatchImpl implementation of IDispatch directly. They have their own
implementation using BEGIN_INTERFACE_PART and END_INTERFACE_PART that delegates
to the COleDispatchImpl object in the CCmdTarget base class. Because of this,
the v-tables in the previous test won't match and the function will return NULL.

RESOLUTION
==========

It is possible to access the object of the class derived from COleControl given
a valid IDispatch pointer. The object can be accessed from another control or
outside of a control with the aid of a helper control. A helper control would be
necessary because the following formula relies on details that are internal to a
COleControl class.

To access the object of the class derived from COleControl successfully, you need
to use a formula similar to this one: "

     COleControl * pCtrl = (COleControl*)
         ((BYTE*)lpDisp - m_xDispatch.m_nOffset);

" (without the quotation marks) In this formula, lpDisp is a valid LPDISPATCH,
m_xDispatch is the XDispatch object member of COleControl that contains the
control's implementation of IDispatch, and m_nOffset is the offset generated by
the INIT_INTERFACE_PART macro for IDispatch.

m_xDispatch is generated by the END_INTERFACE_PART macro as follows:

     #define END_INTERFACE_PART(localClass) \ 
        } m_x##localClass; \ 
        friend class X##localClass; \ 

In this case, localClass is "Dispatch" so m_x##localClass becomes m_xDispatch.

m_nOffset is generated by the INIT_INTERFACE_PART macro as follows:

      #ifndef _AFX_NO_NESTED_DERIVATION
      #define INIT_INTERFACE_PART(theClass, localClass) \ 
            size_t m_nOffset; \ 
               INIT_INTERFACE_PART_DERIVE(theClass,localClass) \ 

      #define INIT_INTERFACE_PART_DERIVE(theClass, localClass) \ 
            X##localClass() \ 
          { m_nOffset = offsetof(theClass, m_x##localClass); } \ 
  m_nOffset becomes offsetof(COleControl, m_xDispatch).

STATUS
======

This behavior is by design.

MORE INFORMATION
================

This difference between CCmdTarget and COleControl's implementation of IDispatch
disappears in Visual C++ version 4.0. COleControl uses COleDispatchImpl in
version 4.0 and therefore, FromIDispatch() will work.

Additional query words: 2.00 2.10 1.50 1.51 1.52 1.52a

======================================================================
Keywords          : kbprb 
Technology        : kbAudDeveloper kbMFC
Version           : 2.00 2.10 | 1.50 1.51 1.52 1.52
Issue type        : kbprb

=============================================================================

THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY.

Copyright Microsoft Corporation 1986-2002.