//+------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 1993. // // File: defutil.cpp // // Contents: Implementations of utility functions for the default // handler and default link objects // // Classes: none // // Functions: DuLockContainer // DuSetClientSite // DuGetClientSite // DuCacheDelegate // // History: dd-mmm-yy Author Comment // 11-Jan-94 alexgo added VDATEHEAP macros to every function // 20-Nov-93 alexgo 32bit port // //-------------------------------------------------------------------------- #include #pragma SEG(defutil) #include #include ASSERTDATA NAME_SEG(defutil) //+------------------------------------------------------------------------- // // Function: DuLockContainer // // Synopsis: Calls IOleContainer->LockContainer from the given client site // // Effects: Unlocking the container may release the calling object. // // Arguments: [pCS] -- the client site from which to get // the IOleContainer pointer // [fLockNew] -- TRUE == lock, FALSE == unlock // [pfLockCur] -- pointer to a flag with the current lock // state // // Requires: // // Returns: void // // Signals: // // Modifies: // // Algorithm: // // History: dd-mmm-yy Author Comment // 20-Nov-93 alexgo 32bit port // // Notes: // //-------------------------------------------------------------------------- #pragma SEG(DuLockContainer) INTERNAL_(void) DuLockContainer(IOleClientSite FAR* pCS, BOOL fLockNew, BOOL FAR*pfLockCur) { VDATEHEAP(); #ifdef _DEBUG BOOL fLocked = FALSE; // used only for debugging so don't waste // the code space in the retail version #endif // _DEBUG IOleContainer FAR* pContainer; //the double bang turns each into a true boolean if (!!fLockNew == !!*pfLockCur) { // already locked as needed return; } // set flag to false first since unlocking container may release obj; // we can just set to false since it is either already false or going // to become false (don't set to true until we know the lock completed). *pfLockCur = FALSE; if (pCS == NULL) { pContainer = NULL; } else { HRESULT hresult = pCS->GetContainer(&pContainer); // Excel 5 can return S_FALSE, pContainer == NULL // so we can't use AssertOutPtrIface here since it // expects all successful returns to provide a // valid interface if (hresult != NOERROR) { pContainer = NULL; // just in case } } if (pContainer != NULL) { // we assume that LockContainer will succeed first and // and set the locked flag that was passed into us. This // way, if LockContainer succeeeds, we won't access memory // that could have potentially been blown away. // If it *fails*, then we handle reset the flag (as our // memory would not have been free'd) BOOL fLockOld = *pfLockCur; *pfLockCur = fLockNew; if( pContainer->LockContainer(fLockNew) != NOERROR ) { //failure case, we were not deleted *pfLockCur = fLockOld; //fLocked is FALSE } #ifdef _DEBUG else { fLocked = TRUE; } #endif // _DEBUG pContainer->Release(); } } //+------------------------------------------------------------------------- // // Function: DuSetClientSite // // Synopsis: Called by the default handler and deflink SetClientSite // implemenations; Releases the old client site (and unlocks // its container), stores the client site (locking its // container). // // Effects: // // Arguments: [fRunning] -- whether or not the delegate is running // [pCSNew] -- the new client site // [ppCSCur] -- a pointer to the original client site // pointer. [*ppCSCur] will be reset // to the new client site pointer. // [pfLockCur] -- pointer to the fLocked flag, used by // DuLockContainer. // // Requires: // // Returns: HRESULT // // Signals: // // Modifies: // // Algorithm: // // History: dd-mmm-yy Author Comment // 22-Nov-93 alexgo 32bit port // // Notes: // //-------------------------------------------------------------------------- #pragma SEG(DuSetClientSite) INTERNAL DuSetClientSite(BOOL fRunning, IOleClientSite FAR* pCSNew, IOleClientSite FAR* FAR* ppCSCur, BOOL FAR*pfLockCur) { VDATEHEAP(); if (pCSNew) { VDATEIFACE( pCSNew ); } IOleClientSite FAR* pCSOldClientSite = *ppCSCur; BOOL fLockOldClientSite = *pfLockCur; *pfLockCur = FALSE; // New ClientSite is not Locked. if ((*ppCSCur = pCSNew) != NULL) { // we've decided to keep the pointer that's been passed to us. So we // must AddRef() and Lock if in Running state. pCSNew->AddRef(); // Lock the newcontainer if (fRunning) { DuLockContainer(pCSNew, TRUE, pfLockCur); } } // If Already Had a ClientSite, Unlock and Free if (pCSOldClientSite != NULL) { // Unlock the old container if (fRunning) { DuLockContainer(pCSOldClientSite, FALSE, &fLockOldClientSite); } pCSOldClientSite->Release(); } return NOERROR; } //+------------------------------------------------------------------------- // // Function: DuCacheDelegate // // Synopsis: Retrieves the requested interface from [pUnk]. If [fAgg] is // true, we release the pointer (so ref counts to not get // obfuscated ;-) // // Effects: // // Arguments: [ppUnk] -- the object to QueryInterface on // [iid] -- the requested interface // [ppv] -- where to put the pointer to the interface // [pUnkOuter] -- controlling unknown, if non-NULL indicates // aggregation and release is called on it // // // // Requires: // // Returns: void *, the requested interface pointer // // Signals: // // Modifies: // // Algorithm: // // History: dd-mmm-yy Author Comment // 29-Jun-94 alexgo better handle re-entrancy // 20-Jun-94 alexgo updated to May '94 aggregation rules // 22-Nov-93 alexgo 32bit port // // Notes: // //-------------------------------------------------------------------------- #pragma SEG(DuCacheDelegate) INTERNAL_(void FAR*) DuCacheDelegate(IUnknown FAR** ppUnk, REFIID iid, LPVOID FAR* ppv, IUnknown *pUnkOuter) { VDATEHEAP(); if (*ppUnk != NULL && *ppv == NULL) { if ((*ppUnk)->QueryInterface (iid, ppv) == NOERROR) { // the QI may actually be an outgoing call so it // is possible that ppUnk was released and set to // NULL during our call. To make the default link // and handler simpler, we check for that case and // release any pointer we may have obtained // from the QI if( *ppUnk == NULL ) { LEDebugOut((DEB_WARN, "WARNING: Delegate " "released during QI, should be OK\n")); if( *ppv ) { // this should never be a final // release on the default handler // since we are calling it from // within a method in the default // link object. Therefore, // we do not need to guard this // release // // in the case of the link object, // this may be the final release // on the proxies, but since they are // not aggregated into the link // object, that's OK. (*(IUnknown **)ppv)->Release(); *ppv = NULL; } } if( pUnkOuter && *ppv) { // we will keep the pointer but we don't want // to bump the ref count of the aggregate, // so we gotta do Release() on the controlling // unknown. pUnkOuter->Release(); } } } return *ppv; }