/* * Hello Object DLL Self-Registering Server * Heavily modified from: */ /* * SELFREG.CPP * Server Self-Registrtation Utility, Chapter 5 * * Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved * * Kraig Brockschmidt, Microsoft * Internet : kraigb@microsoft.com * Compuserve: >INTERNET:kraigb@microsoft.com */ import core.stdc.stdio; import core.stdc.stdlib; import core.stdc.string; import std.string; import core.sys.windows.com; import core.sys.windows.winbase; import core.sys.windows.windef; import core.sys.windows.winreg; import chello; // This class factory object creates Hello objects. class CHelloClassFactory : ComObject, IClassFactory { public: this() { printf("CHelloClassFactory()\n"); } ~this() { printf("~CHelloClassFactory()"); } extern (Windows) : // IUnknown members override HRESULT QueryInterface(const (IID)*riid, LPVOID *ppv) { printf("CHelloClassFactory.QueryInterface()\n"); if (IID_IUnknown == *riid) { printf("IUnknown\n"); *ppv = cast(void*) cast(IUnknown) this; } else if (IID_IClassFactory == *riid) { printf("IClassFactory\n"); *ppv = cast(void*) cast(IClassFactory) this; } else { *ppv = null; return E_NOINTERFACE; } AddRef(); return NOERROR; } // IClassFactory members override HRESULT CreateInstance(IUnknown pUnkOuter, IID*riid, LPVOID *ppvObj) { CHello pObj; HRESULT hr; printf("CHelloClassFactory.CreateInstance()\n"); *ppvObj = null; hr = E_OUTOFMEMORY; // Verify that a controlling unknown asks for IUnknown if (null !is pUnkOuter && memcmp(&IID_IUnknown, riid, IID.sizeof)) return CLASS_E_NOAGGREGATION; // Create the object passing function to notify on destruction. pObj = new CHello(pUnkOuter, &ObjectDestroyed); if (!pObj) return hr; if (pObj.Init()) { hr = pObj.QueryInterface(riid, ppvObj); } // Kill the object if initial creation or Init failed. if (FAILED(hr)) delete pObj; else g_cObj++; return hr; } HRESULT LockServer(BOOL fLock) { printf("CHelloClassFactory.LockServer(%d)\n", fLock); if (fLock) g_cLock++; else g_cLock--; return NOERROR; } }; // Count number of objects and number of locks. ULONG g_cObj =0; ULONG g_cLock=0; import core.sys.windows.dll; HINSTANCE g_hInst; extern (Windows): BOOL DllMain(HINSTANCE hInstance, ULONG ulReason, LPVOID pvReserved) { switch (ulReason) { case DLL_PROCESS_ATTACH: g_hInst = hInstance; dll_process_attach( hInstance, true ); printf("ATTACH\n"); break; case DLL_PROCESS_DETACH: printf("DETACH\n"); dll_process_detach( hInstance, true ); break; case DLL_THREAD_ATTACH: dll_thread_attach( true, true ); printf("THREAD_ATTACH\n"); break; case DLL_THREAD_DETACH: dll_thread_detach( true, true ); printf("THREAD_DETACH\n"); break; default: assert(0); } return true; } /* * DllGetClassObject * * Purpose: * Provides an IClassFactory for a given CLSID that this DLL is * registered to support. This DLL is placed under the CLSID * in the registration database as the InProcServer. * * Parameters: * clsID REFCLSID that identifies the class factory * desired. Since this parameter is passed this * DLL can handle any number of objects simply * by returning different class factories here * for different CLSIDs. * * riid REFIID specifying the interface the caller wants * on the class object, usually IID_ClassFactory. * * ppv LPVOID * in which to return the interface * pointer. * * Return Value: * HRESULT NOERROR on success, otherwise an error code. */ HRESULT DllGetClassObject(CLSID*rclsid, IID*riid, LPVOID *ppv) { HRESULT hr; CHelloClassFactory pObj; printf("DllGetClassObject()\n"); if (CLSID_Hello != *rclsid) return E_FAIL; pObj = new CHelloClassFactory(); if (!pObj) return E_OUTOFMEMORY; hr = pObj.QueryInterface(riid, ppv); if (FAILED(hr)) delete pObj; return hr; } /* * Answers if the DLL can be freed, that is, if there are no * references to anything this DLL provides. * * Return Value: * BOOL true if nothing is using us, false otherwise. */ HRESULT DllCanUnloadNow() { SCODE sc; printf("DllCanUnloadNow()\n"); // Any locks or objects? sc = (0 == g_cObj && 0 == g_cLock) ? S_OK : S_FALSE; return sc; } /* * Instructs the server to create its own registry entries * * Return Value: * HRESULT NOERROR if registration successful, error * otherwise. */ HRESULT DllRegisterServer() { char[128] szID; char[128] szCLSID; char[512] szModule; printf("DllRegisterServer()\n"); // Create some base key strings. StringFromGUID2(&CLSID_Hello, cast(LPOLESTR) szID, 128); unicode2ansi(szID.ptr); strcpy(szCLSID.ptr, "CLSID\\"); strcat(szCLSID.ptr, szID.ptr); // Create ProgID keys SetKeyAndValue("Hello1.0", null, "Hello Object"); SetKeyAndValue("Hello1.0", "CLSID", szID.ptr); // Create VersionIndependentProgID keys SetKeyAndValue("Hello", null, "Hello Object"); SetKeyAndValue("Hello", "CurVer", "Hello1.0"); SetKeyAndValue("Hello", "CLSID", szID.ptr); // Create entries under CLSID SetKeyAndValue(szCLSID.ptr, null, "Hello Object"); SetKeyAndValue(szCLSID.ptr, "ProgID", "Hello1.0"); SetKeyAndValue(szCLSID.ptr, "VersionIndependentProgID", "Hello"); SetKeyAndValue(szCLSID.ptr, "NotInsertable", null); GetModuleFileNameA(g_hInst, szModule.ptr, szModule.length); SetKeyAndValue(szCLSID.ptr, "InprocServer32", szModule.ptr); return NOERROR; } /* * Purpose: * Instructs the server to remove its own registry entries * * Return Value: * HRESULT NOERROR if registration successful, error * otherwise. */ HRESULT DllUnregisterServer() { char[128] szID; char[128] szCLSID; char[256] szTemp; printf("DllUnregisterServer()\n"); // Create some base key strings. StringFromGUID2(&CLSID_Hello, cast(LPOLESTR) szID, 128); unicode2ansi(szID.ptr); strcpy(szCLSID.ptr, "CLSID\\"); strcat(szCLSID.ptr, szID.ptr); RegDeleteKeyA(HKEY_CLASSES_ROOT, "Hello\\CurVer"); RegDeleteKeyA(HKEY_CLASSES_ROOT, "Hello\\CLSID"); RegDeleteKeyA(HKEY_CLASSES_ROOT, "Hello"); RegDeleteKeyA(HKEY_CLASSES_ROOT, "Hello1.0\\CLSID"); RegDeleteKeyA(HKEY_CLASSES_ROOT, "Hello1.0"); strcpy(szTemp.ptr, szCLSID.ptr); strcat(szTemp.ptr, "\\"); strcat(szTemp.ptr, "ProgID"); RegDeleteKeyA(HKEY_CLASSES_ROOT, szTemp.ptr); strcpy(szTemp.ptr, szCLSID.ptr); strcat(szTemp.ptr, "\\"); strcat(szTemp.ptr, "VersionIndependentProgID"); RegDeleteKeyA(HKEY_CLASSES_ROOT, szTemp.ptr); strcpy(szTemp.ptr, szCLSID.ptr); strcat(szTemp.ptr, "\\"); strcat(szTemp.ptr, "NotInsertable"); RegDeleteKeyA(HKEY_CLASSES_ROOT, szTemp.ptr); strcpy(szTemp.ptr, szCLSID.ptr); strcat(szTemp.ptr, "\\"); strcat(szTemp.ptr, "InprocServer32"); RegDeleteKeyA(HKEY_CLASSES_ROOT, szTemp.ptr); RegDeleteKeyA(HKEY_CLASSES_ROOT, szCLSID.ptr); return NOERROR; } /* * SetKeyAndValue * * Purpose: * Private helper function for DllRegisterServer that creates * a key, sets a value, and closes that key. * * Parameters: * pszKey LPTSTR to the name of the key * pszSubkey LPTSTR ro the name of a subkey * pszValue LPTSTR to the value to store * * Return Value: * BOOL true if successful, false otherwise. */ BOOL SetKeyAndValue(LPCSTR pszKey, LPCSTR pszSubkey, LPCSTR pszValue) { HKEY hKey; char[256] szKey; BOOL result; strcpy(szKey.ptr, pszKey); if (pszSubkey) { strcat(szKey.ptr, "\\"); strcat(szKey.ptr, pszSubkey); } result = true; int regresult = RegCreateKeyExA(HKEY_CLASSES_ROOT, szKey.ptr, 0, null, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, null, &hKey, null); if (ERROR_SUCCESS != regresult) { result = false; // If the value is 5, you'll need to run the program with Administrator privileges printf("RegCreateKeyExA() failed with 0x%x\n", regresult); } else { if (null != pszValue) { if (RegSetValueExA(hKey, null, 0, REG_SZ, cast(BYTE *) pszValue, cast(int)((strlen(pszValue) + 1) * char.sizeof)) != ERROR_SUCCESS) result = false; } if (RegCloseKey(hKey) != ERROR_SUCCESS) result = false; } if (!result) printf("SetKeyAndValue() failed\n"); return result; } /* * ObjectDestroyed * * Purpose: * Function for the Hello object to call when it gets destroyed. * Since we're in a DLL we only track the number of objects here, * letting DllCanUnloadNow take care of the rest. */ extern (D) void ObjectDestroyed() { printf("ObjectDestroyed()\n"); g_cObj--; } void unicode2ansi(char *s) { wchar *w; for (w = cast(wchar *) s; *w; w++) *s++ = cast(char)*w; *s = 0; }