1453 lines
49 KiB
C++
1453 lines
49 KiB
C++
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1992 - 1993.
|
|
//
|
|
// File: cobjact.cxx
|
|
//
|
|
// Contents: Functions that activate objects residing in persistent storage.
|
|
//
|
|
// Functions: UnmarshalSCMResult
|
|
// CoGetPersistentInstance
|
|
// CoGetClassObject
|
|
//
|
|
// History: 11-May-93 Ricksa Created
|
|
// 31-Dec-93 ErikGav Chicago port
|
|
// 07-Apr-94 BruceMa Fixed parameter (#5573)
|
|
// 02-May-94 BruceMa CoGetPersistentInstance could return
|
|
// wrong interface
|
|
// 24-Jun-94 BruceMa Memory allocation check
|
|
// 07-Jul-94 BruceMa UnmarshalSCMResult mem alloc check
|
|
// 28-Jul-94 BruceMa Memory sift fix
|
|
// 30-Jan-95 Ricksa New ROT
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
#include <ole2int.h>
|
|
|
|
#include <clsctx.hxx>
|
|
#include <iface.h>
|
|
#include <objsrv.h>
|
|
#include <compname.hxx>
|
|
#include "resolver.hxx"
|
|
#include "smstg.hxx"
|
|
#include "objact.hxx"
|
|
#include "treat.hxx"
|
|
|
|
// We use this to calculate the hash value for the path
|
|
DWORD CalcFileMonikerHash(LPWSTR pwszPath);
|
|
|
|
// computer name. Note that the static constructor does nothing. When the
|
|
// object first gets used, the computer name is extracted from the registry.
|
|
// we cant do it in the constructor because some things that are loaded
|
|
// early in the boot process (before registry Apis are ready) statically
|
|
// link to this Dll.
|
|
|
|
CComputerName g_CompName;
|
|
|
|
// Number of classes that we will try to use the old binding logic on
|
|
const MAX_MULTI_STEP_CLASSES = 2;
|
|
|
|
// Table of classes. Right now this is only WordPerfect.
|
|
// BUGBUG: We should put this information in the registry and then other
|
|
// badly written 16 bit apps can work as well.
|
|
// BUGBUG: We should reinvestigate whether the WP delayed class registration
|
|
// logic is necessary in the thunk layer.
|
|
const CLSID clsidMultiStep[MAX_MULTI_STEP_CLASSES] =
|
|
{{ 0x89FE3FE3, 0x9FF6, 0x101B, {0xB6, 0x78, 0x04, 0x02, 0x1C, 0x00, 0x70, 0x02}},
|
|
{ 0x1395F281, 0x4326, 0x101b, {0x8B, 0x9A, 0xCE, 0x29, 0x3E, 0xF3, 0x84, 0x49}}};
|
|
|
|
#ifdef _CHICAGO_
|
|
CRpcResolver gResolver;
|
|
#endif
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: GetMultiStepClassFactory
|
|
//
|
|
// Synopsis: Get a class object for a class that can't stand the new
|
|
// optimized binding logic.
|
|
//
|
|
// Arguments: [rclsid] - class for code we wish to get
|
|
// [dwClsctx] - class context required.
|
|
// [ppcf] - where to put the class factory.
|
|
//
|
|
// Returns: S_OK - we are returning a class factor
|
|
// S_FALSE - this is not an old style object
|
|
// Other - some failure occurred.
|
|
//
|
|
// History: 05-11-95 Ricksa Created
|
|
//
|
|
//+-------------------------------------------------------------------------
|
|
HRESULT GetMultiStepClassFactory(
|
|
REFCLSID rclsid,
|
|
DWORD dwClsctx,
|
|
IClassFactory **ppcf)
|
|
{
|
|
HRESULT hr = S_FALSE;
|
|
|
|
// We only care if this is a request for a local server because in the
|
|
// in proc case there is no time lag between calls.
|
|
if (dwClsctx & CLSCTX_LOCAL_SERVER)
|
|
{
|
|
// Is this a class that we know about that should be a slow bind?
|
|
for (int i = 0; i < MAX_MULTI_STEP_CLASSES; i++)
|
|
{
|
|
if (IsEqualCLSID(clsidMultiStep[i], rclsid))
|
|
{
|
|
// Get the class object & return it.
|
|
hr = ICoGetClassObject(rclsid, CLSCTX_LOCAL_SERVER, NULL,
|
|
IID_IClassFactory, (void **) ppcf);
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: GetObjectByPath
|
|
//
|
|
// Synopsis: Get object from the ROT by its path
|
|
//
|
|
// Arguments: [pwszName] - name of object to get from the ROT
|
|
// [ppvUnk] - unk to return to caller
|
|
// [riid] - interface to get.
|
|
//
|
|
// Returns: S_OK - got object from the ROT
|
|
// S_FALSE - object was not in the ROT
|
|
// Other - QueryInterface for IID failed.
|
|
//
|
|
// Notes: Ask ROT if path is in the ROT. If it is QI for the requested
|
|
// interface.
|
|
//
|
|
// History: 03-15-95 Ricksa Created
|
|
//
|
|
// Notes: This routine counts on the fact that S_FALSE is not a valid
|
|
// response IUnknown::QueryInterface.
|
|
//
|
|
//+-------------------------------------------------------------------------
|
|
HRESULT GetObjectByPath(WCHAR *pwszName, void **ppvUnk, REFIID riid)
|
|
{
|
|
HRESULT hr = S_FALSE;
|
|
|
|
IUnknown *punk;
|
|
|
|
if (GetObjectFromRotByPath(pwszName, &punk) == S_OK)
|
|
{
|
|
// Get the requested interface
|
|
hr = punk->QueryInterface(riid, ppvUnk);
|
|
|
|
Win4Assert((hr != S_FALSE) && "GetObjectByPath QI ret S_FALSE");
|
|
punk->Release();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: RemapClassCtxForInProcServer
|
|
//
|
|
// Synopsis: Remap CLSCTX so that the correct type of inproc server will
|
|
// be requested.
|
|
//
|
|
// Arguments: [dwCtrl] - requested server context
|
|
//
|
|
// Returns: Updated dwCtrl appropriate for the process' context
|
|
//
|
|
// Notes: If an inproc server is requested make sure it is the right
|
|
// type for the process. In other words, we only load 16 bit
|
|
// inproc servers into 16 bit processes and 32 bit servers
|
|
// into 32 bit processes. The special logic here is only for
|
|
// 16 bit servers since the attempt to load a 16-bit DLL into
|
|
// a 32 bit process will fail anyway.
|
|
//
|
|
// History: 01-11-95 Ricksa Created
|
|
//
|
|
//+-------------------------------------------------------------------------
|
|
DWORD RemapClassCtxForInProcServer(DWORD dwCtrl)
|
|
{
|
|
if (IsWOWThread())
|
|
{
|
|
// 16 bit process - remap CLSCTX_INPROC_SERVER if necessary
|
|
if ((dwCtrl & CLSCTX_INPROC_SERVER) != 0)
|
|
{
|
|
// Turn on the 16 bit inproc server request and turn off the
|
|
// 32 bit server request flag.
|
|
dwCtrl = (dwCtrl & ~CLSCTX_INPROC_SERVER) | CLSCTX_INPROC_SERVER16;
|
|
}
|
|
// if handlers are requested make sure 16-bit is looked for first
|
|
// We mask out 32bit handler flag for Wow threads because we will
|
|
// always look for a 32 bit handler if we don't find a 16 bit one
|
|
if ((dwCtrl & CLSCTX_INPROC_HANDLER) != 0)
|
|
{
|
|
// Turn on the 16 bit inproc handler request and turn off the
|
|
// 32 bit handler request flag.
|
|
dwCtrl = (dwCtrl & ~CLSCTX_INPROC_HANDLER) | CLSCTX_INPROC_HANDLER16;
|
|
}
|
|
}
|
|
#ifdef WX86OLE
|
|
//
|
|
// if we are allowed to remap the clsctx flags and we are running in a
|
|
// wx86 process then remap the flags to prefer an x86 inproc
|
|
else if (((dwCtrl & CLSCTX_NO_REMAP) == 0) && (gcwx86.IsWx86Enabled()))
|
|
{
|
|
if (dwCtrl & CLSCTX_INPROC_SERVER)
|
|
{
|
|
dwCtrl |= CLSCTX_INPROC_SERVERX86;
|
|
}
|
|
|
|
if (dwCtrl & CLSCTX_INPROC_HANDLER)
|
|
{
|
|
dwCtrl |= CLSCTX_INPROC_HANDLERX86;
|
|
}
|
|
}
|
|
#endif
|
|
else
|
|
{
|
|
if ((dwCtrl & CLSCTX_INPROC_SERVER) != 0)
|
|
{
|
|
// Turn off the 16 bit inproc server request
|
|
dwCtrl &= ~CLSCTX_INPROC_SERVER16;
|
|
}
|
|
}
|
|
#ifdef WX86OLE
|
|
if (dwCtrl & CLSCTX_NO_REMAP)
|
|
{
|
|
dwCtrl &= ~CLSCTX_NO_REMAP;
|
|
}
|
|
#endif
|
|
|
|
return dwCtrl;
|
|
}
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: CheckScmHandlerResult
|
|
//
|
|
// Synopsis: Verify that a 32 bit Handler DLL is being returned to the
|
|
// right context.
|
|
//
|
|
// Arguments: [pwszDllToLoad] - DLL to load
|
|
//
|
|
// Returns: S_OK - Everything is OK
|
|
// CO_E_ERRORINDLL - Trying to load bad DLL for process type.
|
|
//
|
|
// Notes: This is only important for 16 bit processes to prevent them
|
|
// from loading 32 handler code. We only allow the loading of
|
|
// OLE32.DLL as a handler in a 16 bit process because it is
|
|
// already loaded anyway.
|
|
//
|
|
// History: 01-11-95 Ricksa Created
|
|
//
|
|
//+-------------------------------------------------------------------------
|
|
HRESULT CheckScmHandlerResult(WCHAR *pwszDllToLoad)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (IsWOWThread())
|
|
{
|
|
// We are a 16 bit process. Unless this is OLE32.DLL, we will fail
|
|
// the load of the handler.
|
|
|
|
// Scan string for last "\" if any.
|
|
WCHAR *pwszScan = pwszDllToLoad;
|
|
WCHAR *pwszLastComponent = pwszDllToLoad;
|
|
|
|
while(*pwszScan != 0)
|
|
{
|
|
if ((*pwszScan == '\\') || (*pwszScan == '/'))
|
|
{
|
|
pwszLastComponent = pwszScan + 1;
|
|
}
|
|
|
|
pwszScan++;
|
|
}
|
|
|
|
// Compare last path component to see if it ole32.dll
|
|
if (lstrcmpiW(pwszLastComponent, L"OLE32.DLL") != 0)
|
|
{
|
|
hr = CO_E_ERRORINDLL;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: IsInternalCLSID
|
|
//
|
|
// Synopsis: checks if the given clsid is an internal class, and
|
|
// bypasses the TreatAs and SCM lookup if so. Also checks for
|
|
// OLE 1.0 classes, which are actually considered to be
|
|
// internal, since their OLE 2.0 implementation wrapper is
|
|
// ours.
|
|
//
|
|
// Arguments: [rclsid] - clsid to look for
|
|
// [riid] - the iid requested
|
|
// [hr] - returns the hresult from DllGetClassObject
|
|
// [ppvClassObj] - where to return the class factory
|
|
//
|
|
// Returns: TRUE - its an internal class, hr is the return code from
|
|
// DllGetClassObject and if hr==S_OK ppvClassObj
|
|
// is the class factory.
|
|
// FALSE - not an internal class
|
|
//
|
|
// Notes: internal classes can not be overridden because there are
|
|
// other mechanisms for creating them eg CreateFileMoniker that
|
|
// bypass implementation lookup.
|
|
//
|
|
// History: 5-04-94 Rickhi Created
|
|
// 5-04-94 KevinRo Added OLE 1.0 support
|
|
//
|
|
//+-------------------------------------------------------------------------
|
|
|
|
BOOL IsInternalCLSID(REFCLSID rclsid,
|
|
REFIID riid,
|
|
HRESULT &hr,
|
|
void ** ppvClassObj)
|
|
{
|
|
DWORD *ptr = (DWORD *) &rclsid;
|
|
CLSID clsid = rclsid;
|
|
|
|
if (*(ptr+1) == 0x00000000 && // all internal clsid's have these
|
|
*(ptr+2) == 0x000000C0 && // common values
|
|
*(ptr+3) == 0x46000000)
|
|
{
|
|
// internal class (eg file moniker). just ask our selves
|
|
// for the class factory.
|
|
//
|
|
//
|
|
// Its possible that an OLE 1.0 class has been marked
|
|
// as TREATAS as part of an upgrade. Here we are going
|
|
// to handle the loading of OLE 1.0 servers. We
|
|
// need to do the GetTreatAs trick first. Rather than
|
|
// invalidate this perfectly good caching routine, the
|
|
// GetTreatAs will only be done if the clsid is in the
|
|
// range of the OLE 1.0 UUID's. Note that the GetTreatAs
|
|
// done here will add the class to the cache, so if the
|
|
// resulting class is outside of the internal range, the
|
|
// lookup done later will be nice and fast.
|
|
//
|
|
|
|
WORD hiWord = HIWORD(clsid.Data1);
|
|
|
|
if (hiWord == 3 || hiWord == 4)
|
|
{
|
|
//
|
|
// Its in the OLE 1.0 class range. See if it has
|
|
// been marked as 'treatas'
|
|
//
|
|
GetTreatAs(rclsid, clsid);
|
|
ptr = (DWORD *) &clsid;
|
|
hiWord = HIWORD(clsid.Data1);
|
|
}
|
|
|
|
if ((*ptr > 0x000002ff && *ptr < 0x00000321) ||
|
|
(hiWord == 3 || hiWord == 4))
|
|
{
|
|
// internal class (eg file moniker) or an OLE 1.0 class.
|
|
// just ask our selves for the class factory.
|
|
|
|
hr = DllGetClassObject(clsid, riid, ppvClassObj);
|
|
return TRUE;
|
|
}
|
|
}
|
|
// not an internal class.
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: DoUnmarshal
|
|
//
|
|
// 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 IUnknown. Next, use unknown to query interface to
|
|
//
|
|
//
|
|
// History: 11-May-93 Ricksa Created
|
|
//
|
|
// Notes: This helper should go away when the server marshals
|
|
// to the interface that it actually wants to return.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
HRESULT DoUnmarshal(InterfaceData *pIFD, REFIID riid, void **ppvUnk)
|
|
{
|
|
// Convert returned interface to a stream
|
|
CXmitRpcStream xrpc(pIFD);
|
|
|
|
// Unmarshal interface
|
|
XIUnknown xunk;
|
|
|
|
HRESULT hr = CoUnmarshalInterface(&xrpc, IID_IUnknown, (void **) &xunk);
|
|
|
|
//CODEWORK: Stress revealed CoGetClassObject returning a null class factory
|
|
// and S_OK
|
|
Win4Assert(((hr == S_OK && xunk != NULL) ||
|
|
(hr != S_OK && xunk == NULL)) &&
|
|
"DoUnamrshal CoUnmarshalInterface failure");
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = xunk->QueryInterface(riid, ppvUnk);
|
|
}
|
|
|
|
//CODEWORK: Stress revealed CoGetClassObject returning a null class factory
|
|
// and S_OK
|
|
Win4Assert(((hr == S_OK && *ppvUnk != NULL) ||
|
|
(hr != S_OK && *ppvUnk == NULL))
|
|
&& "DoUnamrshal QueryInterface failure");
|
|
|
|
MyMemFree(pIFD);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: UnmarshalSCMResult
|
|
//
|
|
// 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 UnmarshalSCMResult(
|
|
HRESULT& hr,
|
|
InterfaceData *pIFD,
|
|
REFCLSID rclsid,
|
|
REFIID riid,
|
|
void **ppvUnk,
|
|
DWORD dwDllThreadModel,
|
|
WCHAR *pwszDllPath,
|
|
void **ppvCf)
|
|
{
|
|
BOOL fResult = TRUE;
|
|
#ifndef _UNICODE
|
|
TCHAR *ptszDllPath;
|
|
UINT cb;
|
|
int ret;
|
|
#else // !_UNICODE
|
|
const TCHAR *ptszDllPath;
|
|
#endif // _UNICODE
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// 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",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;
|
|
}
|
|
}
|
|
|
|
|
|
// Store handler class object -- when the request to unmarshal the
|
|
// object call CoGetClassObject, the call will automatically find
|
|
// this handler in the cache.
|
|
|
|
#ifndef _UNICODE
|
|
// Now that SCM doesn't return inproc results we should never exercise
|
|
// this code path. It is here for completeness.
|
|
ptszDllPath = NULL;
|
|
Win4Assert((pwszDllPath) && "UnmarshalSCMResult: (pwszDllPath == NULL)");
|
|
cb = (lstrlenW(pwszDllPath) + 1) * sizeof(WCHAR);
|
|
ptszDllPath = (LPTSTR) PrivMemAlloc(cb);
|
|
if (ptszDllPath == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
return(TRUE);
|
|
}
|
|
|
|
ret = WideCharToMultiByte( (AreFileApisANSI())?CP_ACP:CP_OEMCP,WC_COMPOSITECHECK,
|
|
pwszDllPath, -1, ptszDllPath, cb, NULL, NULL);
|
|
|
|
#if DBG==1
|
|
CairoleAssert(ret != 0 && "Lost characters in Unicode->Ansi conversion");
|
|
#endif
|
|
#else // !_UNICODE
|
|
ptszDllPath = pwszDllPath;
|
|
#endif // _UNICODE
|
|
|
|
gdllcacheHandler.Add(rclsid, IID_IClassFactory, dwDllThreadModel,
|
|
ptszDllPath, FALSE,(hr == SCM_S_HANDLER16),
|
|
#ifdef WX86OLE
|
|
(hr == SCM_S_HANDLERX86),
|
|
#endif
|
|
hr);
|
|
|
|
#ifndef _UNICODE
|
|
PrivMemFree(ptszDllPath);
|
|
#endif
|
|
ptszDllPath = NULL;
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
// Fall into unmarshal code if we also have an interface pointer
|
|
if ( pIFD == NULL )
|
|
{
|
|
break;
|
|
}
|
|
#endif // GET_INPROC_FROM_SCM
|
|
|
|
case S_OK :
|
|
|
|
hr = DoUnmarshal(pIFD, riid, ppvUnk);
|
|
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.
|
|
#ifndef _UNICODE
|
|
ptszDllPath = NULL;
|
|
Win4Assert((pwszDllPath) && "UnmarshalSCMResult: (pwszDllPath == NULL)");
|
|
cb = (lstrlenW(pwszDllPath) + 1) * sizeof(WCHAR);
|
|
ptszDllPath = (LPTSTR) PrivMemAlloc(cb);
|
|
if (ptszDllPath == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
return(TRUE);
|
|
}
|
|
|
|
ret = WideCharToMultiByte( (AreFileApisANSI())?CP_ACP:CP_OEMCP,WC_COMPOSITECHECK,
|
|
pwszDllPath, -1, ptszDllPath, cb, NULL, NULL);
|
|
|
|
#if DBG==1
|
|
CairoleAssert(ret != 0 && "Lost characters in Unicode->Ansi conversion");
|
|
#endif
|
|
#else // !_UNICODE
|
|
ptszDllPath = pwszDllPath;
|
|
#endif // _UNICODE
|
|
*ppvCf = gdllcacheInprocSrv.Add(rclsid, IID_IClassFactory,
|
|
dwDllThreadModel, ptszDllPath, TRUE,
|
|
(hr == SCM_S_INPROCSERVER16),
|
|
#ifdef WX86OLE
|
|
(hr == SCM_S_INPROCSERVERX86),
|
|
#endif
|
|
hr);
|
|
|
|
#ifndef _UNICODE
|
|
PrivMemFree(ptszDllPath);
|
|
#endif
|
|
ptszDllPath = NULL;
|
|
|
|
// 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) && "UnmarshalSCMResult: SCM_S_INPROC return from SCM");
|
|
#endif // GET_INPROC_FROM_SCM
|
|
}
|
|
}
|
|
|
|
return fResult;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: CoGetPersistentInstance
|
|
//
|
|
// Synopsis: Returns an instantiated interface to an object whose
|
|
// stored state resides on disk.
|
|
//
|
|
// Arguments: [riid] - interface to bind object to
|
|
// [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
|
|
// [rclsidOle1] -- ClassID if OLE 1.0 (CLSID_NULL otherwise)
|
|
// [pfOle1Loaded] -- Returns TRUE if loaded as OLE 1.0
|
|
// [ppvUnk] - where to put bound interface pointer
|
|
//
|
|
// Returns: S_OK - object bound successfully
|
|
// MISSING
|
|
//
|
|
// Algorithm: Parameters are validated first. Then the class ID is retrieved
|
|
// from the storage. We check whether we can use a cached
|
|
// in process server. If we can't we call through to the
|
|
// SCM to get the information. We call UnmarshalSCMResult
|
|
// to process the return from the SCM. If the result is
|
|
// completely processed, we return that result to the caller.
|
|
// Otherwise, if the server is inprocess, we go through the
|
|
// steps to create and bind the interface by calling
|
|
// GetObjectHelper. Finally, we QI to the requested interface.
|
|
//
|
|
// History: 11-May-93 Ricksa Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
#ifdef _CHICAGO_
|
|
STDAPI CoGetPersistentInstance(
|
|
REFIID riid,
|
|
DWORD dwCtrl,
|
|
DWORD grfMode,
|
|
WCHAR *pwszName,
|
|
struct IStorage *pstg,
|
|
REFCLSID rclsidOle1,
|
|
BOOL * pfOle1Loaded,
|
|
void **ppvUnk)
|
|
{
|
|
TRACECALL(TRACE_ACTIVATION, "CoGetPersistentInstance");
|
|
CALLHOOKOBJECT(S_OK,CLSID_NULL,IID_IStorage,(IUnknown **)&pstg);
|
|
|
|
if (!IsApartmentInitialized())
|
|
return CO_E_NOTINITIALIZED;
|
|
|
|
IClassFactory *pcf = NULL;
|
|
WCHAR *pwszDllPath = NULL;
|
|
InterfaceData *pIFD = NULL;
|
|
IUnknown *punk = NULL;
|
|
WCHAR awcNameBuf[MAX_PATH];
|
|
WCHAR *pwszNameUNC = awcNameBuf;
|
|
WCHAR awcServer[MAX_PATH];
|
|
WCHAR *pwszServer = awcServer;
|
|
DWORD dwDllTypeToGet = IsSTAThread() ? APT_THREADED : FREE_THREADED;
|
|
DWORD dwDllServerType;
|
|
DWORD dwHash = 0;
|
|
COleTls Tls;
|
|
|
|
HRESULT hr;
|
|
|
|
BEGIN_BLOCK
|
|
|
|
// Set output parameter in case of error.
|
|
*ppvUnk = NULL;
|
|
|
|
// Make sure input request is at least slightly logical
|
|
if (((pstg != NULL) && (pwszName != NULL))
|
|
|| ((pstg == NULL) && (pwszName == NULL))
|
|
|| ((dwCtrl & ~CLSCTX_SERVER) != 0))
|
|
{
|
|
hr = E_INVALIDARG;
|
|
EXIT_BLOCK;
|
|
}
|
|
|
|
// Make sure we are asking for the correct inproc server
|
|
dwCtrl = RemapClassCtxForInProcServer(dwCtrl);
|
|
|
|
CLSID clsid;
|
|
if(pfOle1Loaded != NULL)
|
|
{
|
|
*pfOle1Loaded = FALSE;
|
|
}
|
|
|
|
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))
|
|
{
|
|
EXIT_BLOCK;
|
|
}
|
|
|
|
// 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 ((hr = GetObjectByPath(pwszName, ppvUnk, riid)) != S_FALSE)
|
|
{
|
|
// Got object from ROT so we are done.
|
|
return hr;
|
|
}
|
|
|
|
// Try to get the class of the file
|
|
hr = GetClassFileEx(pwszName, &clsid, rclsidOle1);
|
|
|
|
|
|
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 (rclsidOle1 != CLSID_NULL)
|
|
{
|
|
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;
|
|
EXIT_BLOCK;
|
|
}
|
|
|
|
if (hr != MK_E_CANTOPENFILE)
|
|
hr = DdeBindToObject(pwszName,
|
|
rclsidOle1,
|
|
FALSE,
|
|
riid,
|
|
ppvUnk);
|
|
|
|
if(pfOle1Loaded != NULL)
|
|
{
|
|
*pfOle1Loaded = TRUE;
|
|
}
|
|
}
|
|
|
|
EXIT_BLOCK;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pwszNameUNC = NULL;
|
|
pwszServer = NULL;
|
|
|
|
STATSTG statstg;
|
|
|
|
if (FAILED(hr = pstg->Stat(&statstg, STATFLAG_NONAME)))
|
|
{
|
|
EXIT_BLOCK;
|
|
}
|
|
|
|
clsid = statstg.clsid;
|
|
}
|
|
|
|
GetTreatAs(clsid, clsid);
|
|
//
|
|
// If this is a OLE 1.0 class, then do a DdeBindToObject on it,
|
|
// and return.
|
|
//
|
|
if (CoIsOle1Class(clsid))
|
|
{
|
|
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;
|
|
EXIT_BLOCK;
|
|
}
|
|
|
|
if (pwszName != NULL)
|
|
{
|
|
if (hr != MK_E_CANTOPENFILE)
|
|
hr = DdeBindToObject(pwszName,clsid,FALSE,riid,ppvUnk);
|
|
|
|
if(pfOle1Loaded != NULL)
|
|
{
|
|
*pfOle1Loaded = TRUE;
|
|
}
|
|
EXIT_BLOCK;
|
|
}
|
|
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"));
|
|
}
|
|
}
|
|
|
|
// Default to success at this point
|
|
hr = S_OK;
|
|
|
|
// We cache information about in process servers so we look in the
|
|
// cache first in hopes of saving some time.
|
|
pcf = (IClassFactory *)
|
|
SearchCacheOrLoadInProc(clsid,
|
|
IID_IClassFactory,
|
|
(pwszServer != NULL),
|
|
FALSE,
|
|
dwCtrl,
|
|
dwDllTypeToGet,
|
|
hr);
|
|
|
|
if ((pcf == NULL)
|
|
&& ((hr = GetMultiStepClassFactory(clsid, dwCtrl, &pcf))
|
|
== S_FALSE))
|
|
{
|
|
// Marshal pstg since SCM can't deal with unmarshaled objects
|
|
fsCSafeStgMarshaled sms(pstg, MSHCTX_DIFFERENTMACHINE, hr);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
EXIT_BLOCK;
|
|
}
|
|
|
|
BOOL fExitBlock;
|
|
DWORD cLoops = 0;
|
|
|
|
do
|
|
{
|
|
dwDllServerType = dwDllTypeToGet;
|
|
|
|
#ifndef GET_INPROC_FROM_SCM
|
|
// Just in case we chicken out and back out our changes
|
|
dwCtrl &= ~(CLSCTX_INPROC_SERVERS | CLSCTX_INPROC_HANDLERS); // make sure we don't ask for inproc stuff
|
|
#endif // GET_INPROC_FROM_SCM
|
|
|
|
// Forward call to service controller
|
|
hr = gResolver.ActivateObject(clsid, dwCtrl, grfMode,
|
|
pwszNameUNC, sms, &pIFD, &dwDllServerType,
|
|
&pwszDllPath, pwszServer);
|
|
|
|
fExitBlock = UnmarshalSCMResult(hr, pIFD, clsid, riid, ppvUnk,
|
|
dwDllServerType, pwszDllPath, (void **) &pcf);
|
|
|
|
if ((hr != NOERROR) && (dwDllServerType == GOT_FROM_ROT))
|
|
{
|
|
// Got something from the ROT. We need to make sure the
|
|
// ROT is clean, so we try accessing the ROT again by
|
|
// name which will go through the logic that cleans the
|
|
// table of bogus entries. Note that we can actually find
|
|
// a valid item while we are doing this clean up.
|
|
if ((hr = GetObjectByPath(pwszName, ppvUnk, riid))
|
|
!= S_FALSE)
|
|
{
|
|
// Got object from ROT so we are done.
|
|
return hr;
|
|
}
|
|
|
|
// This might be our last loop so make sure that this
|
|
// will return an error. Since this is a highly unexpected
|
|
// error case, we return that.
|
|
hr = E_UNEXPECTED;
|
|
}
|
|
|
|
// 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) && (dwDllServerType == GOT_FROM_ROT)
|
|
&& (++cLoops < 5));
|
|
|
|
if (fExitBlock)
|
|
{
|
|
EXIT_BLOCK;
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = GetObjectHelper(pcf, grfMode, pwszName, pstg, NULL, &punk);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = punk->QueryInterface(riid, ppvUnk);
|
|
}
|
|
}
|
|
|
|
END_BLOCK;
|
|
|
|
if (pcf != NULL)
|
|
{
|
|
pcf->Release();
|
|
}
|
|
|
|
if (punk != NULL)
|
|
{
|
|
punk->Release();
|
|
}
|
|
|
|
// RPC stubs allocated path so we trust that it is null or valid.
|
|
if (pwszDllPath != NULL)
|
|
{
|
|
MyMemFree(pwszDllPath);
|
|
}
|
|
|
|
CALLHOOKOBJECT(hr,rclsidOle1,riid,(IUnknown **)ppvUnk);
|
|
return hr;
|
|
}
|
|
#endif
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: CoGetClassObject
|
|
//
|
|
// Synopsis: External entry point that returns an instantiated class object
|
|
//
|
|
// Arguments: [rclsid] - class id for class object
|
|
// [dwContext] - kind of server we wish
|
|
// [pvReserved] - Reserved for future use
|
|
// [riid] - interface to bind class object
|
|
// [ppvClassObj] - where to put interface pointer
|
|
//
|
|
// Returns: S_OK - successfully bound class object
|
|
//
|
|
// Algorithm: Validate all then parameters and then pass this to the
|
|
// internal version of the call.
|
|
//
|
|
// History: 11-May-93 Ricksa Created
|
|
// 11-May-94 KevinRo Added OLE 1.0 support
|
|
// 23-May-94 AlexT Make sure we're initialized!
|
|
// 15-Nov-94 Ricksa Split into external and internal calls
|
|
//
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
STDAPI CoGetClassObject(
|
|
REFCLSID rclsid,
|
|
DWORD dwContext,
|
|
LPVOID pvReserved,
|
|
REFIID riid,
|
|
void FAR* FAR* ppvClassObj)
|
|
{
|
|
OLETRACEIN((API_CoGetClassObject, PARAMFMT("rclsid= %I, dwContext= %x, pvReserved= %p, riid= %I, ppvClassObj= %p"),
|
|
&rclsid, dwContext, pvReserved, &riid, ppvClassObj));
|
|
|
|
TRACECALL(TRACE_ACTIVATION, "CoGetClassObject");
|
|
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
if (ppvClassObj)
|
|
{
|
|
*ppvClassObj = NULL;
|
|
}
|
|
|
|
if (!IsApartmentInitialized())
|
|
{
|
|
CairoleDebugOut((DEB_ERROR, "CoGetClassObject failed - Appartment not initialized\n"));
|
|
hr = CO_E_NOTINITIALIZED;
|
|
goto errRtn;
|
|
}
|
|
|
|
// Validate parameters
|
|
if (IsValidPtrIn(&rclsid, sizeof(CLSID))
|
|
&& IsValidPtrIn(&riid, sizeof(IID))
|
|
&& IsValidPtrOut(ppvClassObj, sizeof(void *))
|
|
#ifdef WX86OLE
|
|
&& ((dwContext & ~(CLSCTX_ALL | CLSCTX_INPROC_SERVER16 |
|
|
CLSCTX_INPROC_SERVERX86 |
|
|
CLSCTX_NO_REMAP |
|
|
CLSCTX_PS_DLL |
|
|
CLSCTX_INPROC_HANDLERX86)) == 0))
|
|
#else
|
|
&& ((dwContext & ~(CLSCTX_ALL | CLSCTX_INPROC_SERVER16 |
|
|
CLSCTX_PS_DLL)) == 0))
|
|
#endif
|
|
{
|
|
*ppvClassObj = NULL;
|
|
|
|
// Make sure we are asking for the correct inproc server
|
|
dwContext = RemapClassCtxForInProcServer(dwContext);
|
|
#ifdef DCOM
|
|
hr = ICoGetClassObject(rclsid,
|
|
dwContext,
|
|
(COSERVERINFO *) pvReserved,
|
|
riid,
|
|
ppvClassObj);
|
|
#else
|
|
hr = IOldCoGetClassObject(rclsid, dwContext, pvReserved, riid,
|
|
ppvClassObj);
|
|
#endif
|
|
}
|
|
|
|
errRtn:
|
|
OLETRACEOUT((API_CoGetClassObject, hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifndef DCOM
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: IOldCoGetClassObject
|
|
//
|
|
// 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 IOldCoGetClassObject(
|
|
REFCLSID rclsid,
|
|
DWORD dwContext,
|
|
LPVOID pvReserved,
|
|
REFIID riid,
|
|
void FAR* FAR* ppvClassObj)
|
|
{
|
|
TRACECALL(TRACE_ACTIVATION, "CoGetClassObject");
|
|
|
|
IUnknown *punk = NULL;
|
|
HRESULT hr = S_OK;
|
|
WCHAR *pwszDllToLoad = NULL;
|
|
InterfaceData *pIFD = NULL;
|
|
CLSID clsid;
|
|
DWORD dwDllServerType = IsSTAThread() ? APT_THREADED : FREE_THREADED;
|
|
#ifndef _UNICODE
|
|
TCHAR *ptszDllToLoad;
|
|
UINT cb;
|
|
int ret;
|
|
#else // !_UNICODE
|
|
const TCHAR *ptszDllToLoad;
|
|
#endif // _UNICODE
|
|
|
|
|
|
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;
|
|
}
|
|
|
|
// Make sure we are asking for the correct inproc server
|
|
// We do this here even though it might already be done in CoGetClassObject
|
|
// as we could get here directly from CoCreateInstance.
|
|
dwContext = RemapClassCtxForInProcServer(dwContext);
|
|
|
|
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); // make sure we don't ask for inproc stuff
|
|
#endif // GET_INPROC_FROM_SCM
|
|
hr = gResolver.OldGetClassObject(clsid, dwContext, NULL, &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)
|
|
{
|
|
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));
|
|
|
|
#ifdef GET_INPROC_FROM_SCM
|
|
// 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;
|
|
#endif // GET_INPROC_FROM_SCM
|
|
|
|
#ifndef _UNICODE
|
|
// Now that SCM doesn't return inproc results we should never exercise
|
|
// this code path. It is here for completeness.
|
|
ptszDllToLoad = NULL;
|
|
Win4Assert((pwszDllToLoad) && "IOldCoGetClassObject: (pwszDllToLoad == NULL)");
|
|
cb = (lstrlenW(pwszDllToLoad) + 1) * sizeof(WCHAR);
|
|
ptszDllToLoad = (LPTSTR) PrivMemAlloc(cb);
|
|
if (ptszDllToLoad == NULL)
|
|
{
|
|
return(E_OUTOFMEMORY);
|
|
}
|
|
|
|
ret = WideCharToMultiByte( (AreFileApisANSI())?CP_ACP:CP_OEMCP,WC_COMPOSITECHECK,
|
|
pwszDllToLoad, -1, ptszDllToLoad, cb, NULL, NULL);
|
|
|
|
#if DBG==1
|
|
CairoleAssert(ret != 0 && "Lost characters in Unicode->Ansi conversion");
|
|
#endif
|
|
|
|
#else // !_UNICODE
|
|
ptszDllPath = pwszDllToLoad;
|
|
#endif // _UNICODE
|
|
|
|
// Store the handler returned
|
|
punk = gdllcacheHandler.Add(clsid, riid, dwDllServerType,
|
|
ptszDllToLoad, fGetClassObject,
|
|
(hr == SCM_S_HANDLER16),
|
|
#ifdef WX86OLE
|
|
(hr == SCM_S_HANDLERX86),
|
|
#endif
|
|
hr);
|
|
|
|
#ifndef _UNICODE
|
|
PrivMemFree(ptszDllToLoad);
|
|
#endif
|
|
ptszDllToLoad = NULL;
|
|
|
|
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.
|
|
|
|
case S_OK :
|
|
|
|
hr = DoUnmarshal(pIFD, riid, (void **) &punk);
|
|
break;
|
|
|
|
|
|
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));
|
|
|
|
#ifdef GET_INPROC_FROM_SCM
|
|
// Just in case we chicken out and back out our changes
|
|
// In process server for class object
|
|
#ifndef _UNICODE
|
|
ptszDllToLoad = NULL;
|
|
Win4Assert((pwszDllToLoad) && "IOldCoGetClassObject: (pwszDllToLoad == NULL)");
|
|
cb = (lstrlenW(pwszDllToLoad) + 1) * sizeof(WCHAR);
|
|
ptszDllToLoad = (LPTSTR) PrivMemAlloc(cb);
|
|
if (ptszDllToLoad == NULL)
|
|
{
|
|
return(E_OUTOFMEMORY);
|
|
}
|
|
|
|
ret = WideCharToMultiByte( (AreFileApisANSI())?CP_ACP:CP_OEMCP,WC_COMPOSITECHECK,
|
|
pwszDllToLoad, -1, ptszDllToLoad, cb, NULL, NULL);
|
|
|
|
#if DBG==1
|
|
CairoleAssert(ret != 0 && "Lost characters in Unicode->Ansi conversion");
|
|
#endif
|
|
|
|
#else // !_UNICODE
|
|
ptszDllPath = pwszDllToLoad;
|
|
#endif // _UNICODE
|
|
|
|
punk = gdllcacheInprocSrv.Add(clsid, riid, dwDllServerType,
|
|
ptszDllToLoad, TRUE,(hr == SCM_S_INPROCSERVER16),
|
|
#ifdef WX86OLE
|
|
(hr == SCM_S_INPROCSERVERX86),
|
|
#endif
|
|
hr);
|
|
#ifndef _UNICODE
|
|
PrivMemFree(ptszDllToLoad);
|
|
#endif
|
|
ptszDllToLoad = NULL;
|
|
|
|
#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;
|
|
}
|
|
#endif // !DCOM
|
|
|
|
#ifndef GET_INPROC_FROM_SCM
|
|
// Just in case we chicken out and back out our changes
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: SearchCacheOrLoadInProc
|
|
//
|
|
// Synopsis: Searches the cache for requested classid.
|
|
// If not found looks to see if an inproc server or handler
|
|
// can be loaded (if requested).
|
|
//
|
|
// Arguments: [rclsid] Class ID
|
|
// [riid] Interface required of class object
|
|
// [fRemote] Whether path is remote
|
|
// [fForScm] Whether it's the scm requesting
|
|
// [dwContext] Which context to load
|
|
// [dwCallerThreadModel] Which threading model to load
|
|
// [hr] Reference to HRESULT for error returns
|
|
//
|
|
// Returns: ~NULL - Class factory for object
|
|
// NULL - Class factory could not be found or
|
|
// constructed.
|
|
//
|
|
// History: 2-5-96 murthys Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
IUnknown *SearchCacheOrLoadInProc(REFCLSID rclsid,
|
|
REFIID riid,
|
|
BOOL fRemote,
|
|
BOOL fForSCM,
|
|
DWORD dwContext,
|
|
DWORD dwDllServerType,
|
|
HRESULT &hr)
|
|
{
|
|
IUnknown *punk = NULL;
|
|
|
|
#ifdef WX86OLE
|
|
if (gcwx86.IsWx86Enabled())
|
|
{
|
|
if (dwContext & CLSCTX_INPROC_SERVERX86)
|
|
{
|
|
// Search cache for in process
|
|
punk = gdllcacheInprocSrv.GetOrLoadClass(rclsid,
|
|
riid,
|
|
FALSE,
|
|
FALSE,
|
|
TRUE,
|
|
dwContext & CLSCTX_INPROC_SERVERS,
|
|
dwDllServerType,
|
|
hr);
|
|
}
|
|
|
|
if ((punk == NULL) && (dwContext & CLSCTX_INPROC_HANDLERX86))
|
|
{
|
|
// Search cache for a cached handler DLL
|
|
punk = gdllcacheHandler.GetOrLoadClass(rclsid,
|
|
riid,
|
|
FALSE,
|
|
FALSE,
|
|
TRUE,
|
|
dwContext & CLSCTX_INPROC_HANDLERS,
|
|
dwDllServerType,
|
|
hr);
|
|
}
|
|
}
|
|
#endif
|
|
if ((punk == NULL) &&
|
|
(dwContext & (CLSCTX_INPROC_SERVERS) ))
|
|
{
|
|
punk = gdllcacheInprocSrv.GetOrLoadClass(rclsid,
|
|
riid,
|
|
FALSE,
|
|
FALSE,
|
|
#ifdef WX86OLE
|
|
FALSE,
|
|
#endif
|
|
dwContext & CLSCTX_INPROC_SERVERS,
|
|
dwDllServerType,
|
|
hr);
|
|
}
|
|
if (punk == NULL && dwContext & CLSCTX_INPROC_HANDLERS)
|
|
{
|
|
punk = gdllcacheHandler.GetOrLoadClass(rclsid,
|
|
riid,
|
|
FALSE,
|
|
FALSE,
|
|
#ifdef WX86OLE
|
|
FALSE,
|
|
#endif
|
|
dwContext & CLSCTX_INPROC_HANDLERS,
|
|
dwDllServerType,
|
|
hr);
|
|
}
|
|
|
|
return(punk);
|
|
}
|
|
#endif // GET_INPROC_FROM_SCM
|