libgit2: Improve error message for unsafe directories
[TortoiseGit.git] / src / GitWCRev / Register.cpp
blob19b884004760944dfd82327123a4a72df42ffaaa
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.
20 #include "stdafx.h"
21 #include <objbase.h> // ATL base
22 #include <atlbase.h>
23 #include <assert.h>
25 #include "Register.h"
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 ////////////////////////////////////////////////////////
46 // Constants
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\\{...}
79 wchar_t szKey[64];
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);
95 // Add the typelib
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);
108 // add TypeLib keys
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);
121 return S_OK;
124 void RegisterInterface(HMODULE hModule, // DLL module handle
125 const CLSID& clsid, // Class ID
126 const wchar_t* szFriendlyName, // Friendly Name
127 const CLSID& libid,
128 const IID& iid)
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\\{...}
143 wchar_t szKey[64];
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\\{...}
175 wchar_t szKey[64];
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\\{...}
195 wchar_t szKey[64];
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.
221 return S_OK;
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);
233 // Get CLSID
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
247 // Open the child.
248 HKEY hKeyChild;
249 LONG lRes = RegOpenKeyEx(hKeyParent, lpszKeyChild, 0, KEY_ALL_ACCESS, &hKeyChild);
250 if (lRes != ERROR_SUCCESS)
251 return lRes;
253 // Enumerate all of the descendants of this child.
254 FILETIME time;
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);
265 return lRes;
267 dwSize = _countof(szBuffer);
270 // Close the child.
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)
284 HKEY hKey;
285 wchar_t szKeyBuf[1024];
287 // Copy key name into buffer.
288 wcscpy_s(szKeyBuf, szKey);
290 // Add subkey name to buffer.
291 if (szSubkey)
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)
300 return FALSE;
302 // Set the Value.
303 if (szValue)
304 RegSetValueEx(hKey, nullptr, 0, REG_SZ, reinterpret_cast<BYTE*>(const_cast<wchar_t*>(szValue)), DWORD((1 + wcslen(szValue)) * sizeof(wchar_t)));
306 RegCloseKey(hKey);
307 return TRUE;
310 BOOL setValue(const wchar_t* szKey, const wchar_t* szEntry, const wchar_t* szValue)
312 HKEY hKey;
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)
317 return FALSE;
319 // Set the Value.
320 if (szValue)
321 RegSetValueEx(hKey, szEntry, 0, REG_SZ, reinterpret_cast<BYTE*>(const_cast<wchar_t*>(szValue)), DWORD((1 + wcslen(szValue)) * sizeof(wchar_t)));
323 RegCloseKey(hKey);
325 return TRUE;
328 /////////////////////////////////////////////////////////////////////////////
329 // TypeLib registration
331 HRESULT LoadTypeLib(HINSTANCE hInstTypeLib, LPCOLESTR lpszIndex, BSTR* pbstrPath, ITypeLib** ppTypeLib)
333 ATLASSERT(pbstrPath && ppTypeLib);
334 if (!pbstrPath || !ppTypeLib)
335 return E_POINTER;
337 *pbstrPath = nullptr;
338 *ppTypeLib = nullptr;
340 USES_CONVERSION;
341 ATLASSERT(hInstTypeLib);
342 wchar_t szModule[MAX_PATH+10] = { 0 };
344 DWORD dwFLen = ::GetModuleFileName(hInstTypeLib, szModule, MAX_PATH);
345 if (dwFLen == 0)
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);
353 if (lpszIndex)
354 lstrcat(szModule, OLE2CT(lpszIndex));
355 LPOLESTR lpszModule = T2OLE(szModule);
356 HRESULT hr = ::LoadTypeLib(lpszModule, ppTypeLib);
357 if (FAILED(hr))
359 // typelib not in module, try <module>.tlb instead
360 lstrcpy(lpszExt, L".tlb");
361 lpszModule = T2OLE(szModule);
362 hr = ::LoadTypeLib(lpszModule, ppTypeLib);
364 if (SUCCEEDED(hr))
366 *pbstrPath = ::SysAllocString(lpszModule);
367 if (!*pbstrPath)
368 hr = E_OUTOFMEMORY;
370 return hr;
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(':'))
384 lpszTemp = lp;
385 lpsz = lp;
388 return UINT(lpszTemp-lpszPathName);
391 HRESULT RegisterTypeLib(HINSTANCE hInstTypeLib, LPCOLESTR lpszIndex)
393 CComBSTR bstrPath;
394 CComPtr<ITypeLib> pTypeLib;
395 HRESULT hr = LoadTypeLib(hInstTypeLib, lpszIndex, &bstrPath, &pTypeLib);
396 if (SUCCEEDED(hr))
398 OLECHAR szDir[MAX_PATH] = { 0 };
399 ocscpy_s(szDir, _countof(szDir), bstrPath);
400 // If index is specified remove it from the path
401 if (lpszIndex)
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);
411 return hr;
414 HRESULT UnRegisterTypeLib(HINSTANCE hInstTypeLib, LPCOLESTR lpszIndex)
416 CComBSTR bstrPath;
417 CComPtr<ITypeLib> pTypeLib;
418 HRESULT hr = LoadTypeLib(hInstTypeLib, lpszIndex, &bstrPath, &pTypeLib);
419 if (SUCCEEDED(hr))
421 TLIBATTR* ptla = 0;
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);
429 return hr;