504 lines
14 KiB
C++
504 lines
14 KiB
C++
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// 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 <apilist.hxx>
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// 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;
|
||
|
}
|
||
|
|
||
|
|
||
|
#ifdef _CHICAGO_
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: SSCallback16
|
||
|
//
|
||
|
// Synopsis: Switches to 16 bit and calls back to 16 bit.
|
||
|
//
|
||
|
// Arguments: [vpfn16] -- function pointer
|
||
|
// [dwParam] -- pointer to parameter
|
||
|
//
|
||
|
// Returns:
|
||
|
//
|
||
|
// History: 12-08-94 JohannP (Johann Posch) Created
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
DWORD WINAPI SSCallback16(DWORD vpfn16, DWORD dwParam)
|
||
|
{
|
||
|
DWORD dwRet;
|
||
|
// switch to the 16 bit stack
|
||
|
//
|
||
|
if (SSONBIGSTACK())
|
||
|
{
|
||
|
StackDebugOut((DEB_STCKSWTCH, "%sSSCallback16 32->16(%p)\n",NestingLevelString(), vpfn16));
|
||
|
dwRet = SSCall(8, SSF_SmallStack, WOWCallback16, vpfn16, dwParam);
|
||
|
StackDebugOut((DEB_STCKSWTCH, "%sSSCallback16 32<-16 done\n",NestingLevelString() ));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
dwRet = WOWCallback16(vpfn16, dwParam);
|
||
|
}
|
||
|
return dwRet;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: SSCallback16Ex
|
||
|
//
|
||
|
// Synopsis: Like SSCallback16 except can handle up 16 bytes of parametes
|
||
|
//
|
||
|
// Arguments: [vpfn16] -- see Callback16Ex
|
||
|
// [dwFlags] --
|
||
|
// [cbArgs] --
|
||
|
// [pArgs] --
|
||
|
// [pdwRetCode] --
|
||
|
//
|
||
|
// Returns:
|
||
|
//
|
||
|
// History: 12-08-94 JohannP (Johann Posch) Created
|
||
|
//
|
||
|
// Notes:
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
BOOL WINAPI SSCallback16Ex(DWORD vpfn16, DWORD dwFlags,
|
||
|
DWORD cbArgs, PVOID pArgs, PDWORD pdwRetCode)
|
||
|
{
|
||
|
DWORD dwRet;
|
||
|
// switch to the 16 bit stack
|
||
|
//
|
||
|
if (SSONBIGSTACK())
|
||
|
{
|
||
|
StackDebugOut((DEB_STCKSWTCH, "%sSSCallback16Ex 32->16 (%p)\n",NestingLevelString(), vpfn16));
|
||
|
dwRet = SSCall(20, SSF_SmallStack, WOWCallback16Ex,vpfn16, dwFlags, cbArgs, pArgs, pdwRetCode);
|
||
|
StackDebugOut((DEB_STCKSWTCH, "%sSSCallback16Ex 32<-16 done\n",NestingLevelString() ));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
dwRet = WOWCallback16Ex(vpfn16, dwFlags, cbArgs, pArgs, pdwRetCode);
|
||
|
}
|
||
|
return dwRet;
|
||
|
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: InvokeOn32
|
||
|
//
|
||
|
// Synopsis: Switches to the 32 bit stack and calls SSAPI(InvokeOn32)
|
||
|
//
|
||
|
// Arguments: [dw1] -- See SSAPI(InvokeOn32)
|
||
|
// [dwMethod] --
|
||
|
// [pvStack16] --
|
||
|
//
|
||
|
// Returns:
|
||
|
//
|
||
|
// History: 12-08-94 JohannP (Johann Posch) Created
|
||
|
//
|
||
|
// Notes: Only executed under WIN95
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
STDAPI_(DWORD) InvokeOn32 (DWORD dw1, DWORD dwMethod, LPVOID pvStack16)
|
||
|
{
|
||
|
DWORD dwRes;
|
||
|
if (SSONSMALLSTACK())
|
||
|
{
|
||
|
StackDebugOut((DEB_STCKSWTCH, "%sSSInvokeOn32 16->32 (0x%08x, %p)\n",
|
||
|
NestingLevelString(), dwMethod, pvStack16));
|
||
|
dwRes = SSCall(12 ,SSF_BigStack, SSInvokeOn32, dw1, dwMethod, pvStack16);
|
||
|
StackDebugOut((DEB_STCKSWTCH, "%sSSInvokeOn32 16<-32 done(0x%08x, %p)\n",
|
||
|
NestingLevelString(), dwMethod, pvStack16));
|
||
|
}
|
||
|
else
|
||
|
dwRes = SSInvokeOn32(dw1, dwMethod, pvStack16);
|
||
|
|
||
|
return dwRes;
|
||
|
}
|
||
|
|
||
|
#endif // _CHICAGO_
|
||
|
|