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