456 lines
11 KiB
C++
456 lines
11 KiB
C++
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1992 - 1993.
|
|
//
|
|
// File: loadcls.cxx
|
|
//
|
|
// Contents: Methods implementing classes defined in loadcls.hxx
|
|
//
|
|
// Functions:
|
|
//
|
|
// History: 12-Jul-93 Ricksa Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
#include <windows.h>
|
|
#include <ole2.h>
|
|
#include <olecom.h>
|
|
#include "loadcls.hxx"
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CLoadedClassEntry::Init
|
|
//
|
|
// Synopsis: Initialize a class entry object by getting the application
|
|
// class object from the DLL.
|
|
//
|
|
// Arguments: [pszCmdLine] - command line with class ID as first entry
|
|
// [lpfngetclassobject] - DllGetClassObject entry point
|
|
//
|
|
// Returns: TRUE - Succeeded
|
|
// FALSE - FAILED
|
|
//
|
|
// Algorithm: Read the string class id from the command line and
|
|
// then ask the DLL to create a class object for the
|
|
// class. Then register the class.
|
|
//
|
|
// History: 12-Jul-93 Ricksa Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
BOOL CLoadedClassEntry::Init(
|
|
LPSTR& pszCmdLine,
|
|
LPFNGETCLASSOBJECT lpfngetclassobject)
|
|
{
|
|
// Get guid from string
|
|
GUID guidClass;
|
|
char *pszClassID = pszCmdLine;
|
|
char *pszNextSpace = strchr(pszCmdLine, ' ');
|
|
|
|
if (pszNextSpace)
|
|
{
|
|
// This is not the last GUID in the string, NULL terminate
|
|
// the string.
|
|
*pszNextSpace = '\0';
|
|
}
|
|
|
|
CairoleDebugOut((DEB_TRACE, "Registering Class: %s\n", pszClassID));
|
|
|
|
// Convert guid in string to binary
|
|
sscanf(pszCmdLine, "%08lX%04X%04X",
|
|
&guidClass.Data1, &guidClass.Data2, &guidClass.Data3);
|
|
|
|
for (int i = 0; i < 8; i++)
|
|
{
|
|
int tmp;
|
|
sscanf(pszCmdLine + 16 + (i * 2), "%02X", &tmp);
|
|
guidClass.Data4[i] = (char) tmp;
|
|
}
|
|
|
|
|
|
// Point to next item in string if any
|
|
pszCmdLine = (pszNextSpace != NULL) ? pszNextSpace + 1 : NULL;
|
|
|
|
// Ask DLL to create class object
|
|
SCODE sc = (*lpfngetclassobject)(guidClass, IID_IUnknown, (void **) &_punk);
|
|
|
|
if (SUCCEEDED(sc))
|
|
{
|
|
// Register the class object with the component object system
|
|
sc = CoRegisterClassObject(guidClass, _punk,
|
|
CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &_dwRegistration);
|
|
|
|
if (FAILED(sc))
|
|
{
|
|
if (sc == CO_E_OBJISREG)
|
|
{
|
|
// If object is registered, the DLL must have registered
|
|
// itself and since compobj.dll doesn't know about the
|
|
// DLL, it will assume that the load is for a remotely
|
|
// shared object which is what we want. So it is safe
|
|
// to ignore this error here.
|
|
sc = S_OK;
|
|
}
|
|
else
|
|
{
|
|
Win4Assert(SUCCEEDED(sc) &&
|
|
"Surrogat: CoRegisterClassObject failed");
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(sc))
|
|
{
|
|
// Registration bumps reference count so we don't have to keep
|
|
// our reference.
|
|
_punk->Release();
|
|
}
|
|
}
|
|
|
|
return (SUCCEEDED(sc)) ? TRUE : FALSE;
|
|
}
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CLoadedClassList::~CLoadedClassList
|
|
//
|
|
// Synopsis: Free all loaded class objects and frees each one.
|
|
//
|
|
// Algorithm: Loops through list of list. Each item in the list is
|
|
// freed and then the succeeding item is processed.
|
|
//
|
|
// History: 12-Jul-93 Ricksa Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
CLoadedClassList::~CLoadedClassList(void)
|
|
{
|
|
CLoadedClassEntryIter ldclsiter(*this);
|
|
|
|
// For each DLL revoke each DLL object
|
|
while(!AtEnd(ldclsiter))
|
|
{
|
|
// Get pointer to object to free
|
|
CLoadedClassEntry *pldcls = ldclsiter.GetEntry();
|
|
|
|
// Advance iterator to next object
|
|
Advance(ldclsiter);
|
|
|
|
// Free current object
|
|
delete pldcls;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CLoadedClassList::Init
|
|
//
|
|
// Synopsis: Initialise the class list for a DLL by having it process
|
|
// all the class ids for the DLL.
|
|
//
|
|
// Arguments: [pszCmdLine] - command line with count of class ids for class
|
|
// [lpfngetclassobject] - DllGetClassObject entry point
|
|
//
|
|
// Returns: TRUE - at least one class was registered
|
|
// FALSE - no class was registered for the DLL.
|
|
//
|
|
// Algorithm: Get count of class ids from the list and then create
|
|
// a class entry object for each entry in the list.
|
|
//
|
|
// History: 12-Jul-93 Ricksa Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
BOOL CLoadedClassList::Init(
|
|
LPSTR& pszCmdLine,
|
|
LPFNGETCLASSOBJECT lpfngetclassobject)
|
|
{
|
|
// Assume we will not be able to initialize any classes
|
|
BOOL fResult = FALSE;
|
|
|
|
// Get number of class entries for this DLL
|
|
char *pszNoClasses = pszCmdLine;
|
|
char *pszNextSpace = strchr(pszCmdLine, ' ');
|
|
|
|
if (pszNextSpace == NULL)
|
|
{
|
|
// Invalid command line -- there have to be guids following
|
|
// the the count otherwise why load the DLL?
|
|
return FALSE;
|
|
}
|
|
|
|
*pszNextSpace = 0;
|
|
|
|
CairoleDebugOut((DEB_TRACE, "Number of classes: %s\n", pszNoClasses));
|
|
|
|
int cClassObjects = atoi(pszNoClasses);
|
|
|
|
if (cClassObjects == 0)
|
|
{
|
|
// Either an invalid string or 0 in either case an error
|
|
return FALSE;
|
|
}
|
|
|
|
// Update string to point to the next token in the string
|
|
pszCmdLine = pszNextSpace + 1;
|
|
|
|
for (int i = 0; i < cClassObjects; i++)
|
|
{
|
|
// Create DLL object
|
|
CLoadedClassEntry *pldcls = new CLoadedClassEntry;
|
|
|
|
if (pldcls->Init(pszCmdLine, lpfngetclassobject))
|
|
{
|
|
// DLL object initialized so put it on the list
|
|
_Push(pldcls);
|
|
|
|
// We were able to initialize at least one class
|
|
fResult = TRUE;
|
|
}
|
|
else
|
|
{
|
|
// Free class object that could not be initialized.
|
|
delete pldcls;
|
|
}
|
|
}
|
|
|
|
return fResult;
|
|
}
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CLoadedClassList::CanExit
|
|
//
|
|
// Synopsis: Determine whether the class list thinks that it can exit
|
|
//
|
|
// Returns: TRUE - all classes in list think exit is OK
|
|
// FALSE - a class in the list did not want to exit.
|
|
//
|
|
// Algorithm: Loop through the list of classes asking each list
|
|
// in turn if exit is ok. If any class says no, break
|
|
// the loop and return FALSE.
|
|
//
|
|
// History: 12-Jul-93 Ricksa Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
BOOL CLoadedClassList::CanExit(void)
|
|
{
|
|
CLoadedClassEntryIter ldclsiter(*this);
|
|
|
|
// Assume that we can exit
|
|
BOOL fFinalResult = TRUE;
|
|
|
|
// For each DLL revoke each DLL object
|
|
while(!AtEnd(ldclsiter))
|
|
{
|
|
if (!ldclsiter->CanExit())
|
|
{
|
|
// DLL said that it could not exit so we will not exit.
|
|
fFinalResult = FALSE;
|
|
break;
|
|
}
|
|
|
|
Advance(ldclsiter);
|
|
}
|
|
|
|
return fFinalResult;
|
|
}
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDllEntry::Init
|
|
//
|
|
// Synopsis: Initialize a DLL object
|
|
//
|
|
// Arguments: [pszCmdLine] - command line
|
|
//
|
|
// Returns: TRUE - object was successfully initialized
|
|
// FALSE - initialization failed.
|
|
//
|
|
// Algorithm: Get the DLL name from the command line and then
|
|
// initialize the DLL object by loading the DLL and
|
|
// getting the file name. Then create a class list
|
|
// using the rest of the commmand line.
|
|
//
|
|
// History: 12-Jul-93 Ricksa Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
BOOL CDllEntry::Init(LPSTR& pszCmdLine)
|
|
{
|
|
// Get DLL name from the string
|
|
char *pszDllName = pszCmdLine;
|
|
char *pszNextSpace = strchr(pszDllName, ' ');
|
|
|
|
if (pszNextSpace == NULL)
|
|
{
|
|
// Nothing after the command line. This is hosed.
|
|
return FALSE;
|
|
}
|
|
|
|
// NULL terminate the name of the DLL
|
|
*pszNextSpace = 0;
|
|
|
|
// Point to next item in string if any
|
|
pszCmdLine = (pszNextSpace != NULL) ? pszNextSpace + 1 : NULL;
|
|
|
|
CairoleDebugOut((DEB_TRACE, "Loading DLL: %s\n", pszDllName));
|
|
|
|
// Load library
|
|
if (!_dll.Init(pszDllName))
|
|
{
|
|
// If the DLL cannot be loaded, there is no point in continuing.
|
|
CairoleDebugOut((DEB_TRACE, "Load of Dll Failed\n", pszDllName));
|
|
return FALSE;
|
|
}
|
|
|
|
// Get class creation entry point
|
|
LPFNGETCLASSOBJECT lpfngetclassobject = _dll.GetDllGetClassObjectAddress();
|
|
|
|
if (lpfngetclassobject == NULL)
|
|
{
|
|
// If the DLL does not have the right entry point there is
|
|
// no point in continuing.
|
|
CairoleDebugOut((DEB_TRACE, "No DllGetClass EP\n", pszDllName));
|
|
return FALSE;
|
|
}
|
|
|
|
// NOTE: with current design we do not care about DllCanUnloadNow
|
|
// for two reasons: (1) Not all DLLs will have the entry point
|
|
// so it doesn't do us any good and (2) Even with the entry point,
|
|
// the class object would have to be released which is registered.
|
|
|
|
// Return result of initializing classes
|
|
return _clslist.Init(pszCmdLine, lpfngetclassobject);
|
|
}
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CLoadedClassTable::LoadClassObjects
|
|
//
|
|
// Synopsis: Load all classes for this instance of surrogate.
|
|
//
|
|
// Arguments: [pszCmdLine] - command line
|
|
//
|
|
// Returns: TRUE - at least one class got loaded
|
|
// FALSE - no classes got loaded.
|
|
//
|
|
// Algorithm: For each DLL entry in the list create a DLL object
|
|
// and have it create the class objects.
|
|
//
|
|
// History: 12-Jul-93 Ricksa Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
BOOL CLoadedClassTable::LoadClassObjects(char *pszCmdLine)
|
|
{
|
|
// Assume we will not be able to initialize any DLLs
|
|
BOOL fResult = FALSE;
|
|
|
|
do
|
|
{
|
|
// Create DLL object
|
|
CDllEntry *pdll = new CDllEntry;
|
|
|
|
if (pdll->Init(pszCmdLine))
|
|
{
|
|
// DLL object initialized so put it on the list
|
|
_Push(pdll);
|
|
|
|
// We were able to initialize at least one DLL
|
|
fResult = TRUE;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
|
|
// Create class objects under dll
|
|
} while (pszCmdLine != NULL);
|
|
|
|
return fResult;
|
|
}
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CLoadedClassTable::CanExit
|
|
//
|
|
// Synopsis: Determine whether the server wishes to exit.
|
|
//
|
|
// Returns: TRUE - server can exit.
|
|
// FALSE - server cannot exit.
|
|
//
|
|
// Algorithm: Loop through all DLL entry objects asking them if they
|
|
// can exit.
|
|
//
|
|
// History: 12-Jul-93 Ricksa Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
BOOL CLoadedClassTable::CanExit(void)
|
|
{
|
|
CDllEntryIter dlliter(*this);
|
|
|
|
// Assume that we can exit
|
|
BOOL fFinalResult = TRUE;
|
|
|
|
// For each DLL revoke each DLL object
|
|
while(!AtEnd(dlliter))
|
|
{
|
|
if (!dlliter->CanExit())
|
|
{
|
|
// DLL said that it could not exit so we will not exit.
|
|
fFinalResult = FALSE;
|
|
}
|
|
|
|
Advance(dlliter);
|
|
}
|
|
|
|
return fFinalResult;
|
|
}
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CLoadedClassTable::RevokeClasses
|
|
//
|
|
// Synopsis: Revokie all classes registered by this server
|
|
//
|
|
// Algorithm: Loop through each DLL object and delete it which in
|
|
// turn unregisters all classes registered for that
|
|
// DLL.
|
|
//
|
|
// History: 12-Jul-93 Ricksa Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
void CLoadedClassTable::RevokeClasses(void)
|
|
{
|
|
CDllEntryIter dlliter(*this);
|
|
|
|
// For each DLL revoke each DLL object
|
|
while(!AtEnd(dlliter))
|
|
{
|
|
// Get the object to free
|
|
CDllEntry *pdll = dlliter.GetEntry();
|
|
|
|
// Point to the next object
|
|
Advance(dlliter);
|
|
|
|
// Delete the current object
|
|
delete pdll;
|
|
}
|
|
}
|