| 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 | 
|---|