This is an implementation of TODO "Need to not hard-code the dll path"

Registration is implemented in somewhat hackish way:
- not all required keys are created, only minimal set to register DLL
  at non-hard-coded location; install.reg is still required;
- not all created keys are removed, namely CLSID\{ca586...};
  for full clean up, uninstall.reg is still required.
---
 Makefile       |    3 +-
 dll.c          |   82 ++++++++++++++++++++++++++++++++++++++++++++++
+--------
 dll.h          |    3 ++
 install.reg.in |    6 ----
 4 files changed, 74 insertions(+), 20 deletions(-)

diff --git a/Makefile b/Makefile
index 4042879..f28c30e 100644
--- a/Makefile
+++ b/Makefile
@@ -33,8 +33,7 @@ uninst%: uninst%.reg

 install.reg: install.reg.in Makefile
        sed < $< > $@ \
-               -e 's|@@MSYSGIT_PATH@@|$(MSYSGIT_PATH)|' \
-               -e 's|@@DLL_PATH@@|$(DLL_PATH)|'
+               -e 's|@@MSYSGIT_PATH@@|$(MSYSGIT_PATH)|'

 %-user.reg: %.reg
        sed < $< > $@ \
diff --git a/dll.c b/dll.c
index bab9d9a..bce60c8 100644
--- a/dll.c
+++ b/dll.c
@@ -1,4 +1,6 @@
 #include <shlobj.h>
+#include <assert.h>
+#include <stdio.h>
 #include "dll.h"
 #include "ext.h"
 #include "factory.h"
@@ -7,6 +9,7 @@
  * The following is just the necessary infrastructure for having
a .dll
  * which can be registered as a COM object.
  */
+HINSTANCE hInst;

 HRESULT PASCAL DllGetClassObject(REFCLSID obj_guid, REFIID
factory_guid,
                void **factory_handle)
@@ -25,29 +28,84 @@ HRESULT PASCAL DllCanUnloadNow(void)
    return (object_count || lock_count) ? S_FALSE : S_OK;
 }

+// as per "How to: Convert Between System::Guid and _GUID"
+static void get_registration_path (char *string)
+{
+       GUID guid = CLSID_git_shell_ext;
+       sprintf (string,
+               KEY_CLSID
+               "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}"
+               "\\InProcServer32",
+               guid.Data1, guid.Data2, guid.Data3,
+               guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3],
+               guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]);
+}
+
+static HRESULT register_git_shell_ext (HKEY root, const char *value)
+{
+       HKEY key;
+       DWORD disp; // required for RegCreateKeyEx, otherwise unused
+       char path_to_value[MAX_PATH]; // more than necessary for registry
key
+       HRESULT result;
+
+       assert (NULL != value);
+       assert (MAX_PATH > strlen(value));
+
+       get_registration_path (path_to_value);
+
+       result = RegCreateKeyEx(root, path_to_value,
+               0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL,
+               &key, &disp);
+       if (ERROR_SUCCESS != result)
+               return result;
+
+       result = RegSetValueEx(key, NULL, // value name: default value
+               0, REG_SZ,
+               (LPBYTE)value, (DWORD)strlen(value));
+       if (ERROR_SUCCESS == result)
+               result = RegSetValueEx(key, "ThreadingModel",
+               0, REG_SZ,
+               THREADING_MODEL, (DWORD)strlen(THREADING_MODEL));
+
+       RegCloseKey (key);
+
+       return result;
+}
+
 HRESULT PASCAL DllRegisterServer(void)
 {
        char module[MAX_PATH];
-       wchar_t module_name[MAX_PATH];
-       ITypeLib *typelib = NULL;
-
-       GetModuleFileName(NULL, module, MAX_PATH);
-       MultiByteToWideChar(CP_ACP, 0, module, -1, module_name, MAX_PATH);
-       if (LoadTypeLib(module_name, &typelib) == S_OK) {
-               HRESULT result = RegisterTypeLib(typelib, module_name, NULL);
-               typelib->lpVtbl->Release(typelib);
-               return result;
-       }
-       return 1;
+       DWORD module_size;
+       HRESULT result;
+
+       if (0 == (module_size = GetModuleFileName(hInst, module, MAX_PATH)))
+               return GetLastError();
+
+       result = register_git_shell_ext (HKEY_LOCAL_MACHINE, module);
+       if (ERROR_SUCCESS != result)
+               result = register_git_shell_ext (HKEY_CURRENT_USER, module);
+
+       return result;
 }

 HRESULT PASCAL DllUnregisterServer(void)
 {
-       return S_OK;
+       HRESULT result;
+       char path_to_value[MAX_PATH]; // more than necessary for registry
key
+
+       get_registration_path (path_to_value);
+
+       result = RegDeleteKey (HKEY_LOCAL_MACHINE, path_to_value);
+       if (ERROR_SUCCESS != result)
+               result = RegDeleteKey (HKEY_CURRENT_USER, path_to_value);
+
+       return result;
 }

 BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID
reserved)
 {
+       hInst = instance;
+
        if (reason == DLL_PROCESS_ATTACH) {
                object_count = lock_count = 0;
                DisableThreadLibraryCalls(instance);
diff --git a/dll.h b/dll.h
index e5de007..1a1ee29 100644
--- a/dll.h
+++ b/dll.h
@@ -5,6 +5,9 @@ const char *program_name = "Git-Cheetah";
 const char *program_version = "Git-Cheetah.Application.1";
 const char *program_id = "Git-Cheetah.Application";

+#define KEY_CLSID "Software\\Classes\\CLSID\\"
+#define THREADING_MODEL "Apartment"
+
 HRESULT PASCAL DllGetClassObject(REFCLSID obj_guid, REFIID
factory_guid,
                                 void **factory_handle);
 HRESULT PASCAL DllCanUnloadNow(void);
diff --git a/install.reg.in b/install.reg.in
index 2eb8f13..29ae2ed 100644
--- a/install.reg.in
+++ b/install.reg.in
@@ -21,12 +21,6 @@ Windows Registry Editor Version 5.00
 [HKEY_CLASSES_ROOT\CLSID\{ca586c80-7c84-4b88-8537-726724df6929}]
 @="Git-Cheetah"

-[HKEY_CLASSES_ROOT\CLSID\
{ca586c80-7c84-4b88-8537-726724df6929}\InProcServer32]
[EMAIL PROTECTED]"@@DLL_PATH@@"
-
-[HKEY_CLASSES_ROOT\CLSID\
{ca586c80-7c84-4b88-8537-726724df6929}\InProcServer32]
-"ThreadingModel"="Apartment"
-
 [HKEY_CLASSES_ROOT\*\shellex\ContextMenuHandlers\Git-Cheetah]

 [HKEY_CLASSES_ROOT\*\shellex\ContextMenuHandlers\Git-Cheetah]
--
1.5.4.rc0.929.g50e2

Reply via email to