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.

929 lines
24 KiB

  1. /* /////////////////////////////////////////////////////////////////////////
  2. * File: comstl/util/variant.hpp (originally MOVriant.h/.cpp, ::SynesisCom)
  3. *
  4. * Purpose: variant class.
  5. *
  6. * Created: 12th December 1996
  7. * Updated: 5th March 2011
  8. *
  9. * Home: http://stlsoft.org/
  10. *
  11. * Copyright (c) 1996-2011, Matthew Wilson and Synesis Software
  12. * All rights reserved.
  13. *
  14. * Redistribution and use in source and binary forms, with or without
  15. * modification, are permitted provided that the following conditions are met:
  16. *
  17. * - Redistributions of source code must retain the above copyright notice, this
  18. * list of conditions and the following disclaimer.
  19. * - Redistributions in binary form must reproduce the above copyright notice,
  20. * this list of conditions and the following disclaimer in the documentation
  21. * and/or other materials provided with the distribution.
  22. * - Neither the name(s) of Matthew Wilson and Synesis Software nor the names of
  23. * any contributors may be used to endorse or promote products derived from
  24. * this software without specific prior written permission.
  25. *
  26. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  27. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  28. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  29. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  30. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  31. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  32. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  33. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  34. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  35. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  36. * POSSIBILITY OF SUCH DAMAGE.
  37. *
  38. * ////////////////////////////////////////////////////////////////////// */
  39. /** \file comstl/util/variant.hpp
  40. *
  41. * \brief [C++ only; requires COM] Definition of the comstl::variant class
  42. * (\ref group__library__utility__com "COM Utility" Library).
  43. */
  44. #ifndef COMSTL_INCL_COMSTL_UTIL_HPP_COMSTL_VARIANT
  45. #define COMSTL_INCL_COMSTL_UTIL_HPP_COMSTL_VARIANT
  46. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  47. # define _COMSTL_VER_COMSTL_UTIL_HPP_COMSTL_VARIANT_MAJOR 2
  48. # define _COMSTL_VER_COMSTL_UTIL_HPP_COMSTL_VARIANT_MINOR 3
  49. # define _COMSTL_VER_COMSTL_UTIL_HPP_COMSTL_VARIANT_REVISION 5
  50. # define _COMSTL_VER_COMSTL_UTIL_HPP_COMSTL_VARIANT_EDIT 158
  51. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  52. /* /////////////////////////////////////////////////////////////////////////
  53. * Includes
  54. */
  55. #ifndef COMSTL_INCL_COMSTL_H_COMSTL
  56. # include <comstl/comstl.h>
  57. #endif /* !COMSTL_INCL_COMSTL_H_COMSTL */
  58. #ifndef COMSTL_INCL_COMSTL_STRING_H_BSTR_FUNCTIONS
  59. # include <comstl/string/BSTR_functions.h>
  60. #endif /* !COMSTL_INCL_COMSTL_STRING_H_BSTR_FUNCTIONS */
  61. #ifndef COMSTL_INCL_COMSTL_SHIMS_ACCESS_HPP_STRING
  62. # include <comstl/shims/access/string.hpp>
  63. #endif /* !COMSTL_INCL_COMSTL_SHIMS_ACCESS_HPP_STRING */
  64. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  65. # ifndef COMSTL_INCL_COMSTL_ERROR_HPP_EXCEPTIONS
  66. # include <comstl/error/exceptions.hpp>
  67. # endif /* !COMSTL_INCL_COMSTL_ERROR_HPP_EXCEPTIONS */
  68. #endif /* !STLSOFT_CF_EXCEPTION_SUPPORT */
  69. #ifndef COMSTL_INCL_COMSTL_UTIL_HPP_INTERFACE_TRAITS
  70. # include <comstl/util/interface_traits.hpp>
  71. #endif /* !COMSTL_INCL_COMSTL_UTIL_HPP_INTERFACE_TRAITS */
  72. #ifndef COMSTL_INCL_COMSTL_UTIL_H_VARIANT_FUNCTIONS
  73. # include <comstl/util/VARIANT_functions.h>
  74. #endif /* !COMSTL_INCL_COMSTL_UTIL_H_VARIANT_FUNCTIONS */
  75. #ifndef STLSOFT_INCL_STLSOFT_UTIL_HPP_CONSTRAINTS
  76. # include <stlsoft/util/constraints.hpp>
  77. #endif /* !STLSOFT_INCL_STLSOFT_UTIL_HPP_CONSTRAINTS */
  78. /* /////////////////////////////////////////////////////////////////////////
  79. * Namespace
  80. */
  81. #ifndef _COMSTL_NO_NAMESPACE
  82. # if defined(_STLSOFT_NO_NAMESPACE) || \
  83. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  84. /* There is no stlsoft namespace, so must define ::comstl */
  85. namespace comstl
  86. {
  87. # else
  88. /* Define stlsoft::comstl_project */
  89. namespace stlsoft
  90. {
  91. namespace comstl_project
  92. {
  93. # endif /* _STLSOFT_NO_NAMESPACE */
  94. #endif /* !_COMSTL_NO_NAMESPACE */
  95. /* /////////////////////////////////////////////////////////////////////////
  96. * Classes
  97. */
  98. /** \brief Facade for the COM VARIANT type
  99. *
  100. * \ingroup group__library__utility__com
  101. *
  102. * \remarks comstl::variant publicly derives from \c VARIANT as a measure
  103. * of expedience, rather than as an act of design sophistication. Any
  104. * manual manipulation of the instances, or their member variables, is
  105. * at the user's risk. Notwithstanding, this is helped by the fact that
  106. * comstl::variant declares no member variables and no virtual member
  107. * functions - for most compilers this means that the Empty Derived
  108. * Optimisation (see Section 12.4 of Imperfect C++) will apply.
  109. */
  110. class variant
  111. : public VARIANT
  112. {
  113. /// Member Types
  114. public:
  115. typedef variant class_type;
  116. typedef cs_bool_t bool_type;
  117. typedef cs_size_t size_type;
  118. /// Conversion
  119. public:
  120. /** Default constructor
  121. *
  122. * Initialises the instance
  123. *
  124. * \post <code>assert(VT_EMPTY == this->vt)</code>
  125. *
  126. * \exception - Does not throw an exception
  127. */
  128. variant();
  129. /** Copying constructor
  130. *
  131. * Initialises the instance with a copy of the given \c VARIANT
  132. *
  133. * \post <code>assert(rhs == *this)</code>
  134. *
  135. * \exception comstl::com_exception If the copy fails
  136. */
  137. variant(VARIANT const& rhs);
  138. /** Copy constructor
  139. *
  140. * \post <code>assert(rhs == *this)</code>
  141. *
  142. * \exception comstl::com_exception If the copy fails
  143. */
  144. variant(class_type const& rhs);
  145. /** Copy assignment operator
  146. *
  147. * \post <code>assert(rhs == *this)</code>
  148. *
  149. * \exception comstl::com_exception If the copy fails
  150. */
  151. class_type& operator =(class_type const& rhs);
  152. /** Conversion constructor
  153. *
  154. * Initialises the instance with the given boolean value
  155. *
  156. * \post <code>assert(VT_BOOL == this->vt)</code>
  157. * \post <code>assert(b == (VARIANT_TRUE == this->boolVal))</code>
  158. *
  159. * \exception - Does not throw an exception
  160. */
  161. variant(bool b);
  162. /** Conversion constructor
  163. *
  164. * Initialises the instance with the given 8-bit signed integer value
  165. *
  166. * \post <code>assert(VT_I1 == this->vt)</code>
  167. * \post <code>assert(i == this->cVal)</code>
  168. *
  169. * \exception - Does not throw an exception
  170. */
  171. variant(stlsoft::sint8_t i);
  172. /** Conversion constructor
  173. *
  174. * Initialises the instance with the given 8-bit unsigned integer value
  175. *
  176. * \post <code>assert(VT_UI1 == this->vt)</code>
  177. * \post <code>assert(i == this->bVal)</code>
  178. *
  179. * \exception - Does not throw an exception
  180. */
  181. variant(stlsoft::uint8_t i);
  182. /** Conversion constructor
  183. *
  184. * Initialises the instance with the given 16-bit signed integer value
  185. *
  186. * \post <code>assert(VT_I2 == this->vt)</code>
  187. * \post <code>assert(i == this->iVal)</code>
  188. *
  189. * \exception - Does not throw an exception
  190. */
  191. variant(stlsoft::sint16_t i);
  192. /** Conversion constructor
  193. *
  194. * Initialises the instance with the given 16-bit unsigned integer value
  195. *
  196. * \post <code>assert(VT_UI2 == this->vt)</code>
  197. * \post <code>assert(i == this->uiVal)</code>
  198. *
  199. * \exception - Does not throw an exception
  200. */
  201. variant(stlsoft::uint16_t i);
  202. /** Conversion constructor
  203. *
  204. * Initialises the instance with the given 32-bit signed integer value
  205. *
  206. * \post <code>assert(VT_I4 == this->vt)</code>
  207. * \post <code>assert(i == this->lVal)</code>
  208. *
  209. * \exception - Does not throw an exception
  210. */
  211. variant(stlsoft::sint32_t i);
  212. /** Conversion constructor
  213. *
  214. * Initialises the instance with the given 32-bit unsigned integer value
  215. *
  216. * \post <code>assert(VT_UI4 == this->vt)</code>
  217. * \post <code>assert(i == this->ulVal)</code>
  218. *
  219. * \exception - Does not throw an exception
  220. */
  221. variant(stlsoft::uint32_t i);
  222. //#ifdef STLSOFT_CF_64BIT_INT_SUPPORT
  223. // variant(stlsoft::sint64_t i);
  224. // variant(stlsoft::uint64_t i);
  225. //#endif /* STLSOFT_CF_64BIT_INT_SUPPORT */
  226. #ifdef STLSOFT_CF_SHORT_DISTINCT_INT_TYPE
  227. /** Conversion constructor
  228. *
  229. * Initialises the instance with the given \c short value
  230. *
  231. * \post <code>assert(VT_I2 == this->vt)</code>
  232. * \post <code>assert(i == this->iVal)</code>
  233. *
  234. * \exception - Does not throw an exception
  235. */
  236. variant(short i);
  237. /** Conversion constructor
  238. *
  239. * Initialises the instance with the given
  240. * <code>unsigned short</code> value
  241. *
  242. * \post <code>assert(VT_UI2 == this->vt)</code>
  243. * \post <code>assert(i == this->uiVal)</code>
  244. *
  245. * \exception - Does not throw an exception
  246. */
  247. variant(unsigned short i);
  248. #endif /* STLSOFT_CF_SHORT_DISTINCT_INT_TYPE */
  249. #ifdef STLSOFT_CF_INT_DISTINCT_INT_TYPE
  250. /** Conversion constructor
  251. *
  252. * Initialises the instance with the given \c int value
  253. *
  254. * \post <code>assert(VT_I4 == this->vt)</code>
  255. * \post <code>assert(i == this->lVal)</code>
  256. *
  257. * \exception - Does not throw an exception
  258. */
  259. variant(int i);
  260. /** Conversion constructor
  261. *
  262. * Initialises the instance with the given
  263. * <code>unsigned int</code> value
  264. *
  265. * \post <code>assert(VT_UI4 == this->vt)</code>
  266. * \post <code>assert(i == this->ulVal)</code>
  267. *
  268. * \exception - Does not throw an exception
  269. */
  270. variant(unsigned int i);
  271. #endif /* STLSOFT_CF_INT_DISTINCT_INT_TYPE */
  272. #ifdef STLSOFT_CF_LONG_DISTINCT_INT_TYPE
  273. /** Conversion constructor
  274. *
  275. * Initialises the instance with the given \c long value
  276. *
  277. * \post <code>assert(VT_I4 == this->vt)</code>
  278. * \post <code>assert(i == this->lVal)</code>
  279. *
  280. * \exception - Does not throw an exception
  281. */
  282. variant(long i);
  283. /** Conversion constructor
  284. *
  285. * Initialises the instance with the given
  286. * <code>unsigned long</code> value
  287. *
  288. * \post <code>assert(VT_UI4 == this->vt)</code>
  289. * \post <code>assert(i == this->ulVal)</code>
  290. *
  291. * \exception - Does not throw an exception
  292. */
  293. variant(unsigned long i);
  294. #endif /* STLSOFT_CF_LONG_DISTINCT_INT_TYPE */
  295. /** Conversion constructor
  296. *
  297. * Initialises the instance with the given \c float value
  298. *
  299. * \post <code>assert(VT_R4 == this->vt)</code>
  300. * \post <code>assert(r == this->fltVal)</code>
  301. *
  302. * \exception - Does not throw an exception
  303. */
  304. variant(float r);
  305. /** Conversion constructor
  306. *
  307. * Initialises the instance with the given \c double value
  308. *
  309. * \post <code>assert(VT_R8 == this->vt)</code>
  310. * \post <code>assert(r == this->dblVal)</code>
  311. *
  312. * \exception - Does not throw an exception
  313. */
  314. variant(double r);
  315. /** Conversion constructor
  316. *
  317. * Initialises the instance with the given currency (\c CY) value
  318. *
  319. * \post <code>assert(VT_CY == this->vt)</code>
  320. * \post <code>assert(r == this->cyVal)</code>
  321. *
  322. * \exception - Does not throw an exception
  323. */
  324. variant(CY cy);
  325. /** Conversion constructor
  326. *
  327. * Initialises the instance with the given \c DECIMAL value
  328. *
  329. * \post <code>assert(VT_DECIMAL == this->vt)</code>
  330. * \post <code>assert(dec == this->decVal)</code>
  331. *
  332. * \exception - Does not throw an exception
  333. */
  334. variant(DECIMAL const& dec);
  335. variant(LPUNKNOWN punk, bool_type bAddRef);
  336. variant(LPDISPATCH pdisp, bool_type bAddRef);
  337. variant(cs_char_a_t const* s, int len = -1);
  338. variant(cs_char_w_t const* s, int len = -1);
  339. variant(VARIANT const& var, VARTYPE vt);
  340. /** Releases any resources associated with the underlying
  341. * <code>VARIANT</code>
  342. */
  343. ~variant() stlsoft_throw_0()
  344. {
  345. stlsoft_constraint_must_be_same_size(class_type, VARIANT);
  346. ::VariantClear(this);
  347. }
  348. /** Clears the variant
  349. *
  350. * \post <code>assert(VT_EMPTY == this->vt)</code>
  351. */
  352. void clear();
  353. /// Operations
  354. public:
  355. HRESULT try_conversion_copy(VARIANT const& var, VARTYPE vt);
  356. HRESULT try_convert(VARTYPE vt);
  357. class_type& convert(VARTYPE vt);
  358. /** Returns a pointer to a specified interface on an object to which
  359. * a client currently holds an interface pointer.
  360. *
  361. * \return An <code>HRESULT</code> code indicating the success of the
  362. * operation.
  363. * \retval <code>S_OK</code> The interface is supported:
  364. * <code>*ppv</code> will hold the pointer to the requested interface
  365. * \retval <code>E_INTERFACE</code> The interface is not supported: the
  366. * value of <code>*ppv</code> is undefined.
  367. *
  368. * \pre <code>NULL != ppv</code>
  369. */
  370. HRESULT QueryInterface(REFIID riid, void** ppv) const;
  371. /** Returns a pointer to a specified interface on an object to which
  372. * a client currently holds an interface pointer.
  373. *
  374. * \return An <code>HRESULT</code> code indicating the success of the
  375. * operation.
  376. * \retval <code>S_OK</code> The interface is supported:
  377. * <code>*ppi</code> will hold the pointer to the requested interface
  378. * \retval <code>E_INTERFACE</code> The interface is not supported: the
  379. * value of <code>*ppi</code> is undefined.
  380. *
  381. * \pre <code>NULL != ppi</code>
  382. */
  383. template <ss_typename_param_k I>
  384. HRESULT QueryInterfaceValue(I** ppi)
  385. {
  386. return QueryInterface(IID_traits<I>::iid(), reinterpret_cast<void**>(ppi));
  387. }
  388. public:
  389. /** Swaps the contents with another instance
  390. */
  391. void swap(class_type& rhs);
  392. /// Comparison
  393. public:
  394. bool_type equal(class_type const& rhs) const;
  395. bool_type equal(VARIANT const& rhs) const;
  396. /// Operators
  397. public:
  398. private:
  399. static void swap_(VARIANT& lhs, VARIANT& rhs);
  400. void handle_error_(char const* message, HRESULT hr);
  401. };
  402. /* /////////////////////////////////////////////////////////////////////////
  403. * String access shims
  404. */
  405. // No string access shims are defined, because there're already a set
  406. // defined for VARIANT, in comstl/shims/access/string.hpp, which is included
  407. // by this file.
  408. /* /////////////////////////////////////////////////////////////////////////
  409. * Operators
  410. */
  411. inline cs_bool_t operator ==(variant const& lhs, variant const& rhs)
  412. {
  413. return lhs.equal(rhs);
  414. }
  415. inline cs_bool_t operator !=(variant const& lhs, variant const& rhs)
  416. {
  417. return !operator ==(lhs, rhs);
  418. }
  419. inline cs_bool_t operator ==(variant const& lhs, VARIANT const& rhs)
  420. {
  421. return lhs.equal(rhs);
  422. }
  423. inline cs_bool_t operator !=(variant const& lhs, VARIANT const& rhs)
  424. {
  425. return !operator ==(lhs, rhs);
  426. }
  427. inline cs_bool_t operator ==(VARIANT const& lhs, variant const& rhs)
  428. {
  429. return rhs.equal(lhs);
  430. }
  431. inline cs_bool_t operator !=(VARIANT const& lhs, variant const& rhs)
  432. {
  433. return !operator ==(lhs, rhs);
  434. }
  435. ////////////////////////////////////////////////////////////////////////////
  436. // Unit-testing
  437. #ifdef STLSOFT_UNITTEST
  438. # include "./unittest/variant_unittest_.h"
  439. #endif /* STLSOFT_UNITTEST */
  440. /* /////////////////////////////////////////////////////////////////////////
  441. * Implementation
  442. */
  443. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  444. inline void variant::handle_error_(char const* message, HRESULT hr)
  445. {
  446. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  447. STLSOFT_THROW_X(com_exception(message, hr));
  448. #else /* ? STLSOFT_CF_EXCEPTION_SUPPORT */
  449. STLSOFT_SUPPRESS_UNUSED(message);
  450. ::VariantClear(this);
  451. this->vt = VT_ERROR;
  452. this->scode = hr;
  453. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  454. }
  455. inline /* static */ void variant::swap_(VARIANT& lhs, VARIANT& rhs)
  456. {
  457. VARIANT t;
  458. ::memcpy(&t, &lhs, sizeof(VARIANT));
  459. ::memcpy(&lhs, &rhs, sizeof(VARIANT));
  460. ::memcpy(&rhs, &t, sizeof(VARIANT));
  461. }
  462. inline variant::variant()
  463. {
  464. ::VariantInit(this);
  465. }
  466. inline variant::variant(class_type const& rhs)
  467. {
  468. ::VariantInit(this);
  469. class_type& rhs_ = const_cast<class_type&>(rhs);
  470. HRESULT hr = ::VariantCopy(this, &rhs_);
  471. if(FAILED(hr))
  472. {
  473. handle_error_("failed to copy variant", hr);
  474. }
  475. }
  476. inline variant::variant(VARIANT const& rhs)
  477. {
  478. ::VariantInit(this);
  479. HRESULT hr = ::VariantCopy(this, const_cast<VARIANT*>(&rhs));
  480. if(FAILED(hr))
  481. {
  482. handle_error_("failed to copy variant", hr);
  483. }
  484. }
  485. inline variant::class_type& variant::operator =(variant::class_type const& rhs)
  486. {
  487. class_type r(rhs);
  488. r.swap(*this);
  489. return *this;
  490. }
  491. inline variant::variant(bool b)
  492. {
  493. ::VariantInit(this);
  494. this->vt = VT_BOOL;
  495. this->boolVal = b ? VARIANT_TRUE : VARIANT_FALSE;
  496. }
  497. inline variant::variant(stlsoft::sint8_t i)
  498. {
  499. ::VariantInit(this);
  500. this->vt = VT_I1;
  501. this->cVal = static_cast<CHAR>(i);
  502. }
  503. inline variant::variant(stlsoft::uint8_t i)
  504. {
  505. ::VariantInit(this);
  506. this->vt = VT_UI1;
  507. this->bVal = static_cast<BYTE>(i);
  508. }
  509. inline variant::variant(stlsoft::sint16_t i)
  510. {
  511. ::VariantInit(this);
  512. this->vt = VT_I2;
  513. this->iVal = static_cast<SHORT>(i);
  514. }
  515. inline variant::variant(stlsoft::uint16_t i)
  516. {
  517. ::VariantInit(this);
  518. this->vt = VT_UI2;
  519. this->uiVal = static_cast<USHORT>(i);
  520. }
  521. inline variant::variant(stlsoft::sint32_t i)
  522. {
  523. ::VariantInit(this);
  524. this->vt = VT_I4;
  525. this->lVal = static_cast<LONG>(i);
  526. }
  527. inline variant::variant(stlsoft::uint32_t i)
  528. {
  529. ::VariantInit(this);
  530. this->vt = VT_UI4;
  531. this->ulVal = static_cast<ULONG>(i);
  532. }
  533. #ifdef STLSOFT_CF_SHORT_DISTINCT_INT_TYPE
  534. inline variant::variant(short i)
  535. {
  536. ::VariantInit(this);
  537. this->vt = VT_I2;
  538. this->iVal = i;
  539. }
  540. inline variant::variant(unsigned short i)
  541. {
  542. ::VariantInit(this);
  543. this->vt = VT_UI2;
  544. this->uiVal = i;
  545. }
  546. #endif /* STLSOFT_CF_SHORT_DISTINCT_INT_TYPE */
  547. #ifdef STLSOFT_CF_INT_DISTINCT_INT_TYPE
  548. inline variant::variant(int i)
  549. {
  550. ::VariantInit(this);
  551. this->vt = VT_I4;
  552. this->lVal = i;
  553. }
  554. inline variant::variant(unsigned int i)
  555. {
  556. ::VariantInit(this);
  557. this->vt = VT_UI4;
  558. this->ulVal = i;
  559. }
  560. #endif /* STLSOFT_CF_INT_DISTINCT_INT_TYPE */
  561. #ifdef STLSOFT_CF_LONG_DISTINCT_INT_TYPE
  562. inline variant::variant(long i)
  563. {
  564. ::VariantInit(this);
  565. this->vt = VT_I4;
  566. this->lVal = i;
  567. }
  568. inline variant::variant(unsigned long i)
  569. {
  570. ::VariantInit(this);
  571. this->vt = VT_UI4;
  572. this->ulVal = i;
  573. }
  574. #endif /* STLSOFT_CF_LONG_DISTINCT_INT_TYPE */
  575. inline variant::variant(float r)
  576. {
  577. ::VariantInit(this);
  578. this->vt = VT_R4;
  579. this->fltVal = r;
  580. }
  581. inline variant::variant(double r)
  582. {
  583. ::VariantInit(this);
  584. this->vt = VT_R8;
  585. this->dblVal = r;
  586. }
  587. inline variant::variant(CY cy)
  588. {
  589. ::VariantInit(this);
  590. this->vt = VT_CY;
  591. this->cyVal = cy;
  592. }
  593. inline variant::variant(DECIMAL const& dec)
  594. {
  595. ::VariantInit(this);
  596. this->vt = VT_DECIMAL;
  597. this->decVal.scale = dec.scale;
  598. this->decVal.sign = dec.sign;
  599. this->decVal.Hi32 = dec.Hi32;
  600. this->decVal.Mid32 = dec.Mid32;
  601. this->decVal.Lo32 = dec.Lo32;
  602. }
  603. inline variant::variant(LPUNKNOWN punk, bool_type bAddRef)
  604. {
  605. ::VariantInit(this);
  606. this->vt = VT_UNKNOWN;
  607. this->punkVal = punk;
  608. if( bAddRef &&
  609. NULL != punk)
  610. {
  611. punk->AddRef();
  612. }
  613. }
  614. inline variant::variant(LPDISPATCH pdisp, bool_type bAddRef)
  615. {
  616. ::VariantInit(this);
  617. this->vt = VT_DISPATCH;
  618. this->pdispVal = pdisp;
  619. if( bAddRef &&
  620. NULL != pdisp)
  621. {
  622. pdisp->AddRef();
  623. }
  624. }
  625. inline variant::variant(cs_char_a_t const* s, int len /* = -1 */)
  626. {
  627. ::VariantInit(this);
  628. this->vt = VT_BSTR;
  629. this->bstrVal = (len < 0) ? bstr_create(s) : bstr_create(s, static_cast<size_type>(len));
  630. if(NULL == this->bstrVal)
  631. {
  632. if( NULL != s &&
  633. '\0' != 0[s])
  634. {
  635. handle_error_("could not initialise from string", E_OUTOFMEMORY);
  636. }
  637. }
  638. }
  639. inline variant::variant(cs_char_w_t const* s, int len /* = -1 */)
  640. {
  641. ::VariantInit(this);
  642. this->vt = VT_BSTR;
  643. this->bstrVal = (len < 0) ? bstr_create(s) : bstr_create(s, static_cast<size_type>(len));
  644. if(NULL == this->bstrVal)
  645. {
  646. if( NULL != s &&
  647. '\0' != 0[s])
  648. {
  649. handle_error_("could not initialise from string", E_OUTOFMEMORY);
  650. }
  651. }
  652. }
  653. inline variant::variant(VARIANT const& var, VARTYPE vt)
  654. {
  655. ::VariantInit(this);
  656. class_type copy;
  657. HRESULT hr = ::VariantChangeType(&copy, const_cast<VARIANT*>(&var), 0, vt);
  658. if(FAILED(hr))
  659. {
  660. handle_error_("could not convert variant to requested type", hr);
  661. }
  662. else
  663. {
  664. copy.swap(*this);
  665. }
  666. }
  667. inline void variant::clear()
  668. {
  669. ::VariantClear(this);
  670. }
  671. inline HRESULT variant::try_conversion_copy(VARIANT const& var, VARTYPE vt)
  672. {
  673. HRESULT hr;
  674. if(vt == this->vt)
  675. {
  676. hr = S_FALSE;
  677. }
  678. else
  679. {
  680. class_type copy;
  681. hr = ::VariantChangeType(&copy, const_cast<VARIANT*>(&var), 0, vt);
  682. if(SUCCEEDED(hr))
  683. {
  684. copy.swap(*this);
  685. }
  686. }
  687. return hr;
  688. }
  689. inline HRESULT variant::try_convert(VARTYPE vt)
  690. {
  691. return try_conversion_copy(*this, vt);
  692. }
  693. inline variant::class_type& variant::convert(VARTYPE vt)
  694. {
  695. HRESULT hr = try_convert(vt);
  696. if(FAILED(hr))
  697. {
  698. handle_error_("could not convert variant to requested type", hr);
  699. }
  700. return *this;
  701. }
  702. inline HRESULT variant::QueryInterface(REFIID riid, void** ppv) const
  703. {
  704. COMSTL_ASSERT(NULL != ppv);
  705. if( VT_UNKNOWN == this->vt ||
  706. VT_DISPATCH == this->vt)
  707. {
  708. return (NULL == this->punkVal) ? E_POINTER : this->punkVal->QueryInterface(riid, ppv);
  709. }
  710. return DISP_E_BADVARTYPE;
  711. }
  712. inline void variant::swap(variant::class_type& rhs)
  713. {
  714. swap_(*this, rhs);
  715. }
  716. inline variant::bool_type variant::equal(variant::class_type const& rhs) const
  717. {
  718. return equal(static_cast<VARIANT const&>(rhs));
  719. }
  720. inline variant::bool_type variant::equal(VARIANT const& rhs) const
  721. {
  722. HRESULT comparisonSucceeded;
  723. int areEqual = VARIANT_equal(*this, rhs, &comparisonSucceeded);
  724. if(FAILED(comparisonSucceeded))
  725. {
  726. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  727. STLSOFT_THROW_X(comstl::com_exception("support for comparison of variant type not currently supported", comparisonSucceeded));
  728. #else /* ? STLSOFT_CF_EXCEPTION_SUPPORT */
  729. OutputDebugStringA("support for comparison of variant type not currently supported\n");
  730. return false;
  731. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  732. }
  733. return 0 != areEqual;
  734. }
  735. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  736. /* ////////////////////////////////////////////////////////////////////// */
  737. #ifndef _COMSTL_NO_NAMESPACE
  738. # if defined(_STLSOFT_NO_NAMESPACE) || \
  739. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  740. } // namespace comstl
  741. # else
  742. } // namespace stlsoft::comstl_project
  743. } // namespace stlsoft
  744. # endif /* _STLSOFT_NO_NAMESPACE */
  745. #endif /* !_COMSTL_NO_NAMESPACE */
  746. /* /////////////////////////////////////////////////////////////////////////
  747. * Namespace
  748. *
  749. * The string access shims exist either in the stlsoft namespace, or in the
  750. * global namespace. This is required by the lookup rules.
  751. *
  752. */
  753. #ifndef _COMSTL_NO_NAMESPACE
  754. # if !defined(_STLSOFT_NO_NAMESPACE) && \
  755. !defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  756. namespace stlsoft
  757. {
  758. # else /* ? _STLSOFT_NO_NAMESPACE */
  759. /* There is no stlsoft namespace, so must define in the global namespace */
  760. # endif /* !_STLSOFT_NO_NAMESPACE */
  761. # if !defined(_STLSOFT_NO_NAMESPACE) && \
  762. !defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  763. } // namespace stlsoft
  764. # else /* ? _STLSOFT_NO_NAMESPACE */
  765. /* There is no stlsoft namespace, so must define in the global namespace */
  766. # endif /* !_STLSOFT_NO_NAMESPACE */
  767. #endif /* !_COMSTL_NO_NAMESPACE */
  768. /* ////////////////////////////////////////////////////////////////////// */
  769. #endif /* !COMSTL_INCL_COMSTL_UTIL_HPP_COMSTL_VARIANT */
  770. /* ///////////////////////////// end of file //////////////////////////// */