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

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

Issue 29329159: Issue #1185 - Fix formatting in installer-lib and its tests (Closed)
Patch Set: Created Oct. 15, 2015, 7:03 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « installer/src/installer-lib/process.h ('k') | installer/src/installer-lib/property.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
OLDNEW
« no previous file with comments | « installer/src/installer-lib/process.h ('k') | installer/src/installer-lib/property.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld