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.

471 lines
15 KiB

  1. /* /////////////////////////////////////////////////////////////////////////
  2. * File: winstl/system/pid_sequence.hpp
  3. *
  4. * Purpose: Process Id sequence class.
  5. *
  6. * Created: 24th June 2005
  7. * Updated: 25th March 2010
  8. *
  9. * Thanks to: Adi Shavit for spotting a small inefficiency in the
  10. * resize()-ing, during the review of Extended STL volume 1
  11. * (see http://extendedstl.com/).
  12. *
  13. * Home: http://stlsoft.org/
  14. *
  15. * Copyright (c) 2005-2010, Matthew Wilson and Synesis Software
  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/system/pid_sequence.hpp
  44. *
  45. * \brief [C++ only] Definition of the winstl::pid_sequence class
  46. * (\ref group__library__system "System" Library).
  47. */
  48. #ifndef WINSTL_INCL_WINSTL_SYSTEM_HPP_PID_SEQUENCE
  49. #define WINSTL_INCL_WINSTL_SYSTEM_HPP_PID_SEQUENCE
  50. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  51. # define WINSTL_VER_WINSTL_SYSTEM_HPP_PID_SEQUENCE_MAJOR 2
  52. # define WINSTL_VER_WINSTL_SYSTEM_HPP_PID_SEQUENCE_MINOR 2
  53. # define WINSTL_VER_WINSTL_SYSTEM_HPP_PID_SEQUENCE_REVISION 2
  54. # define WINSTL_VER_WINSTL_SYSTEM_HPP_PID_SEQUENCE_EDIT 51
  55. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  56. /* /////////////////////////////////////////////////////////////////////////
  57. * Compatibility
  58. */
  59. /*
  60. [Incompatibilies-start]
  61. STLSOFT_COMPILER_IS_COMO:
  62. [Incompatibilies-end]
  63. */
  64. /* /////////////////////////////////////////////////////////////////////////
  65. * Includes
  66. */
  67. #ifndef WINSTL_INCL_WINSTL_H_WINSTL
  68. # include <winstl/winstl.h>
  69. #endif /* !WINSTL_INCL_WINSTL_H_WINSTL */
  70. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  71. # ifndef WINSTL_INCL_WINSTL_ERROR_HPP_WINDOWS_EXCEPTIONS
  72. # include <winstl/error/exceptions.hpp>
  73. # endif /* !WINSTL_INCL_WINSTL_ERROR_HPP_WINDOWS_EXCEPTIONS */
  74. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  75. #ifndef WINSTL_INCL_WINSTL_MEMORY_HPP_PROCESSHEAP_ALLOCATOR
  76. # include <winstl/memory/processheap_allocator.hpp>
  77. #endif /* !WINSTL_INCL_WINSTL_MEMORY_HPP_PROCESSHEAP_ALLOCATOR */
  78. #ifndef WINSTL_INCL_WINSTL_SYSTEM_HPP_SYSTEM_VERSION
  79. # include <winstl/system/system_version.hpp>
  80. #endif /* !WINSTL_INCL_WINSTL_SYSTEM_HPP_SYSTEM_VERSION */
  81. #ifndef STLSOFT_INCL_STLSOFT_MEMORY_HPP_AUTO_BUFFER
  82. # include <stlsoft/memory/auto_buffer.hpp>
  83. #endif /* !STLSOFT_INCL_STLSOFT_MEMORY_HPP_AUTO_BUFFER */
  84. #ifndef STLSOFT_INCL_STLSOFT_ALGORITHMS_HPP_POD
  85. # include <stlsoft/algorithms/pod.hpp>
  86. #endif /* !STLSOFT_INCL_STLSOFT_ALGORITHMS_HPP_POD */
  87. #ifndef STLSOFT_INCL_STLSOFT_UTIL_STD_HPP_ITERATOR_HELPER
  88. # include <stlsoft/util/std/iterator_helper.hpp>
  89. #endif /* !STLSOFT_INCL_STLSOFT_UTIL_STD_HPP_ITERATOR_HELPER */
  90. #ifndef STLSOFT_INCL_STLSOFT_COLLECTIONS_UTIL_HPP_COLLECTIONS
  91. # include <stlsoft/collections/util/collections.hpp>
  92. #endif /* !STLSOFT_INCL_STLSOFT_COLLECTIONS_UTIL_HPP_COLLECTIONS */
  93. #if !defined(_PSAPI_H_) && \
  94. !defined(_PSAPI_H)
  95. # ifndef WINSTL_INCL_WINSTL_DL_HPP_DL_CALL
  96. # include <winstl/dl/dl_call.hpp>
  97. # endif /* !WINSTL_INCL_WINSTL_DL_HPP_DL_CALL */
  98. #endif /* psapi */
  99. #if !defined(STLSOFT_UNITTEST)
  100. # include <algorithm>
  101. #endif /* !STLSOFT_UNITTEST */
  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. * Classes
  121. */
  122. /** \brief Process Id sequence
  123. *
  124. * \ingroup group__library__system
  125. */
  126. class pid_sequence
  127. : public stlsoft_ns_qual(stl_collection_tag)
  128. {
  129. /// \name Member Types
  130. /// @{
  131. public:
  132. /// The value type
  133. typedef DWORD value_type;
  134. /// The allocator type
  135. typedef processheap_allocator<value_type> allocator_type;
  136. /// The class type
  137. typedef pid_sequence class_type;
  138. /// The non-mutating (const) pointer type
  139. typedef value_type const* const_pointer;
  140. /// The non-mutating (const) reference type
  141. typedef value_type const& const_reference;
  142. /// The non-mutating (const) iterator type
  143. typedef stlsoft_ns_qual(pointer_iterator)< value_type
  144. , const_pointer
  145. , const_reference
  146. >::type const_iterator;
  147. /// The size type
  148. typedef ws_size_t size_type;
  149. /// The difference type
  150. typedef ws_ptrdiff_t difference_type;
  151. #if defined(STLSOFT_LF_BIDIRECTIONAL_ITERATOR_SUPPORT)
  152. /// The non-mutating (const) reverse iterator type
  153. typedef stlsoft_ns_qual(const_reverse_bidirectional_iterator_base)< const_iterator
  154. , value_type
  155. , const_reference
  156. , const_pointer
  157. , difference_type
  158. > const_reverse_iterator;
  159. #endif /* STLSOFT_LF_BIDIRECTIONAL_ITERATOR_SUPPORT */
  160. enum
  161. {
  162. elideIdle = 0x0001
  163. , elideSystem = 0x0002
  164. , sort = 0x0004
  165. };
  166. /// @}
  167. /// \name Construction
  168. /// @{
  169. public:
  170. /// Constructs a sequence from the current processes in the host system
  171. ss_explicit_k pid_sequence(ws_uint32_t flags = elideIdle | elideSystem);
  172. /// Copies the contents of the sequence
  173. pid_sequence(class_type const& rhs);
  174. /// Releases the storage associated with the process id list
  175. ~pid_sequence() stlsoft_throw_0();
  176. /// @}
  177. /// \name Iteration
  178. /// @{
  179. public:
  180. /// Begins the iteration
  181. ///
  182. /// \return An iterator representing the start of the sequence
  183. const_iterator begin() const;
  184. /// Ends the iteration
  185. ///
  186. /// \return An iterator representing the end of the sequence
  187. const_iterator end() const;
  188. #if defined(STLSOFT_LF_BIDIRECTIONAL_ITERATOR_SUPPORT)
  189. /// Begins the reverse iteration
  190. ///
  191. /// \return An iterator representing the start of the reverse sequence
  192. const_reverse_iterator rbegin() const;
  193. /// Ends the reverse iteration
  194. ///
  195. /// \return An iterator representing the end of the reverse sequence
  196. const_reverse_iterator rend() const;
  197. #endif /* STLSOFT_LF_BIDIRECTIONAL_ITERATOR_SUPPORT */
  198. /// @}
  199. /// \name Element Access
  200. /// @{
  201. public:
  202. /// Returns a reference to the element at the given index
  203. ///
  204. /// \param index The required index. Behaviour is undefined, if not within the range [0, size())
  205. const_reference operator [](size_type index) const;
  206. /// @}
  207. /// \name Attributes
  208. /// @{
  209. public:
  210. /// Indicates whether the sequence is empty
  211. ws_bool_t empty() const;
  212. /// Returns the number of identifiers in the sequence
  213. size_type size() const;
  214. /// @}
  215. /// \name System Traits
  216. /// @{
  217. public:
  218. /// \brief The process identifier of the Idle process
  219. ///
  220. /// \note The Idle process is a pseudo-process. You should not attempt to
  221. /// manipulate it using the process control functions
  222. static value_type idleProcessId()
  223. {
  224. return 0;
  225. }
  226. /// \brief The process identifier of the System process
  227. ///
  228. /// \note The System process is a pseudo-process. You should not attempt to
  229. /// manipulate it using the process control functions
  230. static value_type systemProcessId()
  231. {
  232. ws_uint32_t major = system_version::major();
  233. ws_uint32_t minor = system_version::minor();
  234. if(4 == major)
  235. {
  236. return 2; // NT 4
  237. }
  238. else
  239. {
  240. if( 5 == major &&
  241. 0 == minor)
  242. {
  243. return 8; // Win2K
  244. }
  245. else if(5 == major &&
  246. 1 == minor)
  247. {
  248. return 4; // WinXP
  249. }
  250. else
  251. {
  252. return 4; // Longhorn and above - this value is a guess!!
  253. }
  254. }
  255. }
  256. /// @}
  257. /// \name Members
  258. /// @{
  259. private:
  260. typedef stlsoft_ns_qual(auto_buffer_old)< value_type
  261. , allocator_type
  262. , 64
  263. > buffer_type_;
  264. buffer_type_ m_pids;
  265. /// @}
  266. /// \name Not to be implemented
  267. /// @{
  268. private:
  269. class_type& operator =(class_type const&);
  270. /// @}
  271. };
  272. ////////////////////////////////////////////////////////////////////////////
  273. // Unit-testing
  274. #ifdef STLSOFT_UNITTEST
  275. # include "./unittest/pid_sequence_unittest_.h"
  276. #endif /* STLSOFT_UNITTEST */
  277. /* /////////////////////////////////////////////////////////////////////////
  278. * Implementation
  279. */
  280. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  281. inline pid_sequence::pid_sequence(ws_uint32_t flags)
  282. : m_pids(buffer_type_::internal_size())
  283. {
  284. DWORD cbReturned;
  285. for(;;)
  286. {
  287. #if defined(_PSAPI_H_) || \
  288. defined(_PSAPI_H)
  289. if(!::EnumProcesses(&m_pids[0], sizeof(value_type) * m_pids.size(), &cbReturned))
  290. #else /* ? psapi */
  291. if(!dl_call<BOOL>( "PSAPI.DLL"
  292. , WINSTL_DL_CALL_WINx_STDCALL_LITERAL("EnumProcesses")
  293. , &m_pids[0]
  294. , sizeof(value_type) * m_pids.size()
  295. , &cbReturned))
  296. #endif /* psapi */
  297. {
  298. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  299. STLSOFT_THROW_X(windows_exception("Failed to enumerate processes", ::GetLastError()));
  300. #else /* ? STLSOFT_CF_EXCEPTION_SUPPORT */
  301. m_pids.resize(0);
  302. break;
  303. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  304. }
  305. else
  306. {
  307. const size_type n = cbReturned / sizeof(value_type);
  308. if(n < m_pids.size())
  309. {
  310. m_pids.resize(n);
  311. break;
  312. }
  313. else
  314. {
  315. const size_type size = m_pids.size();
  316. m_pids.resize(1); // Read "Extended STL, volume 1" to find out what this is for
  317. if(!m_pids.resize(2 * size))
  318. {
  319. // This will only ever be executed when compiled in the
  320. // absence of throwing bad_alloc on memory exhaustion
  321. m_pids.resize(0);
  322. break;
  323. }
  324. }
  325. }
  326. }
  327. if(flags & (elideIdle | elideSystem))
  328. {
  329. value_type* begin = &*m_pids.begin();
  330. value_type* end = &*m_pids.end();
  331. value_type* pIdle = (flags & elideIdle) ? stlsoft_ns_qual_std(find)(begin, end, idleProcessId()) : end;
  332. value_type* pSystem = (flags & elideSystem) ? stlsoft_ns_qual_std(find)(begin, end, systemProcessId()) : end;
  333. // Optimise for the special case where idle is [0] and system is [1]
  334. if( end != pIdle &&
  335. end != pSystem &&
  336. pSystem == pIdle + 1)
  337. {
  338. pod_move(pSystem + 1, end, begin);
  339. m_pids.resize(m_pids.size() - 2);
  340. }
  341. else
  342. {
  343. if(end != pIdle)
  344. {
  345. pod_move(pIdle + 1, end, pIdle);
  346. m_pids.resize(m_pids.size() - 1);
  347. }
  348. if(end != pSystem)
  349. {
  350. pod_move(pSystem + 1, end, pSystem);
  351. m_pids.resize(m_pids.size() - 1);
  352. }
  353. }
  354. }
  355. if(flags & sort)
  356. {
  357. stlsoft_ns_qual_std(sort)(m_pids.begin(), m_pids.end());
  358. }
  359. }
  360. inline pid_sequence::pid_sequence(pid_sequence const& rhs)
  361. : m_pids(rhs.m_pids.size())
  362. {
  363. stlsoft_ns_qual_std(copy)(rhs.m_pids.begin(), rhs.m_pids.end(), m_pids.begin());
  364. }
  365. inline pid_sequence::~pid_sequence() stlsoft_throw_0()
  366. {}
  367. inline pid_sequence::const_iterator pid_sequence::begin() const
  368. {
  369. return &*m_pids.begin();
  370. }
  371. inline pid_sequence::const_iterator pid_sequence::end() const
  372. {
  373. return &*m_pids.end();
  374. }
  375. #if defined(STLSOFT_LF_BIDIRECTIONAL_ITERATOR_SUPPORT)
  376. inline pid_sequence::const_reverse_iterator pid_sequence::rbegin() const
  377. {
  378. return const_reverse_iterator(end());
  379. }
  380. inline pid_sequence::const_reverse_iterator pid_sequence::rend() const
  381. {
  382. return const_reverse_iterator(begin());
  383. }
  384. #endif /* STLSOFT_LF_BIDIRECTIONAL_ITERATOR_SUPPORT */
  385. inline pid_sequence::const_reference pid_sequence::operator [](pid_sequence::size_type index) const
  386. {
  387. WINSTL_MESSAGE_ASSERT("Index out of range", index < size());
  388. return m_pids[index];
  389. }
  390. inline ws_bool_t pid_sequence::empty() const
  391. {
  392. return m_pids.empty();
  393. }
  394. inline pid_sequence::size_type pid_sequence::size() const
  395. {
  396. return m_pids.size();
  397. }
  398. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  399. /* /////////////////////////////////////////////////////////////////////////
  400. * Namespace
  401. */
  402. #ifndef _WINSTL_NO_NAMESPACE
  403. # if defined(_STLSOFT_NO_NAMESPACE) || \
  404. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  405. } // namespace winstl
  406. # else
  407. } // namespace winstl_project
  408. } // namespace stlsoft
  409. # endif /* _STLSOFT_NO_NAMESPACE */
  410. #endif /* !_WINSTL_NO_NAMESPACE */
  411. /* ////////////////////////////////////////////////////////////////////// */
  412. #endif /* !WINSTL_INCL_WINSTL_SYSTEM_HPP_PID_SEQUENCE */
  413. /* ///////////////////////////// end of file //////////////////////////// */