4061 lines
126 KiB
C++
4061 lines
126 KiB
C++
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1992 - 1993.
|
|
//
|
|
// File: dllcache.cxx
|
|
//
|
|
// Contents: Implementations of classes declared in dllcache.hxx
|
|
//
|
|
// Functions:
|
|
// CDllAptEntry::Init
|
|
// CDllAptEntry::Create
|
|
// CDllAptEntry::
|
|
//
|
|
// CDllCache::CDllCache
|
|
// CDllCache::~CDllCache
|
|
// CDllCache::InitClsent
|
|
// CDllCache::CreateClsent
|
|
// CDllCache::GetClassObjForDdeByClsent
|
|
// CDllCache::CleanUpLocalServersForApartment
|
|
// CDllCache::CleanUpDllsForApartment
|
|
// CDllCache::CleanUpDllsForProcess
|
|
// CDllCache::CleanUpForApartmentByDllent
|
|
// CDllCache::AtStorageRef
|
|
// CDllCache::Release
|
|
// CDllCache::InitDllent
|
|
// CDllCache::CreateDllent
|
|
// CDllCache::NewAptEntries
|
|
// CDllCache::AllocAptEntry
|
|
// CDllCache::FreeAptEntry
|
|
// CDllCache::IsValidInApartment
|
|
// CDllCache::MakeValidInApartment
|
|
// CDllCache::GetClassInterface
|
|
// CDllCache::CanUnloadNow
|
|
// CDllCache::Remove
|
|
// CDllCache::Init
|
|
// CDllCache::GetClass
|
|
// CDllCache::GetOrLoadClass
|
|
// CDllCache::GetClassObjForDde
|
|
// CDllCache::GetClassInformationFromKey
|
|
// CDllCache::GetApartmentForCLSID
|
|
// CDllCache::Add
|
|
// CDllCache::FreeUnused
|
|
// CDllCache::RegisterServer
|
|
// CDllCache::Revoke
|
|
// CDllCache::SetDdeServerWindow
|
|
// CDllCache::Search (x4)
|
|
// CDllCache::AllocClassEntry
|
|
// CDllCache::AllocDllPathEntry
|
|
// CDllCache::FreeClassEntry
|
|
// CDllCache::FreeDllPathEntry
|
|
//
|
|
// CleanUpDllsForProcess
|
|
// CleanUpLocalServersForApartment
|
|
// CleanUpDllsForApartment
|
|
// GetAptForCLSID
|
|
// GetClassInformationForDde
|
|
// GetClassInformationFromKey
|
|
// OleMainThreadWndProc
|
|
// InitMainThreadWnd
|
|
// UninitMainThreadWnd
|
|
//
|
|
//
|
|
// History: 09-May-93 Ricksa Created
|
|
// 31-Dec-93 ErikGav Chicago port
|
|
// 09-Jun-94 BruceMa Check new pointers
|
|
// 21-Jun-94 BruceMa Check new pointers
|
|
// 24-Jun-94 Rickhi Add Apartment Crap
|
|
// 24-Jun-94 BruceMa Check new pointers
|
|
// 28-Jun-94 BruceMa Memory sift fixes
|
|
// 07-Jul-94 BruceMa Memory sift fixes
|
|
// 08-Nov-94 Ricksa Final threading changes
|
|
// 07-Mar-95 BruceMa Rewrote
|
|
// 06-Oct-95 BruceMa Various fixes - mostly race conditions
|
|
// 19-Apr-96 Rickhi Add Suspend/Resume/AddRef/Release
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
#include <ole2int.h>
|
|
#include <channelb.hxx>
|
|
#include <tracelog.hxx>
|
|
#include <scmmem.hxx>
|
|
|
|
#include "objact.hxx"
|
|
#include <dllhost.hxx>
|
|
#include <sobjact.hxx>
|
|
#include <treat.hxx>
|
|
|
|
LPCTSTR ptszOle32DllName = TEXT("OLE32.DLL");
|
|
|
|
// Name of window class and message class for dispatching messages.
|
|
//const TCHAR OLE_WINDOW_CLASS = TEXT("OleObjectRpcWindow");
|
|
LPTSTR gOleWindowClass = NULL; // class used to create windows
|
|
|
|
// Various things used for special single threaded DLL processing
|
|
DWORD gdwMainThreadId = 0;
|
|
HWND hwndOleMainThread = NULL;
|
|
|
|
// this flag is to indicate whether it is UninitMainThread that is
|
|
// destroying the window, or system shut down destroying the window.
|
|
BOOL gfDestroyingMainWindow = FALSE;
|
|
|
|
const TCHAR *ptszOleMainThreadWndName = TEXT("OleMainThreadWndName");
|
|
#define DllRegisterClass RegisterClassT
|
|
#define DllUnregisterClass UnregisterClassT
|
|
|
|
|
|
#ifdef _CHICAGO_
|
|
// Note: we have to create a unique string so that get
|
|
// register a unique class for each 16 bit app.
|
|
// The class space is global on chicago.
|
|
//
|
|
LPSTR ptszOleMainThreadWndClass = "OleMainThreadWndClass 0x######## ";
|
|
#define DllCreateWindowEx SSCreateWindowExA
|
|
|
|
STDAPI_(LRESULT) OleNotificationProc(UINT wMsg, WPARAM wParam, LPARAM lParam);
|
|
|
|
#else // !_CHICAGO_
|
|
|
|
const WCHAR *ptszOleMainThreadWndClass = L"OleMainThreadWndClass";
|
|
#define DllCreateWindowEx CreateWindowEx
|
|
|
|
#endif // _CHICAGO_
|
|
|
|
|
|
#ifdef _UNICODE
|
|
#define TSZFMT "%ws"
|
|
#else
|
|
#define TSZFMT "%s"
|
|
#endif
|
|
|
|
static const TCHAR tszOle32Dll[] = TEXT("OLE32.DLL");
|
|
|
|
#define OLE32_DLL tszOle32Dll
|
|
#define OLE32_BYTE_LEN sizeof(OLE32_DLL)
|
|
#define OLE32_CHAR_LEN (sizeof(OLE32_DLL) / sizeof(TCHAR) - 1)
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: CallFreeUnused
|
|
//
|
|
// Synopsis: Free unused from main thread
|
|
//
|
|
// Arguments: [pData] - pointer to single thread parameter packet (unused)
|
|
//
|
|
// Returns: S_OK - call succeeded
|
|
//
|
|
// Algorithm: Call free unused for both inproc servers and in proc handlers.
|
|
//
|
|
// History: 10-Nov-94 Ricksa Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
HRESULT CallFreeUnused(void)
|
|
{
|
|
TRACECALL(TRACE_DLL, "CallFreeUnused");
|
|
|
|
gdllcacheInprocSrv.FreeUnused();
|
|
gdllcacheHandler.FreeUnused();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDllAptEntry::Init
|
|
//
|
|
// Synopsis: Initialize the entry to empty
|
|
//
|
|
// Arguments: dwNext - The next apartment entry in the free list
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 07-Mar-95 BruceMa Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
void CDllAptEntry::Init(DWORD dwNext)
|
|
{
|
|
_dwNext = dwNext;
|
|
_dwSig = 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDllAptEntry::Create
|
|
//
|
|
// Synopsis: Create an apartment entry
|
|
//
|
|
// Arguments: hApt - The creating apartment
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 07-Mar-95 BruceMa Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
void CDllAptEntry::Create(HAPT hApt)
|
|
{
|
|
_dwSig = DLL_APT_CACHE_SIG;
|
|
_hApt = hApt;
|
|
}
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDllCache::CDllCache
|
|
//
|
|
// Synopsis: Create a DLL cache object
|
|
//
|
|
// Algorithm: Let sub-objects do all the work.
|
|
//
|
|
// History: 09-May-93 Ricksa Created
|
|
// 07-Mar-95 BruceMa Rewrote
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
CDllCache::CDllCache(void) :
|
|
_pClassEntries(NULL), _pDllPathEntries(NULL),
|
|
_nClassEntryAvail(NONE), _nDllPathEntryAvail(NONE),
|
|
_nClassEntryInUse(NONE), _nDllPathEntryInUse(NONE),
|
|
_cClassEntries(0), _cDllPathEntries(0),
|
|
_cRefsServerProcess(0)
|
|
{
|
|
Win4Assert (g_fDllState == DLL_STATE_STATIC_CONSTRUCTING);
|
|
}
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDllCache::Load
|
|
//
|
|
// Synopsis: Load the module into the current apartment & retrieve
|
|
// the entry points
|
|
//
|
|
// Arguments: [ptszPath] - Dll path
|
|
// [ppfnGetClassObject] - where to return DllGetClassObejct EP
|
|
// [ppfnDllCanUnloadNow] - where to return DllCanUnloadNow EP
|
|
// fSixteenBit - Whether this is a 16-bit dll
|
|
// phDll - Address to store the loaded HMODULE
|
|
// pIsX86Dll returns TRUE if dll is an X86 dll
|
|
// fLoadAsX86 is TRUE if Dll was found on InprocServerX86 key
|
|
//
|
|
// Returns: S_OK - if successfull
|
|
//
|
|
// History: 24-Jun-94 Rickhi Created
|
|
// 07-Mar-95 BruceMa Rewrote
|
|
// 30-Sep-95 AlanWar Added support for WX86
|
|
//
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
HRESULT CDllCache::Load(LPCTSTR ptszPath,
|
|
LPFNGETCLASSOBJECT *ppfnGetClassObject,
|
|
DLLUNLOADFNP *ppfnDllCanUnload,
|
|
BOOL fSixteenBit,
|
|
HMODULE *phDll
|
|
#ifdef WX86OLE
|
|
,BOOL *pfIsX86Dll,
|
|
BOOL fLoadAsX86
|
|
#endif
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
#ifdef WX86OLE
|
|
BOOL fIsX86Dll;
|
|
#endif
|
|
|
|
if (fSixteenBit)
|
|
{
|
|
CairoleDebugOut((DEB_TRACE,
|
|
"Attempting to load 16 bit DLL " TSZFMT "\n", ptszPath));
|
|
|
|
// In this section, we need to call 16-bit DllGetClassObject. The
|
|
// g_OleThunkWow pointer is the VTABLE to use for getting back to
|
|
// the 16-bit implementation.
|
|
LPFNGETCLASSOBJECT pfnGetClassObject;
|
|
DLLUNLOADFNP pfnDllCanUnload;
|
|
|
|
hr = g_pOleThunkWOW->LoadProcDll(ptszPath,
|
|
(DWORD *)&pfnGetClassObject,
|
|
(DWORD *)&pfnDllCanUnload,
|
|
(DWORD *)phDll);
|
|
|
|
// A failure condition would mean that the DLL could not be found,
|
|
// or otherwise could not be loaded
|
|
if (FAILED(hr))
|
|
{
|
|
CairoleDebugOut((DEB_ERROR,
|
|
"Load 16 bit DLL " TSZFMT " failed(%x)\n",ptszPath,hr));
|
|
return CO_E_DLLNOTFOUND;
|
|
}
|
|
|
|
// The other possible error is the DLL didn't have the required
|
|
// interface
|
|
if (ppfnGetClassObject)
|
|
{
|
|
if (pfnGetClassObject == NULL)
|
|
{
|
|
CairoleDebugOut((DEB_ERROR,
|
|
"Get pfnGetClassObject %ws failed\n",
|
|
ptszPath));
|
|
|
|
return(CO_E_ERRORINDLL);
|
|
}
|
|
*ppfnGetClassObject = pfnGetClassObject;
|
|
}
|
|
|
|
if (ppfnDllCanUnload)
|
|
{
|
|
*ppfnDllCanUnload = pfnDllCanUnload;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CairoleDebugOut((DEB_TRACE,
|
|
"Attempting to load 32 bit DLL " TSZFMT "\n", ptszPath));
|
|
|
|
#ifdef WX86OLE
|
|
fLoadAsX86 = gcwx86.SetLoadAsX86(fLoadAsX86);
|
|
#endif
|
|
// Load the 32-bit DLL
|
|
*phDll = LoadLibraryExT(ptszPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
|
|
#ifdef WX86OLE
|
|
gcwx86.SetLoadAsX86(fLoadAsX86);
|
|
#endif
|
|
|
|
if (*phDll == NULL)
|
|
{
|
|
// Dll could not be loaded
|
|
CairoleDebugOut((DEB_ERROR,
|
|
"Load of " TSZFMT " failed\n",
|
|
ptszPath));
|
|
return HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
#ifdef WX86OLE
|
|
fIsX86Dll = gcwx86.IsModuleX86(*phDll);
|
|
if (pfIsX86Dll)
|
|
{
|
|
*pfIsX86Dll = fIsX86Dll;
|
|
}
|
|
#endif
|
|
|
|
// Get the entry points if desired
|
|
if (ppfnGetClassObject)
|
|
{
|
|
#ifdef WX86OLE
|
|
*ppfnGetClassObject = (LPFNGETCLASSOBJECT)
|
|
GetProcAddress(*phDll, DLL_GET_CLASS_OBJECT_EP);
|
|
if ((*ppfnGetClassObject == NULL) ||
|
|
(fIsX86Dll && ( (*ppfnGetClassObject =
|
|
gcwx86.TranslateDllGetClassObject(
|
|
*ppfnGetClassObject)) == NULL)))
|
|
#else
|
|
if ((*ppfnGetClassObject = (LPFNGETCLASSOBJECT)
|
|
GetProcAddress(*phDll, DLL_GET_CLASS_OBJECT_EP)) == NULL)
|
|
#endif
|
|
{
|
|
// Doesn't have a valid entry point for creation of class objects
|
|
return CO_E_ERRORINDLL;
|
|
}
|
|
}
|
|
|
|
if (ppfnDllCanUnload)
|
|
{
|
|
// Not having a unload entry point is valid behavior
|
|
*ppfnDllCanUnload = (DLLUNLOADFNP) GetProcAddress(*phDll,
|
|
DLL_CAN_UNLOAD_EP);
|
|
#ifdef WX86OLE
|
|
if (fIsX86Dll)
|
|
{
|
|
// Translating a NULL address will do nothing but return a
|
|
// NULL address
|
|
*ppfnDllCanUnload =
|
|
gcwx86.TranslateDllCanUnloadNow(
|
|
*ppfnDllCanUnload);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDllCache::InitClsent
|
|
//
|
|
// Synopsis: Initialize a class entry structure
|
|
//
|
|
// Algorithm: dwCls - The index of this class entry
|
|
// k - The next class entry index in the free list
|
|
//
|
|
// History: 07-Mar-95 BruceMa Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
void CDllCache::InitClsent(DWORD dwCls, DWORD k)
|
|
{
|
|
_pClassEntries[dwCls]._dwNext = k;
|
|
_pClassEntries[dwCls]._dwSig = 0;
|
|
_pClassEntries[dwCls]._dwNextDllCls = NONE;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDllCache::CreateClsentLSvr
|
|
//
|
|
// Synopsis: Create a class entry for a local server
|
|
//
|
|
// Algorithm: dwCls - The index of this class entry
|
|
// rclsid - The class ID for this server
|
|
// punk - IUnknown for the server
|
|
// dwFlags - Either REGCLS_SINGLEUSE or REGCLS_MULTIPLEUSE
|
|
// dwContext - CLSCTX_INPROC_SERVER | CLSREG_LOCAL_SERVER
|
|
// dwReg - The registration key returned to the user
|
|
//
|
|
// History: 07-Mar-95 BruceMa Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
HRESULT CDllCache::CreateClsentLSvr(DWORD dwCls,
|
|
REFCLSID rclsid,
|
|
IUnknown *punk,
|
|
DWORD dwFlags,
|
|
DWORD dwContext,
|
|
DWORD dwReg)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
// Initialize the class entry
|
|
_pClassEntries[dwCls]._dwSig = CLASS_CACHE_SIG;
|
|
_pClassEntries[dwCls]._fAtStorage = FALSE;
|
|
_pClassEntries[dwCls]._clsid = rclsid;
|
|
_pClassEntries[dwCls]._pUnk = punk;
|
|
_pClassEntries[dwCls]._dwContext = dwContext;
|
|
_pClassEntries[dwCls]._dwFlags = dwFlags;
|
|
_pClassEntries[dwCls]._hApt = GetCurrentApartmentId();
|
|
_pClassEntries[dwCls]._dwReg = dwReg;
|
|
_pClassEntries[dwCls]._cCallOut = 0;
|
|
_pClassEntries[dwCls]._fRevoking = FALSE;
|
|
_pClassEntries[dwCls]._fRevokePending = FALSE;
|
|
_pClassEntries[dwCls]._fReleasing = FALSE;
|
|
_pClassEntries[dwCls]._dwDllEnt = NONE;
|
|
_pClassEntries[dwCls]._dwNextDllCls = NONE;
|
|
_pClassEntries[dwCls]._hWndDdeServer = NULL;
|
|
_pClassEntries[dwCls]._dwScmReg = NONE;
|
|
_pClassEntries[dwCls]._pObjServer = NULL;
|
|
|
|
|
|
if (dwContext & CLSCTX_LOCAL_SERVER)
|
|
{
|
|
// store off a pointer to the activation server object.
|
|
_pClassEntries[dwCls]._pObjServer = GetObjServer();
|
|
|
|
if (!(dwFlags & REGCLS_SUSPENDED))
|
|
{
|
|
// Notify SCM that the class is started.
|
|
RegOutput *pRegOut = NULL;
|
|
|
|
RegInput RegIn;
|
|
RegIn.dwSize = 1;
|
|
RegIn.rginent[0].clsid = rclsid;
|
|
RegIn.rginent[0].dwFlags = dwFlags;
|
|
RegIn.rginent[0].ipid = _pClassEntries[dwCls]._pObjServer->GetIPID();
|
|
RegIn.rginent[0].oxid = _pClassEntries[dwCls]._pObjServer->GetOXID();
|
|
|
|
// Release the lock across outgoing calls to the SCM.
|
|
_mxs.Release();
|
|
hr = gResolver.NotifyStarted(&RegIn, &pRegOut);
|
|
_mxs.Request();
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
_pClassEntries[dwCls]._fAtStorage = pRegOut->regoutent[0].dwAtStorage;
|
|
_pClassEntries[dwCls]._dwScmReg = pRegOut->regoutent[0].dwReg;
|
|
MIDL_user_free(pRegOut);
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDllCache::CreateClsentInProc
|
|
//
|
|
// Synopsis: Create a class entry for an inproc server
|
|
//
|
|
// Algorithm: dwCls - The index of this class entry
|
|
// dwDll - The index of the parent dll path entry
|
|
// rclsid - The class ID for this server
|
|
//
|
|
// History: 07-Mar-95 BruceMa Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
HRESULT CDllCache::CreateClsentInProc(DWORD dwCls,
|
|
DWORD dwDll,
|
|
DWORD dwDllThreadModel,
|
|
DWORD dwNextDllCls,
|
|
REFCLSID rclsid
|
|
#ifdef WX86OLE
|
|
,BOOL fWx86
|
|
#endif
|
|
)
|
|
{
|
|
ComDebOut((DEB_TRACE,
|
|
"CDllCache::CreateClsentInproc clsid:%I dwCls:%x dwDll:%x\n",
|
|
&rclsid, dwCls, dwDll));
|
|
|
|
// Initialize the class entry
|
|
_pClassEntries[dwCls]._dwSig = CLASS_CACHE_SIG;
|
|
_pClassEntries[dwCls]._fAtStorage = FALSE;
|
|
_pClassEntries[dwCls]._clsid = rclsid;
|
|
_pClassEntries[dwCls]._pUnk = NULL;
|
|
_pClassEntries[dwCls]._dwContext =
|
|
#ifdef WX86OLE
|
|
fWx86 ? CLSCTX_INPROC_SERVERX86 :
|
|
#endif
|
|
CLSCTX_INPROC_SERVER;
|
|
_pClassEntries[dwCls]._dwFlags = REGCLS_MULTIPLEUSE;
|
|
_pClassEntries[dwCls]._hApt = GetCurrentApartmentId();
|
|
_pClassEntries[dwCls]._dwReg = 0;
|
|
_pClassEntries[dwCls]._cCallOut = 0;
|
|
_pClassEntries[dwCls]._fRevokePending = FALSE;
|
|
_pClassEntries[dwCls]._fRevoking = FALSE;
|
|
_pClassEntries[dwCls]._fReleasing = FALSE;
|
|
_pClassEntries[dwCls]._dwDllEnt = dwDll;
|
|
_pClassEntries[dwCls]._dwDllThreadModel= dwDllThreadModel;
|
|
_pClassEntries[dwCls]._dwNextDllCls = dwNextDllCls;
|
|
_pClassEntries[dwCls]._hWndDdeServer = NULL;
|
|
_pClassEntries[dwCls]._dwScmReg = NONE;
|
|
|
|
if (dwDllThreadModel == FREE_THREADED ||
|
|
dwDllThreadModel == BOTH_THREADED)
|
|
{
|
|
// for any FT and BOTH threaded classes, delay unloading the DLL
|
|
_pDllPathEntries[dwDll]._dwFlags |= DELAYED_UNLOAD;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CDllCache::GetClassObjForDdeByClsent
|
|
//
|
|
// Synopsis: Get a class entry from the table for Dde, returning
|
|
// extra information, including the flags.
|
|
//
|
|
// Effects: The DdeServer needs the ability to query the class factory
|
|
// table to search for classes it needs to provide OLE 1.0
|
|
// support for. This routine will allow it to access the
|
|
// required information.
|
|
//
|
|
// Arguments: dwCls - The index of this class entry
|
|
// lpDdeClassInfo - The DDE structure to fill in
|
|
//
|
|
// Returns: TRUE if the entry matched, FALSE if it did not.
|
|
//
|
|
// History: 5-28-94 kevinro Created
|
|
// 07-Mar-95 BruceMa Rewrote
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL CDllCache::GetClassObjForDdeByClsent(DWORD dwCls,
|
|
LPDDECLASSINFO lpDdeClassInfo)
|
|
{
|
|
Win4Assert(IsValidPtrOut(lpDdeClassInfo, sizeof(DWORD)) &&
|
|
"CDllCache::GetClassObjForDde invalid out parameter");
|
|
|
|
if (lpDdeClassInfo->dwContextMask & _pClassEntries[dwCls]._dwContext)
|
|
{
|
|
HAPT hApt = GetCurrentApartmentId();
|
|
|
|
if (hApt == _pClassEntries[dwCls]._hApt)
|
|
{
|
|
// Found a matching record, set its info
|
|
lpDdeClassInfo->dwContext = _pClassEntries[dwCls]._dwContext;
|
|
lpDdeClassInfo->dwFlags = _pClassEntries[dwCls]._dwFlags;
|
|
lpDdeClassInfo->dwThreadId = _pClassEntries[dwCls]._hApt;
|
|
lpDdeClassInfo->dwRegistrationKey = _pClassEntries[dwCls]._dwReg;
|
|
|
|
if (lpDdeClassInfo->fClaimFactory == TRUE)
|
|
{
|
|
// Release the lock across the outgoing call
|
|
IUnknown *pUnkTmp = _pClassEntries[dwCls]._pUnk;
|
|
|
|
_mxs.Release();
|
|
HRESULT hr = pUnkTmp->QueryInterface(
|
|
IID_IClassFactory,
|
|
(void **)&(lpDdeClassInfo->punk));
|
|
_mxs.Request();
|
|
|
|
if (hr != S_OK)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// We do this only after the QueryInterface has succeeded
|
|
if (_pClassEntries[dwCls]._dwFlags == REGCLS_SINGLEUSE)
|
|
{
|
|
// For a single use class we can only pass it out once. To
|
|
// guarantee it, we set the context to zero so that the
|
|
// above test will not pass again.
|
|
_pClassEntries[dwCls]._dwContext = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lpDdeClassInfo->punk = NULL;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDllCache::Release
|
|
//
|
|
// Synopsis: Disconnect and release the associated server
|
|
//
|
|
// Arguments: dwCls - The index of this class entry
|
|
//
|
|
// History: 07-Mar-95 BruceMa Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
HRESULT CDllCache::Release(DWORD dwCls)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
CairoleDebugOut((DEB_TRACE, "CDllCache::Release Releasing class %d\n",
|
|
dwCls));
|
|
|
|
// Disallow recursive releases (like Lotus Notes 4.0)
|
|
if (_pClassEntries[dwCls]._fReleasing)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
// Invalidate this class entry
|
|
_pClassEntries[dwCls]._dwContext = 0;
|
|
_pClassEntries[dwCls]._fReleasing = TRUE;
|
|
|
|
// Release the lock across outgoing calls and SendMessage (We can do this
|
|
// without setting up local variables since the class entry can't be
|
|
// reused until we do FreeClassEntry)
|
|
if (_pClassEntries[dwCls]._pUnk != NULL)
|
|
{
|
|
_mxs.Release();
|
|
|
|
// Tell SCM about multiple use classes stopping.
|
|
if (_pClassEntries[dwCls]._dwScmReg != NONE)
|
|
{
|
|
gResolver.NotifyStopped(_pClassEntries[dwCls]._clsid,
|
|
_pClassEntries[dwCls]._dwScmReg);
|
|
_pClassEntries[dwCls]._dwScmReg = NONE;
|
|
}
|
|
|
|
// If a DDE Server window exists for this class, then we need to
|
|
// release it now.
|
|
if (_pClassEntries[dwCls]._hWndDdeServer != NULL)
|
|
{
|
|
// It's possible that SendMessage could fail. However, there
|
|
// really isn't anything we can do about it. So, the error
|
|
// code is not checked.
|
|
SSSendMessage(_pClassEntries[dwCls]._hWndDdeServer, WM_USER, 0, 0);
|
|
_pClassEntries[dwCls]._hWndDdeServer == NULL;
|
|
}
|
|
|
|
// Now really release it
|
|
if (_pClassEntries[dwCls]._pUnk != NULL)
|
|
{
|
|
if (IsValidInterface(_pClassEntries[dwCls]._pUnk))
|
|
{
|
|
CoDisconnectObject(_pClassEntries[dwCls]._pUnk, NULL);
|
|
_pClassEntries[dwCls]._pUnk->Release();
|
|
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
hr = CO_E_RELEASED;
|
|
}
|
|
}
|
|
|
|
// Retake the lock
|
|
_mxs.Request();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDllCache::InitDllent
|
|
//
|
|
// Synopsis: Initialize a dll path entry structure
|
|
//
|
|
// Arguments: dwDll - The index of this dll path entry
|
|
// k - The next dll path entry in the free list
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: 07-Mar-95 BruceMa Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
void CDllCache::InitDllent(DWORD dwDll, DWORD k)
|
|
{
|
|
_pDllPathEntries[dwDll]._dwNext = k;
|
|
_pDllPathEntries[dwDll]._dwSig = 0;
|
|
_pDllPathEntries[dwDll]._dwFlags = 0;
|
|
_pDllPathEntries[dwDll]._dw1stClass = NONE;
|
|
_pDllPathEntries[dwDll]._cAptEntries = NOMINAL_NUMBER_THREADS;
|
|
_pDllPathEntries[dwDll]._nAptAvail = 0;
|
|
_pDllPathEntries[dwDll]._nAptInUse = NONE;
|
|
_pDllPathEntries[dwDll]._dwExpireTime = 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDllCache::CreateDllent
|
|
//
|
|
// Synopsis: Fully initialize a DLL object
|
|
//
|
|
// Arguments: dwDll - The index of this dll path entry
|
|
// ptszDllPath - The load path for the dll
|
|
// fSixteenBit - Whether this is a 16-bit dll
|
|
//
|
|
// Algorithm: Creates the first CDllAptEntry which loads the
|
|
// DLL specified by the path, gets the DllGetClassObject
|
|
// entry point and the DllCanUnloadNow entry point.
|
|
// At this point object construction is complete.
|
|
//
|
|
// History: 09-May-93 Ricksa Created
|
|
// 07-Mar-95 BruceMa Rewrote
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
HRESULT CDllCache::CreateDllent(DWORD dwDll,
|
|
LPCTSTR ptszDllPath,
|
|
BOOL fSixteenBit,
|
|
LPFNGETCLASSOBJECT pfnGetClassObject,
|
|
DLLUNLOADFNP pfnDllCanUnload,
|
|
HMODULE hDll
|
|
#ifdef WX86OLE
|
|
,BOOL fIsX86Dll,
|
|
BOOL fLoadAsX86
|
|
#endif
|
|
)
|
|
{
|
|
TRACECALL(TRACE_DLL, "CDllCache::CreateDllent");
|
|
CairoleDebugOut((DEB_TRACE, "Initializing dll " TSZFMT "\n", ptszDllPath));
|
|
|
|
// Get the path length and allocate for it
|
|
UINT ccH = lstrlen(ptszDllPath) + 1;
|
|
_pDllPathEntries[dwDll]._ptszPath = (TCHAR *) PrivMemAlloc(ccH * sizeof(TCHAR));
|
|
if (_pDllPathEntries[dwDll]._ptszPath == NULL)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
// Initialize the dll path entry
|
|
memcpy(_pDllPathEntries[dwDll]._ptszPath, ptszDllPath, ccH * sizeof(TCHAR));
|
|
CharUpper(_pDllPathEntries[dwDll]._ptszPath);
|
|
_pDllPathEntries[dwDll]._dwFlags |= fSixteenBit ? SIXTEEN_BIT : 0;
|
|
_pDllPathEntries[dwDll]._cUsing = 0;
|
|
|
|
// Compute a hash value for more optimal searchs
|
|
_pDllPathEntries[dwDll]._dwHash = Hash(_pDllPathEntries[dwDll]._ptszPath);
|
|
|
|
|
|
// 32 bit libraries have process wide handles, so
|
|
// we'll store them in the DllPathEntry
|
|
if (fSixteenBit)
|
|
{
|
|
_pDllPathEntries[dwDll]._hDll32 = 0;
|
|
}
|
|
else
|
|
{
|
|
_pDllPathEntries[dwDll]._hDll32 = hDll;
|
|
}
|
|
|
|
// Construct the initial per apartment entry
|
|
DWORD dwAptent = AllocAptEntry(dwDll);
|
|
if (dwAptent == NONE)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
// Initialize it
|
|
_pDllPathEntries[dwDll]._pAptEntries[dwAptent].Create(GetCurrentApartmentId());
|
|
|
|
// Check if this is "OLE32.DLL"
|
|
if (lstrcmp(_pDllPathEntries[dwDll]._ptszPath, ptszOle32DllName)
|
|
== 0)
|
|
{
|
|
_pDllPathEntries[dwDll]._pfnGetClassObject = DllGetClassObject;
|
|
_pDllPathEntries[dwDll]._pfnDllCanUnload = NULL;
|
|
_pDllPathEntries[dwDll]._dwFlags |= IS_OLE32;
|
|
}
|
|
else
|
|
{
|
|
_pDllPathEntries[dwDll]._pfnGetClassObject = pfnGetClassObject;
|
|
_pDllPathEntries[dwDll]._pfnDllCanUnload = pfnDllCanUnload;
|
|
_pDllPathEntries[dwDll]._pAptEntries[dwAptent]._hDll = (fSixteenBit ? hDll : 0);
|
|
#ifdef WX86OLE
|
|
if (fIsX86Dll)
|
|
{
|
|
_pDllPathEntries[dwDll]._dwFlags |= WX86_THUNK;
|
|
}
|
|
if (fLoadAsX86)
|
|
{
|
|
_pDllPathEntries[dwDll]._dwFlags |= WX86_LOADASX86;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDllCache::NewAptEntries
|
|
//
|
|
// Synopsis: Allocate and initialize the apartment entries for
|
|
// a dll path entry
|
|
//
|
|
// Arguments: dwDll - The index of this dll path entry
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: 07-Mar-95 BruceMa Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
BOOL CDllCache::NewAptEntries(DWORD dwDll)
|
|
{
|
|
|
|
_pDllPathEntries[dwDll]._pAptEntries = new CDllAptEntry[NOMINAL_NUMBER_THREADS];
|
|
if (_pDllPathEntries[dwDll]._pAptEntries == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
for (int dwApt = 0; dwApt < NOMINAL_NUMBER_THREADS; dwApt++)
|
|
{
|
|
_pDllPathEntries[dwDll]._pAptEntries[dwApt].Init(
|
|
dwApt == NOMINAL_NUMBER_THREADS - 1 ? NONE : dwApt + 1);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDllCache::AllocAptEntry
|
|
//
|
|
// Synopsis: Allocate a new apartment entry for a dll path entry
|
|
//
|
|
// Arguments: dwDll - The index of this dll path entry
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: 07-Mar-95 BruceMa Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
DWORD CDllCache::AllocAptEntry(DWORD dwDll)
|
|
{
|
|
// If we don't have any available entries, then expand the array
|
|
if (_pDllPathEntries[dwDll]._nAptAvail == NONE)
|
|
{
|
|
// Allocate a new array
|
|
DWORD cEnt = _pDllPathEntries[dwDll]._cAptEntries;
|
|
CDllAptEntry *p = new CDllAptEntry[cEnt + NOMINAL_NUMBER_THREADS];
|
|
if (p == NULL)
|
|
{
|
|
return NONE;
|
|
}
|
|
|
|
// Initialize it
|
|
memcpy(p,
|
|
_pDllPathEntries[dwDll]._pAptEntries,
|
|
_pDllPathEntries[dwDll]._cAptEntries * sizeof(CDllAptEntry));
|
|
|
|
// Free old array
|
|
delete _pDllPathEntries[dwDll]._pAptEntries;
|
|
_pDllPathEntries[dwDll]._pAptEntries = p;
|
|
|
|
for (DWORD k = _pDllPathEntries[dwDll]._cAptEntries;
|
|
k < _pDllPathEntries[dwDll]._cAptEntries + NOMINAL_NUMBER_THREADS;
|
|
k++)
|
|
{
|
|
_pDllPathEntries[dwDll]._pAptEntries[k].Init(
|
|
k == _pDllPathEntries[dwDll]._cAptEntries + NOMINAL_NUMBER_THREADS - 1 ? NONE : k + 1 );
|
|
}
|
|
_pDllPathEntries[dwDll]._nAptAvail = _pDllPathEntries[dwDll]._cAptEntries;
|
|
_pDllPathEntries[dwDll]._cAptEntries += NOMINAL_NUMBER_THREADS;
|
|
}
|
|
|
|
// Return the next available entry
|
|
DWORD dwAptent = _pDllPathEntries[dwDll]._nAptAvail;
|
|
_pDllPathEntries[dwDll]._pAptEntries[dwAptent]._dwSig = DLL_APT_CACHE_SIG;
|
|
|
|
_pDllPathEntries[dwDll]._nAptAvail =
|
|
_pDllPathEntries[dwDll]._pAptEntries[dwAptent]._dwNext;
|
|
_pDllPathEntries[dwDll]._pAptEntries[dwAptent]._dwNext =
|
|
_pDllPathEntries[dwDll]._nAptInUse;
|
|
_pDllPathEntries[dwDll]._nAptInUse = dwAptent;
|
|
return dwAptent;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDllCache::FreeAptEntry
|
|
//
|
|
// Synopsis: Free an apt entry in a dll path entry - i.e., make it available
|
|
//
|
|
// Arguments: dwDll - The index of this dll path entry
|
|
// dwAptent - The index of the apartment entry to free
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: 07-Mar-95 BruceMa Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
void CDllCache::FreeAptEntry(DWORD dwDll, DWORD dwAptent)
|
|
{
|
|
// It's at the head of the list
|
|
if (_pDllPathEntries[dwDll]._nAptInUse == dwAptent)
|
|
{
|
|
_pDllPathEntries[dwDll]._nAptInUse =
|
|
_pDllPathEntries[dwDll]._pAptEntries[dwAptent]._dwNext;
|
|
}
|
|
|
|
// Otherwise search for the entry that points to the one we're freeing
|
|
else
|
|
{
|
|
for (DWORD dwPrev = _pDllPathEntries[dwDll]._nAptInUse;
|
|
_pDllPathEntries[dwDll]._pAptEntries[dwPrev]._dwNext != dwAptent;
|
|
dwPrev = _pDllPathEntries[dwDll]._pAptEntries[dwPrev]._dwNext)
|
|
{
|
|
}
|
|
_pDllPathEntries[dwDll]._pAptEntries[dwPrev]._dwNext =
|
|
_pDllPathEntries[dwDll]._pAptEntries[dwAptent]._dwNext;
|
|
}
|
|
|
|
// Relink into the list of available entries
|
|
_pDllPathEntries[dwDll]._pAptEntries[dwAptent]._dwNext =
|
|
_pDllPathEntries[dwDll]._nAptAvail;
|
|
_pDllPathEntries[dwDll]._nAptAvail = dwAptent;
|
|
_pDllPathEntries[dwDll]._pAptEntries[dwAptent].Init(
|
|
_pDllPathEntries[dwDll]._pAptEntries[dwAptent]._dwNext);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDllCache::IsValidInApartment
|
|
//
|
|
// Synopsis: Determine whether Dll object is valid in the current apartment
|
|
//
|
|
// Arguments: dwDll - The index of this dll path entry
|
|
// hApt - apartment to check
|
|
//
|
|
// Returns: TRUE - it is valid
|
|
// FALSE - it isn't valid
|
|
//
|
|
// History: 10-Nov-94 Ricksa Created
|
|
// 07-Mar-95 BruceMa Rewrote
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
BOOL CDllCache::IsValidInApartment(DWORD dwDll, HAPT hApt)
|
|
{
|
|
for (DWORD dwAptent = _pDllPathEntries[dwDll]._nAptInUse;
|
|
dwAptent != NONE;
|
|
dwAptent = _pDllPathEntries[dwDll]._pAptEntries[dwAptent]._dwNext)
|
|
{
|
|
if (_pDllPathEntries[dwDll]._pAptEntries[dwAptent]._hApt == hApt)
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDllCache::MakeValidInApartment
|
|
//
|
|
// Synopsis: Ensure the Dll object is valid in the current apartment
|
|
//
|
|
// Arguments: dwDll - The index of this dll path entry
|
|
//
|
|
// Returns: S_OK - Dll is valid in this apartment
|
|
// E_OUTOFMEMORY - Could not allocate memory
|
|
//
|
|
// History: 24-Jun-94 Rickhi Created
|
|
// 07-Mar-95 BruceMa Rewrote
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
HRESULT CDllCache::MakeValidInApartment(DWORD dwDll)
|
|
{
|
|
HRESULT hr;
|
|
#ifdef WX86OLE
|
|
BOOL fIsX86Dll;
|
|
#endif
|
|
|
|
|
|
|
|
// Walk the list of apartment entries looking for a match
|
|
// with the current apartment id. If one exists, we are valid,
|
|
// Otherwise, we will try to create an entry for the current
|
|
// apartment.
|
|
HAPT hApt = GetCurrentApartmentId();
|
|
if (IsValidInApartment(dwDll, hApt))
|
|
{
|
|
CairoleDebugOut((DEB_TRACE, "Making dll " TSZFMT " valid in apt %d\n",
|
|
_pDllPathEntries[dwDll]._ptszPath, hApt));
|
|
return S_OK;
|
|
}
|
|
|
|
// No match found, create a new entry
|
|
DWORD dwAptent = AllocAptEntry(dwDll);
|
|
if (dwAptent == NONE)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
// Initialize the new apartment entry
|
|
_pDllPathEntries[dwDll]._pAptEntries[dwAptent].Create(hApt);
|
|
|
|
|
|
// Dll is always valid if Ole32 and for non-WOW case
|
|
if ((_pDllPathEntries[dwDll]._dwFlags & IS_OLE32) || !IsWOWProcess())
|
|
{
|
|
_pDllPathEntries[dwDll]._pAptEntries[dwAptent]._hDll = 0;
|
|
return S_OK;
|
|
}
|
|
|
|
// We need to release the lock across the LoadLibrary since there is
|
|
// a chance that an exiting thread waits on our mutext to
|
|
// CleanUpFoApartment while we wait on the kernel mutex which the
|
|
// exiting thread owns
|
|
TCHAR *ptszPath;
|
|
LPFNGETCLASSOBJECT pfnGetClassObject;
|
|
DLLUNLOADFNP pfnDllCanUnload;
|
|
DWORD dwSixteenBit;
|
|
HMODULE hDll;
|
|
|
|
ptszPath = _pDllPathEntries[dwDll]._ptszPath;
|
|
dwSixteenBit = _pDllPathEntries[dwDll]._dwFlags & SIXTEEN_BIT;
|
|
|
|
// Reset the entry point values on every apartment initialization
|
|
// to handle DLLs being unloaded and then reloaded at a different
|
|
// address.
|
|
_mxs.Release();
|
|
hr = Load(ptszPath,
|
|
&pfnGetClassObject,
|
|
&pfnDllCanUnload,
|
|
dwSixteenBit,
|
|
&hDll
|
|
#ifdef WX86OLE
|
|
, &fIsX86Dll,
|
|
_pDllPathEntries[dwDll]._dwFlags & WX86_LOADASX86
|
|
#endif
|
|
);
|
|
_mxs.Request();
|
|
|
|
#ifdef WX86OLE
|
|
if (fIsX86Dll)
|
|
{
|
|
_pDllPathEntries[dwDll]._dwFlags |= WX86_THUNK;
|
|
}
|
|
#endif
|
|
|
|
_pDllPathEntries[dwDll]._pfnGetClassObject = pfnGetClassObject;
|
|
_pDllPathEntries[dwDll]._pfnDllCanUnload = pfnDllCanUnload;
|
|
_pDllPathEntries[dwDll]._pAptEntries[dwAptent]._hDll = hDll;
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
FreeAptEntry(dwDll, dwAptent);
|
|
}
|
|
else
|
|
{
|
|
CairoleDebugOut((DEB_TRACE, "Making dll %ws valid in apt %d\n",
|
|
_pDllPathEntries[dwDll]._ptszPath, hApt));
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDllCache::GetClassInterface
|
|
//
|
|
// Synopsis: Create the class factory from the DLL
|
|
//
|
|
// Arguments: [dwDll] - The index of this dll path entry
|
|
// [rclsid] - class ID
|
|
// [riid] - interface req'd of class object
|
|
// [hr] - HRESULT to return
|
|
//
|
|
// Returns: NULL - class factory could not be created
|
|
// ~NULL - newly created class factory
|
|
//
|
|
// History: 09-May-93 Ricksa Created
|
|
// 07-Mar-95 BruceMa Rewrote
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
IUnknown *CDllCache::GetClassInterface(DWORD dwDll,
|
|
DWORD dwDllThreadModel,
|
|
REFCLSID rclsid,
|
|
REFIID riid,
|
|
HRESULT& hr)
|
|
{
|
|
TRACECALL(TRACE_DLL, "CDllCache::GetClassInterface");
|
|
CairoleDebugOut((DEB_TRACE, "Getting class interface\n"));
|
|
|
|
IUnknown *punk = NULL;
|
|
|
|
// Make sure this Dll is valid in the current apartment.
|
|
if(FAILED(MakeValidInApartment(dwDll)))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
// Need to check to see if the class is 16-bit or not.
|
|
// If it is 16-bit, then this call needs to be routed through
|
|
// a thunk
|
|
if (!(_pDllPathEntries[dwDll]._dwFlags & SIXTEEN_BIT))
|
|
{
|
|
// Find 32 bit interface
|
|
//
|
|
// We load single threaded DLLs specially if we are not in WOW.
|
|
// The reason for this is that the initial release of Daytona
|
|
// did not know about multiple threads and therefore, we want
|
|
// to make sure that they don't get inadvertently multithreaded.
|
|
// The reason we don't have to do this if we are in WOW is that
|
|
// only one thread is allowed to execute at a time even though
|
|
// there are multiple physical threads and therefore the DLL
|
|
// will never be executed in a multithreaded manner.
|
|
|
|
// Release the lock across outgoing calls
|
|
LPFNGETCLASSOBJECT pfnGetClassObject =
|
|
_pDllPathEntries[dwDll]._pfnGetClassObject;
|
|
|
|
// This prevents DllCanUnloadNow being called during this call out
|
|
_pDllPathEntries[dwDll]._cUsing++;
|
|
|
|
// this resets the delay time for delayed unload DLLs
|
|
_pDllPathEntries[dwDll]._dwExpireTime = 0;
|
|
|
|
_mxs.Release();
|
|
|
|
BOOL fThisThread = TRUE;
|
|
switch (dwDllThreadModel)
|
|
{
|
|
case SINGLE_THREADED:
|
|
if ((!IsWOWProcess() || !IsWOWThread() || !IsWOWThreadCallable())
|
|
&& !OnMainThread())
|
|
{
|
|
// Pass the call to the main thread
|
|
fThisThread = FALSE;
|
|
if (IsMTAThread())
|
|
{
|
|
hr = DoSTMTClassCreate(pfnGetClassObject, rclsid, riid, &punk);
|
|
}
|
|
else
|
|
{
|
|
hr = DoSTClassCreate(pfnGetClassObject, rclsid, riid, &punk);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case APT_THREADED:
|
|
if (IsMTAThread())
|
|
{
|
|
// pass call to apartment thread worker
|
|
fThisThread = FALSE;
|
|
hr = DoATClassCreate(pfnGetClassObject, rclsid, riid, &punk);
|
|
}
|
|
break;
|
|
|
|
case FREE_THREADED:
|
|
if (IsSTAThread())
|
|
{
|
|
// pass call to apartment thread worker
|
|
fThisThread = FALSE;
|
|
hr = DoMTClassCreate(pfnGetClassObject, rclsid, riid, &punk);
|
|
}
|
|
break;
|
|
|
|
case BOTH_THREADED:
|
|
break;
|
|
}
|
|
|
|
if (fThisThread)
|
|
{
|
|
hr = (*pfnGetClassObject)(rclsid, riid, (void **) &punk);
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
CairoleDebugOut((DEB_ERROR,"GetClassInterface failed (0x%x)\n",hr));
|
|
}
|
|
|
|
_mxs.Request();
|
|
_pDllPathEntries[dwDll]._cUsing--;
|
|
}
|
|
else
|
|
{
|
|
// Find 16-bit interface
|
|
if (!IsWOWProcess())
|
|
{
|
|
CairoleDebugOut((DEB_TRACE,
|
|
"GetClassInterface on 16bit while not in VDM\n"));
|
|
return NULL;
|
|
}
|
|
|
|
if (!IsWOWThread())
|
|
{
|
|
CairoleDebugOut((DEB_TRACE,
|
|
"GetClassInterface on 16bit while not in 16-bit thread\n"));
|
|
return NULL;
|
|
}
|
|
|
|
// Release the lock across outgoing calls
|
|
LPFNGETCLASSOBJECT pfnGetClassObject =
|
|
_pDllPathEntries[dwDll]._pfnGetClassObject;
|
|
|
|
// This prevents DllCanUnloadNow being called during this call out
|
|
_pDllPathEntries[dwDll]._cUsing++;
|
|
|
|
_mxs.Release();
|
|
hr = g_pOleThunkWOW->CallGetClassObject((DWORD)pfnGetClassObject,
|
|
rclsid,
|
|
riid,
|
|
(void **)&punk);
|
|
_mxs.Request();
|
|
_pDllPathEntries[dwDll]._cUsing--;
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
CairoleDebugOut((DEB_ERROR,
|
|
"GetClassInterface 16-bit failed (0x%x)\n",hr));
|
|
}
|
|
}
|
|
|
|
return punk;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDllCache::CanUnloadNow
|
|
//
|
|
// Synopsis: Find out whether DLL can be unloaded.
|
|
//
|
|
// Algorithm: If the DLL supports unloading, ask it if it can be
|
|
// unloaded and return the result to the caller.
|
|
//
|
|
// Arguments: dwDll - The index of this dll path entry
|
|
//
|
|
// History: 09-May-93 Ricksa Created
|
|
// 07-Mar-95 BruceMa Rewrote
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
HRESULT CDllCache::CanUnloadNow(DWORD dwDll)
|
|
{
|
|
CairoleDebugOut((DEB_TRACE, "Calling CanUnloadNow on " TSZFMT "\n",
|
|
_pDllPathEntries[dwDll]._ptszPath));
|
|
|
|
// Single thread access to the table
|
|
COleStaticLock lck(_mxs);
|
|
|
|
// Unless the code is changed, we should not be here in the Wow case
|
|
CairoleAssert(!IsWOWProcess() && "Freeing unused libraries in WOW");
|
|
|
|
|
|
if (_pDllPathEntries[dwDll]._cUsing != 0)
|
|
{
|
|
// At least one thread is using the object unlocked so we better
|
|
// not release the DLL object.
|
|
return S_FALSE;
|
|
}
|
|
|
|
// Does DLL support unloading itself?
|
|
if (_pDllPathEntries[dwDll]._pfnDllCanUnload)
|
|
{
|
|
// Release the lock across outgoing call
|
|
BOOL fSixteenBit = _pDllPathEntries[dwDll]._dwFlags & SIXTEEN_BIT;
|
|
DLLUNLOADFNP pfnDllCanUnload = _pDllPathEntries[dwDll]._pfnDllCanUnload;
|
|
HRESULT hr;
|
|
|
|
_mxs.Release();
|
|
|
|
// Need to check to see if the class is 16-bit.
|
|
// If it is 16-bit, then this call needs to be routed through a thunk
|
|
if (!fSixteenBit)
|
|
{
|
|
// Call through to the DLL -- does it think it can unload?
|
|
hr = (*pfnDllCanUnload)();
|
|
if (hr == S_OK &&
|
|
_pDllPathEntries[dwDll]._dwFlags & DELAYED_UNLOAD)
|
|
{
|
|
// the DLL thinks it's OK to unload, but we are employing
|
|
// delayed unloading, so go check if we've reached the
|
|
// expire time yet.
|
|
DWORD dwCurrentTime = GetTickCount();
|
|
if (_pDllPathEntries[dwDll]._dwExpireTime == 0)
|
|
{
|
|
// first time we've reached this state, record the
|
|
// expire timer. When current time exceeds this time
|
|
// we can unload.
|
|
_pDllPathEntries[dwDll]._dwExpireTime = dwCurrentTime + DLL_DELAY_UNLOAD_TIME;
|
|
if (_pDllPathEntries[dwDll]._dwExpireTime < DLL_DELAY_UNLOAD_TIME)
|
|
{
|
|
// handle counter wrapping, we'll just wait a little
|
|
// longer once every 49.7 days.
|
|
_pDllPathEntries[dwDll]._dwExpireTime = DLL_DELAY_UNLOAD_TIME;
|
|
}
|
|
hr = S_FALSE;
|
|
}
|
|
else
|
|
{
|
|
if ((_pDllPathEntries[dwDll]._dwExpireTime > dwCurrentTime) ||
|
|
(dwCurrentTime + DLL_DELAY_UNLOAD_TIME < _pDllPathEntries[dwDll]._dwExpireTime))
|
|
{
|
|
hr = S_FALSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!IsWOWThread() || !IsWOWThreadCallable())
|
|
{
|
|
_mxs.Request();
|
|
return S_FALSE;
|
|
}
|
|
|
|
hr = g_pOleThunkWOW->CallCanUnloadNow((DWORD) pfnDllCanUnload);
|
|
}
|
|
|
|
_mxs.Request();
|
|
return hr;
|
|
|
|
}
|
|
|
|
return S_FALSE;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDllCache::CleanUpForApartmentByDllent
|
|
//
|
|
// Synopsis: Find and delete the apartment entry for the given apt
|
|
//
|
|
// Arguments: [dwDll] - the index of this dll path entry
|
|
// [hApt] - apartment to clean up
|
|
//
|
|
// Returns: TRUE - There are no apartments using this object
|
|
// FALSE - There are still apartments using this object
|
|
//
|
|
// Algorithm: Search the list for a matching apartment entry, unlink
|
|
// it from the chain, and delete it.
|
|
//
|
|
// History: 24-Jun-94 Rickhi Created
|
|
// 10-Nov-94 Ricksa Modified for DllCanUnloadNow
|
|
// 07-Mar-95 BruceMa Rewrote
|
|
// 29-May-96 BruceMa Also release class entries for the
|
|
// specified apartment for this dll
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
BOOL CDllCache::CleanUpForApartmentByDllent(DWORD dwDll, HAPT hApt)
|
|
{
|
|
DWORD dwNext;
|
|
// Remove all class entries associated with this apartment
|
|
DWORD dwClsent, dwNextCls;
|
|
|
|
|
|
// Loop through the active apartments for this dll
|
|
for (DWORD dwAptent = _pDllPathEntries[dwDll]._nAptInUse;
|
|
dwAptent != NONE;
|
|
dwAptent = dwNext)
|
|
{
|
|
|
|
// BUGBUG: The following for loop is inside the outer for loop to
|
|
// decrease the likelihood of a race condition in which another thread in
|
|
// the multithreaded apartement creates a class entry while the Release
|
|
// routine is being called only to have the corresponding apartment entry deleted
|
|
// and even worse, the DLL unloaded out from under it.
|
|
|
|
for (dwClsent = _pDllPathEntries[dwDll]._dw1stClass;
|
|
dwClsent != NONE;
|
|
dwClsent = dwNextCls)
|
|
{
|
|
// Pickup the next class entry now in case we delete
|
|
// this class entry
|
|
dwNextCls = _pClassEntries[dwClsent]._dwNextDllCls;
|
|
|
|
// Remove this class entry if it's for this apartment
|
|
if (_pClassEntries[dwClsent]._hApt == hApt)
|
|
{
|
|
// Release the server
|
|
Release(dwClsent);
|
|
|
|
// In case another thread came in and invalidated dwNextCls
|
|
dwNextCls = _pClassEntries[dwClsent]._dwNextDllCls;
|
|
|
|
// Release the class entry
|
|
FreeClassEntry(dwClsent);
|
|
}
|
|
}
|
|
|
|
// Save the next apartment entry in case we delete this one
|
|
dwNext = _pDllPathEntries[dwDll]._pAptEntries[dwAptent]._dwNext;
|
|
|
|
// Only for the specified apartment
|
|
if (_pDllPathEntries[dwDll]._pAptEntries[dwAptent]._hApt == hApt)
|
|
{
|
|
HMODULE hDll =
|
|
_pDllPathEntries[dwDll]._pAptEntries[dwAptent]._hDll;
|
|
BOOL fSixteenBit = _pDllPathEntries[dwDll]._dwFlags & SIXTEEN_BIT;
|
|
|
|
// Free the library
|
|
if (fSixteenBit && IsWOWThread() && IsWOWThreadCallable() &&
|
|
!(_pDllPathEntries[dwDll]._dwFlags & IS_OLE32))
|
|
{
|
|
|
|
// Release the lock across the free library
|
|
// No need to worry about another thread coming in and attaching while
|
|
// the lock is released because that would only happen in the free threaded
|
|
// apartment, which cannot host 16-bit DLLs.
|
|
_mxs.Release();
|
|
g_pOleThunkWOW->UnloadProcDll((DWORD) hDll);
|
|
// Retake the lock
|
|
_mxs.Request();
|
|
|
|
// In case dwNext got invalidated
|
|
dwNext = _pDllPathEntries[dwDll]._pAptEntries[dwAptent]._dwNext;
|
|
}
|
|
|
|
// Remove the apartment entry
|
|
FreeAptEntry(dwDll, dwAptent);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
return _pDllPathEntries[dwDll]._nAptInUse != NONE;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDllCache::RemoveAndUnload
|
|
//
|
|
// Synopsis: Unload a dll
|
|
//
|
|
// Arguments: dwDll - This index of this dll path entry
|
|
//
|
|
// History: 07-Mar-95 BruceMa Created
|
|
//
|
|
// Notes: The dll has already said it can unload
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
void CDllCache::RemoveAndUnload(DWORD dwDll)
|
|
{
|
|
CairoleDebugOut((DEB_TRACE, "RemoveAndUnload " TSZFMT " dwDll:%x\n",
|
|
_pDllPathEntries[dwDll]._ptszPath, dwDll));
|
|
Win4Assert(_pDllPathEntries[dwDll]._nAptInUse == NONE && "Cannot unload dll with apartments attached.");
|
|
Win4Assert(_pDllPathEntries[dwDll]._dw1stClass == NONE && "Cannot unload dll with classes attached.");
|
|
|
|
// Invalidate this entry while holding the lock because we're going to
|
|
// unload the dll
|
|
_pDllPathEntries[dwDll]._dwSig = NULL;
|
|
|
|
// 32 bit libraries haven't been freed yet
|
|
if (!(_pDllPathEntries[dwDll]._dwFlags & SIXTEEN_BIT) &&
|
|
!IsWOWThread() &&
|
|
!(_pDllPathEntries[dwDll]._dwFlags & IS_OLE32) &&
|
|
_pDllPathEntries[dwDll]._hDll32)
|
|
{
|
|
_mxs.Release();
|
|
FreeLibrary(_pDllPathEntries[dwDll]._hDll32);
|
|
_mxs.Request();
|
|
}
|
|
|
|
// Delete the path
|
|
PrivMemFree(_pDllPathEntries[dwDll]._ptszPath);
|
|
_pDllPathEntries[dwDll]. _ptszPath = NULL;
|
|
|
|
|
|
delete _pDllPathEntries[dwDll]._pAptEntries;
|
|
_pDllPathEntries[dwDll]._pAptEntries = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDllCache::GetClass
|
|
//
|
|
// Synopsis: Get a class factory object for a class
|
|
//
|
|
// Arguments: [rclsid] Class ID
|
|
// [riid] Interface required of class object
|
|
// [fRemote] Whether path is remote
|
|
// [fForScm] Whether it's the scm requesting
|
|
//
|
|
// Returns: ~NULL - Class factory for object
|
|
// NULL - Class factory could not be found or
|
|
// constructed.
|
|
//
|
|
// History: 09-May-93 Ricksa Created
|
|
// 07-Mar-95 BruceMa Rewrote
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
HRESULT CDllCache::GetClass(REFCLSID rclsid,
|
|
REFIID riid,
|
|
BOOL fRemote,
|
|
BOOL fForSCM,
|
|
BOOL fSurrogate,
|
|
#ifdef WX86OLE
|
|
BOOL fWx86,
|
|
#endif
|
|
IUnknown **ppunk
|
|
)
|
|
{
|
|
TRACECALL(TRACE_DLL, "CDllCache::GetClass");
|
|
CairoleDebugOut((DEB_TRACE, "Get class\n"));
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
*ppunk = NULL;
|
|
|
|
// Single thread access to the table
|
|
COleStaticLock lck(_mxs);
|
|
|
|
// It's on behalf of the scm
|
|
if (fForSCM)
|
|
{
|
|
DWORD dwClsent;
|
|
|
|
// Note: On Chicago we are already on the thread that registered
|
|
// the class; RPC sees to this. On NT we are on the thread that
|
|
// registered the class because GetAptForCLSID() followed by
|
|
// GetToComThread() guarantees this.
|
|
//
|
|
// Search for the entry for this CLSID
|
|
dwClsent = Search(rclsid, CLSCTX_LOCAL_SERVER, GetCurrentApartmentId());
|
|
|
|
// Check if we have a registered class
|
|
if (dwClsent != NONE &&
|
|
!(_pClassEntries[dwClsent]._dwFlags & REGCLS_SUSPENDED))
|
|
{
|
|
if (_pClassEntries[dwClsent]._dwFlags == REGCLS_SINGLEUSE)
|
|
{
|
|
_pClassEntries[dwClsent]._dwContext = 0;
|
|
}
|
|
|
|
// Release the lock across outgoing call
|
|
IUnknown *pUnkTmp = _pClassEntries[dwClsent]._pUnk;
|
|
|
|
// Indicate we're in an outgoing call
|
|
_pClassEntries[dwClsent]._cCallOut++;
|
|
|
|
_mxs.Release();
|
|
// Since we are being called on behalf of SCM we know that
|
|
// we are being invoked remotely. Set the Wx86 stub invoked flag
|
|
// if we are calling into x86 code so that any custom interfaces
|
|
// can be thunked back and not rejected.
|
|
#ifdef WX86OLE
|
|
if (gcwx86.IsN2XProxy(pUnkTmp))
|
|
{
|
|
gcwx86.SetStubInvokeFlag(1);
|
|
}
|
|
#endif
|
|
hr = pUnkTmp->QueryInterface(fSurrogate ? IID_IClassFactory : riid,
|
|
(void **)ppunk);
|
|
|
|
_mxs.Request();
|
|
|
|
// We're no longer in an outgoing call
|
|
_pClassEntries[dwClsent]._cCallOut--;
|
|
|
|
// If a revoke came in while we were calling out then do the
|
|
// revoke now
|
|
if (_pClassEntries[dwClsent]._fRevokePending &&
|
|
_pClassEntries[dwClsent]._cCallOut == 0)
|
|
{
|
|
// Release our reference on the server
|
|
Release(dwClsent);
|
|
|
|
// Free the class entry
|
|
FreeClassEntry(dwClsent);
|
|
|
|
// Since the object has been released return failure
|
|
hr = CO_E_OBJNOTCONNECTED;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Else it's a local request
|
|
DWORD dwClsent;
|
|
|
|
// Search for the class
|
|
dwClsent = Search(rclsid,
|
|
#ifdef WX86OLE
|
|
fWx86 ? CLSCTX_INPROC_SERVERX86 | CLSCTX_INPROC_HANDLERX86 :
|
|
CLSCTX_INPROC,
|
|
#else
|
|
CLSCTX_INPROC,
|
|
#endif
|
|
GetCurrentApartmentId());
|
|
|
|
// Check if we found it
|
|
if (dwClsent != NONE)
|
|
{
|
|
// If the path is remote and we were launched AtStorage, then
|
|
// we need to be launched AtStorage again at the remote site, so
|
|
// fail locally
|
|
if (fRemote && _pClassEntries[dwClsent]._fAtStorage)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
// Check if it's a locally registered local server
|
|
if (_pClassEntries[dwClsent]._dwDllEnt == NONE)
|
|
{
|
|
if (_pClassEntries[dwClsent]._dwFlags == REGCLS_SINGLEUSE)
|
|
{
|
|
_pClassEntries[dwClsent]._dwContext = 0;
|
|
}
|
|
|
|
// Release the lock across outgoing call
|
|
IUnknown *pUnkTmp = _pClassEntries[dwClsent]._pUnk;
|
|
|
|
// Indicate we're in an outgoing call
|
|
_pClassEntries[dwClsent]._cCallOut++;
|
|
|
|
_mxs.Release();
|
|
|
|
hr = pUnkTmp->QueryInterface(fSurrogate ? IID_IClassFactory : riid,
|
|
(void **)ppunk);
|
|
_mxs.Request();
|
|
|
|
// We're no longer in an outgoing call
|
|
_pClassEntries[dwClsent]._cCallOut--;
|
|
|
|
// If a revoke came in while we were calling out then do the
|
|
// revoke now
|
|
if (_pClassEntries[dwClsent]._fRevokePending &&
|
|
_pClassEntries[dwClsent]._cCallOut == 0)
|
|
{
|
|
// Release our reference on the server
|
|
Release(dwClsent);
|
|
|
|
// Free the class entry
|
|
FreeClassEntry(dwClsent);
|
|
}
|
|
}
|
|
|
|
// Else it's a dll. Note - we could have AddRef'd the
|
|
// interface the first time we got it, when we created this
|
|
// class entry, but then there would be no way to know when
|
|
// to release it and therefore the dll could never unload. So
|
|
// instead we do the same as if we had just loaded the dll.
|
|
else
|
|
{
|
|
*ppunk = GetClassInterface(_pClassEntries[dwClsent]._dwDllEnt,
|
|
_pClassEntries[dwClsent]._dwDllThreadModel,
|
|
rclsid,
|
|
riid,
|
|
hr);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// It's ok to have no class factory in the cache, so return a success
|
|
// error code here.
|
|
//
|
|
Win4Assert( *ppunk == 0 );
|
|
return S_OK;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDllCache::GetOrLoadClass
|
|
//
|
|
// Synopsis: Get a class factory object for a class, loading an INPROC
|
|
// DLL if needed
|
|
//
|
|
// 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: 09-May-93 KevinRo
|
|
//
|
|
// Note:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
IUnknown *CDllCache::GetOrLoadClass(REFCLSID rclsid,
|
|
REFIID riid,
|
|
BOOL fRemote,
|
|
BOOL fForSCM,
|
|
#ifdef WX86OLE
|
|
BOOL fWx86,
|
|
#endif
|
|
DWORD dwContext,
|
|
DWORD dwCallerThreadModel,
|
|
HRESULT &hr)
|
|
{
|
|
CairoleDebugOut((DEB_ITRACE,
|
|
"CDllCache::GetOrLoadClass(clsid(%I),riid(%I),fRemote(%x),fForSCM(%x)"
|
|
",dwContext(%x),dwCallerThreadModel(%x))\n",
|
|
&rclsid,
|
|
&riid,
|
|
fRemote,
|
|
fForSCM,
|
|
dwContext,
|
|
dwCallerThreadModel));
|
|
|
|
IUnknown *punk = NULL;
|
|
|
|
hr = S_OK;
|
|
|
|
#ifndef GET_INPROC_FROM_SCM
|
|
// Just in case we chicken out and back out our changes
|
|
//
|
|
// The context should either be INPROC_HANDLER or INPROC_SERVER, but
|
|
// never both.
|
|
//
|
|
Win4Assert((dwContext & CLSCTX_INPROC_HANDLERS) || (dwContext & CLSCTX_INPROC_SERVERS));
|
|
Win4Assert(!!(dwContext & CLSCTX_INPROC_SERVERS) != !!(dwContext & CLSCTX_INPROC_HANDLERS));
|
|
#endif // GET_INPROC_FROM_SCM
|
|
|
|
//
|
|
// First, check to see if the class is available in the cache
|
|
// already. If it is, grab it and get out.
|
|
//
|
|
#ifdef WX86OLE
|
|
hr = GetClass(rclsid,riid,fRemote,fForSCM,FALSE,fWx86,&punk);
|
|
#else
|
|
hr = GetClass(rclsid,riid,fRemote,fForSCM,FALSE,&punk);
|
|
#endif
|
|
|
|
//
|
|
// If it is, then just return it
|
|
//
|
|
if (punk != NULL)
|
|
{
|
|
CairoleDebugOut((DEB_ITRACE,
|
|
"::GetOrLoadClass(clsid(%I)...) found class in cache",&rclsid));
|
|
return(punk);
|
|
}
|
|
|
|
#ifndef GET_INPROC_FROM_SCM
|
|
// Just in case we chicken out and back out our changes
|
|
//
|
|
// The CLSID wasn't found. Look it up
|
|
// in the registry and see if it exists. We follow a priority order
|
|
//
|
|
|
|
CairoleDebugOut((DEB_ITRACE,"::GetClass clsid(%I) not found. Try loading\n",&rclsid));
|
|
|
|
TCHAR achBuffer[80]; // Holds the string CLSID\{guid}\InprocServer|handler etc
|
|
|
|
memcpy(achBuffer,CLSIDBACK,CLSIDBACK_BYTE_LEN);
|
|
|
|
wStringFromGUID2T(rclsid,&achBuffer[CLSIDBACK_CHAR_LEN],GUIDSTR_MAX);
|
|
|
|
//
|
|
// achBuffer now has the string 'CLSID\{strofguid}'. This is the prefix string we
|
|
// need for doing the following code. Each bit of code below will stomp its own.
|
|
//
|
|
// Note that GUIDSTR_MAX is the number of characters including the NULL of the
|
|
// length of a GUID. We are going to manually append an additional slash to
|
|
// the string, which 'eats' the NULL character.
|
|
//
|
|
#define PREFIX_STRING_OFFSET (CLSIDBACK_CHAR_LEN + GUIDSTR_MAX )
|
|
|
|
achBuffer[PREFIX_STRING_OFFSET - 1] = '\\';
|
|
|
|
TCHAR achDllPath[MAX_PATH];
|
|
LONG clDllPath;
|
|
ULONG ulDllType;
|
|
LONG lErr;
|
|
|
|
//
|
|
// Assume it won't be found
|
|
//
|
|
hr = REGDB_E_CLASSNOTREG;
|
|
|
|
// If 16-bit has been requested and we find it, we'll return that
|
|
if (dwContext & CLSCTX_INPROC_SERVER16)
|
|
{
|
|
clDllPath = MAX_PATH;
|
|
memcpy(&achBuffer[PREFIX_STRING_OFFSET],tszInprocServer16,sizeof(tszInprocServer16));
|
|
|
|
CairoleAssert(punk == NULL);
|
|
hr = REGDB_E_CLASSNOTREG;
|
|
|
|
// Read 16 bit DLL information
|
|
if (wQueryStripRegValue(HKEY_CLASSES_ROOT,achBuffer,achDllPath,&clDllPath) == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// Found a 16-bit INPROC server. Add it to the cache.
|
|
//
|
|
#ifdef WX86OLE
|
|
punk = Add(rclsid,riid,APT_THREADED,achDllPath,TRUE,TRUE,FALSE,hr);
|
|
#else
|
|
punk = Add(rclsid,riid,APT_THREADED,achDllPath,TRUE,TRUE,hr);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
#ifdef WX86OLE
|
|
if ((punk == NULL) && (fWx86) && (dwContext & CLSCTX_INPROC_SERVERX86))
|
|
{
|
|
clDllPath = MAX_PATH;
|
|
memcpy(&achBuffer[PREFIX_STRING_OFFSET],tszInprocServerX86,sizeof(tszInprocServerX86));
|
|
|
|
hr = REGDB_E_CLASSNOTREG;
|
|
|
|
// Read 32 bit DLL information
|
|
if (wGetDllInfo(HKEY_CLASSES_ROOT,achBuffer,achDllPath,&clDllPath,&ulDllType) == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// If we are after a proxy/stub dll, then load it as both
|
|
// no matter what the DLL says.
|
|
//
|
|
if (dwContext & CLSCTX_PS_DLL)
|
|
{
|
|
ulDllType = BOTH_THREADED;
|
|
}
|
|
|
|
//
|
|
// If it turns out this path is for OLE32.DLL, then add the DLL without the
|
|
// path.
|
|
//
|
|
LPCTSTR pDllName = wCompareDllName(achDllPath,OLE32_DLL,OLE32_CHAR_LEN)?
|
|
OLE32_DLL:achDllPath;
|
|
|
|
//
|
|
// load it.
|
|
//
|
|
punk = Add(rclsid,riid,ulDllType,achDllPath,TRUE,FALSE,
|
|
!(pDllName == OLE32_DLL),hr);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Could be that we are trying to load an INPROC_SERVER
|
|
//
|
|
if ( (punk == NULL) && (dwContext & CLSCTX_INPROC_SERVER))
|
|
{
|
|
clDllPath = MAX_PATH;
|
|
|
|
//
|
|
// Need to reassign since it could have changed above
|
|
//
|
|
hr = REGDB_E_CLASSNOTREG;
|
|
|
|
memcpy(&achBuffer[PREFIX_STRING_OFFSET],tszInprocServer,sizeof(tszInprocServer));
|
|
|
|
// Read 32-bit DLL information
|
|
if (wGetDllInfo(HKEY_CLASSES_ROOT,achBuffer,achDllPath,&clDllPath,&ulDllType) == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// If we are after a proxy/stub dll, then load it as both
|
|
// no matter what the DLL says.
|
|
//
|
|
if (dwContext & CLSCTX_PS_DLL)
|
|
{
|
|
ulDllType = BOTH_THREADED;
|
|
}
|
|
//
|
|
// load it.
|
|
//
|
|
#ifdef WX86OLE
|
|
punk = Add(rclsid,riid,ulDllType,achDllPath,TRUE,FALSE,FALSE,hr);
|
|
#else
|
|
punk = Add(rclsid,riid,ulDllType,achDllPath,TRUE,FALSE,hr);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
//
|
|
// If INPROC_HANDLER16 set, then we look to load a 16-bit handler.
|
|
// If the handler is ole2.dll, then we will load ole32 instead.
|
|
// Otherwise we load the found 16bit dll but only if in a WOW thread.
|
|
//
|
|
if ((punk == NULL) && (dwContext & CLSCTX_INPROC_HANDLER16 ))
|
|
{
|
|
clDllPath = MAX_PATH;
|
|
|
|
memcpy(&achBuffer[PREFIX_STRING_OFFSET],tszInprocHandler16,sizeof(tszInprocHandler16));
|
|
|
|
lErr = wGetDllInfo(HKEY_CLASSES_ROOT,achBuffer,achDllPath,&clDllPath,&ulDllType);
|
|
|
|
//
|
|
// Need to reassign since it could have changed above
|
|
//
|
|
hr = REGDB_E_CLASSNOTREG;
|
|
|
|
if (lErr == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// If the inproc handler is ole2.dll, then subst
|
|
// ole32.dll instead
|
|
//
|
|
if (wCompareDllName(achDllPath,OLE2_DLL,OLE2_CHAR_LEN))
|
|
{
|
|
// Add and load OLE32.DLL
|
|
#ifdef WX86OLE
|
|
punk = Add(rclsid,riid,BOTH_THREADED,OLE32_DLL,TRUE,FALSE,FALSE,hr);
|
|
#else
|
|
punk = Add(rclsid,riid,BOTH_THREADED,OLE32_DLL,TRUE,FALSE,hr);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
// Otherwise, load the 16-bit fellow but only if in WOW thread
|
|
if (IsWOWThread())
|
|
{
|
|
#ifdef WX86OLE
|
|
punk = Add(rclsid,riid,ulDllType,achDllPath,TRUE,TRUE,FALSE,hr);
|
|
#else
|
|
punk = Add(rclsid,riid,ulDllType,achDllPath,TRUE,TRUE,hr);
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// See about 32-bit handlers. A was a change made after the
|
|
// Win95 (August release) and Windows/NT 3.51 release. Previously
|
|
// the code would give preference to loading 32-bit handlers. This
|
|
// means that even if an ISV provided both 16 and 32-bit handlers,
|
|
// the code would only attempt to provide the 32-bit handler. This
|
|
// was bad because servers with handlers could not be inserted into
|
|
// containers in the wrong model. We have fixed it here.
|
|
//
|
|
// Another thing to watch out for are applications that use our
|
|
// default handler. 16-bit applications can and should be able to
|
|
// use OLE32 has a handler. This will happen if the server app is
|
|
// actually a 32-bit.
|
|
//
|
|
//
|
|
#ifdef WX86OLE
|
|
if((punk == NULL) && (fWx86) && (dwContext & CLSCTX_INPROC_HANDLERX86))
|
|
{
|
|
clDllPath = MAX_PATH;
|
|
|
|
memcpy(&achBuffer[PREFIX_STRING_OFFSET],tszInprocHandlerX86,sizeof(tszInprocHandlerX86));
|
|
|
|
lErr = wGetDllInfo(HKEY_CLASSES_ROOT,achBuffer,achDllPath,&clDllPath,&ulDllType);
|
|
|
|
//
|
|
// Need to reassign since it could have changed above
|
|
//
|
|
hr = REGDB_E_CLASSNOTREG;
|
|
|
|
if (lErr == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// If it turns out this path is for OLE32.DLL, then add the DLL without the
|
|
// path.
|
|
//
|
|
LPCTSTR pDllName = wCompareDllName(achDllPath,OLE32_DLL,OLE32_CHAR_LEN)?
|
|
OLE32_DLL:achDllPath;
|
|
|
|
// Add a 32-bit handler to the pile.
|
|
punk = Add(rclsid,riid,ulDllType,pDllName,TRUE,FALSE,!(pDllName == ptszOle32DllName),hr);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if((punk == NULL) && (dwContext & CLSCTX_INPROC_HANDLERS))
|
|
{
|
|
clDllPath = MAX_PATH;
|
|
|
|
memcpy(&achBuffer[PREFIX_STRING_OFFSET],tszInprocHandler,sizeof(tszInprocHandler));
|
|
|
|
lErr = wGetDllInfo(HKEY_CLASSES_ROOT,achBuffer,achDllPath,&clDllPath,&ulDllType);
|
|
|
|
//
|
|
// Need to reassign since it could have changed above
|
|
//
|
|
hr = REGDB_E_CLASSNOTREG;
|
|
|
|
if (lErr == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// If it turns out this path is for OLE32.DLL, then add the DLL without the
|
|
// path.
|
|
//
|
|
LPCTSTR pDllName = wCompareDllName(achDllPath,OLE32_DLL,OLE32_CHAR_LEN)?
|
|
OLE32_DLL:achDllPath;
|
|
|
|
//
|
|
// If we are looking for a INPROC_HANDER16 and this is OLE32.DLL, or if we
|
|
// are looking for an INPROC_HANDLER, then load this path. Note that pDllName
|
|
// was set above.
|
|
//
|
|
// If we're in a Wow thread the only 32 bit DLL we're allowed to load is
|
|
// OLE32.DLL
|
|
if ((IsWOWThread() && (pDllName == OLE32_DLL)) ||
|
|
(!IsWOWThread() ))
|
|
{
|
|
// Add a 32-bit handler to the pile.
|
|
#ifdef WX86OLE
|
|
punk = Add(rclsid,riid,ulDllType,pDllName,TRUE,FALSE,FALSE,hr);
|
|
#else
|
|
punk = Add(rclsid,riid,ulDllType,pDllName,TRUE,FALSE,hr);
|
|
#endif
|
|
}
|
|
}
|
|
#ifdef WX86OLE
|
|
else if (gcwx86.IsWx86Installed() && (! gcwx86.IsWx86Enabled()))
|
|
{
|
|
// If Wx86 is installed on this system, but this is not a Wx86
|
|
// process and we could not find an InprocHandler32 we want to
|
|
// look for a InprocHandlerX86 in case an x86 local server is
|
|
// avaialable. If we find an InprocHandlerX86 and it is Ole32.dll
|
|
// then we will use it otherwise we can't since we assume it is
|
|
// an x86 dll.
|
|
clDllPath = MAX_PATH;
|
|
|
|
memcpy(&achBuffer[PREFIX_STRING_OFFSET],tszInprocHandlerX86,sizeof(tszInprocHandlerX86));
|
|
|
|
lErr = wGetDllInfo(HKEY_CLASSES_ROOT,achBuffer,achDllPath,&clDllPath,&ulDllType);
|
|
|
|
if (lErr == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// If it turns out this path is for OLE32.DLL, then add the DLL without the
|
|
// path.
|
|
//
|
|
BOOLEAN fIsOle32 = wCompareDllName(achDllPath,OLE32_DLL,OLE32_CHAR_LEN);
|
|
if (fIsOle32)
|
|
{
|
|
// Only if it is Ole32.Dll Add a 32-bit handler to native pile.
|
|
LPCTSTR pDllName = OLE32_DLL;
|
|
punk = Add(rclsid,riid,ulDllType,pDllName,TRUE,FALSE,FALSE,hr);
|
|
}
|
|
}
|
|
}
|
|
if (lErr != ERROR_SUCCESS)
|
|
#else
|
|
else
|
|
#endif
|
|
{
|
|
// We're here if we couldn't find a 32-bit handler. If non-Wow caller didn't
|
|
// explicitly request 16-bit handler we'll look for one here. But the only one
|
|
// allowed is OLE2.DLL => OLE32.DLL
|
|
if (!IsWOWThread() && !(dwContext & CLSCTX_INPROC_HANDLER16))
|
|
{
|
|
clDllPath = MAX_PATH;
|
|
|
|
memcpy(&achBuffer[PREFIX_STRING_OFFSET],tszInprocHandler16,sizeof(tszInprocHandler16));
|
|
|
|
lErr = wGetDllInfo(HKEY_CLASSES_ROOT,achBuffer,achDllPath,&clDllPath,&ulDllType);
|
|
|
|
//
|
|
// Need to reassign since it could have changed above
|
|
//
|
|
hr = REGDB_E_CLASSNOTREG;
|
|
|
|
if (lErr == ERROR_SUCCESS)
|
|
{
|
|
//
|
|
// If the inproc handler is ole2.dll, then subst
|
|
// ole32.dll instead
|
|
//
|
|
if (wCompareDllName(achDllPath,OLE2_DLL,OLE2_CHAR_LEN))
|
|
{
|
|
// Add and load OLE32.DLL
|
|
#ifdef WX86OLE
|
|
punk = Add(rclsid,riid,BOTH_THREADED,OLE32_DLL,TRUE,FALSE,FALSE,hr);
|
|
#else
|
|
punk = Add(rclsid,riid,BOTH_THREADED,OLE32_DLL,TRUE,FALSE,hr);
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return(punk);
|
|
#else // GET_INPROC_FROM_SCM
|
|
return NULL; // don't have it cached
|
|
#endif // GET_INPROC_FROM_SCM
|
|
}
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: CDllCache::GetClassObjForDde
|
|
//
|
|
// Synopsis: Get a class entry from the table for Dde, returning
|
|
// extra information, including the flags.
|
|
//
|
|
// Effects: The DdeServer needs the ability to query the class factory
|
|
// table to search for classes it needs to provide OLE 1.0
|
|
// support for. This routine will allow it to access the
|
|
// required information.
|
|
//
|
|
// Arguments: [clsid] Class to lookup ClassObject for
|
|
// [lpDdeInfo] Structure to fill in
|
|
//
|
|
// Returns: TRUE if the entry matched, FALSE if it did not.
|
|
//
|
|
// History: 5-28-94 kevinro Created
|
|
// 07-Mar-95 BruceMa Rewrote
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL CDllCache::GetClassObjForDde(REFCLSID clsid,
|
|
LPDDECLASSINFO lpDdeInfo)
|
|
{
|
|
TRACECALL(TRACE_DLL, "CDllCache::GetClassObjForDde");
|
|
|
|
CairoleDebugOut((DEB_TRACE, "Get class object for DDE\n"));
|
|
|
|
// Single thread access to the table
|
|
COleStaticLock lck(_mxs);
|
|
|
|
Win4Assert(IsValidPtrOut(lpDdeInfo, sizeof(DWORD)) &&
|
|
"CDllCache::GetClassObjForDde invalid out parameter");
|
|
|
|
DWORD dwClsent = Search(clsid, CLSCTX_LOCAL_SERVER, GetCurrentApartmentId());
|
|
|
|
if (dwClsent != NONE)
|
|
{
|
|
return GetClassObjForDdeByClsent(dwClsent, lpDdeInfo);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CDllCache::GetClassInformationFromKey
|
|
//
|
|
// Synopsis: Get class object information for the Dde server using a key
|
|
//
|
|
// Effects: This routine is called by the DDE server code to retrieve the
|
|
// class information for a specific class registration. The
|
|
// theory is that the DDE server window has already called
|
|
// GetClassInformationForDde. Some time X has passed, and the
|
|
// server has a request for the specific class registration.
|
|
//
|
|
// This routine allows the DDE server to request current
|
|
// class information by specific registration key.
|
|
//
|
|
// Arguments: [lpDdeInfo] Structure to fill in with information
|
|
//
|
|
// Requires: lpDdeInfo->dwRegistrationKey is the key to the specific
|
|
// class being asked for.
|
|
//
|
|
// Returns: TRUE Structure filled in with appropriate information
|
|
// FALSE The registration is no longer valid.
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: 5-28-94 kevinro Created
|
|
// 07-Mar-95 BruceMa Rewrote
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL CDllCache::GetClassInformationFromKey(LPDDECLASSINFO lpDdeInfo)
|
|
{
|
|
TRACECALL(TRACE_DLL, "CDllCache::GetClassInformationFromKey");
|
|
|
|
CairoleDebugOut((DEB_TRACE, "Get class inbfo from key for DDE\n"));
|
|
|
|
// Single thread access to the table
|
|
COleStaticLock lck(_mxs);
|
|
|
|
DWORD dwClsent = Search(lpDdeInfo->dwRegistrationKey, GetCurrentApartmentId());
|
|
|
|
if (dwClsent != NONE)
|
|
{
|
|
return GetClassObjForDdeByClsent(dwClsent, lpDdeInfo);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef _CHICAGO_
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDllCache::GetApartmentForCLSID
|
|
//
|
|
// Synopsis: Get the apartment id for this clsid
|
|
//
|
|
// Arguments: [rclsid] class ID
|
|
// [hApt] Where to return the apartment id
|
|
//
|
|
// Returns: TRUE Got the apartment id for an available class object
|
|
// FALSE No available class object for given class
|
|
//
|
|
// History: 30-Apr-93 JohannP Created
|
|
// 07-Mar-95 BruceMa Rewrote
|
|
// 06-Oct-95 BruceMa Make for Chicago only
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
inline BOOL CDllCache::GetApartmentForCLSID(REFCLSID rclsid, HAPT &hApt)
|
|
{
|
|
|
|
CairoleDebugOut((DEB_TRACE, "Get apartment for CLSID\n"));
|
|
|
|
// On Chicago we are already on the correct thread
|
|
hApt = GetCurrentApartmentId();
|
|
return TRUE;
|
|
}
|
|
#endif // _CHICAGO_
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDllCache::Add
|
|
//
|
|
// Synopsis: Add a DLL entry to the cache
|
|
//
|
|
// Arguments: [rclsid] - class id
|
|
// [riid] - interface required of the class object
|
|
// [ptszDllPath] - path to DLL
|
|
// [fGetClassObject] - whether class factory object is needed.
|
|
// [fSixteenBit] - TRUE if we want the 16bit dll
|
|
// [fWx86] - TRUE if x86 dll in Wx86 process
|
|
// [hr] - hresult returned
|
|
//
|
|
// Returns: Pointer to class factory if requested.
|
|
//
|
|
// Algorithm: Create a path key. If such a DLL is already cached, use
|
|
// that otherwise create a new DLL path entry. Then add
|
|
// a new class object.
|
|
//
|
|
// History: 09-May-93 Ricksa Created
|
|
// 28-Jun-94 BruceMa Memory SIFT fixes
|
|
// 07-Jul-94 BruceMa Memory SIFT fixes
|
|
// 21-Nov-94 BruceMa Don't return E_OUTOFMEMORY if can't find
|
|
// dll
|
|
// 07-Mar-95 BruceMa Rewrote
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
IUnknown *CDllCache::Add(REFCLSID rclsid,
|
|
REFIID riid,
|
|
DWORD dwDllThreadModel,
|
|
const TCHAR *ptszDllPath,
|
|
BOOL fGetClassObject,
|
|
BOOL fSixteenBit,
|
|
#ifdef WX86OLE
|
|
BOOL fWx86,
|
|
#endif
|
|
HRESULT& hr)
|
|
{
|
|
TRACECALL(TRACE_DLL, "CDllCache::Add");
|
|
CairoleDebugOut((DEB_TRACE, "Add dll %ts to cache\n", ptszDllPath));
|
|
|
|
hr = E_FAIL;
|
|
|
|
IUnknown *punk = NULL;
|
|
|
|
// Single thread access to the table
|
|
COleStaticLock lck(_mxs);
|
|
|
|
// This better be a valid dll path
|
|
if (ptszDllPath != NULL)
|
|
{
|
|
LPFNGETCLASSOBJECT pfnGetClassObject;
|
|
DLLUNLOADFNP pfnDllCanUnload;
|
|
HMODULE hDll;
|
|
|
|
#ifdef WX86OLE
|
|
BOOL fIsX86Dll = FALSE;
|
|
#endif
|
|
|
|
// Check if we already have an entry for this dll
|
|
DWORD dwDllent = SearchForDll(ptszDllPath
|
|
#ifdef WX86OLE
|
|
, fWx86
|
|
#endif
|
|
);
|
|
// If not, create a new dll path entry
|
|
if (dwDllent == NONE)
|
|
{
|
|
// Check if this is "OLE32.DLL" - we don't need to load
|
|
// ourselves; we're already running
|
|
if (lstrcmp(ptszDllPath, ptszOle32DllName)
|
|
!= 0)
|
|
{
|
|
// We need to release the lock across the LoadLibrary since
|
|
// there is a chance that an exiting thread waits on our
|
|
// mutext to CleanUpForApartment while we wait on the kernel
|
|
// mutex which the exiting thread owns, causing a deadlock.
|
|
_mxs.Release();
|
|
|
|
// Load the library
|
|
hr = Load(ptszDllPath,
|
|
&pfnGetClassObject,
|
|
&pfnDllCanUnload,
|
|
fSixteenBit,
|
|
&hDll
|
|
#ifdef WX86OLE
|
|
,&fIsX86Dll,
|
|
fWx86
|
|
#endif
|
|
);
|
|
|
|
// Retake the lock while intializng the dll entry
|
|
_mxs.Request();
|
|
|
|
// Check for success
|
|
if (FAILED(hr))
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
// Check whether another thread got in and loaded the dll
|
|
dwDllent = SearchForDll(ptszDllPath
|
|
#ifdef WX86OLE
|
|
, fWx86
|
|
#endif
|
|
);
|
|
|
|
// If so, then use that
|
|
if (dwDllent != NONE)
|
|
{
|
|
// Make it valid for this apartment
|
|
if (FAILED(MakeValidInApartment(dwDllent)))
|
|
{
|
|
return NULL;
|
|
}
|
|
_mxs.Release();
|
|
FreeLibrary(hDll);
|
|
_mxs.Request();
|
|
}
|
|
|
|
// Else create a new dll entry
|
|
else
|
|
{
|
|
// Allocate a dll path entry
|
|
dwDllent = AllocDllPathEntry();
|
|
if (dwDllent == NONE)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
return NULL;
|
|
}
|
|
|
|
// Initialize the dll path entry (this will load the dll)
|
|
hr = CreateDllent(dwDllent,
|
|
ptszDllPath,
|
|
fSixteenBit,
|
|
pfnGetClassObject,
|
|
pfnDllCanUnload,
|
|
hDll
|
|
#ifdef WX86OLE
|
|
,fIsX86Dll,
|
|
fWx86
|
|
#endif
|
|
);
|
|
if (FAILED(hr))
|
|
{
|
|
FreeDllPathEntry(dwDllent);
|
|
return NULL;
|
|
}
|
|
|
|
_pDllPathEntries[dwDllent]._dw1stClass = NONE;
|
|
|
|
// Make it valid for this apartment
|
|
if (FAILED(MakeValidInApartment(dwDllent)))
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
CairoleAssert(dwDllent != NONE);
|
|
|
|
|
|
// Get requested interface
|
|
punk = GetClassInterface(dwDllent,
|
|
dwDllThreadModel,
|
|
rclsid,
|
|
riid,
|
|
hr);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// Add a class entry for this interface if we don't already
|
|
// have one
|
|
|
|
// search according to type of dll as passed into thus func
|
|
if (Search(rclsid,
|
|
#ifdef WX86OLE
|
|
fWx86 ? CLSCTX_INPROC_SERVERX86 :
|
|
#endif
|
|
CLSCTX_INPROC_SERVER,
|
|
GetCurrentApartmentId()) == NONE)
|
|
{
|
|
DWORD dwClsent = AllocClassEntry();
|
|
if (dwClsent == NONE)
|
|
{
|
|
return NULL;
|
|
}
|
|
CreateClsentInProc(dwClsent,
|
|
dwDllent,
|
|
dwDllThreadModel,
|
|
_pDllPathEntries[dwDllent]._dw1stClass,
|
|
rclsid
|
|
#ifdef WX86OLE
|
|
,fWx86
|
|
#endif
|
|
);
|
|
_pDllPathEntries[dwDllent]._dw1stClass = dwClsent;
|
|
}
|
|
|
|
return punk;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDllCache::FreeUnused
|
|
//
|
|
// Synopsis: Free any unused DLLs
|
|
//
|
|
// Algorithm: For each DLL in the list of DLLs call its Dll can unload
|
|
// now entry point.
|
|
//
|
|
// History: 09-May-93 Ricksa Created
|
|
// 04-May-94 AlexT Only free DLL if it returns S_OK!
|
|
// 07-Mar-95 BruceMa Rewrote
|
|
//
|
|
//
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
void CDllCache::FreeUnused(void)
|
|
{
|
|
TRACECALL(TRACE_DLL, "CDllCache::FreeUnused");
|
|
|
|
CairoleDebugOut((DEB_TRACE, "Free unused dll's\n"));
|
|
|
|
// Single thread access to the table
|
|
COleStaticLock lck(_mxs);
|
|
|
|
// Unless the code is changed, we should not be here in the Wow case
|
|
CairoleAssert(!IsWOWProcess() && "Freeing unused libraries in WOW");
|
|
|
|
// Free any loaded dll's (only if we still have a cache)
|
|
if (_pDllPathEntries)
|
|
{
|
|
// Sequentially scan the list of loaded dll's, unloading where we can
|
|
DWORD dwNext;
|
|
|
|
for (DWORD dwDllent = _nDllPathEntryInUse;
|
|
dwDllent != NONE;
|
|
dwDllent = dwNext)
|
|
{
|
|
// Save the next entry in case we free this one
|
|
dwNext = _pDllPathEntries[dwDllent]._dwNext;
|
|
|
|
// Check if we can unload this dll
|
|
if (CanUnloadNow(dwDllent) == S_OK)
|
|
{
|
|
// remove our apartment from the dll
|
|
BOOL fRemove = !CleanUpForApartmentByDllent(dwDllent, GetCurrentApartmentId());
|
|
|
|
// get the next entry again in case we Released the lock
|
|
// in the above routine
|
|
dwNext = _pDllPathEntries[dwDllent]._dwNext;
|
|
|
|
if (fRemove)
|
|
{
|
|
RemoveAndUnload(dwDllent);
|
|
FreeDllPathEntry(dwDllent);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDllCache::RegisterServer
|
|
//
|
|
// Synopsis: Register a class factory
|
|
//
|
|
// Arguments: [rclsid] - class ID
|
|
// [punk] - class factory instance ptr
|
|
// [flags] - type of factory instance
|
|
//
|
|
// Returns: Registration key
|
|
//
|
|
// Algorithm: Create a class entry and then add server to list of
|
|
// registered servers.
|
|
//
|
|
// History: 09-May-93 Ricksa Created
|
|
// 07-Mar-95 BruceMa Rewrote
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
HRESULT CDllCache::RegisterServer(REFCLSID rclsid,
|
|
IUnknown *punk,
|
|
DWORD dwFlags,
|
|
DWORD dwContext,
|
|
LPDWORD lpdwRegister)
|
|
{
|
|
CairoleDebugOut((DEB_TRACE, "Register server\n"));
|
|
TRACECALL(TRACE_DLL, "CDllCache::RegisterServer");
|
|
|
|
HRESULT hr = E_OUTOFMEMORY;
|
|
|
|
// Take a reference immediately (if we fail for any reason we
|
|
// Release it below)
|
|
punk->AddRef();
|
|
|
|
{
|
|
// scoped single thread access to the table
|
|
COleStaticLock lck(_mxs);
|
|
|
|
// Allocate a new class entry
|
|
DWORD dwClsent = AllocClassEntry();
|
|
if (dwClsent != NONE)
|
|
{
|
|
// Formulate a unique registration key for this class entry
|
|
DWORD dwReg = (GetCurrentApartmentId()) << 16 | dwClsent;
|
|
|
|
// Initialize it
|
|
hr = CreateClsentLSvr(dwClsent,
|
|
rclsid,
|
|
punk,
|
|
dwFlags,
|
|
dwContext,
|
|
dwReg);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
*lpdwRegister = dwReg;
|
|
}
|
|
else
|
|
{
|
|
FreeClassEntry(dwClsent);
|
|
}
|
|
}
|
|
}
|
|
|
|
// If we failed we release our reference. This is done outside the
|
|
// scope of the lock.
|
|
if (FAILED(hr))
|
|
{
|
|
punk->Release();
|
|
}
|
|
|
|
return(hr);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDllCache::Revoke
|
|
//
|
|
// Synopsis: Revoke the registration of a previously registered
|
|
// class object.
|
|
//
|
|
// Arguments: [dwRegister] - registration key
|
|
//
|
|
// Returns: TRUE - remote objects have been deregistered.
|
|
// FALSE - remote objects were not deregistered.
|
|
//
|
|
// Algorithm: First validate the registration key. If objects have
|
|
// been revoked already we will always say TRUE. Then if
|
|
// the object is remote, revoke this list of remote objects.
|
|
// For local objects we just revoke the single entry.
|
|
//
|
|
// Note: dwRegistry has the form aptId << 16 + CClassEntry index
|
|
//
|
|
// History: 09-May-93 Ricksa Created
|
|
// 01-Jul-94 AlexT Don't call out while holding mutex
|
|
// 13-Feb-95 BruceMa Change registration/revocation logic
|
|
// 07-Mar-95 BruceMa Rewrote
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
HRESULT CDllCache::Revoke(DWORD dwRegister)
|
|
{
|
|
IUnknown *pUnk;
|
|
|
|
TRACECALL(TRACE_DLL, "CDllCache::Revoke");
|
|
|
|
CairoleDebugOut((DEB_TRACE, "Revokeclass object %x\n", dwRegister));
|
|
|
|
// Single thread access to the table
|
|
COleStaticLock lck(_mxs);
|
|
|
|
DWORD dwClsent = dwRegister & 0xffff;
|
|
|
|
|
|
// There is case where an app calls CoRevoke from CoDisconnectObject which
|
|
// we call from Release - so guard against this recursive behavior
|
|
if (_pClassEntries[dwClsent]._fRevoking)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
// Make sure the registration key contains an index to a valid
|
|
// in use class entry and that the class entry is still valid
|
|
if (!(0 <= dwClsent &&
|
|
dwClsent < _cClassEntries &&
|
|
_pClassEntries[dwClsent]._dwSig == CLASS_CACHE_SIG))
|
|
{
|
|
CairoleAssert("CDllCache::Revoke Invalid registration key");
|
|
return CO_E_OBJNOTREG;
|
|
}
|
|
|
|
// Make sure apartment id's match if we're not free threaded
|
|
DWORD dwRegAptId = (dwRegister >> 16) & 0xffff; // Chicago has
|
|
// negative tid's
|
|
HAPT hCurrApt = GetCurrentApartmentId();
|
|
|
|
if (!(dwRegAptId == (hCurrApt & 0xffff) &&
|
|
hCurrApt == _pClassEntries[dwClsent]._hApt))
|
|
{
|
|
CairoleDebugOut((DEB_ERROR,
|
|
"CDllCache::Revoke %x: Wrong thread attempting to revoke\n", dwRegister));
|
|
return RPC_E_WRONG_THREAD;
|
|
}
|
|
|
|
// If there is an active outgoing call on another thread, then let
|
|
// that thread do the revoke
|
|
if (_pClassEntries[dwClsent]._cCallOut > 0)
|
|
{
|
|
_pClassEntries[dwClsent]._fRevokePending = TRUE;
|
|
return S_OK;
|
|
}
|
|
|
|
// Release our reference on the server
|
|
_pClassEntries[dwClsent]._fRevoking = TRUE;
|
|
Release(dwClsent);
|
|
|
|
// Free the class entry
|
|
FreeClassEntry(dwClsent);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDllCache::AddRefServerProcess
|
|
//
|
|
// Synopsis: increments the reference count on the server process
|
|
//
|
|
// Notes: CoAddRefServerProcess and CoReleaseServerProcess are used
|
|
// by the applications object instances and LockServer
|
|
// implementation in order to control the lifetime of the server
|
|
// process.
|
|
//
|
|
// When a new object instance is created, and when class object's
|
|
// LockServer(TRUE) method is called, applications should call
|
|
// CoAddRefServerProcess. When an object instance's reference
|
|
// count reaches zero, and when the class object's
|
|
// LockServer(FALSE) method is called, applications should call
|
|
// CoReleaseServerProcess.
|
|
//
|
|
// When the server's global reference count reaches zero, all
|
|
// externaly registered class objects are automatically
|
|
// suspended, allowing the server to shutdown in a thread-safe
|
|
// manner.
|
|
//
|
|
// History: 17-Apr-96 Rickhi Created
|
|
//
|
|
//+-------------------------------------------------------------------------
|
|
ULONG CDllCache::AddRefServerProcess(void)
|
|
{
|
|
COleStaticLock lck(_mxs);
|
|
return ++_cRefsServerProcess;
|
|
}
|
|
|
|
ULONG CDllCache::ReleaseServerProcess(void)
|
|
{
|
|
COleStaticLock lck(_mxs);
|
|
|
|
ULONG cRefs = --_cRefsServerProcess;
|
|
if (cRefs == 0)
|
|
{
|
|
HRESULT hr = SuspendProcessClassObjects();
|
|
Win4Assert(hr == S_OK);
|
|
}
|
|
return cRefs;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDllCache::SuspendProcessClassObjects
|
|
//
|
|
// Synopsis: Marks all the externally registered class objects in this
|
|
// process as suspended, so that no new activation requests
|
|
// from the SCM will be honoured.
|
|
//
|
|
// Notes: See AddRefServerProcess and ReleaseServerProcess above.
|
|
//
|
|
// History: 17-Apr-96 Rickhi Created
|
|
//
|
|
//+-------------------------------------------------------------------------
|
|
HRESULT CDllCache::SuspendProcessClassObjects(void)
|
|
{
|
|
CairoleDebugOut((DEB_ACTIVATE, "SuspendProcessClassObjects\n"));
|
|
COleStaticLock lck(_mxs);
|
|
|
|
// walk the list of class entries, and for any that are registered as
|
|
// local servers, mark them as suspended.
|
|
|
|
for (int k = _nClassEntryInUse; k != NONE; k = _pClassEntries[k]._dwNext)
|
|
{
|
|
if (_pClassEntries[k]._dwContext & CLSCTX_LOCAL_SERVER)
|
|
{
|
|
_pClassEntries[k]._dwFlags |= REGCLS_SUSPENDED;
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDllCache::ResumeProcessClassObjects
|
|
//
|
|
// Synopsis: Marks all the externally registered class objects in this
|
|
// process as available, so that new activation requests from
|
|
// the SCM will be honoured. This also notifies the SCM about
|
|
// any class objects that have been registered suspended.
|
|
//
|
|
// Notes: See SuspendProcessClassObjects above.
|
|
//
|
|
// History: 17-Apr-96 Rickhi Created
|
|
//
|
|
//+-------------------------------------------------------------------------
|
|
HRESULT CDllCache::ResumeProcessClassObjects(void)
|
|
{
|
|
CairoleDebugOut((DEB_ACTIVATE, "ResumeProcessClassObjects\n"));
|
|
|
|
HRESULT hr = S_OK;
|
|
COleStaticLock lck(_mxs);
|
|
|
|
// if none in use, exit early, otherwise _nClassEntryInUse == -1 and
|
|
// we try to allocate a huge amount of stack space.
|
|
|
|
if (_nClassEntryInUse == NONE)
|
|
return hr;
|
|
|
|
// allocate a block of memory on the stack, large enough to hold the
|
|
// maximum number of entries we may have to register with the SCM.
|
|
|
|
ULONG cbAlloc = sizeof(RegInput) +
|
|
((sizeof(RegInputEntry) + sizeof(DWORD))*
|
|
_nClassEntryInUse);
|
|
|
|
RegInput *pRegIn = (RegInput*) _alloca(cbAlloc);
|
|
RegInputEntry *pRegEnt = &pRegIn->rginent[0];
|
|
DWORD *pRegIndex = (DWORD *)(&pRegIn->rginent[_nClassEntryInUse+1]);
|
|
ULONG cToReg = 0;
|
|
|
|
|
|
// walk the list of class entries, and for any that are registered as
|
|
// local servers and marked suspended, mark them as available and
|
|
// notify the SCM about them.
|
|
|
|
for (int k = _nClassEntryInUse; k != NONE; k = _pClassEntries[k]._dwNext)
|
|
{
|
|
if ((_pClassEntries[k]._dwFlags & REGCLS_SUSPENDED) &&
|
|
(_pClassEntries[k]._dwScmReg == NONE))
|
|
{
|
|
// must be for a local server
|
|
Win4Assert(_pClassEntries[k]._dwContext & CLSCTX_LOCAL_SERVER);
|
|
Win4Assert(_pClassEntries[k]._pObjServer != NULL);
|
|
|
|
// turn off the suspended flag for this clsid.
|
|
_pClassEntries[k]._dwFlags &= ~REGCLS_SUSPENDED;
|
|
|
|
// add to the list to tell the SCM about
|
|
pRegEnt->clsid = _pClassEntries[k]._clsid;
|
|
pRegEnt->dwFlags = _pClassEntries[k]._dwFlags;
|
|
pRegEnt->oxid = _pClassEntries[k]._pObjServer->GetOXID();
|
|
pRegEnt->ipid = _pClassEntries[k]._pObjServer->GetIPID();
|
|
pRegEnt++;
|
|
|
|
*pRegIndex = k; // remember the index of this entry
|
|
pRegIndex++; // so we can update it below.
|
|
|
|
cToReg++;
|
|
}
|
|
}
|
|
|
|
// reset the pointers we mucked with in the loop above, and set the
|
|
// total number of entries we are passing to the SCM.
|
|
|
|
pRegIn->dwSize = cToReg;
|
|
pRegEnt = &pRegIn->rginent[0];
|
|
pRegIndex = (DWORD *)(&pRegIn->rginent[_nClassEntryInUse+1]);
|
|
|
|
|
|
// call the SCM to register all the classes and get back all the
|
|
// registration keys.
|
|
|
|
RegOutput *pRegOut = NULL;
|
|
_mxs.Release();
|
|
hr = gResolver.NotifyStarted(pRegIn, &pRegOut);
|
|
_mxs.Request();
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
Win4Assert((pRegOut->dwSize == pRegIn->dwSize) &&
|
|
"CRpcResolver::NotifyStarted Invalid regout");
|
|
|
|
// update the entries with the registration keys from the SCM.
|
|
for (ULONG i = 0; i < cToReg; i++)
|
|
{
|
|
k = *pRegIndex;
|
|
pRegIndex++;
|
|
|
|
_pClassEntries[k]._fAtStorage = pRegOut->regoutent[0].dwAtStorage;
|
|
_pClassEntries[k]._dwScmReg = pRegOut->regoutent[0].dwReg;
|
|
}
|
|
|
|
// Free memory from RPC
|
|
MIDL_user_free(pRegOut);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CDllCache::SetDdeServerWindow
|
|
//
|
|
// Synopsis: Finds the registration associated with dwKey, and sets the
|
|
// HWND for the DDE server.
|
|
//
|
|
// Effects: Part of the shutdown of a class object involves telling the
|
|
// DDE server to stop servicing requests for the class. The
|
|
// communication mechanism used between the DDE server and
|
|
// the Class Registration Table is a window handle.
|
|
//
|
|
// During the initial creation of the DDE server window, we
|
|
// don't know what the window handle is going to be. This
|
|
// routine allows us to set the window handle into the table,
|
|
// so we can be called back.
|
|
//
|
|
// It is also possible that the Server Window may go away
|
|
// before the class object is revoked. This routine is also
|
|
// called in that case to set the hwnd to NULL.
|
|
//
|
|
// Arguments: [dwKey] -- Key for the registration
|
|
// [hwndDdeServer] -- Window handle to Dde Server
|
|
//
|
|
// Returns: TRUE if call was successful.
|
|
// FALSE if the dwKey was not valid.
|
|
//
|
|
// History: 7-05-94 kevinro Created
|
|
// 07-Mar-95 BruceMa Rewrote
|
|
//
|
|
// Notes:
|
|
//
|
|
// This is part of the DDE server support. The code that calls it is
|
|
// in com\remote\dde\server
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL CDllCache::SetDdeServerWindow(DWORD dwKey, HWND hwndDdeServer)
|
|
{
|
|
TRACECALL(TRACE_DLL, "CDllCache::SetDdeServer");
|
|
|
|
CairoleDebugOut((DEB_TRACE, "Set DDE server window\n"));
|
|
|
|
// Single thread access to the table
|
|
COleStaticLock lck(_mxs);
|
|
|
|
Win4Assert(dwKey != 0);
|
|
Win4Assert((hwndDdeServer == NULL) || IsWindow(hwndDdeServer));
|
|
|
|
// Search for the class entry
|
|
DWORD dwClsent = Search(dwKey, GetCurrentApartmentId());
|
|
|
|
// Found it
|
|
if (dwClsent != NONE)
|
|
{
|
|
_pClassEntries[dwClsent]._hWndDdeServer = hwndDdeServer;
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDllCache::CleanUpLocalServersForApartment
|
|
//
|
|
// Synopsis: Clean up any registered local servers for the current apartment
|
|
//
|
|
// Algorithm: Delete internal objects
|
|
//
|
|
// History: 02-Feb-94 Ricksa Created
|
|
// 07-Mar-95 BruceMa Rewrote
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
void CDllCache::CleanUpLocalServersForApartment(void)
|
|
{
|
|
// Single thread access to the tables
|
|
COleStaticLock lck(_mxs);
|
|
|
|
// It is possible for the entries to be NULL if CoInitializeEx fails.
|
|
if (_pClassEntries)
|
|
{
|
|
HAPT hApt = GetCurrentApartmentId();
|
|
DWORD dwNext;
|
|
|
|
for (DWORD dwClsent = _nClassEntryInUse; dwClsent != NONE;
|
|
dwClsent = dwNext)
|
|
{
|
|
// Get the next entry in case we release this one
|
|
dwNext = _pClassEntries[dwClsent]._dwNext;
|
|
|
|
// Check whether it's valid and for this apartment
|
|
// Only release if it was for a local server. If it is for
|
|
// a Dll it will get released later, either when the Dll
|
|
// is unloaded or at CoUninitialize
|
|
|
|
if (_pClassEntries[dwClsent]._dwSig == CLASS_CACHE_SIG &&
|
|
_pClassEntries[dwClsent]._hApt == hApt &&
|
|
_pClassEntries[dwClsent]._dwDllEnt == NONE)
|
|
{
|
|
// Let the developer know that they're missing a Revoke
|
|
CairoleDebugOut((DEB_ERROR,
|
|
"Missing revoke on pClassFactory=%lx (%I)\n",
|
|
_pClassEntries[dwClsent]._pUnk,
|
|
&(_pClassEntries[dwClsent]._clsid)));
|
|
|
|
// Release the server
|
|
Release(dwClsent);
|
|
|
|
// In case dwNext got invalidated
|
|
dwNext = _pClassEntries[dwClsent]._dwNext;
|
|
|
|
// Release the class entry
|
|
FreeClassEntry(dwClsent);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDllCache::CleanUpDllsForApartment
|
|
//
|
|
// Synopsis: Clean up any class information for the current apartment
|
|
//
|
|
// Algorithm: Delete internal objects
|
|
//
|
|
// History: 02-Feb-94 Ricksa Created
|
|
// 07-Mar-95 BruceMa Rewrote
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
void CDllCache::CleanUpDllsForApartment(void)
|
|
{
|
|
// Release all the DLL objects associated with
|
|
// this apartment
|
|
|
|
HAPT hApt = GetCurrentApartmentId();
|
|
|
|
// Single thread access to the tables
|
|
COleStaticLock lck(_mxs);
|
|
|
|
if (_pDllPathEntries)
|
|
{
|
|
DWORD dwNext;
|
|
BOOL fMore;
|
|
|
|
for (DWORD dwDllent = _nDllPathEntryInUse; dwDllent != NONE;
|
|
dwDllent = dwNext)
|
|
{
|
|
// Save the next entry in case we delete this one
|
|
dwNext = _pDllPathEntries[dwDllent]._dwNext;
|
|
|
|
if (IsValidInApartment(dwDllent, hApt))
|
|
{
|
|
// Clean up this entry for this apartment
|
|
BOOL fRemove = !CleanUpForApartmentByDllent(dwDllent, hApt);
|
|
|
|
// In case dwNext got invalidated
|
|
dwNext = _pDllPathEntries[dwDllent]._dwNext;
|
|
|
|
if (fRemove)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
if (!IsWOWProcess())
|
|
{
|
|
_mxs.Release();
|
|
hr = CanUnloadNow(dwDllent);
|
|
_mxs.Request();
|
|
}
|
|
|
|
if ((hr == S_OK) && (_pDllPathEntries[dwDllent]._nAptInUse == NONE))
|
|
{
|
|
// Delete the dll entry if no more apartments are using it
|
|
// *and* the Dll says it's OK.
|
|
RemoveAndUnload(dwDllent);
|
|
FreeDllPathEntry(dwDllent);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDllCache::CleanUpDllsForProcess
|
|
//
|
|
// Synopsis: Clean up any remaining cache allocations
|
|
//
|
|
// Algorithm: Delete internal objects
|
|
//
|
|
// History: 02-Feb-94 Ricksa Created
|
|
// 07-Mar-95 BruceMa Rewrote
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
void CDllCache::CleanUpDllsForProcess(void)
|
|
{
|
|
CairoleDebugOut((DEB_TRACE, "Clean up Dll class cache for process\n"));
|
|
|
|
// Single thread
|
|
COleStaticLock lck(_mxs);
|
|
|
|
// In case CoInitialize failed
|
|
if (_pDllPathEntries)
|
|
{
|
|
// Delete the dll path entries. This is explicit because there
|
|
// are apartment entries to clean up. (Note - this must be done
|
|
// first because there are class entries associated with a dll.)
|
|
while (_nDllPathEntryInUse != NONE)
|
|
{
|
|
DWORD dwApt;
|
|
|
|
for(dwApt = _pDllPathEntries[_nDllPathEntryInUse]._nAptInUse;
|
|
dwApt != NONE;
|
|
dwApt = _pDllPathEntries[_nDllPathEntryInUse]._nAptInUse)
|
|
{
|
|
CleanUpForApartmentByDllent(_nDllPathEntryInUse,
|
|
_pDllPathEntries[_nDllPathEntryInUse]._pAptEntries[dwApt]._hApt );
|
|
}
|
|
RemoveAndUnload(_nDllPathEntryInUse);
|
|
FreeDllPathEntry(_nDllPathEntryInUse);
|
|
}
|
|
PrivMemFree(_pDllPathEntries);
|
|
_pDllPathEntries = NULL;
|
|
}
|
|
|
|
_cDllPathEntries = 0;
|
|
_nDllPathEntryInUse = NONE;
|
|
_nDllPathEntryAvail = NONE;
|
|
|
|
|
|
// Now free the class entries.
|
|
if (_pClassEntries)
|
|
{
|
|
// Delete the class entries
|
|
PrivMemFree(_pClassEntries);
|
|
_pClassEntries = NULL;
|
|
}
|
|
|
|
_cClassEntries = 0;
|
|
_nClassEntryInUse = NONE;
|
|
_nClassEntryAvail = NONE;
|
|
|
|
CleanupTreatAs();
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDllCache::Search
|
|
//
|
|
// Synopsis: Search for a class entry by clsid and specific context
|
|
// and specific apartment
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: 07-Mar-95 BruceMa Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
DWORD CDllCache::Search(REFCLSID clsid, DWORD dwContext, HAPT hApt)
|
|
{
|
|
// Search
|
|
for (int k = _nClassEntryInUse; k != NONE; k = _pClassEntries[k]._dwNext)
|
|
{
|
|
if (IsEqualCLSID(clsid, _pClassEntries[k]._clsid) &&
|
|
(_pClassEntries[k]._dwContext & dwContext) &&
|
|
!((dwContext & CLSCTX_INPROC_SERVER) &&
|
|
(_pClassEntries[k]._dwFlags & REGCLS_SURROGATE)) &&
|
|
(_pClassEntries[k]._hApt == hApt))
|
|
{
|
|
return k;
|
|
}
|
|
}
|
|
|
|
return NONE;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDllCache::Search
|
|
//
|
|
// Synopsis: Search for a class entry by registration key
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: 07-Mar-95 BruceMa Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
DWORD CDllCache::Search(DWORD dwRegKey, HAPT hApt)
|
|
{
|
|
// Search
|
|
for (int k = _nClassEntryInUse; k != NONE; k = _pClassEntries[k]._dwNext)
|
|
{
|
|
if (dwRegKey == _pClassEntries[k]._dwReg &&
|
|
hApt == _pClassEntries[k]._hApt)
|
|
{
|
|
return k;
|
|
}
|
|
}
|
|
|
|
return NONE;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDllCache::SearchForDll
|
|
//
|
|
// Synopsis: Search for a dll path entry
|
|
//
|
|
// Algorithm: Upper case and compute a hash. Then search by the hash
|
|
// value and by the pathname only if the hash matches.
|
|
//
|
|
// History: 07-Mar-95 BruceMa Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
DWORD CDllCache::SearchForDll(const TCHAR *ptszDllPath
|
|
#ifdef WX86OLE
|
|
, BOOL fWx86
|
|
#endif
|
|
)
|
|
{
|
|
TCHAR tszPath[MAX_PATH];
|
|
LPTSTR ptszPath = tszPath;
|
|
DWORD cCh = lstrlen(ptszDllPath);
|
|
DWORD dwHash;
|
|
BOOL fFreePath = FALSE;
|
|
#ifdef WX86OLE
|
|
BOOL fWx86Dll;
|
|
#endif
|
|
|
|
// Compute a hash value for the search path
|
|
if (cCh > MAX_PATH - 1)
|
|
{
|
|
ptszPath = (LPTSTR) PrivMemAlloc((cCh + 1) * sizeof(TCHAR));
|
|
if (ptszPath == NULL)
|
|
{
|
|
return NONE;
|
|
}
|
|
fFreePath = TRUE;
|
|
}
|
|
lstrcpy(ptszPath, ptszDllPath);
|
|
CharUpper(ptszPath);
|
|
dwHash = Hash(ptszPath);
|
|
|
|
// Search
|
|
for (int k = _nDllPathEntryInUse; k != NONE;
|
|
k = _pDllPathEntries[k]._dwNext)
|
|
{
|
|
#ifdef WX86OLE
|
|
fWx86Dll = _pDllPathEntries[k]._dwFlags & WX86_LOADASX86;
|
|
#endif
|
|
if (_pDllPathEntries[k]._dwHash == dwHash &&
|
|
_pDllPathEntries[k]._dwSig == DLL_PATH_CACHE_SIG
|
|
#ifdef WX86OLE
|
|
// We also must match the dll type (x86 or risc)
|
|
&& ((fWx86 && fWx86Dll) || (! fWx86 && ! fWx86Dll))
|
|
#endif
|
|
)
|
|
{
|
|
if (lstrcmp(_pDllPathEntries[k]._ptszPath, ptszPath) == 0)
|
|
{
|
|
if (fFreePath)
|
|
{
|
|
PrivMemFree(ptszPath);
|
|
}
|
|
return k;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (fFreePath)
|
|
{
|
|
PrivMemFree(ptszPath);
|
|
}
|
|
|
|
return NONE;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDllCache::AllocClassEntry
|
|
//
|
|
// Synopsis: Allocate a new class entry
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: 07-Mar-95 BruceMa Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
DWORD CDllCache::AllocClassEntry(void)
|
|
{
|
|
// If we don't have any available entries, then expand the array
|
|
if (_nClassEntryAvail == NONE)
|
|
{
|
|
// Allocate a new array
|
|
SClassEntry *p = (SClassEntry *) PrivMemAlloc(sizeof(SClassEntry) *
|
|
(_cClassEntries + NOMINAL_CACHE_SIZE));
|
|
if (p == NULL)
|
|
{
|
|
return NONE;
|
|
}
|
|
|
|
// Initialize it and free the old one.
|
|
memcpy(p, _pClassEntries, _cClassEntries * sizeof(SClassEntry));
|
|
|
|
PrivMemFree(_pClassEntries);
|
|
_pClassEntries = p;
|
|
|
|
for (DWORD k = _cClassEntries;
|
|
k < _cClassEntries + NOMINAL_CACHE_SIZE;
|
|
k++)
|
|
{
|
|
InitClsent(k, k == _cClassEntries + NOMINAL_CACHE_SIZE - 1 ? NONE
|
|
: k + 1 );
|
|
}
|
|
_nClassEntryAvail = _cClassEntries;
|
|
_cClassEntries += NOMINAL_CACHE_SIZE;
|
|
}
|
|
|
|
// Init and return the next available entry
|
|
DWORD dwClsent = _nClassEntryAvail;
|
|
_pClassEntries[dwClsent]._dwSig = CLASS_CACHE_SIG;
|
|
|
|
_nClassEntryAvail = _pClassEntries[dwClsent]._dwNext;
|
|
_pClassEntries[dwClsent]._dwNext = _nClassEntryInUse;
|
|
Win4Assert((_pClassEntries[dwClsent]._dwNext == NONE ||
|
|
_pClassEntries[dwClsent]._dwNext < _cClassEntries)
|
|
&& "Bad class entry index");
|
|
_nClassEntryInUse = dwClsent;
|
|
return dwClsent;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDllCache::AllocDllPathEntry
|
|
//
|
|
// Synopsis: Allocate a new dll path entry
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: 07-Mar-95 BruceMa Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
DWORD CDllCache::AllocDllPathEntry(void)
|
|
{
|
|
// If we don't have any available entries, then expand the array
|
|
if (_nDllPathEntryAvail == NONE)
|
|
{
|
|
// Allocate a new array
|
|
SDllPathEntry *p = (SDllPathEntry *) PrivMemAlloc(
|
|
sizeof(SDllPathEntry) * (_cDllPathEntries + NOMINAL_CACHE_SIZE));
|
|
if (p == NULL)
|
|
{
|
|
return NONE;
|
|
}
|
|
|
|
// Initialize it and free the old one.
|
|
memcpy(p, _pDllPathEntries, _cDllPathEntries * sizeof(SDllPathEntry));
|
|
|
|
PrivMemFree(_pDllPathEntries);
|
|
_pDllPathEntries = p;
|
|
|
|
for (DWORD k = _cDllPathEntries;
|
|
k < _cDllPathEntries + NOMINAL_CACHE_SIZE;
|
|
k++)
|
|
{
|
|
InitDllent(k, k == _cDllPathEntries + NOMINAL_CACHE_SIZE - 1 ? NONE
|
|
: k + 1 );
|
|
}
|
|
_nDllPathEntryAvail = _cDllPathEntries;
|
|
_cDllPathEntries += NOMINAL_CACHE_SIZE;
|
|
}
|
|
|
|
// Init and return the next available entry
|
|
DWORD dwDllent = _nDllPathEntryAvail;
|
|
_pDllPathEntries[dwDllent]._dwSig = DLL_PATH_CACHE_SIG;
|
|
|
|
// Allocate and initialize apartment entries
|
|
if (!NewAptEntries(dwDllent))
|
|
{
|
|
return NONE;
|
|
}
|
|
|
|
_nDllPathEntryAvail = _pDllPathEntries[dwDllent]._dwNext;
|
|
_pDllPathEntries[dwDllent]._dwNext = _nDllPathEntryInUse;
|
|
_nDllPathEntryInUse =dwDllent;
|
|
return dwDllent;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDllCache::FreeClassEntry
|
|
//
|
|
// Synopsis: Free a class entry - i.e., make it available
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: 07-Mar-95 BruceMa Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
void CDllCache::FreeClassEntry(DWORD dwClsent)
|
|
{
|
|
DWORD dwPrevCls;
|
|
BOOL fBreak = FALSE;
|
|
|
|
// Saftey check
|
|
if (_pClassEntries[dwClsent]._dwSig != CLASS_CACHE_SIG)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// First check whether it is on a list of class entries for a given dll
|
|
// - if so, unthread it
|
|
for (DWORD dwDllent = _nDllPathEntryInUse;
|
|
dwDllent != NONE;
|
|
dwDllent = _pDllPathEntries[dwDllent]._dwNext)
|
|
{
|
|
for (DWORD dwNextCls = _pDllPathEntries[dwDllent]._dw1stClass;
|
|
dwNextCls != NONE;
|
|
dwPrevCls = dwNextCls,
|
|
dwNextCls = _pClassEntries[dwNextCls]._dwNextDllCls)
|
|
{
|
|
if (dwNextCls == dwClsent)
|
|
{
|
|
// It's at the head of the list
|
|
if (dwNextCls == _pDllPathEntries[dwDllent]._dw1stClass)
|
|
{
|
|
_pDllPathEntries[dwDllent]._dw1stClass =
|
|
_pClassEntries[dwNextCls]._dwNextDllCls;
|
|
}
|
|
|
|
// Else it's in the list
|
|
else
|
|
{
|
|
_pClassEntries[dwPrevCls]._dwNextDllCls =
|
|
_pClassEntries[dwNextCls]._dwNextDllCls;
|
|
}
|
|
fBreak = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
if (fBreak)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
// Then remove it from the list of in-use entries
|
|
// It's at the head of the list
|
|
if (_nClassEntryInUse == dwClsent)
|
|
{
|
|
_nClassEntryInUse = _pClassEntries[dwClsent]._dwNext;
|
|
Win4Assert((_nClassEntryInUse == NONE ||
|
|
_nClassEntryInUse < _cClassEntries) && "Bad class entry index");
|
|
}
|
|
|
|
// Otherwise search for the entry that points to the one we're releasing
|
|
else
|
|
{
|
|
for (DWORD dwPrev = _nClassEntryInUse;
|
|
_pClassEntries[dwPrev]._dwNext != dwClsent;
|
|
dwPrev = _pClassEntries[dwPrev]._dwNext)
|
|
{
|
|
}
|
|
_pClassEntries[dwPrev]._dwNext = _pClassEntries[dwClsent]._dwNext;
|
|
}
|
|
|
|
// Relink into the list of available entries
|
|
_pClassEntries[dwClsent]._dwNext = _nClassEntryAvail;
|
|
_nClassEntryAvail = dwClsent;
|
|
InitClsent(dwClsent, _pClassEntries[dwClsent]._dwNext);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDllCache::FreeDllPathEntry
|
|
//
|
|
// Synopsis: Free a dll path entry - i.e., make it available
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: 07-Mar-95 BruceMa Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
void CDllCache::FreeDllPathEntry(DWORD dwDllent)
|
|
{
|
|
ComDebOut((DEB_TRACE, "FreeDllPathEntry dwDll:%x\n", dwDllent));
|
|
|
|
// It's at the head of the list
|
|
if (_nDllPathEntryInUse == dwDllent)
|
|
{
|
|
_nDllPathEntryInUse = _pDllPathEntries[dwDllent]._dwNext;
|
|
}
|
|
|
|
// Otherwise search for the entry that points to the one we're releasing
|
|
else
|
|
{
|
|
for (DWORD dwPrev = _nDllPathEntryInUse;
|
|
_pDllPathEntries[dwPrev]._dwNext != dwDllent;
|
|
dwPrev = _pDllPathEntries[dwPrev]._dwNext)
|
|
{
|
|
}
|
|
_pDllPathEntries[dwPrev]._dwNext = _pDllPathEntries[dwDllent]._dwNext;
|
|
}
|
|
|
|
// Relink into the list of available entries
|
|
_pDllPathEntries[dwDllent]._dwNext = _nDllPathEntryAvail;
|
|
_nDllPathEntryAvail = dwDllent;
|
|
|
|
// Delete the array of apartment entries
|
|
if (_pDllPathEntries[dwDllent]._pAptEntries)
|
|
{
|
|
delete _pDllPathEntries[dwDllent]._pAptEntries;
|
|
}
|
|
|
|
// Now reinitialize this dll path entry
|
|
InitDllent(dwDllent, _pDllPathEntries[dwDllent]._dwNext);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDllCache::Hash
|
|
//
|
|
// Synopsis: Compute a hash value for a pathname
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: 07-Mar-95 BruceMa Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
DWORD CDllCache::Hash(LPTSTR ptszPath)
|
|
{
|
|
DWORD dwHash = 0;
|
|
|
|
for (DWORD k = 0; ptszPath[k]; k++)
|
|
{
|
|
dwHash *= 3;
|
|
dwHash ^= ptszPath[k];
|
|
}
|
|
return dwHash;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: CleanUpDllsForProcess
|
|
//
|
|
// Synopsis: Free all cached Dll class object information for this process
|
|
//
|
|
// Algorithm: Tell class caches to free themselves
|
|
//
|
|
// History: 02-Feb-94 Ricksa Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
void CleanUpDllsForProcess(void)
|
|
{
|
|
// Clean up server cache
|
|
gdllcacheInprocSrv.CleanUpDllsForProcess();
|
|
|
|
// Clean up handler cache
|
|
gdllcacheHandler.CleanUpDllsForProcess();
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: CleanUpDllsForApartment
|
|
//
|
|
// Synopsis: Free all cached class object information for this Apartment.
|
|
//
|
|
// Algorithm: Tell class caches to cleanup the current apartment
|
|
//
|
|
// History: 26-Jun-94 Rickhi Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
void CleanUpDllsForApartment(void)
|
|
{
|
|
// Clean up server cache
|
|
gdllcacheInprocSrv.CleanUpDllsForApartment();
|
|
|
|
// Clean up handler cache
|
|
gdllcacheHandler.CleanUpDllsForApartment();
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: CleanUpLocalServersForApartment
|
|
//
|
|
// Synopsis: Free all cached LocalServer class objects for this Apartment.
|
|
//
|
|
// Algorithm: Tell class caches to cleanup the current apartment
|
|
//
|
|
// History: 18-Dec-95 Rickhi Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
void CleanUpLocalServersForApartment(void)
|
|
{
|
|
// Clean up server cache
|
|
gdllcacheInprocSrv.CleanUpLocalServersForApartment();
|
|
|
|
// dont need to call on gdllcacheHandler since local servers are never
|
|
// stored in that cache.
|
|
}
|
|
|
|
|
|
|
|
#ifdef _CHICAGO_
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: GetAptForCLSID
|
|
//
|
|
// Synopsis: Get the ApartmentId for a given class
|
|
//
|
|
// Algorithm: search the cache of registrations for an available class
|
|
// object of the given class, and return its apartment id.
|
|
//
|
|
// Returns: HAPT - if found (thread id is member)
|
|
// haptNULL - if not
|
|
//
|
|
// History: 30-Apr-94 JohannP Created
|
|
// 06-Oct-95 BruceMa Make for Chicago only
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
HAPT GetAptForCLSID(const GUID *pclsid)
|
|
{
|
|
HAPT hApt;
|
|
if (gdllcacheInprocSrv.GetApartmentForCLSID(*pclsid, hApt))
|
|
{
|
|
return hApt;
|
|
}
|
|
else
|
|
{
|
|
return haptNULL;
|
|
}
|
|
}
|
|
#endif // _CHICAGO_
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: GetClassInformationForDde
|
|
//
|
|
// Synopsis: Get class object information for the Dde server
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: [clsid] -- ClassID to search for
|
|
// [lpDdeInfo] -- Structure to fill in with information
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: 5-28-94 kevinro Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL GetClassInformationForDde( REFCLSID clsid,
|
|
LPDDECLASSINFO lpDdeInfo)
|
|
{
|
|
return gdllcacheInprocSrv.GetClassObjForDde(clsid,lpDdeInfo);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: GetClassInformationFromKey
|
|
//
|
|
// Synopsis: Get class object information for the Dde server using a key
|
|
//
|
|
// Arguments: [lpDdeInfo] -- Structure to fill in with information
|
|
//
|
|
// Requires: lpDdeInfo->dwRegistrationKey is the key to the specific
|
|
// class being asked for.
|
|
//
|
|
// Returns: TRUE - Structure filled in with appropriate information
|
|
// FALSE - The registration is no longer valid.
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: 5-28-94 kevinro Created
|
|
//
|
|
// Notes:
|
|
//
|
|
// See CDllCache::GetClassInformationFromKey
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL GetClassInformationFromKey(LPDDECLASSINFO lpDdeInfo)
|
|
{
|
|
return gdllcacheInprocSrv.GetClassInformationFromKey(lpDdeInfo);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: SetDdeServerWindow
|
|
//
|
|
// Synopsis: Finds the registration associated with dwKey, and sets the
|
|
// HWND for the DDE server.
|
|
//
|
|
// Effects: See CDllCache::SetDdeServerWindow for details
|
|
//
|
|
// Arguments: [dwKey] -- Key for the registration
|
|
// [hwndDdeServer] -- Window handle to Dde Server
|
|
//
|
|
// Returns: TRUE if call was successful.
|
|
// FALSE if the dwKey was not valid.
|
|
//
|
|
// History: 7-05-94 kevinro Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL SetDdeServerWindow( DWORD dwKey, HWND hwndDdeServer)
|
|
{
|
|
|
|
TRACECALL(TRACE_DLL, "SetDdeServerWindow");
|
|
return gdllcacheInprocSrv.SetDdeServerWindow(dwKey, hwndDdeServer);
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: OleMainThreadWndProc
|
|
//
|
|
// Synopsis: Window proc for handling messages to the main thread
|
|
//
|
|
// Arguments: [hWnd] - window the message is on
|
|
// [message] - message the window receives
|
|
// [wParam] - first message parameter
|
|
// [lParam] - second message parameter.
|
|
//
|
|
// Returns: Depends on the message
|
|
//
|
|
// Algorithm: If the message is one a user message that we have defined,
|
|
// dispatch it. Otherwise, send any other message to the
|
|
// default window proc.
|
|
//
|
|
// History: 22-Nov-94 Ricksa Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
LRESULT OleMainThreadWndProc(
|
|
HWND hWnd,
|
|
UINT message,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
switch(message)
|
|
{
|
|
case WM_OLE_GETCLASS:
|
|
// get the host interface for single-threaded dlls
|
|
return GetSingleThreadedHost(lParam);
|
|
|
|
#ifdef _CHICAGO_
|
|
case WM_OLE_ORPC_NOTIFY:
|
|
// got the initialization message
|
|
OleNotificationProc(message, wParam, lParam);
|
|
return 0;
|
|
|
|
#endif // _CHICAGO_
|
|
|
|
#ifndef _CHICAGO_
|
|
// Check whether it is UninitMainThreadWnd or system shutdown that
|
|
// is destroying the window. Only actually do the destroy if it is us.
|
|
//
|
|
// BUGBUG: Chicago hit this but the debugger was unable to tell
|
|
// us who we were called by....so for now i just removed it.
|
|
case WM_DESTROY:
|
|
case WM_CLOSE:
|
|
if (gfDestroyingMainWindow == FALSE)
|
|
{
|
|
// Not in UninitMainThreadWnd so just ignore this message. Do not
|
|
// dispatch it.
|
|
ComDebOut((DEB_WARN, "Attempted to destroy Window outside of UninitMainThreadWnd"));
|
|
return 0;
|
|
}
|
|
// else fallthru
|
|
#endif // _CHICAGO_
|
|
}
|
|
|
|
// We don't process the message so pass it on to the default
|
|
// window proc.
|
|
return SSDefWindowProc(hWnd, message, wParam, lParam);
|
|
}
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: InitMainThreadWnd
|
|
//
|
|
// Synopsis: Do initialization necessary for main window processing.
|
|
//
|
|
// Returns: TRUE - we got initialized
|
|
// FALSE - initialization failed.
|
|
//
|
|
// Algorithm: First register out window class. Then create our main thread
|
|
// window. Finally, save the id of the main thread.
|
|
//
|
|
// History: 22-Nov-94 Ricksa Created
|
|
// 24-Mar-95 JohannP Added notify mechanismen
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL InitMainThreadWnd(void)
|
|
{
|
|
ComDebOut((DEB_ENDPNT, "InitMainThreadWnd on %x\n", GetCurrentThreadId()));
|
|
Win4Assert(IsSTAThread());
|
|
|
|
#ifdef _CHICAGO_
|
|
if (IsWOWProcess())
|
|
{
|
|
// Chicago WOW requires a different class per thread.
|
|
wsprintfA(ptszOleMainThreadWndClass,"OleMainThreadWndClass %08X",
|
|
CoGetCurrentProcess());
|
|
}
|
|
#endif // _CHICAGO_
|
|
|
|
BOOL fRetVal = TRUE;
|
|
|
|
// Register windows class.
|
|
WNDCLASST xClass;
|
|
xClass.style = 0;
|
|
xClass.lpfnWndProc = OleMainThreadWndProc;
|
|
xClass.cbClsExtra = 0;
|
|
|
|
// DDE needs some extra space in the window
|
|
xClass.cbWndExtra = sizeof(LPVOID) + sizeof(ULONG) + sizeof(HANDLE);
|
|
xClass.hInstance = g_hinst;
|
|
xClass.hIcon = NULL;
|
|
xClass.hCursor = NULL;
|
|
xClass.hbrBackground = (HBRUSH) (COLOR_BACKGROUND + 1);
|
|
xClass.lpszMenuName = NULL;
|
|
xClass.lpszClassName = ptszOleMainThreadWndClass;
|
|
|
|
gOleWindowClass = (LPTSTR) RegisterClassT( &xClass );
|
|
if (gOleWindowClass == 0)
|
|
{
|
|
// it is possible the dll got unloaded without us having called
|
|
// unregister so we call it here and try again.
|
|
|
|
UnregisterClassT(ptszOleMainThreadWndClass, g_hinst);
|
|
gOleWindowClass = (LPTSTR) RegisterClassT(&xClass);
|
|
|
|
if (gOleWindowClass == 0)
|
|
{
|
|
ComDebOut((DEB_ERROR, "RegisterClass failed in InitMainThreadWnd\n"));
|
|
fRetVal = FALSE;
|
|
}
|
|
}
|
|
|
|
// Remember the main thread
|
|
gdwMainThreadId = GetCurrentThreadId();
|
|
|
|
if (!IsWOWProcess() && fRetVal)
|
|
{
|
|
// this window is only needed for the non WOW case since
|
|
// WOW is not a real apartment case
|
|
// Create a main window for this application instance.
|
|
|
|
hwndOleMainThread = DllCreateWindowEx(
|
|
0,
|
|
gOleWindowClass,
|
|
ptszOleMainThreadWndName,
|
|
// must use WS_POPUP so the window does not get assigned
|
|
// a hot key by user.
|
|
(WS_DISABLED | WS_POPUP),
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
NULL,
|
|
NULL,
|
|
g_hinst,
|
|
NULL);
|
|
|
|
Win4Assert(hwndOleMainThread && "Register Window on OleWindowClass failed \n");
|
|
if (!hwndOleMainThread)
|
|
{
|
|
// We did not get a window so we can not report success.
|
|
// Cleanup the registered window class and gdwMainThreadId.
|
|
UninitMainThreadWnd();
|
|
fRetVal = FALSE;
|
|
}
|
|
}
|
|
|
|
ComDebOut((DEB_ENDPNT, "InitMainThreadWnd done on %x\n", gdwMainThreadId));
|
|
return fRetVal;
|
|
}
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: UninitMainThreadWnd
|
|
//
|
|
// Synopsis: Free resources used by main window processing.
|
|
//
|
|
// Algorithm: Destroy the window and then unregister the window class.
|
|
//
|
|
// History: 22-Nov-94 Ricksa Created
|
|
// 24-Mar-95 JohannP Added notify mechanismen
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
void UninitMainThreadWnd(void)
|
|
{
|
|
ComDebOut((DEB_ENDPNT, "UninitMainThreadWnd on %x\n", gdwMainThreadId));
|
|
Win4Assert(IsSTAThread());
|
|
|
|
if (gdwMainThreadId)
|
|
{
|
|
BOOL fRet = FALSE;
|
|
|
|
#ifdef _CHICAGO_
|
|
// destroy the notification window if it still exist
|
|
COleTls tls;
|
|
if (tls->hwndOleRpcNotify != NULL)
|
|
{
|
|
ComDebOut((DEB_ENDPNT,"Destroying NotifyThreadWnd %x\n", tls->hwndOleRpcNotify));
|
|
fRet = SSDestroyWindow(tls->hwndOleRpcNotify);
|
|
Win4Assert(fRet && "Destroy Window failed on NotifyThreadWnd\n");
|
|
tls->hwndOleRpcNotify = NULL;
|
|
}
|
|
#endif // _CHICAGO_
|
|
|
|
// Destroy the window
|
|
if (!IsWOWProcess() && IsWindow(hwndOleMainThread))
|
|
{
|
|
// flag here is to indicate that we are destroying the window.
|
|
// as opposed to the system shutdown closing the window. the
|
|
// flag is looked at in dcomrem\chancont\ThreadWndProc.
|
|
gfDestroyingMainWindow = TRUE;
|
|
SSDestroyWindow(hwndOleMainThread);
|
|
gfDestroyingMainWindow = FALSE;
|
|
hwndOleMainThread = NULL;
|
|
}
|
|
|
|
// Unregister the window class
|
|
if (UnregisterClassT(ptszOleMainThreadWndClass, g_hinst) == FALSE)
|
|
{
|
|
ComDebOut((DEB_ERROR,"Unregister Class failed on OleMainThreadWndClass %ws because %d\n", ptszOleMainThreadWndClass, GetLastError()));
|
|
}
|
|
|
|
gdwMainThreadId = 0;
|
|
}
|
|
|
|
ComDebOut((DEB_ENDPNT,"UninitMainThreadWnd done on %x\n", gdwMainThreadId));
|
|
return;
|
|
}
|