|
1 /* |
|
2 * Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 // CUtils.cpp : Handy bits and pieces for apps |
|
22 // |
|
23 |
|
24 #include "stdafx.h" |
|
25 #include <windows.h> |
|
26 #include <tchar.h> |
|
27 #include "Utils.h" |
|
28 |
|
29 CUtils::CUtils() |
|
30 : m_hMutex((HANDLE)0) |
|
31 { |
|
32 // open the Service Control Manager |
|
33 hSCM = OpenSCManager(NULL, // local machine |
|
34 NULL, // ServicesActive database |
|
35 SC_MANAGER_ALL_ACCESS); // full access |
|
36 } |
|
37 |
|
38 CUtils::~CUtils() |
|
39 { |
|
40 if (hSCM) |
|
41 CloseServiceHandle(hSCM); |
|
42 |
|
43 if (m_hMutex) |
|
44 CloseHandle(m_hMutex); |
|
45 } |
|
46 |
|
47 |
|
48 // attempts to create a mutex for this process. |
|
49 // if it fails, another process of the same name is already running |
|
50 bool CUtils::AlreadyRunning(LPCTSTR szAppName) |
|
51 { |
|
52 m_hMutex = CreateMutex(NULL, FALSE, szAppName); |
|
53 if ((!m_hMutex) || (WaitForSingleObject( m_hMutex, 0 ) == WAIT_TIMEOUT)) |
|
54 { |
|
55 return true; |
|
56 } |
|
57 |
|
58 return false; |
|
59 } |
|
60 |
|
61 |
|
62 // invokes an application then waits for it to exit |
|
63 bool CUtils::CallProcessAndWait(LPCTSTR szApplication, LPTSTR szCommandLine, LPCTSTR szDirectory, bool bRunMinimised) |
|
64 { |
|
65 bool valid = false; |
|
66 STARTUPINFO startInfo = {0}; |
|
67 startInfo.cb = sizeof(STARTUPINFO); |
|
68 retCode = -1; |
|
69 |
|
70 // run window minimised and not active |
|
71 if (bRunMinimised) |
|
72 { |
|
73 startInfo.dwFlags = STARTF_USESHOWWINDOW; |
|
74 startInfo.wShowWindow = SW_SHOWMINIMIZED | SW_SHOWMINNOACTIVE; |
|
75 } |
|
76 |
|
77 PROCESS_INFORMATION procInfo = {0}; |
|
78 |
|
79 // event attributes for the child process |
|
80 SECURITY_ATTRIBUTES eventAttr; |
|
81 eventAttr.nLength = sizeof(eventAttr); |
|
82 eventAttr.lpSecurityDescriptor = NULL; |
|
83 eventAttr.bInheritHandle = TRUE; |
|
84 |
|
85 // NOTE: if passing a command line, include the application name in szCommandLine and pass NULL for szApplication |
|
86 if (CreateProcess(szApplication, szCommandLine, NULL, NULL, FALSE, NULL, NULL, |
|
87 szDirectory, &startInfo, &procInfo)) |
|
88 { |
|
89 if (WAIT_OBJECT_0 == WaitForSingleObject(procInfo.hProcess, INFINITE)) |
|
90 { |
|
91 GetExitCodeProcess(procInfo.hProcess, &retCode); |
|
92 CloseHandle(procInfo.hThread); |
|
93 CloseHandle(procInfo.hProcess); |
|
94 valid = true; |
|
95 } |
|
96 } |
|
97 else |
|
98 _GetWindowsError(); |
|
99 |
|
100 return valid; |
|
101 } |
|
102 |
|
103 |
|
104 bool CUtils::CallProcess(LPCTSTR szApplication, LPTSTR szCommandLine, LPCTSTR szDirectory) |
|
105 { |
|
106 bool valid = false; |
|
107 STARTUPINFO startInfo = {0}; |
|
108 startInfo.cb = sizeof(STARTUPINFO); |
|
109 |
|
110 PROCESS_INFORMATION procInfo = {0}; |
|
111 |
|
112 // event attributes for the child process |
|
113 SECURITY_ATTRIBUTES eventAttr; |
|
114 eventAttr.nLength = sizeof(eventAttr); |
|
115 eventAttr.lpSecurityDescriptor = NULL; |
|
116 eventAttr.bInheritHandle = TRUE; |
|
117 |
|
118 if (CreateProcess(szApplication, szCommandLine, NULL, NULL, FALSE, NULL, NULL, |
|
119 szDirectory, &startInfo, &procInfo)) |
|
120 { |
|
121 CloseHandle(procInfo.hThread); |
|
122 CloseHandle(procInfo.hProcess); |
|
123 valid = true; |
|
124 } |
|
125 else |
|
126 _GetWindowsError(); |
|
127 |
|
128 return valid; |
|
129 } |
|
130 |
|
131 // requests an NT service to perform a particular request |
|
132 bool CUtils::ServiceRequest(const char *szServiceName, const unsigned int iRequest) |
|
133 { |
|
134 bool valid = false; |
|
135 |
|
136 if (hSCM) |
|
137 { |
|
138 switch(iRequest) |
|
139 { |
|
140 case REQ_START: |
|
141 if (Validate(hSCM, szServiceName, SERVICE_INACTIVE)) |
|
142 { |
|
143 SC_HANDLE hService = OpenService(hSCM, szServiceName, SERVICE_ALL_ACCESS); |
|
144 if (hService) |
|
145 { |
|
146 DealWithDependentServices(szServiceName, iRequest); |
|
147 |
|
148 if (StartService(hService, 0, NULL)) |
|
149 valid = true; |
|
150 |
|
151 CloseServiceHandle(hService); |
|
152 } |
|
153 else |
|
154 _GetWindowsError(); |
|
155 } |
|
156 else |
|
157 { |
|
158 valid = true; // already started |
|
159 } |
|
160 break; |
|
161 case REQ_STOP: |
|
162 if (Validate(hSCM, szServiceName, SERVICE_ACTIVE)) |
|
163 { |
|
164 SC_HANDLE hService = OpenService(hSCM, szServiceName, SERVICE_STOP); |
|
165 if (hService) |
|
166 { |
|
167 DealWithDependentServices(szServiceName, iRequest); |
|
168 |
|
169 SERVICE_STATUS status; |
|
170 if (ControlService(hService, SERVICE_CONTROL_STOP, &status)) |
|
171 valid = true; |
|
172 |
|
173 CloseServiceHandle(hService); |
|
174 } |
|
175 else |
|
176 _GetWindowsError(); |
|
177 } |
|
178 else |
|
179 { |
|
180 valid = true; // already stopped |
|
181 } |
|
182 break; |
|
183 default: |
|
184 break; |
|
185 }; |
|
186 |
|
187 } |
|
188 return valid; |
|
189 } |
|
190 |
|
191 |
|
192 |
|
193 // recurses through a directory structure, performing an action on the files/directories within |
|
194 unsigned int CUtils::RecurseDir(const char *szDirectory, const unsigned int iCommand) |
|
195 { |
|
196 iFileCommand = iCommand; |
|
197 iFileCount = 0; |
|
198 |
|
199 Recurse(szDirectory); |
|
200 |
|
201 return iFileCount; |
|
202 } |
|
203 |
|
204 |
|
205 // adds a backslash to a path if it doesn't already have one |
|
206 void CUtils::AddSlash(char *szPath) |
|
207 { |
|
208 if (*(szPath + strlen(szPath) - 1) != '\\') |
|
209 strcat(szPath, "\\"); |
|
210 } |
|
211 |
|
212 |
|
213 bool CUtils::ListServices(DWORD dwState) |
|
214 { |
|
215 return Validate(hSCM, NULL, dwState, true); |
|
216 } |
|
217 |
|
218 //////////////////////////////////////////////////////////////////////////////////////////////// |
|
219 // |
|
220 // Private Methods |
|
221 // |
|
222 //////////////////////////////////////////////////////////////////////////////////////////////// |
|
223 |
|
224 bool CUtils::Validate(SC_HANDLE hSCM, const char *szServiceName, DWORD dwState, bool bDisplayOnly) |
|
225 { |
|
226 bool valid = false; |
|
227 DWORD dwBytes = 0; |
|
228 DWORD dwNumServices = 0; |
|
229 DWORD dwResumeHandle = 0; |
|
230 static ENUM_SERVICE_STATUS status[200]; |
|
231 |
|
232 // get list of services in particular state |
|
233 if (EnumServicesStatus(hSCM, // handle |
|
234 SERVICE_WIN32, // service |
|
235 dwState, // state |
|
236 (ENUM_SERVICE_STATUS *)status, // returned info |
|
237 200 * sizeof(ENUM_SERVICE_STATUS), // length of buffer |
|
238 &dwBytes, // returned length |
|
239 &dwNumServices, // number services returned |
|
240 &dwResumeHandle)) // point to continue |
|
241 { |
|
242 if (bDisplayOnly) |
|
243 { |
|
244 printf("\n\nServices\n========\n\n"); |
|
245 } |
|
246 |
|
247 for (DWORD i=0;i<dwNumServices;i++) |
|
248 { |
|
249 if (bDisplayOnly) |
|
250 { |
|
251 if (status[i].ServiceStatus.dwCurrentState == SERVICE_RUNNING) |
|
252 printf("STARTED %s (%s)\n", status[i].lpDisplayName, status[i].lpServiceName); |
|
253 else if (status[i].ServiceStatus.dwCurrentState == SERVICE_STOPPED) |
|
254 printf("STOPPED %s (%s)\n", status[i].lpDisplayName, status[i].lpServiceName); |
|
255 else if (status[i].ServiceStatus.dwCurrentState == SERVICE_PAUSED) |
|
256 printf("PAUSED %s (%s)\n", status[i].lpDisplayName, status[i].lpServiceName); |
|
257 else |
|
258 printf("PENDING %s (%s)\n", status[i].lpDisplayName, status[i].lpServiceName); |
|
259 } |
|
260 else |
|
261 { |
|
262 if (stricmp(status[i].lpServiceName, szServiceName) == 0) |
|
263 { |
|
264 valid = true; |
|
265 break; |
|
266 } |
|
267 } |
|
268 } |
|
269 } |
|
270 |
|
271 // check the driver list, just in case it's in there... |
|
272 if (!valid) |
|
273 { |
|
274 if (EnumServicesStatus(hSCM, // handle |
|
275 SERVICE_DRIVER, // driver |
|
276 dwState, // state |
|
277 (ENUM_SERVICE_STATUS *)status, // returned info |
|
278 200 * sizeof(ENUM_SERVICE_STATUS), // length of buffer |
|
279 &dwBytes, // returned length |
|
280 &dwNumServices, // number services returned |
|
281 &dwResumeHandle)) // point to continue |
|
282 { |
|
283 if (bDisplayOnly) |
|
284 { |
|
285 printf("\n\nDrivers\n=======\n\n"); |
|
286 } |
|
287 |
|
288 for (DWORD i=0;i<dwNumServices;i++) |
|
289 { |
|
290 if (bDisplayOnly) |
|
291 { |
|
292 if (status[i].ServiceStatus.dwCurrentState == SERVICE_RUNNING) |
|
293 printf("STARTED %s (%s)\n", status[i].lpDisplayName, status[i].lpServiceName); |
|
294 else if (status[i].ServiceStatus.dwCurrentState == SERVICE_STOPPED) |
|
295 printf("STOPPED %s (%s)\n", status[i].lpDisplayName, status[i].lpServiceName); |
|
296 else if (status[i].ServiceStatus.dwCurrentState == SERVICE_PAUSED) |
|
297 printf("PAUSED %s (%s)\n", status[i].lpDisplayName, status[i].lpServiceName); |
|
298 else |
|
299 printf("PENDING %s (%s)\n", status[i].lpDisplayName, status[i].lpServiceName); |
|
300 } |
|
301 else |
|
302 { |
|
303 if (stricmp(status[i].lpServiceName, szServiceName) == 0) |
|
304 { |
|
305 valid = true; |
|
306 break; |
|
307 } |
|
308 } |
|
309 } |
|
310 } |
|
311 } |
|
312 |
|
313 return valid; |
|
314 } |
|
315 |
|
316 |
|
317 void |
|
318 CUtils::Recurse(const char * rootDir) |
|
319 { |
|
320 char fullname[MAX_PATH + 1]; |
|
321 HANDLE hFind; |
|
322 |
|
323 sprintf( fullname, "%s\\*", rootDir ); |
|
324 hFind = FindFirstFile(fullname, &ffd); |
|
325 |
|
326 if(hFind != INVALID_HANDLE_VALUE) |
|
327 { |
|
328 do |
|
329 { |
|
330 sprintf( fullname, "%s\\%s", rootDir, ffd.cFileName ); |
|
331 |
|
332 // directory so recurse into it |
|
333 if(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) |
|
334 { |
|
335 // ignore current and previous dirs |
|
336 if ((stricmp (ffd.cFileName, ".") != 0) && (strcmp (ffd.cFileName, "..") != 0)) |
|
337 { |
|
338 Recurse(fullname); |
|
339 |
|
340 // remove it |
|
341 if (iFileCommand == DELETEALL) |
|
342 if (RemoveDirectory(fullname)) |
|
343 iFileCount++; |
|
344 } |
|
345 } |
|
346 else |
|
347 { |
|
348 // remove now empty directory |
|
349 if (iFileCommand == DELETEALL || iFileCommand == DELETEFILESONLY) |
|
350 if (DeleteFile( fullname )) |
|
351 iFileCount++; |
|
352 |
|
353 // clear the attributes |
|
354 if (iFileCommand == REMOVEALLATTRIBUTES) |
|
355 if (SetFileAttributes(fullname, FILE_ATTRIBUTE_NORMAL)) |
|
356 iFileCount++; |
|
357 } |
|
358 } |
|
359 while(FindNextFile(hFind, &ffd)); |
|
360 |
|
361 FindClose( hFind ); |
|
362 } |
|
363 |
|
364 // remove this root now we are finished with it |
|
365 if (iFileCommand == DELETEALL) |
|
366 if (RemoveDirectory(rootDir)) |
|
367 iFileCount++; |
|
368 } |
|
369 |
|
370 |
|
371 void |
|
372 CUtils::DealWithDependentServices(const char *szServiceName, const unsigned int iRequest) |
|
373 { |
|
374 DWORD dwBytes = 0; |
|
375 DWORD dwNumServices = 0; |
|
376 DWORD dwResumeHandle = 0; |
|
377 ENUM_SERVICE_STATUS status[100]; |
|
378 |
|
379 // service may have dependent services so stop them first |
|
380 SC_HANDLE hService = OpenService(hSCM, szServiceName, SERVICE_ENUMERATE_DEPENDENTS); |
|
381 if (hService) |
|
382 { |
|
383 if (EnumDependentServices(hService, |
|
384 SERVICE_ACTIVE, |
|
385 (ENUM_SERVICE_STATUS *)status, // returned info |
|
386 100 * sizeof(ENUM_SERVICE_STATUS), // length of buffer |
|
387 &dwBytes, // returned length |
|
388 &dwNumServices)) // number services returned |
|
389 { |
|
390 for (DWORD i=0;i<dwNumServices;i++) |
|
391 { |
|
392 // recurse until we stop the last dependant |
|
393 ServiceRequest(status[i].lpServiceName, iRequest); |
|
394 } |
|
395 } |
|
396 |
|
397 CloseServiceHandle(hService); |
|
398 |
|
399 // if there were dependents, allow some time register service stops |
|
400 if (dwNumServices) |
|
401 Sleep(2000); |
|
402 } |
|
403 else |
|
404 _GetWindowsError(); |
|
405 } |
|
406 |
|
407 void |
|
408 CUtils::_GetWindowsError() |
|
409 { |
|
410 LPVOID lpSysError; |
|
411 DWORD dwRet = GetLastError(); |
|
412 |
|
413 FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, |
|
414 NULL, |
|
415 dwRet, |
|
416 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language |
|
417 ( LPTSTR ) &lpSysError, |
|
418 0, |
|
419 NULL ); |
|
420 |
|
421 if (lpSysError) |
|
422 _tcscpy(szError, ( LPTSTR )lpSysError); |
|
423 |
|
424 LocalFree( lpSysError ); |
|
425 } |
|
426 |
|
427 LPTSTR |
|
428 CUtils::GetWindowsError() |
|
429 { |
|
430 return szError; |
|
431 } |
|
432 |
|
433 LPTSTR |
|
434 CUtils::GetWindowsErrorNow() |
|
435 { |
|
436 _GetWindowsError(); |
|
437 return szError; |
|
438 } |
|
439 |
|
440 |
|
441 /////////////////////////////////////////////////////////////////////////////////// |
|
442 // Trim the text of unwanted characters |
|
443 // |
|
444 void |
|
445 CUtils::TrimTabsCRAndWhitespace(char *szBuffer) |
|
446 { |
|
447 // strip any unwanted chars off the end of each value |
|
448 char *ptr = szBuffer + strlen(szBuffer) - 1; |
|
449 if (ptr && (*ptr)) |
|
450 { |
|
451 while ((*ptr) == '\r' || (*ptr) == '\n' || (*ptr) == '\t' || (*ptr) == ' ') |
|
452 ptr--; |
|
453 |
|
454 *(ptr + 1) = (char)0; |
|
455 } |
|
456 } |
|
457 |
|
458 |
|
459 /////////////////////////////////////////////////////////////////////////////////// |
|
460 // Trim the buffered text to the first EOL and adjust the file pointer to suit |
|
461 // If EOL's included, include all up to the next occurance of text or EOF |
|
462 // |
|
463 int |
|
464 CUtils::TrimBufferToFirstEOL(HANDLE mmphndl, char *szBuffer, bool bIncludeCR) |
|
465 { |
|
466 int count = 0; |
|
467 int length = strlen(szBuffer); |
|
468 int actualend = 0; |
|
469 |
|
470 // move to first CR |
|
471 while (*(szBuffer + count) && (*(szBuffer + count) != '\r') && (*(szBuffer + count) != '\n')) |
|
472 count++; |
|
473 |
|
474 |
|
475 // move to after CRs |
|
476 actualend = count; |
|
477 while ((*(szBuffer + actualend) == '\r') || (*(szBuffer + actualend) == '\n')) |
|
478 actualend++; |
|
479 |
|
480 if (count) |
|
481 { |
|
482 // include the CRs |
|
483 if (bIncludeCR) |
|
484 count = actualend; |
|
485 |
|
486 // terminate the string at our desired point |
|
487 *(szBuffer + count) = (char)0; |
|
488 |
|
489 // set file pointer accordingly |
|
490 if (mmphndl) |
|
491 SetFilePointer(mmphndl, 0 - (length - actualend), NULL, FILE_CURRENT); |
|
492 } |
|
493 |
|
494 return count; |
|
495 } |
|
496 |
|
497 |
|
498 /////////////////////////////////////////////////////////////////////////////////// |
|
499 // Trim the buffered text to the last EOL and adjust the file pointer to suit |
|
500 // |
|
501 void |
|
502 CUtils::TrimBufferToLastEOL(HANDLE mmphndl, char *szBuffer) |
|
503 { |
|
504 // move back to last CR |
|
505 char *end = szBuffer + strlen(szBuffer) - 1; |
|
506 while ((end != szBuffer) && (*end != '\r') && (*end != '\n')) |
|
507 end--; |
|
508 |
|
509 // NULL-terminate line and adjust file pointer |
|
510 if (end != (szBuffer + strlen(szBuffer) - 1)) |
|
511 { |
|
512 int diff = (szBuffer + strlen(szBuffer) - 1) - end; |
|
513 (*end) = (char)0; |
|
514 |
|
515 // back up the file pointer to the end of the last line |
|
516 if (mmphndl) |
|
517 SetFilePointer(mmphndl, 0 - diff, NULL, FILE_CURRENT); |
|
518 } |
|
519 } |