dllmain.cpp

#include "headers.h"

//
// Helper methods
//

static long g_cReferences = 0;
static long g_cLocks = 0;
static HMODULE g_hmodule = NULL;

static const WCHAR * pszEngineName = L"SimpleScript";
static const WCHAR * pszOLEScript = L"OLEScript";
static const WCHAR * pszCLSID = L"CLSID";
static const WCHAR * pszProgID = L"ProgID";
static const WCHAR * pszDescription = L"SimpleScript Language Engine";
static const WCHAR * pszInprocServer = L"InprocServer32";
static const WCHAR * pszActiveScripting = L"Active Scripting Engine";
static const WCHAR * pszParsing = L"Active Scripting Engine with Parsing";
static const WCHAR * pszThreadingModel = L"ThreadingModel";
static const WCHAR * pszBoth = L"Both";
static const WCHAR * pszImplementedCats = L"Implemented Categories";

void DLLAddRef(void)
{
InterlockedIncrement(&g_cReferences);
}

void DLLRelease(void)
{
InterlockedDecrement(&g_cReferences);
}

void DLLAddLock(void)
{
InterlockedIncrement(&g_cLocks);
}

void DLLReleaseLock(void)
{
InterlockedDecrement(&g_cLocks);
}

static BOOL AttachProcess(HMODULE hmodule)
{
g_hmodule = hmodule;
return TRUE;
}

static BOOL DetachProcess()
{
return TRUE;
}

static BOOL AttachThread()
{
return TRUE;
}

static BOOL DetachThread()
{
return TRUE;
}

static HRESULT OpenKey(HKEY hkeyParent, const WCHAR * pszKey, HKEY * phkey)
{
Assert(hkeyParent != NULL);
AssertOutPtr(phkey);

    LONG err;
err = RegOpenKeyExW(hkeyParent, pszKey, 0, KEY_ALL_ACCESS, phkey);
return HRESULT_FROM_WIN32(err);
}

static HRESULT CreateKey(HKEY hkeyParent, const WCHAR * pszKey, HKEY * phkey = NULL)
{
Assert(hkeyParent != NULL);

    LONG err;
HKEY hkey = NULL;
HRESULT hr;

    err = RegCreateKeyExW(hkeyParent, pszKey, 0, NULL,
REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, NULL);
hr = HRESULT_FROM_WIN32(err);
if (FAILED(hr))
goto LError;

    if (phkey != NULL)
{
*phkey = hkey;
hkey = NULL;
}

    hr = S_OK;

LError:

    if (NULL != hkey)
RegCloseKey(hkey);

    return hr;
}

static HRESULT SetValue(HKEY hkey, const WCHAR * pszName, const WCHAR * pszValue)
{
Assert(hkey != NULL);
AssertReadStringN(pszName);
AssertReadString(pszValue);

    LONG err;

    err = RegSetValueExW(hkey, pszName, 0, REG_SZ,
(const BYTE *) pszValue, (wcslen(pszValue) + 1) * sizeof WCHAR);

    return HRESULT_FROM_WIN32(err);
}

//
// Public entrypoints
//

STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void * * ppv)
{
HRESULT hr;
ClassFactory * pFactory = NULL;

    if (NULL == ppv)
return E_POINTER;

    AssertOutPtr(ppv);

    *ppv = NULL;

    if (!IsEqualCLSID(rclsid, CLSID_SimpleScript))
return E_INVALIDARG;

    hr = ClassFactory::Create(&pFactory);
if (FAILED(hr))
goto LError;

    hr = pFactory->QueryInterface(riid, ppv);
if (FAILED(hr))
goto LError;

    hr = S_OK;

LError:

    if (NULL != pFactory)
pFactory->Release();

    return hr;
}

STDAPI DllUnregisterServer(void)
{
// This method fails silently.

    HRESULT hr;

HKEY hkeyCLSID;
HKEY hkeyClassId;
HKEY hkeySimpleScript;
ICatRegister * pCategoryRegister;

    const DWORD cchClassId = 39;
WCHAR pszClassId[cchClassId];
CATID catids[2];

    // HKCRCLSID
hr = OpenKey(HKEY_CLASSES_ROOT, pszCLSID, &hkeyCLSID);
if (SUCCEEDED(hr))
{
StringFromGUID2(CLSID_SimpleScript, pszClassId, cchClassId);
// HKCRCLSID{...}
hr = OpenKey(hkeyCLSID, pszClassId, &hkeyClassId);
if (SUCCEEDED(hr))
{
hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr,
NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pCategoryRegister);
if (SUCCEEDED(hr))
{
catids[0] = CATID_ActiveScript;
catids[1] = CATID_ActiveScriptParse;
pCategoryRegister->UnRegisterClassImplCategories(CLSID_SimpleScript, 2, catids);
pCategoryRegister->Release();
}
RegDeleteKeyW(hkeyClassId, pszImplementedCats);
RegDeleteKeyW(hkeyClassId, pszOLEScript);
RegDeleteKeyW(hkeyClassId, pszProgID);
RegDeleteKeyW(hkeyClassId, pszInprocServer);
RegCloseKey(hkeyClassId);
RegDeleteKeyW(hkeyCLSID, pszClassId);
}
RegCloseKey(hkeyCLSID);
}

    hr = OpenKey(HKEY_CLASSES_ROOT, pszEngineName, &hkeySimpleScript);
if (SUCCEEDED(hr))
{
RegDeleteKeyW(hkeySimpleScript, pszCLSID);
RegDeleteKeyW(hkeySimpleScript, pszOLEScript);
RegCloseKey(hkeySimpleScript);
RegDeleteKeyW(HKEY_CLASSES_ROOT, pszEngineName);
}

    return S_OK;
}

STDAPI DllRegisterServer(void)
{
HRESULT hr;
DWORD error;

    HKEY hkeySimpleScript = NULL;
HKEY hkeyCLSID1 = NULL;
HKEY hkeyCLSID2 = NULL;
HKEY hkeyClassId = NULL;
HKEY hkeyProgID = NULL;
HKEY hkeyInprocServer = NULL;
ICatRegister * pCategoryRegister = NULL;

CATEGORYINFO catinfo[2];

    const DWORD cchDllPathMax = MAX_PATH + 1;
WCHAR pszDllPath[cchDllPathMax];
const DWORD cchClassId = 39;
WCHAR pszClassId[cchClassId];
DWORD cchDllPath;
CATID catids[2];

DllUnregisterServer(); // Ignore errors

    // HKCRSimpleScript
hr = CreateKey(HKEY_CLASSES_ROOT, pszEngineName, &hkeySimpleScript);
if (FAILED(hr))
goto LError;

    // HKCRSimpleScriptOLEScript
hr = CreateKey(hkeySimpleScript, pszOLEScript);
if (FAILED(hr))
goto LError;

    // HKCRSimpleScript(Default) = "SimpleScript Language Engine"
hr = SetValue(hkeySimpleScript, NULL, pszDescription);
if (FAILED(hr))
goto LError;

    // HKCRSimpleScriptCLSID
hr = CreateKey(hkeySimpleScript, pszCLSID, &hkeyCLSID1);
if (FAILED(hr))
goto LError;

    StringFromGUID2(CLSID_SimpleScript, pszClassId, cchClassId);

    // HKCRSimpleScriptCLSID(Default) = "{...}"
hr = SetValue(hkeyCLSID1, NULL, pszClassId);
if (FAILED(hr))
goto LError;

    // HKCRCLSID
hr = CreateKey(HKEY_CLASSES_ROOT, pszCLSID, &hkeyCLSID2);
if (FAILED(hr))
goto LError;

    // HKCRCLSID{...}
hr = CreateKey(hkeyCLSID2, pszClassId, &hkeyClassId);
if (FAILED(hr))
goto LError;

    // HKCRCLSID{...}OLEScript
hr = CreateKey(hkeyClassId, pszOLEScript);
if (FAILED(hr))
goto LError;

    cchDllPath = GetModuleFileNameW(g_hmodule, pszDllPath, cchDllPathMax - 1);
// GetModuleFileNameW doesn't necessarily terminate the buffer.
pszDllPath[cchDllPathMax - 1] = '
if (cchDllPath == 0)
{
error = GetLastError();
hr = HRESULT_FROM_WIN32(error);
if (FAILED(hr))
goto LError;
}

    // HKCRCLSID{...}(Default) = "SimpleScript Language Engine"
hr = SetValue(hkeyClassId, NULL, pszDescription);
if (FAILED(hr))
goto LError;

    // HKCRCLSID{...}ProgID
hr = CreateKey(hkeyClassId, pszProgID, &hkeyProgID);
if (FAILED(hr))
goto LError;

    // HKCRCLSID{...}ProgID(Default) = "SimpleScript"
hr = SetValue(hkeyProgID, NULL, pszEngineName);
if (FAILED(hr))
goto LError;

    // HKCRCLSID{...}InprocServer32
hr = CreateKey(hkeyClassId, pszInprocServer, &hkeyInprocServer);
if (FAILED(hr))
goto LError;

    // HKCRCLSID{...}InprocServer32(Default) = "c:simplescript.dll"
hr = SetValue(hkeyInprocServer, NULL, pszDllPath);
if (FAILED(hr))
goto LError;

    // HKCRCLSID{...}InprocServer32ThreadingModel = "Both"
hr = SetValue(hkeyInprocServer, pszThreadingModel, pszBoth);
if (FAILED(hr))
goto LError;

    hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr,
NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pCategoryRegister);
if (FAILED(hr))
goto LError;

    catinfo[0].catid = CATID_ActiveScript;
catinfo[0].lcid = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
wcscpy(catinfo[0].szDescription, pszActiveScripting);
catinfo[1].catid = CATID_ActiveScriptParse;
catinfo[1].lcid = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
wcscpy(catinfo[1].szDescription, pszParsing);

hr = pCategoryRegister->RegisterCategories(2, catinfo);
if (FAILED(hr))
goto LError;

    catids[0] = CATID_ActiveScript;
catids[1] = CATID_ActiveScriptParse;

    hr = pCategoryRegister->RegisterClassImplCategories(CLSID_SimpleScript, 2, catids);
if (FAILED(hr))
goto LError;

    hr = S_OK;

LError:

    if (NULL != hkeyInprocServer)
RegCloseKey(hkeyInprocServer);
if (NULL != hkeyProgID)
RegCloseKey(hkeyProgID);
if (NULL != hkeyClassId)
RegCloseKey(hkeyClassId);
if (NULL != hkeyCLSID2)
RegCloseKey(hkeyCLSID2);
if (NULL != hkeyCLSID1)
RegCloseKey(hkeyCLSID1);
if (NULL != hkeySimpleScript)
RegCloseKey(hkeySimpleScript);
if (NULL != pCategoryRegister)
pCategoryRegister->Release();

    return hr;
}

STDAPI DllCanUnloadNow (void)
{
if (0 == g_cReferences && 0 == g_cLocks)
return S_OK;
else
return S_FALSE;
}

EXTERN_C BOOL WINAPI DllMain(HANDLE hmodule, DWORD dwReason, PVOID pvReserved)
{
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
return AttachProcess((HMODULE)hmodule);
case DLL_THREAD_ATTACH:
return AttachThread();
case DLL_PROCESS_DETACH:
return DetachProcess();
case DLL_THREAD_DETACH:
return DetachThread();
default:
Bug("DllMain() called with unrecognized dwReason.");
return FALSE;
}
}