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.

1223 lines
48 KiB

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