Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1879 lines
56 KiB

//+---------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1993 - 1994.
//
// File: d:\nt\private\cairole\com\class\compobj.cxx
//
// Contents:
//
// Classes:
//
// Functions: GetInfoLevel
// DllMain
// CheckAndStartSCM
// CoGetCurrentProcess
// CoBuildVersion
// SetOleThunkWowPtr
// CoInitializeWOW
// CoInitialize
// CoInitializeEx
// CoUninitialize
//
// History: 09-Jun-94 BruceMa Added this file header
// 09-Jun-94 BruceMa Distinguish CoInitialize errors
// 14-Jun-94 BruceMa Ensure single threading
// 17-Jun-94 Bradlo Add SetState/GetState
// 06-Jul-94 BruceMa Support for CoGetCurrentProcess
// 28-Jul-94 BruceMa Allow CoGetCurrentProcess to do a
// partial CoInitialize (because Publisher
// didn't call CoInitialize (!))
// 29-Aug-94 AndyH set the locale for the CRT
// 29-Sep-94 AndyH remove setlocale call
// 06-Oct-94 BruceMa Allow CoGetCurrentProcess to work even
// if that thread didn't call CoInitialize
// 09-Nov-94 BruceMa Initialize/Delete IMallocSpy
// critical section
// 12-Dec-94 BruceMa Delete Chicago pattern table at
// CoUninitialize
// 09-Jan-95 BruceMa Initialize/Delete ROT
// critical section
// 10-May-95 KentCe Defer Heap Destruction to the last
// process detach.
// 28-Aug-95 BruceMa Close g_hRegPatTblEvent at
// ProcessUninitialize
// 25-Sep-95 BruceMa Check that scm is started during
// CoInitialize
// 25-Oct-95 Rickhi Improve CoInit Time.
//
//----------------------------------------------------------------------
// compobj.cpp - main file for the compobj dll
#if !defined(_CHICAGO_)
extern "C"
{
#include <nt.h> // NT_PRODUCT_TYPE
#include <ntdef.h> // NT_PRODUCT_TYPE
#include <ntrtl.h> // NT_PRODUCT_TYPE
#include <nturtl.h> // NT_PRODUCT_TYPE
#include <windef.h> // NT_PRODUCT_TYPE
#include <winbase.h> // NT_PRODUCT_TYPE
}
#endif
#include <ole2int.h>
#include <verole.h> // for CoBuildVersion
#include <thunkapi.hxx> // For interacting with the VDM
#include <scmstart.hxx>
#include <cevent.hxx>
#include <olespy.hxx>
#ifndef _CHICAGO_
#include <shrtbl.hxx> // CDllShrTbl
#endif
#ifdef _CHICAGO_
#include "pattbl.hxx"
#include <smmutex.hxx>
#endif // _CHICAGO_
#include <olepfn.hxx>
#if DBG==1
#include <outfuncs.h>
#endif
DEFHOOKOBJECT // HOOKOLE
NAME_SEG(CompObj)
ASSERTDATA
HRESULT Storage32DllGetClassObject(REFCLSID clsid, REFIID iid, void **ppv);
HRESULT MonikerDllGetClassObject(REFCLSID clsid, REFIID iid, void **ppv);
HRESULT Ole232DllGetClassObject(REFCLSID clsid, REFIID iid, void **ppv);
EXTERN_C HRESULT PrxDllGetClassObject(REFCLSID clsid, REFIID iid, void **ppv);
HRESULT MallocInitialize(BOOL fForceLocalAlloc);
BOOL MallocUninitialize(void);
STDAPI OleReleaseEnumVerbCache();
extern void ClipboardProcessUninitialize();
extern void CleanUpLocalServersForProcess();
extern void CleanUpDllsForProcess();
extern void CleanUpLocalServersForApartment();
extern void CleanUpDllsForApartment();
extern void CleanROTForApartment();
#ifdef DCOM
extern void DllHostProcessInitialize();
extern void DllHostThreadUninitialize();
extern void DllHostProcessUninitialize();
extern ULONG gcHostProcessInits;
#endif
#if defined(_CHICAGO_)
COleStaticMutexSem g_Rpcrt4Sem;
#endif
#ifdef _CHICAGO_
extern HANDLE g_hRegPatTblEvent;
extern CChicoPatternTbl *g_pPatTbl;
STDAPI SSAPI(CoInitializeEx)(LPVOID pvReserved, ULONG flags );
char *szHeapDestoySync = "OleHeapDestroyMutex";
#else
CDllShrdTbl *g_pShrdTbl = NULL;
#endif // _CHICAGO_
#ifndef _CHICAGO_
extern void ScmGetThreadId( DWORD * pThreadID );
#endif
STDAPI CoSetState(IUnknown *punkStateNew);
WINOLEAPI CoSetErrorInfo(DWORD dwReserved, IErrorInfo * pErrorInfo);
#if defined(_CHICAGO_)
//
// Locate the following in a shared data segment.
//
#pragma data_seg(".sdata")
SOleSharedTables gs_SharedTables = { 0, NULL, NULL, NULL, NULL, NULL, 0 };
LONG gs_lNextGuidIndex = 0x1;
LONG gs_ProcessAttachCount = 0; // Count of process attaches.
#pragma data_seg()
extern HANDLE gs_hSharedHeap; // hSharedHeap Handle for Win95.
#endif // defined(_CHICAGO_)
void ProcessUninitialize( void );
void DoThreadSpecificCleanup();
COleStaticMutexSem g_mxsSingleThreadOle;
COleStaticMutexSem gmxsOleMisc;
// The following pointer is used to hold an interface to the
// WOW thunk interface.
LPOLETHUNKWOW g_pOleThunkWOW = NULL;
// The following is the count of per-process CoInitializes that have been done.
DWORD g_cProcessInits = 0; // total per process inits
DWORD g_cMTAInits = 0; // # of multi-threaded inits
DWORD g_cSTAInits = 0; // # of apartment-threaded inits
// Holds the process id of SCM. DCOM uses this to unmarshal an object
// interface on the SCM. See MakeSCMProxy in dcomrem\ipidtbl.cxx.
DWORD gdwScmProcessID = 0;
//
// On Chicago, we keep shared state
//
#ifdef _CHICAGO_
const TCHAR * SHAREDSTATEMUTEXNAME = TEXT("OleCoSharedStateMtx");
const WCHAR * SHAREDSTATENAME = L"OleCoSharedState";
HANDLE g_hSharedState = NULL;
HANDLE g_hSharedStateMutex = NULL;
SOleSharedTables * g_post = NULL;
#endif // _CHICAGO_
// enable object hooking
DEFENABLEHOOKOBJECT
DEFGETHOOKINTERFACE
#if DBG==1
//---------------------------------------------------------------------------
//
// function: GetInfoLevel
//
// purpose: This routine is called when a process attaches. It extracts
// the debug info levels values from win.ini.
//
//---------------------------------------------------------------------------
// externals used below in calls to this function
extern "C" unsigned long heapInfoLevel; // memory tracking
//Set ole32!heapInfoLevel != 0 to use the OLE debug allocator in debug build.
//Set ole32!heapInfoLevel & DEB_ITRACE for backtrace of memory leaks in debug build.
extern "C" unsigned long olInfoLevel; // lower layer storage
extern "C" unsigned long msfInfoLevel; // upper layer storage
extern "C" unsigned long LEInfoLevel; // linking and embedding
extern "C" unsigned long RefInfoLevel; // CSafeRef class
extern "C" unsigned long DDInfoLevel; // Drag'n'drop
extern "C" unsigned long mnkInfoLevel; // Monikers
extern "C" unsigned long hkInfoLevel; // HOOKOLE
#ifndef _CHICAGO_
extern "C" unsigned long propInfoLevel; // properties
#endif
#ifdef SERVER_HANDLER
extern "C" unsigned long HdlInfoLevel; // ServerHandler and ClientSiteHandler
#endif // SERVER_HANDLER
extern DWORD g_dwInfoLevel;
DECLARE_INFOLEVEL(intr); // For 1.0/2.0 interop
DECLARE_INFOLEVEL(UserNdr); // For Oleprxy32 and NDR
DECLARE_INFOLEVEL(Stack); // For stack switching
DECLARE_INFOLEVEL(hk); // hook OLE
ULONG GetInfoLevel(CHAR *pszKey, ULONG *pulValue, CHAR *pszdefval)
{
CHAR szValue[20];
DWORD cbValue = sizeof(szValue);
// if the default value has not been overridden in the debugger,
// then get it from win.ini.
if (*pulValue == (DEB_ERROR | DEB_WARN))
{
if (GetProfileStringA("CairOLE InfoLevels", // section
pszKey, // key
pszdefval, // default value
szValue, // return buffer
cbValue))
{
*pulValue = strtoul (szValue, NULL, 16);
}
}
return *pulValue;
}
// stack switching is by defaul on
BOOL fSSOn = TRUE;
#endif // DBG
//+-------------------------------------------------------------------------
//
// Function: DllGetClassObject
//
// Synopsis: Dll entry point
//
// Arguments: [clsid] - class id for new class
// [iid] - interface required of class
// [ppv] - where to put new interface
//
// Returns: S_OK - class object created successfully created.
//
// History: 21-Jan-94 Ricksa Created
//
//--------------------------------------------------------------------------
STDAPI DllGetClassObject(REFCLSID clsid, REFIID iid, void **ppv)
{
OLETRACEIN((API_DllGetClassObject, PARAMFMT("rclsid= %I,iid= %I,ppv= %p"), &clsid, &iid, ppv));
HRESULT hr = Storage32DllGetClassObject(clsid, iid, ppv);
if (FAILED(hr))
{
hr = MonikerDllGetClassObject(clsid, iid, ppv);
}
if (FAILED(hr))
{
hr = PrxDllGetClassObject(clsid, iid, ppv);
}
if (FAILED(hr))
{
hr = ComDllGetClassObject(clsid, iid, ppv);
}
if (FAILED(hr))
{
hr = Ole232DllGetClassObject(clsid, iid, ppv);
}
OLETRACEOUT((API_DllGetClassObject, hr));
return hr;
}
//+-------------------------------------------------------------------------
//
// Function: DllMain
//
// Synopsis: Dll entry point for OLE/COM
//
// Arguments: [hDll] - a handle to the dll instance
// [dwReason] - the reason LibMain was called
// [lpvReserved] - NULL - called due to FreeLibrary
// - non-NULL - called due to process exit
//
// Returns: TRUE on success, FALSE otherwise
//
// Notes:
// If we are called because of FreeLibrary, then we should do as
// much cleanup as we can. If we are called because of process
// termination, we should not do any cleanup, as other threads in
// this process will have already been killed, potentially while
// holding locks around resources.
//
// The officially approved DLL entrypoint name is DllMain. This
// entry point will be called by the CRT Init function.
//
// History: 06-Dec-93 Rickhi dont do cleanup on process exit
// 09-Nov-94 BruceMa Initialize/Delete IMallocSpy
// critical section
// 16-Jan-95 KevinRo Changed to DllMain to remove a bunch
// of unneeded code and calls
//
//--------------------------------------------------------------------------
extern "C" BOOL WINAPI DllMain(
HANDLE hInstance,
DWORD dwReason,
LPVOID lpvReserved)
{
HRESULT hr;
if (dwReason == DLL_PROCESS_DETACH)
{
CairoleDebugOut((DEB_DLL,
"DLL_PROCESS_DETACH: %s\n",
lpvReserved?"Process Exit":"Dll Unload"));
// Process is exiting so lets clean up if we have to
#if defined(_CHICAGO_)
//
// BUGBUG: (KevinRo) Turns out that the Win95/Nashville loader
// has a bug that prevents us from correctly unloading DLL's.
// The problem is that they decrement their reference counts
// before calling DllMain()'s. When we free'd RPCRT4.DLL,
// the loader would in turn free MSVCRT.DLL too early, and
// we would die on return.
// The PSD group is going to fix the loader someday. Until
// then, we will just leave RPCRT4 loaded.
//
// FreeRPCRT4();
//
#endif
//
// When there is a FreeLibrary, and we still have initialized OLE
// com threads, then try to get rid of all of the global process
// stuff we are maintaining.
//
if (g_cProcessInits != 0 && lpvReserved == NULL )
{
ProcessUninitialize();
UNINITHOOKOBJECT();
}
ThreadNotification((HINSTANCE)hInstance, dwReason, lpvReserved);
MallocUninitialize();
#if defined(_CHICAGO_)
//
// Due to shared memory structures stored in our shared data segment,
// we must delay the destruction of the shared heap until the last
// process detaches from OLE32.DLL.
//
// We put a block here for two reasons. First to take advantage of
// the C++ semantics that will guarantee that the destructor for the
// mutex object is called by any exit path from the block. Secondly,
// we use it so that if code is added after this block, we won't
// hold the mutex any longer than we absolutely need to.
{
// Synchronize with process attaches so that we guarantee that
// all variables connected with the heap are valid.
CSmMutex smxs;
smxs.Init(szHeapDestoySync, TRUE);
// Are we the last process that is using the heap?
if (--gs_ProcessAttachCount == 0)
{
// Is there a heap?
if (gs_hSharedHeap != NULL)
{
HeapDestroy(gs_hSharedHeap);
gs_hSharedHeap = NULL;
// The following are pointers into the shared heap so
// they all need to be NULL'd because they are no longer
// valid.
gs_SharedTables.pscmrot = NULL;
gs_SharedTables.gpCHandlerList = NULL;
gs_SharedTables.gpCInProcList = NULL;
gs_SharedTables.gpCLocSrvList = NULL;
gs_SharedTables.gpCClassCacheList = NULL;
}
}
}
#endif
#if DBG==1
CloseDebugSinks();
#endif
//
// Only bother to rundown the static mutex pool if we're being
// unloaded w/o exiting the process
//
if (lpvReserved == NULL)
{
//
// Destruct the static mutex pool
//
while (g_pInitializedStaticMutexList != NULL)
{
COleStaticMutexSem * pMutex;
pMutex = g_pInitializedStaticMutexList;
g_pInitializedStaticMutexList = pMutex->pNextMutex;
pMutex->Destroy();
}
DeleteCriticalSection (&g_OleMutexCreationSem);
}
#if DBG==1
CairoleAssert (g_fDllState == DLL_STATE_NORMAL);
g_fDllState = DLL_STATE_STATIC_DESTRUCTING;
#endif
return TRUE;
}
else if (dwReason == DLL_PROCESS_ATTACH)
{
// Initialize the mutex package. Do this BEFORE doing anything
// else, as even a DebugOut will fault if the critical section
// is not initialized.
InitializeCriticalSection (&g_OleMutexCreationSem);
ComDebOut((DEB_DLL,"DLL_PROCESS_ATTACH:\n"));
#if DBG==1
// Note that we've completed running the static constructors
CairoleAssert (g_fDllState == DLL_STATE_STATIC_CONSTRUCTING);
g_fDllState = DLL_STATE_NORMAL;
#endif
#if DBG==1
OpenDebugSinks(); // Set up for logging
// set the various info levels
GetInfoLevel("cairole", &CairoleInfoLevel, "0x0003");
GetInfoLevel("ol", &olInfoLevel, "0x0003");
GetInfoLevel("msf", &msfInfoLevel, "0x0003");
GetInfoLevel("LE", &LEInfoLevel, "0x0003");
#ifdef SERVER_HANDLER
GetInfoLevel("Hdl", &HdlInfoLevel, "0x0003");
#endif // SERVER_HANDLER
GetInfoLevel("Ref", &RefInfoLevel, "0x0003");
GetInfoLevel("DD", &DDInfoLevel, "0x0003");
GetInfoLevel("mnk", &mnkInfoLevel, "0x0003");
GetInfoLevel("intr", &intrInfoLevel, "0x0003");
GetInfoLevel("UserNdr", &UserNdrInfoLevel, "0x0003");
GetInfoLevel("Stack", &StackInfoLevel, "0x0003");
#ifndef _CHICAGO_
GetInfoLevel("prop", &propInfoLevel, "0x0003");
#endif
ULONG dummy;
// Get API trace level
dummy = DEB_WARN|DEB_ERROR;
GetInfoLevel("api", &dummy, "0x0000");
g_dwInfoLevel = (DWORD) dummy;
fSSOn = (BOOL)GetInfoLevel("StackOn", &dummy, "0x0003");
GetInfoLevel("heap", &heapInfoLevel, "0x0003");
if(heapInfoLevel != 0)
{
//Initialize the OLE debug memory allocator.
hr = MallocInitialize(FALSE);
}
else
#endif //DBG==1
{
//Initialize the OLE retail memory allocator.
hr = MallocInitialize(TRUE);
}
if(FAILED(hr))
{
ComDebOut((DEB_ERROR, "Failed to init memory allocator hr:%x",hr));
return FALSE;
}
//
// this will be needed for the J version
// setlocale(LC_CTYPE, "");
//
g_hmodOLE2 = (HMODULE)hInstance;
g_hinst = (HINSTANCE)hInstance;
#if defined(_CHICAGO_)
//
// Keep track of the number of process attaches. See detach logic
// for details.
//
{
// Synchronize with process detaches so that we guarantee that
// all variables connected with the heap are in a valid state.
CSmMutex smxs;
smxs.Init(szHeapDestoySync, TRUE);
gs_ProcessAttachCount++;
}
#endif
InitializeOleSpy(OLESPY_TRACE);
#ifdef TRACELOG
if (!sg_pTraceLog)
{
sg_pTraceLog = (CTraceLog *) new CTraceLog();
CairoleAssert(sg_pTraceLog && "Create Trace Log Failed");
}
#endif // TRACELOG
// init the object hooking
INITHOOKOBJECT(S_OK);
}
return ThreadNotification((HINSTANCE)hInstance, dwReason, lpvReserved);
}
#ifdef _CHICAGO_
//+---------------------------------------------------------------------------
//
// Function: CheckAndStartSCM, private
//
// Synopsis: Checks to see if the SCM needs to be started, and starts it
// up if it does.
//
// Arguments: None.
//
// Returns: Appropriate status code
//
// History: 07-Apr-94 PhilipLa Created
//
// Only Chicago uses these shared state tables. At one time, NT had them also,
// but only for the unique process ID. NT now uses a call to the SCM to get
// the unique process ID
//
// On NT, the SCM is Auto-Start so we dont need to check if it is running.
// There is a race between the shell starting and SCM starting, but the code
// to deal with that race is in the shell and in the SCM.
//
//----------------------------------------------------------------------------
HRESULT CheckAndStartSCM(void)
{
CairoleDebugOut((DEB_COMPOBJ, "In CheckAndStartSCM\n"));
HRESULT hr = S_OK;
BOOL fCreated = FALSE;
SECURITY_ATTRIBUTES secattr;
secattr.nLength = sizeof(SECURITY_ATTRIBUTES);
secattr.lpSecurityDescriptor = NULL;
secattr.bInheritHandle = FALSE;
if (g_hSharedStateMutex == NULL)
{
//First, create the Mutex for this shared block
if (NULL == (g_hSharedStateMutex = CreateMutex(&secattr, FALSE,
SHAREDSTATEMUTEXNAME)))
{
return CO_E_INIT_SCM_MUTEX_EXISTS;
}
}
//Now take the mutex. We can then party on this block as much
// as we want until we release the mutex.
WaitForSingleObject(g_hSharedStateMutex, INFINITE);
if (g_post == NULL)
{
g_post = &gs_SharedTables;
}
hr = StartSCM();
ReleaseMutex(g_hSharedStateMutex);
CairoleDebugOut((DEB_COMPOBJ, "Out CheckAndStartSCM\n"));
return hr;
}
#endif
//+---------------------------------------------------------------------------
//
// Function: ProcessInitialize, private
//
// Synopsis: Performs all of the process initialization. Happens when
// the first com thread calls CoInitialize.
//
// Arguments: None.
//
// Returns: S_OK, CO_E_INIT_RPC_CHANNEL, E_FAIL
//
// History: 29-Aug-95 RickHi Created
//
//----------------------------------------------------------------------------
HRESULT ProcessInitialize()
{
HRESULT hr = S_OK;
#ifdef _CHICAGO_
// BUGBUG: KevinRo: Needed to add this back in to get the Nashville
// build going again.
// NASHVILLE_KEVINRO
// init remoting piece of COM
hr = ChannelProcessInitialize();
if (SUCCEEDED(hr))
{
// Start the SCM if necessary.
hr = CheckAndStartSCM();
}
else
{
hr = CO_E_INIT_RPC_CHANNEL;
}
if (FAILED(hr))
{
// Clean up
ChannelProcessUninitialize();
}
#endif // _CHICAGO_
// Initialize the OleSpy
InitializeOleSpy(OLESPY_CLIENT);
// Initialize Access Control.
if (SUCCEEDED(hr))
hr = InitializeAccessControl();
#ifdef DCOM
// init the dll host objects
DllHostProcessInitialize();
#endif
ComDebErr(FAILED(hr), "ProcessInitialize failed\n");
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: ProcessUninitialize, private
//
// Synopsis: Performs all of the process de-initialization. Happens when
// the last com thread calls CoUninitialize, or when the
// DLL_PROCESS_DETACH notification comes through.
//
// Arguments: None.
//
// Returns: Nothing.
//
// History: 29-Aug-94 RickHi Created
//
//----------------------------------------------------------------------------
void ProcessUninitialize()
{
// clean up clipboard window class registration
ClipboardProcessUninitialize();
// Free Enum verb cache
OleReleaseEnumVerbCache();
// release any proxies or marshaled server objects
IDTableProcessUninitialize();
// clean up the rot
DestroyRunningObjectTable();
// Cleanup AccessControl.
UninitializeAccessControl();
// Turn off RPC
ChannelProcessUninitialize();
// Free loaded Dlls class cache
CleanUpDllsForProcess();
// delete the shared mem table object
#ifdef _CHICAGO_
if (g_pPatTbl != NULL)
{
delete g_pPatTbl;
g_pPatTbl = NULL;
}
if (g_hRegPatTblEvent)
{
CloseHandle(g_hRegPatTblEvent);
g_hRegPatTblEvent = NULL;
}
#else
if (g_pShrdTbl)
{
delete g_pShrdTbl;
g_pShrdTbl = NULL;
}
#endif // _CHICAGO_
#ifdef TRACELOG
if (sg_pTraceLog)
{
CTraceLog *pTraceLog = sg_pTraceLog;
sg_pTraceLog = NULL; // prevent more entries into the log
delete pTraceLog; // delete the log, also dumps it.
}
#endif // TRACELOG
UninitializeOleSpy(OLESPY_TRACE);
// If WOW is going down, disable it.
// WARNING: IsWOWThread & IsWOWProcess will no longer return valid results!!!!
g_pOleThunkWOW = NULL;
}
//+---------------------------------------------------------------------------
//
// Function: STAProcessInitialize, private
//
// Synopsis: Performs all of the process initialization needed when the
// first Single-Threaded Apartment initializes.
//
// Returns: S_OK, E_FAIL
//
// History: 11-Mar-96 RickHi Created
//
//----------------------------------------------------------------------------
HRESULT STAProcessInitialize()
{
Win4Assert(IsSTAThread());
// we want to remember the thread so we can dispatch getting
// single threaded class objects to the main thread.
if (!InitMainThreadWnd())
{
ComDebOut((DEB_ERROR, "InitMainThreadWnd failed \n"));
return E_FAIL;
}
return S_OK;
}
//+---------------------------------------------------------------------------
//
// Function: STAProcessUninitialize, private
//
// Synopsis: Performs all of the process uninitialization needed when the
// first Single-Threaded Apartment uninitializes.
//
// History: 11-Mar-96 RickHi Created
//
//----------------------------------------------------------------------------
void STAProcessUninitialize()
{
Win4Assert(IsSTAThread());
UninitMainThreadWnd();
}
//+---------------------------------------------------------------------------
//
// Function: ApartmentUninitialzie, private
//
// Synopsis: Performs all of the process uninitialization needed when a
// Single-Threaded Apartment uninitializes, and when the
// Multi-Threaded apartment uninitializes.
//
// returns: TRUE - uninit complete
// FALSE - uninit aborted
//
// History: 11-Mar-96 RickHi Created
//
//----------------------------------------------------------------------------
BOOL ApartmentUninitialize()
{
// NOTE: The following sequence of uninitializes is critical:
//
// 1) Prevent incoming calls
// 2) LocalServer class cache
// 3) object activation (objact) server object
// 4) Dll host server object
// 5) standard identity table
// 6) running object table
// 7) Prevent outgoing calls (channel)
// 8) Dll class cache - since chnl cleanup may touch proxies/stubs
// Prevent incoming calls.
ThreadStop();
// ThreadStop let pending calls complete and while doing so the apartment
// init count may have been incremented again. If it has, we abort the
// uninit before any real cleanup is done.
COleTls tls;
if (tls->dwFlags & OLETLS_APARTMENTTHREADED)
{
if (tls->cComInits > 1)
return FALSE;
}
else
{
if (g_cMTAInits > 1)
return FALSE;
}
// cleanup per apartment registered LocalServer class table
CleanUpLocalServersForApartment();
#ifdef DCOM
// cleanup per apartment object activation server objects
ObjactThreadUninitialize();
// clean up the Dll Host Apartments
DllHostThreadUninitialize();
#endif
// cleanup per apartment identity objects
IDTableThreadUninitialize();
// cleanup per apartment ROT.
CleanROTForApartment();
// cleanup the per apartment channel.
ChannelThreadUninitialize();
// cleanup per apartment Dll class table.
CleanUpDllsForApartment();
return TRUE;
}
//+---------------------------------------------------------------------------
//
// Function: SetOleThunkWowPtr
//
// Synopsis: Sets the value of g_pOleThunkWOW, as part of CoInitializeWow
// and OleInitializeWow. This function is called by these
// routines.
//
// Effects:
//
// Arguments: [pOleThunk] -- VTable pointer to OleThunkWow interface
//
// Returns: none
//
// History: 4-05-94 kevinro Created
//----------------------------------------------------------------------------
void SetOleThunkWowPtr(LPOLETHUNKWOW lpthk)
{
//
// The theory here is that the lpthk parameter is the address into the
// olethk32.dll and once loaded will never change. Therefore it only
// needs to be set on the first call. After that, we can ignore the
// subsequent calls, since they should be passing in the same value.
//
// If g_pOleThunkWOW is set to INVALID_HANDLE_VALUE, then OLETHK32 had
// been previously unloaded, but is reloading
//
// I don't belive there is a multi-threaded issue here, since the pointer
// value will always set as the same. Therefore, if two threads set it,
// no problem.
//
if(!IsWOWThreadCallable())
{
g_pOleThunkWOW = lpthk;
}
}
//+---------------------------------------------------------------------------
//
// Function: CoInitializeWOW, private
//
// Synopsis: Entry point to initialize the 16-bit WOW thunk layer.
//
// Effects: This routine is called when OLE32 is loaded by a VDM.
// It serves two functions: It lets OLE know that it is
// running in a VDM, and it passes in the address to a set
// of functions that are called by the thunk layer. This
// allows normal 32-bit processes to avoid loading the WOW
// DLL since the thunk layer references it.
//
// Arguments: [vlpmalloc] -- 16:16 pointer to the 16 bit allocator.
// [lpthk] -- Flat pointer to the OleThunkWOW virtual
// interface. This is NOT an OLE/IUnknown style
// interface.
//
// Requires:
//
// Returns:
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: 3-15-94 kevinro Created
//
// Notes:
//
// Note that vlpmalloc is a 16:16 pointer, and cannot be called directly
//----------------------------------------------------------------------------
STDAPI CoInitializeWOW( LPMALLOC vlpmalloc, LPOLETHUNKWOW lpthk )
{
//
// At the moment, there was no need to hang onto the 16bit vlpmalloc
// routine for this thread. That may change once we get to the threaded
// model
//
vlpmalloc;
HRESULT hr;
OLETRACEIN((API_CoInitializeWOW, PARAMFMT("vlpmalloc= %x, lpthk= %p"), vlpmalloc, lpthk));
// Get (or allocate) the per-thread data structure
COleTls Tls(hr);
if (FAILED(hr))
{
ComDebOut((DEB_ERROR, "CoInitializeWOW Tls OutOfMemory"));
return CO_E_INIT_TLS;
}
Tls->dwFlags |= OLETLS_WOWTHREAD;
SetOleThunkWowPtr(lpthk);
// WOW may be calling CoInitialize on multiple threads
hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
OLETRACEOUT((API_CoInitializeWOW, hr));
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: CoUnloadingWow
//
// Synopsis: Entry point to notify OLE32 that OLETHK32 is unloading
//
// Effects: This routine is called by OLETHK32 when it is being unloaded.
// The key trick is to make sure that we uninitialize the current
// thread before OLETHK32 goes away, and set the global thunk
// vtbl pointer to INVALID_HANDLE_VALUE before it does go away.
//
// Otherwise, we run a risk that OLE32 will attempt to call
// back to OLETHK32
//
// Arguments: fProcessDetach - whether this is a process detach
//
// Requires: IsWOWProcess must be TRUE
//
// Returns:
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: 3-18-95 kevinro Created
//
// Notes:
//
// This routine is only called by PROCESS_DETACH in OLETHK32.DLL.
// Because of this, there shouldn't be any threading protection needed,
// since the loader will protect us.
//
//----------------------------------------------------------------------------
STDAPI CoUnloadingWOW(BOOL fProcessDetach)
{
//
// First, cleanup this thread
//
DoThreadSpecificCleanup();
//
// Now, set the global WOW thunk pointer to an invalid value. This
// will prevent it from being called in the future.
//
if (fProcessDetach)
{
g_pOleThunkWOW = (OleThunkWOW *) INVALID_HANDLE_VALUE;
}
return(NOERROR);
}
//+-------------------------------------------------------------------------
//
// Function: CoInitialize
//
// Synopsis: COM Initializer
//
// Arguments: [pvReserved]
//
// Returns: HRESULT
//
// History: 09-Nov-94 Ricksa Added this function comment & modified
// to get rid of single threaded init flag.
//
//--------------------------------------------------------------------------
STDAPI CoInitialize(LPVOID pvReserved)
{
HRESULT hr;
OLETRACEIN((API_CoInitialize, PARAMFMT("pvReserved= %p"), pvReserved));
hr = CoInitializeEx( pvReserved, COINIT_APARTMENTTHREADED);
OLETRACEOUT((API_CoInitialize, hr));
return hr;
}
//+-------------------------------------------------------------------------
//
// Function: CoInitializeEx
//
// Synopsis: COM Initializer
//
// Arguments: [pMalloc]
// [flags]
//
// Returns: HRESULT
//
// History: 06-Apr-94 AlexT Added this function comment,
// Cleaned up pMalloc usage
// 25-May-94 AlexT Make success return code more closely
// match 16-bit OLE
// 28-Aug-94 AndyH pMalloc must be NULL except for Excel
//
// Notes: If we're going to return successfully, we return one of the
// following two values:
//
// S_OK if caller passed in a NULL pMalloc and we accepted it
// S_OK if caller passed in NULL pMalloc and this was the first
// successful call on this thread
// S_FALSE if caller passed in NULL pMalloc and this was not the
// first successful call on this thread
//
// This is slightly different from 16-bit OLE, because 16-bit OLE
// didn't allow task allocations before CoInitialize was called
// (we do), and 16-bit OLE allowed the app to change the allocator.
//
// For chicago: SSAPI(x) expands to SSx; the x api is in
// stkswtch.cxx which switches to the 16 bit stack first and
// calls then SSx.
//
//--------------------------------------------------------------------------
STDAPI SSAPI(CoInitializeEx)(LPVOID pMalloc, ULONG flags)
{
ComDebOut((DEB_TRACE, "CoInitializeEx pMalloc:%x flags:%x\n", pMalloc, flags));
if ((flags & (COINIT_DISABLE_OLE1DDE|COINIT_APARTMENTTHREADED|
COINIT_SPEED_OVER_MEMORY))
!= flags)
{
ComDebOut((DEB_ERROR, "CoInitializeEx(%x,%x) illegal flag", pMalloc, flags));
return E_INVALIDARG;
}
if (NULL != pMalloc)
{
// Allocator NOT replaceable! When called from 16-bits, the Thunk
// layer always pases a NULL pMalloc.
#ifndef _CHICAGO_
// EXCEL50 for NT supplies an allocator. We dont use it, but we
// dont return error either, or we would break them.
if (!IsTaskName(L"EXCEL.EXE"))
#endif
{
ComDebOut((DEB_ERROR, "CoInitializeEx(%x,%x) illegal pMalloc", pMalloc, flags));
return E_INVALIDARG;
}
}
// Get (or allocate) the per-thread data structure
HRESULT hr;
COleTls Tls(hr);
if (FAILED(hr))
{
ComDebOut((DEB_ERROR, "CoInitializeEx Tls OutOfMemory"));
return CO_E_INIT_TLS;
}
if (( (flags & COINIT_APARTMENTTHREADED) && (Tls->dwFlags & OLETLS_MULTITHREADED)) ||
(!(flags & COINIT_APARTMENTTHREADED) && (Tls->dwFlags & OLETLS_APARTMENTTHREADED)))
{
// tried to change the threading mode.
ComDebOut((DEB_ERROR,"CoInitializeEx Attempt to change threadmodel\n"));
return RPC_E_CHANGED_MODE;
}
#ifdef DCOM
// This flag can be set at any time. It cannot be disabled.
if (flags & COINIT_SPEED_OVER_MEMORY)
{
gSpeedOverMem = TRUE;
}
#endif
// increment the per-thread init count
if (1 == ++(Tls->cComInits))
{
// first time for thread, might also be first time for process
// so go check that now.
// Single thread CoInitialize/CoUninitialize to guarantee
// that no race conditions occur where two threads are
// simultaneously initializing and uninitializing the library.
COleStaticLock lck(g_mxsSingleThreadOle);
hr = wCoInitializeEx(Tls, flags);
return hr;
}
// this is the 2nd or greater successful call on this thread
ComDebOut((DEB_TRACE, "CoInitializeEx returned S_FALSE\n"));
return S_FALSE;
}
//+-------------------------------------------------------------------------
//
// Function: wCoInitializeEx
//
// Synopsis: worker routine for CoInitialize, and special entry point
// for DLLHost threads when Initializing.
//
// Arguments: [tls] - tls ptr for this thread
// [flags] - initialization flags
//
// History: 10-Apr-96 Rickhi Created
//
// Notes: When called by the DLLHost threads that are initializing,
// the g_mxsSingleThreadOle mutex is being held by the requesting
// thread, so it is still safe to muck with global state.
//
//+-------------------------------------------------------------------------
INTERNAL wCoInitializeEx(COleTls &Tls, ULONG flags)
{
HRESULT hr = S_OK;
if (1 == ++g_cProcessInits)
{
// first time for process, do per-process initialization
hr = ProcessInitialize();
if (FAILED(hr))
{
// ProcessInitialize failed, we must call ProcessUninitialize
// to cleanup *before* we release the lock.
goto ErrorReturn;
}
}
if (flags & COINIT_APARTMENTTHREADED)
{
// apartment threaded, count 1 more STA init, mark the thread
// as being apartment threaded, and conditionally disable
// OLE1.
Tls->dwFlags |= OLETLS_APARTMENTTHREADED;
if (flags & COINIT_DISABLE_OLE1DDE)
{
Tls->dwFlags |= OLETLS_DISABLE_OLE1DDE;
}
if (1 == ++g_cSTAInits && gdwMainThreadId == 0)
{
// do main-thread apartment initialization. It is possible
// to have the first thread in here not be the main thread
// if the DLLHost code just spun a thread to be the main
// one.
STAProcessInitialize();
}
}
else
{
// multi threaded, count 1 more MTA init, mark the thread
// as being multi-threaded, and always disable OLE1
Tls->dwFlags |= (OLETLS_MULTITHREADED | OLETLS_DISABLE_OLE1DDE);
++g_cMTAInits;
}
#ifdef _CHICAGO_
hr = ChannelThreadInitialize();
if (FAILED(hr))
{
ChannelThreadUninitialize();
if (flags & COINIT_APARTMENTTHREADED)
{
if (--g_cSTAInits == 0)
STAProcessUninitialize();
}
else
{
--g_cMTAInits;
}
goto ErrorReturn;
}
#endif // _CHICAGO_
// this is the first successful call on this thread. make
// sure to return S_OK and not some other random sucess code.
ComDebOut((DEB_TRACE, "CoInitializeEx returned S_OK\n"));
return S_OK;
ErrorReturn:
// An error occurred. Fixup our tls init counter and
// undo the TLS state change
// cleanup our counter if the intialization failed so
// that other threads waiting on the lock wont assume
// that ProcessInitialize has been done.
if (--g_cProcessInits == 0)
{
ProcessUninitialize();
}
Tls->cComInits--;
Tls->dwFlags = OLETLS_LOCALTID; // clear all the flags
ComDebOut((DEB_ERROR,"CoInitializeEx Failed %x\n", hr));
return hr;
}
//+-------------------------------------------------------------------------
//
// Function: SSAPI(CoUnInitialize)
//
// Synopsis: COM UnInitializer, normally called from OleUninitialize
// when the app is going away.
//
// Effects: Cleans up per apartment state, and if this is the last
// apartment, cleans up global state.
//
// Arguments: none
//
// Returns: nothing
//
// History: 24-Jun-94 Rickhi Added this function comment,
// Cleaned up pMalloc usage
// 29-Jun-94 AlexT Rework so that we don't own the mutex
// while we might yield.
//
// Notes: It is critical that we not own any mutexes when we might
// make a call that would allow a different WOW thread to run
// (which could otherwise lead to deadlock). Examples of such
// calls are Object RPC, SendMessage, and Yield.
//
//--------------------------------------------------------------------------
STDAPI_(void) SSAPI(CoUninitialize)(void)
{
OLETRACEIN((API_CoUninitialize, NOPARAM));
TRACECALL(TRACE_INITIALIZE, "CoUninitialize");
// Get the thread init count.
COleTls Tls(TRUE);
if (!Tls.IsNULL() && Tls->cComInits > 0)
{
if ((1 == Tls->cComInits))
{
// last time for thread, do per-thread cleanup
wCoUninitialize(Tls, FALSE);
}
else
{
// Decrement thread count. This must be done after the above cleanup
// so that IsApartmentIntialized returns TRUE during the cleanup.
Tls->cComInits--;
}
}
else
{
ComDebOut((DEB_ERROR,
"(0 == thread inits) Unbalanced call to CoUninitialize\n"));
}
OLETRACEOUTEX((API_CoUninitialize, NORETURN));
return;
}
//+-------------------------------------------------------------------------
//
// Function: wCoUnInitialize
//
// Synopsis: worker routine for CoUninitialize, and special entry point
// for DLLHost threads when cleaning up.
//
// Effects: Cleans up apartment state.
//
// History: 10-Apr-96 Rickhi Created
//
// Notes: When called with fHostThread == TRUE, the g_mxsSingleThreadOle
// critical section is already held by the main thread that is
// uninitializing, currently waiting in DllHostProcessUninitialize
// for the host threads to exit. The host threads use this
// uninitializer to avoid taking the CS and deadlocking with the
// main thread.
//
//--------------------------------------------------------------------------
INTERNAL_(void) wCoUninitialize(COleTls &Tls, BOOL fHostThread)
{
ComDebOut((DEB_COMPOBJ, "CoUninitialize Thread\n"));
if (Tls->dwFlags & OLETLS_THREADUNINITIALIZING)
{
// somebody called CoUninitialize while inside CoUninitialize. Since
// we dont subtract the thread init count until after init is done.
// we can end up here. Just warn the user about the problem and
// return without doing any more work.
ComDebOut((DEB_WARN, "Unbalanced Nested call to CoUninitialize\n"));
return;
}
// mark the thread as uninitializing
Tls->dwFlags |= OLETLS_THREADUNINITIALIZING;
if (Tls->dwFlags & OLETLS_APARTMENTTHREADED)
{
// do per-apartment cleanup
if (!ApartmentUninitialize())
{
// uninit was aborted while waiting for pending calls
// to complete.
Tls->dwFlags &= ~OLETLS_THREADUNINITIALIZING;
ComDebOut((DEB_WARN, "CoUninitialize Aborted\n"));
return;
}
}
if (!fHostThread)
{
// Single thread CoInitialize/CoUninitialize to guarantee
// that no race conditions occur where two threads are
// simultaneously initializing and uninitializing the library.
g_mxsSingleThreadOle.Request();
#ifdef DCOM
if (g_cProcessInits-1 == gcHostProcessInits)
{
// clean up the dll host threads now, before continuing
DllHostProcessUninitialize();
}
#endif
}
if (Tls->dwFlags & OLETLS_APARTMENTTHREADED)
{
// STA thread, count 1 less STA init
if (1 == g_cSTAInits)
{
// last STA, do last-apartment thread uninitialization
STAProcessUninitialize();
}
g_cSTAInits--;
}
else
{
// MTA thread, count 1 less MTA init
if (1 == g_cMTAInits)
{
// last thread in the MTA, uninitialize the apartment
// (except some low-level remoting stuff). Ignore aborts
// since the exit path is clean from here on (for MTA only)
ApartmentUninitialize();
if (g_cProcessInits-1 == gcHostProcessInits && !fHostThread)
{
// while we released the lock in ApartmentUninitialize,
// some other thread processing a call could have activated
// a host apartment, we'll go clean those up now if those
// are the only threads with init's left.
DllHostProcessUninitialize();
}
}
// Decrement MTA count. This must be done after the above cleanup
// so that IsApartmentIntialized returns TRUE during the cleanup.
g_cMTAInits--;
}
if (!fHostThread)
{
if (1 == g_cProcessInits)
{
// last time for process, do per-process cleanup
CairoleDebugOut((DEB_COMPOBJ, "CoUninitialize Process\n"));
Win4Assert(Tls->cComInits == 1);
ProcessUninitialize();
}
}
// Decrement process count. This must be done after the above cleanup
// so that IsApartmentIntialized returns TRUE during the cleanup.
g_cProcessInits--;
if (!fHostThread)
{
g_mxsSingleThreadOle.Release();
}
//Release the per-thread error object.
CoSetErrorInfo(0, NULL);
// Release the per-thread "state" object (regardless of whether we
// are Apartment or Free threaded. This must be done now since the
// OLE Automation Dll tries to free this in DLL detach, which may
// try to call back into the OLE32 dll which may already be detached!
CoSetState(NULL);
#ifdef WX86OLE
// make sure wx86 state is also freed
if (gcwx86.SetIsWx86Calling(TRUE))
{
CoSetState(NULL);
}
#endif
// mark the thread as finished uninitializing and turn off all flags
// and reset the count of initializations.
Tls->dwFlags = OLETLS_LOCALTID;
Tls->cComInits = 0;
}
//+-------------------------------------------------------------------------
//
// Function: IsApartmentInitialized
//
// Synopsis: Check if the current apartment is initialized
//
// Returns: TRUE - apartment initialized, TLS data guaranteed to exist
// for this thread.
// FALSE - apartment not initialized
//
// History: 09-Aug-94 Rickhi commented
//
//--------------------------------------------------------------------------
BOOL IsApartmentInitialized()
{
HRESULT hr;
COleTls Tls(hr);
// initialized if any MTA apartment exists, or if the current thread has
// been initialized.
return (SUCCEEDED(hr) && (g_cMTAInits > 0 || Tls->cComInits != 0))
? TRUE : FALSE;
}
//+---------------------------------------------------------------------
//
// Function: CoGetCurrentProcess
//
// Synopsis: Returns a unique value for the current thread. This routine is
// necessary because hTask values from Windows get reused
// periodically.
//
// Arguments: -
//
// Returns: DWORD
//
// History: 28-Jul-94 BruceMa Created.
//
// Notes:
//
//----------------------------------------------------------------------
STDAPI_(DWORD) CoGetCurrentProcess(void)
{
HRESULT hr;
OLETRACEIN((API_CoGetCurrentProcess, NOPARAM));
#ifdef _CHICAGO_
// CODEWORK: The following is here because Publisher uses storage
// but inadvertantly (!) forgot to call CoInitialize
if (g_cProcessInits == 0)
{
hr = CheckAndStartSCM();
if ( FAILED(hr) )
{
CairoleDebugOut((DEB_ERROR, "Failed to start SCM, hr = %x", hr));
OLETRACEOUTEX((API_CoGetCurrentProcess, RETURNFMT("%ud"), 0));
return 0;
}
}
#endif
COleTls Tls(hr);
if ( FAILED(hr) )
{
OLETRACEOUTEX((API_CoGetCurrentProcess, RETURNFMT("%ud"), 0));
return 0;
}
// Get our OLE-specific thread id
if ( Tls->dwApartmentID == 0 )
{
#ifdef _CHICAGO_
// On Chicago, we merely increment the globally available
// process ID to the next value.
Win4Assert(g_post != NULL);
Win4Assert(g_hSharedStateMutex != NULL);
WaitForSingleObject(g_hSharedStateMutex, INFINITE);
Tls->dwApartmentID = ++g_post->dwNextProcessID;
ReleaseMutex(g_hSharedStateMutex);
#else
// This sets our dwApartmentID.
ScmGetThreadId( &Tls->dwApartmentID );
#endif
}
Win4Assert(Tls->dwApartmentID);
OLETRACEOUTEX((API_CoGetCurrentProcess, RETURNFMT("%ud"), Tls->dwApartmentID));
return Tls->dwApartmentID;
}
//+-------------------------------------------------------------------------
//
// Function: CoBuildVersion
//
// Synopsis: Return build version DWORD
//
// Returns: DWORD hiword = 23
// DWORD loword = build number
//
// History: 16-Feb-94 AlexT Use verole.h rmm for loword
//
// Notes: The high word must always be constant for a given platform.
// For Win16 it must be exactly 23 (because that's what 16-bit
// OLE 2.01 shipped with). We can choose a different high word
// for other platforms. The low word must be greater than 639
// (also because that's what 16-bit OLE 2.01 shipped with).
//
//--------------------------------------------------------------------------
STDAPI_(DWORD) CoBuildVersion( VOID )
{
WORD wLowWord;
WORD wHighWord;
OLETRACEIN((API_CoBuildVersion, NOPARAM));
wHighWord = 23;
wLowWord = rmm; // from ih\verole.h
Win4Assert(wHighWord == 23 && "CoBuildVersion high word magic number");
Win4Assert(wLowWord > 639 && "CoBuildVersion low word not large enough");
DWORD dwVersion;
dwVersion = MAKELONG(wLowWord, wHighWord);
OLETRACEOUTEX((API_CoBuildVersion, RETURNFMT("%x"), dwVersion));
return dwVersion;
}
//+-------------------------------------------------------------------------
//
// Function: CoSetState
// CoGetState
//
// Synopsis: These are private APIs, exported for use by the
// OLE Automation DLLs, which allow them to get and
// set a single per thread "state" object that is
// released at CoUninitialize time.
//
// Arguments: [punk/ppunk] the object to set/get
//
// History: 15-Jun-94 Bradlo Created
//
//--------------------------------------------------------------------------
STDAPI CoSetState(IUnknown *punkStateNew)
{
OLETRACEIN((API_CoSetState, PARAMFMT("punk= %p"), punkStateNew));
HRESULT hr;
COleTls Tls(hr);
#ifdef WX86OLE
// Make sure we get the flag on our stack before any callouts
BOOL fWx86Thread = gcwx86.IsWx86Calling();
#endif
if (SUCCEEDED(hr))
{
IUnknown *punkStateOld;
// Note that either the AddRef or the Release below could (in
// theory) cause a reentrant call to us. By keeping
// punkStateOld in a stack variable, we handle this case.
if (NULL != punkStateNew)
{
// We're going to replace the existing state with punkStateNew;
// take a reference right away
// Note thate even if this AddRef reenters TLSSetState we're
// okay because we haven't touched pData->punkState yet.
punkStateNew->AddRef();
}
#ifdef WX86OLE
// If this was called from x86 code via wx86 thunk layer then use
// alternate location in TLS.
if (fWx86Thread)
{
punkStateOld = Tls->punkStateWx86;
Tls->punkStateWx86 = punkStateNew;
} else {
punkStateOld = Tls->punkState;
Tls->punkState = punkStateNew;
}
#else
punkStateOld = Tls->punkState;
Tls->punkState = punkStateNew;
#endif
if (NULL != punkStateOld)
{
// Once again, even if this Release reenters TLSSetState we're
// okay because we're not going to touch pData->punkState again
punkStateOld->Release();
}
OLETRACEOUT((API_CoSetState, S_OK));
return S_OK;
}
OLETRACEOUT((API_CoSetState, S_FALSE));
return S_FALSE;
}
STDAPI CoGetState(IUnknown **ppunk)
{
OLETRACEIN((API_CoGetState, PARAMFMT("ppunk= %p"), ppunk));
HRESULT hr;
COleTls Tls(hr);
#ifdef WX86OLE
// Make sure we get the flag on our stack before any callouts
BOOL fWx86Thread = gcwx86.IsWx86Calling();
#endif
IUnknown *punk;
if (SUCCEEDED(hr))
{
#ifdef WX86OLE
// If this was called from x86 code via wx86 thunk layer then use
// alternate location in TLS.
punk = fWx86Thread ? Tls->punkStateWx86 :
Tls->punkState;
#else
punk = Tls->punkState;
#endif
if (punk)
{
punk->AddRef();
*ppunk = punk;
OLETRACEOUT((API_CoGetState, S_OK));
return S_OK;
}
}
*ppunk = NULL;
OLETRACEOUT((API_CoGetState, S_FALSE));
return S_FALSE;
}
//+---------------------------------------------------------------------------
//
// Function: CoQueryReleaseObject, private
//
// Synopsis: Determine if this object is one that should be released during
// shutdown.
//
// Effects: Turns out that some WOW applications don't cleanup properly.
// Specifically, sometimes they don't release objects that they
// really should have. Among the problems caused by this are that
// some objects don't get properly cleaned up. Storages, for
// example, don't get closed. This leaves the files open.
// Monikers are being released, which eat memory.
//
// This function is called by the thunk manager to determine
// if an object pointer is one that is known to be leaked, and
// if the object should be released anyway. There are several
// classes of object that are safe to release, and some that
// really must be released.
//
// Arguments: [punk] -- Unknown pointer to check
//
// Requires:
//
// Returns:
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: 8-15-94 kevinro Created
//
// Notes:
//
//----------------------------------------------------------------------------
DWORD adwQueryInterfaceTable[QI_TABLE_END] = { 0 , 0 };
STDAPI CoQueryReleaseObject(IUnknown *punk)
{
OLETRACEIN((API_CoQueryReleaseObject, PARAMFMT("punk= %p"), punk));
CairoleDebugOut((DEB_ITRACE,
"CoQueryReleaseObject(%x)\n",
punk));
//
// A punk is a pointer to a pointer to a vtbl. We are going to check the
// vtbl to see if we can release it.
//
DWORD pQueryInterface;
HRESULT hr;
if (IsBadReadPtr(punk,sizeof(DWORD)))
{
hr = S_FALSE;
goto ErrorReturn;
}
if (IsBadReadPtr(*(DWORD**)punk,sizeof(DWORD)))
{
hr = S_FALSE;
goto ErrorReturn;
}
// Pick up the QI function pointer
pQueryInterface = **(DWORD **)(punk);
CairoleDebugOut((DEB_ITRACE,
"CoQueryReleaseObject pQueryInterface = %x\n",
pQueryInterface));
//
// adwQueryInterfaceTable is an array of known QueryInterface pointers.
// Either the value in the table is zero, or it is the address of the
// classes QueryInterface method. As each object of interest is created,
// it will fill in its reserved entry in the array. Check olepfn.hxx for
// details
//
if( pQueryInterface != 0)
{
for (int i = 0 ; i < QI_TABLE_END ; i++)
{
if (adwQueryInterfaceTable[i] == pQueryInterface)
{
CairoleDebugOut((DEB_ITRACE,
"CoQueryReleaseObject punk matched %x\n",i));
hr = NOERROR;
goto ErrorReturn;
}
}
}
CairoleDebugOut((DEB_ITRACE,
"CoQueryReleaseObject No match on punk\n"));
hr = S_FALSE;
ErrorReturn:
OLETRACEOUT((API_CoQueryReleaseObject, hr));
return hr;
}
#if defined(_CHICAGO_)
//+---------------------------------------------------------------------------
//
// Function: CoCreateAlmostGuid
//
// Synopsis: Creates a GUID for internal use that is going to be unique
// as long as something has OLE32 loaded. We don't need a true
// GUID for the uses of this routine, since the values are only
// used on this local machine, and are used in data structures
// that are not persistent.
// Effects:
//
// Arguments: [pGuid] -- The output goes here.
//
// History: 5-08-95 kevinro Created
//
// Notes:
//
//----------------------------------------------------------------------------
STDAPI CoCreateAlmostGuid(GUID *pGuid)
{
DWORD *pGuidPtr = (DWORD *)pGuid;
//
// Note: As long as we increment the value, we don't
// care what it is. This, in combination with the PID,TID, and TickCount
// make this GUID unique enough for what we need. We would need to allocate
// 4 gig of UUID's to run the NextGuidIndex over.
//
InterlockedIncrement(&gs_lNextGuidIndex);
pGuidPtr[0] = gs_lNextGuidIndex;
pGuidPtr[1] = GetTickCount();
pGuidPtr[2] = GetCurrentThreadId();
pGuidPtr[3] = GetCurrentProcessId();
return(S_OK);
}
#endif