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-2015 Ged Murphy <gedmurphy@reactos.org>
7  *
8  */
9 
10 #include "precomp.h"
11 
12 typedef struct _STOP_DATA
13 {
14     LPWSTR ServiceName;
15     LPWSTR DisplayName;
16     LPWSTR ServiceList;
17 
18 } STOP_DATA, *PSTOP_DATA;
19 
20 static LPWSTR
21 AddServiceToList(LPWSTR *lpServiceList,
22                  LPWSTR lpServiceToAdd)
23 {
24     LPWSTR lpNewList = NULL;
25     LPWSTR ptr;
26     DWORD dwToAddSize;
27     DWORD dwCurSize;
28 
29     dwToAddSize = wcslen(lpServiceToAdd) + 1;
30 
31     /* Is this is the first in the list? */
32     if (!*lpServiceList)
33     {
34         /* Add another char for double null */
35         dwToAddSize++;
36 
37         lpNewList = HeapAlloc(GetProcessHeap(),
38                               0,
39                               dwToAddSize * sizeof(WCHAR));
40         if (lpNewList)
41         {
42             /* Copy the service name */
43             StringCchCopy(lpNewList,
44                           dwToAddSize,
45                           lpServiceToAdd);
46 
47             /* Add the double null char */
48             lpNewList[dwToAddSize - 1] = L'\0';
49         }
50     }
51     else
52     {
53         ptr = *lpServiceList;
54         dwCurSize = 0;
55 
56         /* Get the list size */
57         for (;;)
58         {
59             /* Break when we hit the double null */
60             if (*ptr == L'\0' && *(ptr + 1) == L'\0')
61                 break;
62 
63             ptr++;
64             dwCurSize++;
65         }
66         dwCurSize++;
67 
68         /* Add another char for double null */
69         dwCurSize++;
70 
71         /* Extend the list size */
72         lpNewList = HeapReAlloc(GetProcessHeap(),
73                                 0,
74                                 *lpServiceList,
75                                 (dwCurSize + dwToAddSize) * sizeof(WCHAR));
76         if (lpNewList)
77         {
78             /* Copy the service name */
79             StringCchCopy(&lpNewList[dwCurSize - 1],
80                           dwToAddSize,
81                           lpServiceToAdd);
82 
83             /* Add the double null char */
84             lpNewList[dwCurSize + dwToAddSize - 1] = L'\0';
85         }
86     }
87 
88     return lpNewList;
89 }
90 
91 static BOOL
92 BuildListOfServicesToStop(LPWSTR *lpServiceList,
93                           LPWSTR lpServiceName)
94 {
95     LPENUM_SERVICE_STATUS lpServiceStatus;
96     DWORD dwCount, i;
97     BOOL bRet = FALSE;
98 
99     /* Get a list of service dependents */
100     lpServiceStatus = TV2_GetDependants(lpServiceName, &dwCount);
101     if (lpServiceStatus)
102     {
103         for (i = 0; i < dwCount; i++)
104         {
105             /* Does this service need stopping? */
106             if (lpServiceStatus[i].ServiceStatus.dwCurrentState != SERVICE_STOPPED &&
107                 lpServiceStatus[i].ServiceStatus.dwCurrentState != SERVICE_STOP_PENDING)
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 static VOID
138 AddServiceNamesToStop(HWND hServiceListBox,
139                       LPWSTR lpServiceList)
140 {
141     LPQUERY_SERVICE_CONFIG lpServiceConfig;
142     LPWSTR lpStr;
143 
144     lpStr = lpServiceList;
145 
146     /* Loop through all the services in the list */
147     for (;;)
148     {
149         /* Break when we hit the double null */
150         if (*lpStr == L'\0' && *(lpStr + 1) == L'\0')
151             break;
152 
153         /* If this isn't our first time in the loop we'll
154            have been left on a null char */
155         if (*lpStr == L'\0')
156             lpStr++;
157 
158         /* Get the service's display name */
159         lpServiceConfig = GetServiceConfig(lpStr);
160         if (lpServiceConfig)
161         {
162             /* Add the service to the listbox */
163             SendMessageW(hServiceListBox,
164                          LB_ADDSTRING,
165                          0,
166                          (LPARAM)lpServiceConfig->lpDisplayName);
167 
168             HeapFree(GetProcessHeap(), 0, lpServiceConfig);
169         }
170 
171         /* Move onto the next string */
172         while (*lpStr != L'\0')
173             lpStr++;
174     }
175 }
176 
177 static BOOL
178 InitDialog(HWND hDlg,
179            UINT Message,
180            WPARAM wParam,
181            LPARAM lParam)
182 {
183     PSTOP_DATA StopData;
184     HWND hServiceListBox;
185     LPWSTR lpPartialStr, lpStr;
186     DWORD fullLen;
187     HICON hIcon = NULL;
188     BOOL bRet = FALSE;
189 
190     StopData = (PSTOP_DATA)lParam;
191 
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(StopData->DisplayName) + 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                         StopData->DisplayName);
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         LocalFree(lpPartialStr);
244     }
245 
246     /* Display the list of services which need stopping */
247     hServiceListBox = GetDlgItem(hDlg, IDC_STOP_DEPENDS_LB);
248     if (hServiceListBox)
249     {
250         AddServiceNamesToStop(hServiceListBox,
251                               (LPWSTR)StopData->ServiceList);
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 
264     switch (Message)
265     {
266         case WM_INITDIALOG:
267         {
268             return InitDialog(hDlg,
269                               Message,
270                               wParam,
271                               lParam);
272         }
273 
274         case WM_COMMAND:
275         {
276             switch (LOWORD(wParam))
277             {
278                 case IDOK:
279                 case IDCANCEL:
280                 {
281                     EndDialog(hDlg,
282                               LOWORD(wParam));
283                     return TRUE;
284                 }
285             }
286         }
287     }
288 
289     return FALSE;
290 }
291 
292 BOOL
293 CreateStopDependsDialog(HWND hParent,
294                         LPWSTR ServiceName,
295                         LPWSTR DisplayName,
296                         LPWSTR ServiceList)
297 {
298     STOP_DATA StopData;
299     INT_PTR Result;
300 
301     StopData.ServiceName = ServiceName;
302     StopData.DisplayName = DisplayName;
303     StopData.ServiceList = ServiceList;
304 
305     Result = DialogBoxParamW(hInstance,
306                              MAKEINTRESOURCEW(IDD_DLG_DEPEND_STOP),
307                              hParent,
308                              StopDependsDialogProc,
309                              (LPARAM)&StopData);
310     if (Result == IDOK)
311         return TRUE;
312 
313     return FALSE;
314 }
315