Sync with trunk r63502.
[reactos.git] / base / applications / mscutils / servman / stop_dependencies.c
1 /*
2 * PROJECT: ReactOS Services
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: base/applications/mscutils/servman/stop_dependencies.c
5 * PURPOSE: Routines related to stopping dependent services
6 * COPYRIGHT: Copyright 2006-2010 Ged Murphy <gedmurphy@reactos.org>
7 *
8 */
9
10 #include "precomp.h"
11
12 static LPWSTR
13 AddServiceToList(LPWSTR *lpServiceList,
14 LPWSTR lpServiceToAdd)
15 {
16 LPWSTR lpNewList = NULL;
17 LPWSTR ptr;
18 DWORD dwToAddSize;
19 DWORD dwCurSize;
20
21 dwToAddSize = wcslen(lpServiceToAdd) + 1;
22
23 /* Is this is the first in the list? */
24 if (!*lpServiceList)
25 {
26 /* Add another char for double null */
27 dwToAddSize++;
28
29 lpNewList = HeapAlloc(GetProcessHeap(),
30 0,
31 dwToAddSize * sizeof(WCHAR));
32 if (lpNewList)
33 {
34 /* Copy the service name */
35 StringCchCopy(lpNewList,
36 dwToAddSize,
37 lpServiceToAdd);
38
39 /* Add the double null char */
40 lpNewList[dwToAddSize - 1] = L'\0';
41 }
42 }
43 else
44 {
45 ptr = *lpServiceList;
46 dwCurSize = 0;
47
48 /* Get the list size */
49 while (TRUE)
50 {
51 /* Break when we hit the double null */
52 if (*ptr == L'\0' && *(ptr + 1) == L'\0')
53 break;
54
55 ptr++;
56 dwCurSize++;
57 }
58 dwCurSize++;
59
60 /* Add another char for double null */
61 dwCurSize++;
62
63 /* Extend the list size */
64 lpNewList = HeapReAlloc(GetProcessHeap(),
65 0,
66 *lpServiceList,
67 (dwCurSize + dwToAddSize) * sizeof(WCHAR));
68 if (lpNewList)
69 {
70 /* Copy the service name */
71 StringCchCopy(&lpNewList[dwCurSize - 1],
72 dwToAddSize,
73 lpServiceToAdd);
74
75 /* Add the double null char */
76 lpNewList[dwCurSize + dwToAddSize - 1] = L'\0';
77 }
78 }
79
80 return lpNewList;
81 }
82
83 static BOOL
84 BuildListOfServicesToStop(LPWSTR *lpServiceList,
85 LPWSTR lpServiceName)
86 {
87 LPENUM_SERVICE_STATUS lpServiceStatus;
88 DWORD dwCount, i;
89 BOOL bRet = FALSE;
90
91 /* Get a list of service dependents */
92 lpServiceStatus = TV2_GetDependants(lpServiceName, &dwCount);
93 if (lpServiceStatus)
94 {
95 for (i = 0; i < dwCount; i++)
96 {
97 /* Does this service need stopping? */
98 if (lpServiceStatus[i].ServiceStatus.dwCurrentState != SERVICE_STOPPED &&
99 lpServiceStatus[i].ServiceStatus.dwCurrentState != SERVICE_STOP_PENDING)
100 {
101 /* Does this service have any dependents? */
102 if (TV2_HasDependantServices(lpServiceStatus[i].lpServiceName))
103 {
104 /* recall this function with the dependent */
105 BuildListOfServicesToStop(lpServiceList, lpServiceStatus[i].lpServiceName);
106 }
107
108 /* Add the service to the list */
109 *lpServiceList = AddServiceToList(lpServiceList, lpServiceStatus[i].lpServiceName);
110
111 /* We've got one */
112 bRet = TRUE;
113 }
114 }
115
116 HeapFree(GetProcessHeap(),
117 0,
118 lpServiceStatus);
119 }
120
121 return bRet;
122 }
123
124 LPWSTR
125 GetListOfServicesToStop(LPWSTR lpServiceName)
126 {
127 LPWSTR lpServiceList = NULL;
128
129 /* Call recursive function to get our list */
130 if (BuildListOfServicesToStop(&lpServiceList, lpServiceName))
131 return lpServiceList;
132 else
133 return NULL;
134 }
135
136 static VOID
137 AddServiceNamesToStop(HWND hServiceListBox,
138 LPWSTR lpServiceList)
139 {
140 LPQUERY_SERVICE_CONFIG lpServiceConfig;
141 LPWSTR lpStr;
142
143 lpStr = lpServiceList;
144
145 /* Loop through all the services in the list */
146 while (TRUE)
147 {
148 /* Break when we hit the double null */
149 if (*lpStr == L'\0' && *(lpStr + 1) == L'\0')
150 break;
151
152 /* If this isn't our first time in the loop we'll
153 have been left on a null char */
154 if (*lpStr == L'\0')
155 lpStr++;
156
157 /* Get the service's display name */
158 lpServiceConfig = GetServiceConfig(lpStr);
159 if (lpServiceConfig)
160 {
161 /* Add the service to the listbox */
162 SendMessageW(hServiceListBox,
163 LB_ADDSTRING,
164 0,
165 (LPARAM)lpServiceConfig->lpDisplayName);
166 }
167
168 /* Move onto the next string */
169 while (*lpStr != L'\0')
170 lpStr++;
171 }
172 }
173
174 static BOOL
175 DoInitDependsDialog(PMAIN_WND_INFO pInfo,
176 HWND hDlg)
177 {
178 HWND hServiceListBox;
179 LPWSTR lpPartialStr, lpStr;
180 DWORD fullLen;
181 HICON hIcon = NULL;
182 BOOL bRet = FALSE;
183
184 if (pInfo)
185 {
186 /* Tag the info to the window */
187 SetWindowLongPtrW(hDlg,
188 GWLP_USERDATA,
189 (LONG_PTR)pInfo);
190
191 /* Load the icon for the window */
192 hIcon = (HICON)LoadImageW(hInstance,
193 MAKEINTRESOURCE(IDI_SM_ICON),
194 IMAGE_ICON,
195 GetSystemMetrics(SM_CXSMICON),
196 GetSystemMetrics(SM_CXSMICON),
197 0);
198 if (hIcon)
199 {
200 /* Set it */
201 SendMessageW(hDlg,
202 WM_SETICON,
203 ICON_SMALL,
204 (LPARAM)hIcon);
205 DestroyIcon(hIcon);
206 }
207
208 /* Load the stop depends note */
209 if (AllocAndLoadString(&lpPartialStr,
210 hInstance,
211 IDS_STOP_DEPENDS))
212 {
213 /* Get the length required */
214 fullLen = wcslen(lpPartialStr) + wcslen(pInfo->pCurrentService->lpDisplayName) + 1;
215
216 lpStr = HeapAlloc(ProcessHeap,
217 0,
218 fullLen * sizeof(WCHAR));
219 if (lpStr)
220 {
221 /* Add the service name to the depends note */
222 _snwprintf(lpStr,
223 fullLen,
224 lpPartialStr,
225 pInfo->pCurrentService->lpDisplayName);
226
227 /* Add the string to the dialog */
228 SendDlgItemMessageW(hDlg,
229 IDC_STOP_DEPENDS,
230 WM_SETTEXT,
231 0,
232 (LPARAM)lpStr);
233
234 HeapFree(ProcessHeap,
235 0,
236 lpStr);
237
238 bRet = TRUE;
239 }
240
241 LocalFree(lpPartialStr);
242 }
243
244 /* Display the list of services which need stopping */
245 hServiceListBox = GetDlgItem(hDlg,
246 IDC_STOP_DEPENDS_LB);
247 if (hServiceListBox)
248 {
249 AddServiceNamesToStop(hServiceListBox,
250 (LPWSTR)pInfo->pTag);
251 }
252 }
253
254 return bRet;
255 }
256
257 INT_PTR CALLBACK
258 StopDependsDialogProc(HWND hDlg,
259 UINT message,
260 WPARAM wParam,
261 LPARAM lParam)
262 {
263 PMAIN_WND_INFO pInfo = NULL;
264
265 /* Get the window context */
266 pInfo = (PMAIN_WND_INFO)GetWindowLongPtrW(hDlg,
267 GWLP_USERDATA);
268 if (pInfo == NULL && message != WM_INITDIALOG)
269 {
270 return FALSE;
271 }
272
273 switch (message)
274 {
275 case WM_INITDIALOG:
276 {
277 BOOL bRet = FALSE;
278
279 pInfo = (PMAIN_WND_INFO)lParam;
280 if (pInfo != NULL)
281 {
282 bRet = DoInitDependsDialog(pInfo, hDlg);
283 }
284
285 return bRet;
286 }
287
288 case WM_COMMAND:
289 {
290 switch (LOWORD(wParam))
291 {
292 case IDOK:
293 case IDCANCEL:
294 {
295 EndDialog(hDlg,
296 LOWORD(wParam));
297 return TRUE;
298 }
299 }
300 }
301 }
302
303 return FALSE;
304 }