1
// TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2017, 2019 - TortoiseGit
4 // Copyright (C) 2005-2008, 2010-2011, 2014 - TortoiseSVN
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software Foundation,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 #include <objbase.h> // ATL base
28 // Internal helper functions prototypes
31 // Set the given key and its value.
32 BOOL
setKeyAndValue(const wchar_t* pszPath
, const wchar_t* szSubkey
, const wchar_t* szValue
);
35 BOOL
setValue(const wchar_t* szKey
, const wchar_t* szEntry
, const wchar_t* szValue
);
38 // Convert a CLSID into a char string.
39 void CLSIDtochar(const CLSID
& clsid
, wchar_t* szCLSID
, int length
);
41 // Delete szKeyChild and all of its descendants.
42 LONG
recursiveDeleteKey(HKEY hKeyParent
, const wchar_t* szKeyChild
);
44 ////////////////////////////////////////////////////////
49 // Size of a CLSID as a string
50 const int CLSID_STRING_SIZE
= 39;
52 /////////////////////////////////////////////////////////
54 // Public function implementation
58 // Register the component in the registry.
60 HRESULT
RegisterServer(HMODULE hModule
, // DLL module handle
61 const CLSID
& clsid
, // Class ID
62 const wchar_t* szFriendlyName
, // Friendly Name
63 const wchar_t* szVerIndProgID
, // Programmatic
64 const wchar_t* szProgID
,
65 const CLSID
& libid
) // Type lib ID
67 // Get server location.
68 wchar_t szModule
[1024] = { 0 };
69 ::GetModuleFileName(hModule
, szModule
, _countof(szModule
) - 1);
71 wcscat_s(szModule
, L
" /automation");
72 // Convert the CLSID into a wchar_t.
73 wchar_t szCLSID
[CLSID_STRING_SIZE
];
74 CLSIDtochar(clsid
, szCLSID
, _countof(szCLSID
));
75 wchar_t szLIBID
[CLSID_STRING_SIZE
];
76 CLSIDtochar(libid
, szLIBID
, _countof(szLIBID
));
78 // Build the key CLSID\\{...}
80 wcscpy_s(szKey
, L
"CLSID\\");
81 wcscat_s(szKey
, szCLSID
);
83 // Add the CLSID to the registry.
84 setKeyAndValue(szKey
, nullptr, szFriendlyName
);
86 // Add the server filename subkey under the CLSID key.
87 setKeyAndValue(szKey
, L
"LocalServer32", szModule
);
89 // Add the ProgID subkey under the CLSID key.
90 setKeyAndValue(szKey
, L
"ProgID", szProgID
);
92 // Add the version-independent ProgID subkey under CLSID key.
93 setKeyAndValue(szKey
, L
"VersionIndependentProgID", szVerIndProgID
);
96 setKeyAndValue(szKey
, L
"TypeLib", szLIBID
);
99 // Add the version-independent ProgID subkey under HKEY_CLASSES_ROOT.
100 setKeyAndValue(szVerIndProgID
, nullptr, szFriendlyName
);
101 setKeyAndValue(szVerIndProgID
, L
"CLSID", szCLSID
);
102 setKeyAndValue(szVerIndProgID
, L
"CurVer", szProgID
);
104 // Add the versioned ProgID subkey under HKEY_CLASSES_ROOT.
105 setKeyAndValue(szProgID
, nullptr, szFriendlyName
);
106 setKeyAndValue(szProgID
, L
"CLSID", szCLSID
);
109 wcscpy_s(szKey
, L
"TypeLib\\");
110 wcscat_s(szKey
, szLIBID
);
112 // Add the CLSID to the registry.
113 setKeyAndValue(szKey
, nullptr, nullptr);
114 wcscat_s(szKey
, L
"\\1.0");
115 setKeyAndValue(szKey
, nullptr, szFriendlyName
);
116 wcscat_s(szKey
, L
"\\0");
117 setKeyAndValue(szKey
, nullptr, nullptr);
118 wcscat_s(szKey
, L
"\\win32");
119 setKeyAndValue(szKey
, nullptr, szModule
);
124 void RegisterInterface(HMODULE hModule
, // DLL module handle
125 const CLSID
& clsid
, // Class ID
126 const wchar_t* szFriendlyName
, // Friendly Name
130 // Get server location.
131 wchar_t szModule
[512] = { 0 };
132 ::GetModuleFileName(hModule
, szModule
, _countof(szModule
) - 1);
134 // Convert the CLSID into a wchar_t.
135 wchar_t szCLSID
[CLSID_STRING_SIZE
];
136 CLSIDtochar(clsid
, szCLSID
, _countof(szCLSID
));
137 wchar_t szLIBID
[CLSID_STRING_SIZE
];
138 CLSIDtochar(libid
, szLIBID
, _countof(szCLSID
));
139 wchar_t szIID
[CLSID_STRING_SIZE
];
140 CLSIDtochar(iid
, szIID
, _countof(szCLSID
));
142 // Build the key Interface\\{...}
144 wcscpy_s(szKey
, L
"Interface\\");
145 wcscat_s(szKey
, szIID
);
147 // Add the value to the registry.
148 setKeyAndValue(szKey
, nullptr, szFriendlyName
);
150 wchar_t szKey2
[MAX_PATH
] = { 0 };
151 wcscpy_s(szKey2
, szKey
);
152 wcscat_s(szKey2
, L
"\\ProxyStubClsID");
153 // Add the server filename subkey under the IID key.
154 setKeyAndValue(szKey2
, nullptr, L
"{00020424-0000-0000-C000-000000000046}"); //IUnknown
156 wcscpy_s(szKey2
, szKey
);
157 wcscat_s(szKey2
, L
"\\ProxyStubClsID32");
158 // Add the server filename subkey under the IID key.
159 setKeyAndValue(szKey2
, nullptr, L
"{00020424-0000-0000-C000-000000000046}"); //IUnknown
161 wcscpy_s(szKey2
, szKey
);
162 wcscat_s(szKey2
, L
"\\TypeLib");
163 // Add the server filename subkey under the CLSID key.
164 setKeyAndValue(szKey2
, nullptr, szLIBID
);
166 setValue(szKey2
, L
"Version", L
"1.0");
169 void UnregisterInterface(const IID
& iid
)
171 wchar_t szIID
[CLSID_STRING_SIZE
];
172 CLSIDtochar(iid
, szIID
, _countof(szIID
));
174 // Build the key Interface\\{...}
176 wcscpy_s(szKey
, L
"Interface\\");
177 wcscat_s(szKey
, szIID
);
179 recursiveDeleteKey(HKEY_CLASSES_ROOT
, szKey
);
183 // Remove the component from the registry.
185 LONG
UnregisterServer(const CLSID
& clsid
, // Class ID
186 const wchar_t* szVerIndProgID
, // Programmatic
187 const wchar_t* szProgID
,
188 const CLSID
& libid
) // Type lib ID
190 // Convert the CLSID into a wchar_t.
191 wchar_t szCLSID
[CLSID_STRING_SIZE
];
192 CLSIDtochar(clsid
, szCLSID
, _countof(szCLSID
));
194 // Build the key CLSID\\{...}
196 wcscpy_s(szKey
, L
"CLSID\\");
197 wcscat_s(szKey
, szCLSID
);
199 // Delete the CLSID Key - CLSID\{...}
200 LONG lResult
= recursiveDeleteKey(HKEY_CLASSES_ROOT
, szKey
);
201 assert((lResult
== ERROR_SUCCESS
) || (lResult
== ERROR_FILE_NOT_FOUND
)); // Subkey may not exist.
203 // Delete the version-independent ProgID Key.
204 lResult
= recursiveDeleteKey(HKEY_CLASSES_ROOT
, szVerIndProgID
);
205 assert((lResult
== ERROR_SUCCESS
) || (lResult
== ERROR_FILE_NOT_FOUND
)); // Subkey may not exist.
207 // Delete the ProgID key.
208 lResult
= recursiveDeleteKey(HKEY_CLASSES_ROOT
, szProgID
);
209 assert((lResult
== ERROR_SUCCESS
) || (lResult
== ERROR_FILE_NOT_FOUND
)); // Subkey may not exist.
211 wchar_t szLIBID
[CLSID_STRING_SIZE
];
212 CLSIDtochar(libid
, szLIBID
, _countof(szLIBID
));
214 wcscpy_s(szKey
, L
"TypeLib\\");
215 wcscat_s(szKey
, szLIBID
);
217 // Delete the TypeLib Key - LIBID\{...}
218 lResult
= recursiveDeleteKey(HKEY_CLASSES_ROOT
, szKey
);
219 assert((lResult
== ERROR_SUCCESS
) || (lResult
== ERROR_FILE_NOT_FOUND
)); // Subkey may not exist.
224 ///////////////////////////////////////////////////////////
226 // Internal helper functions
229 // Convert a CLSID to a wchar_t string.
230 void CLSIDtochar(const CLSID
& clsid
, wchar_t* szCLSID
, int length
)
232 assert(length
>= CLSID_STRING_SIZE
);
234 CComHeapPtr
<OLECHAR
> wszCLSID
;
235 StringFromCLSID(clsid
, &wszCLSID
);
237 // Covert from wide characters to non-wide.
238 wcscpy_s(szCLSID
, length
, wszCLSID
);
242 // Delete a key and all of its descendants.
244 LONG
recursiveDeleteKey(HKEY hKeyParent
, // Parent of key to delete
245 const wchar_t* lpszKeyChild
) // Key to delete
249 LONG lRes
= RegOpenKeyEx(hKeyParent
, lpszKeyChild
, 0, KEY_ALL_ACCESS
, &hKeyChild
);
250 if (lRes
!= ERROR_SUCCESS
)
253 // Enumerate all of the descendants of this child.
255 wchar_t szBuffer
[256];
256 DWORD dwSize
= _countof(szBuffer
);
257 while (RegEnumKeyEx(hKeyChild
, 0, szBuffer
, &dwSize
, nullptr, nullptr, nullptr, &time
) == S_OK
)
259 // Delete the descendants of this child.
260 lRes
= recursiveDeleteKey(hKeyChild
, szBuffer
);
261 if (lRes
!= ERROR_SUCCESS
)
263 // Cleanup before exiting.
264 RegCloseKey(hKeyChild
);
267 dwSize
= _countof(szBuffer
);
271 RegCloseKey(hKeyChild
);
273 // Delete this child.
274 return RegDeleteKey(hKeyParent
, lpszKeyChild
);
278 // Create a key and set its value.
279 // - This helper function was borrowed and modified from
280 // Kraig Brockschmidt's book Inside OLE.
282 BOOL
setKeyAndValue(const wchar_t* szKey
, const wchar_t* szSubkey
, const wchar_t* szValue
)
285 wchar_t szKeyBuf
[1024];
287 // Copy key name into buffer.
288 wcscpy_s(szKeyBuf
, szKey
);
290 // Add subkey name to buffer.
293 wcscat_s(szKeyBuf
, L
"\\");
294 wcscat_s(szKeyBuf
, szSubkey
);
297 // Create and open key and subkey.
298 long lResult
= RegCreateKeyEx(HKEY_CLASSES_ROOT
, szKeyBuf
, 0, nullptr, REG_OPTION_NON_VOLATILE
, KEY_ALL_ACCESS
, nullptr, &hKey
, nullptr);
299 if (lResult
!= ERROR_SUCCESS
)
304 RegSetValueEx(hKey
, nullptr, 0, REG_SZ
, reinterpret_cast<BYTE
*>(const_cast<wchar_t*>(szValue
)), DWORD((1 + wcslen(szValue
)) * sizeof(wchar_t)));
310 BOOL
setValue(const wchar_t* szKey
, const wchar_t* szEntry
, const wchar_t* szValue
)
314 // Create and open key and subkey.
315 long lResult
= RegOpenKeyEx(HKEY_CLASSES_ROOT
, szKey
, 0, KEY_ALL_ACCESS
, &hKey
);
316 if (lResult
!= ERROR_SUCCESS
)
321 RegSetValueEx(hKey
, szEntry
, 0, REG_SZ
, reinterpret_cast<BYTE
*>(const_cast<wchar_t*>(szValue
)), DWORD((1 + wcslen(szValue
)) * sizeof(wchar_t)));
328 /////////////////////////////////////////////////////////////////////////////
329 // TypeLib registration
331 HRESULT
LoadTypeLib(HINSTANCE hInstTypeLib
, LPCOLESTR lpszIndex
, BSTR
* pbstrPath
, ITypeLib
** ppTypeLib
)
333 ATLASSERT(pbstrPath
&& ppTypeLib
);
334 if (!pbstrPath
|| !ppTypeLib
)
337 *pbstrPath
= nullptr;
338 *ppTypeLib
= nullptr;
341 ATLASSERT(hInstTypeLib
);
342 wchar_t szModule
[MAX_PATH
+10] = { 0 };
344 DWORD dwFLen
= ::GetModuleFileName(hInstTypeLib
, szModule
, MAX_PATH
);
346 return HRESULT_FROM_WIN32(::GetLastError());
347 else if (dwFLen
== MAX_PATH
)
348 return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER
);
350 // get the extension pointer in case of fail
351 LPWSTR lpszExt
= ::PathFindExtension(szModule
);
354 lstrcat(szModule
, OLE2CT(lpszIndex
));
355 LPOLESTR lpszModule
= T2OLE(szModule
);
356 HRESULT hr
= ::LoadTypeLib(lpszModule
, ppTypeLib
);
359 // typelib not in module, try <module>.tlb instead
360 lstrcpy(lpszExt
, L
".tlb");
361 lpszModule
= T2OLE(szModule
);
362 hr
= ::LoadTypeLib(lpszModule
, ppTypeLib
);
366 *pbstrPath
= ::SysAllocString(lpszModule
);
373 static inline UINT WINAPI
GetDirLen(LPCOLESTR lpszPathName
)
375 ATLASSERT(lpszPathName
);
377 // always capture the complete file name including extension (if present)
378 LPCOLESTR lpszTemp
= lpszPathName
;
379 for (LPCOLESTR lpsz
= lpszPathName
; *lpsz
;)
381 LPCOLESTR lp
= CharNextW(lpsz
);
382 // remember last directory/drive separator
383 if (*lpsz
== OLESTR('\\') || *lpsz
== OLESTR('/') || *lpsz
== OLESTR(':'))
388 return UINT(lpszTemp
-lpszPathName
);
391 HRESULT
RegisterTypeLib(HINSTANCE hInstTypeLib
, LPCOLESTR lpszIndex
)
394 CComPtr
<ITypeLib
> pTypeLib
;
395 HRESULT hr
= LoadTypeLib(hInstTypeLib
, lpszIndex
, &bstrPath
, &pTypeLib
);
398 OLECHAR szDir
[MAX_PATH
] = { 0 };
399 ocscpy_s(szDir
, _countof(szDir
), bstrPath
);
400 // If index is specified remove it from the path
403 size_t nLenPath
= ocslen(szDir
);
404 size_t nLenIndex
= ocslen(lpszIndex
);
405 if (memcmp(szDir
+ nLenPath
- nLenIndex
, lpszIndex
, nLenIndex
) == 0)
406 szDir
[nLenPath
- nLenIndex
] = 0;
408 szDir
[GetDirLen(szDir
)] = '\0';
409 hr
= ::RegisterTypeLib(pTypeLib
, bstrPath
, szDir
);
414 HRESULT
UnRegisterTypeLib(HINSTANCE hInstTypeLib
, LPCOLESTR lpszIndex
)
417 CComPtr
<ITypeLib
> pTypeLib
;
418 HRESULT hr
= LoadTypeLib(hInstTypeLib
, lpszIndex
, &bstrPath
, &pTypeLib
);
422 hr
= pTypeLib
->GetLibAttr(&ptla
);
423 if ((SUCCEEDED(hr
)) && (ptla
!= 0))
425 hr
= ::UnRegisterTypeLib(ptla
->guid
, ptla
->wMajorVerNum
, ptla
->wMinorVerNum
, ptla
->lcid
, ptla
->syskind
);
426 pTypeLib
->ReleaseTLibAttr(ptla
);