461 lines
9.8 KiB
C++
461 lines
9.8 KiB
C++
|
|
/* - - - - - - - - */
|
|
|
|
/*
|
|
** Copyright (C) Microsoft Corporation 1992-1995. All rights reserved.
|
|
*/
|
|
|
|
/* - - - - - - - - */
|
|
|
|
#include <windows.h>
|
|
#include <windowsx.h>
|
|
#include <shellapi.h>
|
|
#include <ole2.h>
|
|
#include <coguid.h>
|
|
|
|
#define INTERNAL_(type) type
|
|
|
|
|
|
const char aszRegServerKey[] = "InprocServer";
|
|
const char aszServerEntry[] = "DllGetClassObject";
|
|
const char aszServerQuery[] = "DllCanUnloadNow";
|
|
const char aszCLSID[] = "CLSID\\";
|
|
STDAPI_(void) MyFreeUnusedLibraries(void);
|
|
|
|
/* - - - - - - - - */
|
|
|
|
struct DllEntry {
|
|
public:
|
|
CLSID clsid;
|
|
IClassFactory FAR* pFactory;
|
|
LPFNCANUNLOADNOW lpfnCanUnloadNow;
|
|
HINSTANCE hInstance;
|
|
DllEntry FAR* pNextDll;
|
|
};
|
|
|
|
class FAR CTask {
|
|
public:
|
|
static CTask FAR* LookupTask(HTASK FAR& hTask);
|
|
static IClassFactory FAR* LookupClass(CTask FAR* pTask, REFCLSID clsid, HINSTANCE hInstance);
|
|
static void FreeUnusedLibraries(CTask FAR* pTask);
|
|
HRESULT AddTaskDll(REFCLSID rclsid, IClassFactory FAR* pFactory, LPFNCANUNLOADNOW lpfnCanUnloadNow, HINSTANCE hInstance);
|
|
IMalloc FAR* QueryMalloc(void)
|
|
{
|
|
return m_pMalloc;
|
|
};
|
|
CTask(HTASK hTask, IMalloc FAR* pMalloc);
|
|
AddRef(void);
|
|
Release(void);
|
|
~CTask(void);
|
|
private:
|
|
ULONG m_refs;
|
|
HTASK m_hTask;
|
|
IMalloc FAR* m_pMalloc;
|
|
DllEntry FAR* m_pDllEntry;
|
|
CTask FAR* m_pTaskNext;
|
|
};
|
|
|
|
/* - - - - - - - - */
|
|
|
|
#define GlobalPtrHandle(pv) ((HGLOBAL)LOWORD(GlobalHandle(SELECTOROF(pv))))
|
|
|
|
class CStdMalloc : public IMalloc {
|
|
public:
|
|
CStdMalloc(void)
|
|
{
|
|
m_refs = 0;
|
|
}
|
|
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void FAR* FAR* ppvObj)
|
|
{
|
|
if (iid == IID_IUnknown || iid == IID_IMalloc) {
|
|
*ppvObj = this;
|
|
m_refs++;
|
|
return NULL;
|
|
} else
|
|
return ResultFromScode(E_NOINTERFACE);
|
|
}
|
|
ULONG STDMETHODCALLTYPE AddRef(void)
|
|
{
|
|
return ++m_refs;
|
|
}
|
|
ULONG STDMETHODCALLTYPE Release(void)
|
|
{
|
|
return --m_refs;
|
|
}
|
|
void FAR* STDMETHODCALLTYPE Alloc(ULONG cb)
|
|
{
|
|
return (void FAR*)GlobalLock(GlobalAlloc(GMEM_SHARE | GMEM_FIXED, cb));
|
|
}
|
|
void FAR* STDMETHODCALLTYPE Realloc(void FAR* pv, ULONG cb)
|
|
{
|
|
HGLOBAL h;
|
|
|
|
h = GlobalPtrHandle(pv);
|
|
GlobalUnlock(h);
|
|
return (void FAR*)GlobalLock(GlobalReAlloc(h, cb, GMEM_FIXED));
|
|
}
|
|
void STDMETHODCALLTYPE Free(void FAR* pv)
|
|
{
|
|
GlobalFree(GlobalPtrHandle(pv));
|
|
}
|
|
ULONG STDMETHODCALLTYPE GetSize(void FAR* pv)
|
|
{
|
|
return GlobalSize(GlobalPtrHandle(pv));
|
|
}
|
|
int STDMETHODCALLTYPE DidAlloc(void FAR* pv)
|
|
{
|
|
return !IsBadWritePtr(pv, 0);
|
|
}
|
|
void STDMETHODCALLTYPE HeapMinimize(void)
|
|
{
|
|
GlobalCompact(-1);
|
|
}
|
|
private:
|
|
ULONG m_refs;
|
|
};
|
|
|
|
/* - - - - - - - - */
|
|
|
|
CTask FAR* pTaskList;
|
|
CStdMalloc NEAR v_stdMalloc;
|
|
|
|
/* - - - - - - - - */
|
|
|
|
CTask FAR* CTask::LookupTask(
|
|
HTASK FAR& hTask)
|
|
{
|
|
CTask FAR* pTaskCurrent;
|
|
|
|
hTask = GetCurrentTask();
|
|
for (pTaskCurrent = pTaskList; pTaskCurrent; pTaskCurrent = pTaskCurrent->m_pTaskNext)
|
|
if (pTaskCurrent->m_hTask == hTask)
|
|
return pTaskCurrent;
|
|
return NULL;
|
|
}
|
|
|
|
/* - - - - - - - - */
|
|
|
|
IClassFactory FAR* CTask::LookupClass(
|
|
CTask FAR* pTask,
|
|
REFCLSID rclsid,
|
|
HINSTANCE hInstance)
|
|
{
|
|
DllEntry FAR* pDllEntry;
|
|
|
|
for (pDllEntry = pTask->m_pDllEntry; pDllEntry; pDllEntry = pDllEntry->pNextDll) {
|
|
if ((hInstance == pDllEntry->hInstance) &&
|
|
(rclsid == pDllEntry->clsid))
|
|
return pDllEntry->pFactory;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/* - - - - - - - - */
|
|
|
|
void CTask::FreeUnusedLibraries(CTask FAR* pTask)
|
|
{
|
|
DllEntry FAR* pDllEntryPrev;
|
|
DllEntry FAR* pDllEntryCur;
|
|
|
|
pDllEntryPrev = NULL;
|
|
pDllEntryCur = pTask->m_pDllEntry;
|
|
for (; pDllEntryCur;)
|
|
if (pDllEntryCur->lpfnCanUnloadNow() == S_OK) {
|
|
pDllEntryCur->pFactory->Release();
|
|
FreeModule(pDllEntryCur->hInstance);
|
|
if (pDllEntryPrev == NULL) {
|
|
pTask->m_pDllEntry = pDllEntryCur->pNextDll;
|
|
pTask->m_pMalloc->Free(pDllEntryCur);
|
|
pDllEntryCur = pTask->m_pDllEntry;
|
|
} else {
|
|
pDllEntryPrev->pNextDll = pDllEntryCur->pNextDll;
|
|
pTask->m_pMalloc->Free(pDllEntryCur);
|
|
pDllEntryCur = pDllEntryPrev->pNextDll;
|
|
}
|
|
|
|
} else {
|
|
pDllEntryPrev = pDllEntryCur;
|
|
pDllEntryCur = pDllEntryCur->pNextDll;
|
|
}
|
|
}
|
|
|
|
/* - - - - - - - - */
|
|
|
|
HRESULT CTask::AddTaskDll(
|
|
REFCLSID rclsid,
|
|
IClassFactory FAR* pFactory,
|
|
LPFNCANUNLOADNOW lpfnCanUnloadNow,
|
|
HINSTANCE hInstance)
|
|
{
|
|
DllEntry FAR* pDllEntry;
|
|
|
|
pDllEntry = (DllEntry FAR*)(m_pMalloc->Alloc(sizeof(DllEntry)));
|
|
if (!pDllEntry)
|
|
return ResultFromScode(E_OUTOFMEMORY);
|
|
pDllEntry->clsid = rclsid;
|
|
pDllEntry->pFactory = pFactory;
|
|
pDllEntry->lpfnCanUnloadNow = lpfnCanUnloadNow;
|
|
pDllEntry->hInstance = hInstance;
|
|
pDllEntry->pNextDll = m_pDllEntry;
|
|
m_pDllEntry = pDllEntry;
|
|
return NULL;
|
|
}
|
|
|
|
/* - - - - - - - - */
|
|
|
|
CTask::CTask(
|
|
HTASK hTask,
|
|
IMalloc FAR* pMalloc)
|
|
{
|
|
m_refs = 1;
|
|
m_hTask = hTask;
|
|
m_pMalloc = pMalloc;
|
|
m_pMalloc->AddRef();
|
|
m_pDllEntry = NULL;
|
|
m_pTaskNext = pTaskList;
|
|
pTaskList = this;
|
|
}
|
|
|
|
CTask::AddRef(void)
|
|
{
|
|
++m_refs;
|
|
|
|
return 0;
|
|
}
|
|
|
|
CTask::Release(void)
|
|
{
|
|
if (m_refs == 1)
|
|
delete this;
|
|
else
|
|
--m_refs;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* - - - - - - - - */
|
|
|
|
CTask::~CTask(
|
|
void)
|
|
{
|
|
for (; m_pDllEntry;) {
|
|
DllEntry FAR* pDllEntry;
|
|
|
|
m_pDllEntry->pFactory->Release();
|
|
FreeModule(m_pDllEntry->hInstance);
|
|
pDllEntry = m_pDllEntry->pNextDll;
|
|
m_pMalloc->Free(m_pDllEntry);
|
|
m_pDllEntry = pDllEntry;
|
|
}
|
|
m_pMalloc->Release();
|
|
if (this == pTaskList)
|
|
pTaskList = m_pTaskNext;
|
|
else {
|
|
CTask FAR* pTask;
|
|
|
|
for (pTask = pTaskList; pTask->m_pTaskNext != this; pTask = pTask->m_pTaskNext)
|
|
;
|
|
pTask->m_pTaskNext = m_pTaskNext;
|
|
}
|
|
}
|
|
|
|
/* - - - - - - - - */
|
|
|
|
// converts GUID into (...) form without leading identifier; no errors
|
|
INTERNAL_(int) StringFromGUID2(REFGUID rguid, LPSTR lpsz)
|
|
{
|
|
wsprintf(lpsz, "{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
|
|
rguid.Data1, rguid.Data2, rguid.Data3,
|
|
rguid.Data4[0], rguid.Data4[1],
|
|
rguid.Data4[2], rguid.Data4[3],
|
|
rguid.Data4[4], rguid.Data4[5],
|
|
rguid.Data4[6], rguid.Data4[7]);
|
|
|
|
return _fstrlen(lpsz) + 1;
|
|
}
|
|
|
|
/* - - - - - - - - */
|
|
|
|
#define GUIDSTR_MAX (1+ 3*sizeof(GUID) +sizeof(GUID)-1 +1 +1)
|
|
#define CLSIDSTR_MAX (sizeof(aszCLSID)-1+GUIDSTR_MAX)
|
|
|
|
// alternate to StringFromCLSID which puts string in caller-supplied buffer;
|
|
// returns the amount of data copied including the zero terminator; 0 if none.
|
|
STDAPI_(int) StringFromCLSID2(REFCLSID rclsid, LPSTR lpsz, int cbMax)
|
|
{
|
|
if (cbMax < CLSIDSTR_MAX)
|
|
return 0;
|
|
|
|
return sizeof(aszCLSID)-1 +
|
|
StringFromGUID2(rclsid, _fstrchr(_fstrcpy(lpsz, aszCLSID),'\0'));
|
|
}
|
|
|
|
/* - - - - - - - - */
|
|
|
|
static LONG RegQueryClassValue(REFCLSID rclsid, LPCSTR lpszSubKey, LPSTR lpszValue, int cbMax)
|
|
{
|
|
char szKey[256];
|
|
int cbClsid;
|
|
LONG cbValue = cbMax;
|
|
|
|
// translate rclsid into string
|
|
cbClsid = StringFromCLSID2(rclsid, &szKey[0], sizeof(szKey));
|
|
|
|
szKey[cbClsid-1] = '\\';
|
|
_fstrcpy(&szKey[cbClsid], lpszSubKey);
|
|
|
|
return RegQueryValue(HKEY_CLASSES_ROOT, szKey, lpszValue, &cbValue);
|
|
}
|
|
|
|
/* - - - - - - - - */
|
|
|
|
STDAPI CoGetClassObject(
|
|
REFCLSID rclsid,
|
|
DWORD dwClsContext,
|
|
LPVOID pvReserved,
|
|
REFIID riid,
|
|
void FAR* FAR* ppv)
|
|
{
|
|
char aszServer[256];
|
|
HTASK htask;
|
|
CTask FAR* pTask;
|
|
IClassFactory FAR* pFactory;
|
|
HINSTANCE hInstance;
|
|
HRESULT hr;
|
|
|
|
if (pvReserved != NULL)
|
|
return ResultFromScode(E_INVALIDARG);
|
|
if (!(dwClsContext & CLSCTX_INPROC_SERVER))
|
|
return ResultFromScode(E_INVALIDARG);
|
|
if (!(pTask = CTask::LookupTask(htask)))
|
|
return ResultFromScode(E_UNEXPECTED);
|
|
if (RegQueryClassValue(rclsid, aszRegServerKey, aszServer, sizeof(aszServer)) != 0)
|
|
return ResultFromScode(E_UNEXPECTED);
|
|
hInstance = LoadLibrary(aszServer);
|
|
if (hInstance < HINSTANCE_ERROR)
|
|
return ResultFromScode(E_UNEXPECTED);
|
|
if (pFactory = CTask::LookupClass(pTask, rclsid, hInstance))
|
|
hr = pFactory->QueryInterface(riid, ppv);
|
|
else {
|
|
LPFNCANUNLOADNOW lpfnCanUnloadNow;
|
|
LPFNGETCLASSOBJECT lpfnGetClassObject;
|
|
|
|
lpfnCanUnloadNow = (LPFNCANUNLOADNOW)GetProcAddress(hInstance, aszServerQuery);
|
|
if ((lpfnGetClassObject = (LPFNGETCLASSOBJECT)GetProcAddress(hInstance, aszServerEntry)) != NULL) {
|
|
IMalloc FAR* pMalloc;
|
|
|
|
pMalloc = pTask->QueryMalloc();
|
|
hr = (*lpfnGetClassObject)(rclsid, IID_IClassFactory, (void FAR* FAR*)&pFactory);
|
|
if (!hr) {
|
|
hr = pTask->AddTaskDll(rclsid, pFactory, lpfnCanUnloadNow, hInstance);
|
|
if (!hr)
|
|
return pFactory->QueryInterface(riid, ppv);
|
|
pFactory->Release();
|
|
}
|
|
} else
|
|
hr = ResultFromScode(E_UNEXPECTED);
|
|
}
|
|
FreeLibrary(hInstance);
|
|
return hr;
|
|
}
|
|
|
|
/* - - - - - - - - */
|
|
|
|
STDAPI CoCreateInstance(
|
|
REFCLSID rclsid,
|
|
IUnknown FAR* pUnkOuter,
|
|
DWORD dwClsContext,
|
|
REFIID riid,
|
|
LPVOID FAR* ppv)
|
|
{
|
|
HRESULT hr;
|
|
IClassFactory FAR* pFactory;
|
|
|
|
hr = CoGetClassObject(rclsid, dwClsContext, NULL, IID_IClassFactory, (void FAR* FAR*)&pFactory);
|
|
if (!hr) {
|
|
hr = pFactory->CreateInstance(pUnkOuter, riid, ppv);
|
|
pFactory->Release();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
/* - - - - - - - - */
|
|
|
|
STDAPI GetStandardTaskMalloc(
|
|
IMalloc FAR* FAR* ppMalloc)
|
|
{
|
|
v_stdMalloc.AddRef();
|
|
*ppMalloc = &v_stdMalloc;
|
|
return NULL;
|
|
}
|
|
|
|
/* - - - - - - - - */
|
|
|
|
STDAPI CoGetMalloc(
|
|
DWORD dwMemContext,
|
|
IMalloc FAR* FAR* ppMalloc)
|
|
{
|
|
HTASK htask;
|
|
CTask FAR* pTask;
|
|
IMalloc FAR* pMalloc;
|
|
|
|
if (dwMemContext != MEMCTX_TASK)
|
|
return ResultFromScode(E_UNEXPECTED);
|
|
if (!(pTask = CTask::LookupTask(htask)))
|
|
return ResultFromScode(E_UNEXPECTED);
|
|
pMalloc = pTask->QueryMalloc();
|
|
pMalloc->AddRef();
|
|
*ppMalloc = pMalloc;
|
|
return NULL;
|
|
}
|
|
|
|
/* - - - - - - - - */
|
|
|
|
STDAPI CoInitialize(
|
|
IMalloc FAR* pMalloc)
|
|
{
|
|
HTASK htask;
|
|
CTask FAR* pTask;
|
|
|
|
if (!pMalloc)
|
|
pMalloc = (IMalloc FAR *) &v_stdMalloc;
|
|
if (pTask = CTask::LookupTask(htask)) {
|
|
pTask->AddRef();
|
|
return ResultFromScode(S_FALSE);
|
|
}
|
|
pTask = new FAR CTask(htask, pMalloc);
|
|
return pTask ? NULL : ResultFromScode(E_OUTOFMEMORY);
|
|
}
|
|
|
|
/* - - - - - - - - */
|
|
|
|
STDAPI_(void) CoUninitialize(
|
|
void)
|
|
{
|
|
HTASK htask;
|
|
CTask FAR* pTask;
|
|
|
|
if (pTask = CTask::LookupTask(htask))
|
|
pTask->Release();
|
|
}
|
|
|
|
/* - - - - - - - - */
|
|
|
|
STDAPI_(void) MyFreeUnusedLibraries(
|
|
void)
|
|
{
|
|
HTASK htask;
|
|
CTask FAR* pTask;
|
|
|
|
if (pTask = CTask::LookupTask(htask))
|
|
CTask::FreeUnusedLibraries(pTask);
|
|
}
|
|
|
|
/* - - - - - - - - */
|
|
|
|
STDAPI_(BOOL) IsEqualGUID(REFGUID guid1, REFGUID guid2)
|
|
{
|
|
return guid1 == guid2;
|
|
}
|
|
|