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.

447 lines
15 KiB

  1. /* /////////////////////////////////////////////////////////////////////////
  2. * File: winstl/string/resource_string.hpp (was winstl_resource_string.h; originally MWResStr.h: ::SynesisWin)
  3. *
  4. * Purpose: basic_resource_string class.
  5. *
  6. * Created: 1st November 1994
  7. * Updated: 10th August 2009
  8. *
  9. * Thanks to: Ryan Ginstrom for suggesting the implementation for handling
  10. * Unicode strings on Win9x.
  11. *
  12. * Home: http://stlsoft.org/
  13. *
  14. * Copyright (c) 1994-2009, Matthew Wilson and Synesis Software
  15. * Copyright (c) 2004-2005, Ryan Ginstrom
  16. * All rights reserved.
  17. *
  18. * Redistribution and use in source and binary forms, with or without
  19. * modification, are permitted provided that the following conditions are met:
  20. *
  21. * - Redistributions of source code must retain the above copyright notice, this
  22. * list of conditions and the following disclaimer.
  23. * - Redistributions in binary form must reproduce the above copyright notice,
  24. * this list of conditions and the following disclaimer in the documentation
  25. * and/or other materials provided with the distribution.
  26. * - Neither the name(s) of Matthew Wilson and Synesis Software nor the names of
  27. * any contributors may be used to endorse or promote products derived from
  28. * this software without specific prior written permission.
  29. *
  30. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  31. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  32. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  33. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  34. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  35. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  36. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  37. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  38. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  39. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  40. * POSSIBILITY OF SUCH DAMAGE.
  41. *
  42. * ////////////////////////////////////////////////////////////////////// */
  43. /** \file winstl/string/resource_string.hpp
  44. *
  45. * \brief [C++ only] Definition of the winstl::basic_resource_string class
  46. * template
  47. * (\ref group__library__string "String" Library).
  48. */
  49. #ifndef WINSTL_INCL_WINSTL_STRING_HPP_RESOURCE_STRING
  50. #define WINSTL_INCL_WINSTL_STRING_HPP_RESOURCE_STRING
  51. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  52. # define WINSTL_VER_WINSTL_STRING_HPP_RESOURCE_STRING_MAJOR 4
  53. # define WINSTL_VER_WINSTL_STRING_HPP_RESOURCE_STRING_MINOR 2
  54. # define WINSTL_VER_WINSTL_STRING_HPP_RESOURCE_STRING_REVISION 4
  55. # define WINSTL_VER_WINSTL_STRING_HPP_RESOURCE_STRING_EDIT 83
  56. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  57. /* /////////////////////////////////////////////////////////////////////////
  58. * Compatibility
  59. */
  60. /*
  61. [Incompatibilies-start]
  62. STLSOFT_COMPILER_IS_MSVC: _MSC_VER<1200
  63. [Incompatibilies-end]
  64. */
  65. /* /////////////////////////////////////////////////////////////////////////
  66. * Includes
  67. */
  68. #ifndef WINSTL_INCL_WINSTL_H_WINSTL
  69. # include <winstl/winstl.h>
  70. #endif /* !WINSTL_INCL_WINSTL_H_WINSTL */
  71. //#ifndef STLSOFT_INCL_STLSOFT_STRING_HPP_STRING_TRAITS
  72. //# include <stlsoft/string/string_traits.hpp>
  73. //#endif /* !STLSOFT_INCL_STLSOFT_STRING_HPP_STRING_TRAITS */
  74. #ifndef STLSOFT_INCL_STLSOFT_ERROR_HPP_EXCEPTIONS
  75. # include <stlsoft/error/exceptions.hpp> // for null_exception_policy
  76. #endif /* !STLSOFT_INCL_STLSOFT_ERROR_HPP_EXCEPTIONS */
  77. #ifndef WINSTL_INCL_WINSTL_ERROR_HPP_WINDOWS_EXCEPTIONS
  78. # include <winstl/error/exceptions.hpp>
  79. #endif /* !WINSTL_INCL_WINSTL_ERROR_HPP_WINDOWS_EXCEPTIONS */
  80. #ifndef STLSOFT_INCL_EXCEPTION
  81. # define STLSOFT_INCL_EXCEPTION
  82. # include <exception>
  83. #endif /* !STLSOFT_INCL_EXCEPTION */
  84. #ifdef STLSOFT_UNITTEST
  85. # include <iostream> // for std::cout, std::endl
  86. # include <string> // for std::string, std::wstring
  87. #endif /* STLSOFT_UNITTEST */
  88. /* /////////////////////////////////////////////////////////////////////////
  89. * Namespace
  90. */
  91. #ifndef _WINSTL_NO_NAMESPACE
  92. # if defined(_STLSOFT_NO_NAMESPACE) || \
  93. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  94. /* There is no stlsoft namespace, so must define ::winstl */
  95. namespace winstl
  96. {
  97. # else
  98. /* Define stlsoft::winstl_project */
  99. namespace stlsoft
  100. {
  101. namespace winstl_project
  102. {
  103. # endif /* _STLSOFT_NO_NAMESPACE */
  104. #endif /* !_WINSTL_NO_NAMESPACE */
  105. /* /////////////////////////////////////////////////////////////////////////
  106. * Classes
  107. */
  108. /** \brief Instances of this class represent Windows string resources, and are
  109. * constructed from instance identifiers.
  110. *
  111. * \ingroup group__library__string
  112. *
  113. * It is an adaptor template, so is parameterised with the underlying string
  114. * type. For example, <code>winstl::basic_resource_string&lt;std::string&gt;</code>
  115. * is parameterised from <code>std::string</code>, and can therefore use its methods
  116. * and is compatible with its client code:
  117. *
  118. \code
  119. winstl::basic_resource_string<std::string> str(1024);
  120. std::cout << "String with id 1024: " << str << std::endl;
  121. fprintf(stdout, "String with id 1024: %.*s\n", str.size(), str.data());
  122. \endcode
  123. *
  124. * The second template parameter is the exception policy, which determines
  125. * how the string reacts to a failure to load a string resource corresponding
  126. * to the given Id. It is defaulted to stlsoft::null_exception_policy, which
  127. * means that, when a corresponding string resource is not loaded, the
  128. * resource string instance will be correctly constructed but will contain
  129. * the empty string, i.e.:
  130. *
  131. \code
  132. // Assuming 9999999 is not a valid string resource identifier in the
  133. // module whose instance handle is in hinst ...
  134. winstl::basic_resource_string<std::string> str(hinst, 9999999);
  135. assert(0 == str.size());
  136. assert(str == "");
  137. \endcode
  138. *
  139. * If you want your parameterisation to throw an exception when the string
  140. * resource is not found, simply specify a policy that throws an exception
  141. * to the parameterisation, as in:
  142. *
  143. \code
  144. // Assuming 9999999 is not a valid string resource identifier in the
  145. // module whose instance handle is in hinst ...
  146. try
  147. {
  148. winstl::basic_resource_string<std::string, throw_MyX_policy> str(hinst, 9999999);
  149. std::cerr << "Should never get here!!" << std::endl;
  150. }
  151. catch(MyX &x)
  152. {
  153. std::cerr << "This is what's expected" << std::endl;
  154. }
  155. \endcode
  156. *
  157. * \note The handling of Unicode strings under Windows 9x family operating
  158. * systems eschews the use of LoadStringW(), instead manipulating the resource
  159. * information via FindResourceEx() / LoadResource() / LockResource(). This
  160. * code kindly provided by Ryan Ginstrom.
  161. *
  162. * \param S The string class, e.g. std::string, stlsoft::simple_string, etc.
  163. * \param X The exception class
  164. */
  165. template< ss_typename_param_k S
  166. #ifdef STLSOFT_CF_TEMPLATE_CLASS_DEFAULT_CLASS_ARGUMENT_SUPPORT
  167. # ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  168. , ss_typename_param_k X = resource_exception_policy
  169. # else /* ? STLSOFT_CF_EXCEPTION_SUPPORT */
  170. , ss_typename_param_k X = stlsoft_ns_qual(null_exception_policy)
  171. # endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  172. #else /* ? STLSOFT_CF_TEMPLATE_CLASS_DEFAULT_CLASS_ARGUMENT_SUPPORT */
  173. , ss_typename_param_k X /* = stlsoft_ns_qual(null_exception_policy) */
  174. #endif /* STLSOFT_CF_TEMPLATE_CLASS_DEFAULT_CLASS_ARGUMENT_SUPPORT */
  175. >
  176. // class basic_resource_string
  177. class basic_resource_string
  178. : public S
  179. , protected X
  180. {
  181. private:
  182. typedef S parent_class_type;
  183. public:
  184. /// The type of the underlying string
  185. typedef S string_type;
  186. /// The type of the current parameterisation
  187. typedef basic_resource_string<S, X> class_type;
  188. /// The exception policy type
  189. typedef X exception_policy_type;
  190. /// The exception policy type
  191. ///
  192. /// \deprecated
  193. typedef exception_policy_type exception_type;
  194. // typedef stlsoft_ns_qual(string_traits)<S> string_traits_type;
  195. /// The value type
  196. typedef ss_typename_type_k string_type::value_type value_type;
  197. /// \name Construction
  198. /// @{
  199. public:
  200. /// Constructs an around the string loaded from the given \c id
  201. ss_explicit_k basic_resource_string(ws_int_t id) stlsoft_throw_1(ss_typename_type_k exception_policy_type::thrown_type)
  202. {
  203. this->load_(::GetModuleHandle(NULL), id, NULL);
  204. }
  205. /// Constructs an around the string loaded from the given \c id and \c hinst
  206. basic_resource_string(HINSTANCE hinst, ws_int_t id) stlsoft_throw_1(ss_typename_type_k exception_policy_type::thrown_type)
  207. {
  208. this->load_(hinst, id, NULL);
  209. }
  210. /// Constructs an around the string loaded from the given \c id, or uses the given default
  211. ss_explicit_k basic_resource_string(ws_int_t id, value_type const* defaultValue)
  212. {
  213. this->load_(::GetModuleHandle(NULL), id, defaultValue);
  214. }
  215. /// Constructs an around the string loaded from the given \c id and \c hinst
  216. basic_resource_string(HINSTANCE hinst, ws_int_t id, value_type const* defaultValue)
  217. {
  218. this->load_(hinst, id, defaultValue);
  219. }
  220. /// Copy constructor
  221. basic_resource_string(class_type const& rhs)
  222. : parent_class_type(rhs)
  223. {}
  224. /// Copy constructor
  225. basic_resource_string(string_type const& rhs)
  226. : parent_class_type(rhs)
  227. {}
  228. /// Copy assignment operator
  229. class_type& operator =(class_type const& rhs)
  230. {
  231. parent_class_type::operator =(rhs);
  232. return *this;
  233. }
  234. /// Copy assignment operator
  235. class_type& operator =(string_type const& rhs)
  236. {
  237. parent_class_type::operator =(rhs);
  238. return *this;
  239. }
  240. /// @}
  241. // Implementation
  242. private:
  243. ws_int_t load_string_(HINSTANCE hinst, int uID, ws_char_a_t *buffer, ws_size_t cchBuffer)
  244. {
  245. return ::LoadStringA(hinst, static_cast<UINT>(uID), buffer, static_cast<int>(cchBuffer));
  246. }
  247. ws_int_t load_string_(HINSTANCE hinst, int uID, ws_char_w_t *buffer, ws_size_t cchBuffer)
  248. {
  249. if(::GetVersion() & 0x80000000)
  250. {
  251. // This block of code kindly provided by Ryan Ginstrom
  252. int block = (uID >> 4) + 1; // Compute block number.
  253. int num = uID & 0xf; // Compute offset into block.
  254. HRSRC hRC = ::FindResourceEx( hinst
  255. , RT_STRING
  256. , MAKEINTRESOURCE(block)
  257. , MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL));
  258. if(NULL != hRC)
  259. {
  260. HGLOBAL hgl = ::LoadResource(hinst, hRC);
  261. if(NULL != hgl)
  262. {
  263. LPWSTR res_str = (LPWSTR)::LockResource(hgl);
  264. if(NULL != res_str)
  265. {
  266. for(int i = 0; i < num; ++i)
  267. {
  268. res_str += *res_str + 1;
  269. }
  270. const LPCWSTR ptr = res_str + 1;
  271. const ws_size_t cch = static_cast<ws_size_t>(*res_str);
  272. if(cch < cchBuffer)
  273. {
  274. cchBuffer = cch + 1; // This is +1, since lstrcpyn 'uses' a character for the nul character
  275. buffer[cch] = L'\0';
  276. }
  277. ::lstrcpynW(buffer, ptr, static_cast<int>(cchBuffer));
  278. return static_cast<ws_int_t>(cchBuffer);
  279. }
  280. }
  281. }
  282. return 0;
  283. }
  284. return ::LoadStringW(hinst, static_cast<UINT>(uID), buffer, static_cast<int>(cchBuffer));
  285. }
  286. void load_(HINSTANCE hinst, ws_int_t id, value_type const* defaultValue) stlsoft_throw_1(ss_typename_type_k exception_policy_type::thrown_type)
  287. {
  288. // TODO: Verify that it's not possible to load string resources of >256. If that's
  289. // wrong, then need to fix this to use auto_buffer
  290. value_type sz[1024];
  291. if(0 == this->load_string_(hinst, id, sz, STLSOFT_NUM_ELEMENTS(sz)))
  292. {
  293. if(NULL != defaultValue)
  294. {
  295. parent_class_type::operator =(defaultValue);
  296. }
  297. else
  298. {
  299. exception_policy_type()("string did not load", ::GetLastError(), MAKEINTRESOURCE(id), RT_STRING);
  300. parent_class_type::operator =(string_type());
  301. }
  302. }
  303. else
  304. {
  305. parent_class_type::operator =(sz);
  306. }
  307. }
  308. };
  309. /* /////////////////////////////////////////////////////////////////////////
  310. * Creator Functions
  311. */
  312. //inline make_resource_string
  313. ////////////////////////////////////////////////////////////////////////////
  314. // Unit-testing
  315. #ifdef STLSOFT_UNITTEST
  316. # include "./unittest/resource_string_unittest_.h"
  317. #endif /* STLSOFT_UNITTEST */
  318. /* /////////////////////////////////////////////////////////////////////////
  319. * String access shims
  320. */
  321. #if 0
  322. /* c_str_ptr_null */
  323. /** \brief Returns the corresponding C-string pointer of \c s, or a null pointer
  324. *
  325. * \ingroup group__library__string
  326. */
  327. template< ss_typename_param_k S
  328. , ss_typename_param_k X
  329. >
  330. inline C const* c_str_ptr_null(basic_resource_string<S, X> const& s)
  331. {
  332. return (s.length() == 0) ? 0 : s.c_str();
  333. }
  334. /* c_str_ptr */
  335. /** \brief Returns the corresponding C-string pointer of \c s
  336. *
  337. * \ingroup group__library__string
  338. */
  339. template< ss_typename_param_k S
  340. , ss_typename_param_k X
  341. >
  342. inline C const* c_str_ptr(basic_resource_string<S, X> const& s)
  343. {
  344. return s.c_str();
  345. }
  346. /* c_str_ptr */
  347. /** \brief Returns the corresponding C-string pointer of \c s
  348. *
  349. * \ingroup group__library__string
  350. */
  351. template< ss_typename_param_k S
  352. , ss_typename_param_k X
  353. >
  354. inline C const* c_str_data(basic_resource_string<S, X> const& s)
  355. {
  356. return s.c_str();
  357. }
  358. /* c_str_ptr_len */
  359. /** \brief Returns the length (in characters) of \c s, <b><i>not</i></b> including the null-terminating character
  360. *
  361. * \ingroup group__library__string
  362. */
  363. template< ss_typename_param_k S
  364. , ss_typename_param_k X
  365. >
  366. inline ss_size_t c_str_len(basic_resource_string<S, X> const& s)
  367. {
  368. return s.length();
  369. }
  370. #endif /* 0 */
  371. /* ////////////////////////////////////////////////////////////////////// */
  372. #ifndef _WINSTL_NO_NAMESPACE
  373. # if defined(_STLSOFT_NO_NAMESPACE) || \
  374. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  375. } // namespace winstl
  376. # else
  377. } // namespace winstl_project
  378. } // namespace stlsoft
  379. # endif /* _STLSOFT_NO_NAMESPACE */
  380. #endif /* !_WINSTL_NO_NAMESPACE */
  381. /* ////////////////////////////////////////////////////////////////////// */
  382. #endif /* !WINSTL_INCL_WINSTL_STRING_HPP_RESOURCE_STRING */
  383. /* ///////////////////////////// end of file //////////////////////////// */