/************************************************************************* ** ** OLE 2 Server Sample Code ** ** svrpsobj.c ** ** This file contains all PseudoObj methods and related support ** functions. ** ** (c) Copyright Microsoft Corp. 1992 - 1993 All Rights Reserved ** *************************************************************************/ #include "outline.h" OLEDBGDATA extern LPOUTLINEAPP g_lpApp; extern IUnknownVtbl g_PseudoObj_UnknownVtbl; extern IOleObjectVtbl g_PseudoObj_OleObjectVtbl; extern IDataObjectVtbl g_PseudoObj_DataObjectVtbl; /* PseudoObj_Init ** -------------- ** Initialize fields in a newly constructed PseudoObj. ** NOTE: ref cnt of PseudoObj initialized to 0 */ void PseudoObj_Init( LPPSEUDOOBJ lpPseudoObj, LPSERVERNAME lpServerName, LPSERVERDOC lpServerDoc ) { OleDbgOut2("++PseudoObj Created\r\n"); lpPseudoObj->m_cRef = 0; lpPseudoObj->m_lpName = lpServerName; lpPseudoObj->m_lpDoc = lpServerDoc; lpPseudoObj->m_lpOleAdviseHldr = NULL; lpPseudoObj->m_lpDataAdviseHldr = NULL; lpPseudoObj->m_fObjIsClosing = FALSE; INIT_INTERFACEIMPL( &lpPseudoObj->m_Unknown, &g_PseudoObj_UnknownVtbl, lpPseudoObj ); INIT_INTERFACEIMPL( &lpPseudoObj->m_OleObject, &g_PseudoObj_OleObjectVtbl, lpPseudoObj ); INIT_INTERFACEIMPL( &lpPseudoObj->m_DataObject, &g_PseudoObj_DataObjectVtbl, lpPseudoObj ); /* OLE2NOTE: Increment the refcnt of the Doc on behalf of the ** PseudoObj. the Document should not shut down unless all ** pseudo objects are closed. when a pseudo object is destroyed, ** it calls ServerDoc_PseudoObjUnlockDoc to release this hold on ** the document. */ ServerDoc_PseudoObjLockDoc(lpServerDoc); } /* PseudoObj_AddRef ** ---------------- ** ** increment the ref count of the PseudoObj object. ** ** Returns the new ref count on the object */ ULONG PseudoObj_AddRef(LPPSEUDOOBJ lpPseudoObj) { ++lpPseudoObj->m_cRef; #if defined( _DEBUG ) OleDbgOutRefCnt4( "PseudoObj_AddRef: cRef++\r\n", lpPseudoObj, lpPseudoObj->m_cRef ); #endif return lpPseudoObj->m_cRef; } /* PseudoObj_Release ** ----------------- ** ** decrement the ref count of the PseudoObj object. ** if the ref count goes to 0, then the PseudoObj is destroyed. ** ** Returns the remaining ref count on the object */ ULONG PseudoObj_Release(LPPSEUDOOBJ lpPseudoObj) { ULONG cRef; /********************************************************************* ** OLE2NOTE: when the obj refcnt == 0, then destroy the object. ** ** otherwise the object is still in use. ** *********************************************************************/ cRef = --lpPseudoObj->m_cRef; #if defined( _DEBUG ) OleDbgAssertSz(lpPseudoObj->m_cRef >= 0,"Release called with cRef == 0"); OleDbgOutRefCnt4( "PseudoObj_Release: cRef--\r\n", lpPseudoObj,cRef); #endif if (cRef == 0) PseudoObj_Destroy(lpPseudoObj); return cRef; } /* PseudoObj_QueryInterface ** ------------------------ ** ** Retrieve a pointer to an interface on the PseudoObj object. ** ** Returns S_OK if interface is successfully retrieved. ** E_NOINTERFACE if the interface is not supported */ HRESULT PseudoObj_QueryInterface( LPPSEUDOOBJ lpPseudoObj, REFIID riid, LPVOID FAR* lplpvObj ) { SCODE sc = E_NOINTERFACE; /* OLE2NOTE: we must make sure to set all out ptr parameters to NULL. */ *lplpvObj = NULL; if (IsEqualIID(riid, &IID_IUnknown)) { OleDbgOut4("PseudoObj_QueryInterface: IUnknown* RETURNED\r\n"); *lplpvObj = (LPVOID) &lpPseudoObj->m_Unknown; PseudoObj_AddRef(lpPseudoObj); sc = S_OK; } else if (IsEqualIID(riid, &IID_IOleObject)) { OleDbgOut4("PseudoObj_QueryInterface: IOleObject* RETURNED\r\n"); *lplpvObj = (LPVOID) &lpPseudoObj->m_OleObject; PseudoObj_AddRef(lpPseudoObj); sc = S_OK; } else if (IsEqualIID(riid, &IID_IDataObject)) { OleDbgOut4("PseudoObj_QueryInterface: IDataObject* RETURNED\r\n"); *lplpvObj = (LPVOID) &lpPseudoObj->m_DataObject; PseudoObj_AddRef(lpPseudoObj); sc = S_OK; } OleDbgQueryInterfaceMethod(*lplpvObj); return ResultFromScode(sc); } /* PseudoObj_Close * --------------- * * Close the pseudo object. Force all external connections to close * down. This causes link clients to release this PseudoObj. when * the refcount actually reaches 0, then the PseudoObj will be * destroyed. * * Returns: * FALSE -- user canceled the closing of the doc. * TRUE -- the doc was successfully closed */ BOOL PseudoObj_Close(LPPSEUDOOBJ lpPseudoObj) { LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpPseudoObj->m_lpDoc; LPSERVERNAME lpServerName = (LPSERVERNAME)lpPseudoObj->m_lpName; LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp; LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc; BOOL fStatus = TRUE; if (lpPseudoObj->m_fObjIsClosing) return TRUE; // Closing is already in progress lpPseudoObj->m_fObjIsClosing = TRUE; // guard against recursive call OLEDBG_BEGIN3("PseudoObj_Close\r\n") /* OLE2NOTE: in order to have a stable App, Doc, AND pseudo object ** during the process of closing, we intially AddRef the App, ** Doc, and PseudoObj ref counts and later Release them. These ** initial AddRefs are artificial; they are simply done to ** guarantee that these objects do not get destroyed until the ** end of this routine. */ OleApp_AddRef(lpOleApp); OleDoc_AddRef(lpOleDoc); PseudoObj_AddRef(lpPseudoObj); if (lpPseudoObj->m_lpDataAdviseHldr) { /* OLE2NOTE: send last OnDataChange notification to clients ** that have registered for data notifications when object ** stops running (ADVF_DATAONSTOP) */ PseudoObj_SendAdvise( lpPseudoObj, OLE_ONDATACHANGE, NULL, /* lpmkObj -- not relevant here */ ADVF_DATAONSTOP ); /* OLE2NOTE: we just sent the last data notification that we ** need to send; release our DataAdviseHolder. we SHOULD be ** the only one using it. */ OleStdVerifyRelease( (LPUNKNOWN)lpPseudoObj->m_lpDataAdviseHldr, "DataAdviseHldr not released properly" ); lpPseudoObj->m_lpDataAdviseHldr = NULL; } if (lpPseudoObj->m_lpOleAdviseHldr) { // OLE2NOTE: inform all of our linking clients that we are closing. PseudoObj_SendAdvise( lpPseudoObj, OLE_ONCLOSE, NULL, /* lpmkObj -- not relevant here */ 0 /* advf -- not relevant here */ ); /* OLE2NOTE: OnClose is the last notification that we need to ** send; release our OleAdviseHolder. we SHOULD be the only ** one using it. this will make our destructor realize that ** OnClose notification has already been sent. */ OleStdVerifyRelease( (LPUNKNOWN)lpPseudoObj->m_lpOleAdviseHldr, "OleAdviseHldr not released properly" ); lpPseudoObj->m_lpOleAdviseHldr = NULL; } /* OLE2NOTE: this call forces all external connections to our ** object to close down and therefore guarantees that we receive ** all releases associated with those external connections. */ OLEDBG_BEGIN2("CoDisconnectObject called\r\n") CoDisconnectObject((LPUNKNOWN)&lpPseudoObj->m_Unknown, 0); OLEDBG_END2 PseudoObj_Release(lpPseudoObj); // release artificial AddRef above OleDoc_Release(lpOleDoc); // release artificial AddRef above OleApp_Release(lpOleApp); // release artificial AddRef above OLEDBG_END3 return fStatus; } /* PseudoObj_Destroy ** ----------------- ** Destroy (Free) the memory used by a PseudoObj structure. ** This function is called when the ref count of the PseudoObj goes ** to zero. the ref cnt goes to zero after PseudoObj_Delete forces ** the OleObject to unload and release its pointers to the ** PseudoObj IOleClientSite and IAdviseSink interfaces. */ void PseudoObj_Destroy(LPPSEUDOOBJ lpPseudoObj) { LPSERVERDOC lpServerDoc = lpPseudoObj->m_lpDoc; LPOLEAPP lpOleApp = (LPOLEAPP)g_lpApp; LPOLEDOC lpOleDoc = (LPOLEDOC)lpServerDoc; OLEDBG_BEGIN3("PseudoObj_Destroy\r\n") /* OLE2NOTE: in order to have a stable App, Doc, AND pseudo object ** during the process of closing, we intially AddRef the App, ** Doc ref counts and later Release them. These ** initial AddRefs are artificial; they are simply done to ** guarantee that these objects do not get destroyed until the ** end of this routine. */ OleApp_AddRef(lpOleApp); OleDoc_AddRef(lpOleDoc); /****************************************************************** ** OLE2NOTE: we no longer need the advise and enum holder objects, ** so release them. ******************************************************************/ if (lpPseudoObj->m_lpDataAdviseHldr) { /* release DataAdviseHldr; we SHOULD be the only one using it. */ OleStdVerifyRelease( (LPUNKNOWN)lpPseudoObj->m_lpDataAdviseHldr, "DataAdviseHldr not released properly" ); lpPseudoObj->m_lpDataAdviseHldr = NULL; } if (lpPseudoObj->m_lpOleAdviseHldr) { /* release OleAdviseHldr; we SHOULD be the only one using it. */ OleStdVerifyRelease( (LPUNKNOWN)lpPseudoObj->m_lpOleAdviseHldr, "OleAdviseHldr not released properly" ); lpPseudoObj->m_lpOleAdviseHldr = NULL; } /* forget the pointer to destroyed PseudoObj in NameTable */ if (lpPseudoObj->m_lpName) lpPseudoObj->m_lpName->m_lpPseudoObj = NULL; /* OLE2NOTE: release the lock on the Doc held on behalf of the ** PseudoObj. the Document should not shut down unless all ** pseudo objects are closed. when a pseudo object is first ** created, it calls ServerDoc_PseudoObjLockDoc to guarantee ** that the document stays alive (called from PseudoObj_Init). */ ServerDoc_PseudoObjUnlockDoc(lpServerDoc, lpPseudoObj); Delete(lpPseudoObj); // Free the memory for the structure itself OleDoc_Release(lpOleDoc); // release artificial AddRef above OleApp_Release(lpOleApp); // release artificial AddRef above OLEDBG_END3 } /* PseudoObj_GetSel ** ---------------- ** Return the line range for the pseudo object */ void PseudoObj_GetSel(LPPSEUDOOBJ lpPseudoObj, LPLINERANGE lplrSel) { LPOUTLINENAME lpOutlineName = (LPOUTLINENAME)lpPseudoObj->m_lpName; lplrSel->m_nStartLine = lpOutlineName->m_nStartLine; lplrSel->m_nEndLine = lpOutlineName->m_nEndLine; } /* PseudoObj_GetExtent * ------------------- * * Get the extent (width, height) of the entire document. */ void PseudoObj_GetExtent(LPPSEUDOOBJ lpPseudoObj, LPSIZEL lpsizel) { LPOLEDOC lpOleDoc = (LPOLEDOC)lpPseudoObj->m_lpDoc; LPLINELIST lpLL = (LPLINELIST)&((LPOUTLINEDOC)lpOleDoc)->m_LineList; LINERANGE lrSel; PseudoObj_GetSel(lpPseudoObj, (LPLINERANGE)&lrSel); LineList_CalcSelExtentInHimetric(lpLL, (LPLINERANGE)&lrSel, lpsizel); } /* PseudoObj_SendAdvise * -------------------- * * This function sends an advise notification on behalf of a specific * doc object to all its clients. */ void PseudoObj_SendAdvise( LPPSEUDOOBJ lpPseudoObj, WORD wAdvise, LPMONIKER lpmkObj, DWORD dwAdvf ) { LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpPseudoObj->m_lpDoc; switch (wAdvise) { case OLE_ONDATACHANGE: // inform clients that the data of the object has changed if (lpOutlineDoc->m_nDisableDraw == 0) { /* drawing is currently enabled. inform clients that ** the data of the object has changed */ lpPseudoObj->m_fDataChanged = FALSE; if (lpPseudoObj->m_lpDataAdviseHldr) { OLEDBG_BEGIN2("IDataAdviseHolder::SendOnDataChange called\r\n"); lpPseudoObj->m_lpDataAdviseHldr->lpVtbl->SendOnDataChange( lpPseudoObj->m_lpDataAdviseHldr, (LPDATAOBJECT)&lpPseudoObj->m_DataObject, 0, dwAdvf ); OLEDBG_END2 } } else { /* drawing is currently disabled. do not send ** notifications until drawing is re-enabled. */ lpPseudoObj->m_fDataChanged = TRUE; } break; case OLE_ONCLOSE: // inform clients that the object is shutting down if (lpPseudoObj->m_lpOleAdviseHldr) { OLEDBG_BEGIN2("IOleAdviseHolder::SendOnClose called\r\n"); lpPseudoObj->m_lpOleAdviseHldr->lpVtbl->SendOnClose( lpPseudoObj->m_lpOleAdviseHldr ); OLEDBG_END2 } break; case OLE_ONSAVE: // inform clients that the object has been saved if (lpPseudoObj->m_lpOleAdviseHldr) { OLEDBG_BEGIN2("IOleAdviseHolder::SendOnClose called\r\n"); lpPseudoObj->m_lpOleAdviseHldr->lpVtbl->SendOnSave( lpPseudoObj->m_lpOleAdviseHldr ); OLEDBG_END2 } break; case OLE_ONRENAME: // inform clients that the object's name has changed if (lpmkObj && lpPseudoObj->m_lpOleAdviseHldr) { OLEDBG_BEGIN2("IOleAdviseHolder::SendOnRename called\r\n"); if (lpPseudoObj->m_lpOleAdviseHldr) lpPseudoObj->m_lpOleAdviseHldr->lpVtbl->SendOnRename( lpPseudoObj->m_lpOleAdviseHldr, lpmkObj ); OLEDBG_END2 } break; } } /* PseudoObj_GetFullMoniker * ------------------------ * * Returns the Full, absolute Moniker which identifies this pseudo object. */ LPMONIKER PseudoObj_GetFullMoniker(LPPSEUDOOBJ lpPseudoObj, LPMONIKER lpmkDoc) { LPOUTLINENAME lpOutlineName = (LPOUTLINENAME)lpPseudoObj->m_lpName; LPMONIKER lpmkItem = NULL; LPMONIKER lpmkPseudoObj = NULL; if (lpmkDoc != NULL) { CreateItemMonikerA(OLESTDDELIM,lpOutlineName->m_szName,&lpmkItem); /* OLE2NOTE: create an absolute moniker which identifies the ** pseudo object. this moniker is created as a composite of ** the absolute moniker for the entire document appended ** with an item moniker which identifies the selection of ** the pseudo object relative to the document. */ CreateGenericComposite(lpmkDoc, lpmkItem, &lpmkPseudoObj); if (lpmkItem) OleStdRelease((LPUNKNOWN)lpmkItem); return lpmkPseudoObj; } else { return NULL; } } /************************************************************************* ** PseudoObj::IUnknown interface implementation *************************************************************************/ STDMETHODIMP PseudoObj_Unk_QueryInterface( LPUNKNOWN lpThis, REFIID riid, LPVOID FAR* lplpvObj ) { LPPSEUDOOBJ lpPseudoObj = ((struct CPseudoObjUnknownImpl FAR*)lpThis)->lpPseudoObj; return PseudoObj_QueryInterface(lpPseudoObj, riid, lplpvObj); } STDMETHODIMP_(ULONG) PseudoObj_Unk_AddRef(LPUNKNOWN lpThis) { LPPSEUDOOBJ lpPseudoObj = ((struct CPseudoObjUnknownImpl FAR*)lpThis)->lpPseudoObj; OleDbgAddRefMethod(lpThis, "IUnknown"); return PseudoObj_AddRef(lpPseudoObj); } STDMETHODIMP_(ULONG) PseudoObj_Unk_Release (LPUNKNOWN lpThis) { LPPSEUDOOBJ lpPseudoObj = ((struct CPseudoObjUnknownImpl FAR*)lpThis)->lpPseudoObj; OleDbgReleaseMethod(lpThis, "IUnknown"); return PseudoObj_Release(lpPseudoObj); } /************************************************************************* ** PseudoObj::IOleObject interface implementation *************************************************************************/ STDMETHODIMP PseudoObj_OleObj_QueryInterface( LPOLEOBJECT lpThis, REFIID riid, LPVOID FAR* lplpvObj ) { LPPSEUDOOBJ lpPseudoObj = ((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj; return PseudoObj_QueryInterface(lpPseudoObj, riid, lplpvObj); } STDMETHODIMP_(ULONG) PseudoObj_OleObj_AddRef(LPOLEOBJECT lpThis) { LPPSEUDOOBJ lpPseudoObj = ((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj; OleDbgAddRefMethod(lpThis, "IOleObject"); return PseudoObj_AddRef((LPPSEUDOOBJ)lpPseudoObj); } STDMETHODIMP_(ULONG) PseudoObj_OleObj_Release(LPOLEOBJECT lpThis) { LPPSEUDOOBJ lpPseudoObj = ((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj; OleDbgReleaseMethod(lpThis, "IOleObject"); return PseudoObj_Release((LPPSEUDOOBJ)lpPseudoObj); } STDMETHODIMP PseudoObj_OleObj_SetClientSite( LPOLEOBJECT lpThis, LPOLECLIENTSITE lpClientSite ) { OleDbgOut2("PseudoObj_OleObj_SetClientSite\r\n"); // OLE2NOTE: a pseudo object does NOT support SetExtent return ResultFromScode(E_FAIL); } STDMETHODIMP PseudoObj_OleObj_GetClientSite( LPOLEOBJECT lpThis, LPOLECLIENTSITE FAR* lplpClientSite ) { OleDbgOut2("PseudoObj_OleObj_GetClientSite\r\n"); *lplpClientSite = NULL; // OLE2NOTE: a pseudo object does NOT support SetExtent return ResultFromScode(E_FAIL); } STDMETHODIMP PseudoObj_OleObj_SetHostNamesA( LPOLEOBJECT lpThis, LPCSTR szContainerApp, LPCSTR szContainerObj ) { OleDbgOut2("PseudoObj_OleObj_SetHostNamesA\r\n"); // OLE2NOTE: a pseudo object does NOT support SetExtent return ResultFromScode(E_FAIL); } STDMETHODIMP PseudoObj_OleObj_SetHostNames( LPOLEOBJECT lpThis, LPCOLESTR szContainerApp, LPCOLESTR szContainerObj ) { OleDbgOut2("PseudoObj_OleObj_SetHostNames\r\n"); // OLE2NOTE: a pseudo object does NOT support SetExtent return ResultFromScode(E_FAIL); } STDMETHODIMP PseudoObj_OleObj_Close( LPOLEOBJECT lpThis, DWORD dwSaveOption ) { LPPSEUDOOBJ lpPseudoObj = ((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj; BOOL fStatus; OLEDBG_BEGIN2("PseudoObj_OleObj_Close\r\n") /* OLE2NOTE: a pseudo object's implementation of IOleObject::Close ** should ignore the dwSaveOption parameter. it is NOT ** applicable to pseudo objects. */ fStatus = PseudoObj_Close(lpPseudoObj); OleDbgAssertSz(fStatus == TRUE, "PseudoObj_OleObj_Close failed\r\n"); OLEDBG_END2 return NOERROR; } STDMETHODIMP PseudoObj_OleObj_SetMoniker( LPOLEOBJECT lpThis, DWORD dwWhichMoniker, LPMONIKER lpmk ) { OleDbgOut2("PseudoObj_OleObj_SetMoniker\r\n"); // OLE2NOTE: a pseudo object does NOT support SetMoniker return ResultFromScode(E_FAIL); } STDMETHODIMP PseudoObj_OleObj_GetMoniker( LPOLEOBJECT lpThis, DWORD dwAssign, DWORD dwWhichMoniker, LPMONIKER FAR* lplpmk ) { LPPSEUDOOBJ lpPseudoObj = ((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj; LPOLEDOC lpOleDoc = (LPOLEDOC)lpPseudoObj->m_lpDoc; LPMONIKER lpmkDoc; OLEDBG_BEGIN2("PseudoObj_OleObj_GetMoniker\r\n") lpmkDoc = OleDoc_GetFullMoniker(lpOleDoc, GETMONIKER_ONLYIFTHERE); *lplpmk = PseudoObj_GetFullMoniker(lpPseudoObj, lpmkDoc); OLEDBG_END2 if (*lplpmk != NULL) return NOERROR; else return ResultFromScode(E_FAIL); } STDMETHODIMP PseudoObj_OleObj_InitFromData( LPOLEOBJECT lpThis, LPDATAOBJECT lpDataObject, BOOL fCreation, DWORD reserved ) { LPPSEUDOOBJ lpPseudoObj = ((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj; OleDbgOut2("PseudoObj_OleObj_InitFromData\r\n"); // REVIEW: NOT YET IMPLEMENTED return ResultFromScode(E_NOTIMPL); } STDMETHODIMP PseudoObj_OleObj_GetClipboardData( LPOLEOBJECT lpThis, DWORD reserved, LPDATAOBJECT FAR* lplpDataObject ) { LPPSEUDOOBJ lpPseudoObj = ((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj; OleDbgOut2("PseudoObj_OleObj_GetClipboardData\r\n"); // REVIEW: NOT YET IMPLEMENTED return ResultFromScode(E_NOTIMPL); } STDMETHODIMP PseudoObj_OleObj_DoVerb( LPOLEOBJECT lpThis, LONG lVerb, LPMSG lpmsg, LPOLECLIENTSITE lpActiveSite, LONG lindex, HWND hwndParent, LPCRECT lprcPosRect ) { LPPSEUDOOBJ lpPseudoObj = ((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj; LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpPseudoObj->m_lpDoc; LPSERVERDOC lpServerDoc = lpPseudoObj->m_lpDoc; LINERANGE lrSel; HRESULT hrErr; OLEDBG_BEGIN2("PseudoObj_OleObj_DoVerb\r\n"); /* OLE2NOTE: we must first ask our Document to perform the same ** verb. then if the verb is NOT OLEIVERB_HIDE we should also ** select the range of our pseudo object. ** however, we must give our document its own embedding site as ** its active site. */ hrErr = SvrDoc_OleObj_DoVerb( (LPOLEOBJECT)&lpServerDoc->m_OleObject, lVerb, lpmsg, lpServerDoc->m_lpOleClientSite, lindex, NULL, /* we have no hwndParent to give */ NULL /* we have no lprcPosRect to give */ ); if (FAILED(hrErr)) { OLEDBG_END2 return hrErr; } if (lVerb != OLEIVERB_HIDE) { PseudoObj_GetSel(lpPseudoObj, &lrSel); OutlineDoc_SetSel(lpOutlineDoc, &lrSel); } OLEDBG_END2 return NOERROR; } STDMETHODIMP PseudoObj_OleObj_EnumVerbs( LPOLEOBJECT lpThis, LPENUMOLEVERB FAR* lplpenumOleVerb ) { OleDbgOut2("PseudoObj_OleObj_EnumVerbs\r\n"); /* OLE2NOTE: we must make sure to set all out parameters to NULL. */ *lplpenumOleVerb = NULL; /* A pseudo object may NOT return OLE_S_USEREG; they must call the ** OleReg* API or provide their own implementation. Because this ** pseudo object does NOT implement IPersist, simply a low-level ** remoting handler (ProxyManager) object as opposed to a ** DefHandler object is used as the handler for the pseudo ** object in a clients process space. The ProxyManager does NOT ** handle the OLE_S_USEREG return values. */ return OleRegEnumVerbs((REFCLSID)&CLSID_APP, lplpenumOleVerb); } STDMETHODIMP PseudoObj_OleObj_Update(LPOLEOBJECT lpThis) { OleDbgOut2("PseudoObj_OleObj_Update\r\n"); /* OLE2NOTE: a server-only app is always "up-to-date". ** a container-app which contains links where the link source ** has changed since the last update of the link would be ** considered "out-of-date". the "Update" method instructs the ** object to get an update from any out-of-date links. */ return NOERROR; } STDMETHODIMP PseudoObj_OleObj_IsUpToDate(LPOLEOBJECT lpThis) { LPPSEUDOOBJ lpPseudoObj = ((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj; OleDbgOut2("PseudoObj_OleObj_IsUpToDate\r\n"); /* OLE2NOTE: a server-only app is always "up-to-date". ** a container-app which contains links where the link source ** has changed since the last update of the link would be ** considered "out-of-date". */ return NOERROR; } STDMETHODIMP PseudoObj_OleObj_GetUserClassID( LPOLEOBJECT lpThis, LPCLSID lpclsid ) { LPPSEUDOOBJ lpPseudoObj = ((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj; LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpPseudoObj->m_lpDoc; OleDbgOut2("PseudoObj_OleObj_GetUserClassID\r\n"); /* OLE2NOTE: we must be carefull to return the correct CLSID here. ** if we are currently preforming a "TreatAs (aka. ActivateAs)" ** operation then we need to return the class of the object ** written in the storage of the object. otherwise we would ** return our own class id. */ return ServerDoc_GetClassID(lpServerDoc, lpclsid); } STDMETHODIMP PseudoObj_OleObj_GetUserTypeA( LPOLEOBJECT lpThis, DWORD dwFormOfType, LPSTR FAR* lpszUserType ) { LPPSEUDOOBJ lpPseudoObj = ((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj; LPSERVERDOC lpServerDoc = (LPSERVERDOC)lpPseudoObj->m_lpDoc; OleDbgOut2("PseudoObj_OleObj_GetUserType\r\n"); /* OLE2NOTE: we must make sure to set all out parameters to NULL. */ *lpszUserType = NULL; /* OLE2NOTE: we must be carefull to return the correct user type here. ** if we are currently preforming a "TreatAs (aka. ActivateAs)" ** operation then we need to return the user type name that ** corresponds to the class of the object we are currently ** emmulating. otherwise we should return our normal user type ** name corresponding to our own class. This routine determines ** the current clsid in effect. ** ** A pseudo object may NOT return OLE_S_USEREG; they must call the ** OleReg* API or provide their own implementation. Because this ** pseudo object does NOT implement IPersist, simply a low-level ** remoting handler (ProxyManager) object as opposed to a ** DefHandler object is used as the handler for the pseudo ** object in a clients process space. The ProxyManager does NOT ** handle the OLE_S_USEREG return values. */ #if defined( SVR_TREATAS ) if (! IsEqualCLSID(&lpServerDoc->m_clsidTreatAs, &CLSID_NULL) ) return OleRegGetUserTypeA( &lpServerDoc->m_clsidTreatAs,dwFormOfType,lpszUserType); else #endif // SVR_TREATAS return OleRegGetUserTypeA(&CLSID_APP, dwFormOfType, lpszUserType); } STDMETHODIMP PseudoObj_OleObj_GetUserType( LPOLEOBJECT lpThis, DWORD dwFormOfType, LPOLESTR FAR* lpszUserType ) { LPSTR pstr; HRESULT hr = PseudoObj_OleObj_GetUserTypeA(lpThis, dwFormOfType, &pstr); CopyAndFreeSTR(pstr, lpszUserType); return hr; } STDMETHODIMP PseudoObj_OleObj_SetExtent( LPOLEOBJECT lpThis, DWORD dwDrawAspect, LPSIZEL lplgrc ) { OleDbgOut2("PseudoObj_OleObj_SetExtent\r\n"); // OLE2NOTE: a pseudo object does NOT support SetExtent return ResultFromScode(E_FAIL); } STDMETHODIMP PseudoObj_OleObj_GetExtent( LPOLEOBJECT lpThis, DWORD dwDrawAspect, LPSIZEL lpsizel ) { LPPSEUDOOBJ lpPseudoObj = ((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj; OleDbgOut2("PseudoObj_OleObj_GetExtent\r\n"); /* OLE2NOTE: it is VERY important to check which aspect the caller ** is asking about. an object implemented by a server EXE MAY ** fail to return extents when asked for DVASPECT_ICON. */ if (dwDrawAspect == DVASPECT_CONTENT) { PseudoObj_GetExtent(lpPseudoObj, lpsizel); return NOERROR; } else { return ResultFromScode(E_FAIL); } } STDMETHODIMP PseudoObj_OleObj_Advise( LPOLEOBJECT lpThis, LPADVISESINK lpAdvSink, LPDWORD lpdwConnection ) { LPPSEUDOOBJ lpPseudoObj = ((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj; HRESULT hrErr; SCODE sc; OLEDBG_BEGIN2("PseudoObj_OleObj_Advise\r\n"); if (lpPseudoObj->m_lpOleAdviseHldr == NULL && CreateOleAdviseHolder(&lpPseudoObj->m_lpOleAdviseHldr) != NOERROR) { sc = E_OUTOFMEMORY; goto error; } OLEDBG_BEGIN2("IOleAdviseHolder::Advise called\r\n") hrErr = lpPseudoObj->m_lpOleAdviseHldr->lpVtbl->Advise( lpPseudoObj->m_lpOleAdviseHldr, lpAdvSink, lpdwConnection ); OLEDBG_END2 OLEDBG_END2 return hrErr; error: OLEDBG_END2 return ResultFromScode(sc); } STDMETHODIMP PseudoObj_OleObj_Unadvise(LPOLEOBJECT lpThis, DWORD dwConnection) { LPPSEUDOOBJ lpPseudoObj = ((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj; HRESULT hrErr; SCODE sc; OLEDBG_BEGIN2("PseudoObj_OleObj_Unadvise\r\n"); if (lpPseudoObj->m_lpOleAdviseHldr == NULL) { sc = E_FAIL; goto error; } OLEDBG_BEGIN2("IOleAdviseHolder::Unadvise called\r\n") hrErr = lpPseudoObj->m_lpOleAdviseHldr->lpVtbl->Unadvise( lpPseudoObj->m_lpOleAdviseHldr, dwConnection ); OLEDBG_END2 OLEDBG_END2 return hrErr; error: OLEDBG_END2 return ResultFromScode(sc); } STDMETHODIMP PseudoObj_OleObj_EnumAdvise( LPOLEOBJECT lpThis, LPENUMSTATDATA FAR* lplpenumAdvise ) { LPPSEUDOOBJ lpPseudoObj = ((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj; HRESULT hrErr; SCODE sc; OLEDBG_BEGIN2("PseudoObj_OleObj_EnumAdvise\r\n"); /* OLE2NOTE: we must make sure to set all out parameters to NULL. */ *lplpenumAdvise = NULL; if (lpPseudoObj->m_lpOleAdviseHldr == NULL) { sc = E_FAIL; goto error; } OLEDBG_BEGIN2("IOleAdviseHolder::EnumAdvise called\r\n") hrErr = lpPseudoObj->m_lpOleAdviseHldr->lpVtbl->EnumAdvise( lpPseudoObj->m_lpOleAdviseHldr, lplpenumAdvise ); OLEDBG_END2 OLEDBG_END2 return hrErr; error: OLEDBG_END2 return ResultFromScode(sc); } STDMETHODIMP PseudoObj_OleObj_GetMiscStatus( LPOLEOBJECT lpThis, DWORD dwAspect, DWORD FAR* lpdwStatus ) { LPPSEUDOOBJ lpPseudoObj = ((struct CPseudoObjOleObjectImpl FAR*)lpThis)->lpPseudoObj; LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpPseudoObj->m_lpDoc; OleDbgOut2("PseudoObj_OleObj_GetMiscStatus\r\n"); /* Get our default MiscStatus for the given Aspect. this ** information is registered in the RegDB. We query the RegDB ** here to guarantee that the value returned from this method ** agrees with the values in RegDB. in this way we only have to ** maintain the info in one place (in the RegDB). Alternatively ** we could have the values hard coded here. ** ** OLE2NOTE: A pseudo object may NOT return OLE_S_USEREG; they must ** call the ** OleReg* API or provide their own implementation. Because this ** pseudo object does NOT implement IPersist, simply a low-level ** remoting handler (ProxyManager) object as opposed to a ** DefHandler object is used as the handler for the pseudo ** object in a clients process space. The ProxyManager does NOT ** handle the OLE_S_USEREG return values. */ OleRegGetMiscStatus((REFCLSID)&CLSID_APP, dwAspect, lpdwStatus); /* OLE2NOTE: check if the pseudo object is compatible to be ** linked by an OLE 1.0 container. it is compatible if ** either the pseudo object is an untitled document or a ** file-based document. if the pseudo object is part of ** an embedded object, then it is NOT compatible to be ** linked by an OLE 1.0 container. if it is compatible then ** we should include OLEMISC_CANLINKBYOLE1 as part of the ** dwStatus flags. */ if (lpOutlineDoc->m_docInitType == DOCTYPE_NEW || lpOutlineDoc->m_docInitType == DOCTYPE_FROMFILE) *lpdwStatus |= OLEMISC_CANLINKBYOLE1; return NOERROR; } STDMETHODIMP PseudoObj_OleObj_SetColorScheme( LPOLEOBJECT lpThis, LPLOGPALETTE lpLogpal ) { OleDbgOut2("PseudoObj_OleObj_SetColorScheme\r\n"); // REVIEW: NOT YET IMPLEMENTED return ResultFromScode(E_NOTIMPL); } /************************************************************************* ** PseudoObj::IDataObject interface implementation *************************************************************************/ STDMETHODIMP PseudoObj_DataObj_QueryInterface ( LPDATAOBJECT lpThis, REFIID riid, LPVOID FAR* lplpvObj ) { LPPSEUDOOBJ lpPseudoObj = ((struct CPseudoObjDataObjectImpl FAR*)lpThis)->lpPseudoObj; return PseudoObj_QueryInterface(lpPseudoObj, riid, lplpvObj); } STDMETHODIMP_(ULONG) PseudoObj_DataObj_AddRef(LPDATAOBJECT lpThis) { LPPSEUDOOBJ lpPseudoObj = ((struct CPseudoObjDataObjectImpl FAR*)lpThis)->lpPseudoObj; OleDbgAddRefMethod(lpThis, "IDataObject"); return PseudoObj_AddRef((LPPSEUDOOBJ)lpPseudoObj); } STDMETHODIMP_(ULONG) PseudoObj_DataObj_Release (LPDATAOBJECT lpThis) { LPPSEUDOOBJ lpPseudoObj = ((struct CPseudoObjDataObjectImpl FAR*)lpThis)->lpPseudoObj; OleDbgReleaseMethod(lpThis, "IDataObject"); return PseudoObj_Release((LPPSEUDOOBJ)lpPseudoObj); } STDMETHODIMP PseudoObj_DataObj_GetData ( LPDATAOBJECT lpThis, LPFORMATETC lpformatetc, LPSTGMEDIUM lpMedium ) { LPPSEUDOOBJ lpPseudoObj = ((struct CPseudoObjDataObjectImpl FAR*)lpThis)->lpPseudoObj; LPSERVERDOC lpServerDoc = lpPseudoObj->m_lpDoc; LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc; LPSERVERAPP lpServerApp = (LPSERVERAPP)g_lpApp; LPOLEAPP lpOleApp = (LPOLEAPP)lpServerApp; LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)lpServerApp; LINERANGE lrSel; SCODE sc = S_OK; OLEDBG_BEGIN2("PseudoObj_DataObj_GetData\r\n") PseudoObj_GetSel(lpPseudoObj, &lrSel); /* OLE2NOTE: we must make sure to set all out parameters to NULL. */ lpMedium->tymed = TYMED_NULL; lpMedium->pUnkForRelease = NULL; // we transfer ownership to caller lpMedium->hGlobal = NULL; if (lpformatetc->cfFormat == lpOutlineApp->m_cfOutline) { // Verify caller asked for correct medium if (!(lpformatetc->tymed & TYMED_HGLOBAL)) { sc = DATA_E_FORMATETC; goto error; } lpMedium->hGlobal = OutlineDoc_GetOutlineData (lpOutlineDoc,&lrSel); if (! lpMedium->hGlobal) return ResultFromScode(E_OUTOFMEMORY); lpMedium->tymed = TYMED_HGLOBAL; OleDbgOut3("PseudoObj_DataObj_GetData: rendered CF_OUTLINE\r\n"); } else if(lpformatetc->cfFormat == CF_METAFILEPICT && (lpformatetc->dwAspect & DVASPECT_CONTENT) ) { // Verify caller asked for correct medium if (!(lpformatetc->tymed & TYMED_MFPICT)) { sc = DATA_E_FORMATETC; goto error; } lpMedium->hGlobal=ServerDoc_GetMetafilePictData(lpServerDoc,&lrSel); if (! lpMedium->hGlobal) { sc = E_OUTOFMEMORY; goto error; } lpMedium->tymed = TYMED_MFPICT; OleDbgOut3("PseudoObj_DataObj_GetData: rendered CF_METAFILEPICT\r\n"); } else if (lpformatetc->cfFormat == CF_METAFILEPICT && (lpformatetc->dwAspect & DVASPECT_ICON) ) { CLSID clsid; // Verify caller asked for correct medium if (!(lpformatetc->tymed & TYMED_MFPICT)) { sc = DATA_E_FORMATETC; goto error; } /* OLE2NOTE: we should return the default icon for our class. ** we must be carefull to use the correct CLSID here. ** if we are currently preforming a "TreatAs (aka. ActivateAs)" ** operation then we need to use the class of the object ** written in the storage of the object. otherwise we would ** use our own class id. */ if (ServerDoc_GetClassID(lpServerDoc, (LPCLSID)&clsid) != NOERROR) { sc = DATA_E_FORMATETC; goto error; } lpMedium->hGlobal=GetIconOfClass( g_lpApp->m_hInst,(REFCLSID)&clsid, NULL, FALSE); if (! lpMedium->hGlobal) { sc = E_OUTOFMEMORY; goto error; } lpMedium->tymed = TYMED_MFPICT; OleDbgOut3("PseudoObj_DataObj_GetData: rendered CF_METAFILEPICT (icon)\r\n"); return NOERROR; } else if (lpformatetc->cfFormat == CF_TEXT) { // Verify caller asked for correct medium if (!(lpformatetc->tymed & TYMED_HGLOBAL)) { sc = DATA_E_FORMATETC; goto error; } lpMedium->hGlobal = OutlineDoc_GetTextData (lpOutlineDoc, &lrSel); if (! lpMedium->hGlobal) { sc = E_OUTOFMEMORY; goto error; } lpMedium->tymed = TYMED_HGLOBAL; OleDbgOut3("PseudoObj_DataObj_GetData: rendered CF_TEXT\r\n"); } else { sc = DATA_E_FORMATETC; goto error; } OLEDBG_END2 return NOERROR; error: OLEDBG_END2 return ResultFromScode(sc); } STDMETHODIMP PseudoObj_DataObj_GetDataHere ( LPDATAOBJECT lpThis, LPFORMATETC lpformatetc, LPSTGMEDIUM lpMedium ) { LPPSEUDOOBJ lpPseudoObj = ((struct CPseudoObjDataObjectImpl FAR*)lpThis)->lpPseudoObj; LPSERVERDOC lpServerDoc = lpPseudoObj->m_lpDoc; LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc; LPSERVERAPP lpServerApp = (LPSERVERAPP)g_lpApp; LPOLEAPP lpOleApp = (LPOLEAPP)lpServerApp; LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)lpServerApp; OleDbgOut("PseudoObj_DataObj_GetDataHere\r\n"); /* Caller is requesting data to be returned in Caller allocated ** medium, but we do NOT support this. we only support ** global memory blocks that WE allocate for the caller. */ return ResultFromScode(DATA_E_FORMATETC); } STDMETHODIMP PseudoObj_DataObj_QueryGetData ( LPDATAOBJECT lpThis, LPFORMATETC lpformatetc ) { LPPSEUDOOBJ lpPseudoObj = ((struct CPseudoObjDataObjectImpl FAR*)lpThis)->lpPseudoObj; LPSERVERDOC lpServerDoc = lpPseudoObj->m_lpDoc; LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc; LPSERVERAPP lpServerApp = (LPSERVERAPP)g_lpApp; LPOLEAPP lpOleApp = (LPOLEAPP)lpServerApp; LPOUTLINEAPP lpOutlineApp = (LPOUTLINEAPP)lpServerApp; OleDbgOut2("PseudoObj_DataObj_QueryGetData\r\n"); /* Caller is querying if we support certain format but does not ** want any data actually returned. */ if (lpformatetc->cfFormat == CF_METAFILEPICT && (lpformatetc->dwAspect & (DVASPECT_CONTENT | DVASPECT_ICON)) ) { return OleStdQueryFormatMedium(lpformatetc, TYMED_MFPICT); } else if (lpformatetc->cfFormat == (lpOutlineApp)->m_cfOutline || lpformatetc->cfFormat == CF_TEXT) { return OleStdQueryFormatMedium(lpformatetc, TYMED_HGLOBAL); } return ResultFromScode(DATA_E_FORMATETC); } STDMETHODIMP PseudoObj_DataObj_GetCanonicalFormatEtc( LPDATAOBJECT lpThis, LPFORMATETC lpformatetc, LPFORMATETC lpformatetcOut ) { HRESULT hrErr; OleDbgOut2("PseudoObj_DataObj_GetCanonicalFormatEtc\r\n"); if (!lpformatetcOut) return ResultFromScode(E_INVALIDARG); /* OLE2NOTE: we must make sure to set all out parameters to NULL. */ lpformatetcOut->ptd = NULL; if (!lpformatetc) return ResultFromScode(E_INVALIDARG); // OLE2NOTE: we must validate that the format requested is supported if ((hrErr=lpThis->lpVtbl->QueryGetData(lpThis,lpformatetc)) != NOERROR) return hrErr; /* OLE2NOTE: an app that is insensitive to target device (as the ** Outline Sample is) should fill in the lpformatOut parameter ** but NULL out the "ptd" field; it should return NOERROR if the ** input formatetc->ptd what non-NULL. this tells the caller ** that it is NOT necessary to maintain a separate screen ** rendering and printer rendering. if should return ** DATA_S_SAMEFORMATETC if the input and output formatetc's are ** identical. */ *lpformatetcOut = *lpformatetc; if (lpformatetc->ptd == NULL) return ResultFromScode(DATA_S_SAMEFORMATETC); else { lpformatetcOut->ptd = NULL; return NOERROR; } } STDMETHODIMP PseudoObj_DataObj_SetData ( LPDATAOBJECT lpThis, LPFORMATETC lpformatetc, LPSTGMEDIUM lpmedium, BOOL fRelease ) { LPPSEUDOOBJ lpPseudoObj = ((struct CPseudoObjDataObjectImpl FAR*)lpThis)->lpPseudoObj; LPSERVERDOC lpServerDoc = lpPseudoObj->m_lpDoc; LPOUTLINEDOC lpOutlineDoc = (LPOUTLINEDOC)lpServerDoc; LPSERVERAPP lpServerApp = (LPSERVERAPP)g_lpApp; OleDbgOut2("PseudoObj_DataObj_SetData\r\n"); // REVIEW: NOT-YET-IMPLEMENTED return ResultFromScode(E_NOTIMPL); } STDMETHODIMP PseudoObj_DataObj_EnumFormatEtc( LPDATAOBJECT lpThis, DWORD dwDirection, LPENUMFORMATETC FAR* lplpenumFormatEtc ) { SCODE sc; OleDbgOut2("PseudoObj_DataObj_EnumFormatEtc\r\n"); /* OLE2NOTE: a pseudo object only needs to enumerate the static list ** of formats that are registered for our app in the ** registration database. it is NOT ** required that a pseudo object (ie. non-DataTransferDoc) ** enumerate the OLE formats: CF_LINKSOURCE, CF_EMBEDSOURCE, or ** CF_EMBEDDEDOBJECT. we do NOT use pseudo objects for data ** transfers. ** ** A pseudo object may NOT return OLE_S_USEREG; they must call the ** OleReg* API or provide their own implementation. Because this ** pseudo object does NOT implement IPersist, simply a low-level ** remoting handler (ProxyManager) object as opposed to a ** DefHandler object is used as the handler for the pseudo ** object in a clients process space. The ProxyManager does NOT ** handle the OLE_S_USEREG return values. */ if (dwDirection == DATADIR_GET) return OleRegEnumFormatEtc( (REFCLSID)&CLSID_APP, dwDirection, lplpenumFormatEtc); else if (dwDirection == DATADIR_SET) sc = E_NOTIMPL; else sc = E_INVALIDARG; return ResultFromScode(sc); } STDMETHODIMP PseudoObj_DataObj_DAdvise( LPDATAOBJECT lpThis, FORMATETC FAR* lpFormatetc, DWORD advf, LPADVISESINK lpAdvSink, DWORD FAR* lpdwConnection ) { LPPSEUDOOBJ lpPseudoObj = ((struct CPseudoObjDataObjectImpl FAR*)lpThis)->lpPseudoObj; HRESULT hrErr; SCODE sc; OLEDBG_BEGIN2("PseudoObj_DataObj_DAdvise\r\n") /* OLE2NOTE: we must make sure to set all out parameters to NULL. */ *lpdwConnection = 0; /* OLE2NOTE: we should validate if the caller is setting up an ** Advise for a data type that we support. we must ** explicitly allow an advise for the "wildcard" advise. */ if ( !( lpFormatetc->cfFormat == 0 && lpFormatetc->ptd == NULL && lpFormatetc->dwAspect == -1L && lpFormatetc->lindex == -1L && lpFormatetc->tymed == -1L) && (hrErr = PseudoObj_DataObj_QueryGetData(lpThis, lpFormatetc)) != NOERROR) { sc = GetScode(hrErr); goto error; } if (lpPseudoObj->m_lpDataAdviseHldr == NULL && CreateDataAdviseHolder(&lpPseudoObj->m_lpDataAdviseHldr) != NOERROR) { sc = E_OUTOFMEMORY; goto error; } OLEDBG_BEGIN2("IOleAdviseHolder::Advise called\r\n") hrErr = lpPseudoObj->m_lpDataAdviseHldr->lpVtbl->Advise( lpPseudoObj->m_lpDataAdviseHldr, (LPDATAOBJECT)&lpPseudoObj->m_DataObject, lpFormatetc, advf, lpAdvSink, lpdwConnection ); OLEDBG_END2 OLEDBG_END2 return hrErr; error: OLEDBG_END2 return ResultFromScode(sc); } STDMETHODIMP PseudoObj_DataObj_DUnadvise(LPDATAOBJECT lpThis, DWORD dwConnection) { LPPSEUDOOBJ lpPseudoObj = ((struct CPseudoObjDataObjectImpl FAR*)lpThis)->lpPseudoObj; HRESULT hrErr; SCODE sc; OLEDBG_BEGIN2("PseudoObj_DataObj_Unadvise\r\n"); // no one registered if (lpPseudoObj->m_lpDataAdviseHldr == NULL) { sc = E_FAIL; goto error; } OLEDBG_BEGIN2("IOleAdviseHolder::DUnadvise called\r\n") hrErr = lpPseudoObj->m_lpDataAdviseHldr->lpVtbl->Unadvise( lpPseudoObj->m_lpDataAdviseHldr, dwConnection ); OLEDBG_END2 OLEDBG_END2 return hrErr; error: OLEDBG_END2 return ResultFromScode(sc); } STDMETHODIMP PseudoObj_DataObj_EnumAdvise( LPDATAOBJECT lpThis, LPENUMSTATDATA FAR* lplpenumAdvise ) { LPPSEUDOOBJ lpPseudoObj = ((struct CPseudoObjDataObjectImpl FAR*)lpThis)->lpPseudoObj; HRESULT hrErr; SCODE sc; OLEDBG_BEGIN2("PseudoObj_DataObj_EnumAdvise\r\n"); /* OLE2NOTE: we must make sure to set all out parameters to NULL. */ *lplpenumAdvise = NULL; if (lpPseudoObj->m_lpDataAdviseHldr == NULL) { sc = E_FAIL; goto error; } OLEDBG_BEGIN2("IOleAdviseHolder::EnumAdvise called\r\n") hrErr = lpPseudoObj->m_lpDataAdviseHldr->lpVtbl->EnumAdvise( lpPseudoObj->m_lpDataAdviseHldr, lplpenumAdvise ); OLEDBG_END2 OLEDBG_END2 return hrErr; error: OLEDBG_END2 return ResultFromScode(sc); }