Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Side by Side Diff: installer/src/installer-lib/process.h

Issue 5675960980471808: Updated installer with custom action (Closed)
Patch Set: Created March 8, 2014, 5:06 a.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
OLDNEW
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
OLDNEW

Powered by Google App Engine
This is Rietveld