]> granicus.if.org Git - apache/blob - support/win32/ApacheMonitor.c
More splitting as suggested by minfrin.
[apache] / support / win32 / ApacheMonitor.c
1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /* ====================================================================
18  * ApacheMonitor.c Simple program to manage and monitor Apache services.
19  *
20  * Contributed by Mladen Turk <mturk mappingsoft.com>
21  *
22  * 05 Aug 2001
23  * ====================================================================
24  */
25
26 #define _WIN32_WINNT 0x0500
27 #ifndef STRICT
28 #define STRICT
29 #endif
30 #ifndef OEMRESOURCE
31 #define OEMRESOURCE
32 #endif
33
34 #if defined(_MSC_VER) && _MSC_VER >= 1400
35 #define _CRT_SECURE_NO_DEPRECATE
36 #endif
37
38 #include <windows.h>
39 #include <windowsx.h>
40 #include <commctrl.h>
41 #include <objbase.h>
42 #include <shlobj.h>
43 #include <stdlib.h>
44 #include <stdio.h>
45 #include <WtsApi32.h>
46 #include <tchar.h>
47 #include "ApacheMonitor.h"
48
49 #ifndef AM_STRINGIFY
50 /** Properly quote a value as a string in the C preprocessor */
51 #define AM_STRINGIFY(n) AM_STRINGIFY_HELPER(n)
52 /** Helper macro for AM_STRINGIFY */
53 #define AM_STRINGIFY_HELPER(n) #n
54 #endif
55
56 #define OS_VERSION_WINNT    2
57 #define OS_VERSION_WIN2K    3
58
59 /* Should be enough */
60 #define MAX_APACHE_SERVICES 128
61 #define MAX_APACHE_COMPUTERS 32
62
63 #define WM_TRAYMESSAGE         (WM_APP+1)
64 #define WM_UPDATEMESSAGE       (WM_USER+1)
65 #define WM_MANAGEMESSAGE       (WM_USER+2)
66 #define WM_TIMER_REFRESH       10
67 #define WM_TIMER_RESCAN        11
68 #define SERVICE_APACHE_RESTART 128
69 #define XBITMAP                16
70 #define YBITMAP                16
71 #define MAX_LOADSTRING         100
72 #define REFRESH_TIME           2000           /* service refresh time (ms) */
73 #define RESCAN_TIME            20000          /* registry rescan time (ms) */
74
75 typedef struct _st_APACHE_SERVICE
76 {
77     LPTSTR   szServiceName;
78     LPTSTR   szDisplayName;
79     LPTSTR   szDescription;
80     LPTSTR   szImagePath;
81     LPTSTR   szComputerName;
82     DWORD    dwPid;
83 } ST_APACHE_SERVICE;
84
85 typedef struct _st_MONITORED_COMPUTERS
86 {
87     LPTSTR  szComputerName;
88     HKEY    hRegistry;
89 } ST_MONITORED_COMP;
90
91 /* Global variables */
92 HINSTANCE         g_hInstance = NULL;
93 TCHAR            *g_szTitle;          /* The title bar text */
94 TCHAR            *g_szWindowClass;    /* Window Class Name  */
95 HICON             g_icoStop;
96 HICON             g_icoRun;
97 UINT              g_bUiTaskbarCreated;
98 DWORD             g_dwOSVersion;
99 BOOL              g_bDlgServiceOn = FALSE;
100 BOOL              g_bConsoleRun = FALSE;
101 ST_APACHE_SERVICE g_stServices[MAX_APACHE_SERVICES];
102 ST_MONITORED_COMP g_stComputers[MAX_APACHE_COMPUTERS];
103
104 HBITMAP           g_hBmpStart, g_hBmpStop;
105 HBITMAP           g_hBmpPicture, g_hBmpOld;
106 BOOL              g_bRescanServices;
107 HWND              g_hwndServiceDlg;
108 HWND              g_hwndMain;
109 HWND              g_hwndStdoutList;
110 HWND              g_hwndConnectDlg;
111 HCURSOR           g_hCursorHourglass;
112 HCURSOR           g_hCursorArrow;
113
114 LANGID            g_LangID;
115 CRITICAL_SECTION  g_stcSection;
116 LPTSTR            g_szLocalHost;
117
118 /* locale language support */
119 static TCHAR *g_lpMsg[IDS_MSG_LAST - IDS_MSG_FIRST + 1];
120
121
122 void am_ClearServicesSt()
123 {
124     int i;
125     for (i = 0; i < MAX_APACHE_SERVICES; i++)
126     {
127         if (g_stServices[i].szServiceName) {
128             free(g_stServices[i].szServiceName);
129         }
130         if (g_stServices[i].szDisplayName) {
131             free(g_stServices[i].szDisplayName);
132         }
133         if (g_stServices[i].szDescription) {
134             free(g_stServices[i].szDescription);
135         }
136         if (g_stServices[i].szImagePath) {
137             free(g_stServices[i].szImagePath);
138         }
139         if (g_stServices[i].szComputerName) {
140             free(g_stServices[i].szComputerName);
141         }
142
143     }
144     memset(g_stServices, 0, sizeof(ST_APACHE_SERVICE) * MAX_APACHE_SERVICES);
145
146 }
147
148
149 void am_ClearComputersSt()
150 {
151     int i;
152     for (i = 0; i < MAX_APACHE_COMPUTERS; i++) {
153         if (g_stComputers[i].szComputerName) {
154             free(g_stComputers[i].szComputerName);
155             RegCloseKey(g_stComputers[i].hRegistry);
156         }
157     }
158     memset(g_stComputers, 0, sizeof(ST_MONITORED_COMP) * MAX_APACHE_COMPUTERS);
159
160 }
161
162
163 BOOL am_IsComputerConnected(LPTSTR szComputerName)
164 {
165     int i = 0;
166     while (g_stComputers[i].szComputerName != NULL) {
167         if (_tcscmp(g_stComputers[i].szComputerName, szComputerName) == 0) {
168             return TRUE;
169         }
170         ++i;
171     }
172     return FALSE;
173 }
174
175
176 void am_DisconnectComputer(LPTSTR szComputerName)
177 {
178     int i = 0, j;
179     while (g_stComputers[i].szComputerName != NULL) {
180         if (_tcscmp(g_stComputers[i].szComputerName, szComputerName) == 0) {
181             break;
182         }
183         ++i;
184     }
185     if (g_stComputers[i].szComputerName != NULL) {
186         free(g_stComputers[i].szComputerName);
187         RegCloseKey(g_stComputers[i].hRegistry);
188         for (j = i; j < MAX_APACHE_COMPUTERS - 1; j++) {
189             g_stComputers[j].szComputerName= g_stComputers[j+1].szComputerName;
190             g_stComputers[j].hRegistry = g_stComputers[j+1].hRegistry;
191         }
192         g_stComputers[j].szComputerName = NULL;
193         g_stComputers[j].hRegistry = NULL;
194     }
195 }
196
197
198 void ErrorMessage(LPCTSTR szError, BOOL bFatal)
199 {
200     LPVOID lpMsgBuf = NULL;
201     if (szError) {
202         MessageBox(NULL, szError, g_lpMsg[IDS_MSG_ERROR - IDS_MSG_FIRST],
203                    MB_OK | (bFatal ? MB_ICONERROR : MB_ICONEXCLAMATION));
204     }
205     else {
206         FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
207                       FORMAT_MESSAGE_FROM_SYSTEM |
208                       FORMAT_MESSAGE_IGNORE_INSERTS,
209                       NULL, GetLastError(), g_LangID,
210                       (LPTSTR) &lpMsgBuf, 0, NULL);
211         MessageBox(NULL, (LPCTSTR)lpMsgBuf,
212                    g_lpMsg[IDS_MSG_ERROR - IDS_MSG_FIRST],
213                    MB_OK | (bFatal ? MB_ICONERROR : MB_ICONEXCLAMATION));
214         LocalFree(lpMsgBuf);
215     }
216     if (bFatal) {
217         PostQuitMessage(0);
218     }
219 }
220
221
222 int am_RespawnAsUserAdmin(HWND hwnd, DWORD op, LPCTSTR szService, 
223                           LPCTSTR szComputerName)
224 {
225     TCHAR args[MAX_PATH + MAX_COMPUTERNAME_LENGTH + 12];
226
227     if (g_dwOSVersion < OS_VERSION_WIN2K) {
228         ErrorMessage(g_lpMsg[IDS_MSG_SRVFAILED - IDS_MSG_FIRST], FALSE);
229         return 0;
230     }
231
232     _sntprintf(args, sizeof(args) / sizeof(TCHAR), 
233                _T("%d \"%s\" \"%s\""), op, szService,
234                szComputerName ? szComputerName : _T(""));
235     if (!ShellExecute(hwnd, _T("runas"), __targv[0], args, NULL, SW_NORMAL)) {
236         ErrorMessage(g_lpMsg[IDS_MSG_SRVFAILED - IDS_MSG_FIRST],
237                      FALSE);
238         return 0;
239     }
240
241     return 1;
242 }
243
244
245 BOOL am_ConnectComputer(LPTSTR szComputerName)
246 {
247     int i = 0;
248     HKEY hKeyRemote;
249     TCHAR szTmp[MAX_PATH];
250
251     while (g_stComputers[i].szComputerName != NULL) {
252         if (_tcscmp(g_stComputers[i].szComputerName, szComputerName) == 0) {
253             return FALSE;
254         }
255         ++i;
256     }
257     if (i > MAX_APACHE_COMPUTERS - 1) {
258         return FALSE;
259     }
260     if (RegConnectRegistry(szComputerName, HKEY_LOCAL_MACHINE, &hKeyRemote)
261             != ERROR_SUCCESS) {
262         _sntprintf(szTmp, sizeof(szTmp) / sizeof(TCHAR), 
263                    g_lpMsg[IDS_MSG_ECONNECT - IDS_MSG_FIRST],
264                    szComputerName);
265         ErrorMessage(szTmp, FALSE);
266         return FALSE;
267     }
268     else {
269         g_stComputers[i].szComputerName = _tcsdup(szComputerName);
270         g_stComputers[i].hRegistry = hKeyRemote;
271         return TRUE;
272     }
273 }
274
275
276 LPTSTR GetStringRes(int id)
277 {
278     static TCHAR buffer[MAX_PATH];
279
280     buffer[0] = 0;
281     LoadString(GetModuleHandle(NULL), id, buffer, MAX_PATH);
282     return buffer;
283 }
284
285
286 BOOL GetSystemOSVersion(LPDWORD dwVersion)
287 {
288     OSVERSIONINFO osvi;
289     /*
290     Try calling GetVersionEx using the OSVERSIONINFOEX structure.
291     If that fails, try using the OSVERSIONINFO structure.
292     */
293     memset(&osvi, 0, sizeof(OSVERSIONINFO));
294     osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
295
296     if (!GetVersionEx(&osvi)) {
297         return FALSE;
298     }
299
300     switch (osvi.dwPlatformId)
301     {
302     case VER_PLATFORM_WIN32_NT:
303         if (osvi.dwMajorVersion >= 5)
304             *dwVersion = OS_VERSION_WIN2K;
305         else
306             *dwVersion = OS_VERSION_WINNT;            
307         break;
308
309     case VER_PLATFORM_WIN32_WINDOWS:
310     case VER_PLATFORM_WIN32s:
311     default:
312         *dwVersion = 0;
313         return FALSE;
314     }
315     return TRUE;
316 }
317
318
319 static VOID ShowNotifyIcon(HWND hWnd, DWORD dwMessage)
320 {
321     NOTIFYICONDATA nid;
322     int i = 0, n = 0;
323
324     memset(&nid, 0, sizeof(nid));
325     nid.cbSize = sizeof(NOTIFYICONDATA);
326     nid.hWnd = hWnd;
327     nid.uID = 0xFF;
328     nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
329     nid.uCallbackMessage = WM_TRAYMESSAGE;
330
331     while (g_stServices[i].szServiceName != NULL)
332     {
333         if (g_stServices[i].dwPid != 0) {
334             ++n;
335         }
336         ++i;
337     }
338     if (dwMessage != NIM_DELETE)
339     {
340         if (n) {
341             nid.hIcon = g_icoRun;
342         }
343         else {
344             nid.hIcon = g_icoStop;
345         }
346     }
347     else {
348         nid.hIcon = NULL;
349     }
350     if (n == i && n > 0) {
351         _tcscpy(nid.szTip, g_lpMsg[IDS_MSG_RUNNINGALL - IDS_MSG_FIRST]);
352     }
353     else if (n) {
354         _sntprintf(nid.szTip, sizeof(nid.szTip) / sizeof(TCHAR), 
355                   g_lpMsg[IDS_MSG_RUNNING - IDS_MSG_FIRST], n, i);
356     }
357     else if (i) {
358         _sntprintf(nid.szTip, sizeof(nid.szTip) / sizeof(TCHAR), 
359                   g_lpMsg[IDS_MSG_RUNNINGNONE - IDS_MSG_FIRST], i);
360     }
361     else {
362         _tcscpy(nid.szTip, g_lpMsg[IDS_MSG_NOSERVICES - IDS_MSG_FIRST]);
363     }
364     Shell_NotifyIcon(dwMessage, &nid);
365 }
366
367
368 void appendMenuItem(HMENU hMenu, UINT uMenuId, LPTSTR szName,
369                     BOOL fDefault, BOOL fEnabled)
370 {
371     MENUITEMINFO mii;
372
373     memset(&mii, 0, sizeof(MENUITEMINFO));
374     mii.cbSize = sizeof(MENUITEMINFO);
375     mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE;
376     if (_tcslen(szName))
377     {
378         mii.fType = MFT_STRING;
379         mii.wID = uMenuId;
380         if (fDefault) {
381             mii.fState = MFS_DEFAULT;
382         }
383         if (!fEnabled) {
384             mii.fState |= MFS_DISABLED;
385         }
386         mii.dwTypeData = szName;
387     }
388     else {
389         mii.fType = MFT_SEPARATOR;
390     }
391     InsertMenuItem(hMenu, uMenuId, FALSE, &mii);
392 }
393
394
395 void appendServiceMenu(HMENU hMenu, UINT uMenuId,
396                        LPTSTR szServiceName, BOOL fRunning)
397 {
398     MENUITEMINFO mii;
399     HMENU smh;
400
401     smh = CreatePopupMenu();
402
403     appendMenuItem(smh, IDM_SM_START + uMenuId,
404                    g_lpMsg[IDS_MSG_SSTART - IDS_MSG_FIRST], FALSE, !fRunning);
405     appendMenuItem(smh, IDM_SM_STOP + uMenuId,
406                    g_lpMsg[IDS_MSG_SSTOP - IDS_MSG_FIRST], FALSE, fRunning);
407     appendMenuItem(smh, IDM_SM_RESTART + uMenuId,
408                    g_lpMsg[IDS_MSG_SRESTART - IDS_MSG_FIRST], FALSE, fRunning);
409
410     memset(&mii, 0, sizeof(MENUITEMINFO));
411     mii.cbSize = sizeof(MENUITEMINFO);
412     mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE | MIIM_SUBMENU
413               | MIIM_CHECKMARKS;
414     mii.fType = MFT_STRING;
415     mii.wID = uMenuId;
416     mii.hbmpChecked = g_hBmpStart;
417     mii.hbmpUnchecked = g_hBmpStop;
418     mii.dwTypeData = szServiceName;
419     mii.hSubMenu = smh;
420     mii.fState = fRunning ? MFS_CHECKED : MFS_UNCHECKED;
421     InsertMenuItem(hMenu, IDM_SM_SERVICE + uMenuId, FALSE, &mii);
422 }
423
424
425 void ShowTryPopupMenu(HWND hWnd)
426 {
427     /* create popup menu */
428     HMENU hMenu = CreatePopupMenu();
429     POINT pt;
430
431     if (hMenu)
432     {
433         appendMenuItem(hMenu, IDM_RESTORE,
434                        g_lpMsg[IDS_MSG_MNUSHOW - IDS_MSG_FIRST],
435                        TRUE, TRUE);
436         appendMenuItem(hMenu, IDC_SMANAGER,
437                        g_lpMsg[IDS_MSG_MNUSERVICES - IDS_MSG_FIRST],
438                        FALSE, TRUE);
439         appendMenuItem(hMenu, 0, _T(""), FALSE, TRUE);
440         appendMenuItem(hMenu, IDM_EXIT,
441                        g_lpMsg[IDS_MSG_MNUEXIT - IDS_MSG_FIRST],
442                        FALSE, TRUE);
443
444         if (!SetForegroundWindow(hWnd)) {
445             SetForegroundWindow(NULL);
446         }
447         GetCursorPos(&pt);
448         TrackPopupMenu(hMenu, TPM_LEFTALIGN|TPM_RIGHTBUTTON,
449                        pt.x, pt.y, 0, hWnd, NULL);
450         DestroyMenu(hMenu);
451     }
452 }
453
454
455 void ShowTryServicesMenu(HWND hWnd)
456 {
457     /* create services list popup menu and submenus */
458     HMENU hMenu = CreatePopupMenu();
459     POINT pt;
460     int i = 0;
461
462     if (hMenu)
463     {
464         while (g_stServices[i].szServiceName != NULL)
465         {
466             appendServiceMenu(hMenu, i, g_stServices[i].szDisplayName,
467                               g_stServices[i].dwPid != 0);
468             ++i;
469         }
470         if (i)
471         {
472             if (!SetForegroundWindow(hWnd)) {
473                 SetForegroundWindow(NULL);
474             }
475             GetCursorPos(&pt);
476             TrackPopupMenu(hMenu, TPM_LEFTALIGN|TPM_RIGHTBUTTON,
477                            pt.x, pt.y, 0, hWnd, NULL);
478             DestroyMenu(hMenu);
479         }
480     }
481 }
482
483
484 BOOL CenterWindow(HWND hwndChild)
485 {
486    RECT rChild, rWorkArea;
487    int wChild, hChild;
488    int xNew, yNew;
489    BOOL bResult;
490
491    /* Get the Height and Width of the child window */
492    GetWindowRect(hwndChild, &rChild);
493    wChild = rChild.right - rChild.left;
494    hChild = rChild.bottom - rChild.top;
495
496    /* Get the limits of the 'workarea' */
497    bResult = SystemParametersInfo(SPI_GETWORKAREA, sizeof(RECT),
498                                   &rWorkArea, 0);
499    if (!bResult) {
500       rWorkArea.left = rWorkArea.top = 0;
501       rWorkArea.right = GetSystemMetrics(SM_CXSCREEN);
502       rWorkArea.bottom = GetSystemMetrics(SM_CYSCREEN);
503    }
504
505    /* Calculate new X and Y position*/
506    xNew = (rWorkArea.right - wChild) / 2;
507    yNew = (rWorkArea.bottom - hChild) / 2;
508    return SetWindowPos(hwndChild, HWND_TOP, xNew, yNew, 0, 0,
509                        SWP_NOSIZE | SWP_SHOWWINDOW);
510 }
511
512
513 static void addListBoxItem(HWND hDlg, LPTSTR lpStr, HBITMAP hBmp)
514 {
515     LRESULT nItem;
516
517     nItem = SendMessage(hDlg, LB_ADDSTRING, 0, (LPARAM)lpStr);
518     SendMessage(hDlg, LB_SETITEMDATA, nItem, (LPARAM)hBmp);
519 }
520
521
522 static void addListBoxString(HWND hListBox, LPTSTR lpStr)
523 {
524     static int nItems = 0;
525     if (!g_bDlgServiceOn) {
526         return;
527     }
528     ++nItems;
529     if (nItems > MAX_LOADSTRING)
530     {
531         SendMessage(hListBox, LB_RESETCONTENT, 0, 0);
532         nItems = 1;
533     }
534     ListBox_SetCurSel(hListBox,
535                       ListBox_AddString(hListBox, lpStr));
536
537 }
538
539
540 BOOL ApacheManageService(LPCTSTR szServiceName, LPCTSTR szImagePath,
541                          LPTSTR szComputerName, DWORD dwCommand)
542 {
543     TCHAR szMsg[MAX_PATH];
544     BOOL retValue;
545     BOOL serviceFlag = TRUE;
546     SC_HANDLE schService;
547     SC_HANDLE schSCManager;
548     SERVICE_STATUS schSStatus;
549     int ticks;
550
551     schSCManager = OpenSCManager(szComputerName, NULL,
552                                  SC_MANAGER_CONNECT);
553     if (!schSCManager) {
554         ErrorMessage(g_lpMsg[IDS_MSG_SRVFAILED - IDS_MSG_FIRST],
555                      FALSE);
556         return FALSE;
557     }
558
559     schService = OpenService(schSCManager, szServiceName,
560                              SERVICE_QUERY_STATUS | SERVICE_START |
561                              SERVICE_STOP | SERVICE_USER_DEFINED_CONTROL);
562     if (schService == NULL)
563     {
564         /* Avoid recursion of ImagePath NULL (from this Respawn) */
565         if (szImagePath) {
566             am_RespawnAsUserAdmin(g_hwndMain, dwCommand, 
567                                   szServiceName, szComputerName);
568         }
569         else {
570             ErrorMessage(g_lpMsg[IDS_MSG_SRVFAILED - IDS_MSG_FIRST],
571                          FALSE);
572         }
573         CloseServiceHandle(schSCManager);
574         return FALSE;
575     }
576     else
577     {
578         retValue = FALSE;
579         g_bConsoleRun = TRUE;
580         SetCursor(g_hCursorHourglass);
581         switch (dwCommand)
582         {
583           case SERVICE_CONTROL_STOP:
584             _sntprintf(szMsg, sizeof(szMsg) / sizeof(TCHAR), 
585                        g_lpMsg[IDS_MSG_SRVSTOP - IDS_MSG_FIRST],
586                        szServiceName);
587             addListBoxString(g_hwndStdoutList, szMsg);
588             if (ControlService(schService, SERVICE_CONTROL_STOP,
589                                &schSStatus)) {
590                 Sleep(1000);
591                 while (QueryServiceStatus(schService, &schSStatus))
592                 {
593                     if (schSStatus.dwCurrentState == SERVICE_STOP_PENDING)
594                     {
595                         Sleep(1000);
596                     }
597                     else {
598                         break;
599                     }
600                 }
601             }
602             if (QueryServiceStatus(schService, &schSStatus))
603             {
604                 if (schSStatus.dwCurrentState == SERVICE_STOPPED)
605                 {
606                     retValue = TRUE;
607                     _sntprintf(szMsg, sizeof(szMsg) / sizeof(TCHAR), 
608                                g_lpMsg[IDS_MSG_SRVSTOPPED - IDS_MSG_FIRST],
609                                szServiceName);
610                     addListBoxString(g_hwndStdoutList, szMsg);
611                 }
612             }
613             break;
614
615           case SERVICE_CONTROL_CONTINUE:
616             _sntprintf(szMsg, sizeof(szMsg) / sizeof(TCHAR),
617                        g_lpMsg[IDS_MSG_SRVSTART - IDS_MSG_FIRST],
618                        szServiceName);
619             addListBoxString(g_hwndStdoutList, szMsg);
620
621             if (StartService(schService, 0, NULL))
622             {
623                 Sleep(1000);
624                 while (QueryServiceStatus(schService, &schSStatus))
625                 {
626                     if (schSStatus.dwCurrentState == SERVICE_START_PENDING)
627                     {
628                         Sleep(1000);
629                     }
630                     else {
631                         break;
632                     }
633                 }
634             }
635             if (QueryServiceStatus(schService, &schSStatus))
636             {
637                 if (schSStatus.dwCurrentState == SERVICE_RUNNING)
638                 {
639                     retValue = TRUE;
640                     _sntprintf(szMsg, sizeof(szMsg) / sizeof(TCHAR), 
641                                g_lpMsg[IDS_MSG_SRVSTARTED - IDS_MSG_FIRST],
642                                szServiceName);
643                     addListBoxString(g_hwndStdoutList, szMsg);
644                 }
645             }
646             break;
647
648           case SERVICE_APACHE_RESTART:
649             _sntprintf(szMsg, sizeof(szMsg) / sizeof(TCHAR), 
650                        g_lpMsg[IDS_MSG_SRVRESTART - IDS_MSG_FIRST],
651                        szServiceName);
652             addListBoxString(g_hwndStdoutList, szMsg);
653             if (ControlService(schService, SERVICE_APACHE_RESTART,
654                                &schSStatus))
655             {
656                 ticks = 60;
657                 while (schSStatus.dwCurrentState == SERVICE_START_PENDING)
658                 {
659                     Sleep(1000);
660                     if (!QueryServiceStatus(schService, &schSStatus))
661                     {
662                         CloseServiceHandle(schService);
663                         CloseServiceHandle(schSCManager);
664                         g_bConsoleRun = FALSE;
665                         SetCursor(g_hCursorArrow);
666                         return FALSE;
667                     }
668                     if (!--ticks) {
669                         break;
670                     }
671                 }
672             }
673             if (schSStatus.dwCurrentState == SERVICE_RUNNING)
674             {
675                 retValue = TRUE;
676                 _sntprintf(szMsg, sizeof(szMsg) / sizeof(TCHAR), 
677                            g_lpMsg[IDS_MSG_SRVRESTARTED - IDS_MSG_FIRST],
678                            szServiceName);
679                 addListBoxString(g_hwndStdoutList, szMsg);
680             }
681             break;
682         }
683         CloseServiceHandle(schService);
684         CloseServiceHandle(schSCManager);
685         if (!retValue) {
686             ErrorMessage(g_lpMsg[IDS_MSG_SRVFAILED - IDS_MSG_FIRST],
687                          FALSE);
688         }
689         g_bConsoleRun = FALSE;
690         SetCursor(g_hCursorArrow);
691         return retValue;
692     }
693     return FALSE;
694 }
695
696
697 BOOL IsServiceRunning(LPCTSTR szServiceName, LPCTSTR szComputerName,
698                       LPDWORD lpdwPid)
699 {
700     DWORD dwPid;
701     SC_HANDLE schService;
702     SC_HANDLE schSCManager;
703     SERVICE_STATUS schSStatus;
704
705     dwPid = 0;
706     schSCManager = OpenSCManager(szComputerName, NULL,
707                                 SC_MANAGER_CONNECT);
708     if (!schSCManager) {
709         return FALSE;
710     }
711
712     schService = OpenService(schSCManager, szServiceName,
713                              SERVICE_QUERY_STATUS);
714     if (schService != NULL)
715     {
716         if (QueryServiceStatus(schService, &schSStatus))
717         {
718             dwPid = schSStatus.dwCurrentState;
719             if (lpdwPid) {
720                 *lpdwPid = 1;
721             }
722         }
723         CloseServiceHandle(schService);
724         CloseServiceHandle(schSCManager);
725         return dwPid == SERVICE_RUNNING ? TRUE : FALSE;
726     }
727     else {
728         g_bRescanServices = TRUE;
729     }
730     CloseServiceHandle(schSCManager);
731     return FALSE;
732 }
733
734
735 BOOL FindRunningServices(void)
736 {
737     int i = 0;
738     DWORD dwPid;
739     BOOL rv = FALSE;
740     while (g_stServices[i].szServiceName != NULL)
741     {
742         if (!IsServiceRunning(g_stServices[i].szServiceName,
743                               g_stServices[i].szComputerName, &dwPid)) {
744             dwPid = 0;
745         }
746         if (g_stServices[i].dwPid != dwPid) {
747             rv = TRUE;
748         }
749         g_stServices[i].dwPid = dwPid;
750         ++i;
751     }
752     return rv;
753 }
754
755
756 BOOL GetApacheServicesStatus()
757 {
758     TCHAR szKey[MAX_PATH];
759     TCHAR achKey[MAX_PATH];
760     TCHAR szImagePath[MAX_PATH];
761     TCHAR szBuf[MAX_PATH];
762     TCHAR szTmp[MAX_PATH];
763     HKEY hKey, hSubKey, hKeyRemote;
764     DWORD retCode, rv, dwKeyType;
765     DWORD dwBufLen = MAX_PATH;
766     int i, stPos = 0;
767     int computers = 0;
768
769     g_bRescanServices = FALSE;
770
771     am_ClearServicesSt();
772     while (g_stComputers[computers].szComputerName != NULL) {
773         hKeyRemote = g_stComputers[computers].hRegistry;
774         retCode = RegOpenKeyEx(hKeyRemote,
775                                _T("System\\CurrentControlSet\\Services\\"),
776                                0, KEY_READ, &hKey);
777         if (retCode != ERROR_SUCCESS)
778         {
779             ErrorMessage(NULL, FALSE);
780             return FALSE;
781         }
782         for (i = 0, retCode = ERROR_SUCCESS; retCode == ERROR_SUCCESS; i++)
783         {
784             retCode = RegEnumKey(hKey, i, achKey, MAX_PATH);
785             if (retCode == ERROR_SUCCESS)
786             {
787                 _tcscpy(szKey, _T("System\\CurrentControlSet\\Services\\"));
788                 _tcscat(szKey, achKey);
789
790                 if (RegOpenKeyEx(hKeyRemote, szKey, 0,
791                                  KEY_QUERY_VALUE, &hSubKey) == ERROR_SUCCESS)
792                 {
793                     dwBufLen = MAX_PATH;
794                     rv = RegQueryValueEx(hSubKey, _T("ImagePath"), NULL,
795                                          &dwKeyType, (LPBYTE)szImagePath, &dwBufLen);
796
797                     if (rv == ERROR_SUCCESS
798                             && (dwKeyType == REG_SZ
799                              || dwKeyType == REG_EXPAND_SZ)
800                             && dwBufLen)
801                     {
802                         _tcscpy(szBuf, szImagePath);
803                         CharLower(szBuf);
804                         /* the service name could be httpd*.exe or Apache*.exe */
805                         if (((_tcsstr(szBuf, _T("\\apache")) != NULL)
806                              || (_tcsstr(szBuf, _T("\\httpd")) != NULL))
807                                 && _tcsstr(szBuf, _T(".exe"))
808                                 && (_tcsstr(szBuf, _T("--ntservice")) != NULL
809                                        || _tcsstr(szBuf, _T("-k ")) != NULL))
810                         {
811                             g_stServices[stPos].szServiceName = _tcsdup(achKey);
812                             g_stServices[stPos].szImagePath = _tcsdup(szImagePath);
813                             g_stServices[stPos].szComputerName =
814                                 _tcsdup(g_stComputers[computers].szComputerName);
815                             dwBufLen = MAX_PATH;
816                             if (RegQueryValueEx(hSubKey, _T("Description"), NULL,
817                                                 &dwKeyType, (LPBYTE)szBuf, &dwBufLen)
818                                     == ERROR_SUCCESS) {
819                                 g_stServices[stPos].szDescription = _tcsdup(szBuf);
820                             }
821                             dwBufLen = MAX_PATH;
822                             if (RegQueryValueEx(hSubKey, _T("DisplayName"), NULL,
823                                                 &dwKeyType, (LPBYTE)szBuf, &dwBufLen)
824                                     == ERROR_SUCCESS)
825                             {
826                                 if (_tcscmp(g_stComputers[computers]
827                                         .szComputerName, g_szLocalHost) != 0)
828                                 {
829                                     _tcscpy(szTmp, g_stComputers[computers]
830                                                       .szComputerName + 2);
831                                     _tcscat(szTmp, _T("@"));
832                                     _tcscat(szTmp, szBuf);
833                                 }
834                                 else {
835                                     _tcscpy(szTmp, szBuf);
836                                 }
837                                 g_stServices[stPos].szDisplayName = _tcsdup(szTmp);
838
839                             }
840                             ++stPos;
841                             if (stPos >= MAX_APACHE_SERVICES) {
842                                 retCode = !ERROR_SUCCESS;
843                             }
844                         }
845                     }
846                     RegCloseKey(hSubKey);
847                 }
848             }
849         }
850         ++computers;
851         RegCloseKey(hKey);
852     }
853     FindRunningServices();
854     return TRUE;
855 }
856
857
858 LRESULT CALLBACK ConnectDlgProc(HWND hDlg, UINT message,
859                                 WPARAM wParam, LPARAM lParam)
860 {
861     TCHAR szCmp[MAX_COMPUTERNAME_LENGTH+4];
862     switch (message)
863     {
864     case WM_INITDIALOG:
865         ShowWindow(hDlg, SW_HIDE);
866         g_hwndConnectDlg = hDlg;
867         CenterWindow(hDlg);
868         ShowWindow(hDlg, SW_SHOW);
869         SetFocus(GetDlgItem(hDlg, IDC_COMPUTER));
870         return TRUE;
871
872     case WM_COMMAND:
873         switch (LOWORD(wParam))
874         {
875         case IDOK:
876             memset(szCmp, 0, sizeof(szCmp));
877             _tcscpy(szCmp, _T("\\\\"));
878             SendMessage(GetDlgItem(hDlg, IDC_COMPUTER), WM_GETTEXT,
879                         (WPARAM) MAX_COMPUTERNAME_LENGTH,
880                         (LPARAM) szCmp+2);
881
882             _tcsupr(szCmp);
883             if (_tcslen(szCmp) < 3) {
884                 EndDialog(hDlg, TRUE);
885                 return TRUE;
886             }
887             am_ConnectComputer(szCmp);
888             SendMessage(g_hwndMain, WM_TIMER, WM_TIMER_RESCAN, 0);
889
890         case IDCANCEL:
891             EndDialog(hDlg, TRUE);
892             return TRUE;
893
894         case IDC_LBROWSE:
895         {
896             BROWSEINFO bi;
897             ITEMIDLIST *il;
898             LPMALLOC pMalloc;
899             memset(&bi, 0, sizeof(BROWSEINFO));
900             SHGetSpecialFolderLocation(hDlg, CSIDL_NETWORK, &il);
901
902             bi.lpszTitle      = _T("ApacheMonitor :\nSelect Network Computer!");
903             bi.pszDisplayName = szCmp;
904             bi.hwndOwner =      hDlg;
905             bi.ulFlags =        BIF_BROWSEFORCOMPUTER;
906             bi.lpfn =           NULL;
907             bi.lParam =         0;
908             bi.iImage =         0;
909             bi.pidlRoot =       il;
910
911             if (SHBrowseForFolder(&bi) != NULL) {
912                 SendMessage(GetDlgItem(hDlg, IDC_COMPUTER),
913                             WM_SETTEXT,
914                             (WPARAM) NULL, (LPARAM) szCmp);
915             }
916             if (SHGetMalloc(&pMalloc)) {
917                 pMalloc->lpVtbl->Free(pMalloc, il);
918                 pMalloc->lpVtbl->Release(pMalloc);
919             }
920             return TRUE;
921         }
922         }
923         break;
924
925     case WM_QUIT:
926     case WM_CLOSE:
927         EndDialog(hDlg, TRUE);
928         return TRUE;
929
930     default:
931         return FALSE;
932     }
933     return FALSE;
934
935 }
936
937
938 LRESULT CALLBACK ServiceDlgProc(HWND hDlg, UINT message,
939                                 WPARAM wParam, LPARAM lParam)
940 {
941     TCHAR szBuf[MAX_PATH];
942     HWND hListBox;
943     static HWND hStatusBar;
944     TEXTMETRIC tm;
945     int i, y;
946     HDC hdcMem;
947     RECT rcBitmap;
948     LRESULT nItem;
949     LPMEASUREITEMSTRUCT lpmis;
950     LPDRAWITEMSTRUCT lpdis;
951
952     memset(szBuf, 0, sizeof(szBuf));
953     switch (message)
954     {
955     case WM_INITDIALOG:
956         ShowWindow(hDlg, SW_HIDE);
957         g_hwndServiceDlg = hDlg;
958         SetWindowText(hDlg, g_szTitle);
959         Button_Enable(GetDlgItem(hDlg, IDC_SSTART), FALSE);
960         Button_Enable(GetDlgItem(hDlg, IDC_SSTOP), FALSE);
961         Button_Enable(GetDlgItem(hDlg, IDC_SRESTART), FALSE);
962         Button_Enable(GetDlgItem(hDlg, IDC_SDISCONN), FALSE);
963         SetWindowText(GetDlgItem(hDlg, IDC_SSTART),
964                       g_lpMsg[IDS_MSG_SSTART - IDS_MSG_FIRST]);
965         SetWindowText(GetDlgItem(hDlg, IDC_SSTOP),
966                       g_lpMsg[IDS_MSG_SSTOP - IDS_MSG_FIRST]);
967         SetWindowText(GetDlgItem(hDlg, IDC_SRESTART),
968                       g_lpMsg[IDS_MSG_SRESTART - IDS_MSG_FIRST]);
969         SetWindowText(GetDlgItem(hDlg, IDC_SMANAGER),
970                       g_lpMsg[IDS_MSG_SERVICES - IDS_MSG_FIRST]);
971         SetWindowText(GetDlgItem(hDlg, IDC_SCONNECT),
972                       g_lpMsg[IDS_MSG_CONNECT - IDS_MSG_FIRST]);
973         SetWindowText(GetDlgItem(hDlg, IDCANCEL),
974                       g_lpMsg[IDS_MSG_OK - IDS_MSG_FIRST]);
975         hListBox = GetDlgItem(hDlg, IDL_SERVICES);
976         g_hwndStdoutList = GetDlgItem(hDlg, IDL_STDOUT);
977         hStatusBar = CreateStatusWindow(0x0800 /* SBT_TOOLTIPS */
978                                       | WS_CHILD | WS_VISIBLE,
979                                         _T(""), hDlg, IDC_STATBAR);
980         if (GetApacheServicesStatus())
981         {
982             i = 0;
983             while (g_stServices[i].szServiceName != NULL)
984             {
985                 addListBoxItem(hListBox, g_stServices[i].szDisplayName,
986                                g_stServices[i].dwPid == 0 ? g_hBmpStop
987                                                           : g_hBmpStart);
988                 ++i;
989             }
990         }
991         CenterWindow(hDlg);
992         ShowWindow(hDlg, SW_SHOW);
993         SetFocus(hListBox);
994         SendMessage(hListBox, LB_SETCURSEL, 0, 0);
995         return TRUE;
996         break;
997
998     case WM_MANAGEMESSAGE:
999         ApacheManageService(g_stServices[LOWORD(wParam)].szServiceName,
1000                     g_stServices[LOWORD(wParam)].szImagePath,
1001                     g_stServices[LOWORD(wParam)].szComputerName,
1002                     LOWORD(lParam));
1003
1004         return TRUE;
1005         break;
1006
1007     case WM_UPDATEMESSAGE:
1008         hListBox = GetDlgItem(hDlg, IDL_SERVICES);
1009         SendMessage(hListBox, LB_RESETCONTENT, 0, 0);
1010         SendMessage(hStatusBar, SB_SETTEXT, 0, (LPARAM)_T(""));
1011         Button_Enable(GetDlgItem(hDlg, IDC_SSTART), FALSE);
1012         Button_Enable(GetDlgItem(hDlg, IDC_SSTOP), FALSE);
1013         Button_Enable(GetDlgItem(hDlg, IDC_SRESTART), FALSE);
1014         Button_Enable(GetDlgItem(hDlg, IDC_SDISCONN), FALSE);
1015         i = 0;
1016         while (g_stServices[i].szServiceName != NULL)
1017         {
1018             addListBoxItem(hListBox, g_stServices[i].szDisplayName,
1019                 g_stServices[i].dwPid == 0 ? g_hBmpStop : g_hBmpStart);
1020             ++i;
1021         }
1022         SendMessage(hListBox, LB_SETCURSEL, 0, 0);
1023         /* Dirty hack to bring the window to the foreground */
1024         SetWindowPos(hDlg, HWND_TOPMOST, 0, 0, 0, 0,
1025                                 SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);
1026         SetWindowPos(hDlg, HWND_NOTOPMOST, 0, 0, 0, 0,
1027                                 SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);
1028         SetFocus(hListBox);
1029         return TRUE;
1030         break;
1031
1032     case WM_MEASUREITEM:
1033         lpmis = (LPMEASUREITEMSTRUCT) lParam;
1034         lpmis->itemHeight = YBITMAP;
1035         return TRUE;
1036
1037     case WM_SETCURSOR:
1038         if (g_bConsoleRun) {
1039             SetCursor(g_hCursorHourglass);
1040         }
1041         else {
1042             SetCursor(g_hCursorArrow);
1043         }
1044         return TRUE;
1045
1046     case WM_DRAWITEM:
1047         lpdis = (LPDRAWITEMSTRUCT) lParam;
1048         if (lpdis->itemID == -1) {
1049             break;
1050         }
1051         switch (lpdis->itemAction)
1052         {
1053         case ODA_FOCUS:
1054         case ODA_SELECT:
1055         case ODA_DRAWENTIRE:
1056             g_hBmpPicture = (HBITMAP)SendMessage(lpdis->hwndItem,
1057                                                  LB_GETITEMDATA,
1058                                                  lpdis->itemID, (LPARAM) 0);
1059
1060             hdcMem = CreateCompatibleDC(lpdis->hDC);
1061             g_hBmpOld = SelectObject(hdcMem, g_hBmpPicture);
1062
1063             BitBlt(lpdis->hDC, lpdis->rcItem.left, lpdis->rcItem.top,
1064                    lpdis->rcItem.right - lpdis->rcItem.left,
1065                    lpdis->rcItem.bottom - lpdis->rcItem.top,
1066                    hdcMem, 0, 0, SRCCOPY);
1067             SendMessage(lpdis->hwndItem, LB_GETTEXT,
1068                         lpdis->itemID, (LPARAM) szBuf);
1069
1070             GetTextMetrics(lpdis->hDC, &tm);
1071             y = (lpdis->rcItem.bottom + lpdis->rcItem.top - tm.tmHeight) / 2;
1072
1073             SelectObject(hdcMem, g_hBmpOld);
1074             DeleteDC(hdcMem);
1075
1076             rcBitmap.left = lpdis->rcItem.left + XBITMAP + 2;
1077             rcBitmap.top = lpdis->rcItem.top;
1078             rcBitmap.right = lpdis->rcItem.right;
1079             rcBitmap.bottom = lpdis->rcItem.top + YBITMAP;
1080
1081             if (lpdis->itemState & ODS_SELECTED)
1082             {
1083                 if (g_hBmpPicture == g_hBmpStop)
1084                 {
1085                     Button_Enable(GetDlgItem(hDlg, IDC_SSTART), TRUE);
1086                     Button_SetStyle(GetDlgItem(hDlg, IDC_SSTART), BS_DEFPUSHBUTTON, TRUE);
1087                     Button_Enable(GetDlgItem(hDlg, IDC_SSTOP), FALSE);
1088                     Button_Enable(GetDlgItem(hDlg, IDC_SRESTART), FALSE);
1089                 }
1090                 else if (g_hBmpPicture == g_hBmpStart)
1091                 {
1092                     Button_Enable(GetDlgItem(hDlg, IDC_SSTART), FALSE);
1093                     Button_Enable(GetDlgItem(hDlg, IDC_SSTOP), TRUE);
1094                     Button_SetStyle(GetDlgItem(hDlg, IDC_SSTOP), BS_DEFPUSHBUTTON, TRUE);
1095                     Button_Enable(GetDlgItem(hDlg, IDC_SRESTART), TRUE);
1096                 }
1097                 else {
1098                     Button_Enable(GetDlgItem(hDlg, IDC_SSTART), FALSE);
1099                     Button_Enable(GetDlgItem(hDlg, IDC_SSTOP), FALSE);
1100                     Button_Enable(GetDlgItem(hDlg, IDC_SRESTART), FALSE);
1101                 }
1102                 if (_tcscmp(g_stServices[lpdis->itemID].szComputerName,
1103                            g_szLocalHost) == 0) {
1104                     Button_Enable(GetDlgItem(hDlg, IDC_SDISCONN), FALSE);
1105                 }
1106                 else {
1107                     Button_Enable(GetDlgItem(hDlg, IDC_SDISCONN), TRUE);
1108                 }
1109
1110                 if (g_stServices[lpdis->itemID].szDescription) {
1111                     SendMessage(hStatusBar, SB_SETTEXT, 0,
1112                             (LPARAM)g_stServices[lpdis->itemID].szDescription);
1113                 }
1114                 else {
1115                     SendMessage(hStatusBar, SB_SETTEXT, 0, (LPARAM)_T(""));
1116                 }
1117                 if (lpdis->itemState & ODS_FOCUS) {
1118                     SetTextColor(lpdis->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
1119                     SetBkColor(lpdis->hDC, GetSysColor(COLOR_HIGHLIGHT));
1120                     FillRect(lpdis->hDC, &rcBitmap, (HBRUSH)(COLOR_HIGHLIGHT+1));
1121                 }
1122                 else {
1123                     SetTextColor(lpdis->hDC, GetSysColor(COLOR_INACTIVECAPTIONTEXT));
1124                     SetBkColor(lpdis->hDC, GetSysColor(COLOR_INACTIVECAPTION));
1125                     FillRect(lpdis->hDC, &rcBitmap, (HBRUSH)(COLOR_INACTIVECAPTION+1));
1126                 }
1127             }
1128             else
1129             {
1130                SetTextColor(lpdis->hDC, GetSysColor(COLOR_MENUTEXT));
1131                SetBkColor(lpdis->hDC, GetSysColor(COLOR_WINDOW));
1132                FillRect(lpdis->hDC, &rcBitmap, (HBRUSH)(COLOR_WINDOW+1));
1133             }
1134             TextOut(lpdis->hDC, XBITMAP + 6, y, szBuf, (int)_tcslen(szBuf));
1135             break;
1136         }
1137         return TRUE;
1138     case WM_COMMAND:
1139         switch (LOWORD(wParam))
1140         {
1141         case IDL_SERVICES:
1142             switch (HIWORD(wParam))
1143             {
1144             case LBN_DBLCLK:
1145                 /* if started then stop, if stopped then start */
1146                 hListBox = GetDlgItem(hDlg, IDL_SERVICES);
1147                 nItem = SendMessage(hListBox, LB_GETCURSEL, 0, 0);
1148                 if (nItem != LB_ERR)
1149                 {
1150                     g_hBmpPicture = (HBITMAP)SendMessage(hListBox,
1151                                                          LB_GETITEMDATA,
1152                                                          nItem, (LPARAM) 0);
1153                     if (g_hBmpPicture == g_hBmpStop) {
1154                         SendMessage(hDlg, WM_MANAGEMESSAGE, nItem,
1155                                     SERVICE_CONTROL_CONTINUE);
1156                     }
1157                     else {
1158                         SendMessage(hDlg, WM_MANAGEMESSAGE, nItem,
1159                                     SERVICE_CONTROL_STOP);
1160                     }
1161
1162                 }
1163                 return TRUE;
1164             }
1165             break;
1166
1167         case IDCANCEL:
1168             EndDialog(hDlg, TRUE);
1169             return TRUE;
1170
1171         case IDC_SSTART:
1172             Button_Enable(GetDlgItem(hDlg, IDC_SSTART), FALSE);
1173             hListBox = GetDlgItem(hDlg, IDL_SERVICES);
1174             nItem = SendMessage(hListBox, LB_GETCURSEL, 0, 0);
1175             if (nItem != LB_ERR) {
1176                 SendMessage(hDlg, WM_MANAGEMESSAGE, nItem,
1177                             SERVICE_CONTROL_CONTINUE);
1178             }
1179             Button_Enable(GetDlgItem(hDlg, IDC_SSTART), TRUE);
1180             return TRUE;
1181
1182         case IDC_SSTOP:
1183             Button_Enable(GetDlgItem(hDlg, IDC_SSTOP), FALSE);
1184             hListBox = GetDlgItem(hDlg, IDL_SERVICES);
1185             nItem = SendMessage(hListBox, LB_GETCURSEL, 0, 0);
1186             if (nItem != LB_ERR) {
1187                 SendMessage(hDlg, WM_MANAGEMESSAGE, nItem,
1188                             SERVICE_CONTROL_STOP);
1189             }
1190             Button_Enable(GetDlgItem(hDlg, IDC_SSTOP), TRUE);
1191             return TRUE;
1192
1193         case IDC_SRESTART:
1194             Button_Enable(GetDlgItem(hDlg, IDC_SRESTART), FALSE);
1195             hListBox = GetDlgItem(hDlg, IDL_SERVICES);
1196             nItem = SendMessage(hListBox, LB_GETCURSEL, 0, 0);
1197             if (nItem != LB_ERR) {
1198                 SendMessage(hDlg, WM_MANAGEMESSAGE, nItem,
1199                             SERVICE_APACHE_RESTART);
1200             }
1201             Button_Enable(GetDlgItem(hDlg, IDC_SRESTART), TRUE);
1202             return TRUE;
1203
1204         case IDC_SMANAGER:
1205             if (g_dwOSVersion >= OS_VERSION_WIN2K) {
1206                 ShellExecute(hDlg, _T("open"), _T("services.msc"), _T("/s"),
1207                              NULL, SW_NORMAL);
1208             }
1209             else {
1210                 WinExec("Control.exe SrvMgr.cpl Services", SW_NORMAL);
1211             }
1212             return TRUE;
1213
1214         case IDC_SCONNECT:
1215             DialogBox(g_hInstance, MAKEINTRESOURCE(IDD_DLGCONNECT),
1216                       hDlg, (DLGPROC)ConnectDlgProc);
1217             return TRUE;
1218
1219         case IDC_SDISCONN:
1220             hListBox = GetDlgItem(hDlg, IDL_SERVICES);
1221             nItem = SendMessage(hListBox, LB_GETCURSEL, 0, 0);
1222             if (nItem != LB_ERR) {
1223                 am_DisconnectComputer(g_stServices[nItem].szComputerName);
1224                 SendMessage(g_hwndMain, WM_TIMER, WM_TIMER_RESCAN, 0);
1225             }
1226             return TRUE;
1227         }
1228         break;
1229
1230     case WM_SIZE:
1231         switch (LOWORD(wParam))
1232         {
1233         case SIZE_MINIMIZED:
1234             EndDialog(hDlg, TRUE);
1235             return TRUE;
1236             break;
1237         }
1238         break;
1239
1240     case WM_QUIT:
1241     case WM_CLOSE:
1242         EndDialog(hDlg, TRUE);
1243         return TRUE;
1244
1245     default:
1246         return FALSE;
1247     }
1248     return FALSE;
1249 }
1250
1251
1252 LRESULT CALLBACK WndProc(HWND hWnd, UINT message,
1253                           WPARAM wParam, LPARAM lParam)
1254 {
1255     if (message == g_bUiTaskbarCreated)
1256     {
1257         /* restore the tray icon on shell restart */
1258         ShowNotifyIcon(hWnd, NIM_ADD);
1259         return DefWindowProc(hWnd, message, wParam, lParam);
1260     }
1261     switch (message)
1262     {
1263     case WM_CREATE:
1264         GetApacheServicesStatus();
1265         ShowNotifyIcon(hWnd, NIM_ADD);
1266         SetTimer(hWnd, WM_TIMER_REFRESH, REFRESH_TIME, NULL);
1267         SetTimer(hWnd, WM_TIMER_RESCAN,  RESCAN_TIME, NULL);
1268         break;
1269
1270     case WM_TIMER:
1271         switch (wParam)
1272         {
1273         case WM_TIMER_RESCAN:
1274         {
1275             int nPrev = 0, nNew = 0;
1276             EnterCriticalSection(&g_stcSection);
1277             if (FindRunningServices() || g_bRescanServices)
1278             {
1279                 ShowNotifyIcon(hWnd, NIM_MODIFY);
1280                 if (g_hwndServiceDlg)
1281                     PostMessage(g_hwndServiceDlg, WM_UPDATEMESSAGE, 0, 0);
1282             }
1283             /* check if services list changed */
1284             while (g_stServices[nPrev].szServiceName != NULL)
1285                 ++nPrev;
1286             GetApacheServicesStatus();
1287             while (g_stServices[nNew].szServiceName != NULL)
1288                 ++nNew;
1289             if (nPrev != nNew)
1290             {
1291                 ShowNotifyIcon(hWnd, NIM_MODIFY);
1292                 if (g_hwndServiceDlg) {
1293                     PostMessage(g_hwndServiceDlg, WM_UPDATEMESSAGE, 0, 0);
1294                 }
1295             }
1296             LeaveCriticalSection(&g_stcSection);
1297             break;
1298         }
1299
1300         case WM_TIMER_REFRESH:
1301         {
1302             int nPrev = 0, nNew = 0;
1303             EnterCriticalSection(&g_stcSection);
1304             if (g_bRescanServices)
1305             {
1306                 GetApacheServicesStatus();
1307                 ShowNotifyIcon(hWnd, NIM_MODIFY);
1308                 if (g_hwndServiceDlg) {
1309                     PostMessage(g_hwndServiceDlg, WM_UPDATEMESSAGE, 0, 0);
1310                 }
1311             }
1312             else if (FindRunningServices())
1313             {
1314                 ShowNotifyIcon(hWnd, NIM_MODIFY);
1315                 if (g_hwndServiceDlg) {
1316                     PostMessage(g_hwndServiceDlg, WM_UPDATEMESSAGE, 0, 0);
1317                 }
1318             }
1319             LeaveCriticalSection(&g_stcSection);
1320             break;
1321         }
1322         }
1323         break;
1324
1325     case WM_QUIT:
1326         ShowNotifyIcon(hWnd, NIM_DELETE);
1327         break;
1328
1329     case WM_TRAYMESSAGE:
1330         switch (lParam)
1331         {
1332         case WM_LBUTTONDBLCLK:
1333             if (!g_bDlgServiceOn)
1334             {
1335                 g_bDlgServiceOn = TRUE;
1336                 DialogBox(g_hInstance, MAKEINTRESOURCE(IDD_DLGSERVICES),
1337                           hWnd, (DLGPROC)ServiceDlgProc);
1338                 g_bDlgServiceOn = FALSE;
1339                 g_hwndServiceDlg = NULL;
1340             }
1341             else if (IsWindow(g_hwndServiceDlg))
1342             {
1343                 /* Dirty hack to bring the window to the foreground */
1344                 SetWindowPos(g_hwndServiceDlg, HWND_TOPMOST, 0, 0, 0, 0,
1345                              SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);
1346                 SetWindowPos(g_hwndServiceDlg, HWND_NOTOPMOST, 0, 0, 0, 0,
1347                              SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);
1348                 SetFocus(g_hwndServiceDlg);
1349             }
1350             break;
1351
1352         case WM_LBUTTONUP:
1353             ShowTryServicesMenu(hWnd);
1354             break;
1355
1356         case WM_RBUTTONUP:
1357             ShowTryPopupMenu(hWnd);
1358             break;
1359         }
1360         break;
1361
1362     case WM_COMMAND:
1363         if ((LOWORD(wParam) & IDM_SM_START) == IDM_SM_START)
1364         {
1365             ApacheManageService(g_stServices[LOWORD(wParam)
1366                                            - IDM_SM_START].szServiceName,
1367                                 g_stServices[LOWORD(wParam)
1368                                            - IDM_SM_START].szImagePath,
1369                                 g_stServices[LOWORD(wParam)
1370                                            - IDM_SM_START].szComputerName,
1371                                 SERVICE_CONTROL_CONTINUE);
1372             return TRUE;
1373         }
1374         else if ((LOWORD(wParam) & IDM_SM_STOP) == IDM_SM_STOP)
1375         {
1376             ApacheManageService(g_stServices[LOWORD(wParam)
1377                                            - IDM_SM_STOP].szServiceName,
1378                                 g_stServices[LOWORD(wParam)
1379                                            - IDM_SM_STOP].szImagePath,
1380                                 g_stServices[LOWORD(wParam)
1381                                            - IDM_SM_STOP].szComputerName,
1382                                 SERVICE_CONTROL_STOP);
1383             return TRUE;
1384         }
1385         else if ((LOWORD(wParam) & IDM_SM_RESTART) == IDM_SM_RESTART)
1386         {
1387             ApacheManageService(g_stServices[LOWORD(wParam)
1388                                            - IDM_SM_RESTART].szServiceName,
1389                                 g_stServices[LOWORD(wParam)
1390                                            - IDM_SM_RESTART].szImagePath,
1391                                 g_stServices[LOWORD(wParam)
1392                                            - IDM_SM_RESTART].szComputerName,
1393                                 SERVICE_APACHE_RESTART);
1394             return TRUE;
1395         }
1396         switch (LOWORD(wParam))
1397         {
1398         case IDM_RESTORE:
1399             if (!g_bDlgServiceOn)
1400             {
1401                 g_bDlgServiceOn = TRUE;
1402                 DialogBox(g_hInstance, MAKEINTRESOURCE(IDD_DLGSERVICES),
1403                           hWnd, (DLGPROC)ServiceDlgProc);
1404                 g_bDlgServiceOn = FALSE;
1405                 g_hwndServiceDlg = NULL;
1406             }
1407             else if (IsWindow(g_hwndServiceDlg)) {
1408                 SetFocus(g_hwndServiceDlg);
1409             }
1410             break;
1411
1412         case IDC_SMANAGER:
1413             if (g_dwOSVersion >= OS_VERSION_WIN2K) {
1414                 ShellExecute(NULL, _T("open"), _T("services.msc"), _T("/s"),
1415                              NULL, SW_NORMAL);
1416             }
1417             else {
1418                 WinExec("Control.exe SrvMgr.cpl Services", SW_NORMAL);
1419             }
1420             return TRUE;
1421
1422         case IDM_EXIT:
1423             ShowNotifyIcon(hWnd, NIM_DELETE);
1424             PostQuitMessage(0);
1425             return TRUE;
1426         }
1427
1428     default:
1429         return DefWindowProc(hWnd, message, wParam, lParam);
1430     }
1431
1432     return FALSE;
1433 }
1434
1435
1436 static int KillAWindow(HWND appwindow)
1437 {
1438     HANDLE appproc;
1439     DWORD procid;
1440     BOOL postres;
1441
1442     SetLastError(0);
1443     GetWindowThreadProcessId(appwindow, &procid);
1444     if (GetLastError())
1445         return(2);
1446
1447     appproc = OpenProcess(SYNCHRONIZE, 0, procid);
1448     postres = PostMessage(appwindow, WM_COMMAND, IDM_EXIT, 0);
1449     if (appproc && postres) {
1450         if (WaitForSingleObject(appproc, 10 /* seconds */ * 1000)
1451                 == WAIT_OBJECT_0) {
1452             CloseHandle(appproc);
1453             return (0);
1454         }
1455     }
1456     if (appproc)
1457         CloseHandle(appproc);
1458
1459     if ((appproc = OpenProcess(PROCESS_TERMINATE, 0, procid)) != NULL) {
1460         if (TerminateProcess(appproc, 0)) {
1461             CloseHandle(appproc);
1462             return (0);
1463         }
1464         CloseHandle(appproc);
1465     }
1466
1467     /* Perhaps we were short of permissions? */
1468     return (2);
1469 }
1470
1471
1472 static int KillAllMonitors(void)
1473 {
1474     HWND appwindow;
1475     int exitcode = 0;
1476     PWTS_PROCESS_INFO tsProcs;
1477     DWORD tsProcCount, i;
1478     DWORD thisProcId; 
1479
1480     /* This is graceful, close our own Window, clearing the icon */
1481     if ((appwindow = FindWindow(g_szWindowClass, g_szTitle)) != NULL)
1482         exitcode = KillAWindow(appwindow);
1483
1484     if (g_dwOSVersion < OS_VERSION_WIN2K)
1485         return exitcode;
1486
1487     thisProcId = GetCurrentProcessId();
1488
1489     if (!WTSEnumerateProcesses(WTS_CURRENT_SERVER_HANDLE, 0, 1,
1490                                &tsProcs, &tsProcCount))
1491         return exitcode;
1492
1493     /* This is ungraceful; close other Windows, with a lingering icon.
1494      * Since on terminal server it's not possible to post the message
1495      * to exit across sessions, we have to suffer this side effect
1496      * of a taskbar 'icon' which will evaporate the next time that
1497      * the user hovers over it or when the taskbar area is updated.
1498      */
1499     for (i = 0; i < tsProcCount; ++i) {
1500         if (_tcscmp(tsProcs[i].pProcessName, _T(AM_STRINGIFY(BIN_NAME))) == 0
1501                 && tsProcs[i].ProcessId != thisProcId)
1502             WTSTerminateProcess(WTS_CURRENT_SERVER_HANDLE, 
1503                                 tsProcs[i].ProcessId, 1);
1504     }
1505     WTSFreeMemory(tsProcs);
1506     return exitcode;
1507 }
1508
1509
1510 /* Create main invisible window */
1511 HWND CreateMainWindow(HINSTANCE hInstance)
1512 {
1513     HWND hWnd = NULL;
1514     WNDCLASSEX wcex;
1515
1516     wcex.cbSize = sizeof(WNDCLASSEX);
1517
1518     wcex.style          = CS_HREDRAW | CS_VREDRAW;
1519     wcex.lpfnWndProc    = (WNDPROC)WndProc;
1520     wcex.cbClsExtra     = 0;
1521     wcex.cbWndExtra     = 0;
1522     wcex.hInstance      = hInstance;
1523     wcex.hIcon   = (HICON)LoadImage(hInstance, MAKEINTRESOURCE(IDI_APSRVMON),
1524                                     IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR);
1525     wcex.hCursor        = g_hCursorArrow;
1526     wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
1527     wcex.lpszMenuName   = 0;
1528     wcex.lpszClassName  = g_szWindowClass;
1529     wcex.hIconSm = (HICON)LoadImage(hInstance, MAKEINTRESOURCE(IDI_APSRVMON),
1530                                     IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
1531
1532     if (RegisterClassEx(&wcex)) {
1533         hWnd = CreateWindow(g_szWindowClass, g_szTitle,
1534                             0, 0, 0, 0, 0,
1535                             NULL, NULL, hInstance, NULL);
1536     }
1537     return hWnd;
1538 }
1539
1540
1541 #ifndef UNICODE
1542 /* Borrowed from CRT internal.h for _MBCS argc/argv parsing in this GUI app */
1543 int  __cdecl _setargv(void);
1544 #endif
1545
1546 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
1547                    LPSTR lpCmdLine, int nCmdShow)
1548 {
1549     TCHAR szTmp[MAX_LOADSTRING];
1550     TCHAR szCmp[MAX_COMPUTERNAME_LENGTH+4];
1551     MSG msg;
1552     /* existing window */
1553     HWND appwindow;
1554     DWORD dwControl;
1555     int i;
1556     DWORD d;
1557
1558     if (!GetSystemOSVersion(&g_dwOSVersion))
1559     {
1560         ErrorMessage(NULL, TRUE);
1561         return 1;
1562     }
1563
1564     g_LangID = GetUserDefaultLangID();
1565     if ((g_LangID & 0xFF) != LANG_ENGLISH) {
1566         g_LangID = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
1567     }
1568     for (i = IDS_MSG_FIRST; i <= IDS_MSG_LAST; ++i) {
1569         LoadString(hInstance, i, szTmp, MAX_LOADSTRING);
1570         g_lpMsg[i - IDS_MSG_FIRST] = _tcsdup(szTmp);
1571     }
1572     LoadString(hInstance, IDS_APMONITORTITLE, szTmp, MAX_LOADSTRING);
1573     d = MAX_COMPUTERNAME_LENGTH+1;
1574     _tcscpy(szCmp, _T("\\\\"));
1575     GetComputerName(szCmp + 2, &d);
1576     _tcsupr(szCmp);
1577     g_szLocalHost = _tcsdup(szCmp);
1578
1579     memset(g_stComputers, 0, sizeof(ST_MONITORED_COMP) * MAX_APACHE_COMPUTERS);
1580     g_stComputers[0].szComputerName = _tcsdup(szCmp);
1581     g_stComputers[0].hRegistry = HKEY_LOCAL_MACHINE;
1582     g_szTitle = _tcsdup(szTmp);
1583     LoadString(hInstance, IDS_APMONITORCLASS, szTmp, MAX_LOADSTRING);
1584     g_szWindowClass = _tcsdup(szTmp);
1585
1586     appwindow = FindWindow(g_szWindowClass, g_szTitle);
1587
1588 #ifdef UNICODE
1589     __wargv = CommandLineToArgvW(GetCommandLineW(), &__argc);
1590 #else
1591     _setargv();
1592 #endif
1593
1594     if ((__argc == 2) && (_tcscmp(__targv[1], _T("--kill")) == 0))
1595     {
1596         /* Off to chase and close up every ApacheMonitor taskbar window */
1597         return KillAllMonitors();
1598     }
1599     else if ((__argc == 4) && (g_dwOSVersion >= OS_VERSION_WIN2K))
1600     {
1601         dwControl = _ttoi(__targv[1]);
1602         if ((dwControl != SERVICE_CONTROL_CONTINUE) &&
1603             (dwControl != SERVICE_APACHE_RESTART) &&
1604             (dwControl != SERVICE_CONTROL_STOP))
1605         {
1606             return 1;
1607         }
1608
1609         /* Chase down and close up our session's previous window */
1610         if ((appwindow) != NULL)
1611             KillAWindow(appwindow);
1612     }
1613     else if (__argc != 1) {
1614         return 1;
1615     }
1616     else if (appwindow)
1617     {
1618         ErrorMessage(g_lpMsg[IDS_MSG_APPRUNNING - IDS_MSG_FIRST], FALSE);
1619         return 0;
1620     }
1621
1622     g_icoStop          = LoadImage(hInstance, MAKEINTRESOURCE(IDI_ICOSTOP),
1623                                    IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
1624     g_icoRun           = LoadImage(hInstance, MAKEINTRESOURCE(IDI_ICORUN),
1625                                    IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
1626     g_hCursorHourglass = LoadImage(NULL, MAKEINTRESOURCE(OCR_WAIT),
1627                                    IMAGE_CURSOR, LR_DEFAULTSIZE,
1628                                    LR_DEFAULTSIZE, LR_SHARED);
1629     g_hCursorArrow     = LoadImage(NULL, MAKEINTRESOURCE(OCR_NORMAL),
1630                                    IMAGE_CURSOR, LR_DEFAULTSIZE,
1631                                    LR_DEFAULTSIZE, LR_SHARED);
1632     g_hBmpStart        = LoadImage(hInstance, MAKEINTRESOURCE(IDB_BMPRUN),
1633                                    IMAGE_BITMAP, XBITMAP, YBITMAP,
1634                                    LR_DEFAULTCOLOR);
1635     g_hBmpStop         = LoadImage(hInstance, MAKEINTRESOURCE(IDB_BMPSTOP),
1636                                    IMAGE_BITMAP, XBITMAP, YBITMAP,
1637                                    LR_DEFAULTCOLOR);
1638
1639     memset(g_stServices, 0, sizeof(ST_APACHE_SERVICE) * MAX_APACHE_SERVICES);
1640     CoInitialize(NULL);
1641     InitCommonControls();
1642     g_hInstance = hInstance;
1643     g_hwndMain = CreateMainWindow(hInstance);
1644     g_bUiTaskbarCreated = RegisterWindowMessage(_T("TaskbarCreated"));
1645     InitializeCriticalSection(&g_stcSection);
1646     g_hwndServiceDlg = NULL;
1647     if (g_hwndMain != NULL)
1648     {
1649         /* To avoid recursion, pass ImagePath NULL (a noop on NT and later) */
1650         if ((__argc == 4) && (g_dwOSVersion >= OS_VERSION_WIN2K))
1651             ApacheManageService(__targv[2], NULL, __targv[3], dwControl);
1652
1653         while (GetMessage(&msg, NULL, 0, 0) == TRUE)
1654         {
1655             TranslateMessage(&msg);
1656             DispatchMessage(&msg);
1657         }
1658         am_ClearServicesSt();
1659     }
1660     am_ClearComputersSt();
1661     DeleteCriticalSection(&g_stcSection);
1662     DestroyIcon(g_icoStop);
1663     DestroyIcon(g_icoRun);
1664     DestroyCursor(g_hCursorHourglass);
1665     DestroyCursor(g_hCursorArrow);
1666     DeleteObject(g_hBmpStart);
1667     DeleteObject(g_hBmpStop);
1668     CoUninitialize();
1669     return 0;
1670 }
1671