OLD | NEW |
1 #include <windows.h> | 1 /** |
| 2 * \file process.h |
| 3 */ |
| 4 |
| 5 #ifndef PROCESS_H |
| 6 #define PROCESS_H |
| 7 |
| 8 #include <vector> |
| 9 #include <set> |
| 10 #include <algorithm> |
| 11 #include <memory> |
| 12 |
| 13 #include <Windows.h> |
2 #include <TlHelp32.h> | 14 #include <TlHelp32.h> |
3 | 15 |
4 #include <vector> | 16 //------------------------------------------------------- |
5 | 17 // Windows_Handle |
| 18 //------------------------------------------------------- |
| 19 /** |
| 20 * A handle to some Windows platform resource. |
| 21 * |
| 22 * Note, this is not the same as a Windows Installer handle (MSIHANDLE). |
| 23 * The two handles have different underlying types and use different functions t
o close. |
| 24 */ |
6 class Windows_Handle | 25 class Windows_Handle |
7 { | 26 { |
8 public: | 27 public: |
9 /** | 28 /** |
10 * Ordinary constructor. | 29 * Ordinary constructor. |
11 * | 30 * |
12 * Validates argument against INVALID_HANDLE_VALUE. No other checks performed. | 31 * Validates argument against INVALID_HANDLE_VALUE. No other checks performed. |
13 */ | 32 */ |
14 Windows_Handle( HANDLE h ) ; | 33 Windows_Handle( HANDLE h ) ; |
15 | 34 |
16 /** | 35 /** |
17 * Destructor | 36 * Destructor |
18 */ | 37 */ |
19 ~Windows_Handle() ; | 38 ~Windows_Handle() ; |
20 | 39 |
21 /** | 40 /** |
22 * Copy constructor declared but not defined. | 41 * Conversion operator to underlying HANDLE. |
| 42 */ |
| 43 operator HANDLE() const { return handle ; } ; |
| 44 |
| 45 /** |
| 46 * Raw handle assignment. |
| 47 * |
| 48 * This is equivalent to destroying the old object and constructing a new one
in its place. |
| 49 * In C++11 this would be handled by the move constructor on an rvalue referen
ce. |
| 50 */ |
| 51 void operator=( HANDLE h ) ; |
| 52 |
| 53 private: |
| 54 /** |
| 55 * \invariant The handle is an open handle to some system resource. |
| 56 */ |
| 57 HANDLE handle ; |
| 58 |
| 59 /** |
| 60 * Validation function for the handle. Invoked at both construction and assign
ment. |
| 61 */ |
| 62 void validate_handle() ; |
| 63 |
| 64 /** |
| 65 * Copy constructor declared private and not defined. |
23 * | 66 * |
24 * \par Implementation | 67 * \par Implementation |
25 * Add "= delete" for C++11. | 68 * Add "= delete" for C++11. |
26 */ | 69 */ |
27 Windows_Handle( const Windows_Handle & ) ; | 70 Windows_Handle( const Windows_Handle & ) ; |
28 | 71 |
29 /** | 72 /** |
30 * Copy assignment declared but not defined. | 73 * Copy assignment declared private and not defined. |
31 * | 74 * |
32 * \par Implementation | 75 * \par Implementation |
33 * Add "= delete" for C++11. | 76 * Add "= delete" for C++11. |
34 */ | 77 */ |
35 Windows_Handle operator=( const Windows_Handle & ) ; | 78 Windows_Handle operator=( const Windows_Handle & ) ; |
36 | 79 |
37 /** | |
38 * Conversion operator to underlying HANDLE. | |
39 */ | |
40 operator HANDLE() const { return handle ; } ; | |
41 | |
42 private: | |
43 /** | |
44 * \invariant The handle is an open handle to some system resource. | |
45 */ | |
46 HANDLE handle ; | |
47 }; | 80 }; |
48 | 81 |
49 /** | 82 //------------------------------------------------------- |
50 * \tparam Predicate A unary predicate type, either function pointer or function
object. Ordinarily inferred from the parameter. | 83 // exe_name_set: case-insensitive wide-string set |
51 */ | 84 //------------------------------------------------------- |
52 template< class T > | 85 int wcscmpi( const wchar_t * s1, const wchar_t * s2 ) ; |
53 class Process_List | 86 |
54 { | 87 struct exe_name |
| 88 { |
| 89 /** |
| 90 * Pointer to wide-character string, which is supposed to be null-terminated. |
| 91 */ |
| 92 const wchar_t * name ; |
| 93 |
| 94 exe_name( const wchar_t * name ) : name( name ) {} ; |
| 95 } ; |
| 96 |
| 97 template <> |
| 98 struct std::less< exe_name > |
| 99 : std::binary_function< exe_name, exe_name, bool > |
| 100 { |
| 101 bool operator()( const exe_name & a, const exe_name & b ) const |
| 102 { |
| 103 return wcscmpi( a.name, b.name ) < 0 ; |
| 104 } |
| 105 } ; |
| 106 |
| 107 struct exe_name_set |
| 108 : public std::set< exe_name > |
| 109 { |
| 110 exe_name_set( const wchar_t * exe_name_list[], size_t n_exe_names ) |
| 111 { |
| 112 for ( unsigned int j = 0 ; j < n_exe_names ; ++ j ) |
| 113 { |
| 114 insert( exe_name( exe_name_list[ j ] ) ) ; |
| 115 } |
| 116 } |
| 117 } ; |
| 118 |
| 119 //------------------------------------------------------- |
| 120 //------------------------------------------------------- |
| 121 /** |
| 122 * Filter by process name. Comparison is case-insensitive. |
| 123 */ |
| 124 class process_by_any_exe_name_CI |
| 125 : public std::unary_function< PROCESSENTRY32W, bool > |
| 126 { |
| 127 const exe_name_set & names ; |
55 public: | 128 public: |
56 /** | 129 bool operator()( const PROCESSENTRY32W & ) ; |
57 * \tparam Predicate Function pointer or function object. Generally inferred f
rom the argument. | 130 process_by_any_exe_name_CI( const exe_name_set & names ) |
58 * \param admit A selection filter predicate. | 131 : names( names ) |
59 *» A process appears in the list only if the predicate returns true. | 132 {} |
60 *» The use of this predicate is analogous to that in std::copy_if. | 133 } ; |
61 * \tparam Converter Function pointer or function object. Generally inferred f
rom the argument. | 134 |
62 * \param convert A conversion function that takes a PROCESSENTRY32W as input
argument and returns an element of type T. | 135 //------------------------------------------------------- |
63 */ | 136 // Process utility functions. |
64 template< class Predicate, class Converter > | 137 //------------------------------------------------------- |
65 Process_List( Predicate admit, Converter convert ); | 138 /** |
66 | 139 * A promiscuous filter admits everything. |
67 /** | 140 */ |
68 */ | 141 struct every_process |
69 ~Process_List() {}; | 142 : public std::unary_function< PROCESSENTRY32W, bool > |
70 | 143 { |
71 /** | 144 bool operator()( const PROCESSENTRY32W & ) { return true ; } ; |
72 * This class is principally a way of initializing a vector by filtering and e
xtracting a process list. | 145 } ; |
73 * There's no point in keeping the underlying vector private. | 146 |
74 */ | 147 /** |
75 std::vector< T > v; | 148 * Filter by process name. Comparison is case-insensitive. |
76 }; | 149 */ |
77 | 150 class process_by_name_CI |
78 /** | 151 : public std::unary_function< PROCESSENTRY32W, bool > |
| 152 { |
| 153 const wchar_t * name ; |
| 154 const size_t length ; |
| 155 process_by_name_CI() ; |
| 156 public: |
| 157 bool operator()( const PROCESSENTRY32W & ) ; |
| 158 process_by_name_CI( const wchar_t * name ) ; |
| 159 } ; |
| 160 |
| 161 /** |
| 162 * Extractor that copies the entire process structure. |
| 163 */ |
| 164 struct copy_all |
| 165 : public std::unary_function< PROCESSENTRY32W, PROCESSENTRY32W > |
| 166 { |
| 167 PROCESSENTRY32W operator()( const PROCESSENTRY32W & process ) { return process
; } |
| 168 } ; |
| 169 |
| 170 /** |
| 171 * Extractor that copies only the PID. |
| 172 */ |
| 173 struct copy_PID |
| 174 : public std::unary_function< PROCESSENTRY32W, DWORD > |
| 175 { |
| 176 inline DWORD operator()( const PROCESSENTRY32W & process ) { return process.th
32ProcessID ; } |
| 177 } ; |
| 178 |
| 179 /** |
| 180 * Case-insensitive wide-character C-style string comparison, fixed-length |
| 181 */ |
| 182 int wcsncmpi( const wchar_t * a, const wchar_t * b, unsigned int length ) ; |
| 183 |
| 184 /** |
| 185 * Retrieve the process ID that created a window. |
| 186 * |
| 187 * Wrapper around GetWindowThreadProcessId. |
| 188 * Converts an error return from the system call into an exception. |
| 189 * The system call can also retrieve the creating thread; we ignore it. |
| 190 * |
| 191 * \param window |
| 192 * Handle of the window |
| 193 * \return |
| 194 * ID of the process that created the argument window |
| 195 * |
| 196 * \sa |
| 197 * MSDN [GetWindowThreadProcessId function](http://msdn.microsoft.com/en-us/li
brary/windows/desktop/ms633522%28v=vs.85%29.aspx) |
| 198 */ |
| 199 DWORD creator_process( HWND window ) ; |
| 200 |
| 201 //------------------------------------------------------- |
| 202 // Snapshot |
| 203 //------------------------------------------------------- |
| 204 /** |
| 205 * A snapshot of all the processes running on the system. |
| 206 * |
| 207 * Unfortunately, we cannot provide standard iterator for this class. |
| 208 * Standard iterators must be copy-constructible, which entails the possibility
of multiple, coexisting iteration states. |
| 209 * The iteration behavior provided by Process32First and Process32Next relies up
on state held within the snapshot itself. |
| 210 * Thus, there can be only one iterator at a time for the snapshot. |
| 211 * The two requirements are not simultaneously satisfiable. |
| 212 * |
| 213 * As a substitute for a standard iterator, we provide a few functions mimicking
the pattern of standard iterators. |
| 214 * This class acts as its own iterator. |
| 215 * The pointer returned is either one to the member variable "process" or else 0
. |
| 216 * |
79 * \par Implementation | 217 * \par Implementation |
80 * | 218 * |
81 * CreateToolhelp32Snapshot function http://msdn.microsoft.com/en-us/library/win
dows/desktop/ms682489%28v=vs.85%29.aspx | 219 * - MSDN [CreateToolhelp32Snapshot function](http://msdn.microsoft.com/en-us/li
brary/windows/desktop/ms682489%28v=vs.85%29.aspx) |
82 * Process32First function http://msdn.microsoft.com/en-us/library/windows/deskt
op/ms684834%28v=vs.85%29.aspx | 220 * - MSDN [Process32First function](http://msdn.microsoft.com/en-us/library/wind
ows/desktop/ms684834%28v=vs.85%29.aspx) |
83 * Process32Next function http://msdn.microsoft.com/en-us/library/windows/deskto
p/ms684836%28v=vs.85%29.aspx | 221 * - MSDN [Process32Next function](http://msdn.microsoft.com/en-us/library/windo
ws/desktop/ms684836%28v=vs.85%29.aspx) |
84 * PROCESSENTRY32 structure http://msdn.microsoft.com/en-us/library/windows/desk
top/ms684839%28v=vs.85%29.aspx | 222 * - MSDN [PROCESSENTRY32 structure](http://msdn.microsoft.com/en-us/library/win
dows/desktop/ms684839%28v=vs.85%29.aspx) |
85 */ | 223 */ |
86 template< class T > template< class Predicate, class Converter > | 224 class Snapshot |
87 Process_List< T >::Process_List( Predicate admit, Converter convert ) | 225 { |
88 { | 226 /** |
| 227 * Handle to the process snapshot. |
| 228 */ |
| 229 Windows_Handle handle ; |
| 230 |
| 231 /** |
| 232 * Buffer for reading a single process entry out of the snapshot. |
| 233 */ |
| 234 PROCESSENTRY32W process; |
| 235 |
| 236 /** |
| 237 * Copy constructor declared private and not defined. |
| 238 * |
| 239 * \par Implementation |
| 240 * Add "= delete" for C++11. |
| 241 */ |
| 242 Snapshot( const Snapshot & ) ; |
| 243 |
| 244 /** |
| 245 * Copy assignment declared private and not defined. |
| 246 * |
| 247 * \par Implementation |
| 248 * Add "= delete" for C++11. |
| 249 */ |
| 250 Snapshot operator=( const Snapshot & ) ; |
| 251 |
| 252 |
| 253 public: |
| 254 /** |
| 255 * Default constructor takes the snapshot. |
| 256 */ |
| 257 Snapshot() ; |
| 258 |
| 259 /** |
| 260 * Reconstruct the current instance with a new system snapshot. |
| 261 */ |
| 262 void refresh() ; |
| 263 |
| 264 /** |
| 265 * Return a pointer to the first process in the snapshot. |
| 266 */ |
| 267 PROCESSENTRY32W * begin() ; |
| 268 |
| 269 /** |
| 270 * The end pointer is an alias for the null pointer. |
| 271 */ |
| 272 inline PROCESSENTRY32W * end() const { return 0 ; } |
| 273 |
| 274 /** |
| 275 * Return a pointer to the next process in the snapshot. |
| 276 * begin() must have been called first. |
| 277 */ |
| 278 PROCESSENTRY32W * next() ; |
| 279 |
| 280 /** |
| 281 * Type definition for pointer to underlying structure. |
| 282 */ |
| 283 typedef PROCESSENTRY32W * Pointer ; |
| 284 } ; |
| 285 |
| 286 //------------------------------------------------------- |
| 287 // initialize_process_list |
| 288 //------------------------------------------------------- |
| 289 /** |
| 290 * \tparam T The type into which a PROCESSENTRY32W struture is extracted. |
| 291 * \tparam Admittance Function type for argument 'admit' |
| 292 * \tparam Extractor Function type for argument 'extract' |
| 293 * \param admit A unary predicate function class that determines what's included |
| 294 *» A process appears in the list only if the predicate returns true. |
| 295 *» The use of this predicate is analogous to that in std::copy_if. |
| 296 * \param convert A conversion function that takes a PROCESSENTRY32W as input ar
gument and returns an element of type T. |
| 297 */ |
| 298 template< class T, class Admittance, class Extractor > |
| 299 void initialize_process_list( std::vector< T > & v, Snapshot & snap, Admittance
admit = Admittance(), Extractor extract = Extractor() ) |
| 300 { |
| 301 Snapshot::Pointer p = snap.begin() ; |
| 302 while ( p != snap.end() ) |
| 303 { |
| 304 if ( admit( * p ) ) |
| 305 { |
| 306 /* |
| 307 » * We don't have C++11 emplace_back, which can construct the element in p
lace. |
| 308 » * Instead, we copy the return value of the converter. |
| 309 » */ |
| 310 v.push_back( extract( * p ) ); |
| 311 } |
| 312 p = snap.next() ; |
| 313 } |
| 314 } ; |
| 315 |
| 316 //------------------------------------------------------- |
| 317 // initialize_process_set |
| 318 //------------------------------------------------------- |
| 319 /** |
| 320 * \tparam T The type into which a PROCESSENTRY32W struture is extracted. |
| 321 * \tparam Admittance Function type for argument 'admit' |
| 322 * \tparam Extractor Function type for argument 'extract' |
| 323 * \param admit A unary predicate function class that determines what's included |
| 324 *» A process appears in the list only if the predicate returns true. |
| 325 *» The use of this predicate is analogous to that in std::copy_if. |
| 326 * \param convert A conversion function that takes a PROCESSENTRY32W as input ar
gument and returns an element of type T. |
| 327 */ |
| 328 template< class T, class Admittance, class Extractor > |
| 329 void initialize_process_set( std::set< T > & set, Snapshot & snap, Admittance ad
mit = Admittance(), Extractor extract = Extractor() ) |
| 330 { |
| 331 Snapshot::Pointer p = snap.begin() ; |
| 332 while ( p != snap.end() ) |
| 333 { |
| 334 if ( admit( * p ) ) |
| 335 { |
| 336 set.insert( extract( * p ) ); |
| 337 } |
| 338 p = snap.next() ; |
| 339 } |
| 340 } ; |
| 341 |
| 342 //------------------------------------------------------- |
| 343 // enumerate_windows |
| 344 //------------------------------------------------------- |
| 345 |
| 346 /** |
| 347 * States of a window enumeration. |
| 348 */ |
| 349 typedef enum |
| 350 { |
| 351 started,» ///< The iteration is currently running |
| 352 normal,» ///< Iteration terminated without error. |
| 353 early,» ///< Callback returned false and terminated iteration early. |
| 354 exception,» ///< Callback threw an exception and thereby terminated iterat
ion. |
| 355 error»» ///< Callback always return true but EnumWindows failed. |
| 356 } enumerate_windows_state ; |
| 357 |
| 358 /** |
| 359 * Data to perform a window enumeration, shared between the main function and th
e callback function. |
| 360 */ |
| 361 template< class F > |
| 362 struct ew_data |
| 363 { |
| 364 F & f ; |
| 365 |
| 366 enumerate_windows_state status ; |
| 367 |
| 368 std::unique_ptr< std::exception > ee ; |
| 369 |
| 370 ew_data( F & f ) |
| 371 : f( f ), status( started ) |
| 372 {} |
| 373 } ; |
| 374 |
| 375 /** |
| 376 * Callback function for EnumWindows. |
| 377 */ |
| 378 template< class F > |
| 379 BOOL CALLBACK enumeration_callback( HWND window, LPARAM x ) |
| 380 { |
| 381 // LPARAM is always the same size as a pointer |
| 382 ew_data< F > * data = reinterpret_cast< ew_data< F > * >( x ) ; |
| 383 try |
| 384 { |
| 385 bool r = data -> f( window ) ; |
| 386 if ( ! r ) |
| 387 { |
| 388 data -> status = early ; |
| 389 } |
| 390 return r ; |
| 391 } |
| 392 catch ( std::exception e ) |
| 393 { |
| 394 data -> ee = std::unique_ptr< std::exception >( new( std::nothrow ) std::exc
eption( e ) ) ; |
| 395 data -> status = exception ; |
| 396 return FALSE ; |
| 397 } |
| 398 catch ( ... ) |
| 399 { |
| 400 data -> status = exception ; |
| 401 return FALSE ; |
| 402 } |
| 403 return TRUE ; |
| 404 } |
| 405 |
| 406 /** |
| 407 * Enumerate windows, applying a function to each one. |
| 408 */ |
| 409 template< class F > |
| 410 bool enumerate_windows( F f ) |
| 411 { |
| 412 ew_data< F > data( f ) ; |
| 413 BOOL x( ::EnumWindows( enumeration_callback< F >, reinterpret_cast< LPARAM >(
& data ) ) ) ; |
| 414 bool r ; |
| 415 if ( data.status != started ) |
| 416 { |
| 417 // Assert status was changed within the callback |
| 418 if ( data.status == exception ) |
| 419 { |
| 420 /* |
| 421 * The callback threw an exception of some sort. |
| 422 * We forward it to the extent we are able. |
| 423 */ |
| 424 if ( data.ee ) |
| 425 { |
| 426 » throw * data.ee ; |
| 427 } |
| 428 else |
| 429 { |
| 430 » throw std::runtime_error( "Unknown exception thrown in callback function
." ) ; |
| 431 } |
| 432 } |
| 433 r = false ; |
| 434 } |
| 435 else |
| 436 { |
| 437 if ( x ) |
| 438 { |
| 439 data.status = normal ; |
| 440 r = true ; |
| 441 } |
| 442 else |
| 443 { |
| 444 // Assert EnumWindows failed |
| 445 data.status = error ; |
| 446 r = false ; |
| 447 } |
| 448 } |
| 449 return r ; |
| 450 } |
| 451 |
| 452 //------------------------------------------------------- |
| 453 // Process_Closer |
| 454 //------------------------------------------------------- |
| 455 class Process_Closer |
| 456 { |
| 457 /** |
| 458 * Set of process identifiers matching one of the executable names. |
| 459 */ |
| 460 std::set< DWORD > pid_set ; |
| 461 |
| 462 /** |
| 463 * Set of executable names by which to filter. |
| 464 * |
| 465 * The argument of the filter constructor is a set by reference. |
| 466 * Since it does not make a copy for itself, we define it as a class member to
provide its allocation. |
| 467 */ |
| 468 exe_name_set exe_names ; |
| 469 |
| 470 /** |
| 471 * Filter function object matches on any of the exe names specified in the con
structor. |
| 472 */ |
| 473 process_by_any_exe_name_CI filter ; |
| 474 |
| 475 /** |
| 476 * Copy function object copies just the process ID. |
| 477 */ |
| 478 copy_PID copy ; |
| 479 |
| 480 /** |
| 481 * Snapshot of running processes. |
| 482 */ |
| 483 Snapshot & snapshot ; |
| 484 |
| 485 void update() |
| 486 { |
| 487 initialize_process_set( pid_set, snapshot, filter, copy ) ; |
| 488 } ; |
| 489 |
| 490 template< class F > |
| 491 class only_our_processes |
| 492 { |
| 493 Process_Closer & self ; |
| 494 |
| 495 F f ; |
| 496 |
| 497 public: |
| 498 only_our_processes( Process_Closer & self, F f ) |
| 499 : f( f ), self( self ) |
| 500 {} |
| 501 |
| 502 bool operator()( HWND window ) |
| 503 { |
| 504 bool b ; |
| 505 try |
| 506 { |
| 507 » b = self.contains( creator_process( window ) ) ; |
| 508 } |
| 509 catch ( ... ) |
| 510 { |
| 511 » // ignore window handles that are no longer valid |
| 512 » return true ; |
| 513 } |
| 514 if ( ! b ) |
| 515 { |
| 516 » // Assert the process that created the window is not in our pid_set |
| 517 » return true ; |
| 518 } |
| 519 return f( window ) ; |
| 520 } |
| 521 } ; |
| 522 |
| 523 public: |
| 524 Process_Closer( Snapshot & snapshot, const wchar_t * exe_name_list[], size_t n
_exe_names ) |
| 525 : snapshot( snapshot ), exe_names( exe_name_list, n_exe_names ), filter( exe
_names ) |
| 526 { |
| 527 update() ; |
| 528 } |
| 529 |
| 530 /** |
| 531 * Refresh our state to match the snapshot state. |
| 532 */ |
| 533 void refresh() |
| 534 { |
| 535 pid_set.clear() ; |
| 536 update() ; |
| 537 } |
| 538 |
| 539 bool is_running() { return ! pid_set.empty() ; } ; |
| 540 |
| 541 bool contains( DWORD pid ) const { return pid_set.find( pid ) != pid_set.end()
; } ; |
| 542 |
| 543 template< class F > |
| 544 bool iterate_our_windows( F f ) |
| 545 { |
| 546 only_our_processes< F > g( * this, f ) ; |
| 547 return enumerate_windows( g ) ; |
| 548 } |
| 549 |
89 /* | 550 /* |
90 * Take a snapshot only of all processes on the system, and not all the other
data available through the CreateToolhelp32Snapshot. | 551 * Shut down every process in the pid_set. |
91 * Second argument is ignored for flag TH32CS_SNAPPROCESS. | 552 */ |
92 */ | 553 bool shut_down() ; |
93 Windows_Handle handle( ::CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 ) ); | 554 |
94 // Size initialization required for Process32FirstW to succeed. | 555 } ; |
95 PROCESSENTRY32W process; | 556 |
96 process.dwSize = sizeof( PROCESSENTRY32W ); | 557 #endif |
97 /* | |
98 * Process32FirstW and Process32NextW iterate through the process snapshot. | |
99 */ | |
100 BOOL have_process = ::Process32FirstW( handle, & process ); | |
101 while ( have_process ) | |
102 { | |
103 if ( admit( process ) ) | |
104 { | |
105 /* | |
106 * We don't have C++11 emplace_back, which can construct the element in pl
ace. | |
107 * Instead, we copy the return value of the converter. | |
108 */ | |
109 v.push_back( convert( process ) ); | |
110 } | |
111 have_process = ::Process32NextW( handle, & process ); | |
112 } | |
113 } | |
114 | |
OLD | NEW |