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