Microsoft KB Archive/243240

= PRB: MFC ActiveX Control Fails to Insert into PowerPoint 2000 =

Article ID: 243240

Article Last Modified on 12/12/2003

-

APPLIES TO


 * Microsoft PowerPoint 2000 Standard Edition
 * Microsoft Foundation Class Library 4.2
 * Microsoft Visual C++ 6.0 Professional Edition

-



This article was previously published under Q243240



SYMPTOMS
When trying to insert an MFC ActiveX Control into Microsoft PowerPoint 2000 by selecting Object from the Insert menu, you get the following error message:

PowerPoint found an error that it cannot correct, you should save presentations, quit, and then restart PowerPoint.



CAUSE
MFC tries to QueryInterface for IOleControlSite in its implementation of IOleObject::SetClientSite. However, Microsoft PowerPoint does not expect this situation for OLE objects inserted through Insert|Object, and reports the error.



RESOLUTION
Change your implementation to avoid calling QueryInterface for IOleControlSite until after IOleObject::SetClientSite is called.



MORE INFORMATION
The following steps describe how to override MFC's implementation of IOleObject for an MFC ActiveX Control, and move the QueryInterface for IOleControlSite from SetClientSite to SetHostNames. An added benefit of overriding SetHostNames is that your control can easily get the name of the container and containing document where it was inserted.  Open an existing MFC ActiveX Control you may have with Insert|Object support, or create a new one for this example. Follow steps 3, 5, and 7 in the following Microsoft Knowledge Base article, replacing "COffCtlDispCtrl" with the name of your COleControl class instead. This allows you to override IOleObject:

190985 HOWTO: Get IDispatch of an Excel or Word Document from an OCX

  Replace the implementation for SetClientSite with the following code: // Change 'CMfcAxCtrlCtrl' in the next line to be the name of // your COleControl class... METHOD_MANAGE_STATE(CMfcAxCtrlCtrl, MyOleObject) ASSERT_VALID(pThis);

// maintain reference counts if (pClientSite != NULL) pClientSite->AddRef; if(pThis->m_pClientSite) { pThis->m_pClientSite->Release; pThis->m_pClientSite = NULL; }  pThis->m_pClientSite = pClientSite;

// Release existing pointer to ambient property dispinterface. pThis->m_ambientDispDriver.ReleaseDispatch;

if (pClientSite != NULL) {     BOOL bValue; pThis->m_bAutoClip = pThis->GetAmbientProperty(        DISPID_AMBIENT_AUTOCLIP, VT_BOOL, &bValue) ? bValue : 0; pThis->m_bMsgReflect = pThis->GetAmbientProperty(        DISPID_AMBIENT_MESSAGEREFLECT, VT_BOOL, &bValue) ? bValue : 0; pThis->m_bUIDead = (BYTE)(pThis->AmbientUIDead); }

// Release existing pointer to in-place site, if any. if(pThis->m_pInPlaceSite) { pThis->m_pInPlaceSite->Release; pThis->m_pInPlaceSite = NULL; }

LPVOID pInterface; if(pThis->m_pControlSite) { pThis->m_pControlSite->Release; }  pThis->m_pControlSite = NULL;

// Initialize pointer to simple frame site if (pClientSite == NULL || !pThis->m_bSimpleFrame ||     FAILED(pClientSite->QueryInterface(IID_ISimpleFrameSite,      &pInterface))) {     pInterface = NULL; }

if(pThis->m_pSimpleFrameSite) { pThis->m_pSimpleFrameSite->Release; pThis->m_pSimpleFrameSite = NULL; }  pThis->m_pSimpleFrameSite = (LPSIMPLEFRAMESITE) pInterface;

// Let the control run its own code here. pThis->OnSetClientSite;

// Unless IPersist*::Load or IPersist*::InitNew is called after this, // we can't count on ambient properties being available while loading. pThis->m_bCountOnAmbients = FALSE;

return S_OK;   Replace the implementation for SetHostNames with the following: // Change 'CMfcAxCtrlCtrl' in the next line to be the name of // your COleControl class... METHOD_MANAGE_STATE(CMfcAxCtrlCtrl, MyOleObject) ASSERT_VALID(pThis);

// Convert OLESTR into ASCII string. char app[1024], obj[1024]; WideCharToMultiByte(CP_ACP, 0, pwApp, -1, app, 1024, NULL, NULL); WideCharToMultiByte(CP_ACP, 0, pwObj, -1, obj, 1024, NULL, NULL); char buf[1024]; sprintf(buf, "SetHostNames(\"%s\", \"%s\") called", app, obj); ::MessageBox(NULL, buf, "MyControl", MB_SETFOREGROUND);

// Get IOleControlSite if (pThis->m_pClientSite && !pThis->m_pControlSite) { pThis->m_pClientSite->QueryInterface(IID_IOleControlSite,     (void**)&pThis->m_pControlSite); }  return S_OK; After moving the code that calls QueryInterface for IOleControlSite from SetClientSite to SetHostNames, your control should insert into Microsoft PowerPoint without any errors. The example code above also demonstrates how you can discern the application and document name into which your control has been inserted using the arguments passed into SetHostNames. 

Keywords: kbctrlcreate kbprb KB243240

-

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

© Microsoft Corporation. All rights reserved.