1374 lines
43 KiB
C++
1374 lines
43 KiB
C++
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1992 - 1993.
|
|
//
|
|
// File: actapi.cxx
|
|
//
|
|
// Contents: Functions that activate objects residing in persistent storage.
|
|
//
|
|
// Functions: CoGetPersistentInstanceEx
|
|
//
|
|
// History: 20-Sep-95 GregJen Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
#include <ole2int.h>
|
|
|
|
#include <iface.h>
|
|
#include <objsrv.h>
|
|
#include <compname.hxx>
|
|
#include "resolver.hxx"
|
|
#include "smstg.hxx"
|
|
#include "objact.hxx"
|
|
#include "clsctx.hxx"
|
|
#include "treat.hxx"
|
|
|
|
// We use this to calculate the hash value for the path
|
|
extern DWORD CalcFileMonikerHash(LPWSTR pwszPath);
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Class: CSplit_QI
|
|
//
|
|
// Synopsis: Helper for splitting a multi_QI block into separate arrays
|
|
//
|
|
// Arguments: [pMqi] - pointer to multi_QI array
|
|
//
|
|
// History: 14-Nov-95 GregJen Created
|
|
//
|
|
// notes: the RPC calls to the SCM take a bunch of arrays, some [in], and
|
|
// some [out]. We get called with an array of structs. This class
|
|
// splits everything out of the array of MULTI_QI structs, and
|
|
// makes arrays for the RPC call parameters.
|
|
//--------------------------------------------------------------------------
|
|
|
|
class CSplit_QI
|
|
{
|
|
private:
|
|
PMInterfacePointer SomePMItfPtrs[2];
|
|
HRESULT SomeHRs[2];
|
|
IID SomeIIDs[2];
|
|
|
|
DWORD _dwCount;
|
|
|
|
char * _pAllocBlock;
|
|
|
|
public:
|
|
PMInterfacePointer * _pItfArray;
|
|
HRESULT * _pHrArray;
|
|
IID * _pIIDArray;
|
|
|
|
// we just have a constructor and a destructor
|
|
CSplit_QI( HRESULT & hr, DWORD count, MULTI_QI * pInputArray );
|
|
|
|
~CSplit_QI();
|
|
|
|
};
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: CSplit_QI constructor
|
|
//
|
|
// Synopsis: Helper for allocating the arrays for a multi-qi call
|
|
//
|
|
// Arguments: [hr] - hr to return by reference
|
|
// [count] - number of IIDs requested
|
|
// [pInputArray] - the MULTI_QI structure passed in to us
|
|
//
|
|
// Returns: S_OK - everything set up OK
|
|
//
|
|
// History: 01-Dec-95 GregJen Created
|
|
////
|
|
//--------------------------------------------------------------------------
|
|
CSplit_QI::CSplit_QI( HRESULT & hr, DWORD count, MULTI_QI * pInputArray )
|
|
{
|
|
_pAllocBlock = NULL;
|
|
_pItfArray = NULL;
|
|
_dwCount = count;
|
|
|
|
// if they only asked for 1 or 2, save time by just using
|
|
// our memory on the stack
|
|
if ( count <= 2 )
|
|
{
|
|
_pItfArray = SomePMItfPtrs;
|
|
_pHrArray = SomeHRs;
|
|
_pIIDArray = SomeIIDs;
|
|
for ( DWORD i = 0; i < count; i++ )
|
|
{
|
|
_pIIDArray[i] = *(pInputArray[i].pIID);
|
|
}
|
|
memset( _pItfArray, 0, sizeof(SomePMItfPtrs) );
|
|
|
|
hr = S_OK;
|
|
return;
|
|
}
|
|
|
|
ULONG ulItfArrSz = count * sizeof( PMInterfacePointer );
|
|
ULONG ulHRArrSz = count * sizeof( HRESULT );
|
|
ULONG ulIIDArrSz = count * sizeof( IID );
|
|
|
|
_pAllocBlock = (char * )PrivMemAlloc( ulItfArrSz +
|
|
ulHRArrSz +
|
|
ulIIDArrSz );
|
|
if ( _pAllocBlock )
|
|
{
|
|
hr = S_OK;
|
|
|
|
// carve up the allocated block
|
|
_pItfArray = (PMInterfacePointer *) _pAllocBlock;
|
|
_pHrArray = (HRESULT *) (_pAllocBlock +
|
|
ulItfArrSz );
|
|
_pIIDArray = (IID * ) ( _pAllocBlock +
|
|
ulItfArrSz +
|
|
ulHRArrSz );
|
|
|
|
// copy the IIDs and zero the MInterfacePointers
|
|
for ( DWORD i = 0; i < count; i++ )
|
|
{
|
|
_pIIDArray[i] = *(pInputArray[i].pIID);
|
|
}
|
|
memset( _pItfArray, 0, ulItfArrSz );
|
|
|
|
}
|
|
else
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
|
|
}
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: CSplit_QI destructor
|
|
//
|
|
// Synopsis: Helper for freeing the arrays for a multi-qi call
|
|
//
|
|
// Arguments: none
|
|
//
|
|
// Returns: nothing
|
|
//
|
|
// History: 01-Dec-95 GregJen Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
CSplit_QI::~CSplit_QI()
|
|
{
|
|
|
|
// make sure to clean up any dangling interface pointers
|
|
if ( _pItfArray )
|
|
{
|
|
for ( DWORD i = 0; i < _dwCount; i++ )
|
|
{
|
|
if ( _pItfArray[i] )
|
|
{
|
|
CXmitRpcStream xrpc( (InterfaceData*)_pItfArray[i] );
|
|
|
|
CoReleaseMarshalData(&xrpc);
|
|
|
|
MyMemFree(_pItfArray[i]);
|
|
_pItfArray[i] = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
// only do the free if we allocated something
|
|
if ( _pAllocBlock )
|
|
{
|
|
PrivMemFree( _pAllocBlock );
|
|
}
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: UpdateResultsArray
|
|
//
|
|
// Synopsis: Helper for returning the correct hr from a multi-qi call
|
|
//
|
|
// Arguments: [hrIn] - hr from the calling function
|
|
// [dwCount] - number of IIDs requested
|
|
// [pResults] - where to put pointer to returned interface
|
|
//
|
|
// Returns: S_OK - All Interface are OK
|
|
//
|
|
// History: 30-Aug-95 GregJen Created
|
|
////
|
|
//--------------------------------------------------------------------------
|
|
inline
|
|
HRESULT
|
|
UpdateResultsArray( HRESULT hrIn, DWORD dwCount, MULTI_QI * pResults )
|
|
{
|
|
HRESULT hr = hrIn;
|
|
DWORD i;
|
|
|
|
// make sure the HR is set correctly
|
|
if ( SUCCEEDED( hrIn ) )
|
|
{
|
|
// assume no interfaces were found
|
|
DWORD dwFound = 0;
|
|
for ( i=0; i<dwCount; i++ )
|
|
{
|
|
if ( FAILED( pResults[i].hr ) )
|
|
pResults[i].pItf = NULL;
|
|
else
|
|
{
|
|
dwFound++;
|
|
Win4Assert(pResults[i].pItf != NULL );
|
|
}
|
|
}
|
|
|
|
if ( dwFound == 0 )
|
|
{
|
|
// if there was only 1 interface, return its hr.
|
|
if ( dwCount == 1 )
|
|
hr = pResults[0].hr;
|
|
else
|
|
hr = E_NOINTERFACE;
|
|
}
|
|
else if ( dwFound < dwCount )
|
|
hr = CO_S_NOTALLINTERFACES;
|
|
|
|
}
|
|
else
|
|
{
|
|
// failed - set all the hr's to the overall failure code,
|
|
// and clean up any interface pointers we got
|
|
for ( i=0; i<dwCount; i++ )
|
|
{
|
|
if ( pResults[i].pItf )
|
|
pResults[i].pItf->Release();
|
|
pResults[i].pItf = NULL;
|
|
pResults[i].hr = hr;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: DoBetterUnmarshal
|
|
//
|
|
// Synopsis: Helper for unmarshaling an interface from remote
|
|
//
|
|
// Arguments: [pIFD] - serialized interface reference returned by SCM
|
|
// [riid] - interface ID requested by application
|
|
// [ppvUnk] - where to put pointer to returned interface
|
|
//
|
|
// Returns: S_OK - Interface unmarshaled
|
|
//
|
|
// Algorithm: Convert marshaled data to a stream and then unmarshal
|
|
// to the right interface
|
|
//
|
|
//
|
|
// History: 11-May-93 Ricksa Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
inline
|
|
HRESULT DoBetterUnmarshal(MInterfacePointer *&pIFD, REFIID riid, IUnknown **ppvUnk)
|
|
{
|
|
// Convert returned interface to a stream
|
|
CXmitRpcStream xrpc( (InterfaceData*)pIFD );
|
|
|
|
HRESULT hr = CoUnmarshalInterface(&xrpc, riid, (void **) ppvUnk);
|
|
|
|
//CODEWORK: Stress revealed CoGetClassObject returning a null class factory
|
|
// and S_OK
|
|
Win4Assert(((hr == S_OK && *ppvUnk != NULL) ||
|
|
(hr != S_OK && *ppvUnk == NULL))
|
|
&& "DoBetterUnmarshal QueryInterface failure");
|
|
|
|
MyMemFree(pIFD);
|
|
pIFD = NULL;
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: UnmarshalMultipleSCMResults
|
|
//
|
|
// Synopsis: Common routine for dealing with results from SCM
|
|
//
|
|
// Arguments: [sc] - SCODE returned by SCM
|
|
// [pIFD] - serialized interface reference returned by SCM
|
|
// [riid] - interface ID requested by application
|
|
// [ppunk] - where to put pointer to returned interface
|
|
// [pwszDllPath] - path to DLL if there is one.
|
|
// [ppunk] - pointer to returned interface.
|
|
// [usMethodOrdinal] - method for error reporting
|
|
//
|
|
// Returns: TRUE - processing is complete for the call
|
|
// FALSE - this is a DLL and client needs to instantiate.
|
|
//
|
|
// Algorithm: If the SCODE indicates a failure, then this sets an
|
|
// SCODE indicating that the service controller returned
|
|
// an error and propagates the result from the SCM. Otherwise,
|
|
// if the SCM has returned a result indicating that a
|
|
// handler has been returned, the handler DLL is cached.
|
|
// If a marshaled interface has been returned, then that is
|
|
// unmarshaled. If an inprocess server has been returned,
|
|
// the DLL is cached and the class object is created.
|
|
//
|
|
// History: 11-May-93 Ricksa Created
|
|
//
|
|
// Notes: This routine is simply a helper for CoGetPersistentInstance.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
BOOL UnmarshalMultipleSCMResults(
|
|
HRESULT& hr,
|
|
PMInterfacePointer *pItfArray,
|
|
DWORD dwContext,
|
|
REFCLSID rclsid,
|
|
IUnknown * punkOuter,
|
|
DWORD dwCount,
|
|
IID * pIIDs,
|
|
HRESULT * pHrArray,
|
|
MULTI_QI * pResults,
|
|
DWORD dwDllThreadModel,
|
|
WCHAR *pwszDllPath,
|
|
IClassFactory **ppvCf)
|
|
{
|
|
BOOL fResult = TRUE;
|
|
DWORD i;
|
|
HRESULT hr2;
|
|
IUnknown * pUnk;
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// Flag for fall through from a 16 bit case
|
|
BOOL f16BitFallThru = FALSE;
|
|
// Flag for fall through from got-handler
|
|
BOOL fGetClassObject = FALSE;
|
|
BOOL fHandlerAndServer = FALSE;
|
|
|
|
switch (hr)
|
|
{
|
|
#ifdef GET_INPROC_FROM_SCM
|
|
case SCM_S_HANDLER16:
|
|
CairoleDebugOut((DEB_ACTIVATE,
|
|
"16-bit InprocHandler\n"));
|
|
|
|
// Note: if the process is a 32 bit process and the
|
|
// DLL is a 16 bit DLL, the load will fail. Since
|
|
// we assume that this is a fairly rare case, we
|
|
// let the lower level code discover this.
|
|
|
|
f16BitFallThru = TRUE;
|
|
|
|
#ifdef WX86OLE
|
|
case SCM_S_HANDLERX86:
|
|
#endif
|
|
case SCM_S_HANDLER:
|
|
CairoleDebugOut((DEB_ACTIVATE,
|
|
"InprocHandler(%ws)\n",pwszDllPath));
|
|
|
|
// Just in case we chicken out and back out our changes
|
|
if (!f16BitFallThru)
|
|
{
|
|
// Validate that 32 bit handler DLL is being loaded
|
|
// in the correct process.
|
|
hr = CheckScmHandlerResult(pwszDllPath);
|
|
|
|
if (hr != NOERROR)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Figure out if we really need the class object for the
|
|
// handler. Otherwise we will just put it in the cache
|
|
// and unmarshal the class object.
|
|
fGetClassObject =
|
|
(dwContext & CLSCTX_INPROC_HANDLER) ? TRUE : FALSE;
|
|
|
|
/***
|
|
#else // GET_INPROC_FROM_SCM
|
|
// Only time we should be in this path is when we called the
|
|
// SCM for non-INPROC and get advised that a handler exists
|
|
fGetClassObject = FALSE;
|
|
***/
|
|
|
|
// Store the handler returned
|
|
pUnk = gdllcacheHandler.Add(rclsid, IID_IClassFactory,
|
|
dwDllThreadModel, pwszDllPath, fGetClassObject,
|
|
(hr == SCM_S_HANDLER16),
|
|
#ifdef WX86OLE
|
|
(hr == SCM_S_HANDLERX86),
|
|
#endif
|
|
hr);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
if (fGetClassObject)
|
|
{
|
|
// Request was really for a handler so we are done.
|
|
*ppvCf = (IClassFactory*) pUnk;
|
|
fResult = FALSE;
|
|
break;
|
|
}
|
|
|
|
// We got a handler back but we have just cached it to make
|
|
// processing faster when we create a real instance of an
|
|
// object. So we unmarshal the real object.
|
|
fHandlerAndServer = TRUE;
|
|
#endif // GET_INPROC_FROM_SCM
|
|
|
|
case S_OK :
|
|
if ( punkOuter && !fHandlerAndServer )
|
|
return CLASS_E_NOAGGREGATION;
|
|
|
|
for ( i=0; i<dwCount; i++, pResults++ )
|
|
{
|
|
|
|
pResults->hr = pHrArray[i];
|
|
|
|
if ( SUCCEEDED( pHrArray[i] ) )
|
|
{
|
|
hr2 = DoBetterUnmarshal( pItfArray[i],
|
|
*(pResults->pIID),
|
|
&pResults->pItf);
|
|
|
|
|
|
|
|
// ... and try to set the overall HR correctly
|
|
pResults->hr = hr2;
|
|
if ( FAILED( hr2 ) )
|
|
hr = CO_S_NOTALLINTERFACES;
|
|
}
|
|
else
|
|
hr = CO_S_NOTALLINTERFACES;
|
|
|
|
}
|
|
break;
|
|
|
|
#ifdef GET_INPROC_FROM_SCM
|
|
case SCM_S_INPROCSERVER16:
|
|
CairoleDebugOut((DEB_ACTIVATE, "16-bit InprocServer\n"));
|
|
|
|
#ifdef WX86OLE
|
|
case SCM_S_INPROCSERVERX86:
|
|
#endif
|
|
case SCM_S_INPROCSERVER:
|
|
CairoleDebugOut((DEB_ACTIVATE, "InprocServer(%ws)\n",pwszDllPath));
|
|
|
|
// Just in case we chicken out and back out our changes
|
|
// This is an inprocesses server -- we want cache that information
|
|
// and do the work of instantiating an object.
|
|
*ppvCf = (IClassFactory*) gdllcacheInprocSrv.Add(rclsid, IID_IClassFactory,
|
|
dwDllThreadModel, pwszDllPath, TRUE,
|
|
(hr == SCM_S_INPROCSERVER16),
|
|
#ifdef WX86OLE
|
|
(hr == SCM_S_INPROCSERVERX86),
|
|
#endif
|
|
hr);
|
|
|
|
// If we actually got an inproc server object successfully
|
|
// then we want to continue processing otherwise we can
|
|
// just return the error that occurred.
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
fResult = FALSE;
|
|
}
|
|
#else // GET_INPROC_FROM_SCM
|
|
// Error: Should never come here as we handled INPROC_SERVERS
|
|
// before calling SCM
|
|
Win4Assert((FALSE) && "UnmarshalMultipleSCMResults: SCM_S_INPROC return from SCM");
|
|
#endif // GET_INPROC_FROM_SCM
|
|
}
|
|
}
|
|
|
|
return fResult;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: CoGetInstanceFromFile
|
|
//
|
|
// Synopsis: Returns an instantiated interface to an object whose
|
|
// stored state resides on disk.
|
|
//
|
|
// Arguments: [pServerInfo] - server information block
|
|
// [dwCtrl] - kind of server required
|
|
// [grfMode] - how to open the storage if it is a file.
|
|
// [pwszName] - name of storage if it is a file.
|
|
// [pstg] - IStorage to use for object
|
|
// [pclsidOverride]
|
|
// [ppvUnk] - where to put bound interface pointer
|
|
//
|
|
// Returns: S_OK - object bound successfully
|
|
// MISSING
|
|
//--------------------------------------------------------------------------
|
|
|
|
STDAPI CoGetInstanceFromFile(
|
|
COSERVERINFO * pServerInfo,
|
|
CLSID * pclsidOverride,
|
|
IUnknown * punkOuter, // only relevant locally
|
|
DWORD dwClsCtx,
|
|
DWORD grfMode,
|
|
OLECHAR * pwszName,
|
|
DWORD dwCount,
|
|
MULTI_QI * pResults )
|
|
{
|
|
TRACECALL(TRACE_ACTIVATION, "CoGetInstanceFromFile");
|
|
|
|
#ifdef DCOM
|
|
if ( pServerInfo &&
|
|
( ! IsValidPtrIn( pServerInfo, sizeof(COSERVERINFO) ) ||
|
|
pServerInfo->dwReserved1 ||
|
|
pServerInfo->dwReserved2 ) )
|
|
#else
|
|
if ( pServerInfo )
|
|
#endif
|
|
return E_INVALIDARG;
|
|
|
|
return GetInstanceHelper( pServerInfo,
|
|
pclsidOverride,
|
|
punkOuter,
|
|
dwClsCtx,
|
|
grfMode,
|
|
pwszName,
|
|
NULL,
|
|
dwCount,
|
|
pResults );
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: CoGetInstanceFromIStorage
|
|
//
|
|
// Synopsis: Returns an instantiated interface to an object whose
|
|
// stored state resides on disk.
|
|
//
|
|
// Arguments: [pServerInfo] - server information block
|
|
// [dwCtrl] - kind of server required
|
|
// [grfMode] - how to open the storage if it is a file.
|
|
// [pwszName] - name of storage if it is a file.
|
|
// [pstg] - IStorage to use for object
|
|
// [pclsidOverride]
|
|
// [ppvUnk] - where to put bound interface pointer
|
|
//
|
|
// Returns: S_OK - object bound successfully
|
|
// MISSING
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
STDAPI CoGetInstanceFromIStorage(
|
|
COSERVERINFO * pServerInfo,
|
|
CLSID * pclsidOverride,
|
|
IUnknown * punkOuter, // only relevant locally
|
|
DWORD dwClsCtx,
|
|
struct IStorage * pstg,
|
|
DWORD dwCount,
|
|
MULTI_QI * pResults )
|
|
{
|
|
|
|
STATSTG statstg;
|
|
CLSID clsid;
|
|
HRESULT hr;
|
|
|
|
TRACECALL(TRACE_ACTIVATION, "CoGetInstanceFromIStorage");
|
|
|
|
#ifdef DCOM
|
|
if ( pServerInfo &&
|
|
( ! IsValidPtrIn( pServerInfo, sizeof(COSERVERINFO) ) ||
|
|
pServerInfo->dwReserved1 ||
|
|
pServerInfo->dwReserved2 ) )
|
|
#else
|
|
if ( pServerInfo )
|
|
#endif
|
|
return E_INVALIDARG;
|
|
|
|
statstg.pwcsName = 0;
|
|
|
|
hr = pstg->Stat(&statstg, STATFLAG_DEFAULT);
|
|
|
|
if ( FAILED(hr) )
|
|
return hr;
|
|
|
|
if ( pclsidOverride == NULL )
|
|
clsid = statstg.clsid;
|
|
else
|
|
clsid = *pclsidOverride;
|
|
|
|
hr = GetInstanceHelper( pServerInfo,
|
|
pclsidOverride,
|
|
punkOuter,
|
|
dwClsCtx,
|
|
statstg.grfMode,
|
|
statstg.pwcsName,
|
|
pstg,
|
|
dwCount,
|
|
pResults );
|
|
|
|
PrivMemFree( statstg.pwcsName );
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT GetInstanceHelper(
|
|
COSERVERINFO * pServerInfo,
|
|
CLSID * pclsidOverride,
|
|
IUnknown * punkOuter, // only relevant locally
|
|
DWORD dwClsCtx,
|
|
DWORD grfMode,
|
|
OLECHAR * pwszName,
|
|
struct IStorage * pstg,
|
|
DWORD dwCount,
|
|
MULTI_QI * pResults )
|
|
{
|
|
if (!IsApartmentInitialized())
|
|
return CO_E_NOTINITIALIZED;
|
|
|
|
IUnknown *punk;
|
|
|
|
WCHAR awcNameBuf[MAX_PATH];
|
|
WCHAR * pwszNameUNC = awcNameBuf;
|
|
WCHAR awcServer[MAX_PATH];
|
|
WCHAR * pwszServer = awcServer;
|
|
|
|
DWORD dwDllServerType = IsSTAThread() ? APT_THREADED : FREE_THREADED;
|
|
IClassFactory * pcf;
|
|
HRESULT hr = E_FAIL;
|
|
BOOL fExitBlock;
|
|
BOOL bFileWasOpened;
|
|
DWORD i; // handy iterator
|
|
|
|
// Make sure input request is at least slightly logical
|
|
if ( ((pwszName == NULL) && (pstg == NULL))
|
|
|| ((dwClsCtx & ~CLSCTX_VALID_MASK) != 0)
|
|
|| ( dwCount < 1 )
|
|
|| ( pResults == NULL ) )
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
// check the MULTI_QI for validity (and clear out the hresults)
|
|
for ( i=0; i<dwCount; i++ )
|
|
{
|
|
if ( pResults[i].pItf || !pResults[i].pIID )
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto final_exit;
|
|
}
|
|
pResults[i].hr = E_NOINTERFACE;
|
|
}
|
|
|
|
bFileWasOpened = FALSE;
|
|
|
|
CLSID clsid;
|
|
if (pwszName)
|
|
{
|
|
// If there is a path supplied convert it to a normalized form
|
|
// so it can be used by any process in the net.
|
|
hr = ProcessPath(pwszName, &pwszNameUNC, &pwszServer);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
goto exit_point;
|
|
}
|
|
|
|
// Limit on loops for retrying to get class of object
|
|
DWORD cGetClassRetries = 0;
|
|
|
|
// We loop here looking for either the running object or
|
|
// for the class of the file. We do this because there
|
|
// are race conditions where the can be starting or stopping
|
|
// and the class of the object might not be available because
|
|
// of the opening mode of the object's server.
|
|
do
|
|
{
|
|
// Look in the ROT first to see if we need to bother
|
|
// looking up the class of the file.
|
|
|
|
if (GetObjectFromRotByPath(pwszName,
|
|
(IUnknown **) &punk) == S_OK)
|
|
{
|
|
// Got object from ROT so we are done.
|
|
goto qiexit_point;
|
|
}
|
|
|
|
// Try to get the class of the file
|
|
if ( pclsidOverride != NULL )
|
|
{
|
|
clsid = *pclsidOverride;
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
hr = GetClassFile(pwszName, &clsid);
|
|
bFileWasOpened = TRUE;
|
|
}
|
|
|
|
|
|
if (hr == STG_E_ACCESSDENIED)
|
|
{
|
|
// The point here of the sleep is to try to let the
|
|
// operation that is holding the class id unavailable
|
|
// complete.
|
|
Sleep(GET_CLASS_RETRY_SLEEP_MS);
|
|
continue;
|
|
}
|
|
|
|
// Either we succeeded or something other than error
|
|
// access denied occurred here. For all these cases
|
|
// we break the loop.
|
|
break;
|
|
|
|
} while (cGetClassRetries++ < GET_CLASS_RETRY_MAX);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
// If we were unable to determine the classid, and the
|
|
// caller provided one as a Ole1 clsid, try loading it
|
|
// If it succeeds, then return
|
|
|
|
if (pclsidOverride != NULL)
|
|
{
|
|
goto dde_exit;
|
|
}
|
|
|
|
goto final_exit;
|
|
}
|
|
}
|
|
|
|
CLSID tmpClsid;
|
|
|
|
hr = OleGetAutoConvert(clsid, &tmpClsid);
|
|
if ( ( hr == REGDB_E_KEYMISSING ) || ( hr == REGDB_E_CLASSNOTREG ) )
|
|
{
|
|
// do nothing
|
|
}
|
|
else if ( FAILED(hr) )
|
|
{
|
|
goto exit_point;
|
|
}
|
|
else
|
|
{
|
|
clsid = tmpClsid;
|
|
}
|
|
|
|
hr = GetTreatAs(clsid, clsid);
|
|
if ( FAILED(hr) )
|
|
{
|
|
goto exit_point;
|
|
}
|
|
|
|
// Make sure we are asking for the correct inproc server
|
|
dwClsCtx = RemapClassCtxForInProcServer(dwClsCtx);
|
|
|
|
//
|
|
// If this is a OLE 1.0 class, then do a DdeBindToObject on it,
|
|
// and return.
|
|
//
|
|
if (CoIsOle1Class(clsid))
|
|
{
|
|
if (pwszName != NULL)
|
|
{
|
|
goto dde_exit;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Something is fishy here. We don't have a pwszName,
|
|
// yet CoIsOle1Class returned the class as an ole1 class.
|
|
// To get to this point without a pwszName, there must have
|
|
// been a pstg passed into the API.
|
|
//
|
|
// This isn't supposed to happen. To recover, just fall
|
|
// through and load the class as an OLE 2.0 class
|
|
//
|
|
CairoleDebugOut((DEB_ERROR,
|
|
"CoIsOle1Class is TRUE on a storage!\n"));
|
|
}
|
|
}
|
|
|
|
|
|
// At this point, we know the clsid we want to activate
|
|
pcf = (IClassFactory *)
|
|
SearchCacheOrLoadInProc(clsid,
|
|
IID_IClassFactory,
|
|
(pwszServer != NULL),
|
|
FALSE,
|
|
dwClsCtx,
|
|
dwDllServerType,
|
|
hr);
|
|
|
|
if ( pcf ==NULL )
|
|
{
|
|
// Marshal pstg since SCM can't deal with unmarshaled objects
|
|
CSafeStgMarshaled MarshalledStg(pstg, MSHCTX_DIFFERENTMACHINE, hr);
|
|
MInterfacePointer * pMrshlStg;
|
|
|
|
if ( pstg == 0 )
|
|
pMrshlStg = 0;
|
|
else
|
|
pMrshlStg = MarshalledStg;
|
|
|
|
if (FAILED(hr))
|
|
goto exit_point;
|
|
|
|
// split the array of structs into individual arrays
|
|
CSplit_QI SplitQI( hr, dwCount, pResults );
|
|
|
|
DWORD cLoops = 0;
|
|
BOOL FoundInROT;
|
|
|
|
#ifndef GET_INPROC_FROM_SCM
|
|
// Just in case we chicken out and back out our changes
|
|
dwClsCtx &= ~(CLSCTX_INPROC_SERVERS | CLSCTX_INPROC_HANDLERS); // make sure we don't ask for inproc stuff
|
|
#endif // GET_INPROC_FROM_SCM
|
|
|
|
do
|
|
{
|
|
hr = gResolver.GetPersistentInstance( pServerInfo,
|
|
&clsid,
|
|
dwClsCtx,
|
|
grfMode,
|
|
bFileWasOpened,
|
|
pwszName,
|
|
pMrshlStg,
|
|
dwCount,
|
|
SplitQI._pIIDArray,
|
|
&FoundInROT,
|
|
SplitQI._pItfArray,
|
|
SplitQI._pHrArray,
|
|
&dwDllServerType,
|
|
&pwszServer );
|
|
|
|
fExitBlock = UnmarshalMultipleSCMResults(hr,
|
|
SplitQI._pItfArray,
|
|
dwClsCtx,
|
|
clsid,
|
|
punkOuter,
|
|
dwCount,
|
|
SplitQI._pIIDArray,
|
|
SplitQI._pHrArray,
|
|
pResults,
|
|
dwDllServerType,
|
|
pwszServer,
|
|
&pcf);
|
|
|
|
// If we get something from the ROT, we need to retry until
|
|
// we get an object. Because objects can disappear from the
|
|
// ROT async to us, we need to retry a few times. But since
|
|
// this theoretically could happen forever, we place an arbitrary
|
|
// limit on the number of retries to the ROT.
|
|
} while( (hr != NOERROR)
|
|
&& (FoundInROT)
|
|
&& (++cLoops < 5));
|
|
|
|
}
|
|
|
|
if ( pcf )
|
|
{
|
|
// Create the instance and do the qi's
|
|
hr = GetObjectHelperMulti( pcf,
|
|
grfMode,
|
|
punkOuter,
|
|
pwszName,
|
|
pstg,
|
|
dwCount,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
pResults );
|
|
|
|
pcf->Release();
|
|
}
|
|
|
|
exit_point:
|
|
|
|
hr = UpdateResultsArray( hr, dwCount, pResults );
|
|
|
|
final_exit:
|
|
if ( pwszServer != awcServer )
|
|
PrivMemFree( pwszServer );
|
|
|
|
return hr;
|
|
|
|
dde_exit:
|
|
if (hr != MK_E_CANTOPENFILE)
|
|
{
|
|
COleTls Tls;
|
|
if( Tls->dwFlags & OLETLS_DISABLE_OLE1DDE )
|
|
{
|
|
// If this app doesn't want or can tolerate having a DDE
|
|
// window then currently it can't use OLE1 classes because
|
|
// they are implemented using DDE windows.
|
|
//
|
|
hr = CO_E_OLE1DDE_DISABLED;
|
|
goto final_exit;
|
|
}
|
|
|
|
hr = DdeBindToObject(pwszName,
|
|
clsid,
|
|
FALSE,
|
|
IID_IUnknown,
|
|
(void **)&punk);
|
|
|
|
if (FAILED(hr))
|
|
goto final_exit;
|
|
}
|
|
// FALLTHRU to qi exit point
|
|
|
|
qiexit_point:
|
|
// Get the requested interfaces
|
|
for ( i = 0; i<dwCount; i++ )
|
|
{
|
|
pResults[i].hr = punk->QueryInterface(*(pResults[i].pIID),
|
|
(void**)&pResults[i].pItf );
|
|
}
|
|
punk->Release();
|
|
|
|
// Got object from ROT so we are done.
|
|
goto exit_point;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: ICoGetClassObject
|
|
//
|
|
// Synopsis: Internal entry point that returns an instantiated class object
|
|
//
|
|
// Arguments: [rclsid] - class id for class object
|
|
// [dwContext] - kind of server we wish
|
|
// [pvReserved] - Reserved
|
|
// [riid] - interface to bind class object
|
|
// [ppvClassObj] - where to put interface pointer
|
|
//
|
|
// Returns: S_OK - successfully bound class object
|
|
//
|
|
// Algorithm: First, the context is validated. Then we try to use
|
|
// any cached information by looking up either cached in
|
|
// process servers or handlers based on the context.
|
|
// If no cached information suffices, we call the SCM
|
|
// to find out what to use. If the SCM returns a handler
|
|
// or an inprocess server, we cache that information.
|
|
// If the class is implemented by a local server, then
|
|
// the class object is unmarshaled. Otherwise, the object
|
|
// is instantiated locally using the returned DLL.
|
|
//
|
|
//
|
|
// History: 15-Nov-94 Ricksa Split into external and internal calls
|
|
//
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
STDAPI ICoGetClassObject(
|
|
REFCLSID rclsid,
|
|
DWORD dwContext,
|
|
COSERVERINFO * pServerInfo,
|
|
REFIID riid,
|
|
void FAR* FAR* ppvClassObj)
|
|
{
|
|
TRACECALL(TRACE_ACTIVATION, "CoGetClassObject");
|
|
|
|
IUnknown *punk = NULL;
|
|
HRESULT hr = S_OK;
|
|
WCHAR *pwszDllToLoad = NULL;
|
|
MInterfacePointer *pIFD = NULL;
|
|
CLSID clsid;
|
|
DWORD dwDllServerType = IsSTAThread() ? APT_THREADED : FREE_THREADED;
|
|
|
|
#ifdef DCOM
|
|
if ( pServerInfo &&
|
|
( ! IsValidPtrIn( pServerInfo, sizeof(COSERVERINFO) ) ||
|
|
pServerInfo->dwReserved1 ||
|
|
pServerInfo->dwReserved2 ) )
|
|
#else
|
|
if ( pServerInfo )
|
|
#endif
|
|
return E_INVALIDARG;
|
|
|
|
BEGIN_BLOCK
|
|
|
|
// IsInternalCLSID will also check to determine if the CLSID is
|
|
// an OLE 1.0 CLSID, in which case we get back our internal
|
|
// class factory.
|
|
|
|
if (IsInternalCLSID(rclsid, riid, hr, ppvClassObj))
|
|
{
|
|
// this is an internally implemented clsid, or an OLE 1.0 class
|
|
// so we already got the class factory (if available) and set
|
|
// the return code appropriately.
|
|
EXIT_BLOCK;
|
|
}
|
|
|
|
if (FAILED(hr = GetTreatAs(rclsid, clsid)))
|
|
{
|
|
EXIT_BLOCK;
|
|
}
|
|
|
|
punk = SearchCacheOrLoadInProc(clsid,
|
|
riid,
|
|
FALSE,
|
|
FALSE,
|
|
dwContext,
|
|
dwDllServerType,
|
|
hr);
|
|
|
|
// If still don't have a punk, go to the scm
|
|
if (!punk)
|
|
{
|
|
// Ask the service controller for the class object
|
|
#ifndef GET_INPROC_FROM_SCM
|
|
// Just in case we chicken out and back out our changes
|
|
dwContext &= ~(CLSCTX_INPROC_SERVERS | CLSCTX_INPROC_HANDLERS); //
|
|
#endif // GET_INPROC_FROM_SCM
|
|
hr = gResolver.GetClassObject(clsid, dwContext, (IID *)&riid,
|
|
pServerInfo, &pIFD, &dwDllServerType, &pwszDllToLoad);
|
|
|
|
// A proxy/stub DLL needs to be loaded as both no matter what
|
|
if (dwContext & CLSCTX_PS_DLL)
|
|
{
|
|
dwDllServerType = BOTH_THREADED;
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
EXIT_BLOCK;
|
|
}
|
|
|
|
// Flag for special handler behavior
|
|
BOOL fGetClassObject;
|
|
|
|
// Flag for fall through from a 16 bit case
|
|
BOOL f16BitFallThru = FALSE;
|
|
|
|
switch (hr)
|
|
{
|
|
#ifdef GET_INPROC_FROM_SCM
|
|
case SCM_S_HANDLER16:
|
|
CairoleDebugOut((DEB_ACTIVATE,
|
|
"16-bit InprocHandler\n"));
|
|
|
|
// Note: if the process is a 32 bit process and the
|
|
// DLL is a 16 bit DLL, the load will fail. Since
|
|
// we assume that this is a fairly rare case, we
|
|
// let the lower level code discover this.
|
|
|
|
f16BitFallThru = TRUE;
|
|
|
|
#ifdef WX86OLE
|
|
case SCM_S_HANDLERX86:
|
|
#endif
|
|
case SCM_S_HANDLER:
|
|
CairoleDebugOut((DEB_ACTIVATE,
|
|
"InprocHandler(%ws)\n",pwszDllToLoad));
|
|
|
|
// Just in case we chicken out and back out our changes
|
|
if (!f16BitFallThru)
|
|
{
|
|
// Validate that 32 bit handler DLL is being loaded
|
|
// in the correct process.
|
|
hr = CheckScmHandlerResult(pwszDllToLoad);
|
|
|
|
if (hr != NOERROR)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Figure out if we really need the class object for the
|
|
// handler. Otherwise we will just put it in the cache
|
|
// and unmarshal the class object.
|
|
fGetClassObject =
|
|
(dwContext & CLSCTX_INPROC_HANDLER) ? TRUE : FALSE;
|
|
|
|
/***
|
|
#else // GET_INPROC_FROM_SCM
|
|
// Only time we should be in this path is when we called the
|
|
// SCM for non-INPROC and get advised that a handler exists
|
|
fGetClassObject = FALSE;
|
|
***/
|
|
|
|
// Store the handler returned
|
|
punk = gdllcacheHandler.Add(clsid, riid, dwDllServerType,
|
|
pwszDllToLoad, fGetClassObject,
|
|
(hr == SCM_S_HANDLER16),
|
|
#ifdef WX86OLE
|
|
(hr == SCM_S_HANDLERX86),
|
|
#endif
|
|
hr);
|
|
|
|
if (fGetClassObject)
|
|
{
|
|
// Request was really for a handler so we are done.
|
|
break;
|
|
}
|
|
|
|
// We got a handler back but we have just cached it to make
|
|
// processing faster when we create a real instance of an
|
|
// object. So we unmarshal the real object.
|
|
|
|
#endif // GET_INPROC_FROM_SCM
|
|
case S_OK :
|
|
|
|
//hr = DoUnmarshal((InterfaceData*)pIFD, riid,(void**) &punk);
|
|
hr = DoBetterUnmarshal(pIFD, riid, &punk);
|
|
break;
|
|
|
|
|
|
#ifdef GET_INPROC_FROM_SCM
|
|
case SCM_S_INPROCSERVER16:
|
|
CairoleDebugOut((DEB_ACTIVATE,
|
|
"16-bit InprocServer\n"));
|
|
|
|
#ifdef WX86OLE
|
|
case SCM_S_INPROCSERVERX86:
|
|
#endif
|
|
case SCM_S_INPROCSERVER:
|
|
CairoleDebugOut((DEB_ACTIVATE,
|
|
"InprocServer(%ws)\n",pwszDllToLoad));
|
|
|
|
// Just in case we chicken out and back out our changes
|
|
// In process server for class object
|
|
punk = gdllcacheInprocSrv.Add(clsid, riid, dwDllServerType,
|
|
pwszDllToLoad, TRUE,(hr == SCM_S_INPROCSERVER16),
|
|
#ifdef WX86OLE
|
|
(hr == SCM_S_INPROCSERVERX86),
|
|
#endif
|
|
hr);
|
|
#else // GET_INPROC_FROM_SCM
|
|
// Error: Should never come here as we handled INPROC_SERVERS
|
|
// before calling SCM
|
|
Win4Assert((FALSE) && "IOldCoGetClassObject: SCM_S_INPROC return from SCM");
|
|
#endif // GET_INPROC_FROM_SCM
|
|
}
|
|
}
|
|
|
|
*ppvClassObj = punk;
|
|
if ((punk == NULL) && SUCCEEDED(hr))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
|
|
END_BLOCK;
|
|
|
|
if (pwszDllToLoad != NULL)
|
|
{
|
|
MyMemFree(pwszDllToLoad);
|
|
}
|
|
|
|
CALLHOOKOBJECTCREATE(hr,clsid,riid,(IUnknown **)ppvClassObj);
|
|
return hr;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: CoCreateInstanceEx
|
|
//
|
|
// Synopsis: Returns an instantiated interface to an object
|
|
//
|
|
//
|
|
// Arguments: [Clsid] - requested CLSID
|
|
// [pServerInfo] - server information block
|
|
// [punkOuter] - controlling unknown for aggregating
|
|
// [dwCtrl] - kind of server required
|
|
// [dwCount] - count of interfaces
|
|
// [pResults] - MULTI_QI struct of interfaces
|
|
//
|
|
// Returns: S_OK - object bound successfully
|
|
// MISSING
|
|
//
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
STDAPI CoCreateInstanceEx(
|
|
REFCLSID Clsid,
|
|
IUnknown * punkOuter, // only relevant locally
|
|
DWORD dwClsCtx,
|
|
COSERVERINFO * pServerInfo,
|
|
DWORD dwCount,
|
|
MULTI_QI * pResults )
|
|
{
|
|
TRACECALL(TRACE_ACTIVATION, "CoCreateInstanceEx");
|
|
|
|
if (!IsApartmentInitialized())
|
|
return CO_E_NOTINITIALIZED;
|
|
|
|
WCHAR awcNameBuf[MAX_PATH];
|
|
WCHAR * pwszNameUNC = awcNameBuf;
|
|
WCHAR awcServer[MAX_PATH];
|
|
WCHAR * pwszServer = awcServer;
|
|
|
|
DWORD dwDllServerType = IsSTAThread() ? APT_THREADED : FREE_THREADED;
|
|
IClassFactory * pcf = NULL;
|
|
HRESULT hr;
|
|
BOOL fExitBlock;
|
|
DWORD i;
|
|
#ifdef WX86OLE
|
|
BOOL fPunkIsProxy;
|
|
#endif
|
|
|
|
#ifdef DCOM
|
|
if ( pServerInfo &&
|
|
( ! IsValidPtrIn( pServerInfo, sizeof(COSERVERINFO) ) ||
|
|
pServerInfo->dwReserved1 ||
|
|
pServerInfo->dwReserved2 ) )
|
|
#else
|
|
if ( pServerInfo )
|
|
#endif
|
|
return E_INVALIDARG;
|
|
|
|
// Make sure input request is at least slightly logical
|
|
if ( ((dwClsCtx & ~CLSCTX_VALID_MASK) != 0)
|
|
|| ( dwCount < 1 )
|
|
|| ( pResults == NULL ) )
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto final_exit;
|
|
}
|
|
|
|
// check the MULTI_QI for validity (and clear out the hresults)
|
|
for ( i=0; i<dwCount; i++ )
|
|
{
|
|
if ( pResults[i].pItf || !pResults[i].pIID )
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto final_exit;
|
|
}
|
|
pResults[i].hr = E_NOINTERFACE;
|
|
}
|
|
|
|
CLSID realclsid;
|
|
|
|
hr = GetTreatAs(Clsid, realclsid);
|
|
if ( FAILED(hr) )
|
|
{
|
|
goto exit_point;
|
|
}
|
|
|
|
// Make sure we are asking for the correct inproc server
|
|
dwClsCtx = RemapClassCtxForInProcServer(dwClsCtx);
|
|
|
|
// IsInternalCLSID will also check to determine if the CLSID is
|
|
// an OLE 1.0 CLSID, in which case we get back our internal
|
|
// class factory.
|
|
|
|
if (IsInternalCLSID(Clsid, IID_IClassFactory, hr, (void **)&pcf))
|
|
{
|
|
// this is an internally implemented clsid, or an OLE 1.0 class
|
|
// so we already got the class factory (if available) and set
|
|
// the return code appropriately.
|
|
;
|
|
}
|
|
else
|
|
{
|
|
// At this point, we know the clsid we want to activate
|
|
pcf = (IClassFactory *)
|
|
SearchCacheOrLoadInProc(realclsid,
|
|
IID_IClassFactory,
|
|
(pwszServer != NULL),
|
|
FALSE,
|
|
dwClsCtx,
|
|
dwDllServerType,
|
|
hr);
|
|
}
|
|
|
|
if ( pcf == NULL )
|
|
{
|
|
// split the array of structs into individual arrays
|
|
CSplit_QI SplitQI( hr, dwCount, pResults );
|
|
|
|
if ( FAILED(hr) )
|
|
goto exit_point;
|
|
|
|
#ifndef GET_INPROC_FROM_SCM
|
|
// Just in case we chicken out and back out our changes
|
|
dwClsCtx &= ~(CLSCTX_INPROC_SERVERS | CLSCTX_INPROC_HANDLERS); // make sure we don't ask for inproc stuff
|
|
#endif // GET_INPROC_FROM_SCM
|
|
|
|
hr = gResolver.CreateInstance(pServerInfo,
|
|
&realclsid,
|
|
dwClsCtx,
|
|
dwCount,
|
|
SplitQI._pIIDArray,
|
|
SplitQI._pItfArray,
|
|
SplitQI._pHrArray,
|
|
&dwDllServerType,
|
|
&pwszServer);
|
|
|
|
|
|
fExitBlock = UnmarshalMultipleSCMResults(hr,
|
|
SplitQI._pItfArray,
|
|
dwClsCtx,
|
|
realclsid,
|
|
punkOuter,
|
|
dwCount,
|
|
SplitQI._pIIDArray,
|
|
SplitQI._pHrArray,
|
|
pResults,
|
|
dwDllServerType,
|
|
pwszServer,
|
|
&pcf);
|
|
|
|
if (fExitBlock)
|
|
goto exit_point;
|
|
}
|
|
|
|
// if we loaded it inproc, get the interfaces
|
|
if ( pcf )
|
|
{
|
|
IUnknown * pUnk;
|
|
HRESULT hr2;
|
|
|
|
#ifdef WX86OLE
|
|
// If we are calling through the wx86 thunk layer then set a
|
|
// flag that to let it know that ole32 is calling and let any
|
|
// custom interface that was specified for an out parameter to
|
|
// x86 code via an api be thunked as IUnknown since we know it
|
|
// will just be returned back to x86 code.
|
|
fPunkIsProxy = gcwx86.IsN2XProxy(pcf);
|
|
if (fPunkIsProxy)
|
|
{
|
|
gcwx86.SetStubInvokeFlag((UCHAR)-1);
|
|
}
|
|
#endif
|
|
// ask for the first interface (we'll use it as our IUnknown)
|
|
hr = pcf->CreateInstance(punkOuter,*(pResults[0].pIID), (void**) &pUnk );
|
|
|
|
// note that we don't need the pcf anymore, whether there is an
|
|
// error or not.
|
|
pcf->Release();
|
|
|
|
if ( FAILED(hr) )
|
|
goto exit_point;
|
|
|
|
for ( i=0; i<dwCount; i++ )
|
|
{
|
|
#ifdef WX86OLE
|
|
// If we are calling through the wx86 thunk layer then set a
|
|
// flag that to let it know that ole32 is calling and let any
|
|
// custom interface that was specified for an out parameter to
|
|
// x86 code via an api be thunked as IUnknown since we know it
|
|
// will just be returned back to x86 code.
|
|
if (fPunkIsProxy)
|
|
{
|
|
gcwx86.SetStubInvokeFlag((UCHAR)-1);
|
|
}
|
|
#endif
|
|
hr2 = pUnk->QueryInterface( *(pResults[i].pIID),
|
|
(void**)&pResults[i].pItf );
|
|
pResults[i].hr = hr2;
|
|
|
|
}
|
|
pUnk->Release();
|
|
// rely on the UpdateResultsArray to count up failed QI's
|
|
}
|
|
|
|
|
|
exit_point:
|
|
hr = UpdateResultsArray( hr, dwCount, pResults );
|
|
|
|
final_exit:
|
|
if ( pwszServer != awcServer )
|
|
PrivMemFree( pwszServer );
|
|
|
|
return hr;
|
|
|
|
}
|