NCContextMenuRegHandler.cpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. /**
  2. * Copyright (c) 2015 Daniel Molkentin <danimo@owncloud.com>. All rights reserved.
  3. *
  4. * This library is free software; you can redistribute it and/or modify it under
  5. * the terms of the GNU Lesser General Public License as published by the Free
  6. * Software Foundation; either version 2.1 of the License, or (at your option)
  7. * any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful, but WITHOUT
  10. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  11. * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
  12. * details.
  13. */
  14. #include "NCContextMenuRegHandler.h"
  15. #include "RegDelnode.h"
  16. #include <strsafe.h>
  17. #include <objbase.h>
  18. namespace {
  19. HRESULT SetHKCRRegistryKeyAndValue(PCWSTR pszSubKey, PCWSTR pszValueName, PCWSTR pszData)
  20. {
  21. HRESULT hr = 0;
  22. HKEY hKey = nullptr;
  23. // Creates the specified registry key. If the key already exists, the
  24. // function opens it.
  25. hr = HRESULT_FROM_WIN32(RegCreateKeyEx(HKEY_CLASSES_ROOT, pszSubKey, 0,
  26. nullptr, REG_OPTION_NON_VOLATILE, KEY_WRITE, nullptr, &hKey, nullptr));
  27. if (SUCCEEDED(hr))
  28. {
  29. DWORD cbData = 0;
  30. const BYTE * lpData = nullptr;
  31. if (pszData)
  32. {
  33. // Set the specified value of the key.
  34. cbData = lstrlen(pszData) * sizeof(*pszData);
  35. lpData = reinterpret_cast<const BYTE *>(pszData);
  36. }
  37. else
  38. {
  39. cbData = 0;
  40. lpData = nullptr;
  41. }
  42. hr = HRESULT_FROM_WIN32(RegSetValueEx(hKey, pszValueName, 0,
  43. REG_SZ, lpData, cbData));
  44. RegCloseKey(hKey);
  45. }
  46. return hr;
  47. }
  48. HRESULT GetHKCRRegistryKeyAndValue(PCWSTR pszSubKey, PCWSTR pszValueName, PWSTR pszData, DWORD cbData)
  49. {
  50. HRESULT hr = 0;
  51. HKEY hKey = nullptr;
  52. // Try to open the specified registry key.
  53. hr = HRESULT_FROM_WIN32(RegOpenKeyEx(HKEY_CLASSES_ROOT, pszSubKey, 0,
  54. KEY_READ, &hKey));
  55. if (SUCCEEDED(hr))
  56. {
  57. // Get the data for the specified value name.
  58. hr = HRESULT_FROM_WIN32(RegQueryValueEx(hKey, pszValueName, nullptr,
  59. nullptr, reinterpret_cast<LPBYTE>(pszData), &cbData));
  60. RegCloseKey(hKey);
  61. }
  62. return hr;
  63. }
  64. }
  65. HRESULT NCContextMenuRegHandler::RegisterInprocServer(PCWSTR pszModule, const CLSID& clsid, PCWSTR pszFriendlyName, PCWSTR pszThreadModel)
  66. {
  67. if (!pszModule || !pszThreadModel)
  68. {
  69. return E_INVALIDARG;
  70. }
  71. HRESULT hr = 0;
  72. wchar_t szCLSID[MAX_PATH];
  73. StringFromGUID2(clsid, szCLSID, ARRAYSIZE(szCLSID));
  74. wchar_t szSubkey[MAX_PATH];
  75. // Create the HKCR\CLSID\{<CLSID>} key.
  76. hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey), LR"(CLSID\%s)", szCLSID);
  77. if (SUCCEEDED(hr))
  78. {
  79. hr = SetHKCRRegistryKeyAndValue(szSubkey, nullptr, pszFriendlyName);
  80. // Create the HKCR\CLSID\{<CLSID>}\ContextMenuOptIn subkey.
  81. if (SUCCEEDED(hr)) {
  82. hr = SetHKCRRegistryKeyAndValue(szSubkey, L"ContextMenuOptIn", nullptr);
  83. }
  84. // Create the HKCR\CLSID\{<CLSID>}\InprocServer32 key.
  85. if (SUCCEEDED(hr))
  86. {
  87. hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey),
  88. LR"(CLSID\%s\InprocServer32)", szCLSID);
  89. if (SUCCEEDED(hr))
  90. {
  91. // Set the default value of the InprocServer32 key to the
  92. // path of the COM module.
  93. hr = SetHKCRRegistryKeyAndValue(szSubkey, nullptr, pszModule);
  94. if (SUCCEEDED(hr))
  95. {
  96. // Set the threading model of the component.
  97. hr = SetHKCRRegistryKeyAndValue(szSubkey,
  98. L"ThreadingModel", pszThreadModel);
  99. }
  100. }
  101. }
  102. }
  103. return hr;
  104. }
  105. HRESULT NCContextMenuRegHandler::UnregisterInprocServer(const CLSID& clsid)
  106. {
  107. HRESULT hr = S_OK;
  108. wchar_t szCLSID[MAX_PATH];
  109. StringFromGUID2(clsid, szCLSID, ARRAYSIZE(szCLSID));
  110. wchar_t szSubkey[MAX_PATH];
  111. // Delete the HKCR\CLSID\{<CLSID>} key.
  112. hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey), LR"(CLSID\%s)", szCLSID);
  113. if (SUCCEEDED(hr))
  114. {
  115. hr = HRESULT_FROM_WIN32(RegDelnode(HKEY_CLASSES_ROOT, szSubkey));
  116. }
  117. return hr;
  118. }
  119. HRESULT NCContextMenuRegHandler::RegisterShellExtContextMenuHandler(
  120. PCWSTR pszFileType, const CLSID& clsid, PCWSTR pszFriendlyName)
  121. {
  122. if (!pszFileType)
  123. {
  124. return E_INVALIDARG;
  125. }
  126. HRESULT hr = 0;
  127. wchar_t szCLSID[MAX_PATH];
  128. StringFromGUID2(clsid, szCLSID, ARRAYSIZE(szCLSID));
  129. wchar_t szSubkey[MAX_PATH];
  130. // If pszFileType starts with '.', try to read the default value of the
  131. // HKCR\<File Type> key which contains the ProgID to which the file type
  132. // is linked.
  133. if (*pszFileType == L'.')
  134. {
  135. wchar_t szDefaultVal[260];
  136. hr = GetHKCRRegistryKeyAndValue(pszFileType, nullptr, szDefaultVal,
  137. sizeof(szDefaultVal));
  138. // If the key exists and its default value is not empty, use the
  139. // ProgID as the file type.
  140. if (SUCCEEDED(hr) && szDefaultVal[0] != L'\0')
  141. {
  142. pszFileType = szDefaultVal;
  143. }
  144. }
  145. // Create the key HKCR\<File Type>\shellex\ContextMenuHandlers\{friendlyName>}
  146. hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey),
  147. LR"(%s\shellex\ContextMenuHandlers\%s)", pszFileType, pszFriendlyName);
  148. if (SUCCEEDED(hr))
  149. {
  150. // Set the default value of the key.
  151. hr = SetHKCRRegistryKeyAndValue(szSubkey, nullptr, szCLSID);
  152. }
  153. return hr;
  154. }
  155. HRESULT NCContextMenuRegHandler::UnregisterShellExtContextMenuHandler(
  156. PCWSTR pszFileType, PCWSTR pszFriendlyName)
  157. {
  158. if (!pszFileType)
  159. {
  160. return E_INVALIDARG;
  161. }
  162. HRESULT hr = 0;
  163. wchar_t szSubkey[MAX_PATH];
  164. // If pszFileType starts with '.', try to read the default value of the
  165. // HKCR\<File Type> key which contains the ProgID to which the file type
  166. // is linked.
  167. if (*pszFileType == L'.')
  168. {
  169. wchar_t szDefaultVal[260];
  170. hr = GetHKCRRegistryKeyAndValue(pszFileType, nullptr, szDefaultVal,
  171. sizeof(szDefaultVal));
  172. // If the key exists and its default value is not empty, use the
  173. // ProgID as the file type.
  174. if (SUCCEEDED(hr) && szDefaultVal[0] != L'\0')
  175. {
  176. pszFileType = szDefaultVal;
  177. }
  178. }
  179. // Remove the HKCR\<File Type>\shellex\ContextMenuHandlers\{friendlyName} key.
  180. hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey),
  181. LR"(%s\shellex\ContextMenuHandlers\%s)", pszFileType, pszFriendlyName);
  182. if (SUCCEEDED(hr))
  183. {
  184. hr = HRESULT_FROM_WIN32(RegDelnode(HKEY_CLASSES_ROOT, szSubkey));
  185. }
  186. return hr;
  187. }