//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 1994. // // File: cthkmgr.cxx // // Contents: cthunkmanager for an apartment // // Classes: CThkMgr derived from IThunkManager // // Functions: // // History: 5-18-94 JohannP (Johann Posch) Created // //---------------------------------------------------------------------------- #include "headers.cxx" #pragma hdrstop #include #if DBG == 1 BOOL fDebugDump = FALSE; #define DBG_DUMP(x) if (fDebugDump) { x; } #else #define DBG_DUMP(x) #endif #define PprxNull(pprx) ((pprx).dwPtrVal = 0) #define PprxIsNull(pprx) ((pprx).dwPtrVal == 0) #define Pprx16(vpv) PROXYPTR((DWORD)vpv, PPRX_16) #define Pprx32(pto) PROXYPTR((DWORD)pto, PPRX_32) //+--------------------------------------------------------------------------- // // Function: ResolvePprx, public // // Synopsis: Converts a PROXYPTR to a CProxy * // // Arguments: [ppprx] - PROXYPTR // // Returns: Pointer or NULL // // History: 15-Jul-94 DrewB Created // //---------------------------------------------------------------------------- CProxy *ResolvePprx(PROXYPTR *ppprx) { if (ppprx->wType == PPRX_32) { return (CProxy *)ppprx->dwPtrVal; } else { // Get a pointer to all of the proxy rather than just the CProxy part return FIXVDMPTR(ppprx->dwPtrVal, THUNK1632OBJ); } } //+--------------------------------------------------------------------------- // // Function: ReleasePprx, public // // Synopsis: Releases a resolved PROXYPTR // // Arguments: [ppprx] - PROXYPTR // // History: 10-Oct-94 DrewB Created // //---------------------------------------------------------------------------- void ReleasePprx(PROXYPTR *ppprx) { if (ppprx->wType == PPRX_16) { RELVDMPTR(ppprx->dwPtrVal); } } //+--------------------------------------------------------------------------- // // Member: CThkMgr::NewHolder, public // // Synopsis: Creates a new proxy holder // // Arguments: [dwFlags] - Flags // // Returns: Holder or NULL // // History: 16-Jul-94 DrewB Created // //---------------------------------------------------------------------------- PROXYHOLDER *CThkMgr::NewHolder(DWORD dwFlags) { PROXYHOLDER *pph; thkDebugOut((DEB_THUNKMGR, "In CThkMgr::NewHolder(0x%X)\n", dwFlags)); pph = (PROXYHOLDER *)flHolderFreeList.AllocElement(); if (pph == NULL) { goto Exit; } pph->dwFlags = dwFlags; // Start out without any listed proxies pph->cProxies = 0; PprxNull(pph->pprxProxies); // Add to list of holders pph->pphNext = _pphHolders; _pphHolders = pph; Exit: thkDebugOut((DEB_THUNKMGR, "Out CThkMgr::NewHolder => %p\n", pph)); return pph; } //+--------------------------------------------------------------------------- // // Member: CThkMgr::AddProxyToHolder, public // // Synopsis: Adds a new proxy to a holder // // Arguments: [pph] - Holder // [pprxReal] - Proxy // [pprx] - Abstract pointer // // History: 07-Jul-94 DrewB Extracted // //---------------------------------------------------------------------------- void CThkMgr::AddProxyToHolder(PROXYHOLDER *pph,CProxy *pprxReal, PROXYPTR &pprx) { thkDebugOut((DEB_THUNKMGR, "In AddProxyToHolder(%p, %p) cProxies %d\n", pph, pprx.dwPtrVal, pph->cProxies)); thkAssert(ResolvePprx(&pprx) == pprxReal && (ReleasePprx(&pprx), TRUE)); // Bump count of held proxies AddRefHolder(pph); // Add proxy into list of object proxies thkAssert(PprxIsNull(pprxReal->pprxObject)); pprxReal->pprxObject = pph->pprxProxies; pph->pprxProxies = pprx; thkAssert(pprxReal->pphHolder == NULL); pprxReal->pphHolder = pph; thkDebugOut((DEB_THUNKMGR, "out AddProxyToHolder(%p, %p) cProxies %d\n", pph, pprx.dwPtrVal, pph->cProxies)); } //+--------------------------------------------------------------------------- // // Member: CThkMgr::AddRefHolder, public // // Synopsis: Increments the proxy count for a holder // // Arguments: [pph] - Holder // // History: 07-Jul-94 DrewB Created // //---------------------------------------------------------------------------- void CThkMgr::AddRefHolder(PROXYHOLDER *pph) { pph->cProxies++; thkDebugOut((DEB_THUNKMGR, "AddRefHolder(%p) cProxies %d\n", pph, pph->cProxies)); } //+--------------------------------------------------------------------------- // // Method: CThkMgr::ReleaseHolder, public // // Synopsis: Releases a proxy reference on the holder // Cleans up the holder if it was the last reference // // Arguments: [pph] - Holder // // History: 06-21-94 JohannP Created ReleaseAggregateProxies // 07-Jul-94 DrewB Modified // //---------------------------------------------------------------------------- void CThkMgr::ReleaseHolder(PROXYHOLDER *pph) { PROXYHOLDER *pphTmp, *pphPrev; thkDebugOut((DEB_THUNKMGR, "ReleaseHolder(%p) pre cProxies %d\n", pph, pph->cProxies)); thkAssert(pph->cProxies > 0); // Decrement the holder's proxy count pph->cProxies--; if (pph->cProxies == 0) { CProxy *pprxReal; PROXYPTR pprx, pprxNext; // All interfaces for the object have been freed so we can // clean up the object pprx = pph->pprxProxies; while (!PprxIsNull(pprx)) { pprxReal = ResolvePprx(&pprx); pprxNext = pprxReal->pprxObject; thkAssert(pprxReal->cRefLocal == 0); thkAssert(pprxReal->pphHolder == pph); if (pprx.wType == PPRX_16) { // Releases pointer RemoveProxy1632((VPVOID)pprx.dwPtrVal, (THUNK1632OBJ *)pprxReal); } else { RemoveProxy3216((THUNK3216OBJ *)pprxReal); } pprx = pprxNext; } // Remove holder from list pphPrev = NULL; for (pphTmp = _pphHolders; pphTmp && pphTmp != pph; pphPrev = pphTmp, pphTmp = pphTmp->pphNext) { NULL; } // If we didn't find the holder in the holder list then our // list is trashed thkAssert(pphTmp == pph); if (pphPrev == NULL) { _pphHolders = pph->pphNext; } else { pphPrev->pphNext = pph->pphNext; } flHolderFreeList.FreeElement((DWORD)pph); } } //+--------------------------------------------------------------------------- // // Method: CThkMgr::Create // // Synopsis: static member - creates complete thunkmanager // // Arguments: [void] -- // // Returns: pointer to cthkmgr // // History: 6-01-94 JohannP (Johann Posch) Created // // Notes: // //---------------------------------------------------------------------------- CThkMgr *CThkMgr::Create(void) { CThkMgr *pcthkmgr = NULL; CMapDwordPtr *pPT1632 = new CMapDwordPtr(MEMCTX_TASK); CMapDwordPtr *pPT3216 = new CMapDwordPtr(MEMCTX_TASK); if ( (pPT1632 != NULL) && (pPT3216 != NULL) && (pcthkmgr = new CThkMgr( pPT1632, pPT3216 )) ) { // install the new thunkmanager TlsThkSetThkMgr(pcthkmgr); } else { if (pPT1632) { delete pPT1632; } if (pPT3216) { delete pPT3216; } } return pcthkmgr; } //+--------------------------------------------------------------------------- // // Method: CThkMgr::CThkMgr // // Synopsis: private constructor - called by Create // // Arguments: [pPT1632] -- 16/32 proxy table // [pPT3216] -- 32/16 proxy table // // History: 6-01-94 JohannP (Johann Posch) Created // //---------------------------------------------------------------------------- CThkMgr::CThkMgr(CMapDwordPtr *pPT1632, CMapDwordPtr *pPT3216) { _cRefs = 1; _thkstate = THKSTATE_NOCALL; _piidnode = NULL; _pProxyTbl1632 = pPT1632; _pProxyTbl3216 = pPT3216; _pphHolders = NULL; } //+--------------------------------------------------------------------------- // // Method: CThkMgr::~CThkMgr // // Synopsis: destructor // // History: 6-01-94 JohannP (Johann Posch) Created // //---------------------------------------------------------------------------- CThkMgr::~CThkMgr() { PROXYHOLDER *pph; PIIDNODE pin; thkDebugOut((DEB_ITRACE, "_IN CThkMgr::~CThkMgr()\n")); RemoveAllProxies(); delete _pProxyTbl1632; delete _pProxyTbl3216; // Clean up IID requests #if DBG == 1 if (_piidnode != NULL) { thkDebugOut((DEB_WARN, "WARNING: IID requests active at shutdown\n")); } #endif while (_piidnode != NULL) { pin = _piidnode->pNextNode; thkDebugOut((DEB_IWARN, "IID request leak: %p {%s}\n", _piidnode, IidOrInterfaceString(_piidnode->piid))); flRequestFreeList.FreeElement((DWORD)_piidnode); _piidnode = pin; } #if DBG == 1 if (_pphHolders != NULL) { thkDebugOut((DEB_WARN, "WARNING: Proxy holders active at shutdown\n")); } #endif // Clean up any proxy holders while (_pphHolders) { pph = _pphHolders->pphNext; thkDebugOut((DEB_IWARN, "Proxy holder leak: %p {%d, 0x%X}\n", _pphHolders, _pphHolders->cProxies, _pphHolders->dwFlags)); flHolderFreeList.FreeElement((DWORD)_pphHolders); _pphHolders = pph; } thkDebugOut((DEB_ITRACE, "OUT CThkMgr::~CThkMgr()\n")); } //+--------------------------------------------------------------------------- // // Member: CThkMgr::RemoveAllProxies, public // // Synopsis: Removes all live proxies from the proxy tables // // History: 01-Dec-94 DrewB Created // //---------------------------------------------------------------------------- void CThkMgr::RemoveAllProxies(void) { POSITION pos; DWORD dwKey; VPVOID vpv; thkDebugOut((DEB_ITRACE, "_IN CThkMgr::RemoveAllProxies()\n")); // Make sure that we disable 3216 proxies first to guard against calling // back into 16 bit land. #if DBG == 1 DWORD dwCount; dwCount = _pProxyTbl3216->GetCount(); if (dwCount > 0) { thkDebugOut((DEB_WARN, "WARNING: %d 3216 proxies left\n", dwCount)); } #endif // delete the 3216 proxy table while (pos = _pProxyTbl3216->GetStartPosition()) { THUNK3216OBJ *pto3216; _pProxyTbl3216->GetNextAssoc(pos, dwKey, (void FAR* FAR&) pto3216); thkDebugOut((DEB_IWARN, "3216: %p {%d,%d, %p, %p} %s\n", pto3216, pto3216->cRefLocal, pto3216->cRef, pto3216->vpvThis16, pto3216->pphHolder, IidIdxString(pto3216->iidx))); pto3216->grfFlags |= PROXYFLAG_CLEANEDUP; RemoveProxy3216(pto3216); } #if DBG == 1 dwCount = _pProxyTbl1632->GetCount(); if (dwCount > 0) { thkDebugOut((DEB_WARN, "WARNING: %d 1632 proxies left\n", dwCount)); } #endif // delete the 1632 proxy table while (pos = _pProxyTbl1632->GetStartPosition()) { THUNK1632OBJ *pto1632; _pProxyTbl1632->GetNextAssoc(pos, dwKey, (void FAR* FAR&) vpv); pto1632 = FIXVDMPTR(vpv, THUNK1632OBJ); #if DBG == 1 thkDebugOut((DEB_IWARN, "1632: %p {%d,%d, %p, %p} %s\n", vpv, pto1632->cRefLocal, pto1632->cRef, pto1632->punkThis32, pto1632->pphHolder, IidIdxString(pto1632->iidx))); #endif // // Determine if this is a 'special' object that we know we want // to release. If it is, then remove all of the references this // proxy has on it. // if (CoQueryReleaseObject(pto1632->punkThis32) == NOERROR) { thkDebugOut((DEB_WARN, "1632: %p is recognized Releasing object %d times\n", pto1632->punkThis32,pto1632->cRef)); while (pto1632->cRef) { IUnknown *punk; pto1632->cRef--; punk = pto1632->punkThis32; RELVDMPTR(vpv); if (punk->Release() == 0) { break; } pto1632 = FIXVDMPTR(vpv, THUNK1632OBJ); } } // Releases pointer RemoveProxy1632(vpv, pto1632); } thkDebugOut((DEB_ITRACE, "OUT CThkMgr::RemoveAllProxies()\n")); } // *** IUnknown methods *** //+--------------------------------------------------------------------------- // // Method: CThkMgr::QueryInterface // // Synopsis: QueryInterface on the thunkmanager itself // // Arguments: [riid] -- IID of interface to return // [ppvObj] -- Interface return // // Returns: HRESULT // // History: 6-01-94 JohannP (Johann Posch) Created // //---------------------------------------------------------------------------- STDMETHODIMP CThkMgr::QueryInterface (REFIID riid, LPVOID FAR* ppvObj) { if (IsBadWritePtr(ppvObj, sizeof(void *))) { return E_INVALIDARG; } *ppvObj = NULL; // There is no IID_IThunkManager because nobody needs it if (IsEqualIID(riid, IID_IUnknown)) { *ppvObj = (IUnknown *) this; AddRef(); return S_OK; } return E_NOINTERFACE; } //+--------------------------------------------------------------------------- // // Methode: CThkMgr::AddRef // // Synopsis: Adds a reference // // Returns: New ref count // // History: 6-01-94 JohannP (Johann Posch) Created // //---------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CThkMgr::AddRef () { InterlockedIncrement( &_cRefs ); return _cRefs; } //+--------------------------------------------------------------------------- // // Methode: CThkMgr::Release // // Synopsis: Releases a reference // // Returns: New ref count // // History: 6-01-94 JohannP (Johann Posch) Created // //---------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CThkMgr::Release() { if (InterlockedDecrement( &_cRefs ) == 0) { return 0; } return _cRefs; } // *** IThunkManager methods *** // // //+--------------------------------------------------------------------------- // // Method: CThkMgr::IsIIDRequested // // Synopsis: checks if given refiid was requested by WOW // // Arguments: [riid] -- refiid // // Returns: true if requested by 16 bit // // History: 6-01-94 JohannP (Johann Posch) Created // //---------------------------------------------------------------------------- STDMETHODIMP_ (BOOL) CThkMgr::IsIIDRequested(REFIID riid) { PIIDNODE piidnode = _piidnode; BOOL fRet = FALSE; while (piidnode) { if (*piidnode->piid == riid) { fRet = TRUE; break; } piidnode = piidnode->pNextNode; } thkDebugOut((DEB_THUNKMGR, "IsIIDRequested(%s) => %d\n", GuidString(&riid), fRet)); return fRet; } //+--------------------------------------------------------------------------- // // Member: CThkMgr::IsCustom3216Proxy, public // // Synopsis: Attempts to identify the given IUnknown as a 32->16 proxy // and also checks whether it is a thunked interface or not // // Arguments: [punk] - Object // // Returns: BOOL // // History: 11-Jul-94 DrewB Created // //---------------------------------------------------------------------------- STDMETHODIMP_(BOOL) CThkMgr::IsCustom3216Proxy(IUnknown *punk, REFIID riid) { return !IsIIDSupported(riid) && IsProxy3216(punk) != 0; } //+--------------------------------------------------------------------------- // // Method: CThkMgr::IsIIDSupported // // Synopsis: Return whether the given interface is thunked or not // // Arguments: [riid] -- Interface // // Returns: BOOL // // History: 6-01-94 JohannP (Johann Posch) Created // //---------------------------------------------------------------------------- BOOL CThkMgr::IsIIDSupported(REFIID riid) { return IIDIDX_IS_INDEX(IidToIidIdx(riid)); } //+--------------------------------------------------------------------------- // // Method: CThkMgr::AddIIDRequest // // Synopsis: adds the refiid to the request list // // Arguments: [riid] -- Interface // // Returns: true on success // // History: 6-01-94 JohannP (Johann Posch) Created // //---------------------------------------------------------------------------- BOOL CThkMgr::AddIIDRequest(REFIID riid) { PIIDNODE piidnode = _piidnode; thkAssert(!IsIIDSupported(riid)); // create a new node and add at front piidnode = (PIIDNODE)flRequestFreeList.AllocElement(); if (piidnode == NULL) { return FALSE; } piidnode->pNextNode = _piidnode; _piidnode = piidnode; // IID requests are only valid for the lifetime of the call that // requested a custom interface, so there's no need to copy // the IID's memory since it must remain valid for the same time // period piidnode->piid = (IID *)&riid; thkDebugOut((DEB_THUNKMGR, "AddIIDRequest(%s)\n", GuidString(&riid))); return TRUE; } //+--------------------------------------------------------------------------- // // Method: CThkMgr::RemoveIIDRequest // // Synopsis: removes a request for the request list // // Arguments: [riid] -- Interface // // Returns: true on success // // History: 6-01-94 JohannP (Johann Posch) Created // //---------------------------------------------------------------------------- void CThkMgr::RemoveIIDRequest(REFIID riid) { PIIDNODE piidnode; PIIDNODE pinPrev; thkAssert(!IsIIDSupported(riid)); pinPrev = NULL; piidnode = _piidnode; while (piidnode) { if (*piidnode->piid == riid) { break; } pinPrev = piidnode; piidnode = piidnode->pNextNode; } thkAssert(piidnode != NULL && "RemoveIIDRequest: IID not found"); thkDebugOut((DEB_THUNKMGR, "RemoveIIDRequest(%s)\n", GuidString(&riid))); if (pinPrev == NULL) { _piidnode = piidnode->pNextNode; } else { pinPrev->pNextNode = piidnode->pNextNode; } flRequestFreeList.FreeElement((DWORD)piidnode); } //+--------------------------------------------------------------------------- // // Method: CThkMgr::CanGetNewProxy1632 // // Synopsis: Preallocates proxy memory // // Arguments: [iidx] - Custom interface or known index // // Returns: vpv pointer if proxy is available, fails otherwise // // History: 6-01-94 JohannP (Johann Posch) Created // //---------------------------------------------------------------------------- VPVOID CThkMgr::CanGetNewProxy1632(IIDIDX iidx) { VPVOID vpv; THUNK1632OBJ UNALIGNED *pto; thkDebugOut((DEB_THUNKMGR, "%sIn CanGetNewProxy1632(%s)\n", NestingLevelString(), IidIdxString(iidx))); // Allocate proxy memory vpv = (VPVOID)flFreeList16.AllocElement(); if (vpv == NULL) { thkDebugOut((DEB_WARN, "WARNING: Failed to allocate memory " "for 16-bit proxies\n")); goto Exit; } // Add custom interface request if necessary if (vpv && IIDIDX_IS_IID(iidx)) { // add the request for the unknown interface if ( !AddIIDRequest(*IIDIDX_IID(iidx)) ) { flFreeList16.FreeElement( (DWORD)vpv ); vpv = 0; } } // Set up the preallocated proxy as a temporary proxy so that // we can hand it out for nested callbacks pto = FIXVDMPTR(vpv, THUNK1632OBJ); thkAssert(pto != NULL); pto->pfnVtbl = gdata16Data.atfnProxy1632Vtbl; pto->cRefLocal = 0; pto->cRef = 0; pto->iidx = iidx; pto->punkThis32 = NULL; pto->pphHolder = NULL; PprxNull(pto->pprxObject); pto->grfFlags = PROXYFLAG_TEMPORARY; #if DBG == 1 // Deliberately make this an invalid proxy. We want it to be used // in as few places as possible pto->dwSignature = PSIG1632TEMP; #endif RELVDMPTR(vpv); Exit: thkDebugOut((DEB_THUNKMGR, "%sOut CanGetNewProxy1632: %p\n", NestingLevelString(), vpv)); return vpv; } //+--------------------------------------------------------------------------- // // Method: CThkMgr::FreeNewProxy1632 // // Synopsis: frees unused preallocated proxies // // Arguments: [iidx] - Custom interface or known index // // History: 6-01-94 JohannP (Johann Posch) Created // //---------------------------------------------------------------------------- void CThkMgr::FreeNewProxy1632(VPVOID vpv, IIDIDX iidx) { thkDebugOut((DEB_THUNKMGR, "%sIn FreeNewProxy1632(%s)\n", NestingLevelString(), IidIdxString(iidx))); thkAssert(vpv != 0); if (IIDIDX_IS_IID(iidx)) { // remove the request for the unknown interface RemoveIIDRequest(*IIDIDX_IID(iidx)); } #if DBG == 1 // Ensure that we're not getting rid of a temporary proxy that's // in use THUNK1632OBJ UNALIGNED *pto; pto = FIXVDMPTR(vpv, THUNK1632OBJ); if (pto->grfFlags & PROXYFLAG_TEMPORARY) { thkAssert(pto->cRefLocal == 0 && pto->cRef == 0); } RELVDMPTR(vpv); #endif // add element to free list flFreeList16.FreeElement( (DWORD)vpv ); thkDebugOut((DEB_THUNKMGR, "%sOut FreeNewProxy1632\n", NestingLevelString())); } //+--------------------------------------------------------------------------- // // Method: CThkMgr::IsProxy1632 // // Synopsis: checks if given object is an 16/32 object // // Arguments: [vpvObj16] -- Object to check // // Returns: 32-bit object being proxied or NULL // // History: 6-01-94 JohannP (Johann Posch) Created // //---------------------------------------------------------------------------- IUnknown *CThkMgr::IsProxy1632(VPVOID vpvObj16) { VPVOID vpvProxy; DWORD dwKey; POSITION pos; THUNK1632OBJ UNALIGNED *pto; THUNKINFO ti; // First check and see if the vtable pointer is the one for // 16-bit proxies. If it's not, this can't be a proxy // Since we don't know anything about this pointer, we need // to do safe translation pto = (THUNK1632OBJ UNALIGNED *) GetReadPtr16(&ti, vpvObj16, sizeof(THUNK1632OBJ)); if (pto != NULL && pto->pfnVtbl == gdata16Data.atfnProxy1632Vtbl) { // The proxy may be freed memory or just random memory which // happens to have the right value, so make sure that it's // a proxy by looking it up in the proxy table pos = _pProxyTbl1632->GetStartPosition(); while (pos) { _pProxyTbl1632->GetNextAssoc(pos, dwKey, (void FAR* FAR&) vpvProxy); if (vpvProxy == vpvObj16) { RELVDMPTR(vpvObj16); return (IUnknown *)dwKey; } } // Check to see if we're returning no for what we think is // a valid proxy // It's possible for this to occur if somebody made a copy // of a proxy's memory, but in general this assert should // be extremely unlikely thkAssert(pto->dwSignature != PSIG1632); } if (pto != NULL) { RELVDMPTR(vpvObj16); } return NULL; } //+--------------------------------------------------------------------------- // // Method: CThkMgr::FindProxy1632 // // Synopsis: retrieves a 16/32 object (most cases proxy) for a given // 32 bit IUnknown, it can be a real object -> shortcut // // Arguments: [vpvPrealloc] -- preallocated proxy // [punkThis32] -- 32 bit object to be proxied // [iidx] - Interface index or IID // [pfst] - Return what kind of object was found // // Returns: 16/32 object (proxy or real object) // // History: 6-01-94 JohannP (Johann Posch) Created // //---------------------------------------------------------------------------- VPVOID CThkMgr::FindProxy1632(VPVOID vpvPrealloc, IUnknown *punkThis32, IIDIDX iidx, DWORD *pfst) { THUNK1632OBJ UNALIGNED *pto; VPVOID vpv; thkDebugOut((DEB_THUNKMGR, "%sIn FindProxy1632(%p, %p, %s)\n", NestingLevelString(), vpvPrealloc, punkThis32, IidIdxString(iidx))); DebugIncrementNestingLevel(); thkAssert(punkThis32 != NULL); #if DBG == 1 // Ensure that we're not reusing a temporary proxy that's in use if (vpvPrealloc) { pto = FIXVDMPTR(vpvPrealloc, THUNK1632OBJ); if (pto->grfFlags & PROXYFLAG_TEMPORARY) { thkAssert(pto->cRefLocal == 0 && pto->cRef == 0); } RELVDMPTR(vpvPrealloc); } #endif // If we preallocated a proxy with an IID then a request was added // in CanGetNewProxy. Clean it up now if (vpvPrealloc != 0 && IIDIDX_IS_IID(iidx)) { RemoveIIDRequest(*IIDIDX_IID(iidx)); } // Check the proxy table for an existing proxy for the given object pointer // the 32 bit pointer is the key to the 16/32 proxy vpv = LookupProxy1632(punkThis32); if (vpv != NULL) { thkDebugOut((DEB_THUNKMGR, "%sFindProxy1632 found existing proxy,(%p)->%p\n", NestingLevelString(), punkThis32, vpv)); // We found an existing proxy, so reuse it pto = FIXVDMPTR(vpv, THUNK1632OBJ); // If a proxy's refcount is zero, it must be part of an aggregate thkAssert(pto->cRefLocal > 0 || (pto->pphHolder != NULL && (pto->pphHolder->dwFlags & PH_AGGREGATE) != 0)); //Note: IIDIDXs are related to interfaces in our tables // we have our table organized such that more derived // interfaces are higher than less derived // * Custom interfaces will have an IID rather than an index // and will never be promoted above IUnknown in the // below statement (johannp) if (IIDIDX_IS_INDEX(iidx) && IIDIDX_INDEX(iidx) > IIDIDX_INDEX(pto->iidx)) { // 16-bit proxy vtables are all the same so there's no // need to manipulate the vtable pointer here as we // do in the 32-bit case pto->iidx = iidx; } RELVDMPTR(vpv); // AddRef the proxy we found since we're passing out a new reference AddRefProxy1632(vpv); if (pfst) { *pfst = FST_USED_EXISTING; } goto Exit; } // Check and see whether the object we're supposed to proxy is // actually a proxy itself if ( (vpv = IsProxy3216(punkThis32)) != NULL) { thkDebugOut((DEB_THUNKMGR, "%sFindProxy1632 shortcut proxy,(%p)->%p\n", NestingLevelString(), punkThis32, vpv)); // We've discovered that the object that we're supposed to // proxy is actually a proxy itself. In that case, we can // avoid creating a full-circle proxy chain by returning // the real pointer rather than creating a new proxy // // If we're shortcutting proxies for in parameters, we // don't need to manipulate the reference count // In the out parameter case, though, we're actually transferring // ownership so we need to AddRef the real object and clean // up the proxy we shortcut around if (IsOutParamObj()) { THKSTATE thkstate; // We want to temporarily suspend our out state since // we want this AddRef to really occur if it comes // back to a proxy thkstate = GetThkState(); SetThkState(THKSTATE_NOCALL); AddRefOnObj16(vpv); SetThkState(thkstate); // Release the ignored proxy // This avoids leaking proxies in round-trip calls // where nobody holds a pointer to the proxy ReleaseProxy3216((THUNK3216OBJ *)punkThis32); } if (pfst) { *pfst = FST_SHORTCUT; } goto Exit; } // We didn't find an existing proxy and the object to be proxied // is a real object so we need to fill out a new proxy for it // We might have a preallocated proxy provided; if we don't // we need to go to the free list and get a new one if (vpvPrealloc != NULL) { vpv = vpvPrealloc; // If we successfully created a proxy using the preallocated // proxy, mark the preallocated proxy as used so it's not cleaned up vpvPrealloc = NULL; } else { vpv = (VPVOID)flFreeList16.AllocElement(); } if (vpv != NULL) { // Put the new proxy in the proxy list if (!_pProxyTbl1632->SetAt((DWORD)punkThis32, (void *&)vpv)) { // Note that we can put vpv on the free list even it's // the preallocated proxy since that's what the prealloc // cleanup does flFreeList16.FreeElement(vpv); vpv = NULL; goto Exit; } if (IIDIDX_IS_IID(iidx)) { // We're creating a proxy for a custom interface // so just hand out an IUnknown iidx = INDEX_IIDIDX(THI_IUnknown); } pto = FIXVDMPTR(vpv, THUNK1632OBJ); thkAssert(pto != NULL); pto->pfnVtbl = gdata16Data.atfnProxy1632Vtbl; pto->cRefLocal = 1; pto->cRef = (IsOutParamObj()) ? 1 : 0; pto->iidx = iidx; pto->punkThis32 = punkThis32; pto->pphHolder = NULL; PprxNull(pto->pprxObject); pto->grfFlags = PROXYFLAG_NORMAL; #if DBG == 1 pto->dwSignature = PSIG1632; #endif RELVDMPTR(vpv); if (pfst) { *pfst = FST_CREATED_NEW; } thkDebugOut((DEB_THUNKMGR, "%sFindProxy1632 added new proxy, %s (%p)->%p (%d,%d)\n", NestingLevelString(), inInterfaceNames[pto->iidx].pszInterface, punkThis32, vpv, pto->cRefLocal, pto->cRef)); } Exit: // If we didn't use the preallocated proxy for some reason // then put it back on the free list if (vpvPrealloc != NULL) { flFreeList16.FreeElement( (DWORD)vpvPrealloc ); } DebugDecrementNestingLevel(); thkDebugOut((DEB_THUNKMGR, "%sOut FindProxy1632: (%p)->%p\n", NestingLevelString(), punkThis32, vpv)); return vpv; } //+--------------------------------------------------------------------------- // // Method: CThkMgr::FindAggregate1632 // // Synopsis: retrieves an aggregate for 1632 with the given cntrl. unknown // // Arguments: [vpvPrealloc] - Preallocated proxy or NULL // [punkOuter3216] -- the controlling unknown // [punkThis32] -- the 32 bit interface - key // [iidx] -- Index or IID of interface // // Returns: 16/32 proxy object // // History: 6-01-94 JohannP (Johann Posch) Created // //---------------------------------------------------------------------------- VPVOID CThkMgr::FindAggregate1632(VPVOID vpvPrealloc, IUnknown *punkOuter3216, IUnknown *punkThis32, IIDIDX iidx) { THUNK1632OBJ UNALIGNED *pto1632; VPVOID vpv; DWORD fst; BOOL fMarkPUnk1632 = FALSE; thkDebugOut((DEB_THUNKMGR, "%sIn FindAggregate1632(%p, %p, %p, %s)\n", NestingLevelString(), vpvPrealloc, punkOuter3216, punkThis32, IidIdxString(iidx))); DebugIncrementNestingLevel(); thkAssert(punkOuter3216 != NULL && punkThis32 != NULL); // Get back an object for the object to be proxied // This may be a proxy or a real object from a shortcut vpv = FindProxy1632(vpvPrealloc, punkThis32, iidx, &fst); if (vpv == 0) { goto Exit; } // If we got an object and it's not a proxy, we're done // There's nothing we can do since we can't link a real object to // a holder; we can only hope that things work out right if (fst & FST_OBJECT_STATUS) { goto Exit; } // Otherwise, we need to set up a holder for whatever proxies we // have THUNK3216OBJ *ptoUnkOuter3216; PROXYHOLDER *pph; VPVOID vpvProxiedUnkOuter3216; // Determine whether the outer unknown is a proxy or not vpvProxiedUnkOuter3216 = IsProxy3216(punkOuter3216); // This cast is only valid if vpvProxiedUnkOuter3216 is non-NULL ptoUnkOuter3216 = (THUNK3216OBJ *)punkOuter3216; if (vpvProxiedUnkOuter3216 != 0 && ptoUnkOuter3216->pphHolder != NULL) { // Use the existing holder if there is one pph = ptoUnkOuter3216->pphHolder; } else { // Create a new holder pph = NewHolder(PH_AGGREGATE); if (pph == NULL) { FreeProxy1632(punkThis32); vpv = NULL; goto Exit; } // If the outer unknown is a proxy we know its holder hasn't // been set, so add it to the holder we created if (vpvProxiedUnkOuter3216 != 0) { AddProxyToHolder(pph, ptoUnkOuter3216, Pprx32(ptoUnkOuter3216)); // Mark the pUnkOuter3216 as such; needed for aggregation rules thkDebugOut((DEB_THUNKMGR, "%s FindAggregate1632,(%p)->%p marked as pUnkOuter3216\n", NestingLevelString(), ptoUnkOuter3216,Pprx32(ptoUnkOuter3216) )); ptoUnkOuter3216->grfFlags |= PROXYFLAG_PUNKOUTER; fMarkPUnk1632 = TRUE; } } thkAssert(vpvProxiedUnkOuter3216 == 0 || ptoUnkOuter3216->pphHolder == pph); // Add the new interface to the holder // Since this proxy was just created, we know its holder // hasn't been set yet pto1632 = FIXVDMPTR(vpv, THUNK1632OBJ); AddProxyToHolder(pph, pto1632, Pprx16(vpv)); if (fMarkPUnk1632) { pto1632->grfFlags |= PROXYFLAG_PUNK; thkDebugOut((DEB_THUNKMGR, "%s FindAggregate1632,(%p)->%p marked as pUnk1632\n", NestingLevelString(), punkThis32, vpv)); } RELVDMPTR(vpv); Exit: DebugDecrementNestingLevel(); thkDebugOut((DEB_THUNKMGR, "%sOut FindAggregate1632,(%p)->%p\n", NestingLevelString(), punkThis32, vpv)); return vpv; } //+--------------------------------------------------------------------------- // // Method: CThkMgr::QueryInterfaceProxy1632 // // Synopsis: QueryInterface on 32 bit object // // Arguments: [vpvThis16] -- Proxy // [refiid] -- IID // [ppv] -- new object (proxy or real object) for queried // interface // // Returns: HRESULT // // History: 6-01-94 JohannP (Johann Posch) Created // //---------------------------------------------------------------------------- SCODE CThkMgr::QueryInterfaceProxy1632(VPVOID vpvThis16, REFIID refiidIn, LPVOID *ppv) { SCODE scRet; THUNK1632OBJ UNALIGNED *ptoThis; THUNK1632OBJ UNALIGNED *ptoProxy; VPVOID vpvProxy; IIDIDX iidx; IUnknown *punk32, *punkThis32; DWORD fst; BOOL fNotSupported = FALSE; thkDebugOut((DEB_THUNKMGR, "%sIn QueryInterfaceProxy1632(%p)\n", NestingLevelString(), vpvThis16)); DebugIncrementNestingLevel(); ptoThis = FIXVDMPTR(vpvThis16, THUNK1632OBJ); thkAssert(ptoThis != NULL); // Don't validate temporary proxies // We need to support temporary proxies in this method since // Corel Draw 5.0 QI's on a temporary proxy // // BUGBUG - There are many potential problems with object identity, // for example QI'ing where the return is the same object as the // souce. Since the source is temporary it doesn't exist in the // tables so identity will be broken. Of course, this won't cause // any regressions for apps which don't use temporary proxies, // so I think this is acceptable if ((ptoThis->grfFlags & PROXYFLAG_TEMPORARY) == 0) { DebugValidateProxy1632(vpvThis16); } else { thkDebugOut((DEB_WARN, "WARNING: QueryInterfaceProxy1632 on " "temporary %s proxy\n", IidIdxString(ptoThis->iidx))); } *ppv = NULL; // Note: Ikitaro queries for IViewObject and uses it as IViewObject2 REFIID refiid = ( (TlsThkGetAppCompatFlags() & OACF_IVIEWOBJECT2) && IsEqualIID(refiidIn, IID_IViewObject)) ? IID_IViewObject2 : refiidIn; #if DBG==1 if ( (TlsThkGetAppCompatFlags() & OACF_IVIEWOBJECT2) && IsEqualIID(refiidIn, IID_IViewObject)) { thkDebugOut((DEB_WARN,"Ikitaro: return IViewObject2 instead IViewObject\n")); } #endif // DBG==1 iidx = IidToIidIdx(refiid); // see if this a supported interface if (IIDIDX_IS_IID(iidx)) { // add the request for the unknown interface if (!AddIIDRequest(refiid)) { RELVDMPTR(vpvThis16); return E_OUTOFMEMORY; } fNotSupported = TRUE; thkDebugOut((DEB_THUNKMGR, "%sQueryInterfaceProxy1632: unknown iid %s\n", NestingLevelString(), IidIdxString(iidx))); } // We force the object we're QI'ing to have a holder so that // all objects have object refcounting. This should only be // necessary for aggregation but it seems that some apps rely // on all objects having aggregation-like refcounting qualities // BobDay identified PowerPoint as one // We only want to do this in cases where we've identified it's // necessary, which presently is only for // IDataObject // so we only do it then if (ptoThis->pphHolder == NULL && (ptoThis->grfFlags & PROXYFLAG_TEMPORARY) == 0 && IsEqualIID(refiid, IID_IDataObject)) { PROXYHOLDER *pph; pph = NewHolder(PH_NONAGGREGATE); if (pph == NULL) { RELVDMPTR(vpvThis16); scRet = E_OUTOFMEMORY; goto Exit; } AddProxyToHolder(pph, ptoThis, Pprx16(vpvThis16)); // It's not necessary to clean this up if later calls fail // since it doesn't alter the lifetime of the proxy if there's // only one proxy for the holder } if (ptoThis->grfFlags & PROXYFLAG_TEMPORARY) { punkThis32 = *(IUnknown **)ptoThis->punkThis32; } else { punkThis32 = ptoThis->punkThis32; } RELVDMPTR(vpvThis16); if (punkThis32 == NULL) { scRet = E_NOINTERFACE; goto Exit; } thkDebugOut((DEB_THUNKMGR, "%sQueryInterfaceProxy1632: on iid %s\n", NestingLevelString(), IidIdxString(iidx))); scRet = punkThis32->QueryInterface(refiid, (void **)&punk32); if (FAILED(scRet)) { goto Exit; } SetThkState(THKSTATE_INVOKETHKOUT16); vpvProxy = FindProxy1632(NULL, punk32, iidx, &fst); if (vpvProxy == NULL) { // we were unable to create a proxy for the new interface so // clean up the interface and quit punk32->Release(); scRet = E_OUTOFMEMORY; goto ResetState; } if (fNotSupported && !(fst & FST_SHORTCUT)) { // proxy of unknow interface can not be promoted // clean up the interface and quit ReleaseProxy1632(vpvProxy); scRet = E_NOINTERFACE; goto ResetState; } *ppv = (LPVOID)vpvProxy; // If we're returning a proxy, we need to make sure that // it is listed in the proxy holder for this object if (fst & FST_PROXY_STATUS) { // We are returning a proxy. If its holder isn't set, // add it to the holder of the object that was QI'ed // Reconvert 16:16 pointer since calls may have caused // nested calls and flat remapping ptoThis = FIXVDMPTR(vpvThis16, THUNK1632OBJ); ptoProxy = FIXVDMPTR(vpvProxy, THUNK1632OBJ); if (ptoProxy->pphHolder == NULL) { if (ptoThis->pphHolder != NULL) { AddProxyToHolder(ptoThis->pphHolder, ptoProxy, Pprx16(vpvProxy)); } } else if (ptoThis->pphHolder == NULL && (ptoThis->grfFlags & PROXYFLAG_TEMPORARY) == 0) { // ptoThis may not have a holder because it was produced // by a non-QI method such as IOleItemContainer::GetObject // If we find that an interface returned by it does // have a holder, hook it up to the holder // It shouldn't be necessary to do anything unusual with // local references even if ptoThis is really part of an // aggregate since ptoThis must have been produced by // a method where aggregation can't be assumed and all // references must be released on ptoThis itself AddProxyToHolder(ptoProxy->pphHolder, ptoThis, Pprx16(vpvThis16)); } #if DBG == 1 // It's possible for holders to not match because of the above // case with interfaces being returned from non-QI methods // The lifetime for such interfaces must be defined by // strong references, though, so it's not catastrophic // Still, we'd like to be aware of such mismatches just in case if (ptoProxy->pphHolder != ptoThis->pphHolder) { thkDebugOut((DEB_WARN, "WARNING: QueryInterfaceProxy1632: " "this %p has holder %p, proxy %p has holder %p\n", vpvThis16, ptoThis->pphHolder, vpvProxy, ptoProxy->pphHolder)); } #endif RELVDMPTR(vpvThis16); RELVDMPTR(vpvProxy); } ResetState: SetThkState(THKSTATE_NOCALL); Exit: // Clean up our custom interface request if there is one if (IIDIDX_IS_IID(iidx)) { RemoveIIDRequest(refiid); } DebugDecrementNestingLevel(); thkDebugOut((DEB_THUNKMGR, "%sOut QueryInterfaceProxy1632(%p) => %p, 0x%08lX\n", NestingLevelString(), vpvThis16, *ppv, scRet)); return scRet; } //+--------------------------------------------------------------------------- // // Member: CThkMgr::LocalAddRefProxy, public // // Synopsis: Increment a proxy's local refcount // // Arguments: [pprx] - Proxy // // History: 02-Aug-94 DrewB Created // //---------------------------------------------------------------------------- void CThkMgr::LocalAddRefProxy(CProxy *pprx) { pprx->cRefLocal++; thkDebugOut(( DEB_THUNKMGR, "%s LocalAddRefProxy1632 <%08lX> RefCounts: %d,%d\n", NestingLevelString(), pprx, pprx->cRefLocal, pprx->cRef )); // Check for proxies rising from the dead // If we're not part of an aggregate our refcount shouldn't be // one or lower. If it is we're reviving a dead proxy which won't // be in the proxy list and this could cause problems // // Note: With the new proxy stabilization code this can and does // happen so this is only a debug out #if DBG == 1 if (!(pprx->cRefLocal > 1 || (pprx->pphHolder != NULL && (pprx->pphHolder->dwFlags & PH_AGGREGATE) != 0))) { thkDebugOut((DEB_WARN, "WARNING: Proxy %p unlisted with refs %d,%d\n", pprx, pprx->cRefLocal, pprx->cRef)); } #endif if (pprx->cRefLocal == 1) { // We just resurrected a proxy with a zero refcount, // so increment its holder's proxy count since it // was decremented when the proxy released to zero if (pprx->pphHolder != NULL) { AddRefHolder(pprx->pphHolder); } } } //+--------------------------------------------------------------------------- // // Member: CThkMgr::LockProxy, public // // Synopsis: Locks a proxy so that it can't be freed // // Arguments: [pprx] - Proxy // // History: 11-Aug-94 DrewB Created // //---------------------------------------------------------------------------- void CThkMgr::LockProxy(CProxy *pprx) { pprx->grfFlags |= PROXYFLAG_LOCKED; } //+--------------------------------------------------------------------------- // // Method: CThkMgr::AddRefProxy1632 // // Synopsis: addrefs proxy object - delegate call on to real object // // Arguments: [vpvThis16] -- 16/32 proxy // // Returns: local refcount // // History: 6-01-94 JohannP (Johann Posch) Created // // Notes: AddRef rules // * cRef is the addref passed on to the real object // * cRefLocal is the addref collected locally // - the refcount can be 0 if the object was created as on in-param //---------------------------------------------------------------------------- DWORD CThkMgr::AddRefProxy1632(VPVOID vpvThis16) { THUNK1632OBJ UNALIGNED *ptoThis; BOOL fAggregate; LONG cRef; thkDebugOut((DEB_THUNKMGR, "%sIn AddRefProxy1632(%p)\n", NestingLevelString(), vpvThis16)); DebugIncrementNestingLevel(); DebugValidateProxy1632(vpvThis16); ptoThis = FIXVDMPTR(vpvThis16, THUNK1632OBJ); thkDebugOut(( DEB_THUNKMGR, "%s AddRefProxy1632 %08lX RefCounts: %d,%d\n", NestingLevelString(), vpvThis16, ptoThis->cRefLocal, ptoThis->cRef )); // Always increment the proxy local refcount LocalAddRefProxy(ptoThis); // Aggregations rely on all reference counts being forwarded on // to the controlling unknown. Therefore, if we have a proxy // that is part of an aggregate, we must ensure that the proxy // doesn't collect references locally. If it did, they would // not be passed on to the controlling unknown (via the real object) // and the controlling unknown's refcount would be too low if (ptoThis->pphHolder == NULL) { fAggregate = FALSE; } else { fAggregate = (ptoThis->pphHolder->dwFlags & PH_AGGREGATE) != 0; } if (IsOutParamObj()) { // If we're on the way out we're assuming that the object // given to us has its own reference so we bump cRef to // indicate that but we don't call the real object ptoThis->cRef++; } else if (ptoThis->cRef == 0 || fAggregate) { DWORD dwRet; IUnknown *punk; // It's also necessary to pass on real references when the // ref count is zero. This handles the case where an // in parameter, created as 1,0, is AddRef'ed after // its creation, in which case the reference needs to // be passed on to the real object so that the proxy has // at least one real reference since it will stay alive ptoThis->cRef++; punk = ptoThis->punkThis32; RELVDMPTR(vpvThis16); dwRet = punk->AddRef(); thkDebugOut((DEB_THUNKMGR, "%s AddRefProxy1632: AddRef called on (%p):%ld\n", NestingLevelString(), punk, dwRet)); // Reconvert 16:16 pointer since real AddRef may have caused // nested calls and flat remapping ptoThis = FIXVDMPTR(vpvThis16, THUNK1632OBJ); } else { // Just a local addref } DebugDecrementNestingLevel(); thkDebugOut((DEB_THUNKMGR, "%sOut AddRefProxy1632(%p), (%ld,%ld)\n", NestingLevelString(), vpvThis16, ptoThis->cRefLocal, ptoThis->cRef)); cRef = ptoThis->cRefLocal; RELVDMPTR(vpvThis16); return cRef; } //+--------------------------------------------------------------------------- // // Method: CThkMgr::ReleaseProxy1632 // // Synopsis: release on 16/32 proxy - delegate call on to real object // // Arguments: [vpvThis16] -- proxy // // Returns: local refcount // // History: 6-01-94 JohannP (Johann Posch) Created // //---------------------------------------------------------------------------- DWORD CThkMgr::ReleaseProxy1632(VPVOID vpvThis16) { THUNK1632OBJ UNALIGNED *ptoThis; PROXYHOLDER *pph; LONG cRef, cRefLocal; thkDebugOut((DEB_THUNKMGR, "%sIn ReleaseProxy1632(%p)\n", NestingLevelString(), vpvThis16)); DebugIncrementNestingLevel(); DebugValidateProxy1632(vpvThis16); ptoThis = FIXVDMPTR(vpvThis16, THUNK1632OBJ); // There are cases where releasing the real object causes // an entire object to go away so the proxy is gone after // that call. Fortunately these cases only occur when // cRef == cRefLocal == 0, so we can avoid problems by // copying them locally cRef = ptoThis->cRef; cRefLocal = ptoThis->cRefLocal; thkDebugOut(( DEB_THUNKMGR, "%s ReleaseProxy1632 %08lX RefCounts: %d,%d\n", NestingLevelString(), vpvThis16, ptoThis->cRefLocal, ptoThis->cRef )); if (cRef <= 0 && cRefLocal == cRef) { thkDebugOut((DEB_ERROR, "ERROR: ReleaseProxy1632(%p) cRef: %d; cRef: %d\n", vpvThis16, ptoThis->cRef, ptoThis->cRefLocal)); goto Done; } // If our local refcount is the same as the count of references // that we've passed on to the object, then we need to pass // on this release to the real object if (ptoThis->cRef == ptoThis->cRefLocal) { DWORD dwRet; IUnknown *punk; #if DBG == 1 // We'd like to assert this but some apps (Works is one) // release an aggregated object too many times through one // interface. The overall aggregate refcount is ok, though, // so this doesn't cause a problem // thkAssert(ptoThis->cRef > 0); if (ptoThis->cRef <= 0) { thkDebugOut((DEB_WARN, "WARNING: ReleaseProxy1632(%p) cRef: %d\n", vpvThis16, ptoThis->cRef)); } #endif // Use local cRef here for safety if (cRef > 0) { // Decrement cRef after making the real call to ensure that // the proxy lives throughout the call --ptoThis->cRef; } punk = ptoThis->punkThis32; RELVDMPTR(vpvThis16); // check if this is an pUnk proxy in an aggregation // if so mark the pUnkOuter for cleanup if (ptoThis->grfFlags & PROXYFLAG_PUNK) { thkDebugOut((DEB_THUNKMGR, "%s ReleaseProxy1632: Release called on (%p)->%p\n", NestingLevelString(), punk, vpvThis16)); pph = ptoThis->pphHolder; pph->dwFlags |= PH_AGGREGATE_RELEASE; } // Decremente cRefLocal to prevent loops in release --ptoThis->cRefLocal; dwRet = punk->Release(); // Refresh pointer ptoThis = FIXVDMPTR(vpvThis16, THUNK1632OBJ); // Increment cRefLocal after making the real call to ensure that // the proxy lives throughout the call ++ptoThis->cRefLocal; // rese the aggreagation flag if (ptoThis->grfFlags & PROXYFLAG_PUNK) { pph = ptoThis->pphHolder; pph->dwFlags &= !PH_AGGREGATE_RELEASE; } thkDebugOut((DEB_THUNKMGR, "%s ReleaseProxy1632: Release called on (%p):%ld \n", NestingLevelString(), ptoThis->punkThis32, dwRet)); } // Now that we've handled the real object's refcount, decrement // the proxy's refcount and clean it up if necessary // We need to use the local cRefLocal in case the proxy has gone away #if DBG == 1 // We'd like to assert this but some apps (Works is one) // release an aggregated object too many times through one // interface. The overall aggregate refcount is ok, though, // so this doesn't cause a problem thkAssert(cRefLocal > 0); if (cRefLocal <= 0) { thkDebugOut((DEB_WARN, "WARNING: ReleaseProxy1632(%p) cRefLocal: %d\n", vpvThis16, cRefLocal)); } #endif if (cRefLocal <= 0) { ptoThis = NULL; } else if (--ptoThis->cRefLocal == 0) { // Proxies that have no outer unknown can be cleaned // up immediately. If they do have an outer unknown then // they must live as long as the entire object lives, // so we don't clean them up here. They'll be cleaned up // when the object dies pph = ptoThis->pphHolder; if (pph) { // If this proxy isn't part of an aggregate, remove it // from the proxy list so it can't be reused // The only thing this proxy will be good for is // calling through if ((pph->dwFlags & PH_AGGREGATE) == 0) { _pProxyTbl1632->RemoveKey((DWORD)ptoThis->punkThis32); } RELVDMPTR(vpvThis16); // We have a holder, so notify it that one of its // proxies just died // This can cause cleanup of all proxies if the // holder releases to zero ReleaseHolder(pph); } else { // We don't have a holder so we can clean up this proxy // immediately // Releases pointer RemoveProxy1632(vpvThis16, ptoThis); } ptoThis = NULL; DBG_DUMP(DebugDump1632()); } Done: DebugDecrementNestingLevel(); thkDebugOut((DEB_THUNKMGR, "%sOut ReleaseProxy1632(%p) => %d,%d\n", NestingLevelString(), vpvThis16, ptoThis ? ptoThis->cRefLocal : 0, ptoThis ? ptoThis->cRef : 0)); if (ptoThis) { cRef = ptoThis->cRefLocal; RELVDMPTR(vpvThis16); } else { cRef = 0; } return cRef; } //+--------------------------------------------------------------------------- // // Method: CThkMgr::FreeProxy1632 // // Synopsis: frees object for given pUnk (key) // // Arguments: [punkThis32] -- 32 bit unknown - key // // Returns: Refcount // // History: 6-01-94 JohannP (Johann Posch) Created // //---------------------------------------------------------------------------- DWORD CThkMgr::FreeProxy1632(IUnknown *punkThis32) { thkDebugOut((DEB_THUNKMGR, "%sIn FreeProxy1632(%p)\n", NestingLevelString(), punkThis32)); DebugIncrementNestingLevel(); thkAssert(punkThis32 != NULL && "FreeProxy1632: invalid object pointer."); DWORD dwRet = 0; VPVOID vpv; vpv = LookupProxy1632(punkThis32); if (vpv != NULL) { thkDebugOut((DEB_THUNKMGR, "%sFreeProxy1632(%p) found existing proxy %p\n", NestingLevelString(), punkThis32, vpv)); // punkThis32 is a proxy and not a real object, so release it dwRet = ReleaseProxy1632(vpv); } DebugDecrementNestingLevel(); thkDebugOut((DEB_THUNKMGR, "%sOut FreeProxy1632(%p):%ld \n", NestingLevelString(), punkThis32, dwRet)); return dwRet; } //+--------------------------------------------------------------------------- // // Member: CThkMgr::RemoveProxy1632, public // // Synopsis: Destroys the given proxy // // Arguments: [vpv] - 16-bit proxy pointer // [pto] - Flat proxy pointer // // History: 11-Aug-94 DrewB Created // // Notes: Unfixes fixed pointer passed in // //---------------------------------------------------------------------------- void CThkMgr::RemoveProxy1632(VPVOID vpv, THUNK1632OBJ *pto) { _pProxyTbl1632->RemoveKey((DWORD)pto->punkThis32); if ((pto->grfFlags & PROXYFLAG_LOCKED) == 0) { #if DBG == 1 pto->dwSignature = PSIG1632DEAD; #endif RELVDMPTR(vpv); #if DBG == 1 if (!fSaveProxy) #endif { flFreeList16.FreeElement((DWORD)vpv); } } else { RELVDMPTR(vpv); } } //+--------------------------------------------------------------------------- // // Method: CThkMgr::CanGetNewProxy3216 // // Synopsis: checks if new proxy is available // // Arguments: [iidx] - Custom interface or known index // // Returns: Preallocated proxy or NULL // // History: 6-01-94 JohannP (Johann Posch) Created // //---------------------------------------------------------------------------- THUNK3216OBJ *CThkMgr::CanGetNewProxy3216(IIDIDX iidx) { thkDebugOut((DEB_THUNKMGR, "%sIn CanGetNewProxy3216(%s)\n", NestingLevelString(), IidIdxString(iidx))); LPVOID pvoid; pvoid = (LPVOID)flFreeList32.AllocElement(); if ( pvoid == NULL) { thkDebugOut((DEB_WARN, "WARNING: CThkMgr::CanGetNewProxy3216, " "AllocElement failed\n")); return NULL; } // check if the proxy is requested for a no-thop-interface if (pvoid && IIDIDX_IS_IID(iidx)) { // add the request for the unknown interface if ( !AddIIDRequest(*IIDIDX_IID(iidx)) ) { flFreeList32.FreeElement( (DWORD)pvoid ); pvoid = NULL; } } thkDebugOut((DEB_THUNKMGR, "%sOut CanGetNewProxy3216: %p \n", NestingLevelString(), pvoid)); return (THUNK3216OBJ *)pvoid; } //+--------------------------------------------------------------------------- // // Method: CThkMgr::FreeNewProxy3216 // // Synopsis: frees previous reserved proxy // // Arguments: [pto] - Proxy // [iidx] - Custom interface or known index // // History: 6-01-94 JohannP (Johann Posch) Created // //---------------------------------------------------------------------------- void CThkMgr::FreeNewProxy3216(THUNK3216OBJ *pto, IIDIDX iidx) { thkDebugOut((DEB_THUNKMGR, "%sIn FreeNewProxy3216(%p, %s)\n", NestingLevelString(), pto, IidIdxString(iidx))); thkAssert(pto != NULL); if (IIDIDX_IS_IID(iidx)) { // add the request for the unknown interface RemoveIIDRequest(*IIDIDX_IID(iidx)); } thkAssert(pto != NULL); flFreeList32.FreeElement( (DWORD)pto ); thkDebugOut((DEB_THUNKMGR, "%sOut FreeNewProxy3216\n", NestingLevelString())); } //+--------------------------------------------------------------------------- // // Method: CThkMgr::IsProxy3216 // // Synopsis: checks if the given object is a 32/16 proxy // // Arguments: [punk] -- punk of 32 bit object // // Returns: Object being proxied or NULL // // History: 6-01-94 JohannP (Johann Posch) Created // //---------------------------------------------------------------------------- VPVOID CThkMgr::IsProxy3216(IUnknown *punk) { LPVOID pvVtbl, pvFn; THUNK3216OBJ *pto3216; // First check the initial entry in the vtable // If it's not QueryInterfaceProxy3216 then this can't possibly // be a 32/16 proxy pvVtbl = *(void **)punk; pvFn = *(void **)pvVtbl; if (pvFn == ::QueryInterfaceProxy3216) { DWORD dwKey; POSITION pos; // This object has a proxy's vtable but it may be dead, copied // or coincidentally correct random memory, so look for it in // the table pos = _pProxyTbl3216->GetStartPosition(); while (pos) { _pProxyTbl3216->GetNextAssoc(pos, dwKey, (void FAR* FAR&) pto3216); if (pto3216 == (THUNK3216OBJ *)punk) { return (VPVOID)dwKey; } } // Check to see if we're returning no for what we think is // a valid proxy // It's possible for this to occur but it's very unlikely thkAssert(pto3216->dwSignature != PSIG3216); } return 0; } //+--------------------------------------------------------------------------- // // Method: CThkMgr::FindProxy3216 // // Synopsis: retrieves a 32/16 proxy // // Arguments: [ptoPrealloc] - Preallocated proxy or NULL // [vpvThis16] -- 16 bit object (key) // [iidx] - Custom interface or known index // [pfst] - Status return // // Returns: pointer to 32/16 proxy or real object // // History: 6-01-94 JohannP (Johann Posch) Created // //---------------------------------------------------------------------------- IUnknown *CThkMgr::FindProxy3216(THUNK3216OBJ *ptoPrealloc, VPVOID vpvThis16, IIDIDX iidx, DWORD *pfst) { IUnknown *punk; THUNK3216OBJ *pto; THKSTATE thkstate; thkDebugOut((DEB_THUNKMGR, "%sIn FindProxy3216(%p, %p, %s)\n", NestingLevelString(), ptoPrealloc, vpvThis16, IidIdxString(iidx))); DebugIncrementNestingLevel(); thkAssert(vpvThis16 != 0); // If we preallocated a proxy with an IID then a request was added // in CanGetNewProxy. Clean it up now if (ptoPrealloc != 0 && IIDIDX_IS_IID(iidx)) { RemoveIIDRequest(*IIDIDX_IID(iidx)); } thkstate = GetThkState(); // Check and see whether a proxy already exists for this object pto = LookupProxy3216(vpvThis16); if (pto != NULL) { thkDebugOut((DEB_THUNKMGR, "%sFindProxy3216 found existing proxy,(%p)->%p\n", NestingLevelString(), vpvThis16, pto)); // If a proxy's refcount is zero, it must be part of an aggregate thkAssert(pto->cRefLocal > 0 || (pto->pphHolder != NULL && (pto->pphHolder->dwFlags & PH_AGGREGATE) != 0)); // We found an existing proxy, so use it punk = (IUnknown *)pto; // Check and see whether we need to promote the proxy // This occurs in derivation situations where a less-specialized // proxy already exists for the given object. For example, // we might already have an IPersist proxy for this object when // we're looking up IPersistFile. In such cases, we promote // the proxy to the most derived interface if (IIDIDX_IS_INDEX(iidx) && IIDIDX_INDEX(iidx) > IIDIDX_INDEX(pto->iidx)) { pto->pfnVtbl = (DWORD)athopiInterfaceThopis[IIDIDX_INDEX(iidx)].pt3216fn; pto->iidx = iidx; } // AddRef the proxy we found since we're passing out a reference AddRefProxy3216(pto); if (pfst) { *pfst = FST_USED_EXISTING; } goto Exit; } // Check and see whether the object to be proxied is in fact a // proxy itself. If it is, we can just return the real object // rather than creating chains of proxies if ( ( punk = IsProxy1632(vpvThis16)) != NULL) { thkDebugOut((DEB_THUNKMGR, "%sFindProxy3216 shortcut proxy,(%p)->%p\n", NestingLevelString(), vpvThis16, punk)); // In the out parameter case, we are transferring ownership // so we need to AddRef the thing we're returning // Since we're shortcutting around a proxy we lose a reference // to the proxy so release it if (IsOutParamObj()) { // vpvThis16 is a pointer to a proxy // addref the real object and release the proxy // We want to temporarily suspend our out state since // we want this AddRef to really occur if it comes back // to a proxy SetThkState(THKSTATE_NOCALL); punk->AddRef(); SetThkState(thkstate); // Excel lands here with one too few addrefs so don't release if (thkstate != THKSTATE_INVOKETHKOUT16_CLIENTSITE) { ReleaseProxy1632(vpvThis16); } } if (pfst) { *pfst = FST_SHORTCUT; } goto Exit; } // We didn't find an existing proxy or shortcut so we need // to create a new proxy for the given object // We use preallocated memory if possible, otherwise we // get a new proxy from the free list if (ptoPrealloc != NULL) { pto = ptoPrealloc; // Since we're using the preallocated proxy, mark it as used // so we don't clean it up later ptoPrealloc = NULL; } else { pto = (THUNK3216OBJ *)flFreeList32.AllocElement(); } if (pto != NULL) { // Put the new proxy in the proxy table if (!_pProxyTbl3216->SetAt(vpvThis16, pto)) { // Note that we can put the new proxy back on the free // list even if it's the preallocated proxy because // that's what the prealloc cleanup does flFreeList32.FreeElement((DWORD)pto); pto = NULL; goto Exit; } if (IIDIDX_IS_IID(iidx)) { // give out IUnknown for custom interfaces iidx = INDEX_IIDIDX(THI_IUnknown); } punk = (IUnknown *)pto; pto->pfnVtbl = (DWORD)athopiInterfaceThopis[iidx].pt3216fn; pto->cRefLocal = 1; pto->cRef = (IsOutParamObj()) ? 1 : 0; pto->iidx = iidx; pto->vpvThis16 = vpvThis16; pto->pphHolder = NULL; PprxNull(pto->pprxObject); pto->grfFlags = PROXYFLAG_NORMAL; #if DBG == 1 pto->dwSignature = PSIG3216; #endif if (pfst) { *pfst = FST_CREATED_NEW; } thkDebugOut((DEB_THUNKMGR, "%sFindProxy3216 created new proxy, %s (%p)->%p:(%d,%d)\n", NestingLevelString(), inInterfaceNames[pto->iidx].pszInterface, vpvThis16, pto, pto->cRefLocal, pto->cRef)); } Exit: // // If we are succeeding punk will not be NULL. Then do this hack for Excel // if ( punk != NULL && thkstate == THKSTATE_INVOKETHKOUT16_CLIENTSITE ) { SetThkState(THKSTATE_NOCALL); // // Excel 5.0a has a bug where it doesn't addref the proxy // that it returns from the IOleObject::GetClientSite call // this means that we can't release the proxy or we'd kill it // prematurely. // thkDebugOut((DEB_WARN, "FindProxy1632: " "Addrefing proxy for compatability\n")); AddRefOnObj16( vpvThis16 ); SetThkState(thkstate); } // If we haven't used the preallocated proxy, return it to the freelist if (ptoPrealloc) { flFreeList32.FreeElement( (DWORD)ptoPrealloc ); } DebugDecrementNestingLevel(); thkDebugOut((DEB_THUNKMGR, "%sOut FindProxy3216: (%p)->%p\n", NestingLevelString(), vpvThis16, punk)); return punk; } //+--------------------------------------------------------------------------- // // Method: CThkMgr::FindAggregate3216 // // Synopsis: finds/creates an aggregate // // Arguments: [ptoPrealloc] - Preallocated proxy or NULL // [vpvOuter16] -- controlling unknown // [vpvThis16] -- 16 bit object (key) // [iidx] - IID or index of interface // // Returns: 32/16 proxy object // // History: 6-01-94 JohannP (Johann Posch) Created // //---------------------------------------------------------------------------- IUnknown *CThkMgr::FindAggregate3216(THUNK3216OBJ *ptoPrealloc, VPVOID vpvOuter16, VPVOID vpvThis16, IIDIDX iidx) { THUNK3216OBJ *pto3216; IUnknown *punk; DWORD fst; thkDebugOut((DEB_THUNKMGR, "%sIn FindAggregate3216(%p, %p, %p, %s)\n", NestingLevelString(), ptoPrealloc, vpvOuter16, vpvThis16, IidIdxString(iidx))); DebugIncrementNestingLevel(); thkAssert(vpvThis16 != NULL && vpvOuter16 != NULL); // Get back an object for the object to be proxied // This may be a proxy or a real object from a shortcut punk = FindProxy3216(ptoPrealloc, vpvThis16, iidx, &fst); if (punk == NULL) { goto Exit; } // If we got an object and it's not a proxy, we're done // There's nothing we can do since we can't link a real object to // a holder; we can only hope that things work out right if (fst & FST_OBJECT_STATUS) { goto Exit; } // Otherwise, we need to set up a holder for whatever proxies we // have THUNK1632OBJ UNALIGNED *pto1632; PROXYHOLDER *pph; IUnknown *punkProxiedObject; // We know punk is a proxy pto3216 = (THUNK3216OBJ *)punk; // Determine whether the outer unknown is a proxy or not punkProxiedObject = IsProxy1632(vpvOuter16); // Get the proxy pointer if it is if (punkProxiedObject != 0) { pto1632 = FIXVDMPTR(vpvOuter16, THUNK1632OBJ); } if (punkProxiedObject != 0 && pto1632->pphHolder != NULL) { // Use the existing holder if there is one pph = pto1632->pphHolder; } else { // Create a new holder pph = NewHolder(PH_AGGREGATE); if (pph == NULL) { FreeProxy3216(vpvThis16); punk = NULL; goto Exit; } // If the outer unknown is a proxy we know its holder hasn't // been set, so add it to the holder we created if (punkProxiedObject != 0) { AddProxyToHolder(pph, pto1632, Pprx16(vpvOuter16)); } } thkAssert(punkProxiedObject == 0 || pto1632->pphHolder == pph); // Add the new interface to the holder // Since this proxy was just created, we know its holder // hasn't been set yet AddProxyToHolder(pph, pto3216, Pprx32(pto3216)); Exit: if (punkProxiedObject != 0) { RELVDMPTR(vpvOuter16); } DebugDecrementNestingLevel(); thkDebugOut((DEB_THUNKMGR, "%sOut FindAggregate3216,(%p)->%p\n", NestingLevelString(), vpvThis16, pto3216)); return punk; } //+--------------------------------------------------------------------------- // // Method: CThkMgr::QueryInterfaceProxy3216 // // Synopsis: QueryInterface on the given proxy // // Arguments: [ptoThis] -- proxy object // [refiid] -- interface // [ppv] -- out parameter // // Returns: HRESULT // // History: 6-01-94 JohannP (Johann Posch) Created // //---------------------------------------------------------------------------- SCODE CThkMgr::QueryInterfaceProxy3216(THUNK3216OBJ *ptoThis, REFIID refiid, LPVOID *ppv) { SCODE scRet; IUnknown *punkProxy; VPVOID vpvUnk; DWORD fst; thkDebugOut((DEB_THUNKMGR, "%sIn QueryInterfaceProxy3216(%p)\n", NestingLevelString(), ptoThis)); DebugIncrementNestingLevel(); DebugValidateProxy3216(ptoThis); *ppv = NULL; IIDIDX iidx = IidToIidIdx(refiid); if (IIDIDX_IS_IID(iidx)) { // add the request for the unknown interface if (!AddIIDRequest(refiid)) { return E_OUTOFMEMORY; } thkDebugOut((DEB_THUNKMGR, "%sQueryInterfaceProxy3216: unknown iid %s\n", NestingLevelString(), IidIdxString(iidx))); } // We force the object we're QI'ing to have a holder so that // all objects have object refcounting. This should only be // necessary for aggregation but it seems that some apps rely // on all objects having aggregation-like refcounting qualities // BobDay identified PowerPoint as one // We only want to do this in cases where we've identified it's // necessary, which presently is only for // IDataObject // so we only do it then if (ptoThis->pphHolder == NULL && IsEqualIID(refiid, IID_IDataObject)) { PROXYHOLDER *pph; pph = NewHolder(PH_NONAGGREGATE); if (pph == NULL) { scRet = E_OUTOFMEMORY; goto Exit; } AddProxyToHolder(pph, ptoThis, Pprx32(ptoThis)); // It's not necessary to clean this up if later calls fail // since it doesn't alter the lifetime of the proxy if there's // only one proxy for the holder } // see if the interface is supported scRet = QueryInterfaceOnObj16(ptoThis->vpvThis16, refiid, (void **)&vpvUnk); if (FAILED(scRet)) { goto Exit; } if (NULL == vpvUnk) { // Although it is invalid, an app can return NULL for the // output interface and NOERROR for the result on a QueryInterface. // Corel draw has this behavior. Anyway, we nullify these errors // here. scRet = E_NOINTERFACE; goto Exit; } SetThkState(THKSTATE_INVOKETHKOUT32); punkProxy = FindProxy3216(NULL, vpvUnk, iidx, &fst); if (punkProxy == NULL) { // We were unable to create a proxy for the new interface so // clean up the interface and quit ReleaseOnObj16(vpvUnk); scRet = E_OUTOFMEMORY; goto ResetState; } *ppv = punkProxy; // If we're returning a proxy, we need to make sure that // it is listed in the proxy holder for this object if (fst & FST_PROXY_STATUS) { THUNK3216OBJ *ptoProxy; // We are returning a proxy. If its holder isn't set, // add it to the holder of the object that was QI'ed ptoProxy = (THUNK3216OBJ *)punkProxy; if (ptoProxy->pphHolder == NULL) { if (ptoThis->pphHolder != NULL) { AddProxyToHolder(ptoThis->pphHolder, ptoProxy, Pprx32(ptoProxy)); } } else if (ptoThis->pphHolder == NULL) { // ptoThis may not have a holder because it was produced // by a non-QI method such as IOleItemContainer::GetObject // If we find that an interface returned by it does // have a holder, hook it up to the holder // It shouldn't be necessary to do anything unusual with // local references even if ptoThis is really part of an // aggregate since ptoThis must have been produced by // a method where aggregation can't be assumed and all // references must be released on ptoThis itself AddProxyToHolder(ptoProxy->pphHolder, ptoThis, Pprx32(ptoThis)); } #if DBG == 1 // It's possible for holders to not match because of the above // case with interfaces being returned from non-QI methods // The lifetime for such interfaces must be defined by // strong references, though, so it's not catastrophic // Still, we'd like to be aware of such mismatches just in case if (ptoProxy->pphHolder != ptoThis->pphHolder) { thkDebugOut((DEB_WARN, "WARNING: QueryInterfaceProxy3216: " "this %p has holder %p, proxy %p has holder %p\n", ptoThis, ptoThis->pphHolder, ptoProxy, ptoProxy->pphHolder)); } #endif } ResetState: SetThkState(THKSTATE_NOCALL); Exit: // Clean up our custom interface request if necessary if (IIDIDX_IS_IID(iidx)) { // add the request for the unknown interface RemoveIIDRequest(refiid); } DebugDecrementNestingLevel(); thkDebugOut((DEB_THUNKMGR, "%sOut QueryInterfaceProxy3216(%p) => %p, 0x%08lX\n", NestingLevelString(), ptoThis, *ppv, scRet)); return scRet; } //+--------------------------------------------------------------------------- // // Method: CThkMgr::AddRefProxy3216 // // Synopsis: addref on the given object - can addref the real object // // Arguments: [ptoThis] -- proxy object // // Returns: local refcount // // History: 6-01-94 JohannP (Johann Posch) Created // //---------------------------------------------------------------------------- DWORD CThkMgr::AddRefProxy3216(THUNK3216OBJ *ptoThis) { PROXYHOLDER *pph; BOOL fAggregate; thkDebugOut((DEB_THUNKMGR, "%sIn AddRefProxy3216(%p)\n", NestingLevelString(), ptoThis)); DebugIncrementNestingLevel(); DebugValidateProxy3216(ptoThis); thkDebugOut(( DEB_THUNKMGR, "%s AddRefProxy3216 %08lX RefCounts: %d,%d\n", NestingLevelString(), ptoThis, ptoThis->cRefLocal, ptoThis->cRef )); pph = ptoThis->pphHolder; if (pph && (pph->dwFlags & PH_AGGREGATE_RELEASE)) { // we are about to call release on pUnkOuter // Release on PUnk was called and addref or release // calls to pUnkOuter are not supposted to be passed // on any more thkDebugOut((DEB_THUNKMGR, "%s About to addref pUnkOuter3216(%p)\n", NestingLevelString(), ptoThis)); goto Exit; } // Always increment the proxy local refcount LocalAddRefProxy(ptoThis); // Aggregations rely on all reference counts being forwarded on // to the controlling unknown. Therefore, if we have a proxy // that is part of an aggregate, we must ensure that the proxy // doesn't collect references locally. If it did, they would // not be passed on to the controlling unknown (via the real object) // and the controlling unknown's refcount would be too low if (ptoThis->pphHolder == NULL) { fAggregate = FALSE; } else { fAggregate = (ptoThis->pphHolder->dwFlags & PH_AGGREGATE) != 0; } if (IsOutParamObj()) { // If we're on the way out we're assuming that the object // given to us has its own reference so we bump cRef to // indicate that but we don't call the real object ptoThis->cRef++; } else if (ptoThis->cRef == 0 || fAggregate) { DWORD dwRet; // It's also necessary to pass on real references when the // ref count is zero. This handles the case where an // in parameter, created as 1,0, is AddRef'ed after // its creation, in which case the reference needs to // be passed on to the real object so that the proxy has // at least one real reference since it will stay alive ptoThis->cRef++; dwRet = AddRefOnObj16(ptoThis->vpvThis16); thkDebugOut((DEB_THUNKMGR, "%s AddRefProxy3216: AddRef called on (%p):%ld\n", NestingLevelString(), ptoThis->vpvThis16, dwRet)); } else { // Local-only AddRef } Exit: DebugDecrementNestingLevel(); thkDebugOut((DEB_THUNKMGR, "%sOut AddRefProxy3216(%p),(%ld,%ld)\n", NestingLevelString(), ptoThis, ptoThis->cRefLocal, ptoThis->cRef)); return ptoThis->cRefLocal; } //+--------------------------------------------------------------------------- // // Method: CThkMgr::ReleaseProxy3216 // // Synopsis: release on the proxy or aggregate // // Arguments: [ptoThis] -- proxy object // // Returns: local refcount // // History: 6-01-94 JohannP (Johann Posch) Created // //---------------------------------------------------------------------------- DWORD CThkMgr::ReleaseProxy3216(THUNK3216OBJ *ptoThis) { PROXYHOLDER *pph; thkDebugOut((DEB_THUNKMGR, "%sIn ReleaseProxy3216(%p)\n", NestingLevelString(), ptoThis)); DebugIncrementNestingLevel(); DebugValidateProxy3216(ptoThis); thkDebugOut(( DEB_THUNKMGR, "%s ReleaseProxy3216 %08lX RefCounts: %d,%d\n", NestingLevelString(), ptoThis, ptoThis->cRefLocal, ptoThis->cRef )); pph = ptoThis->pphHolder; if (pph && (pph->dwFlags & PH_AGGREGATE_RELEASE)) { // we are about to call release on pUnkOuter // Release on PUnk was called and addref and // release calls to pUnkOuter are not supposted // to be passed on any more thkDebugOut((DEB_THUNKMGR, "%s About to release pUnkOuter3216(%p)\n", NestingLevelString(), ptoThis)); thkDebugOut((DEB_THUNKMGR, "%s ReleaseProxy3216 pUnkOuter stop passing releases on(%p) => %ld,%ld\n", NestingLevelString(), ptoThis, ptoThis ? ptoThis->cRefLocal : 0 , ptoThis ? ptoThis->cRef : 0)); if (ptoThis->cRef == 0 && ptoThis->cRef == ptoThis->cRefLocal) { goto Done; } } // If our local refcount is the same as the count of references // that we've passed on to the object, then we need to pass // on this release to the real object if (ptoThis->cRef == ptoThis->cRefLocal) { DWORD dwRet; thkAssert(ptoThis->cRef > 0); dwRet = ReleaseOnObj16(ptoThis->vpvThis16); // Decrement cRef after making the real call to ensure that // the proxy lives throughout the call --ptoThis->cRef; thkDebugOut((DEB_THUNKMGR, "%s ReleaseProxy3216: Release called on (%p):%ld \n", NestingLevelString(), ptoThis->vpvThis16, dwRet)); } // Now that we've handled the real object's refcount, decrement // the proxy's refcount and clean it up if necessary thkAssert(ptoThis->cRefLocal > 0); if (--ptoThis->cRefLocal == 0) { // Proxies that have no outer unknown can be cleaned // up immediately. If they do have an outer unknown then // they must live as long as the entire object lives, // so we don't clean them up here. They'll be cleaned up // when the object dies if (ptoThis->pphHolder) { // If this proxy isn't part of an aggregate, remove it // from the proxy list so it can't be reused // The only thing this proxy will be good for is // calling through if ((ptoThis->pphHolder->dwFlags & PH_AGGREGATE) == 0) { _pProxyTbl3216->RemoveKey((DWORD)ptoThis->vpvThis16); } // We have a holder, so notify it that one of its // proxies just died // This can cause cleanup of all proxies if the // holder releases to zero ReleaseHolder(ptoThis->pphHolder); } else { // We don't have a holder so we can clean up this proxy // immediately RemoveProxy3216(ptoThis); } ptoThis = NULL; DBG_DUMP(DebugDump3216()); } Done: DebugDecrementNestingLevel(); thkDebugOut((DEB_THUNKMGR, "%sOut ReleaseProxy3216(%p) => %ld,%ld\n", NestingLevelString(), ptoThis, ptoThis ? ptoThis->cRefLocal : 0 , ptoThis ? ptoThis->cRef : 0)); return ptoThis ? ptoThis->cRefLocal : 0; } //+--------------------------------------------------------------------------- // // Member: CThkMgr::ReleaseUnreferencedProxy3216, public // // Synopsis: Releases a proxy in the special case where the proxy // was created for a non-addrefed object // // Arguments: [ptoThis] - 32/16 proxy // // History: 11-Jul-94 DrewB Created // // Notes: Needed to clean up proxies from DebugServerQueryInterface // in DebugServerRelease // //---------------------------------------------------------------------------- void CThkMgr::ReleaseUnreferencedProxy3216(THUNK3216OBJ *ptoThis) { thkAssert(IsProxy3216((IUnknown *)ptoThis) != 0); // Since the object is non-addref'ed, we have to be careful // to ensure that the ReleaseProxy call doesn't end up releasing // the real object, so we force cRef to be different from // cRefLocal. We know that DebugServerQueryInterface gave the // proxy a cRef because it's an out parameter, so we should // always be able to decrement cRef and achieve the desired // effect thkAssert(ptoThis->cRef > 0); ptoThis->cRef--; // Now release the proxy to clean it up // If it was addref'ed, this will just remove a local reference // If it wasn't, this will clean up the proxy // In both cases, no Release should occur on the real object thkAssert(ptoThis->cRefLocal != ptoThis->cRef); ReleaseProxy3216(ptoThis); } //+--------------------------------------------------------------------------- // // Method: CThkMgr::FreeProxy3216 // // Synopsis: releases the object for the given vpUnk16 (key) // // Arguments: [vpvObj16] - Proxy or object // // Returns: local refcount // // History: 6-01-94 JohannP (Johann Posch) Created // //---------------------------------------------------------------------------- DWORD CThkMgr::FreeProxy3216(VPVOID vpvObj16) { thkDebugOut((DEB_THUNKMGR, "%sIn FreeProxy3216(%p)\n", NestingLevelString(), vpvObj16)); DWORD dwRet = 0; THUNK3216OBJ *pto; thkAssert(vpvObj16 != 0); // get the object by the 16 bit this pointer pto = LookupProxy3216(vpvObj16); if (pto != NULL) { thkDebugOut((DEB_THUNKMGR, "%sFreeProxy3216(%p) " "found existing proxy %p\n", NestingLevelString(), vpvObj16, pto)); dwRet = ReleaseProxy3216(pto); } thkDebugOut((DEB_THUNKMGR, "%sOut FreeProxy3216(%p):%ld \n", NestingLevelString(), vpvObj16, dwRet)); return dwRet; } //+--------------------------------------------------------------------------- // // Member: CThkMgr::RemoveProxy3216, public // // Synopsis: Destroys the given proxy // // Arguments: [pto] - Flat proxy pointer // // History: 11-Aug-94 DrewB Created // //---------------------------------------------------------------------------- void CThkMgr::RemoveProxy3216(THUNK3216OBJ *pto) { _pProxyTbl3216->RemoveKey((DWORD)pto->vpvThis16); if ((pto->grfFlags & PROXYFLAG_LOCKED) == 0) { #if DBG == 1 pto->dwSignature = PSIG3216DEAD; if (!fSaveProxy) #endif { flFreeList32.FreeElement((DWORD)pto); } } } //+--------------------------------------------------------------------------- // // Member: CThkMgr::PrepareForCleanup, public // // Synopsis: Marks the 3216 Proxies so that OLE32 cannot call them. // // Arguments: -none- // // History: 24-Aug-94 BobDay Created // //---------------------------------------------------------------------------- void CThkMgr::PrepareForCleanup( void ) { POSITION pos; DWORD dwKey; THUNK3216OBJ *pto3216; // // CODEWORK: OLE32 should be setup so that it doesn't callback while the // thread is detaching. Then this function becomes obsolete. // // delete the 3216 proxy table pos = _pProxyTbl3216->GetStartPosition(); while (pos) { _pProxyTbl3216->GetNextAssoc(pos, dwKey, (void FAR* FAR&) pto3216); thkDebugOut((DEB_IWARN, "Preparing 3216 Proxy for cleanup: " "%08lX %08lX %s\n", pto3216, pto3216->vpvThis16, IidIdxString(pto3216->iidx))); pto3216->grfFlags |= PROXYFLAG_CLEANEDUP; } } #if DBG == 1 void CThkMgr::DebugDump3216() { THUNK3216OBJ *pto3216; DWORD dwKey; POSITION pos; thkDebugOut((DEB_THUNKMGR, "%s DebugDump3216\n",NestingLevelString())); pos = _pProxyTbl3216->GetStartPosition(); while (pos) { _pProxyTbl3216->GetNextAssoc(pos, dwKey, (void FAR* FAR&) pto3216); thkDebugOut((DEB_THUNKMGR, "%s Proxy3216:Key:%p->%p, (%s) (%d,%d)\n", NestingLevelString(), dwKey, pto3216, IidIdxString(pto3216->iidx), pto3216->cRefLocal, pto3216->cRef)); } } void CThkMgr::DebugDump1632() { THUNK1632OBJ UNALIGNED *pto1632; DWORD dwKey; VPVOID vpv; POSITION pos; thkDebugOut((DEB_THUNKMGR, "%s DebugDump1632\n",NestingLevelString())); pos = _pProxyTbl1632->GetStartPosition(); while (pos) { _pProxyTbl1632->GetNextAssoc(pos, dwKey, (void FAR* FAR&) vpv); pto1632 = FIXVDMPTR(vpv, THUNK1632OBJ); thkDebugOut((DEB_THUNKMGR, "%s Proxy1632:key:%p->%p, (%s) (%d,%d)\n", NestingLevelString(), dwKey, pto1632, IidIdxString(pto1632->iidx), pto1632->cRefLocal, pto1632->cRef)); RELVDMPTR(vpv); } } #endif