Synchronize with trunk r58528.
[reactos.git] / base / applications / mscutils / servman / start.c
1 /*
2 * PROJECT: ReactOS Services
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: base/applications/mscutils/servman/start.c
5 * PURPOSE: Start a service
6 * COPYRIGHT: Copyright 2005-2010 Ged Murphy <gedmurphy@reactos.org>
7 *
8 */
9
10 #include "precomp.h"
11
12 static BOOL
13 DoStartService(PMAIN_WND_INFO Info,
14 HWND hProgress,
15 LPWSTR lpStartParams)
16 {
17 SC_HANDLE hSCManager;
18 SC_HANDLE hService;
19 SERVICE_STATUS_PROCESS ServiceStatus;
20 DWORD BytesNeeded = 0;
21 DWORD dwStartTickCount;
22 DWORD dwOldCheckPoint;
23 DWORD dwWaitTime;
24 DWORD dwMaxWait;
25 BOOL bRet = FALSE;
26
27 BOOL bWhiteSpace = TRUE;
28 LPWSTR lpChar;
29 DWORD dwArgsCount = 0;
30 LPCWSTR *lpArgsVector = NULL;
31
32 if (lpStartParams != NULL)
33 {
34 /* Count the number of arguments */
35 lpChar = lpStartParams;
36 while (*lpChar != 0)
37 {
38 if (iswspace(*lpChar))
39 {
40 bWhiteSpace = TRUE;
41 }
42 else
43 {
44 if (bWhiteSpace == TRUE)
45 {
46 dwArgsCount++;
47 bWhiteSpace = FALSE;
48 }
49 }
50
51 lpChar++;
52 }
53
54 /* Allocate the arguments vector and add one for the service name */
55 lpArgsVector = LocalAlloc(LMEM_FIXED, (dwArgsCount + 1) * sizeof(LPCWSTR));
56 if (!lpArgsVector)
57 return FALSE;
58
59 /* Make the service name the first argument */
60 lpArgsVector[0] = Info->pCurrentService->lpServiceName;
61
62 /* Fill the arguments vector */
63 dwArgsCount = 1;
64 bWhiteSpace = TRUE;
65 lpChar = lpStartParams;
66 while (*lpChar != 0)
67 {
68 if (iswspace(*lpChar))
69 {
70 *lpChar = 0;
71 bWhiteSpace = TRUE;
72 }
73 else
74 {
75 if (bWhiteSpace == TRUE)
76 {
77 lpArgsVector[dwArgsCount] = lpChar;
78 dwArgsCount++;
79 bWhiteSpace = FALSE;
80 }
81 }
82
83 lpChar++;
84 }
85 }
86
87 hSCManager = OpenSCManager(NULL,
88 NULL,
89 SC_MANAGER_CONNECT);
90 if (hSCManager)
91 {
92 hService = OpenService(hSCManager,
93 Info->pCurrentService->lpServiceName,
94 SERVICE_START | SERVICE_QUERY_STATUS);
95 if (hService)
96 {
97 if (hProgress)
98 {
99 /* Increment the progress bar */
100 IncrementProgressBar(hProgress, DEFAULT_STEP);
101 }
102
103 /* Start the service */
104 bRet = StartService(hService,
105 dwArgsCount,
106 lpArgsVector);
107 if (!bRet && GetLastError() == ERROR_SERVICE_ALREADY_RUNNING)
108 {
109 /* If it's already running, just return TRUE */
110 bRet = TRUE;
111 }
112 else if (bRet)
113 {
114 bRet = FALSE;
115
116 /* Get the service status to check if it's running */
117 if (QueryServiceStatusEx(hService,
118 SC_STATUS_PROCESS_INFO,
119 (LPBYTE)&ServiceStatus,
120 sizeof(SERVICE_STATUS_PROCESS),
121 &BytesNeeded))
122 {
123 /* We don't want to wait for more than 30 seconds */
124 dwMaxWait = 30000;
125 dwStartTickCount = GetTickCount();
126
127 /* Loop until it's running */
128 while (ServiceStatus.dwCurrentState != SERVICE_RUNNING)
129 {
130 dwOldCheckPoint = ServiceStatus.dwCheckPoint;
131 dwWaitTime = ServiceStatus.dwWaitHint / 10;
132
133 /* Get the latest status info */
134 if (!QueryServiceStatusEx(hService,
135 SC_STATUS_PROCESS_INFO,
136 (LPBYTE)&ServiceStatus,
137 sizeof(SERVICE_STATUS_PROCESS),
138 &BytesNeeded))
139 {
140 /* Something went wrong... */
141 break;
142 }
143
144 /* Is the service making progress? */
145 if (ServiceStatus.dwCheckPoint > dwOldCheckPoint)
146 {
147 /* It is, get the latest tickcount to reset the max wait time */
148 dwStartTickCount = GetTickCount();
149 dwOldCheckPoint = ServiceStatus.dwCheckPoint;
150 IncrementProgressBar(hProgress, DEFAULT_STEP);
151 }
152 else
153 {
154 /* It's not, make sure we haven't exceeded our wait time */
155 if (GetTickCount() >= dwStartTickCount + dwMaxWait)
156 {
157 /* We have, give up */
158 break;
159 }
160 }
161
162 /* Adjust the wait hint times */
163 if (dwWaitTime < 200)
164 dwWaitTime = 200;
165 else if (dwWaitTime > 10000)
166 dwWaitTime = 10000;
167
168 /* Wait before trying again */
169 Sleep(dwWaitTime);
170 }
171 }
172
173 if (ServiceStatus.dwCurrentState == SERVICE_RUNNING)
174 {
175 bRet = TRUE;
176 }
177 }
178
179 CloseServiceHandle(hService);
180 }
181
182 CloseServiceHandle(hSCManager);
183 }
184
185 if (lpArgsVector)
186 LocalFree(lpArgsVector);
187
188 return bRet;
189 }
190
191 BOOL
192 DoStart(PMAIN_WND_INFO Info, LPWSTR lpStartParams)
193 {
194 HWND hProgress;
195 BOOL bRet = FALSE;
196
197 /* Create a progress window to track the progress of the stopping service */
198 hProgress = CreateProgressDialog(Info->hMainWnd,
199 IDS_PROGRESS_INFO_START);
200 if (hProgress)
201 {
202 /* Set the service name and reset the progress bag */
203 InitializeProgressDialog(hProgress, Info->pCurrentService->lpServiceName);
204
205 /* Start the requested service */
206 bRet = DoStartService(Info, hProgress, lpStartParams);
207
208 /* Complete and destroy the progress bar */
209 DestroyProgressDialog(hProgress, bRet);
210 }
211
212 return bRet;
213 }