| OLD | NEW |
| 1 #include <stdexcept> | 1 #include <stdexcept> |
| 2 #include <functional> | 2 #include <functional> |
| 3 #include <wctype.h> | 3 #include <wctype.h> |
| 4 // <thread> is C++11, but implemented in VS2012 | 4 // <thread> is C++11, but implemented in VS2012 |
| 5 #include <thread> | 5 #include <thread> |
| 6 | 6 |
| 7 #include "installer-lib.h" | 7 #include "installer-lib.h" |
| 8 #include "process.h" | 8 #include "process.h" |
| 9 #include "handle.h" | 9 #include "handle.h" |
| 10 #include "session.h" | 10 #include "session.h" |
| 11 | 11 |
| 12 //------------------------------------------------------- | 12 //------------------------------------------------------- |
| 13 //------------------------------------------------------- | 13 //------------------------------------------------------- |
| 14 typedef int (__stdcall *IsImmersiveDynamicFunc)(HANDLE); | 14 typedef int (__stdcall* IsImmersiveDynamicFunc)(HANDLE); |
| 15 bool ProcessByAnyExeNotImmersive::operator()( const PROCESSENTRY32W & process ) | 15 bool ProcessByAnyExeNotImmersive::operator()(const PROCESSENTRY32W& process) |
| 16 { | 16 { |
| 17 // If the name is not found in our list, it's filtered out | 17 // If the name is not found in our list, it's filtered out |
| 18 if (processNames.find(process.szExeFile) == processNames.end()) return false; | 18 if (processNames.find(process.szExeFile) == processNames.end()) |
| 19 { |
| 20 return false; |
| 21 } |
| 19 | 22 |
| 20 // Make sure the process is still alive | 23 // Make sure the process is still alive |
| 21 HANDLE tmpHandle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, process.th32P
rocessID); | 24 HANDLE tmpHandle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, process.th32P
rocessID); |
| 22 if (tmpHandle == NULL) return false; | 25 if (tmpHandle == NULL) |
| 26 { |
| 27 return false; |
| 28 } |
| 23 WindowsHandle procHandle(tmpHandle); | 29 WindowsHandle procHandle(tmpHandle); |
| 24 DWORD exitCode; | 30 DWORD exitCode; |
| 25 if (!GetExitCodeProcess(procHandle, &exitCode)) return false; | 31 if (!GetExitCodeProcess(procHandle, &exitCode)) |
| 26 if (exitCode != STILL_ACTIVE) return false; | 32 { |
| 33 return false; |
| 34 } |
| 35 if (exitCode != STILL_ACTIVE) |
| 36 { |
| 37 return false; |
| 38 } |
| 27 | 39 |
| 28 // Check if this is a Windows Store app process (we don't care for IE in Moder
n UI) | 40 // Check if this is a Windows Store app process (we don't care for IE in Moder
n UI) |
| 29 HMODULE user32Dll = LoadLibrary(L"user32.dll"); | 41 HMODULE user32Dll = LoadLibrary(L"user32.dll"); |
| 30 if (!user32Dll) return true; | 42 if (!user32Dll) |
| 43 { |
| 44 return true; |
| 45 } |
| 31 IsImmersiveDynamicFunc IsImmersiveDynamicCall = (IsImmersiveDynamicFunc)GetPro
cAddress(user32Dll, "IsImmersiveProcess"); | 46 IsImmersiveDynamicFunc IsImmersiveDynamicCall = (IsImmersiveDynamicFunc)GetPro
cAddress(user32Dll, "IsImmersiveProcess"); |
| 32 if (!IsImmersiveDynamicCall) return true; | 47 if (!IsImmersiveDynamicCall) |
| 48 { |
| 49 return true; |
| 50 } |
| 33 return !IsImmersiveDynamicCall(procHandle); | 51 return !IsImmersiveDynamicCall(procHandle); |
| 34 } | 52 } |
| 35 | 53 |
| 36 //------------------------------------------------------- | 54 //------------------------------------------------------- |
| 37 // CreatorProcess | 55 // CreatorProcess |
| 38 //------------------------------------------------------- | 56 //------------------------------------------------------- |
| 39 DWORD CreatorProcess( HWND window ) | 57 DWORD CreatorProcess(HWND window) |
| 40 { | 58 { |
| 41 DWORD pid ; | 59 DWORD pid; |
| 42 DWORD r = GetWindowThreadProcessId( window, & pid ) ; | 60 DWORD r = GetWindowThreadProcessId(window, & pid); |
| 43 if ( r == 0 ) | 61 if (r == 0) |
| 44 { | 62 { |
| 45 // Assert GetWindowThreadProcessId returned an error | 63 // Assert GetWindowThreadProcessId returned an error |
| 46 // If the window handle is invalid, we end up here. | 64 // If the window handle is invalid, we end up here. |
| 47 throw WindowsApiError( "GetWindowThreadProcessId", r ) ; | 65 throw WindowsApiError("GetWindowThreadProcessId", r); |
| 48 } | 66 } |
| 49 return pid ; | 67 return pid; |
| 50 } | 68 } |
| 51 | 69 |
| 52 //------------------------------------------------------- | 70 //------------------------------------------------------- |
| 53 // SendMessageAction, SendEndsessionMessagesAction | 71 // SendMessageAction, SendEndsessionMessagesAction |
| 54 //------------------------------------------------------- | 72 //------------------------------------------------------- |
| 55 /** | 73 /** |
| 56 * Default process exit wait time (per message) 5000 ms | 74 * Default process exit wait time (per message) 5000 ms |
| 57 * | 75 * |
| 58 * 5 seconds is time that the system will wait before it considers a process non-
responsive. | 76 * 5 seconds is time that the system will wait before it considers a process non-
responsive. |
| 59 */ | 77 */ |
| 60 static const unsigned int timeout = 5000 ; // milliseconds | 78 static const unsigned int timeout = 5000 ; // milliseconds |
| 61 | 79 |
| 62 /** | 80 /** |
| 63 * An function object to process the results of sending window messages in SendMe
ssageAction. | 81 * An function object to process the results of sending window messages in SendMe
ssageAction. |
| 64 * | 82 * |
| 65 * We are using SendMessageAction within a system iteration over windows. | 83 * We are using SendMessageAction within a system iteration over windows. |
| 66 * The system has its own convention for continuing/breaking the iteration. | 84 * The system has its own convention for continuing/breaking the iteration. |
| 67 * This convention is assured consistently in SendMessageAction, which also provi
des default behavior. | 85 * This convention is assured consistently in SendMessageAction, which also provi
des default behavior. |
| 68 * This class provides the base for any variation from the default behavior. | 86 * This class provides the base for any variation from the default behavior. |
| 69 */ | 87 */ |
| 70 struct MessageAccumulator | 88 struct MessageAccumulator |
| 71 : public std::binary_function< DWORD_PTR, bool, bool > | 89 : public std::binary_function<DWORD_PTR, bool, bool> |
| 72 { | 90 { |
| 73 virtual result_type operator()( first_argument_type result, second_argument_ty
pe returnValue ) = 0 ; | 91 virtual result_type operator()(first_argument_type result, second_argument_typ
e returnValue) = 0; |
| 74 virtual ~MessageAccumulator() {} ; | 92 virtual ~MessageAccumulator() {}; |
| 75 } ; | 93 }; |
| 76 | 94 |
| 77 /** | 95 /** |
| 78 * Iteration action to send a message to a window and accumulate results. | 96 * Iteration action to send a message to a window and accumulate results. |
| 79 * | 97 * |
| 80 * An error sending the message is not a failure for the function a whole. | 98 * An error sending the message is not a failure for the function a whole. |
| 81 * The goal is to close the process, and if the window is no longer present, then
the process may have already closed. | 99 * The goal is to close the process, and if the window is no longer present, then
the process may have already closed. |
| 82 * Therefore, we're ignoring both the return value and the result. | 100 * Therefore, we're ignoring both the return value and the result. |
| 83 */ | 101 */ |
| 84 class SendMessageAction | 102 class SendMessageAction |
| 85 { | 103 { |
| 86 UINT message ;» » ///< Message type for windows message | 104 UINT message ; ///< Message type for windows message |
| 87 WPARAM p1 ;» » » ///< Generic parameter 1 for windows message | 105 WPARAM p1 ; ///< Generic parameter 1 for windows message |
| 88 LPARAM p2 ;» » » ///< Generic parameter 2 for windows message | 106 LPARAM p2 ; ///< Generic parameter 2 for windows message |
| 89 MessageAccumulator * f ;» ///< Processor for results of sending the messag
e. | 107 MessageAccumulator* f ; ///< Processor for results of sending the message. |
| 90 | 108 |
| 91 public: | 109 public: |
| 92 /** | 110 /** |
| 93 * Full contructor gathers message parameters and a message accumulator. | 111 * Full contructor gathers message parameters and a message accumulator. |
| 94 */ | 112 */ |
| 95 SendMessageAction( UINT message, WPARAM p1, LPARAM p2, MessageAccumulator & f
) | 113 SendMessageAction(UINT message, WPARAM p1, LPARAM p2, MessageAccumulator& f) |
| 96 : message( message ), p1( p1 ), p2( p2 ), f( & f ) | 114 : message(message), p1(p1), p2(p2), f(& f) |
| 97 {} | 115 {} |
| 98 | 116 |
| 99 /** | 117 /** |
| 100 * Abbreviated contructor gathers only message parameters. | 118 * Abbreviated contructor gathers only message parameters. |
| 101 * The message accumulator is absent. | 119 * The message accumulator is absent. |
| 102 */ | 120 */ |
| 103 SendMessageAction( UINT message, WPARAM p1, LPARAM p2 ) | 121 SendMessageAction(UINT message, WPARAM p1, LPARAM p2) |
| 104 : message( message ), p1( p1 ), p2( p2 ), f( 0 ) | 122 : message(message), p1(p1), p2(p2), f(0) |
| 105 {} | 123 {} |
| 106 | 124 |
| 107 /* | 125 /* |
| 108 * Enumeration function applied to each window. | 126 * Enumeration function applied to each window. |
| 109 */ | 127 */ |
| 110 bool operator()( HWND window ) | 128 bool operator()(HWND window) |
| 111 { | 129 { |
| 112 DWORD_PTR result ; | 130 DWORD_PTR result; |
| 113 LRESULT rv = SendMessageTimeoutW( window, message, p1, p2, SMTO_BLOCK, timeo
ut, & result ) ; | 131 LRESULT rv = SendMessageTimeoutW(window, message, p1, p2, SMTO_BLOCK, timeou
t, & result); |
| 114 /* | 132 /* |
| 115 * If we have no message accumulator, the default behavior is to iterate ever
ything. | 133 * If we have no message accumulator, the default behavior is to iterate ever
ything. |
| 116 * If we do have one, we delegate to it the decision whether to break or to c
ontinue. | 134 * If we do have one, we delegate to it the decision whether to break or to c
ontinue. |
| 117 */ | 135 */ |
| 118 if ( ! f ) | 136 if (! f) |
| 119 { | 137 { |
| 120 return true ; | 138 return true; |
| 121 } | 139 } |
| 122 return ( * f )( result, (rv != 0) ) ; | 140 return (* f)(result, (rv != 0)); |
| 123 } | 141 } |
| 124 } ; | 142 }; |
| 125 | 143 |
| 126 /** | 144 /** |
| 127 * Send WM_QUERYENDSESSION and WM_ENDSESSION to a window. | 145 * Send WM_QUERYENDSESSION and WM_ENDSESSION to a window. |
| 128 * | 146 * |
| 129 * This window processor tries to shut down each application individually. | 147 * This window processor tries to shut down each application individually. |
| 130 * The alternative, gathering all the query results first and only then ending se
ssions, cannot be done with a single window enumeration. | 148 * The alternative, gathering all the query results first and only then ending se
ssions, cannot be done with a single window enumeration. |
| 131 */ | 149 */ |
| 132 class SendEndsessionMessagesAction | 150 class SendEndsessionMessagesAction |
| 133 { | 151 { |
| 134 public: | 152 public: |
| 135 /* | 153 /* |
| 136 * Enumeration function applied to each window. | 154 * Enumeration function applied to each window. |
| 137 */ | 155 */ |
| 138 bool operator()( HWND window ) | 156 bool operator()(HWND window) |
| 139 { | 157 { |
| 140 DWORD_PTR result ; | 158 DWORD_PTR result; |
| 141 if ( ! SendMessageTimeoutW( window, WM_QUERYENDSESSION, 0, ENDSESSION_CLOSEA
PP, SMTO_BLOCK, timeout, & result ) ) | 159 if (! SendMessageTimeoutW(window, WM_QUERYENDSESSION, 0, ENDSESSION_CLOSEAPP
, SMTO_BLOCK, timeout, & result)) |
| 142 { | 160 { |
| 143 // Assert sending the message failed | 161 // Assert sending the message failed |
| 144 // Ignore failure, just as with SendMessageAction(). | 162 // Ignore failure, just as with SendMessageAction(). |
| 145 return true ; | 163 return true; |
| 146 } | 164 } |
| 147 // Assert result is FALSE if the process has refused notice that it should s
hut down. | 165 // Assert result is FALSE if the process has refused notice that it should s
hut down. |
| 148 if ( ! result ) | 166 if (! result) |
| 149 { | 167 { |
| 150 /* | 168 /* |
| 151 * Returning false terminates iteration over windows. | 169 * Returning false terminates iteration over windows. |
| 152 * Since this process is refusing to shut down, we can't close all the proc
esses and the operation fails. | 170 * Since this process is refusing to shut down, we can't close all the proc
esses and the operation fails. |
| 153 */ | 171 */ |
| 154 return false ; | 172 return false; |
| 155 } | 173 } |
| 156 SendMessageTimeoutW( window, WM_ENDSESSION, 0, ENDSESSION_CLOSEAPP, SMTO_BLO
CK, timeout, 0 ) ; | 174 SendMessageTimeoutW(window, WM_ENDSESSION, 0, ENDSESSION_CLOSEAPP, SMTO_BLOC
K, timeout, 0); |
| 157 return true ; | 175 return true; |
| 158 } | 176 } |
| 159 } ; | 177 }; |
| 160 | 178 |
| 161 /** | 179 /** |
| 162 * Accumulator for query-endsession message. | 180 * Accumulator for query-endsession message. |
| 163 * | 181 * |
| 164 * Implements a conditional-conjunction of the query results. | 182 * Implements a conditional-conjunction of the query results. |
| 165 * All answers must be true in order for this result to be true, | 183 * All answers must be true in order for this result to be true, |
| 166 * and the calculation is terminated at the first answer 'false'. | 184 * and the calculation is terminated at the first answer 'false'. |
| 167 * As usual, errors sending messages are ignored. | 185 * As usual, errors sending messages are ignored. |
| 168 */ | 186 */ |
| 169 struct EndsessionAccumulator : | 187 struct EndsessionAccumulator : |
| 170 public MessageAccumulator | 188 public MessageAccumulator |
| 171 { | 189 { |
| 172 bool permitEndSession ; ///< Accumulator variable yields final result. | 190 bool permitEndSession ; ///< Accumulator variable yields final result. |
| 173 | 191 |
| 174 /** | 192 /** |
| 175 * Enumeration function applied to each window. | 193 * Enumeration function applied to each window. |
| 176 */ | 194 */ |
| 177 bool operator()( DWORD_PTR result, bool returnValue ) | 195 bool operator()(DWORD_PTR result, bool returnValue) |
| 178 { | 196 { |
| 179 if ( ( ! returnValue ) || result ) | 197 if ((! returnValue) || result) |
| 180 { | 198 { |
| 181 // 1. If the result is true, then the process will permit WM_ENDSESSION | 199 // 1. If the result is true, then the process will permit WM_ENDSESSION |
| 182 // 2. An error sending the message counts as "no new information" | 200 // 2. An error sending the message counts as "no new information" |
| 183 return true ; | 201 return true; |
| 184 } | 202 } |
| 185 // The first false is the result of the calculation. | 203 // The first false is the result of the calculation. |
| 186 // The second false means to terminate enumeration early. | 204 // The second false means to terminate enumeration early. |
| 187 permitEndSession = false ; | 205 permitEndSession = false; |
| 188 return false ; | 206 return false; |
| 189 } | 207 } |
| 190 | 208 |
| 191 /** | 209 /** |
| 192 * Ordinary constructor. | 210 * Ordinary constructor. |
| 193 */ | 211 */ |
| 194 EndsessionAccumulator() | 212 EndsessionAccumulator() |
| 195 : permitEndSession( true ) | 213 : permitEndSession(true) |
| 196 {} | 214 {} |
| 197 } ; | 215 }; |
| 198 | 216 |
| 199 //------------------------------------------------------- | 217 //------------------------------------------------------- |
| 200 // ProcessCloser | 218 // ProcessCloser |
| 201 //------------------------------------------------------- | 219 //------------------------------------------------------- |
| 202 /** | 220 /** |
| 203 * Shut down all the processes in the pidSet. | 221 * Shut down all the processes in the pidSet. |
| 204 * | 222 * |
| 205 * The method used here uses blocking system calls to send messages to target pro
cesses. | 223 * The method used here uses blocking system calls to send messages to target pro
cesses. |
| 206 * Message processing delays, therefore, are sequential and the total delay is th
eir sum. | 224 * Message processing delays, therefore, are sequential and the total delay is th
eir sum. |
| 207 * Windows has non-blocking message calls available, and using a multi-threaded i
mplementation would shorten that delay. | 225 * Windows has non-blocking message calls available, and using a multi-threaded i
mplementation would shorten that delay. |
| 208 * The code, hwoever, is significantly simpler without multi-threading. | 226 * The code, hwoever, is significantly simpler without multi-threading. |
| 209 * The present use of this method is not closing dozens of applications, so delay
performance is not critical. | 227 * The present use of this method is not closing dozens of applications, so delay
performance is not critical. |
| 210 * | 228 * |
| 211 * \return | 229 * \return |
| 212 * The negation of IsRunning(). | 230 * The negation of IsRunning(). |
| 213 * If IsRunning() was true at the beginning, then this function will have run r
efresh() before returning. | 231 * If IsRunning() was true at the beginning, then this function will have run r
efresh() before returning. |
| 214 * | 232 * |
| 215 * \sa | 233 * \sa |
| 216 * - MSDN [WM_QUERYENDSESSION message](http://msdn.microsoft.com/en-us/library/
windows/desktop/aa376890%28v=vs.85%29.aspx) | 234 * - MSDN [WM_QUERYENDSESSION message](http://msdn.microsoft.com/en-us/library/
windows/desktop/aa376890%28v=vs.85%29.aspx) |
| 217 * - MSDN [WM_ENDSESSION message](http://msdn.microsoft.com/en-us/library/windo
ws/desktop/aa376889%28v=vs.85%29.aspx) | 235 * - MSDN [WM_ENDSESSION message](http://msdn.microsoft.com/en-us/library/windo
ws/desktop/aa376889%28v=vs.85%29.aspx) |
| 218 */ | 236 */ |
| 219 bool ProcessCloser::ShutDown(ImmediateSession& session) | 237 bool ProcessCloser::ShutDown(ImmediateSession& session) |
| 220 { | 238 { |
| 221 /* | 239 /* |
| 222 * If we're not running, we don't need to shut down. | 240 * If we're not running, we don't need to shut down. |
| 223 */ | 241 */ |
| 224 if ( ! IsRunning() ) | 242 if (! IsRunning()) |
| 225 { | 243 { |
| 226 return true ; | 244 return true; |
| 227 } | 245 } |
| 228 | 246 |
| 229 /* | 247 /* |
| 230 * Shutting down is a structure as an escalating series of attempts to shut dow
n. | 248 * Shutting down is a structure as an escalating series of attempts to shut dow
n. |
| 231 * After each one, we wait to see if the shut down has completed. | 249 * After each one, we wait to see if the shut down has completed. |
| 232 * Even though we're using a blocking call to send messages, applications need
not block before exiting. | 250 * Even though we're using a blocking call to send messages, applications need
not block before exiting. |
| 233 * Internet Explorer, in particular, does not. | 251 * Internet Explorer, in particular, does not. |
| 234 * | 252 * |
| 235 * Note that termination occurs inside the default case within the switch state
ment | 253 * Note that termination occurs inside the default case within the switch state
ment |
| 236 */ | 254 */ |
| 237 for ( unsigned int stage = 1 ; ; ++ stage ) | 255 for (unsigned int stage = 1 ; ; ++ stage) |
| 238 { | 256 { |
| 239 // Assert IsRunning() | 257 // Assert IsRunning() |
| 240 switch( stage ) | 258 switch (stage) |
| 241 { | 259 { |
| 242 case 1 : | 260 case 1 : |
| 243 /* | |
| 244 * Send WM_QUERYENDSESSION to every admissible window. | |
| 245 * Send WM_ENDSESSION if all processes are ready to shut down. | |
| 246 * We try this technique first, since this allows an application to restore
its application state when it starts up again. | |
| 247 */ | |
| 248 { | 261 { |
| 249 EndsessionAccumulator acc ; | 262 /* |
| 250 SendMessageAction m1( WM_QUERYENDSESSION, 0, ENDSESSION_CLOSEAPP, acc )
; | 263 * Send WM_QUERYENDSESSION to every admissible window. |
| 251 IterateOurWindows( m1 ) ; | 264 * Send WM_ENDSESSION if all processes are ready to shut down. |
| 265 * We try this technique first, since this allows an application to resto
re its application state when it starts up again. |
| 266 */ |
| 267 EndsessionAccumulator acc; |
| 268 SendMessageAction m1(WM_QUERYENDSESSION, 0, ENDSESSION_CLOSEAPP, acc); |
| 269 IterateOurWindows(m1); |
| 252 | 270 |
| 253 if ( acc.permitEndSession ) | 271 if (acc.permitEndSession) |
| 254 { | 272 { |
| 255 SendMessageAction m2( WM_ENDSESSION, 0, ENDSESSION_CLOSEAPP ) ; | 273 SendMessageAction m2(WM_ENDSESSION, 0, ENDSESSION_CLOSEAPP); |
| 256 IterateOurWindows( m2 ) ; | 274 IterateOurWindows(m2); |
| 257 } | 275 } |
| 258 } | 276 } |
| 259 break ; | 277 break; |
| 260 | 278 |
| 261 case 2 : | 279 case 2 : |
| 262 { | 280 { |
| 263 /* | 281 /* |
| 264 * Send WM_QUERYENDSESSION and WM_ENDSESSION to every admissible window s
ingly, not accumulating results. | 282 * Send WM_QUERYENDSESSION and WM_ENDSESSION to every admissible window s
ingly, not accumulating results. |
| 265 */ | 283 */ |
| 266 SendEndsessionMessagesAction m ; | 284 SendEndsessionMessagesAction m; |
| 267 IterateOurWindows( m ) ; | 285 IterateOurWindows(m); |
| 268 } | 286 } |
| 269 break ; | 287 break; |
| 270 | 288 |
| 271 case 3 : | 289 case 3 : |
| 272 { | 290 { |
| 273 /* | 291 /* |
| 274 * Send WM_CLOSE to every admissible window. | 292 * Send WM_CLOSE to every admissible window. |
| 275 */ | 293 */ |
| 276 SendMessageAction m( WM_CLOSE, 0, 0 ) ; | 294 SendMessageAction m(WM_CLOSE, 0, 0); |
| 277 IterateOurWindows( m ) ; | 295 IterateOurWindows(m); |
| 278 } | |
| 279 break ; | |
| 280 | |
| 281 case 4: | |
| 282 /* | |
| 283 * Oh well. Take cover. It gets violent here. Try to kill all matching proc
esses. | |
| 284 */ | |
| 285 for (auto it = pidSet.begin(); it != pidSet.end(); ++it) | |
| 286 { | |
| 287 HANDLE tmpHandle = OpenProcess(PROCESS_TERMINATE, FALSE, *it); | |
| 288 if (!tmpHandle) | |
| 289 { | |
| 290 std::ostringstream stream; | |
| 291 stream << "Can't open process for termination. Error: " << GetLastErro
r(); | |
| 292 session.Log(stream.str()); | |
| 293 continue; | |
| 294 } | |
| 295 WindowsHandle procHandle(tmpHandle); | |
| 296 if (!TerminateProcess(tmpHandle, 0)) | |
| 297 { | |
| 298 std::ostringstream stream; | |
| 299 stream << "Can't terminate process. Error: " << GetLastError(); | |
| 300 session.Log(stream.str()); | |
| 301 } | |
| 302 } | 296 } |
| 303 break; | 297 break; |
| 304 | 298 |
| 305 default: | 299 case 4: |
| 306 // We're out of ways to try to shut down. | 300 /* |
| 307 return false; | 301 * Oh well. Take cover. It gets violent here. Try to kill all matching pr
ocesses. |
| 302 */ |
| 303 for (auto it = pidSet.begin(); it != pidSet.end(); ++it) |
| 304 { |
| 305 HANDLE tmpHandle = OpenProcess(PROCESS_TERMINATE, FALSE, *it); |
| 306 if (!tmpHandle) |
| 307 { |
| 308 std::ostringstream stream; |
| 309 stream << "Can't open process for termination. Error: " << GetLastEr
ror(); |
| 310 session.Log(stream.str()); |
| 311 continue; |
| 312 } |
| 313 WindowsHandle procHandle(tmpHandle); |
| 314 if (!TerminateProcess(tmpHandle, 0)) |
| 315 { |
| 316 std::ostringstream stream; |
| 317 stream << "Can't terminate process. Error: " << GetLastError(); |
| 318 session.Log(stream.str()); |
| 319 } |
| 320 } |
| 321 break; |
| 322 |
| 323 default: |
| 324 // We're out of ways to try to shut down. |
| 325 return false; |
| 308 } | 326 } |
| 309 | 327 |
| 310 /* | 328 /* |
| 311 * Wait loop. | 329 * Wait loop. |
| 312 */ | 330 */ |
| 313 for ( unsigned int j = 0 ; j < 50 ; ++ j ) | 331 for (unsigned int j = 0 ; j < 50 ; ++ j) |
| 314 { | 332 { |
| 315 std::this_thread::sleep_for( std::chrono::milliseconds( 30 ) ) ; | 333 std::this_thread::sleep_for(std::chrono::milliseconds(30)); |
| 316 Refresh() ; | 334 Refresh(); |
| 317 if ( ! IsRunning() ) | 335 if (! IsRunning()) |
| 318 { | 336 { |
| 319 return true ; | 337 return true; |
| 320 } | 338 } |
| 321 } | 339 } |
| 322 // Assert IsRunning() | 340 // Assert IsRunning() |
| 323 } | 341 } |
| 324 // No control path leaves the for-loop. | 342 // No control path leaves the for-loop. |
| 325 } ; | 343 }; |
| 326 | 344 |
| OLD | NEW |