#include #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; }