The Webview Univeral Flutter package for Appeto SDK.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 
 
 
 

278 lignes
13 KiB

  1. //*********************************************************
  2. //
  3. // Copyright (c) Microsoft. All rights reserved.
  4. // This code is licensed under the MIT License.
  5. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
  6. // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
  7. // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  8. // PARTICULAR PURPOSE AND NONINFRINGEMENT.
  9. //
  10. //*********************************************************
  11. #ifndef __WIL_REGISTRY_INCLUDED
  12. #define __WIL_REGISTRY_INCLUDED
  13. #ifdef _KERNEL_MODE
  14. #error This header is not supported in kernel-mode.
  15. #endif
  16. #include <winreg.h>
  17. #include <new.h> // new(std::nothrow)
  18. #include "resource.h" // unique_hkey
  19. namespace wil
  20. {
  21. //! The key name includes the absolute path of the key in the registry, always starting at a
  22. //! base key, for example, HKEY_LOCAL_MACHINE.
  23. size_t const max_registry_key_name_length = 255;
  24. //! The maximum number of characters allowed in a registry value's name.
  25. size_t const max_registry_value_name_length = 16383;
  26. // unique_registry_watcher/unique_registry_watcher_nothrow/unique_registry_watcher_failfast
  27. // These classes make it easy to execute a provided function when a
  28. // registry key changes (optionally recursively). Specify the key
  29. // either as a root key + path, or an open registry handle as wil::unique_hkey
  30. // or a raw HKEY value (that will be duplicated).
  31. //
  32. // Example use with exceptions base error handling:
  33. // auto watcher = wil::make_registry_watcher(HKEY_CURRENT_USER, L"Software\\MyApp", true, wil::RegistryChangeKind changeKind[]
  34. // {
  35. // if (changeKind == RegistryChangeKind::Delete)
  36. // {
  37. // watcher.reset();
  38. // }
  39. // // invalidate cached registry data here
  40. // });
  41. //
  42. // Example use with error code base error handling:
  43. // auto watcher = wil::make_registry_watcher_nothrow(HKEY_CURRENT_USER, L"Software\\MyApp", true, wil::RegistryChangeKind[]
  44. // {
  45. // // invalidate cached registry data here
  46. // });
  47. // RETURN_IF_NULL_ALLOC(watcher);
  48. enum class RegistryChangeKind
  49. {
  50. Modify = 0,
  51. Delete = 1,
  52. };
  53. /// @cond
  54. namespace details
  55. {
  56. struct registry_watcher_state
  57. {
  58. registry_watcher_state(unique_hkey &&keyToWatch, bool isRecursive, wistd::function<void(RegistryChangeKind)> &&callback)
  59. : m_callback(wistd::move(callback)), m_keyToWatch(wistd::move(keyToWatch)), m_isRecursive(isRecursive)
  60. {
  61. }
  62. wistd::function<void(RegistryChangeKind)> m_callback;
  63. unique_hkey m_keyToWatch;
  64. unique_event_nothrow m_eventHandle;
  65. // While not strictly needed since this is ref counted the thread pool wait
  66. // should be last to ensure that the other members are valid
  67. // when it is destructed as it will reference them.
  68. unique_threadpool_wait m_threadPoolWait;
  69. bool m_isRecursive;
  70. volatile long m_refCount = 1;
  71. srwlock m_lock;
  72. // Returns true if the refcount can be increased from a non zero value,
  73. // false it was zero impling that the object is in or on the way to the destructor.
  74. // In this case ReleaseFromCallback() should not be called.
  75. bool TryAddRef()
  76. {
  77. return ::InterlockedIncrement(&m_refCount) > 1;
  78. }
  79. void Release()
  80. {
  81. auto lock = m_lock.lock_exclusive();
  82. if (0 == ::InterlockedDecrement(&m_refCount))
  83. {
  84. lock.reset(); // leave the lock before deleting it.
  85. delete this;
  86. }
  87. }
  88. void ReleaseFromCallback(bool rearm)
  89. {
  90. auto lock = m_lock.lock_exclusive();
  91. if (0 == ::InterlockedDecrement(&m_refCount))
  92. {
  93. // Destroy the thread pool wait now to avoid the wait that would occur in the
  94. // destructor. That wait would cause a deadlock since we are doing this from the callback.
  95. ::CloseThreadpoolWait(m_threadPoolWait.release());
  96. lock.reset(); // leave the lock before deleting it.
  97. delete this;
  98. // Sleep(1); // Enable for testing to find use after free bugs.
  99. }
  100. else if (rearm)
  101. {
  102. ::SetThreadpoolWait(m_threadPoolWait.get(), m_eventHandle.get(), nullptr);
  103. }
  104. }
  105. };
  106. inline void delete_registry_watcher_state(_In_opt_ registry_watcher_state *watcherStorage) { watcherStorage->Release(); }
  107. typedef resource_policy<registry_watcher_state *, decltype(&details::delete_registry_watcher_state),
  108. details::delete_registry_watcher_state, details::pointer_access_none> registry_watcher_state_resource_policy;
  109. }
  110. /// @endcond
  111. template <typename storage_t, typename err_policy = err_exception_policy>
  112. class registry_watcher_t : public storage_t
  113. {
  114. public:
  115. // forward all base class constructors...
  116. template <typename... args_t>
  117. explicit registry_watcher_t(args_t&&... args) WI_NOEXCEPT : storage_t(wistd::forward<args_t>(args)...) {}
  118. // HRESULT or void error handling...
  119. typedef typename err_policy::result result;
  120. // Exception-based constructors
  121. registry_watcher_t(HKEY rootKey, _In_ PCWSTR subKey, bool isRecursive, wistd::function<void(RegistryChangeKind)> &&callback)
  122. {
  123. static_assert(wistd::is_same<void, result>::value, "this constructor requires exceptions; use the create method");
  124. create(rootKey, subKey, isRecursive, wistd::move(callback));
  125. }
  126. registry_watcher_t(unique_hkey &&keyToWatch, bool isRecursive, wistd::function<void(RegistryChangeKind)> &&callback)
  127. {
  128. static_assert(wistd::is_same<void, result>::value, "this constructor requires exceptions; use the create method");
  129. create(wistd::move(keyToWatch), isRecursive, wistd::move(callback));
  130. }
  131. // Pass a root key, sub key pair or use an empty string to use rootKey as the key to watch.
  132. result create(HKEY rootKey, _In_ PCWSTR subKey, bool isRecursive, wistd::function<void(RegistryChangeKind)> &&callback)
  133. {
  134. // Most use will want to create the key, consider adding an option for open as a future design change.
  135. unique_hkey keyToWatch;
  136. HRESULT hr = HRESULT_FROM_WIN32(RegCreateKeyExW(rootKey, subKey, 0, nullptr, 0, KEY_NOTIFY, nullptr, &keyToWatch, nullptr));
  137. if (FAILED(hr))
  138. {
  139. return err_policy::HResult(hr);
  140. }
  141. return err_policy::HResult(create_common(wistd::move(keyToWatch), isRecursive, wistd::move(callback)));
  142. }
  143. result create(unique_hkey &&keyToWatch, bool isRecursive, wistd::function<void(RegistryChangeKind)> &&callback)
  144. {
  145. return err_policy::HResult(create_common(wistd::move(keyToWatch), isRecursive, wistd::move(callback)));
  146. }
  147. private:
  148. // Factored into a standalone function to support Clang which does not support conversion of stateless lambdas
  149. // to __stdcall
  150. static void __stdcall callback(PTP_CALLBACK_INSTANCE, void *context, TP_WAIT *, TP_WAIT_RESULT)
  151. {
  152. #ifndef __WIL_REGISTRY_CHANGE_CALLBACK_TEST
  153. #define __WIL_REGISTRY_CHANGE_CALLBACK_TEST
  154. #endif
  155. __WIL_REGISTRY_CHANGE_CALLBACK_TEST
  156. auto watcherState = static_cast<details::registry_watcher_state *>(context);
  157. if (watcherState->TryAddRef())
  158. {
  159. // using auto reset event so don't need to manually reset.
  160. // failure here is a programming error.
  161. const LSTATUS error = RegNotifyChangeKeyValue(watcherState->m_keyToWatch.get(), watcherState->m_isRecursive,
  162. REG_NOTIFY_CHANGE_LAST_SET | REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_THREAD_AGNOSTIC,
  163. watcherState->m_eventHandle.get(), TRUE);
  164. // Call the client before re-arming to ensure that multiple callbacks don't
  165. // run concurrently.
  166. switch (error)
  167. {
  168. case ERROR_SUCCESS:
  169. case ERROR_ACCESS_DENIED:
  170. // Normal modification: send RegistryChangeKind::Modify and re-arm.
  171. watcherState->m_callback(RegistryChangeKind::Modify);
  172. watcherState->ReleaseFromCallback(true);
  173. break;
  174. case ERROR_KEY_DELETED:
  175. // Key deleted, send RegistryChangeKind::Delete, do not re-arm.
  176. watcherState->m_callback(RegistryChangeKind::Delete);
  177. watcherState->ReleaseFromCallback(false);
  178. break;
  179. case ERROR_HANDLE_REVOKED:
  180. // Handle revoked. This can occur if the user session ends before
  181. // the watcher shuts-down. Disarm silently since there is generally no way to respond.
  182. watcherState->ReleaseFromCallback(false);
  183. break;
  184. default:
  185. FAIL_FAST_HR(HRESULT_FROM_WIN32(error));
  186. }
  187. }
  188. }
  189. // This function exists to avoid template expansion of this code based on err_policy.
  190. HRESULT create_common(unique_hkey &&keyToWatch, bool isRecursive, wistd::function<void(RegistryChangeKind)> &&callback)
  191. {
  192. wistd::unique_ptr<details::registry_watcher_state> watcherState(new(std::nothrow) details::registry_watcher_state(
  193. wistd::move(keyToWatch), isRecursive, wistd::move(callback)));
  194. RETURN_IF_NULL_ALLOC(watcherState);
  195. RETURN_IF_FAILED(watcherState->m_eventHandle.create());
  196. RETURN_IF_WIN32_ERROR(RegNotifyChangeKeyValue(watcherState->m_keyToWatch.get(),
  197. watcherState->m_isRecursive, REG_NOTIFY_CHANGE_LAST_SET | REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_THREAD_AGNOSTIC,
  198. watcherState->m_eventHandle.get(), TRUE));
  199. watcherState->m_threadPoolWait.reset(CreateThreadpoolWait(&registry_watcher_t::callback, watcherState.get(), nullptr));
  200. RETURN_LAST_ERROR_IF(!watcherState->m_threadPoolWait);
  201. storage_t::reset(watcherState.release()); // no more failures after this, pass ownership
  202. SetThreadpoolWait(storage_t::get()->m_threadPoolWait.get(), storage_t::get()->m_eventHandle.get(), nullptr);
  203. return S_OK;
  204. }
  205. };
  206. typedef unique_any_t<registry_watcher_t<details::unique_storage<details::registry_watcher_state_resource_policy>, err_returncode_policy>> unique_registry_watcher_nothrow;
  207. typedef unique_any_t<registry_watcher_t<details::unique_storage<details::registry_watcher_state_resource_policy>, err_failfast_policy>> unique_registry_watcher_failfast;
  208. inline unique_registry_watcher_nothrow make_registry_watcher_nothrow(HKEY rootKey, _In_ PCWSTR subKey, bool isRecursive, wistd::function<void(RegistryChangeKind)> &&callback) WI_NOEXCEPT
  209. {
  210. unique_registry_watcher_nothrow watcher;
  211. watcher.create(rootKey, subKey, isRecursive, wistd::move(callback));
  212. return watcher; // caller must test for success using if (watcher)
  213. }
  214. inline unique_registry_watcher_nothrow make_registry_watcher_nothrow(unique_hkey &&keyToWatch, bool isRecursive, wistd::function<void(RegistryChangeKind)> &&callback) WI_NOEXCEPT
  215. {
  216. unique_registry_watcher_nothrow watcher;
  217. watcher.create(wistd::move(keyToWatch), isRecursive, wistd::move(callback));
  218. return watcher; // caller must test for success using if (watcher)
  219. }
  220. inline unique_registry_watcher_failfast make_registry_watcher_failfast(HKEY rootKey, _In_ PCWSTR subKey, bool isRecursive, wistd::function<void(RegistryChangeKind)> &&callback)
  221. {
  222. return unique_registry_watcher_failfast(rootKey, subKey, isRecursive, wistd::move(callback));
  223. }
  224. inline unique_registry_watcher_failfast make_registry_watcher_failfast(unique_hkey &&keyToWatch, bool isRecursive, wistd::function<void(RegistryChangeKind)> &&callback)
  225. {
  226. return unique_registry_watcher_failfast(wistd::move(keyToWatch), isRecursive, wistd::move(callback));
  227. }
  228. #ifdef WIL_ENABLE_EXCEPTIONS
  229. typedef unique_any_t<registry_watcher_t<details::unique_storage<details::registry_watcher_state_resource_policy>, err_exception_policy >> unique_registry_watcher;
  230. inline unique_registry_watcher make_registry_watcher(HKEY rootKey, _In_ PCWSTR subKey, bool isRecursive, wistd::function<void(RegistryChangeKind)> &&callback)
  231. {
  232. return unique_registry_watcher(rootKey, subKey, isRecursive, wistd::move(callback));
  233. }
  234. inline unique_registry_watcher make_registry_watcher(unique_hkey &&keyToWatch, bool isRecursive, wistd::function<void(RegistryChangeKind)> &&callback)
  235. {
  236. return unique_registry_watcher(wistd::move(keyToWatch), isRecursive, wistd::move(callback));
  237. }
  238. #endif // WIL_ENABLE_EXCEPTIONS
  239. } // namespace wil
  240. #endif