You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1227 lines
48 KiB

  1. /* /////////////////////////////////////////////////////////////////////////
  2. * File: winstl/registry/reg_key_sequence.hpp
  3. *
  4. * Purpose: Contains the basic_reg_key_sequence class template, and ANSI
  5. * and Unicode specialisations thereof.
  6. *
  7. * Notes: The original implementation of the class had the iterator
  8. * and value_type as nested classes. Unfortunately, Visual C++ 5 &
  9. * 6 both had either compilation or linking problems so these are
  10. * regretably now implemented as independent classes.
  11. *
  12. * Thanks: To Allan McLellan, for pointing out some inadequacies in the
  13. * basic_reg_key_sequence class interface.
  14. *
  15. * Created: 19th January 2002
  16. * Updated: 10th August 2009
  17. *
  18. * Home: http://stlsoft.org/
  19. *
  20. * Copyright (c) 2002-2009, Matthew Wilson and Synesis Software
  21. * All rights reserved.
  22. *
  23. * Redistribution and use in source and binary forms, with or without
  24. * modification, are permitted provided that the following conditions are met:
  25. *
  26. * - Redistributions of source code must retain the above copyright notice, this
  27. * list of conditions and the following disclaimer.
  28. * - Redistributions in binary form must reproduce the above copyright notice,
  29. * this list of conditions and the following disclaimer in the documentation
  30. * and/or other materials provided with the distribution.
  31. * - Neither the name(s) of Matthew Wilson and Synesis Software nor the names of
  32. * any contributors may be used to endorse or promote products derived from
  33. * this software without specific prior written permission.
  34. *
  35. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  36. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  37. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  38. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  39. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  40. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  41. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  42. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  43. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  44. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  45. * POSSIBILITY OF SUCH DAMAGE.
  46. *
  47. * ////////////////////////////////////////////////////////////////////// */
  48. /** \file winstl/registry/reg_key_sequence.hpp
  49. *
  50. * \brief [C++ only] Definition of the winstl::basic_reg_key_sequence
  51. * class template
  52. * (\ref group__library__windows_registry "Windows Registry" Library).
  53. */
  54. #ifndef WINSTL_INCL_WINSTL_REGISTRY_HPP_REG_KEY_SEQUENCE
  55. #define WINSTL_INCL_WINSTL_REGISTRY_HPP_REG_KEY_SEQUENCE
  56. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  57. # define WINSTL_VER_WINSTL_REGISTRY_HPP_REG_KEY_SEQUENCE_MAJOR 3
  58. # define WINSTL_VER_WINSTL_REGISTRY_HPP_REG_KEY_SEQUENCE_MINOR 9
  59. # define WINSTL_VER_WINSTL_REGISTRY_HPP_REG_KEY_SEQUENCE_REVISION 1
  60. # define WINSTL_VER_WINSTL_REGISTRY_HPP_REG_KEY_SEQUENCE_EDIT 131
  61. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  62. /* /////////////////////////////////////////////////////////////////////////
  63. * Includes
  64. */
  65. #ifndef WINSTL_INCL_WINSTL_H_WINSTL
  66. # include <winstl/winstl.h>
  67. #endif /* !WINSTL_INCL_WINSTL_H_WINSTL */
  68. #ifndef WINSTL_INCL_WINSTL_REGISTRY_HPP_REGFWD
  69. # include <winstl/registry/regfwd.hpp>
  70. #endif /* !WINSTL_INCL_WINSTL_REGISTRY_HPP_REGFWD */
  71. #ifndef WINSTL_INCL_WINSTL_REGISTRY_UTIL_HPP_DEFS
  72. # include <winstl/registry/util/defs.hpp>
  73. #endif /* !WINSTL_INCL_WINSTL_REGISTRY_UTIL_HPP_DEFS */
  74. #ifndef WINSTL_INCL_WINSTL_REGISTRY_HPP_REG_TRAITS
  75. # include <winstl/registry/reg_traits.hpp>
  76. #endif /* !WINSTL_INCL_WINSTL_REGISTRY_HPP_REG_TRAITS */
  77. #ifndef WINSTL_INCL_WINSTL_REGISTRY_HPP_REG_KEY
  78. # include <winstl/registry/reg_key.hpp>
  79. #endif /* !WINSTL_INCL_WINSTL_REGISTRY_HPP_REG_KEY */
  80. #ifndef WINSTL_INCL_WINSTL_REGISTRY_UTIL_HPP_SHARED_HANDLES
  81. # include <winstl/registry/util/shared_handles.hpp>
  82. #endif /* !WINSTL_INCL_WINSTL_REGISTRY_UTIL_HPP_SHARED_HANDLES */
  83. #ifndef STLSOFT_INCL_STLSOFT_MEMORY_HPP_AUTO_BUFFER
  84. # include <stlsoft/memory/auto_buffer.hpp>
  85. #endif /* !STLSOFT_INCL_STLSOFT_MEMORY_HPP_AUTO_BUFFER */
  86. #ifndef WINSTL_INCL_WINSTL_MEMORY_HPP_PROCESSHEAP_ALLOCATOR
  87. # include <winstl/memory/processheap_allocator.hpp>
  88. #endif /* !WINSTL_INCL_WINSTL_MEMORY_HPP_PROCESSHEAP_ALLOCATOR */
  89. #ifndef STLSOFT_INCL_STLSOFT_UTIL_STD_HPP_ITERATOR_HELPER
  90. # include <stlsoft/util/std/iterator_helper.hpp>
  91. #endif /* !STLSOFT_INCL_STLSOFT_UTIL_STD_HPP_ITERATOR_HELPER */
  92. #ifndef STLSOFT_INCL_STLSOFT_COLLECTIONS_UTIL_HPP_COLLECTIONS
  93. # include <stlsoft/collections/util/collections.hpp>
  94. #endif /* !STLSOFT_INCL_STLSOFT_COLLECTIONS_UTIL_HPP_COLLECTIONS */
  95. #ifndef STLSOFT_INCL_STLSOFT_SMARTPTR_HPP_REF_PTR
  96. # include <stlsoft/smartptr/ref_ptr.hpp>
  97. #endif /* !STLSOFT_INCL_STLSOFT_SMARTPTR_HPP_REF_PTR */
  98. #ifndef STLSOFT_INCL_STLSOFT_SMARTPTR_HPP_SCOPED_HANDLE
  99. # include <stlsoft/smartptr/scoped_handle.hpp>
  100. #endif /* !STLSOFT_INCL_STLSOFT_SMARTPTR_HPP_SCOPED_HANDLE */
  101. /* /////////////////////////////////////////////////////////////////////////
  102. * Namespace
  103. */
  104. #ifndef _WINSTL_NO_NAMESPACE
  105. # if defined(_STLSOFT_NO_NAMESPACE) || \
  106. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  107. /* There is no stlsoft namespace, so must define ::winstl */
  108. namespace winstl
  109. {
  110. # else
  111. /* Define stlsoft::winstl_project */
  112. namespace stlsoft
  113. {
  114. namespace winstl_project
  115. {
  116. # endif /* _STLSOFT_NO_NAMESPACE */
  117. #endif /* !_WINSTL_NO_NAMESPACE */
  118. /* ////////////////////////////////////////////////////////////////////// */
  119. // class basic_reg_key_sequence
  120. /** \brief Presents an STL-like sequence interface over the sub-keys of a given registry key
  121. *
  122. * \ingroup group__library__windows_registry
  123. *
  124. * \param C The character type
  125. * \param T The traits type. On translators that support default template arguments this defaults to reg_traits<C>
  126. * \param A The allocator type. On translators that support default template arguments this defaults to processheap_allocator<C>
  127. */
  128. template< ss_typename_param_k C
  129. #ifdef STLSOFT_CF_TEMPLATE_CLASS_DEFAULT_CLASS_ARGUMENT_SUPPORT
  130. , ss_typename_param_k T = reg_traits<C>
  131. , ss_typename_param_k A = processheap_allocator<C>
  132. #else /* ? STLSOFT_CF_TEMPLATE_CLASS_DEFAULT_CLASS_ARGUMENT_SUPPORT */
  133. , ss_typename_param_k T /* = reg_traits<C> */
  134. , ss_typename_param_k A /* = processheap_allocator<C> */
  135. #endif /* STLSOFT_CF_TEMPLATE_CLASS_DEFAULT_CLASS_ARGUMENT_SUPPORT */
  136. >
  137. class basic_reg_key_sequence
  138. : public stlsoft_ns_qual(stl_collection_tag)
  139. {
  140. /// \name Member Types
  141. /// @{
  142. public:
  143. /// \brief The character type
  144. typedef C char_type;
  145. /// \brief The traits type
  146. typedef T traits_type;
  147. /// \brief The allocator type
  148. typedef A allocator_type;
  149. /// \brief The current parameterisation of the type
  150. typedef basic_reg_key_sequence<C, T, A> class_type;
  151. /// \brief The key type
  152. typedef basic_reg_key<C, T, A> key_type;
  153. /// \brief The value type
  154. typedef key_type value_type;
  155. /// \brief The size type
  156. typedef ss_typename_type_k traits_type::size_type size_type;
  157. /// \brief The reg key type
  158. typedef basic_reg_key<C, T, A> reg_key_type;
  159. /// \brief The mutating (non-const) iterator type
  160. typedef basic_reg_key_sequence_iterator<C, T, value_type, A> iterator;
  161. /// \brief The non-mutating (const) iterator type
  162. ///
  163. /// \note This is retained for backwards compatibility
  164. typedef iterator const_iterator;
  165. /// \brief The reference type
  166. typedef key_type& reference;
  167. /// \brief The non-mutable (const) reference type
  168. typedef key_type const& const_reference;
  169. /// \brief The hkey type
  170. #if defined(STLSOFT_COMPILER_IS_MSVC) && \
  171. _MSC_VER == 1100
  172. /* WSCB: VC5 has an unresolved external linker error if use traits_type::hkey_type */
  173. typedef HKEY hkey_type;
  174. #else /* ? compiler */
  175. typedef ss_typename_type_k traits_type::hkey_type hkey_type;
  176. #endif /* compiler */
  177. /// \brief The difference type
  178. typedef ws_ptrdiff_t difference_type;
  179. /// \brief The non-mutating (const) reverse iterator type
  180. #if defined(STLSOFT_LF_BIDIRECTIONAL_ITERATOR_SUPPORT)
  181. typedef stlsoft_ns_qual(reverse_bidirectional_iterator_base) < iterator
  182. , value_type
  183. , value_type // By-Value Temporary reference category
  184. , void // By-Value Temporary reference category
  185. , difference_type
  186. > reverse_iterator;
  187. #endif /* STLSOFT_LF_BIDIRECTIONAL_ITERATOR_SUPPORT */
  188. /// \brief The Boolean type
  189. typedef ws_bool_t bool_type;
  190. private:
  191. /// \brief The results type of the Registry API
  192. typedef ss_typename_type_k traits_type::result_type result_type;
  193. private:
  194. typedef stlsoft_ns_qual(auto_buffer_old)< char_type
  195. , allocator_type
  196. , CCH_REG_API_AUTO_BUFFER
  197. > buffer_type_;
  198. public:
  199. typedef hkey_type resource_type;
  200. /// @}
  201. /// \name Construction
  202. /// @{
  203. public:
  204. /// \brief Creates an instance which provides access to the sub-keys of the named sub-key of \c hkey
  205. ///
  206. /// \param hkey A registry key handle representing the parent of \c sub_key_name
  207. /// \param sub_key_name The name of the sub-key whose sub-keys will be enumerated. If sub_key_name is NULL or the empty string, then
  208. /// the sub-keys of \c hkey will be enumerated
  209. /// \param accessMask The security access mask with which the key (hkey + sub_key_name) will be opened. Defaults to KEY_READ.
  210. ///
  211. /// \note If accessMask contains KEY_NOTIFY, this method will construct a sequence whose iterators monitor for external iterator
  212. /// invalidation. Use the alternative (four-parameter) constructor form to explicitly suppress monitoring.
  213. basic_reg_key_sequence( hkey_type hkey
  214. , char_type const *sub_key_name
  215. , REGSAM accessMask = KEY_READ);
  216. /// \brief Creates an instance which provides access to the sub-keys of the named sub-key of \c hkey
  217. ///
  218. /// \param hkey A registry key handle representing the parent of \c sub_key_name
  219. /// \param sub_key_name The name of the sub-key whose sub-keys will be enumerated. If sub_key_name is NULL or the empty string, then
  220. /// the sub-keys of \c hkey will be enumerated
  221. /// \param accessMask The security access mask with which the key (hkey + sub_key_name) will be opened. Defaults to KEY_READ
  222. /// \param bMonitorExternalInvalidation If non-zero, the iterators will monitor for external iterator invalidation, throwing
  223. /// an instance of registry_exception (or a derived class) when any sub-keys are added or removed
  224. ///
  225. /// \note The bMonitorExternalInvalidation parameter overrides the accessMask parameter. i.e. if bMonitorExternalInvalidation is
  226. /// non-zero then accessMask is combined with KEY_NOTIFY. If not, then KEY_NOTIFY is stripped from accessMask.
  227. basic_reg_key_sequence( hkey_type hkey
  228. , char_type const *sub_key_name
  229. , REGSAM accessMask
  230. , bool_type bMonitorExternalInvalidation);
  231. /// \brief Creates an instance which provides access to the sub-keys of of \c key
  232. ///
  233. /// \param key A registry key handle representing the parent of \c sub_key_name
  234. ///
  235. /// \note If the key's access mask contains KEY_NOTIFY, this method will construct a sequence whose iterators monitor for external iterator
  236. /// invalidation. Use the alternative (three-parameter) constructor form to explicitly suppress monitoring.
  237. ss_explicit_k basic_reg_key_sequence(reg_key_type const& key);
  238. /// \brief Creates an instance which provides access to the sub-keys of of \c key
  239. ///
  240. /// \param key A registry key handle representing the parent of \c sub_key_name
  241. /// \param accessMask The security access mask with which the key will be used. Defaults to KEY_READ
  242. ///
  243. /// \note If accessMask contains KEY_NOTIFY, this method will construct a sequence whose iterators monitor for external iterator
  244. /// invalidation. Use the alternative (three-parameter) constructor form to explicitly suppress monitoring.
  245. basic_reg_key_sequence( reg_key_type const &key
  246. , REGSAM accessMask);
  247. /// \brief Creates an instance which provides access to the sub-keys of of \c key
  248. ///
  249. /// \param key A registry key handle representing the parent of \c sub_key_name
  250. /// \param accessMask The security access mask with which the key will be used. Defaults to KEY_READ
  251. /// \param bMonitorExternalInvalidation If non-zero, the iterators will monitor for external iterator invalidation, throwing
  252. /// an instance of registry_exception (or a derived class) when any sub-keys are added or removed
  253. ///
  254. /// \note The bMonitorExternalInvalidation parameter overrides the accessMask parameter. i.e. if bMonitorExternalInvalidation is
  255. /// non-zero then accessMask is combined with KEY_NOTIFY. If not, then KEY_NOTIFY is stripped from accessMask.
  256. basic_reg_key_sequence( reg_key_type const &key
  257. , REGSAM accessMask
  258. , bool_type bMonitorExternalInvalidation);
  259. /// \brief Destructor
  260. ~basic_reg_key_sequence() stlsoft_throw_0();
  261. /// @}
  262. /// \name Iteration
  263. /// @{
  264. public:
  265. /// \brief Begins the iteration
  266. ///
  267. /// \return An iterator representing the start of the sequence
  268. iterator begin();
  269. /// \brief Ends the iteration
  270. ///
  271. /// \return An iterator representing the end of the sequence
  272. iterator end();
  273. #if defined(STLSOFT_LF_BIDIRECTIONAL_ITERATOR_SUPPORT)
  274. /// \brief Begins the reverse iteration
  275. ///
  276. /// \return An iterator representing the start of the reverse sequence
  277. reverse_iterator rbegin();
  278. /// \brief Ends the reverse iteration
  279. ///
  280. /// \return An iterator representing the end of the reverse sequence
  281. reverse_iterator rend();
  282. #endif /* STLSOFT_LF_BIDIRECTIONAL_ITERATOR_SUPPORT */
  283. /// @}
  284. /// \name Attributes
  285. /// @{
  286. public:
  287. /// \brief Returns the number of sub-keys
  288. ///
  289. /// \note This gives a result valid only at the epoch of the call. A
  290. /// subsequent call may return a different result.
  291. size_type current_size() const;
  292. /// \brief Returns the number of sub-keys
  293. ///
  294. /// \deprecated This is equivalent to current_size()
  295. size_type size() const;
  296. /// \brief Evalulates whether there are no sub-keys
  297. ws_bool_t empty() const;
  298. /// \brief The key handle
  299. hkey_type get_key_handle() const;
  300. /// \brief The key handle
  301. hkey_type get() const;
  302. /// @}
  303. /// \name Implementation
  304. /// @{
  305. private:
  306. registry_util::shared_handle *create_shared_handle_(result_type &res);
  307. static REGSAM validate_access_mask_(REGSAM accessMask, bool_type bMonitorExternalInvalidation);
  308. static hkey_type dup_key_(hkey_type hkey, REGSAM accessMask/* , result_type *result */);
  309. /// @}
  310. /// \name Members
  311. /// @{
  312. private:
  313. hkey_type m_hkey;
  314. const REGSAM m_accessMask;
  315. const bool_type m_bMonitorExternalInvalidation;
  316. /// @}
  317. /// \name Not to be implemented
  318. /// @{
  319. private:
  320. basic_reg_key_sequence(class_type const&);
  321. class_type& operator =(class_type const&);
  322. /// @}
  323. };
  324. /* Typedefs to commonly encountered types. */
  325. /** \brief Specialisation of the basic_reg_key_sequence template for the ANSI character type \c char
  326. *
  327. * \ingroup group__library__windows_registry
  328. */
  329. typedef basic_reg_key_sequence<ws_char_a_t, reg_traits<ws_char_a_t>, processheap_allocator<ws_char_a_t> > reg_key_sequence_a;
  330. /** \brief Specialisation of the basic_reg_key_sequence template for the Unicode character type \c wchar_t
  331. *
  332. * \ingroup group__library__windows_registry
  333. */
  334. typedef basic_reg_key_sequence<ws_char_w_t, reg_traits<ws_char_w_t>, processheap_allocator<ws_char_w_t> > reg_key_sequence_w;
  335. /** \brief Specialisation of the basic_reg_key_sequence template for the Win32 character type \c TCHAR
  336. *
  337. * \ingroup group__library__windows_registry
  338. */
  339. typedef basic_reg_key_sequence<TCHAR, reg_traits<TCHAR>, processheap_allocator<TCHAR> > reg_key_sequence;
  340. // class basic_reg_key_sequence_iterator
  341. /** \brief Iterator for the basic_reg_key_sequence class
  342. *
  343. * \ingroup group__library__windows_registry
  344. *
  345. * \param C The character type
  346. * \param T The traits type
  347. * \param V The value type
  348. * \param A The allocator type
  349. */
  350. template< ss_typename_param_k C
  351. , ss_typename_param_k T
  352. , ss_typename_param_k V
  353. , ss_typename_param_k A
  354. >
  355. class basic_reg_key_sequence_iterator
  356. : public stlsoft_ns_qual(iterator_base)<winstl_ns_qual_std(bidirectional_iterator_tag)
  357. , V
  358. , ws_ptrdiff_t
  359. , void // By-Value Temporary reference
  360. , V // By-Value Temporary reference
  361. >
  362. {
  363. /// \name Member Types
  364. /// @{
  365. public:
  366. /// \brief The character type
  367. typedef C char_type;
  368. /// \brief The traits type
  369. typedef T traits_type;
  370. /// \brief The value type
  371. typedef V value_type;
  372. /// \brief The allocator type
  373. typedef A allocator_type;
  374. /// \brief The current parameterisation of the type
  375. typedef basic_reg_key_sequence_iterator<C, T, V, A> class_type;
  376. /// \brief The size type
  377. typedef ss_typename_type_k traits_type::size_type size_type;
  378. /// \brief The difference type
  379. typedef ss_typename_type_k traits_type::difference_type difference_type;
  380. /// \brief The string type
  381. typedef ss_typename_type_k traits_type::string_type string_type;
  382. /// \brief The index type
  383. typedef ws_sint32_t index_type;
  384. /// \brief The hkey type
  385. typedef ss_typename_type_k traits_type::hkey_type hkey_type;
  386. private:
  387. /// \brief The results type of the Registry API
  388. typedef ss_typename_type_k traits_type::result_type result_type;
  389. /// \brief The Boolean type
  390. typedef ws_bool_t bool_type;
  391. private:
  392. typedef stlsoft_ns_qual(auto_buffer_old)< char_type
  393. , allocator_type
  394. , CCH_REG_API_AUTO_BUFFER
  395. > buffer_type_;
  396. /// @}
  397. /// \name Construction
  398. /// @{
  399. private:
  400. friend class basic_reg_key_sequence<C, T, A>;
  401. /// \note Eats the key, rather than taking a copy
  402. basic_reg_key_sequence_iterator(registry_util::shared_handle *handle, char_type const* name, size_type cchName, index_type index, REGSAM accessMask)
  403. : m_handle(handle)
  404. , m_index(index)
  405. , m_name(name, cchName)
  406. , m_accessMask(accessMask)
  407. {
  408. WINSTL_ASSERT(NULL != m_handle);
  409. m_handle->test_reset_and_throw();
  410. m_handle->AddRef();
  411. }
  412. public:
  413. /// \brief Default constructor
  414. basic_reg_key_sequence_iterator();
  415. /// \brief Copy constructor
  416. basic_reg_key_sequence_iterator(class_type const& rhs);
  417. /// \brief Destructor
  418. ~basic_reg_key_sequence_iterator() stlsoft_throw_0();
  419. /// \brief Copy assignment operator
  420. class_type& operator =(class_type const& rhs);
  421. /// @}
  422. /// \name Accessors
  423. /// @{
  424. public:
  425. string_type const &get_key_name() const;
  426. /// @}
  427. /// \name Operators
  428. /// @{
  429. public:
  430. /// \brief Pre-increment operator
  431. class_type& operator ++();
  432. /// \brief Pre-decrement operator
  433. class_type& operator --();
  434. /// \brief Post-increment operator
  435. const class_type operator ++(int);
  436. /// \brief Post-decrement operator
  437. const class_type operator --(int);
  438. /// \brief Dereference to return the value representing the current position
  439. const value_type operator *() const;
  440. /// \brief Evaluates whether \c this and \c rhs are equivalent
  441. ws_bool_t equal(class_type const& rhs) const;
  442. /// \brief Evaluates whether \c this and \c rhs are equivalent
  443. ws_bool_t operator ==(class_type const& rhs) const;
  444. /// \brief Evaluates whether \c this and \c rhs are not equivalent
  445. ws_bool_t operator !=(class_type const& rhs) const;
  446. /// @}
  447. /// \name Implementation
  448. /// @{
  449. private:
  450. static index_type sentinel_() stlsoft_throw_0();
  451. /// @}
  452. /// \name Members
  453. /// @{
  454. private:
  455. registry_util::shared_handle *m_handle; // Shared context for registry key and event object
  456. index_type m_index; // Current iteration index
  457. string_type m_name; // The value name
  458. REGSAM m_accessMask; // Security access mask
  459. /// @}
  460. };
  461. ////////////////////////////////////////////////////////////////////////////
  462. // Unit-testing
  463. #ifdef STLSOFT_UNITTEST
  464. # include "./unittest/reg_key_sequence_unittest_.h"
  465. #endif /* STLSOFT_UNITTEST */
  466. ////////////////////////////////////////////////////////////////////////////
  467. // Implementation
  468. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  469. // basic_reg_key_sequence
  470. template <ss_typename_param_k C, ss_typename_param_k T, ss_typename_param_k A>
  471. inline registry_util::shared_handle *basic_reg_key_sequence<C, T, A>::create_shared_handle_(result_type &res)
  472. {
  473. // 1. Duplicate the registry handle
  474. //
  475. // 2. create the shared_handle
  476. hkey_type hkey2 = traits_type::key_dup(m_hkey, m_accessMask, &res);
  477. if(NULL == hkey2)
  478. {
  479. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  480. static const char message[] = "could not duplicate key";
  481. if(ERROR_ACCESS_DENIED == res)
  482. {
  483. STLSOFT_THROW_X(access_denied_exception(message, res));
  484. }
  485. else
  486. {
  487. STLSOFT_THROW_X(key_not_duplicated_exception(message, res));
  488. }
  489. #else /* ? STLSOFT_CF_EXCEPTION_SUPPORT */
  490. ; // This will fall through to the end() call at the end of the function
  491. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  492. }
  493. else
  494. {
  495. // Pop it in a scoped handle for RAII
  496. scoped_handle<HKEY> sh(hkey2, ::RegCloseKey);
  497. registry_util::shared_handle *handle = registry_util::create_shared_handle(hkey2, m_bMonitorExternalInvalidation, REG_NOTIFY_CHANGE_NAME);
  498. if(NULL == handle)
  499. {
  500. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  501. static const char message[] = "could not create shared enumeration context";
  502. DWORD err = ::GetLastError();
  503. if(ERROR_ACCESS_DENIED == err)
  504. {
  505. STLSOFT_THROW_X(access_denied_exception(message, err));
  506. }
  507. else
  508. {
  509. STLSOFT_THROW_X(registry_exception(message, err));
  510. }
  511. #else /* ? STLSOFT_CF_EXCEPTION_SUPPORT */
  512. ; // This will fall through to the end() call at the end of the function
  513. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  514. }
  515. else
  516. {
  517. sh.detach();
  518. return handle;
  519. }
  520. }
  521. return NULL;
  522. }
  523. template <ss_typename_param_k C, ss_typename_param_k T, ss_typename_param_k A>
  524. inline /* static */ REGSAM basic_reg_key_sequence<C, T, A>::validate_access_mask_(REGSAM accessMask, ss_typename_type_k basic_reg_key_sequence<C, T, A>::bool_type bMonitorExternalInvalidation)
  525. {
  526. if(bMonitorExternalInvalidation)
  527. {
  528. return accessMask | KEY_NOTIFY;
  529. }
  530. else
  531. {
  532. return accessMask & ~(KEY_NOTIFY);
  533. }
  534. }
  535. template <ss_typename_param_k C, ss_typename_param_k T, ss_typename_param_k A>
  536. inline /* static */ ss_typename_type_ret_k basic_reg_key_sequence<C, T, A>::hkey_type basic_reg_key_sequence<C, T, A>::dup_key_(ss_typename_type_k basic_reg_key_sequence<C, T, A>::hkey_type hkey, REGSAM accessMask/* , ss_typename_type_k basic_reg_key_sequence<C, T, A>::result_type *result */)
  537. {
  538. result_type res;
  539. HKEY hkeyDup = traits_type::key_dup(hkey, accessMask, &res);
  540. if(ERROR_SUCCESS != res)
  541. {
  542. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  543. static const char message[] = "could not duplicate key";
  544. if(ERROR_ACCESS_DENIED == res)
  545. {
  546. STLSOFT_THROW_X(access_denied_exception(message, res));
  547. }
  548. else
  549. {
  550. STLSOFT_THROW_X(key_not_duplicated_exception(message, res));
  551. }
  552. #else /* ? STLSOFT_CF_EXCEPTION_SUPPORT */
  553. hkeyDup = NULL;
  554. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  555. }
  556. return hkeyDup;
  557. }
  558. template <ss_typename_param_k C, ss_typename_param_k T, ss_typename_param_k A>
  559. inline basic_reg_key_sequence<C, T, A>::basic_reg_key_sequence( ss_typename_type_k basic_reg_key_sequence<C, T, A>::hkey_type hkey
  560. , ss_typename_type_k basic_reg_key_sequence<C, T, A>::char_type const* sub_key_name
  561. , REGSAM accessMask /* = KEY_READ */)
  562. : m_hkey(NULL)
  563. , m_accessMask(accessMask)
  564. , m_bMonitorExternalInvalidation(0 != (KEY_NOTIFY & accessMask))
  565. {
  566. result_type res;
  567. if(ERROR_SUCCESS != (res = traits_type::reg_open_key(hkey, sub_key_name, &m_hkey, accessMask)))
  568. {
  569. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  570. static const char message[] = "could not open key";
  571. if(ERROR_ACCESS_DENIED == res)
  572. {
  573. STLSOFT_THROW_X(access_denied_exception(message, res));
  574. }
  575. else
  576. {
  577. STLSOFT_THROW_X(registry_exception(message, res));
  578. }
  579. #else /* ? STLSOFT_CF_EXCEPTION_SUPPORT */
  580. m_hkey = NULL;
  581. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  582. }
  583. }
  584. template <ss_typename_param_k C, ss_typename_param_k T, ss_typename_param_k A>
  585. inline basic_reg_key_sequence<C, T, A>::basic_reg_key_sequence( ss_typename_type_k basic_reg_key_sequence<C, T, A>::hkey_type hkey
  586. , ss_typename_type_k basic_reg_key_sequence<C, T, A>::char_type const* sub_key_name
  587. , REGSAM accessMask
  588. , ss_typename_type_k basic_reg_key_sequence<C, T, A>::bool_type bMonitorExternalInvalidation)
  589. : m_hkey(NULL)
  590. , m_accessMask(validate_access_mask_(accessMask, bMonitorExternalInvalidation))
  591. , m_bMonitorExternalInvalidation(bMonitorExternalInvalidation)
  592. {
  593. result_type res;
  594. if(ERROR_SUCCESS != (res = traits_type::reg_open_key(hkey, sub_key_name, &m_hkey, accessMask)))
  595. {
  596. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  597. static const char message[] = "could not open key";
  598. if(ERROR_ACCESS_DENIED == res)
  599. {
  600. STLSOFT_THROW_X(access_denied_exception(message, res));
  601. }
  602. else
  603. {
  604. STLSOFT_THROW_X(registry_exception(message, res));
  605. }
  606. #else /* ? STLSOFT_CF_EXCEPTION_SUPPORT */
  607. m_hkey = NULL;
  608. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  609. }
  610. }
  611. template <ss_typename_param_k C, ss_typename_param_k T, ss_typename_param_k A>
  612. inline basic_reg_key_sequence<C, T, A>::basic_reg_key_sequence(ss_typename_type_k basic_reg_key_sequence<C, T, A>::reg_key_type const& key)
  613. : m_hkey(dup_key_(key.m_hkey, key.get_access_mask()))
  614. , m_accessMask(key.get_access_mask())
  615. , m_bMonitorExternalInvalidation(0 != (KEY_NOTIFY & key.get_access_mask()))
  616. {
  617. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  618. if(NULL == m_hkey)
  619. {
  620. STLSOFT_THROW_X(registry_exception("Failed to take duplicate of key", ::GetLastError()));
  621. }
  622. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  623. }
  624. template <ss_typename_param_k C, ss_typename_param_k T, ss_typename_param_k A>
  625. inline basic_reg_key_sequence<C, T, A>::basic_reg_key_sequence( ss_typename_type_k basic_reg_key_sequence<C, T, A>::reg_key_type const &key
  626. , REGSAM accessMask)
  627. : m_hkey(dup_key_(key.m_hkey, accessMask))
  628. , m_accessMask(accessMask)
  629. , m_bMonitorExternalInvalidation(0 != (KEY_NOTIFY & accessMask))
  630. {
  631. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  632. if(NULL == m_hkey)
  633. {
  634. STLSOFT_THROW_X(registry_exception("Failed to take duplicate of key", ::GetLastError()));
  635. }
  636. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  637. }
  638. template <ss_typename_param_k C, ss_typename_param_k T, ss_typename_param_k A>
  639. inline basic_reg_key_sequence<C, T, A>::basic_reg_key_sequence( ss_typename_type_k basic_reg_key_sequence<C, T, A>::reg_key_type const &key
  640. , REGSAM accessMask
  641. , bool_type bMonitorExternalInvalidation)
  642. : m_hkey(dup_key_(key.m_hkey, validate_access_mask_(accessMask, bMonitorExternalInvalidation)))
  643. , m_accessMask(validate_access_mask_(accessMask, bMonitorExternalInvalidation))
  644. , m_bMonitorExternalInvalidation(bMonitorExternalInvalidation)
  645. {
  646. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  647. if(NULL == m_hkey)
  648. {
  649. STLSOFT_THROW_X(registry_exception("Failed to take duplicate of key", ::GetLastError()));
  650. }
  651. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  652. }
  653. template <ss_typename_param_k C, ss_typename_param_k T, ss_typename_param_k A>
  654. inline basic_reg_key_sequence<C, T, A>::~basic_reg_key_sequence() stlsoft_throw_0()
  655. {
  656. if(m_hkey != NULL)
  657. {
  658. ::RegCloseKey(m_hkey);
  659. }
  660. }
  661. template <ss_typename_param_k C, ss_typename_param_k T, ss_typename_param_k A>
  662. inline ss_typename_type_ret_k basic_reg_key_sequence<C, T, A>::iterator basic_reg_key_sequence<C, T, A>::begin()
  663. {
  664. // 1. Check that there are some items
  665. //
  666. // 2. Duplicate the registry key handle & Create the shared handle
  667. //
  668. // 4. Loop to get the full name
  669. //
  670. // 5. Create the iterator and return
  671. // 1. Check that there are some items
  672. // Grab enough for the first item
  673. size_type cchName = 0;
  674. ws_uint32_t numEntries = 0;
  675. result_type res = traits_type::reg_query_info(m_hkey, NULL, NULL, &numEntries, &cchName, NULL, NULL, NULL, NULL, NULL, NULL);
  676. if(ERROR_SUCCESS != res)
  677. {
  678. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  679. static const char message[] = "could not elicit sub-key information";
  680. if(ERROR_ACCESS_DENIED == res)
  681. {
  682. STLSOFT_THROW_X(access_denied_exception(message, res));
  683. }
  684. else
  685. {
  686. STLSOFT_THROW_X(registry_exception(message, res));
  687. }
  688. #else /* ? STLSOFT_CF_EXCEPTION_SUPPORT */
  689. ; // This will fall through to the end() call at the end of the function
  690. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  691. }
  692. else
  693. {
  694. if(0 != numEntries)
  695. {
  696. // 2. Duplicate the registry key handle & create the shared handle
  697. registry_util::shared_handle *handle = create_shared_handle_(res);
  698. ws_sint32_t index = 0;
  699. if(NULL == handle)
  700. {
  701. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  702. static const char message[] = "could not create shared enumeration context";
  703. if(ERROR_ACCESS_DENIED == res)
  704. {
  705. STLSOFT_THROW_X(access_denied_exception(message, res));
  706. }
  707. else
  708. {
  709. STLSOFT_THROW_X(registry_exception(message, res));
  710. }
  711. #else /* ? STLSOFT_CF_EXCEPTION_SUPPORT */
  712. ; // This will fall through to the end() call at the end of the function
  713. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  714. }
  715. else
  716. {
  717. ref_ptr<registry_util::shared_handle> ref(handle, false); // Eat the reference here. The iterator will take another
  718. // 4. Loop to get the full name
  719. buffer_type_ buffer(++cchName); // This is increased so that the call to reg_enum_key is likely to succeed
  720. for(; !buffer.empty(); ) // Need to loop because sub-keys can change, when we're not monitoring
  721. {
  722. cchName = buffer.size();
  723. res = traits_type::reg_enum_key(m_hkey, 0, &buffer[0], &cchName);
  724. if(ERROR_MORE_DATA == res)
  725. {
  726. if(!buffer.resize(2 * buffer.size())) // Throws, or returns false
  727. {
  728. cchName = 0;
  729. index = const_iterator::sentinel_();
  730. break;
  731. }
  732. continue; // "Let's go round again"
  733. }
  734. else if(ERROR_SUCCESS != res)
  735. {
  736. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  737. static const char message[] = "could not enumerate sub-keys";
  738. if(ERROR_ACCESS_DENIED == res)
  739. {
  740. STLSOFT_THROW_X(access_denied_exception(message, res));
  741. }
  742. else
  743. {
  744. STLSOFT_THROW_X(registry_exception(message, res));
  745. }
  746. #else /* ? STLSOFT_CF_EXCEPTION_SUPPORT */
  747. cchName = 0;
  748. index = const_iterator::sentinel_();
  749. break; // This will fall through to the end() call at the end of the function
  750. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  751. }
  752. else
  753. {
  754. break;
  755. }
  756. }
  757. // 5. Create the iterator and return
  758. return iterator(handle, buffer.data(), cchName, index, m_accessMask);
  759. }
  760. }
  761. }
  762. return end();
  763. }
  764. template <ss_typename_param_k C, ss_typename_param_k T, ss_typename_param_k A>
  765. inline ss_typename_type_ret_k basic_reg_key_sequence<C, T, A>::iterator basic_reg_key_sequence<C, T, A>::end()
  766. {
  767. result_type res;
  768. registry_util::shared_handle *handle = create_shared_handle_(res);
  769. ref_ptr<registry_util::shared_handle> ref(handle, false); // Eat the reference here. The iterator will take another
  770. ws_sint32_t index = const_iterator::sentinel_();
  771. if(NULL == handle)
  772. {
  773. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  774. STLSOFT_THROW_X(registry_exception("Failed to take duplicate of key", res));
  775. #else /* ? STLSOFT_CF_EXCEPTION_SUPPORT */
  776. index = 0; // This will fall through to the constructor at the end of the function
  777. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  778. }
  779. return iterator(handle, NULL, 0, index, m_accessMask);
  780. }
  781. #if defined(STLSOFT_LF_BIDIRECTIONAL_ITERATOR_SUPPORT)
  782. template <ss_typename_param_k C, ss_typename_param_k T, ss_typename_param_k A>
  783. inline ss_typename_type_ret_k basic_reg_key_sequence<C, T, A>::reverse_iterator basic_reg_key_sequence<C, T, A>::rbegin()
  784. {
  785. return reverse_iterator(end());
  786. }
  787. template <ss_typename_param_k C, ss_typename_param_k T, ss_typename_param_k A>
  788. inline ss_typename_type_ret_k basic_reg_key_sequence<C, T, A>::reverse_iterator basic_reg_key_sequence<C, T, A>::rend()
  789. {
  790. return reverse_iterator(begin());
  791. }
  792. #endif /* STLSOFT_LF_BIDIRECTIONAL_ITERATOR_SUPPORT */
  793. template <ss_typename_param_k C, ss_typename_param_k T, ss_typename_param_k A>
  794. inline ss_typename_type_ret_k basic_reg_key_sequence<C, T, A>::size_type basic_reg_key_sequence<C, T, A>::size() const
  795. {
  796. return current_size();
  797. }
  798. template <ss_typename_param_k C, ss_typename_param_k T, ss_typename_param_k A>
  799. inline ss_typename_type_ret_k basic_reg_key_sequence<C, T, A>::size_type basic_reg_key_sequence<C, T, A>::current_size() const
  800. {
  801. ws_uint32_t numEntries;
  802. result_type res = traits_type::reg_query_info(m_hkey, NULL, NULL, &numEntries, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
  803. if(ERROR_SUCCESS != res)
  804. {
  805. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  806. static const char message[] = "could not elicit number of sub-keys";
  807. if(ERROR_ACCESS_DENIED == res)
  808. {
  809. STLSOFT_THROW_X(access_denied_exception(message, res));
  810. }
  811. else
  812. {
  813. STLSOFT_THROW_X(registry_exception(message, res));
  814. }
  815. #else /* ? STLSOFT_CF_EXCEPTION_SUPPORT */
  816. numEntries = 0;
  817. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  818. }
  819. return static_cast<size_type>(numEntries);
  820. }
  821. template <ss_typename_param_k C, ss_typename_param_k T, ss_typename_param_k A>
  822. inline ws_bool_t basic_reg_key_sequence<C, T, A>::empty() const
  823. {
  824. return 0 == size();
  825. }
  826. template <ss_typename_param_k C, ss_typename_param_k T, ss_typename_param_k A>
  827. inline ss_typename_type_ret_k basic_reg_key_sequence<C, T, A>::hkey_type basic_reg_key_sequence<C, T, A>::get_key_handle() const
  828. {
  829. return m_hkey;
  830. }
  831. template <ss_typename_param_k C, ss_typename_param_k T, ss_typename_param_k A>
  832. inline ss_typename_type_ret_k basic_reg_key_sequence<C, T, A>::hkey_type basic_reg_key_sequence<C, T, A>::get() const
  833. {
  834. return get_key_handle();
  835. }
  836. // basic_reg_key_sequence_iterator
  837. template <ss_typename_param_k C, ss_typename_param_k T, ss_typename_param_k V, ss_typename_param_k A>
  838. inline /* static */ ss_typename_type_ret_k basic_reg_key_sequence_iterator<C, T, V, A>::index_type basic_reg_key_sequence_iterator<C, T, V, A>::sentinel_() stlsoft_throw_0()
  839. {
  840. return 0x7fffffff;
  841. }
  842. template <ss_typename_param_k C, ss_typename_param_k T, ss_typename_param_k V, ss_typename_param_k A>
  843. inline basic_reg_key_sequence_iterator<C, T, V, A>::basic_reg_key_sequence_iterator()
  844. : m_handle(NULL)
  845. , m_index(sentinel_())
  846. , m_name()
  847. , m_accessMask(KEY_READ)
  848. {}
  849. template <ss_typename_param_k C, ss_typename_param_k T, ss_typename_param_k V, ss_typename_param_k A>
  850. inline basic_reg_key_sequence_iterator<C, T, V, A>::basic_reg_key_sequence_iterator(class_type const& rhs)
  851. : m_handle(rhs.m_handle)
  852. , m_index(rhs.m_index)
  853. , m_name(rhs.m_name)
  854. , m_accessMask(rhs.m_accessMask)
  855. {
  856. if(NULL != m_handle)
  857. {
  858. m_handle->AddRef();
  859. }
  860. }
  861. template <ss_typename_param_k C, ss_typename_param_k T, ss_typename_param_k V, ss_typename_param_k A>
  862. inline ss_typename_type_ret_k basic_reg_key_sequence_iterator<C, T, V, A>::class_type& basic_reg_key_sequence_iterator<C, T, V, A>::operator =(ss_typename_type_k basic_reg_key_sequence_iterator<C, T, V, A>::class_type const& rhs)
  863. {
  864. registry_util::shared_handle *this_handle;
  865. m_index = rhs.m_index;
  866. m_name = rhs.m_name;
  867. this_handle = m_handle;
  868. m_handle = rhs.m_handle;
  869. m_accessMask = rhs.m_accessMask;
  870. if(NULL != m_handle)
  871. {
  872. m_handle->AddRef();
  873. }
  874. if(NULL != this_handle)
  875. {
  876. this_handle->Release();
  877. }
  878. return *this;
  879. }
  880. template <ss_typename_param_k C, ss_typename_param_k T, ss_typename_param_k V, ss_typename_param_k A>
  881. inline basic_reg_key_sequence_iterator<C, T, V, A>::~basic_reg_key_sequence_iterator() stlsoft_throw_0()
  882. {
  883. if(NULL != m_handle)
  884. {
  885. m_handle->Release();
  886. }
  887. }
  888. template <ss_typename_param_k C, ss_typename_param_k T, ss_typename_param_k V, ss_typename_param_k A>
  889. inline const ss_typename_type_k basic_reg_key_sequence_iterator<C, T, V, A>::string_type &basic_reg_key_sequence_iterator<C, T, V, A>::get_key_name() const
  890. {
  891. return m_name;
  892. }
  893. template <ss_typename_param_k C, ss_typename_param_k T, ss_typename_param_k V, ss_typename_param_k A>
  894. inline ss_typename_type_ret_k basic_reg_key_sequence_iterator<C, T, V, A>::class_type& basic_reg_key_sequence_iterator<C, T, V, A>::operator ++()
  895. {
  896. WINSTL_MESSAGE_ASSERT("Attempting to increment an invalid iterator!", NULL != m_handle);
  897. WINSTL_MESSAGE_ASSERT("Attempting to increment an invalid iterator!", sentinel_() != m_index);
  898. // Grab enough for the first item
  899. size_type cchName = 0;
  900. result_type res = traits_type::reg_query_info(m_handle->m_hkey, NULL, NULL, NULL, &cchName, NULL, NULL, NULL, NULL, NULL, NULL);
  901. if(ERROR_SUCCESS != res)
  902. {
  903. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  904. static const char message[] = "could not elicit sub-key information";
  905. if(ERROR_ACCESS_DENIED == res)
  906. {
  907. STLSOFT_THROW_X(access_denied_exception(message, res));
  908. }
  909. else
  910. {
  911. STLSOFT_THROW_X(registry_exception(message, res));
  912. }
  913. #else /* ? STLSOFT_CF_EXCEPTION_SUPPORT */
  914. m_index = sentinel_();
  915. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  916. }
  917. else
  918. {
  919. buffer_type_ buffer(++cchName); // This is increased so that the call to reg_enum_key is likely to succeed
  920. for(; !buffer.empty(); buffer.resize(2 * buffer.size())) // Need to loop because sub-keys can change, when we're not monitoring
  921. {
  922. cchName = buffer.size();
  923. res = traits_type::reg_enum_key(m_handle->m_hkey, static_cast<ws_dword_t>(1 + m_index), &buffer[0], &cchName);
  924. if(ERROR_MORE_DATA == res)
  925. {
  926. continue; // "Let's go round again"
  927. }
  928. else if(ERROR_NO_MORE_ITEMS == res)
  929. {
  930. m_index = sentinel_();
  931. break;
  932. }
  933. else if(ERROR_SUCCESS != res)
  934. {
  935. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  936. static const char message[] = "could not enumerate sub-keys";
  937. if(ERROR_ACCESS_DENIED == res)
  938. {
  939. STLSOFT_THROW_X(access_denied_exception(message, res));
  940. }
  941. else
  942. {
  943. STLSOFT_THROW_X(registry_exception(message, res));
  944. }
  945. #else /* ? STLSOFT_CF_EXCEPTION_SUPPORT */
  946. m_index = sentinel_();
  947. break;
  948. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  949. }
  950. else
  951. {
  952. m_name.assign(buffer.data(), cchName);
  953. ++m_index;
  954. break;
  955. }
  956. }
  957. }
  958. m_handle->test_reset_and_throw();
  959. return *this;
  960. }
  961. template <ss_typename_param_k C, ss_typename_param_k T, ss_typename_param_k V, ss_typename_param_k A>
  962. inline ss_typename_type_ret_k basic_reg_key_sequence_iterator<C, T, V, A>::class_type& basic_reg_key_sequence_iterator<C, T, V, A>::operator --()
  963. {
  964. WINSTL_MESSAGE_ASSERT("Attempting to decrement an invalid iterator", NULL != m_handle);
  965. // Grab enough for the first item
  966. size_type cchName = 0;
  967. ws_uint32_t numEntries = 0;
  968. result_type res = traits_type::reg_query_info(m_handle->m_hkey, NULL, NULL, &numEntries, &cchName, NULL, NULL, NULL, NULL, NULL, NULL);
  969. if(ERROR_SUCCESS != res)
  970. {
  971. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  972. static const char message[] = "could not elicit sub-key information";
  973. if(ERROR_ACCESS_DENIED == res)
  974. {
  975. STLSOFT_THROW_X(access_denied_exception(message, res));
  976. }
  977. else
  978. {
  979. STLSOFT_THROW_X(registry_exception(message, res));
  980. }
  981. #else /* ? STLSOFT_CF_EXCEPTION_SUPPORT */
  982. m_index = sentinel_();
  983. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  984. }
  985. else
  986. {
  987. buffer_type_ buffer(++cchName); // This is increased so that the call to reg_enum_key is likely to succeed
  988. ws_dword_t index;
  989. // If the iterator is currently at the "end()", ...
  990. if(m_index == sentinel_())
  991. {
  992. // ... then set the index to be one past the end
  993. index = numEntries - 1;
  994. }
  995. else
  996. {
  997. // ... otherwise just go back one from current
  998. index = m_index - 1;
  999. }
  1000. for(; !buffer.empty(); buffer.resize(2 * buffer.size())) // Need to loop because sub-keys can change, when we're not monitoring
  1001. {
  1002. cchName = buffer.size();
  1003. res = traits_type::reg_enum_key(m_handle->m_hkey, index, &buffer[0], &cchName);
  1004. if(ERROR_MORE_DATA == res)
  1005. {
  1006. continue; // "Let's go round again"
  1007. }
  1008. else if(ERROR_SUCCESS != res)
  1009. {
  1010. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  1011. static const char message[] = "could not elicit sub-key information";
  1012. if(ERROR_ACCESS_DENIED == res)
  1013. {
  1014. STLSOFT_THROW_X(access_denied_exception(message, res));
  1015. }
  1016. else
  1017. {
  1018. STLSOFT_THROW_X(registry_exception(message, res));
  1019. }
  1020. #else /* ? STLSOFT_CF_EXCEPTION_SUPPORT */
  1021. m_index = sentinel_();
  1022. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  1023. }
  1024. else
  1025. {
  1026. m_name.assign(buffer.data(), cchName);
  1027. m_index = index;
  1028. break;
  1029. }
  1030. }
  1031. }
  1032. m_handle->test_reset_and_throw();
  1033. return *this;
  1034. }
  1035. template <ss_typename_param_k C, ss_typename_param_k T, ss_typename_param_k V, ss_typename_param_k A>
  1036. inline const ss_typename_type_k basic_reg_key_sequence_iterator<C, T, V, A>::class_type basic_reg_key_sequence_iterator<C, T, V, A>::operator ++(int)
  1037. {
  1038. class_type ret(*this);
  1039. operator ++();
  1040. return ret;
  1041. }
  1042. template <ss_typename_param_k C, ss_typename_param_k T, ss_typename_param_k V, ss_typename_param_k A>
  1043. inline const ss_typename_type_k basic_reg_key_sequence_iterator<C, T, V, A>::class_type basic_reg_key_sequence_iterator<C, T, V, A>::operator --(int)
  1044. {
  1045. class_type ret(*this);
  1046. operator --();
  1047. return ret;
  1048. }
  1049. template <ss_typename_param_k C, ss_typename_param_k T, ss_typename_param_k V, ss_typename_param_k A>
  1050. inline const ss_typename_type_k basic_reg_key_sequence_iterator<C, T, V, A>::value_type basic_reg_key_sequence_iterator<C, T, V, A>::operator *() const
  1051. {
  1052. WINSTL_MESSAGE_ASSERT("Attempting to dereference an invalid iterator", NULL != m_handle);
  1053. m_handle->test_reset_and_throw();
  1054. return value_type(m_handle->m_hkey, m_name, m_accessMask);
  1055. }
  1056. template <ss_typename_param_k C, ss_typename_param_k T, ss_typename_param_k V, ss_typename_param_k A>
  1057. inline ws_bool_t basic_reg_key_sequence_iterator<C, T, V, A>::equal(class_type const& rhs) const
  1058. {
  1059. return m_index == rhs.m_index;
  1060. }
  1061. template <ss_typename_param_k C, ss_typename_param_k T, ss_typename_param_k V, ss_typename_param_k A>
  1062. inline ws_bool_t basic_reg_key_sequence_iterator<C, T, V, A>::operator ==(class_type const& rhs) const
  1063. {
  1064. return equal(rhs);
  1065. }
  1066. template <ss_typename_param_k C, ss_typename_param_k T, ss_typename_param_k V, ss_typename_param_k A>
  1067. inline ws_bool_t basic_reg_key_sequence_iterator<C, T, V, A>::operator !=(class_type const& rhs) const
  1068. {
  1069. return !equal(rhs);
  1070. }
  1071. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  1072. /* ////////////////////////////////////////////////////////////////////// */
  1073. #ifndef _WINSTL_NO_NAMESPACE
  1074. # if defined(_STLSOFT_NO_NAMESPACE) || \
  1075. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  1076. } // namespace winstl
  1077. # else
  1078. } // namespace winstl_project
  1079. } // namespace stlsoft
  1080. # endif /* _STLSOFT_NO_NAMESPACE */
  1081. #endif /* !_WINSTL_NO_NAMESPACE */
  1082. /* ////////////////////////////////////////////////////////////////////// */
  1083. #endif /* WINSTL_INCL_WINSTL_REGISTRY_HPP_REG_KEY_SEQUENCE */
  1084. /* ///////////////////////////// end of file //////////////////////////// */