//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 1994. // // File: thkmgr.cxx // // Contents: Thunk manager initialization // IUnknown transition functions // // History: 5-18-94 JohannP (Johann Posch) Created // //---------------------------------------------------------------------------- #include "headers.cxx" #pragma hdrstop //+--------------------------------------------------------------------------- // // Function: ThkMgrInitialize // // Synopsis: Creates a new thunkmanager and set it for given thread // // Arguments: [dw1] // [dw2] // [dw3] // // Returns: HRESULT // // History: 5-18-94 JohannP (Johann Posch) Created // // Notes: Called from CoInitialize // //---------------------------------------------------------------------------- STDAPI ThkMgrInitialize(DWORD dw1, DWORD dw2, DWORD dw3) { CThkMgr *pcthkmgr = NULL; thkDebugOut((DEB_THUNKMGR, "In ThkMgrInitialize()\n")); // // If we are already initialized, do nothing. // if (TlsGetValue(dwTlsThkIndex) != NULL) { thkDebugOut((DEB_THUNKMGR, "OUT ThkMgrInitialize() Already Init\n")); return(NOERROR); } // // initialize the Tls storage // if ( NOERROR != TlsThkInitialize()) { thkDebugOut((DEB_ERROR, "TlsThkInitialize failed")); return E_OUTOFMEMORY; } thkAssert(TlsThkGetThkMgr() == NULL); pcthkmgr = CThkMgr::Create(); TlsThkSetThkMgr(pcthkmgr); thkDebugOut((DEB_THUNKMGR, "Out ThkMgrInitialize() => %p\n", pcthkmgr)); return (pcthkmgr == NULL) ? E_OUTOFMEMORY : NOERROR; } //+--------------------------------------------------------------------------- // // Function: ThkMgrUninitialize // // Synopsis: deletes the thunkmanager and removes it from thread data // tls data are removed as well // // Arguments: [dw1] // [dw2] // [dw3] // // History: 5-18-94 JohannP (Johann Posch) Created // // Notes: Called during CoUninitialize // //---------------------------------------------------------------------------- STDAPI_(void) ThkMgrUninitialize(DWORD dw1, DWORD dw2, DWORD dw3) { thkDebugOut((DEB_THUNKMGR, "In ThkMgrUninitialize()\n")); thkAssert(TlsGetValue(dwTlsThkIndex) != NULL); CThkMgr *pcthkmgr = (CThkMgr*)TlsThkGetThkMgr(); if (pcthkmgr != NULL) { // Note: the thunkmanger gets removed from tlsthk delete pcthkmgr; } // If we weren't called from 16-bit code then it's not safe to reset // the 16-bit stack allocator here because we may be doing this // in thread cleanup and it may not be safe to call back into // 16-bit code TlsThkGetStack32()->Reset(); // uninitialize the tls data for this apartment TlsThkUninitialize(); thkDebugOut((DEB_THUNKMGR, "Out ThkMgrUninitialize()\n")); } //+--------------------------------------------------------------------------- // // Function: IUnknownObj32 // // Synopsis: Entry point from 16bit for IUnknown methods // // Arguments: [vpvThis16] -- Proxy object // [wMethod] -- IUnknown method // [vpvData] -- Call data // // Returns: Call result, pdata contains out data for particular call // // History: 5-18-94 JohannP (Johann Posch) Created // //---------------------------------------------------------------------------- STDAPI_(DWORD) IUnknownObj32(VPVOID vpvThis16, DWORD wMethod, VPVOID vpvData) { DWORD dwRet; LONG vpvInterface; IID iid; if (TlsThkGetData() == NULL) { thkDebugOut((DEB_WARN, "WARNING: IUnknownObj32 call refused\n")); if (wMethod == SMI_QUERYINTERFACE) { return (DWORD)E_FAIL; } else { return 0; } } // Note: at this point we should always get a thunkmanager CThkMgr *pcthkmgr = (CThkMgr*)TlsThkGetThkMgr(); thkAssert(pcthkmgr != NULL && "ThunkManager was not initialized"); thkAssert(vpvThis16 != 0 && "IUnknownObj32: invalid pointer." ); thkAssert(wMethod < SMI_COUNT); switch (wMethod) { case SMI_QUERYINTERFACE: thkAssert(vpvData != NULL && "IUnknownObj32.QueryInterface without IID"); // Copy the 16-bit IID into 32-bit memory for the real call iid = *FIXVDMPTR(vpvData, IID); RELVDMPTR(vpvData); thkDebugOut((DEB_UNKNOWN, "%sIn QueryInterface1632(%p, %s)\n", NestingLevelString(), vpvThis16, IidOrInterfaceString(&iid))); dwRet = pcthkmgr->QueryInterfaceProxy1632(vpvThis16, iid, (void **)&vpvInterface); // Translate the 32-bit HRESULT to a 16-bit HRESULT dwRet = (DWORD)TransformHRESULT_3216((HRESULT)dwRet); // Pass the return interface pointer back through the IID // memory. We re-resolve the data pointer since nested // calls may have occurred (FIXVDMPTR(vpvData, IID))->Data1 = vpvInterface; RELVDMPTR(vpvData); thkDebugOut((DEB_UNKNOWN, "%sOut QueryInterface1632(%p) => %p, 0x%08lX\n", NestingLevelString(), vpvThis16, vpvInterface, dwRet)); break; case SMI_ADDREF: thkDebugOut((DEB_UNKNOWN, "%sIn AddRef1632(%p)\n", NestingLevelString(), vpvThis16)); dwRet = pcthkmgr->AddRefProxy1632(vpvThis16); thkDebugOut((DEB_UNKNOWN, "%sOut AddRef1632(%p) => %d\n", NestingLevelString(), vpvThis16, dwRet)); break; case SMI_RELEASE: thkDebugOut((DEB_UNKNOWN, "%sIn Release1632(%p)\n", NestingLevelString(), vpvThis16)); dwRet = pcthkmgr->ReleaseProxy1632(vpvThis16); thkDebugOut((DEB_UNKNOWN, "%sOut Release1632(%p) => %d\n", NestingLevelString(), vpvThis16, dwRet)); break; } return dwRet; } //+--------------------------------------------------------------------------- // // Function: QueryInterfaceProxy3216 // // Synopsis: call QueryInterface on a 32 bit proxy // // Arguments: [pto] -- This pointer (a 32->16 proxy) // [refiid] -- Interface queried for // [ppv] -- Interface return // // Returns: HRESULT // // History: 5-18-94 JohannP (Johann Posch) Created // //---------------------------------------------------------------------------- SCODE QueryInterfaceProxy3216(THUNK3216OBJ *pto, REFIID refiid, LPVOID *ppv) { HRESULT hrRet; thkDebugOut((DEB_UNKNOWN, "%sIn QueryInterface3216(%p, %s)\n", NestingLevelString(), pto, IidOrInterfaceString(&refiid))); DebugIncrementNestingLevel(); if (TlsThkGetData() == NULL) { thkDebugOut((DEB_WARN, "WARNING: QIProxy3216 call refused\n")); return E_FAIL; } CThkMgr *pcthkmgr = TlsThkGetThkMgr(); thkAssert(pcthkmgr != NULL && "ThunkManager was not initialized"); if ( pto->grfFlags & PROXYFLAG_CLEANEDUP ) { thkDebugOut((DEB_WARN, "QueryInterfaceProxy3216: Attempt to QI " "on cleaned-up proxy %08lX for 16-bit object %08lX %s\n", pto, pto->vpvThis16, IidIdxString(IID_IIDIDX(&refiid)) )); *ppv = NULL; return E_FAIL; } hrRet = pcthkmgr->QueryInterfaceProxy3216(pto, refiid, ppv); // // If the QI for IUnknown failed, then return the current this // pointer as the IUnknown. Watermark 1.02 appears to not support // IUnknown in its IOleInPlaceActiveObject interface, which causes // CoMarshalInterface to fail. The reason it used to work is the // original 16-bit DLL's would just use the provided pointer as // the punk if IUnknown wasn't supported. The following lines of // code emulate that behaviour. // if ((hrRet == E_NOINTERFACE) && IsEqualIID(refiid,IID_IUnknown)) { thkDebugOut((DEB_UNKNOWN, "%s Object %p didn't support QI(IID_IUnknown): Faking it\n", NestingLevelString(), pto)); ((IUnknown *)pto)->AddRef(); *ppv = pto; hrRet = S_OK; } DebugDecrementNestingLevel(); thkDebugOut((DEB_UNKNOWN, "%sOut QueryInterface3216(%p) => %p, ret:0x%08lX\n", NestingLevelString(), pto, *ppv, hrRet)); return hrRet; } //+--------------------------------------------------------------------------- // // Function: AddRefProxy3216 // // Synopsis: call addref on an 16 bit object // // Arguments: [pto] -- This pointer (a 32->16 proxy) // // Returns: New refcount // // History: 5-18-94 JohannP (Johann Posch) Created // //---------------------------------------------------------------------------- DWORD AddRefProxy3216(THUNK3216OBJ *pto) { DWORD dwRet; thkDebugOut((DEB_UNKNOWN, "%sIn AddRef3216(%p)\n", NestingLevelString(), pto)); DebugIncrementNestingLevel(); if (TlsThkGetData() == NULL) { thkDebugOut((DEB_WARN, "WARNING: AddRefProxy3216 call refused\n")); return 0; } CThkMgr *pcthkmgr = TlsThkGetThkMgr(); thkAssert(pcthkmgr != NULL && "ThunkManager was not initialized"); if ( pto->grfFlags & PROXYFLAG_CLEANEDUP ) { thkDebugOut((DEB_WARN, "AddRefProxy3216: Attempt to AddRef " "on cleaned-up proxy %08lX for 16-bit object %08lX\n", pto, pto->vpvThis16)); return 0; } dwRet = pcthkmgr->AddRefProxy3216(pto); DebugDecrementNestingLevel(); thkDebugOut((DEB_UNKNOWN, "%sOut AddRef3216(%p) => %ld\n", NestingLevelString(), pto, dwRet)); return dwRet; } //+--------------------------------------------------------------------------- // // Function: ReleaseProxy3216 // // Synopsis: Release implementation for 32->16 proxies // // Arguments: [pto] -- This pointer (a 32->16 proxy) // // Returns: New refcount // // History: 5-18-94 JohannP (Johann Posch) Created // //---------------------------------------------------------------------------- DWORD ReleaseProxy3216(THUNK3216OBJ *pto) { DWORD dwRet; thkDebugOut((DEB_UNKNOWN, "%sIn Release3216(%p)\n", NestingLevelString(), pto)); DebugIncrementNestingLevel(); if (TlsThkGetData() == NULL) { thkDebugOut((DEB_WARN, "WARNING: ReleaseProxy3216 call refused\n")); return 0; } CThkMgr *pcthkmgr = TlsThkGetThkMgr(); thkAssert(pcthkmgr != NULL && "ThunkManager was not initialized"); if ( pto->grfFlags & PROXYFLAG_CLEANEDUP ) { thkDebugOut((DEB_WARN, "ReleaseProxy3216: Attempt to Release " "on cleaned-up proxy %08lX for 16-bit object %08lX\n", pto, pto->vpvThis16)); return 0; } dwRet = pcthkmgr->ReleaseProxy3216(pto); DebugDecrementNestingLevel(); thkDebugOut((DEB_UNKNOWN, "%sOut Release3216(%p) => %ld\n", NestingLevelString(), pto, dwRet)); return dwRet; } //+--------------------------------------------------------------------------- // // Function: QueryInterfaceOnObj16 // // Synopsis: call QueryInterface on an 16 bit object // // Arguments: [vpvThis16] -- 16-bit this pointer // [refiid] -- IID // [ppv] -- Interface return // // Returns: HRESULT // // History: 5-18-94 JohannP (Johann Posch) Created // //---------------------------------------------------------------------------- struct QIARGS { IID iid; void *pvObject; }; HRESULT QueryInterfaceOnObj16(VPVOID vpvThis16, REFIID refiid, LPVOID *ppv) { HRESULT hrRet; VPVOID vpvArgs; QIARGS UNALIGNED *pqa; BYTE bArgs32[WCB16_MAX_CBARGS]; thkDebugOut((DEB_THUNKMGR, "%sIn QueryInterfaceOnObj16(%p, %s)\n", NestingLevelString(), vpvThis16, IidOrInterfaceString(&refiid))); DebugIncrementNestingLevel(); thkAssert(WCB16_MAX_CBARGS >= 3*sizeof(DWORD)); thkAssert(vpvThis16 != 0 && "QueryInterfaceOnObj16: invalid pointer."); // Allocate space for the sixteen bit arguments memory vpvArgs = STACKALLOC16(sizeof(QIARGS)); if (vpvArgs == 0) { return E_OUTOFMEMORY; } // Fill in the in-param memory pqa = FIXVDMPTR(vpvArgs, QIARGS); pqa->iid = refiid; // Set up the 16-bit stack in pascal order *(VPVOID *)(bArgs32+0*sizeof(VPVOID)) = vpvArgs+ FIELD_OFFSET(QIARGS, pvObject); *(VPVOID *)(bArgs32+1*sizeof(VPVOID)) = vpvArgs; *(VPVOID *)(bArgs32+2*sizeof(VPVOID)) = vpvThis16; RELVDMPTR(vpvArgs); // Call to 16-bit stub if (!CallbackTo16Ex(gdata16Data.fnQueryInterface16, WCB16_PASCAL, 3*sizeof(DWORD), bArgs32, (DWORD *)&hrRet)) { hrRet = E_UNEXPECTED; } // Transform the 16-bit HRESULT to a 32-bit HRESULT hrRet = TransformHRESULT_1632(hrRet); // Copy back out-param memory pqa = FIXVDMPTR(vpvArgs, QIARGS); *ppv = pqa->pvObject; RELVDMPTR(vpvArgs); STACKFREE16(vpvArgs, sizeof(QIARGS)); DebugDecrementNestingLevel(); thkDebugOut((DEB_THUNKMGR, "%sOut QueryInterfaceOnObj16(%p) => %p, ret:0x%08lX\n", NestingLevelString(), vpvThis16, *ppv, hrRet)); return hrRet; } //+--------------------------------------------------------------------------- // // Function: AddRefOnObj16 // // Synopsis: calls addref on an 16 bit object // // Arguments: [vpvThis16] -- 16-bit this pointer // // Returns: New ref count // // History: 5-18-94 JohannP (Johann Posch) Created // //---------------------------------------------------------------------------- #if DBG == 1 DWORD AddRefOnObj16(VPVOID vpvThis16) { DWORD dwRet; thkDebugOut((DEB_THUNKMGR, "%sIn AddRefOnObj16(%p)\n", NestingLevelString(), vpvThis16)); DebugIncrementNestingLevel(); dwRet = CallbackTo16(gdata16Data.fnAddRef16, vpvThis16); DebugDecrementNestingLevel(); thkDebugOut((DEB_THUNKMGR, "%sOut AddRefOnObj16(%p) => %ld\n", NestingLevelString(), vpvThis16, dwRet)); return dwRet; } #endif //+--------------------------------------------------------------------------- // // Function: ReleaseOnObj16 // // Synopsis: Release a 16-bit object // // Arguments: [vpvThis16] -- 16-bit this pointer // // Returns: New ref count // // History: 5-18-94 JohannP (Johann Posch) Created // //---------------------------------------------------------------------------- #if DBG == 1 DWORD ReleaseOnObj16(VPVOID vpvThis16) { DWORD dwRet; thkDebugOut((DEB_THUNKMGR, "%sIn ReleaseOnObj16(%p)\n", NestingLevelString(), vpvThis16)); DebugIncrementNestingLevel(); dwRet = CallbackTo16(gdata16Data.fnRelease16, vpvThis16); #if DBG==1 if(dwRet==0 && TlsThkGetThkMgr()->GetThkState()==THKSTATE_VERIFY16INPARAM) { thkDebugOut((DEB_WARN, "WARINING: 16-bit 0x%x IN parameter with zero " "ref count\n", vpvThis16)); if(thkInfoLevel & DEB_DBGFAIL) thkAssert(!"Wish to Debug"); } #endif DebugDecrementNestingLevel(); thkDebugOut((DEB_THUNKMGR, "%sOut ReleaseOnObj16(%p) => %ld\n", NestingLevelString(), vpvThis16, dwRet)); return dwRet; } #endif #if DBG == 1 void DebugDump() { CThkMgr *pcthkmgr = (CThkMgr*)TlsThkGetThkMgr(); thkAssert(pcthkmgr != NULL && "ThunkManager was not initialized"); pcthkmgr->DebugDump3216(); pcthkmgr->DebugDump1632(); } #endif