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