Fabulous Adventures In Coding

Eric Lippert's Blog

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];

    // HKCR\CLSID
    hr = OpenKey(HKEY_CLASSES_ROOT, pszCLSID, &hkeyCLSID);
    if (SUCCEEDED(hr))
    {
        StringFromGUID2(CLSID_SimpleScript, pszClassId, cchClassId);
        // HKCR\CLSID\{...}
        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

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

    // HKCR\SimpleScript\OLEScript
    hr = CreateKey(hkeySimpleScript, pszOLEScript);
    if (FAILED(hr))
        goto LError;

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

    // HKCR\SimpleScript\CLSID
    hr = CreateKey(hkeySimpleScript, pszCLSID, &hkeyCLSID1);
    if (FAILED(hr))
        goto LError;

    StringFromGUID2(CLSID_SimpleScript, pszClassId, cchClassId);

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

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

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

    // HKCR\CLSID\{...}\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] = '\0';
    if (cchDllPath == 0)
    {
        error = GetLastError();
        hr = HRESULT_FROM_WIN32(error);
        if (FAILED(hr))
            goto LError;
    }

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

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

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

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

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

    // HKCR\CLSID\{...}\InprocServer32\ThreadingModel = "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;
    }
}

Published Wednesday, March 31, 2004 6:17 PM by Eric Lippert
Filed under:

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

 

Fabulous Adventures In Coding said:

April 1, 2004 2:02 AM
 

Fabulous Adventures In Coding said:

April 1, 2004 2:06 AM

Leave a Comment

(required) 
(optional)
(required) 

  
Enter Code Here: Required
Submit

About Eric Lippert

Eric Lippert is a senior developer on the Microsoft C# compiler team. Before that he worked on the framework of Visual Studio Tools For Office. Before that, he worked on the compilers, runtimes and tools for VBScript, JScript, Windows Script Host and other Microsoft Scripting technologies. He lives in Seattle and spends his free time editing books about programming languages, playing the piano, and trying to keep his tiny sailboat upright in Puget Sound.

This Blog

Syndication


© 2009 Microsoft Corporation. All rights reserved. Terms of Use  |  Trademarks  |  Privacy Statement
Microsoft
Page view tracker