| OLD | NEW | 
|---|
| (Empty) |  | 
|  | 1 /** | 
|  | 2  * \file process.h | 
|  | 3  */ | 
|  | 4 | 
|  | 5 #ifndef PROCESS_H | 
|  | 6 #define PROCESS_H | 
|  | 7 | 
|  | 8 #include "installer-lib.h" | 
|  | 9 #include "handle.h" | 
|  | 10 | 
|  | 11 #include <string> | 
|  | 12 #include <cctype> | 
|  | 13 #include <vector> | 
|  | 14 #include <set> | 
|  | 15 #include <algorithm> | 
|  | 16 #include <memory> | 
|  | 17 | 
|  | 18 #include <Windows.h> | 
|  | 19 #include <TlHelp32.h> | 
|  | 20 | 
|  | 21 //------------------------------------------------------- | 
|  | 22 // wstring_ci: case-insensitive wide string | 
|  | 23 //------------------------------------------------------- | 
|  | 24 | 
|  | 25 /** | 
|  | 26  * Traits class for case-insensitive strings. | 
|  | 27  */ | 
|  | 28 template< class T > | 
|  | 29 struct ci_traits: std::char_traits< T > | 
|  | 30 { | 
|  | 31   static bool eq( T c1, T c2 ) | 
|  | 32   { | 
|  | 33     return std::tolower( c1 ) == std::tolower( c2 ) ; | 
|  | 34   } | 
|  | 35 | 
|  | 36   static bool lt( T c1, T c2 ) | 
|  | 37   { | 
|  | 38     return std::tolower( c1 ) < std::tolower( c2 ) ; | 
|  | 39   } | 
|  | 40 | 
|  | 41   /** | 
|  | 42    * Trait comparison function. | 
|  | 43    * | 
|  | 44    * Note that this is not a comparison of C-style strings. | 
|  | 45    * In particular, there's no concern over null characters '\0'. | 
|  | 46    * The argument 'n' is the minimum length of the two strings being compared. | 
|  | 47    * We may assume that the intervals p1[0..n) and p2[0..n) are both valid subst
     rings. | 
|  | 48    */ | 
|  | 49   static int compare( const T * p1, const T * p2, size_t n ) | 
|  | 50   { | 
|  | 51     while ( n-- > 0 ) | 
|  | 52     { | 
|  | 53       T l1 = std::tolower( * p1 ++ ) ; | 
|  | 54       T l2 = std::tolower( * p2 ++ ) ; | 
|  | 55       if ( l1 == l2 ) | 
|  | 56       { | 
|  | 57         continue ; | 
|  | 58       } | 
|  | 59       return ( l1 < l2 ) ? -1 : +1 ; | 
|  | 60     } | 
|  | 61     return 0  ; | 
|  | 62   } | 
|  | 63 } ; | 
|  | 64 | 
|  | 65 typedef std::basic_string< wchar_t, ci_traits< wchar_t > > wstring_ci ; | 
|  | 66 | 
|  | 67 //------------------------------------------------------- | 
|  | 68 // file_name_set: case-insensitive wide-string set | 
|  | 69 //------------------------------------------------------- | 
|  | 70 struct file_name_set | 
|  | 71   : public std::set< wstring_ci > | 
|  | 72 { | 
|  | 73   /** | 
|  | 74    * Empty set constructor. | 
|  | 75    */ | 
|  | 76   file_name_set() | 
|  | 77   {} | 
|  | 78 | 
|  | 79   /** | 
|  | 80    * Constructor initialization from an array. | 
|  | 81    */ | 
|  | 82   template< size_t n_file_names > | 
|  | 83   file_name_set( const wchar_t * ( & file_name_list )[ n_file_names ] ) | 
|  | 84   { | 
|  | 85     for ( unsigned int j = 0 ; j < n_file_names ; ++ j ) | 
|  | 86     { | 
|  | 87       insert( wstring_ci( file_name_list[ j ] ) ) ; | 
|  | 88     } | 
|  | 89   } | 
|  | 90 } ; | 
|  | 91 | 
|  | 92 //------------------------------------------------------- | 
|  | 93 //------------------------------------------------------- | 
|  | 94 /** | 
|  | 95  * Filter by process name. Comparison is case-insensitive. With ABP module loade
     d | 
|  | 96  */ | 
|  | 97 class process_by_any_exe_with_any_module | 
|  | 98   : public std::binary_function< PROCESSENTRY32W, file_name_set, bool > | 
|  | 99 { | 
|  | 100   /** | 
|  | 101    * Set of file names from which to match candidate process names. | 
|  | 102    * | 
|  | 103    * This is a reference to, not a copy of, the set. | 
|  | 104    * The lifetime of this object must be subordinate to that of its referent. | 
|  | 105    * The set used to instantiate this class is a member of Process_Closer, | 
|  | 106    *   and so also is this class. | 
|  | 107    * Hence the lifetimes are coterminous, and the reference is not problematic. | 
|  | 108    */ | 
|  | 109   const file_name_set & processNames ; | 
|  | 110   const file_name_set & moduleNames; | 
|  | 111 public: | 
|  | 112   bool operator()( const PROCESSENTRY32W & ) ; | 
|  | 113   process_by_any_exe_with_any_module( const file_name_set & names, const file_na
     me_set & moduleNames ) | 
|  | 114     : processNames( names ), moduleNames( moduleNames ) | 
|  | 115   {} | 
|  | 116 } ; | 
|  | 117 | 
|  | 118 | 
|  | 119 //------------------------------------------------------- | 
|  | 120 // Process utility functions. | 
|  | 121 //------------------------------------------------------- | 
|  | 122 /** | 
|  | 123  * A promiscuous filter admits everything. | 
|  | 124  */ | 
|  | 125 struct every_process | 
|  | 126   : public std::unary_function< PROCESSENTRY32W, bool > | 
|  | 127 { | 
|  | 128   bool operator()( const PROCESSENTRY32W & ) { return true ; } ; | 
|  | 129 } ; | 
|  | 130 | 
|  | 131 /** | 
|  | 132  * Extractor that copies the entire process structure. | 
|  | 133  */ | 
|  | 134 struct copy_all | 
|  | 135   : public std::unary_function< PROCESSENTRY32W, PROCESSENTRY32W > | 
|  | 136 { | 
|  | 137   PROCESSENTRY32W operator()( const PROCESSENTRY32W & process ) { return process
      ; } | 
|  | 138 } ; | 
|  | 139 | 
|  | 140 /** | 
|  | 141  * Extractor that copies only the PID. | 
|  | 142  */ | 
|  | 143 struct copy_PID | 
|  | 144   : public std::unary_function< PROCESSENTRY32W, DWORD > | 
|  | 145 { | 
|  | 146   inline DWORD operator()( const PROCESSENTRY32W & process ) { return process.th
     32ProcessID ; } | 
|  | 147 } ; | 
|  | 148 | 
|  | 149 /** | 
|  | 150  * Retrieve the process ID that created a window. | 
|  | 151  * | 
|  | 152  * Wrapper around GetWindowThreadProcessId. | 
|  | 153  * Converts an error return from the system call into an exception. | 
|  | 154  * The system call can also retrieve the creating thread; we ignore it. | 
|  | 155  * | 
|  | 156  * \param window | 
|  | 157  *   Handle of the window | 
|  | 158  * \return | 
|  | 159  *   ID of the process that created the argument window | 
|  | 160  * | 
|  | 161  * \sa | 
|  | 162  *   MSDN [GetWindowThreadProcessId function](http://msdn.microsoft.com/en-us/li
     brary/windows/desktop/ms633522%28v=vs.85%29.aspx) | 
|  | 163  */ | 
|  | 164 DWORD creator_process( HWND window ) ; | 
|  | 165 | 
|  | 166 //------------------------------------------------------- | 
|  | 167 // Snapshot | 
|  | 168 //------------------------------------------------------- | 
|  | 169 /** | 
|  | 170  * Traits class for snapshots of all processes on the system. | 
|  | 171  */ | 
|  | 172 struct Process_Snapshot_Traits | 
|  | 173 { | 
|  | 174   /** | 
|  | 175    * The type of the data resulting from CreateToolhelp32Snapshot. | 
|  | 176    */ | 
|  | 177   typedef PROCESSENTRY32W result_type ; | 
|  | 178 | 
|  | 179   /** | 
|  | 180    * Flags used to call CreateToolhelp32Snapshot. | 
|  | 181    */ | 
|  | 182   const static DWORD snapshot_flags = TH32CS_SNAPPROCESS ; | 
|  | 183 | 
|  | 184   /** | 
|  | 185    * Wrapper for 'first' function for processes | 
|  | 186    */ | 
|  | 187   static BOOL first( HANDLE arg1, LPPROCESSENTRY32 arg2 ) | 
|  | 188   { | 
|  | 189     return ::Process32First( arg1, arg2 ) ; | 
|  | 190   } | 
|  | 191 | 
|  | 192   /** | 
|  | 193    * Wrapper for 'next' function for processes | 
|  | 194    */ | 
|  | 195   static BOOL next( HANDLE arg1, LPPROCESSENTRY32 arg2 ) | 
|  | 196   { | 
|  | 197     return ::Process32Next( arg1, arg2 ) ; | 
|  | 198   } | 
|  | 199 } ; | 
|  | 200 | 
|  | 201 /** | 
|  | 202  * Traits class for snapshots of all modules loaded by a process. | 
|  | 203  */ | 
|  | 204 struct Module_Snapshot_Traits | 
|  | 205 { | 
|  | 206   /** | 
|  | 207    * The type of the data resulting from CreateToolhelp32Snapshot. | 
|  | 208    */ | 
|  | 209   typedef MODULEENTRY32W result_type ; | 
|  | 210 | 
|  | 211   /** | 
|  | 212    * Flags used to call CreateToolhelp32Snapshot. | 
|  | 213    */ | 
|  | 214   const static DWORD snapshot_flags = TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32 ; | 
|  | 215 | 
|  | 216   /** | 
|  | 217    * Wrapper for 'first' function for modules | 
|  | 218    */ | 
|  | 219   static BOOL first( HANDLE arg1, LPMODULEENTRY32 arg2 ) | 
|  | 220   { | 
|  | 221     return ::Module32First( arg1, arg2 ) ; | 
|  | 222   } | 
|  | 223 | 
|  | 224   /** | 
|  | 225    * Wrapper for 'next' function for modules | 
|  | 226    */ | 
|  | 227   static BOOL next( HANDLE arg1, LPMODULEENTRY32 arg2 ) | 
|  | 228   { | 
|  | 229     return ::Module32Next( arg1, arg2 ) ; | 
|  | 230   } | 
|  | 231 } ; | 
|  | 232 | 
|  | 233 /** | 
|  | 234  * A snapshot wrapping the results of CreateToolhelp32Snapshot system call. | 
|  | 235  * | 
|  | 236  * Unfortunately, we cannot provide standard iterator for this class. | 
|  | 237  * Standard iterators must be copy-constructible, which entails the possibility 
     of multiple, coexisting iteration states. | 
|  | 238  * The iteration behavior provided by Process32First and Process32Next relies up
     on state held within the snapshot itself. | 
|  | 239  * Thus, there can be only one iterator at a time for the snapshot. | 
|  | 240  * The two requirements are not simultaneously satisfiable. | 
|  | 241  * | 
|  | 242  * Instead of a standard iterator, we provide a first() and next() functions wra
     pping the corresponding system calls. | 
|  | 243  * | 
|  | 244  * \par Implementation | 
|  | 245  * | 
|  | 246  * - MSDN [CreateToolhelp32Snapshot function](http://msdn.microsoft.com/en-us/li
     brary/windows/desktop/ms682489%28v=vs.85%29.aspx) | 
|  | 247  * - MSDN [Process32First function](http://msdn.microsoft.com/en-us/library/wind
     ows/desktop/ms684834%28v=vs.85%29.aspx) | 
|  | 248  * - MSDN [Process32Next function](http://msdn.microsoft.com/en-us/library/windo
     ws/desktop/ms684836%28v=vs.85%29.aspx) | 
|  | 249  * - MSDN [PROCESSENTRY32 structure](http://msdn.microsoft.com/en-us/library/win
     dows/desktop/ms684839%28v=vs.85%29.aspx) | 
|  | 250  * | 
|  | 251  * \par Design Note | 
|  | 252  *   The traits class defines first() and next() functions instead of using func
     tion pointers. | 
|  | 253  *   This arises from a limitation in the compiler. | 
|  | 254  *   The system calls are declared 'WINAPI', which is a compiler-specific extens
     ion. | 
|  | 255  *   That extension, however, does not go far enough to be able to declare a poi
     nter with the same modifier. | 
|  | 256  *   Hence the system calls must be called directly; they are wrapped in the tra
     it functions. | 
|  | 257  */ | 
|  | 258 template< class Traits > | 
|  | 259 class Snapshot | 
|  | 260 { | 
|  | 261 public: | 
|  | 262   /** | 
|  | 263    * Expose the result type from the traits class as our own. | 
|  | 264    */ | 
|  | 265   typedef typename Traits::result_type result_type ; | 
|  | 266 | 
|  | 267 private: | 
|  | 268   /** | 
|  | 269    * Process ID argument for CreateToolhelp32Snapshot. | 
|  | 270    */ | 
|  | 271   DWORD _id ; | 
|  | 272 | 
|  | 273   /** | 
|  | 274    * Handle to the underlying snapshot. | 
|  | 275    */ | 
|  | 276   Windows_Handle handle ; | 
|  | 277 | 
|  | 278   /** | 
|  | 279    * Buffer for reading a single process entry out of the snapshot. | 
|  | 280    * | 
|  | 281    * This buffer is constant insofar as the code outside this class is concerned
     . | 
|  | 282    * The accessor functions first() and next() return pointers to constant resul
     t_type. | 
|  | 283    */ | 
|  | 284   result_type buffer; | 
|  | 285 | 
|  | 286   /** | 
|  | 287    * Copy constructor declared private and not defined. | 
|  | 288    * | 
|  | 289    * \par Implementation | 
|  | 290    *   Add "= delete" for C++11. | 
|  | 291    */ | 
|  | 292   Snapshot( const Snapshot & ) ; | 
|  | 293 | 
|  | 294   /** | 
|  | 295    * Copy assignment declared private and not defined. | 
|  | 296    * | 
|  | 297    * \par Implementation | 
|  | 298    *   Add "= delete" for C++11. | 
|  | 299    */ | 
|  | 300   Snapshot operator=( const Snapshot & ) ; | 
|  | 301 | 
|  | 302   /** | 
|  | 303    * Create a new snapshot and return its handle. | 
|  | 304    */ | 
|  | 305   Windows_Handle::handle_type make_handle() | 
|  | 306   { | 
|  | 307     Windows_Handle::handle_type h = ::CreateToolhelp32Snapshot( Traits::snapshot
     _flags, _id ) ; | 
|  | 308     if ( h == INVALID_HANDLE_VALUE ) | 
|  | 309     { | 
|  | 310       throw windows_api_error( "CreateToolhelp32Snapshot", "INVALID_HANDLE_VALUE
     " ) ; | 
|  | 311     } | 
|  | 312     return h ; | 
|  | 313   } | 
|  | 314 | 
|  | 315 protected: | 
|  | 316   /** | 
|  | 317    * Constructor takes a snapshot. | 
|  | 318    */ | 
|  | 319   Snapshot( DWORD id ) | 
|  | 320     : _id( id ), handle( make_handle() ) | 
|  | 321   { | 
|  | 322     // The various result types all define 'dwSize' with the same semantics. | 
|  | 323     buffer.dwSize = sizeof( result_type ) ; | 
|  | 324   } | 
|  | 325 | 
|  | 326 public: | 
|  | 327   /** | 
|  | 328    * Reconstruct the current instance with a new system snapshot. | 
|  | 329    * | 
|  | 330    * This function uses reinitialization assignment in the Windows_Handle class, | 
|  | 331    *   which takes care of closing the old handle. | 
|  | 332    */ | 
|  | 333   void refresh() | 
|  | 334   { | 
|  | 335     handle = make_handle(); | 
|  | 336   } | 
|  | 337 | 
|  | 338   /** | 
|  | 339    * Retrieve the first snapshot item into our member buffer. | 
|  | 340    * | 
|  | 341    * \return | 
|  | 342    *   Pointer to our member buffer if there was a first item | 
|  | 343    *   0 otherwise | 
|  | 344    * | 
|  | 345    * \par Design Note | 
|  | 346    *   There's no error handling in the present version of this function. | 
|  | 347    *   In part that's because the underlying system call returns either true or 
     false, both of which are ordinarily valid answers. | 
|  | 348    *   The trouble is that a false return is overloaded. | 
|  | 349    *   It can mean either that (ordinary) there are no more items or (exceptiona
     l) the snapshot did not contain the right kind of item. | 
|  | 350    *   GetLastError is no help here; it doesn't distinguish between these cases. | 
|  | 351    *   The upshot is that we rely that our implementation calls the right functi
     ons on the snapshot, | 
|  | 352    *     and so we ignore the case where we've passed bad arguments to the syste
     m call. | 
|  | 353    */ | 
|  | 354   const result_type * first() | 
|  | 355   { | 
|  | 356     return Traits::first(handle, &buffer) ? &buffer : 0; | 
|  | 357   } | 
|  | 358 | 
|  | 359   /** | 
|  | 360    * Retrieve the next snapshot item into our member buffer and return a pointer
      to it. | 
|  | 361    * begin() must have been called first. | 
|  | 362    * | 
|  | 363    * \return | 
|  | 364    *   Pointer to our member buffer if there was a first item | 
|  | 365    *   0 otherwise | 
|  | 366    * | 
|  | 367    * \par Design Note | 
|  | 368    *   See the Design Note for first(); the same considerations apply here. | 
|  | 369    */ | 
|  | 370   const result_type * next() | 
|  | 371   { | 
|  | 372     return Traits::next(handle, &buffer) ? &buffer : 0; | 
|  | 373   } | 
|  | 374 } ; | 
|  | 375 | 
|  | 376 /** | 
|  | 377  * A snapshot of all processes running on the system. | 
|  | 378  */ | 
|  | 379 struct Process_Snapshot | 
|  | 380   : public Snapshot< Process_Snapshot_Traits > | 
|  | 381 { | 
|  | 382   Process_Snapshot() | 
|  | 383     : Snapshot( 0 ) | 
|  | 384   {} | 
|  | 385 } ; | 
|  | 386 | 
|  | 387 /** | 
|  | 388  * A snapshot of all modules loaded for a given process. | 
|  | 389  */ | 
|  | 390 struct Module_Snapshot | 
|  | 391   : public Snapshot< Module_Snapshot_Traits > | 
|  | 392 { | 
|  | 393   Module_Snapshot( DWORD process_id ) | 
|  | 394     : Snapshot( process_id ) | 
|  | 395   {} | 
|  | 396 } ; | 
|  | 397 | 
|  | 398 //------------------------------------------------------- | 
|  | 399 // initialize_process_list | 
|  | 400 //------------------------------------------------------- | 
|  | 401 /** | 
|  | 402  * \tparam T The type into which a PROCESSENTRY32W struture is extracted. | 
|  | 403  * \tparam Admittance Function type for argument 'admit' | 
|  | 404  * \tparam Extractor Function type for argument 'extract' | 
|  | 405  * \param admit A unary predicate function class that determines what's included | 
|  | 406  *      A process appears in the list only if the predicate returns true. | 
|  | 407  *      The use of this predicate is analogous to that in std::copy_if. | 
|  | 408  * \param convert A conversion function that takes a PROCESSENTRY32W as input ar
     gument and returns an element of type T. | 
|  | 409  */ | 
|  | 410 template<class T, class Admittance, class Extractor> | 
|  | 411 void initialize_process_list(std::vector<T>& v, Process_Snapshot &snap, Admittan
     ce admit = Admittance(), Extractor extract = Extractor()) | 
|  | 412 { | 
|  | 413   const PROCESSENTRY32W* p = snap.first(); | 
|  | 414   while (p != 0) | 
|  | 415   { | 
|  | 416     if (admit(*p )) | 
|  | 417     { | 
|  | 418       /* | 
|  | 419         * We don't have C++11 emplace_back, which can construct the element in p
     lace. | 
|  | 420         * Instead, we copy the return value of the converter. | 
|  | 421         */ | 
|  | 422       v.push_back(extract(*p)); | 
|  | 423     } | 
|  | 424     p = snap.next(); | 
|  | 425   } | 
|  | 426 }; | 
|  | 427 | 
|  | 428 //------------------------------------------------------- | 
|  | 429 // initialize_process_set | 
|  | 430 //------------------------------------------------------- | 
|  | 431 /** | 
|  | 432  * \tparam T The type into which a PROCESSENTRY32W struture is extracted. | 
|  | 433  * \tparam Admittance Function type for argument 'admit' | 
|  | 434  * \tparam Extractor Function type for argument 'extract' | 
|  | 435  * \param admit A unary predicate function class that determines what's included | 
|  | 436  *      A process appears in the list only if the predicate returns true. | 
|  | 437  *      The use of this predicate is analogous to that in std::copy_if. | 
|  | 438  * \param convert A conversion function that takes a PROCESSENTRY32W as input ar
     gument and returns an element of type T. | 
|  | 439  */ | 
|  | 440 template<class T, class Admittance, class Extractor> | 
|  | 441 void initialize_process_set(std::set< T > & set, Process_Snapshot &snap, Admitta
     nce admit = Admittance(), Extractor extract = Extractor()) | 
|  | 442 { | 
|  | 443   const PROCESSENTRY32W* p = snap.first(); | 
|  | 444   while (p != 0) | 
|  | 445   { | 
|  | 446     if (admit(*p)) | 
|  | 447     { | 
|  | 448       set.insert(extract(*p)); | 
|  | 449     } | 
|  | 450     p = snap.next(); | 
|  | 451   } | 
|  | 452 }; | 
|  | 453 | 
|  | 454 //------------------------------------------------------- | 
|  | 455 // enumerate_windows | 
|  | 456 //------------------------------------------------------- | 
|  | 457 | 
|  | 458 /** | 
|  | 459  * States of a window enumeration. | 
|  | 460  */ | 
|  | 461 typedef enum | 
|  | 462 { | 
|  | 463   started,        ///< The iteration is currently running | 
|  | 464   normal,         ///< Iteration terminated without error. | 
|  | 465   early,          ///< Callback returned false and terminated iteration early. | 
|  | 466   exception,      ///< Callback threw an exception and thereby terminated iterat
     ion. | 
|  | 467   error           ///< Callback always return true but EnumWindows failed. | 
|  | 468 } enumerate_windows_state ; | 
|  | 469 | 
|  | 470 /** | 
|  | 471  * Data to perform a window enumeration, shared between the main function and th
     e callback function. | 
|  | 472  */ | 
|  | 473 template< class F > | 
|  | 474 struct ew_data | 
|  | 475 { | 
|  | 476   /** | 
|  | 477    * Function to be applied to each enumerated window. | 
|  | 478    */ | 
|  | 479   F & f ; | 
|  | 480 | 
|  | 481   /** | 
|  | 482    * Completion status of the enumeration. | 
|  | 483    */ | 
|  | 484   enumerate_windows_state status ; | 
|  | 485 | 
|  | 486   /** | 
|  | 487    * An exception to be transported across the callback. | 
|  | 488    * | 
|  | 489    * The enumerator and the callback are not guaranteed to share a call stack, | 
|  | 490    *   nor need they even share compatible exception conventions, | 
|  | 491    *   and might not even be in the same thread. | 
|  | 492    * Thus, if the applied function throws an exception, | 
|  | 493    *   we catch it in the callback and re-throw it in the enumerator. | 
|  | 494    * This member holds such an exception. | 
|  | 495    * | 
|  | 496    * This member holds an exception only if 'status' has the value 'exception'. | 
|  | 497    * Otherwise it's a null pointer. | 
|  | 498    */ | 
|  | 499   std::unique_ptr< std::exception > ee ; | 
|  | 500 | 
|  | 501   /** | 
|  | 502    * Ordinary constructor. | 
|  | 503    */ | 
|  | 504   ew_data( F & f ) | 
|  | 505     : f( f ), status( started ) | 
|  | 506   {} | 
|  | 507 } ; | 
|  | 508 | 
|  | 509 /** | 
|  | 510  * Callback function for EnumWindows. | 
|  | 511  * | 
|  | 512  * This function provides two standard behaviors. | 
|  | 513  * It records early termination of the enumeration, should that happen by the ap
     plied function returning false. | 
|  | 514  * It captures any exception thrown for transport back to the enumerator. | 
|  | 515  */ | 
|  | 516 template< class F > | 
|  | 517 BOOL CALLBACK enumeration_callback( HWND window, LPARAM x ) | 
|  | 518 { | 
|  | 519   // LPARAM is always the same size as a pointer | 
|  | 520   ew_data< F > * data = reinterpret_cast< ew_data< F > * >( x ) ; | 
|  | 521   /* | 
|  | 522    * Top-level try statement prevents exception from propagating back to system. | 
|  | 523    */ | 
|  | 524   try | 
|  | 525   { | 
|  | 526     bool r = data -> f( window ) ; | 
|  | 527     if ( ! r ) | 
|  | 528     { | 
|  | 529       data -> status = early ; | 
|  | 530     } | 
|  | 531     return r ; | 
|  | 532   } | 
|  | 533   catch ( std::exception e ) | 
|  | 534   { | 
|  | 535     data -> ee = std::unique_ptr< std::exception >( new( std::nothrow ) std::exc
     eption( e ) ) ; | 
|  | 536     data -> status = exception ; | 
|  | 537     return FALSE ; | 
|  | 538   } | 
|  | 539   catch ( ... ) | 
|  | 540   { | 
|  | 541     data -> ee = std::unique_ptr< std::exception >() ; | 
|  | 542     data -> status = exception ; | 
|  | 543     return FALSE ; | 
|  | 544   } | 
|  | 545 } | 
|  | 546 | 
|  | 547 /** | 
|  | 548  * Enumerate windows, applying a function to each one. | 
|  | 549  */ | 
|  | 550 template< class F > | 
|  | 551 bool enumerate_windows( F f ) | 
|  | 552 { | 
|  | 553   ew_data< F > data( f ) ; | 
|  | 554   BOOL x( ::EnumWindows( enumeration_callback< F >, reinterpret_cast< LPARAM >( 
     & data ) ) ) ; | 
|  | 555   bool r ; | 
|  | 556   if ( data.status != started ) | 
|  | 557   { | 
|  | 558     // Assert status was changed within the callback | 
|  | 559     if ( data.status == exception ) | 
|  | 560     { | 
|  | 561       /* | 
|  | 562        * The callback threw an exception of some sort. | 
|  | 563        * We forward it to the extent we are able. | 
|  | 564        */ | 
|  | 565       if ( data.ee ) | 
|  | 566       { | 
|  | 567         throw * data.ee ; | 
|  | 568       } | 
|  | 569       else | 
|  | 570       { | 
|  | 571         throw std::runtime_error( "Unknown exception thrown in callback function
     ." ) ; | 
|  | 572       } | 
|  | 573     } | 
|  | 574     r = false ; | 
|  | 575   } | 
|  | 576   else | 
|  | 577   { | 
|  | 578     if ( x ) | 
|  | 579     { | 
|  | 580       data.status = normal ; | 
|  | 581       r = true ; | 
|  | 582     } | 
|  | 583     else | 
|  | 584     { | 
|  | 585       // Assert EnumWindows failed | 
|  | 586       data.status = error ; | 
|  | 587       r = false ; | 
|  | 588     } | 
|  | 589   } | 
|  | 590   return r ; | 
|  | 591 } | 
|  | 592 | 
|  | 593 //------------------------------------------------------- | 
|  | 594 // Process_Closer | 
|  | 595 //------------------------------------------------------- | 
|  | 596 class Process_Closer | 
|  | 597 { | 
|  | 598   /** | 
|  | 599    * Set of process identifiers matching one of the executable names. | 
|  | 600    */ | 
|  | 601   std::set< DWORD > pid_set ; | 
|  | 602 | 
|  | 603   /** | 
|  | 604    * Set of executable names by which to filter. | 
|  | 605    * | 
|  | 606    * The argument of the filter constructor is a set by reference. | 
|  | 607    * Since it does not make a copy for itself, we define it as a class member to
      provide its allocation. | 
|  | 608    */ | 
|  | 609   file_name_set process_names ; | 
|  | 610 | 
|  | 611   /** | 
|  | 612    * Set of module (DLL) names by which to filter. | 
|  | 613    */ | 
|  | 614   file_name_set module_names ; | 
|  | 615 | 
|  | 616   process_by_any_exe_with_any_module filter ; | 
|  | 617 | 
|  | 618   /** | 
|  | 619    * Copy function object copies just the process ID. | 
|  | 620    */ | 
|  | 621   copy_PID copy ; | 
|  | 622 | 
|  | 623   /** | 
|  | 624    * Snapshot of running processes. | 
|  | 625    */ | 
|  | 626   Process_Snapshot & snapshot ; | 
|  | 627 | 
|  | 628   void update() | 
|  | 629   { | 
|  | 630     initialize_process_set( pid_set, snapshot, filter, copy ) ; | 
|  | 631   } ; | 
|  | 632 | 
|  | 633   template< class F > | 
|  | 634   class only_our_processes | 
|  | 635   { | 
|  | 636     Process_Closer & self ; | 
|  | 637 | 
|  | 638     F f ; | 
|  | 639 | 
|  | 640   public: | 
|  | 641     only_our_processes( Process_Closer & self, F f ) | 
|  | 642       : f( f ), self( self ) | 
|  | 643     {} | 
|  | 644 | 
|  | 645     bool operator()( HWND window ) | 
|  | 646     { | 
|  | 647       bool b ; | 
|  | 648       try | 
|  | 649       { | 
|  | 650         b = self.contains( creator_process( window ) ) ; | 
|  | 651       } | 
|  | 652       catch ( ... ) | 
|  | 653       { | 
|  | 654         // ignore window handles that are no longer valid | 
|  | 655         return true ; | 
|  | 656       } | 
|  | 657       if ( ! b ) | 
|  | 658       { | 
|  | 659         // Assert the process that created the window is not in our pid_set | 
|  | 660         return true ; | 
|  | 661       } | 
|  | 662       return f( window ) ; | 
|  | 663     } | 
|  | 664   } ; | 
|  | 665 | 
|  | 666 public: | 
|  | 667   template <size_t n_file_names, size_t n_module_names> | 
|  | 668   Process_Closer(Process_Snapshot & snapshot, const wchar_t* (&file_name_list)[n
     _file_names], const wchar_t* (&module_name_list)[n_module_names]) | 
|  | 669     : snapshot(snapshot), process_names(file_name_list), module_names(module_nam
     e_list), filter(process_names, module_names) | 
|  | 670   { | 
|  | 671     update() ; | 
|  | 672   } | 
|  | 673   template <size_t n_file_names> | 
|  | 674   Process_Closer(Process_Snapshot & snapshot, const wchar_t * (&file_name_list)[
     n_file_names]) | 
|  | 675     : snapshot(snapshot), process_names(file_name_list), module_names(), filter(
     process_names, module_names) | 
|  | 676   { | 
|  | 677     update() ; | 
|  | 678   } | 
|  | 679 | 
|  | 680   /** | 
|  | 681    * Refresh our state to match the snapshot state. | 
|  | 682    */ | 
|  | 683   void refresh() | 
|  | 684   { | 
|  | 685     pid_set.clear() ; | 
|  | 686     update() ; | 
|  | 687   } | 
|  | 688 | 
|  | 689   bool is_running() { return ! pid_set.empty() ; } ; | 
|  | 690 | 
|  | 691   bool contains( DWORD pid ) const { return pid_set.find( pid ) != pid_set.end()
      ; } ; | 
|  | 692 | 
|  | 693   template< class F > | 
|  | 694   bool iterate_our_windows( F f ) | 
|  | 695   { | 
|  | 696     only_our_processes< F > g( * this, f ) ; | 
|  | 697     return enumerate_windows( g ) ; | 
|  | 698   } | 
|  | 699 | 
|  | 700   /* | 
|  | 701    * Shut down every process in the pid_set. | 
|  | 702    */ | 
|  | 703   bool shut_down() ; | 
|  | 704 | 
|  | 705 } ; | 
|  | 706 | 
|  | 707 #endif | 
| OLD | NEW | 
|---|