You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
251 lines
6.5 KiB
251 lines
6.5 KiB
#include <windows.h>
|
|
#include "comdll.h"
|
|
#include "ddraw.h"
|
|
#include "ddrawex.h"
|
|
|
|
|
|
|
|
|
|
UINT g_cRefDll = 0; // reference count for this DLL
|
|
HANDLE g_hinst = NULL; // HMODULE for this DLL
|
|
|
|
|
|
|
|
typedef struct {
|
|
const IClassFactoryVtbl *cf;
|
|
const CLSID *pclsid;
|
|
HRESULT (STDMETHODCALLTYPE *pfnCreate)(IUnknown *, REFIID, void **);
|
|
HRESULT (STDMETHODCALLTYPE *pfnRegUnReg)(BOOL bReg, HKEY hkCLSID, LPCSTR pszCLSID, LPCSTR pszModule);
|
|
} OBJ_ENTRY;
|
|
|
|
extern const IClassFactoryVtbl c_CFVtbl; // forward
|
|
|
|
//
|
|
// we always do a linear search here so put your most often used things first
|
|
//
|
|
const OBJ_ENTRY c_clsmap[] = {
|
|
{&c_CFVtbl, &CLSID_DirectDrawFactory, DirectDrawFactory_CreateInstance, NULL},
|
|
// add more entries here
|
|
{ NULL, NULL, NULL, NULL }
|
|
};
|
|
|
|
// static class factory (no allocs!)
|
|
|
|
STDMETHODIMP CClassFactory_QueryInterface(IClassFactory *pcf, REFIID riid, void **ppvObj)
|
|
{
|
|
if (IsEqualIID(riid, &IID_IClassFactory) || IsEqualIID(riid, &IID_IUnknown))
|
|
{
|
|
*ppvObj = (void *)pcf;
|
|
}
|
|
else
|
|
{
|
|
*ppvObj = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
DllAddRef();
|
|
return NOERROR;
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CClassFactory_AddRef(IClassFactory *pcf)
|
|
{
|
|
DllAddRef();
|
|
return 2;
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CClassFactory_Release(IClassFactory *pcf)
|
|
{
|
|
DllRelease();
|
|
return 1;
|
|
}
|
|
|
|
STDMETHODIMP CClassFactory_CreateInstance(IClassFactory *pcf, IUnknown *punkOuter, REFIID riid, void **ppvObject)
|
|
{
|
|
OBJ_ENTRY *this = IToClass(OBJ_ENTRY, cf, pcf);
|
|
return this->pfnCreate(punkOuter, riid, ppvObject);
|
|
}
|
|
|
|
STDMETHODIMP CClassFactory_LockServer(IClassFactory *pcf, BOOL fLock)
|
|
{
|
|
if (fLock)
|
|
DllAddRef();
|
|
else
|
|
DllRelease();
|
|
return S_OK;
|
|
}
|
|
|
|
const IClassFactoryVtbl c_CFVtbl = {
|
|
CClassFactory_QueryInterface, CClassFactory_AddRef, CClassFactory_Release,
|
|
CClassFactory_CreateInstance,
|
|
CClassFactory_LockServer
|
|
};
|
|
|
|
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppv)
|
|
{
|
|
if (IsEqualIID(riid, &IID_IClassFactory) || IsEqualIID(riid, &IID_IUnknown))
|
|
{
|
|
const OBJ_ENTRY *pcls;
|
|
for (pcls = c_clsmap; pcls->pclsid; pcls++)
|
|
{
|
|
if (IsEqualIID(rclsid, pcls->pclsid))
|
|
{
|
|
*ppv = (void *)&(pcls->cf);
|
|
DllAddRef(); // Class Factory keeps dll in memory
|
|
return NOERROR;
|
|
}
|
|
}
|
|
}
|
|
// failure
|
|
*ppv = NULL;
|
|
return CLASS_E_CLASSNOTAVAILABLE;;
|
|
}
|
|
|
|
STDAPI_(void) DllAddRef()
|
|
{
|
|
InterlockedIncrement(&g_cRefDll);
|
|
}
|
|
|
|
STDAPI_(void) DllRelease()
|
|
{
|
|
InterlockedDecrement(&g_cRefDll);
|
|
}
|
|
|
|
STDAPI DllCanUnloadNow(void)
|
|
{
|
|
return g_cRefDll == 0 ? S_OK : S_FALSE;
|
|
}
|
|
|
|
STDAPI_(BOOL) DllEntryPoint(HANDLE hDll, DWORD dwReason, LPVOID lpReserved)
|
|
{
|
|
if (dwReason == DLL_PROCESS_ATTACH)
|
|
{
|
|
g_hinst = hDll;
|
|
DisableThreadLibraryCalls(hDll);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
STDAPI_(void) TStringFromGUID(const GUID* pguid, LPTSTR pszBuf)
|
|
{
|
|
wsprintf(pszBuf, TEXT("{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}"), pguid->Data1,
|
|
pguid->Data2, pguid->Data3, pguid->Data4[0], pguid->Data4[1], pguid->Data4[2],
|
|
pguid->Data4[3], pguid->Data4[4], pguid->Data4[5], pguid->Data4[6], pguid->Data4[7]);
|
|
}
|
|
|
|
#ifndef UNICODE
|
|
STDAPI_(void) WStringFromGUID(const GUID* pguid, LPWSTR pszBuf)
|
|
{
|
|
char szAnsi[40];
|
|
TStringFromGUID(pguid, szAnsi);
|
|
MultiByteToWideChar(CP_ACP, 0, szAnsi, -1, pszBuf, sizeof(szAnsi));
|
|
}
|
|
#endif
|
|
|
|
|
|
BOOL DeleteKeyAndSubKeys(HKEY hkIn, LPCTSTR pszSubKey)
|
|
{
|
|
HKEY hk;
|
|
TCHAR szTmp[MAX_PATH];
|
|
DWORD dwTmpSize;
|
|
long l;
|
|
BOOL f;
|
|
|
|
l = RegOpenKeyEx(hkIn, pszSubKey, 0, KEY_ALL_ACCESS, &hk);
|
|
if (l != ERROR_SUCCESS)
|
|
return FALSE;
|
|
|
|
// loop through all subkeys, blowing them away.
|
|
//
|
|
f = TRUE;
|
|
while (f) {
|
|
dwTmpSize = MAX_PATH;
|
|
l = RegEnumKeyEx(hk, 0, szTmp, &dwTmpSize, 0, NULL, NULL, NULL);
|
|
if (l != ERROR_SUCCESS)
|
|
break;
|
|
f = DeleteKeyAndSubKeys(hk, szTmp);
|
|
}
|
|
|
|
// there are no subkeys left, [or we'll just generate an error and return FALSE].
|
|
// let's go blow this dude away.
|
|
//
|
|
RegCloseKey(hk);
|
|
l = RegDeleteKey(hkIn, pszSubKey);
|
|
|
|
return (l == ERROR_SUCCESS) ? TRUE : FALSE;
|
|
}
|
|
|
|
#define INPROCSERVER32 TEXT("InProcServer32")
|
|
#define CLSID TEXT("CLSID")
|
|
#define THREADINGMODEL TEXT("ThreadingModel")
|
|
#define TMBOTH TEXT("Both")
|
|
|
|
STDAPI DllRegisterServer(void)
|
|
{
|
|
const OBJ_ENTRY *pcls;
|
|
TCHAR szPath[MAX_PATH];
|
|
|
|
GetModuleFileName(g_hinst, szPath, ARRAYSIZE(szPath)); // get path to this DLL
|
|
|
|
for (pcls = c_clsmap; pcls->pclsid; pcls++)
|
|
{
|
|
HKEY hkCLSID;
|
|
if (RegOpenKey(HKEY_CLASSES_ROOT, CLSID, &hkCLSID) == ERROR_SUCCESS)
|
|
{
|
|
HKEY hkOurs;
|
|
LONG err;
|
|
TCHAR szGUID[80];
|
|
|
|
TStringFromGUID(pcls->pclsid, szGUID);
|
|
|
|
err = RegCreateKey(hkCLSID, szGUID, &hkOurs);
|
|
if (err == ERROR_SUCCESS)
|
|
{
|
|
HKEY hkInproc;
|
|
err = RegCreateKey(hkOurs, INPROCSERVER32, &hkInproc);
|
|
if (err == ERROR_SUCCESS)
|
|
{
|
|
err = RegSetValueEx(hkInproc, NULL, 0, REG_SZ, (LPBYTE)szPath, (lstrlen(szPath) + 1) * sizeof(TCHAR));
|
|
if (err == ERROR_SUCCESS)
|
|
{
|
|
err = RegSetValueEx(hkInproc, THREADINGMODEL, 0, REG_SZ, (LPBYTE)TMBOTH, sizeof(TMBOTH));
|
|
}
|
|
RegCloseKey(hkInproc);
|
|
}
|
|
|
|
if (pcls->pfnRegUnReg)
|
|
pcls->pfnRegUnReg(TRUE, hkOurs, szGUID, szPath);
|
|
|
|
RegCloseKey(hkOurs);
|
|
}
|
|
RegCloseKey(hkCLSID);
|
|
|
|
if (err != ERROR_SUCCESS)
|
|
return HRESULT_FROM_WIN32(err);
|
|
}
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
STDAPI DllUnregisterServer(void)
|
|
{
|
|
const OBJ_ENTRY *pcls;
|
|
for (pcls = c_clsmap; pcls->pclsid; pcls++)
|
|
{
|
|
HKEY hkCLSID;
|
|
if (RegOpenKey(HKEY_CLASSES_ROOT, CLSID, &hkCLSID) == ERROR_SUCCESS)
|
|
{
|
|
TCHAR szGUID[80];
|
|
|
|
TStringFromGUID(pcls->pclsid, szGUID);
|
|
|
|
DeleteKeyAndSubKeys(hkCLSID, szGUID);
|
|
|
|
RegCloseKey(hkCLSID);
|
|
|
|
if (pcls->pfnRegUnReg)
|
|
pcls->pfnRegUnReg(FALSE, NULL, szGUID, NULL);
|
|
|
|
}
|
|
}
|
|
return S_OK;
|
|
}
|