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