Microsoft KB Archive/138414

= PRB: FromIDispatch Returns NULL for OLE Control =

Article ID: 138414

Article Last Modified on 11/21/2006

-

APPLIES TO

 Microsoft Foundation Class Library 4.2, when used with:  Microsoft Visual C++ 2.0 Professional Edition

 Microsoft Visual C++ 4.1 Subscription

 Microsoft Visual C++ 1.5 Professional Edition

 Microsoft Visual C++ 1.51</li></ul>

 Microsoft Visual C++ 1.52 Professional Edition</li></ul> </li></ul>

-

<div class="notice_section">

This article was previously published under Q138414

<div class="symptoms_section">

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.

<div class="cause_section">

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.

<div class="resolution_section">

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); 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).

<div class="status_section">

STATUS
This behavior is by design.

<div class="moreinformation_section">

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 KB138414

-

[mailto:TECHNET@MICROSOFT.COM Send feedback to Microsoft]

© Microsoft Corporation. All rights reserved.