1 /*
2  * PROJECT:     ReactOS Applications
3  * LICENSE:     LGPL - See COPYING in the top level directory
4  * FILE:        base/applications/msconfig/srvpage.c
5  * PURPOSE:     Services page message handler
6  * COPYRIGHT:   Copyright 2005-2006 Christoph von Wittich <Christoph@ApiViewer.de>
7  *
8  */
9 
10 #include "precomp.h"
11 
12 #include <winsvc.h>
13 #include <winver.h>
14 
15 HWND hServicesPage;
16 HWND hServicesListCtrl;
17 HWND hServicesDialog;
18 
19 void GetServices ( void );
20 
21 INT_PTR CALLBACK
22 ServicesPageWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
23 {
24     LV_COLUMN   column;
25     TCHAR       szTemp[256];
26     DWORD dwStyle;
27 
28     UNREFERENCED_PARAMETER(lParam);
29     UNREFERENCED_PARAMETER(wParam);
30 
31     switch (message) {
32     case WM_INITDIALOG:
33 
34         hServicesListCtrl = GetDlgItem(hDlg, IDC_SERVICES_LIST);
35         hServicesDialog = hDlg;
36 
37         dwStyle = (DWORD) SendMessage(hServicesListCtrl, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
38         dwStyle = dwStyle | LVS_EX_FULLROWSELECT | LVS_EX_CHECKBOXES;
39         SendMessage(hServicesListCtrl, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, dwStyle);
40 
41         SetWindowPos(hDlg, NULL, 10, 32, 0, 0, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_NOZORDER);
42 
43         // Initialize the application page's controls
44         column.mask = LVCF_TEXT | LVCF_WIDTH;
45 
46         LoadString(hInst, IDS_SERVICES_COLUMN_SERVICE, szTemp, 256);
47         column.pszText = szTemp;
48         column.cx = 200;
49         (void)ListView_InsertColumn(hServicesListCtrl, 0, &column);
50 
51         column.mask = LVCF_TEXT | LVCF_WIDTH;
52         LoadString(hInst, IDS_SERVICES_COLUMN_REQ, szTemp, 256);
53         column.pszText = szTemp;
54         column.cx = 70;
55         (void)ListView_InsertColumn(hServicesListCtrl, 1, &column);
56 
57         column.mask = LVCF_TEXT | LVCF_WIDTH;
58         LoadString(hInst, IDS_SERVICES_COLUMN_VENDOR, szTemp, 256);
59         column.pszText = szTemp;
60         column.cx = 200;
61         (void)ListView_InsertColumn(hServicesListCtrl, 2, &column);
62 
63         column.mask = LVCF_TEXT | LVCF_WIDTH;
64         LoadString(hInst, IDS_SERVICES_COLUMN_STATUS, szTemp, 256);
65         column.pszText = szTemp;
66         column.cx = 70;
67         (void)ListView_InsertColumn(hServicesListCtrl, 3, &column);
68 
69         GetServices();
70         return TRUE;
71     }
72 
73     return 0;
74 }
75 
76 void
77 GetServices ( void )
78 {
79     LV_ITEM item;
80     WORD wCodePage;
81     WORD wLangID;
82     SC_HANDLE ScHandle;
83     SC_HANDLE hService;
84     DWORD BytesNeeded = 0;
85     DWORD ResumeHandle = 0;
86     DWORD NumServices = 0;
87     DWORD dwHandle, dwLen;
88     size_t Index;
89     UINT BufLen;
90     TCHAR szStatus[128];
91     TCHAR* lpData;
92     TCHAR* lpBuffer;
93     TCHAR szStrFileInfo[80];
94     TCHAR FileName[MAX_PATH];
95     LPVOID pvData;
96 
97     LPSERVICE_FAILURE_ACTIONS pServiceFailureActions = NULL;
98     LPQUERY_SERVICE_CONFIG pServiceConfig = NULL;
99     ENUM_SERVICE_STATUS_PROCESS *pServiceStatus = NULL;
100 
101     ScHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);
102     if (ScHandle != NULL)
103     {
104         if (EnumServicesStatusEx(ScHandle, SC_ENUM_PROCESS_INFO, SERVICE_WIN32, SERVICE_STATE_ALL, (LPBYTE)pServiceStatus, 0, &BytesNeeded, &NumServices, &ResumeHandle, 0) == 0)
105         {
106             /* Call function again if required size was returned */
107             if (GetLastError() == ERROR_MORE_DATA)
108             {
109                 /* reserve memory for service info array */
110                 pServiceStatus = HeapAlloc(GetProcessHeap(), 0, BytesNeeded);
111                 if (!pServiceStatus)
112                 {
113                     CloseServiceHandle(ScHandle);
114                     return;
115                 }
116 
117                 /* fill array with service info */
118                 if (EnumServicesStatusEx(ScHandle, SC_ENUM_PROCESS_INFO, SERVICE_WIN32, SERVICE_STATE_ALL, (LPBYTE)pServiceStatus, BytesNeeded, &BytesNeeded, &NumServices, &ResumeHandle, 0) == 0)
119                 {
120                     HeapFree(GetProcessHeap(), 0, pServiceStatus);
121                     CloseServiceHandle(ScHandle);
122                     return;
123                 }
124             }
125             else /* exit on failure */
126             {
127                 CloseServiceHandle(ScHandle);
128                 return;
129             }
130         }
131 
132         if (NumServices)
133         {
134             if (!pServiceStatus)
135             {
136                 CloseServiceHandle(ScHandle);
137                 return;
138             }
139 
140             for (Index = 0; Index < NumServices; Index++)
141             {
142                 memset(&item, 0, sizeof(LV_ITEM));
143                 item.mask = LVIF_TEXT;
144                 item.iImage = 0;
145                 item.pszText = pServiceStatus[Index].lpDisplayName;
146                 item.iItem = ListView_GetItemCount(hServicesListCtrl);
147                 item.lParam = 0;
148                 item.iItem = ListView_InsertItem(hServicesListCtrl, &item);
149 
150                 if (pServiceStatus[Index].ServiceStatusProcess.dwCurrentState == SERVICE_RUNNING)
151                 {
152                     ListView_SetCheckState(hServicesListCtrl, item.iItem, TRUE);
153                 }
154 
155                 BytesNeeded = 0;
156                 hService = OpenService(ScHandle, pServiceStatus[Index].lpServiceName, SC_MANAGER_CONNECT);
157                 if (hService != NULL)
158                 {
159                     /* check if service is required by the system*/
160                     if (!QueryServiceConfig2(hService, SERVICE_CONFIG_FAILURE_ACTIONS, (LPBYTE)NULL, 0, &BytesNeeded))
161                     {
162                         if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
163                         {
164                             pServiceFailureActions = HeapAlloc(GetProcessHeap(), 0, BytesNeeded);
165                             if (pServiceFailureActions == NULL)
166                             {
167                                 HeapFree(GetProcessHeap(), 0, pServiceStatus);
168                                 CloseServiceHandle(hService);
169                                 CloseServiceHandle(ScHandle);
170                                 return;
171                             }
172 
173                             if (!QueryServiceConfig2(hService, SERVICE_CONFIG_FAILURE_ACTIONS, (LPBYTE)pServiceFailureActions, BytesNeeded, &BytesNeeded))
174                             {
175                                 HeapFree(GetProcessHeap(), 0, pServiceFailureActions);
176                                 HeapFree(GetProcessHeap(), 0, pServiceStatus);
177                                 CloseServiceHandle(hService);
178                                 CloseServiceHandle(ScHandle);
179                                 return;
180                             }
181                         }
182                         else /* exit on failure */
183                         {
184                             HeapFree(GetProcessHeap(), 0, pServiceStatus);
185                             CloseServiceHandle(hService);
186                             CloseServiceHandle(ScHandle);
187                             return;
188                         }
189                     }
190 
191                     if (pServiceFailureActions != NULL)
192                     {
193                         if (pServiceFailureActions->cActions && pServiceFailureActions->lpsaActions[0].Type == SC_ACTION_REBOOT)
194                         {
195                                 LoadString(hInst, IDS_SERVICES_YES, szStatus, 128);
196                                 item.pszText = szStatus;
197                                 item.iSubItem = 1;
198                                 SendMessage(hServicesListCtrl, LVM_SETITEMTEXT, item.iItem, (LPARAM) &item);
199                         }
200                         HeapFree(GetProcessHeap(), 0, pServiceFailureActions);
201                         pServiceFailureActions = NULL;
202                     }
203 
204                     /* get vendor of service binary */
205                     BytesNeeded = 0;
206                     if (!QueryServiceConfig(hService, NULL, 0, &BytesNeeded))
207                     {
208                         if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
209                         {
210                             pServiceConfig = HeapAlloc(GetProcessHeap(), 0, BytesNeeded);
211                             if (pServiceConfig == NULL)
212                             {
213                                 HeapFree(GetProcessHeap(), 0, pServiceStatus);
214                                 CloseServiceHandle(hService);
215                                 CloseServiceHandle(ScHandle);
216                                 return;
217                             }
218                             if (!QueryServiceConfig(hService, pServiceConfig, BytesNeeded, &BytesNeeded))
219                             {
220                                 HeapFree(GetProcessHeap(), 0, pServiceConfig);
221                                 HeapFree(GetProcessHeap(), 0, pServiceStatus);
222                                 CloseServiceHandle(hService);
223                                 CloseServiceHandle(ScHandle);
224                                 return;
225                             }
226                         }
227                         else /* exit on failure */
228                         {
229                             HeapFree(GetProcessHeap(), 0, pServiceStatus);
230                             CloseServiceHandle(hService);
231                             CloseServiceHandle(ScHandle);
232                             return;
233                         }
234                     }
235 
236                     if (pServiceConfig->lpBinaryPathName[0] != _T('"'))
237                     {
238                         /* Assume everything before the first space is the binary path */
239                         /* FIXME: This is a reasonable heuristic but some
240                          *        services use unquoted paths with spaces */
241                         StringCchCopyN(FileName,
242                                        _countof(FileName),
243                                        pServiceConfig->lpBinaryPathName,
244                                        _tcscspn(pServiceConfig->lpBinaryPathName, _T(" ")));
245                     }
246                     else
247                     {
248                         /* Binary path is inside the quotes */
249                         StringCchCopyN(FileName,
250                                        _countof(FileName),
251                                        pServiceConfig->lpBinaryPathName + 1,
252                                        _tcscspn(pServiceConfig->lpBinaryPathName + 1, _T("\"")));
253                     }
254 
255                     HeapFree(GetProcessHeap(), 0, pServiceConfig);
256                     pServiceConfig = NULL;
257 
258                     dwLen = GetFileVersionInfoSize(FileName, &dwHandle);
259                     if (dwLen)
260                     {
261                         lpData = HeapAlloc(GetProcessHeap(), 0, dwLen);
262                         if (lpData == NULL)
263                         {
264                             HeapFree(GetProcessHeap(), 0, pServiceStatus);
265                             CloseServiceHandle(hService);
266                             CloseServiceHandle(ScHandle);
267                             return;
268                         }
269                         if (!GetFileVersionInfo (FileName, dwHandle, dwLen, lpData))
270                         {
271                             HeapFree(GetProcessHeap(), 0, lpData);
272                             HeapFree(GetProcessHeap(), 0, pServiceStatus);
273                             CloseServiceHandle(hService);
274                             CloseServiceHandle(ScHandle);
275                             return;
276                         }
277 
278                         if (VerQueryValue(lpData, _T("\\VarFileInfo\\Translation"), &pvData, (PUINT) &BufLen))
279                         {
280                             wCodePage = LOWORD(*(DWORD*) pvData);
281                             wLangID = HIWORD(*(DWORD*) pvData);
282                             wsprintf(szStrFileInfo, _T("StringFileInfo\\%04X%04X\\CompanyName"), wCodePage, wLangID);
283                         }
284 
285                         if (VerQueryValue (lpData, szStrFileInfo, (void**) &lpBuffer, (PUINT) &BufLen))
286                         {
287                             item.pszText = lpBuffer;
288                             item.iSubItem = 2;
289                             SendMessage(hServicesListCtrl, LVM_SETITEMTEXT, item.iItem, (LPARAM) &item);
290                         }
291                         HeapFree(GetProcessHeap(), 0, lpData);
292                     }
293                     else
294                     {
295                         LoadString(hInst, IDS_SERVICES_UNKNOWN, szStatus, 128);
296                         item.pszText = szStatus;
297                         item.iSubItem = 2;
298                         SendMessage(hServicesListCtrl, LVM_SETITEMTEXT, item.iItem, (LPARAM) &item);
299                     }
300                     CloseServiceHandle(hService);
301                 }
302 
303                 LoadString(hInst, ((pServiceStatus[Index].ServiceStatusProcess.dwCurrentState == SERVICE_STOPPED) ? IDS_SERVICES_STATUS_STOPPED : IDS_SERVICES_STATUS_RUNNING), szStatus, 128);
304                 item.pszText = szStatus;
305                 item.iSubItem = 3;
306                 SendMessage(hServicesListCtrl, LVM_SETITEMTEXT, item.iItem, (LPARAM) &item);
307 
308             }
309         }
310 
311         HeapFree(GetProcessHeap(), 0, pServiceStatus);
312         CloseServiceHandle(ScHandle);
313     }
314 
315 }
316