//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 1994. // // File: inv32.cxx // // Contents: Implementation of InvokeOn32 // // History: 22-Feb-94 DrewB Created // //---------------------------------------------------------------------------- #include "headers.cxx" #pragma hdrstop STDAPI_(BOOL) IsValidInterface( void FAR* pv ); #include //+--------------------------------------------------------------------------- // // Function: InvokeOn32, public // // Synopsis: Sets up the THUNKINFO and starts thunking for a 16->32 call // // Arguments: [dw1] - Ignored // [dwMethod] - Method index // [pvStack32] - 32-bit stack // // Returns: Appropriate status code // // History: 18-Dec-93 JohannP Created // 21-Feb-94 DrewB Modified // 09-Dec-94 JohannP added stack switching // // Note: On WIN95 this function get is executed on the 32 bit stack. // //---------------------------------------------------------------------------- #if DBG == 1 extern "C" { ULONG InvokeOn32_count = 0; ULONG InvokeOn32_break = 0; int _iInvokeOn32BreakIidx = -1; int _iInvokeOn32BreakMethod = -1; }; #endif // InvokeOn32 uses a lot of local variables so allocate its locals // rather than declaring them on the stack. This saves roughly // 150 bytes of stack per call struct INVOKE32RECORD { THOP CONST *pThop; THOP CONST * CONST *ppThop; UINT uiThop; VTBLFN CONST *pvfnVtbl; VTBLFN CONST * CONST *ppvfnThis32; DWORD dwStack32[MAX_PARAMS]; THUNKINFO ti; VPVOID vpvThis16; THUNK1632OBJ UNALIGNED *pto; IIDIDX iidx; ThreadData *ptd; }; STDAPI_(DWORD) SSAPI(InvokeOn32)(DWORD dw1, DWORD dwMethod, LPVOID pvStack16) { // NOTE: Do not declare local variables in this routine // except for debug builds INVOKE32RECORD *pir; DWORD dwResult; #if DBG == 1 ULONG ulInvokeOn32_count = ++InvokeOn32_count; if (InvokeOn32_count == InvokeOn32_break) { DebugBreak(); } thkDebugOut((DEB_ITRACE, "%sInvokeOn32(0x%08x, %p)\n", NestingLevelString(), dwMethod, pvStack16)); #endif // DBG if(!TlsThkGetData()) return(CO_E_NOTINITIALIZED); pir = (INVOKE32RECORD *)STACKALLOC32(sizeof(INVOKE32RECORD)); if (pir == NULL) { // This error isn't guaranteed to mean anything for // this call. Not much else we can do, though return (DWORD)E_OUTOFMEMORY; } // pvStack16 is the pointer to the first parameter of the 16-bit // routine. The compiler will adjust it appropriately according // to the calling convention of the routine so for PASCAL APIs // it will be high and for CDECL methods it will be low pir->ti.s16.pbStart = (BYTE *)pvStack16; pir->ti.s16.pbCurrent = pir->ti.s16.pbStart; pir->ti.s32.pbStart = (BYTE *)pir->dwStack32; pir->ti.s32.pbCurrent = pir->ti.s32.pbStart; pir->ti.scResult = S_OK; pir->ti.fResultThunked = FALSE; if (dwMethod >= THK_API_BASE) { dwMethod -= THK_API_BASE; pir->iidx = IIDIDX_INVALID; // APIs are handled as if there were a giant interface which // contains all the APIs as methods. pir->ppThop = apthopsApiThops; pir->uiThop = THK_API_COUNT; pir->pvfnVtbl = apfnApiFunctions; // APIs are pascal so we need to move downward in memory to // get to the next parameter pir->ti.s16.iDir = -1; pir->ti.dwCallerProxy = 0; } else { // For each interface there is an array of thop strings, one for // each method. The IUnknown methods don't have thop strings so // bias the thop string pointer to account for that thkAssert(dwMethod >= SMI_COUNT); // Methods are cdecl so we need to move upwards in memory to // get to the next parameter pir->ti.s16.iDir = 1; // We need to look up the appropriate method pointer by // looking in the 32-bit object's vtable GET_STACK16(&pir->ti, pir->vpvThis16, VPVOID); thkDebugOut((DEB_INVOKES, "InvokeOn32: vpvThis16 = %08lX\n", pir->vpvThis16 )); pir->pto = FIXVDMPTR(pir->vpvThis16, THUNK1632OBJ); if (pir->pto == NULL) { STACKFREE32(pir, sizeof(INVOKE32RECORD)); return (DWORD)E_INVALIDARG; } if ((pir->pto->grfFlags & PROXYFLAG_TEMPORARY) == 0) { // Make sure proxy is still valid. // After PPC/Win95 we might want to look at using // a signiture for validating this rather than IsValidInterface // because it will speed this code path up. if (!IsValidInterface(pir->pto->punkThis32)) { thkDebugOut(( DEB_ERROR, "InvokeOn32: %p: Invalid proxied object %p\n", pir->vpvThis16, pir->pto->punkThis32)); STACKFREE32(pir, sizeof(INVOKE32RECORD)); RELVDMPTR(pir->vpvThis16); return (DWORD)E_INVALIDARG; } DebugValidateProxy1632(pir->vpvThis16); pir->ppvfnThis32 = (VTBLFN CONST * CONST*)pir->pto->punkThis32; } else { // Temporary proxies cannot be validated // A temporary proxy's this pointer is actually a pointer // to the real this pointer, so indirect through the this // pointer to retrieve the real this pointer pir->ppvfnThis32 = (VTBLFN CONST * CONST *)*(void **)pir->pto->punkThis32; thkAssert(pir->ppvfnThis32 != NULL); thkDebugOut((DEB_WARN, "WARNING: InvokeOn32 on temporary " "%s proxy for %p\n", IidIdxString(pir->pto->iidx), pir->ppvfnThis32)); } pir->iidx = pir->pto->iidx; RELVDMPTR(pir->vpvThis16); if (pir->ppvfnThis32 == NULL) { STACKFREE32(pir, sizeof(INVOKE32RECORD)); return (DWORD)E_FAIL; } pir->ti.dwCallerProxy = pir->vpvThis16; thkAssert(pir->iidx < THI_COUNT); pir->ppThop = athopiInterfaceThopis[pir->iidx].ppThops-SMI_COUNT; pir->uiThop = athopiInterfaceThopis[pir->iidx].uiSize; pir->pvfnVtbl = *pir->ppvfnThis32; // Push the 32-bit this pointer on the stack first TO_STACK32(&pir->ti, pir->ppvfnThis32, VTBLFN CONST * CONST*); } thkAssert(dwMethod < pir->uiThop); pir->pThop = pir->ppThop[dwMethod]; thkAssert(pir->pThop != NULL); pir->ti.pThop = pir->pThop; pir->ti.pvfn = pir->pvfnVtbl[dwMethod]; pir->ti.iidx = pir->iidx; pir->ti.dwMethod = dwMethod; pir->ptd = TlsThkGetData(); if (pir->ptd == NULL) { thkDebugOut((DEB_WARN, "WARNING: InvokeOn32: Call refused\n")); STACKFREE32(pir, sizeof(INVOKE32RECORD)); return (DWORD)E_FAIL; } pir->ti.pThkMgr = pir->ptd->pCThkMgr; thkAssert(pir->ti.pThkMgr != NULL); #if DBG == 1 if (pir->iidx == IIDIDX_INVALID) { thkDebugOut((DEB_INVOKES, "%s#(%04X):InvokeOn32 on %p, %s\n", NestingLevelString(), ulInvokeOn32_count, pir->ti.pvfn, apszApiNames[dwMethod])); } else { thkDebugOut((DEB_INVOKES, "%s#(%04X):InvokeOn32 on %p:%p, %s::%s (0x%0x:0x%0x)\n", NestingLevelString(), ulInvokeOn32_count, pir->ppvfnThis32, pir->ti.pvfn, inInterfaceNames[pir->iidx].pszInterface, inInterfaceNames[pir->iidx].ppszMethodNames[dwMethod], pir->iidx, dwMethod)); } #endif DebugIncrementNestingLevel(); // save and set the new thunk state pir->ti.pThkMgr->SetThkState(THKSTATE_INVOKETHKIN32); #if DBG == 1 if ((_iInvokeOn32BreakIidx > 0 && _iInvokeOn32BreakIidx == (int)pir->iidx) && (_iInvokeOn32BreakMethod < 0 || _iInvokeOn32BreakMethod == (int)dwMethod)) { DebugBreak(); } #endif #if DBG == 1 SStackRecord sr; RecordStackState16(&sr); #endif #if DBG == 1 if (fStabilizeProxies) #endif { // HACK HACK HACK // Because of changes in the way refcounting rules work between // 16 and 32-bits, we have to stabilize this pointers for // 16->32 calls. To effect this, we do a purely local AddRef // // Temporary proxies are not valid proxies so they cannot // be stabilized if (pir->iidx != IIDIDX_INVALID) { DWORD dwFlags; pir->pto = FIXVDMPTR(pir->vpvThis16, THUNK1632OBJ); dwFlags = pir->pto->grfFlags; RELVDMPTR(pir->vpvThis16); if ((dwFlags & PROXYFLAG_TEMPORARY) == 0) { pir->ti.pThkMgr->AddRefProxy1632(pir->vpvThis16); } } } dwResult = EXECUTE_THOP1632(&pir->ti); #if DBG == 1 if (fStabilizeProxies) #endif { // Remove our stabilization reference // Note that we don't really know whether the proxy is // still valid, so we're just crossing our fingers here // and hoping that things continue to work if (pir->iidx != IIDIDX_INVALID) { DWORD dwFlags; pir->pto = FIXVDMPTR(pir->vpvThis16, THUNK1632OBJ); dwFlags = pir->pto->grfFlags; RELVDMPTR(pir->vpvThis16); if ((dwFlags & PROXYFLAG_TEMPORARY) == 0) { DebugValidateProxy1632(pir->vpvThis16); pir->ti.pThkMgr->ReleaseProxy1632(pir->vpvThis16); } } } #if DBG == 1 if ( !pir->ti.fResultThunked && FAILED(dwResult) ) { if (pir->iidx == IIDIDX_INVALID) { thkDebugOut((DEB_FAILURES, "InvokeOn32 probable failure %s sc = %08lX\n", apszApiNames[dwMethod], dwResult)); } else { thkDebugOut((DEB_FAILURES, "InvokeOn32 probable failure %s::%s sc = %08lX\n", inInterfaceNames[pir->iidx].pszInterface, inInterfaceNames[pir->iidx].ppszMethodNames[dwMethod], dwResult)); } if(thkInfoLevel & DEB_DBGFAIL) thkAssert(!"Wish to Debug"); } CheckStackState16(&sr); #endif pir->ti.pThkMgr->SetThkState(THKSTATE_NOCALL); DebugDecrementNestingLevel(); if ( !pir->ti.fResultThunked ) { dwResult = TransformHRESULT_3216( dwResult ); } #if DBG == 1 if (pir->iidx == IIDIDX_INVALID) { thkDebugOut((DEB_INVOKES, "%s#(%04X):InvokeOn32 on %p, %s returns 0x%08lX\n", NestingLevelString(), ulInvokeOn32_count, pir->ti.pvfn, apszApiNames[dwMethod], dwResult )); } else { thkDebugOut((DEB_INVOKES, "%s#(%04X):InvokeOn32 on %p:%p, %s::%s returns 0x%08lX\n", NestingLevelString(), ulInvokeOn32_count, pir->ppvfnThis32, pir->ti.pvfn, inInterfaceNames[pir->iidx].pszInterface, inInterfaceNames[pir->iidx].ppszMethodNames[dwMethod], dwResult)); } #endif STACKFREE32(pir, sizeof(INVOKE32RECORD)); return dwResult; }