]> granicus.if.org Git - apache/blob - support/win32/ApacheMonitor.c
Fix access for non-Administrators (superusers and the like) to allow them
[apache] / support / win32 / ApacheMonitor.c
1 /* ====================================================================
2  * The Apache Software License, Version 1.1
3  *
4  * Copyright (c) 2000-2002 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                                      GENERIC_EXECUTE);
784         if (!schSCManager) {
785             return FALSE;
786         }
787
788         schService = OpenService(schSCManager, szServiceName, 
789                                  GENERIC_EXECUTE);
790         if (schService != NULL)
791         {
792             retValue = FALSE;
793             g_bConsoleRun = TRUE;
794             SetCursor(g_hCursorHourglass);
795             switch (dwCommand)
796             {
797             case SERVICE_CONTROL_STOP:
798                 sprintf(szMsg, g_lpMsg[IDS_MSG_SRVSTOP - IDS_MSG_FIRST], 
799                         szServiceName);
800                 addListBoxString(g_hwndStdoutList, szMsg);
801                 if (ControlService(schService, SERVICE_CONTROL_STOP, 
802                                    &schSStatus)) {
803                     Sleep(1000);
804                     while (QueryServiceStatus(schService, &schSStatus)) 
805                     {
806                         if (schSStatus.dwCurrentState == SERVICE_STOP_PENDING)
807                         {
808                             Sleep(1000);
809                         }
810                         else {
811                             break;
812                         }
813                     }
814                 }
815                 if (QueryServiceStatus(schService, &schSStatus))
816                 {
817                     if (schSStatus.dwCurrentState == SERVICE_STOPPED)
818                     {
819                         retValue = TRUE;
820                         sprintf(szMsg, 
821                                 g_lpMsg[IDS_MSG_SRVSTOPPED - IDS_MSG_FIRST], 
822                                 szServiceName);
823                         addListBoxString(g_hwndStdoutList, szMsg);
824                     }
825                 }
826                 break;
827
828             case SERVICE_CONTROL_CONTINUE:
829                 sprintf(szMsg, g_lpMsg[IDS_MSG_SRVSTART - IDS_MSG_FIRST],
830                         szServiceName);
831                 addListBoxString(g_hwndStdoutList, szMsg);
832
833                 if (StartService(schService, 0, NULL)) 
834                 {
835                     Sleep(1000);
836                     while (QueryServiceStatus(schService, &schSStatus)) 
837                     {
838                         if (schSStatus.dwCurrentState == SERVICE_START_PENDING)
839                         {
840                             Sleep(1000);
841                         }
842                         else {
843                             break;
844                         }
845                     }
846                 }
847                 if (QueryServiceStatus(schService, &schSStatus))
848                 {
849                     if (schSStatus.dwCurrentState == SERVICE_RUNNING)
850                     {
851                         retValue = TRUE;
852                         sprintf(szMsg, 
853                                 g_lpMsg[IDS_MSG_SRVSTARTED - IDS_MSG_FIRST],
854                                 szServiceName);
855                         addListBoxString(g_hwndStdoutList, szMsg);
856                     }
857                 }
858                 break;
859
860             case SERVICE_APACHE_RESTART:
861                 sprintf(szMsg, g_lpMsg[IDS_MSG_SRVRESTART - IDS_MSG_FIRST],
862                         szServiceName);
863                 addListBoxString(g_hwndStdoutList, szMsg);
864                 if (ControlService(schService, SERVICE_APACHE_RESTART,
865                                    &schSStatus)) 
866                 {
867                     ticks = 60;
868                     while (schSStatus.dwCurrentState == SERVICE_START_PENDING)
869                     {
870                         Sleep(1000);
871                         if (!QueryServiceStatus(schService, &schSStatus))
872                         {
873                             CloseServiceHandle(schService);
874                             CloseServiceHandle(schSCManager);
875                             g_bConsoleRun = FALSE;
876                             SetCursor(g_hCursorArrow);
877                             return FALSE;
878                         }
879                         if (!--ticks) {
880                             break;
881                         }
882                     }
883                 }
884                 if (schSStatus.dwCurrentState == SERVICE_RUNNING)
885                 {
886                     retValue = TRUE;
887                     sprintf(szMsg, 
888                             g_lpMsg[IDS_MSG_SRVRESTARTED - IDS_MSG_FIRST],
889                             szServiceName);
890                     addListBoxString(g_hwndStdoutList, szMsg);
891                 }
892                 break;
893             }
894             CloseServiceHandle(schService);
895             CloseServiceHandle(schSCManager);
896             if (!retValue) {
897                 ErrorMessage(g_lpMsg[IDS_MSG_SRVFAILED - IDS_MSG_FIRST], 
898                              FALSE);
899             }
900             g_bConsoleRun = FALSE;
901             SetCursor(g_hCursorArrow);
902             return retValue;
903         }
904         else {
905             g_bRescanServices = TRUE;
906         }
907         CloseServiceHandle(schSCManager);
908         return FALSE;
909     }
910
911     return FALSE;
912 }
913
914
915 BOOL IsServiceRunning(LPCSTR szServiceName, LPCSTR szComputerName, 
916                       LPDWORD lpdwPid)
917 {
918     DWORD dwPid;
919     HWND hWnd;
920     SC_HANDLE schService;
921     SC_HANDLE schSCManager;
922     SERVICE_STATUS schSStatus;
923
924     if (g_dwOSVersion == OS_VERSION_WIN9X)
925     {
926         hWnd = FindWindow("ApacheWin95ServiceMonitor", szServiceName);
927         if (hWnd && GetWindowThreadProcessId(hWnd, &dwPid)) 
928         {
929             *lpdwPid = 1;
930             return TRUE;
931         }
932         else {
933             return FALSE;
934         }
935     }
936     else
937     {
938         dwPid = 0;
939         schSCManager = OpenSCManager(szComputerName, NULL,
940                                      GENERIC_READ);
941         if (!schSCManager) {
942             return FALSE;
943         }
944
945         schService = OpenService(schSCManager, szServiceName, 
946                                  SERVICE_QUERY_STATUS);
947         if (schService != NULL)
948         {
949             if (QueryServiceStatus(schService, &schSStatus))
950             {
951                 dwPid = schSStatus.dwCurrentState;
952                 if (lpdwPid) {
953                     *lpdwPid = 1;
954                 }
955             }
956             CloseServiceHandle(schService);
957             CloseServiceHandle(schSCManager);
958             return dwPid == SERVICE_RUNNING ? TRUE : FALSE;
959         }
960         else {
961             g_bRescanServices = TRUE;
962         }
963         CloseServiceHandle(schSCManager);
964         return FALSE;
965
966     }
967
968     return FALSE;
969 }
970
971
972 BOOL FindRunningServices(void)
973 {
974     int i = 0;
975     DWORD dwPid;
976     BOOL rv = FALSE;
977     while (g_stServices[i].szServiceName != NULL)
978     {
979         if (!IsServiceRunning(g_stServices[i].szServiceName, 
980                               g_stServices[i].szComputerName, &dwPid)) {
981             dwPid = 0;
982         }
983         if (g_stServices[i].dwPid != dwPid) {
984             rv = TRUE;
985         }
986         g_stServices[i].dwPid = dwPid;
987         ++i;
988     }
989     return rv;
990 }
991
992
993 BOOL GetApacheServicesStatus()
994 {
995     CHAR szKey[MAX_PATH];
996     CHAR achKey[MAX_PATH];
997     CHAR szImagePath[MAX_PATH];
998     CHAR szBuf[MAX_PATH];
999     CHAR szTmp[MAX_PATH];
1000     HKEY hKey, hSubKey, hKeyRemote;
1001     DWORD retCode, rv, dwKeyType;
1002     DWORD dwBufLen = MAX_PATH;
1003     int i, stPos = 0;
1004     int computers = 0;
1005
1006     g_bRescanServices = FALSE;
1007
1008     am_ClearServicesSt();
1009     while (g_stComputers[computers].szComputerName != NULL) {
1010         hKeyRemote = g_stComputers[computers].hRegistry;
1011         retCode = RegOpenKeyEx(hKeyRemote,
1012                                "System\\CurrentControlSet\\Services\\",
1013                                0, KEY_READ, &hKey);
1014         if (retCode != ERROR_SUCCESS)
1015         {
1016             ErrorMessage(NULL, FALSE);
1017             return FALSE;
1018         }
1019         for (i = 0, retCode = ERROR_SUCCESS; retCode == ERROR_SUCCESS; i++)
1020         {
1021             retCode = RegEnumKey(hKey, i, achKey, MAX_PATH);
1022             if (retCode == ERROR_SUCCESS)
1023             {
1024                 lstrcpy(szKey, "System\\CurrentControlSet\\Services\\");
1025                 lstrcat(szKey, achKey);
1026
1027                 if (RegOpenKeyEx(hKeyRemote, szKey, 0, 
1028                                  KEY_QUERY_VALUE, &hSubKey) == ERROR_SUCCESS)
1029                 {
1030                     dwBufLen = MAX_PATH;
1031                     rv = RegQueryValueEx(hSubKey, "ImagePath", NULL,
1032                                          &dwKeyType, szImagePath, &dwBufLen);
1033
1034                     if (rv == ERROR_SUCCESS
1035                             && (dwKeyType == REG_SZ 
1036                              || dwKeyType == REG_EXPAND_SZ)
1037                             && dwBufLen)
1038                     {
1039                         lstrcpy(szBuf, szImagePath);
1040                         CharLower(szBuf);
1041                         /* the service name could be Apache*.exe */
1042                         if ((strstr(szBuf, "\\apache") != NULL)
1043                                 && strstr(szBuf, ".exe") 
1044                                 && (strstr(szBuf, "--ntservice") != NULL 
1045                                        || strstr(szBuf, "-k ") != NULL))
1046                         {
1047                             g_stServices[stPos].szServiceName = strdup(achKey);
1048                             g_stServices[stPos].szImagePath = 
1049                                                            strdup(szImagePath);
1050                             g_stServices[stPos].szComputerName = 
1051                                strdup(g_stComputers[computers].szComputerName);
1052                             dwBufLen = MAX_PATH;
1053                             if (RegQueryValueEx(hSubKey, "Description", NULL,
1054                                                 &dwKeyType, szBuf, &dwBufLen) 
1055                                     == ERROR_SUCCESS) {
1056                                 g_stServices[stPos].szDescription = 
1057                                                                  strdup(szBuf);
1058                             }
1059                             dwBufLen = MAX_PATH;
1060                             if (RegQueryValueEx(hSubKey, "DisplayName", NULL,
1061                                                 &dwKeyType, szBuf, &dwBufLen) 
1062                                     == ERROR_SUCCESS) 
1063                             {
1064                                 if (strcmp(g_stComputers[computers]
1065                                         .szComputerName, g_szLocalHost) != 0) 
1066                                 { 
1067                                     strcpy(szTmp, g_stComputers[computers]
1068                                                       .szComputerName + 2);
1069                                     strcat(szTmp, "@");
1070                                     strcat(szTmp, szBuf);
1071                                 }
1072                                 else {
1073                                     strcpy(szTmp, szBuf);
1074                                 }
1075                                 g_stServices[stPos].szDisplayName 
1076                                                         = strdup(szTmp);
1077
1078                             }
1079                             ++stPos;
1080                             if (stPos >= MAX_APACHE_SERVICES) {
1081                                 retCode = !ERROR_SUCCESS;
1082                             }
1083                         }
1084                     }
1085                     RegCloseKey(hSubKey);
1086                 }
1087             }
1088         }
1089         ++computers;
1090     }
1091     RegCloseKey(hKey);
1092     FindRunningServices();
1093     return TRUE;
1094 }
1095
1096
1097 LRESULT CALLBACK ConnectDlgProc(HWND hDlg, UINT message, 
1098                                 WPARAM wParam, LPARAM lParam)
1099 {
1100     CHAR szCmp[MAX_COMPUTERNAME_LENGTH+4];
1101     switch (message) 
1102     { 
1103     case WM_INITDIALOG: 
1104         ShowWindow(hDlg, SW_HIDE);
1105         g_hwndConnectDlg = hDlg;
1106         CenterWindow(hDlg);
1107         ShowWindow(hDlg, SW_SHOW);
1108         SetFocus(GetDlgItem(hDlg, IDC_COMPUTER));
1109         return TRUE;
1110
1111     case WM_COMMAND: 
1112         switch (LOWORD(wParam)) 
1113         { 
1114         case IDOK: 
1115             memset(szCmp, 0, MAX_COMPUTERNAME_LENGTH+4);
1116             strcpy(szCmp, "\\\\");
1117             SendMessage(GetDlgItem(hDlg, IDC_COMPUTER), WM_GETTEXT, 
1118                         (WPARAM) MAX_COMPUTERNAME_LENGTH, 
1119                         (LPARAM) szCmp+2); 
1120
1121             strupr(szCmp);
1122             if (strlen(szCmp) < 3) {
1123                 EndDialog(hDlg, TRUE); 
1124                 return TRUE;
1125             }
1126             am_ConnectComputer(szCmp);
1127             SendMessage(g_hwndMain, WM_TIMER, WM_TIMER_RESCAN, 0);
1128
1129         case IDCANCEL:
1130             EndDialog(hDlg, TRUE); 
1131             return TRUE; 
1132
1133         case IDC_LBROWSE:
1134         {
1135             BROWSEINFO bi;
1136             ITEMIDLIST *il;
1137             LPMALLOC pMalloc;
1138             memset(&bi, 0, sizeof(BROWSEINFO));
1139             SHGetSpecialFolderLocation(hDlg, CSIDL_NETWORK, &il);
1140
1141             bi.lpszTitle      = "ApacheMonitor :\nSelect Network Computer!";
1142             bi.pszDisplayName = szCmp;
1143             bi.hwndOwner =      hDlg;
1144             bi.ulFlags =        BIF_BROWSEFORCOMPUTER;
1145             bi.lpfn =           NULL;
1146             bi.lParam =         0;
1147             bi.iImage =         0;
1148             bi.pidlRoot =       il;
1149
1150             if (SHBrowseForFolder(&bi) != NULL) {
1151                 SendMessage(GetDlgItem(hDlg, IDC_COMPUTER), 
1152                             WM_SETTEXT, 
1153                             (WPARAM) NULL, (LPARAM) szCmp); 
1154             }
1155             if (SHGetMalloc(&pMalloc)) {
1156                 pMalloc->lpVtbl->Free(pMalloc, il);
1157                 pMalloc->lpVtbl->Release(pMalloc);
1158             }
1159             return TRUE;
1160         }
1161         }
1162         break;
1163
1164     case WM_QUIT:
1165     case WM_CLOSE: 
1166         EndDialog(hDlg, TRUE);
1167         return TRUE;
1168
1169     default:
1170         return FALSE;
1171     }
1172     return FALSE;
1173
1174 }
1175
1176
1177 LRESULT CALLBACK ServiceDlgProc(HWND hDlg, UINT message, 
1178                                 WPARAM wParam, LPARAM lParam)
1179 {
1180     CHAR szBuf[MAX_PATH]; 
1181     HWND hListBox;
1182     static HWND hStatusBar; 
1183     TEXTMETRIC tm; 
1184     int i, y; 
1185     HDC hdcMem; 
1186     RECT rcBitmap; 
1187     UINT nItem;
1188     LPMEASUREITEMSTRUCT lpmis; 
1189     LPDRAWITEMSTRUCT lpdis; 
1190
1191     memset(szBuf, 0, MAX_PATH);
1192     switch (message) 
1193     {
1194     case WM_INITDIALOG: 
1195         ShowWindow(hDlg, SW_HIDE);
1196         g_hwndServiceDlg = hDlg;
1197         SetWindowText(hDlg, g_szTitle);
1198         Button_Enable(GetDlgItem(hDlg, IDC_SSTART), FALSE);
1199         Button_Enable(GetDlgItem(hDlg, IDC_SSTOP), FALSE);
1200         Button_Enable(GetDlgItem(hDlg, IDC_SRESTART), FALSE);
1201         Button_Enable(GetDlgItem(hDlg, IDC_SDISCONN), FALSE);
1202         SetWindowText(GetDlgItem(hDlg, IDC_SSTART), 
1203                       g_lpMsg[IDS_MSG_SSTART - IDS_MSG_FIRST]);
1204         SetWindowText(GetDlgItem(hDlg, IDC_SSTOP), 
1205                       g_lpMsg[IDS_MSG_SSTOP - IDS_MSG_FIRST]);
1206         SetWindowText(GetDlgItem(hDlg, IDC_SRESTART), 
1207                       g_lpMsg[IDS_MSG_SRESTART - IDS_MSG_FIRST]);
1208         SetWindowText(GetDlgItem(hDlg, IDC_SMANAGER), 
1209                       g_lpMsg[IDS_MSG_SERVICES - IDS_MSG_FIRST]);
1210         SetWindowText(GetDlgItem(hDlg, IDC_SCONNECT), 
1211                       g_lpMsg[IDS_MSG_CONNECT - IDS_MSG_FIRST]);
1212         SetWindowText(GetDlgItem(hDlg, IDC_SEXIT), 
1213                       g_lpMsg[IDS_MSG_MNUEXIT - IDS_MSG_FIRST]);
1214         if (g_dwOSVersion < OS_VERSION_WINNT)
1215         {
1216             ShowWindow(GetDlgItem(hDlg, IDC_SMANAGER), SW_HIDE);
1217             ShowWindow(GetDlgItem(hDlg, IDC_SCONNECT), SW_HIDE);
1218             ShowWindow(GetDlgItem(hDlg, IDC_SDISCONN), SW_HIDE);
1219         }
1220         hListBox = GetDlgItem(hDlg, IDL_SERVICES); 
1221         g_hwndStdoutList = GetDlgItem(hDlg, IDL_STDOUT);
1222         hStatusBar = CreateStatusWindow(0x0800 /* SBT_TOOLTIPS */
1223                                       | WS_CHILD | WS_VISIBLE,
1224                                         "", hDlg, IDC_STATBAR);
1225         if (GetApacheServicesStatus())
1226         {
1227             i = 0;
1228             while (g_stServices[i].szServiceName != NULL)
1229             {
1230                 addListBoxItem(hListBox, g_stServices[i].szDisplayName,
1231                                g_stServices[i].dwPid == 0 ? g_hBmpStop 
1232                                                           : g_hBmpStart);
1233                 ++i;
1234             }
1235         }
1236         CenterWindow(hDlg);
1237         ShowWindow(hDlg, SW_SHOW);
1238         SetFocus(hListBox); 
1239         SendMessage(hListBox, LB_SETCURSEL, 0, 0); 
1240         return TRUE;
1241         break;
1242
1243     case WM_MANAGEMESSAGE:
1244         ApacheManageService(g_stServices[LOWORD(wParam)].szServiceName,
1245                     g_stServices[LOWORD(wParam)].szImagePath,
1246                     g_stServices[LOWORD(wParam)].szComputerName,
1247                     LOWORD(lParam));
1248
1249         return TRUE;
1250         break;
1251
1252     case WM_UPDATEMESSAGE:
1253         hListBox = GetDlgItem(hDlg, IDL_SERVICES); 
1254         SendMessage(hListBox, LB_RESETCONTENT, 0, 0); 
1255         SendMessage(hStatusBar, SB_SETTEXT, 0, (LPARAM)"");
1256         Button_Enable(GetDlgItem(hDlg, IDC_SSTART), FALSE);
1257         Button_Enable(GetDlgItem(hDlg, IDC_SSTOP), FALSE);
1258         Button_Enable(GetDlgItem(hDlg, IDC_SRESTART), FALSE);
1259         Button_Enable(GetDlgItem(hDlg, IDC_SDISCONN), FALSE);
1260         i = 0;
1261         while (g_stServices[i].szServiceName != NULL)
1262         {
1263             addListBoxItem(hListBox, g_stServices[i].szDisplayName, 
1264                 g_stServices[i].dwPid == 0 ? g_hBmpStop : g_hBmpStart);
1265             ++i;
1266         }
1267         SendMessage(hListBox, LB_SETCURSEL, 0, 0); 
1268         /* Dirty hack to bring the window to the foreground */
1269         SetWindowPos(hDlg, HWND_TOPMOST, 0, 0, 0, 0,
1270                                 SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);
1271         SetWindowPos(hDlg, HWND_NOTOPMOST, 0, 0, 0, 0,
1272                                 SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);
1273         SetFocus(hListBox); 
1274         return TRUE;
1275         break;
1276
1277     case WM_MEASUREITEM: 
1278         lpmis = (LPMEASUREITEMSTRUCT) lParam; 
1279         lpmis->itemHeight = YBITMAP; 
1280         return TRUE; 
1281
1282     case WM_SETCURSOR:
1283         if (g_bConsoleRun) {
1284             SetCursor(g_hCursorHourglass);
1285         }
1286         else {
1287             SetCursor(g_hCursorArrow);
1288         }
1289         return TRUE;
1290
1291     case WM_DRAWITEM: 
1292         lpdis = (LPDRAWITEMSTRUCT) lParam; 
1293         if (lpdis->itemID == -1) { 
1294             break; 
1295         } 
1296         switch (lpdis->itemAction) 
1297         { 
1298         case ODA_SELECT: 
1299         case ODA_DRAWENTIRE: 
1300             g_hBmpPicture = (HBITMAP)SendMessage(lpdis->hwndItem, 
1301                                                  LB_GETITEMDATA,
1302                                                  lpdis->itemID, (LPARAM) 0);
1303
1304             hdcMem = CreateCompatibleDC(lpdis->hDC); 
1305             g_hBmpOld = SelectObject(hdcMem, g_hBmpPicture); 
1306
1307             BitBlt(lpdis->hDC, lpdis->rcItem.left, lpdis->rcItem.top,
1308                    lpdis->rcItem.right - lpdis->rcItem.left,
1309                    lpdis->rcItem.bottom - lpdis->rcItem.top,
1310                    hdcMem, 0, 0, SRCCOPY);
1311             SendMessage(lpdis->hwndItem, LB_GETTEXT, 
1312                         lpdis->itemID, (LPARAM) szBuf); 
1313
1314             GetTextMetrics(lpdis->hDC, &tm);
1315             y = (lpdis->rcItem.bottom + lpdis->rcItem.top - tm.tmHeight) / 2;
1316
1317             SelectObject(hdcMem, g_hBmpOld); 
1318             DeleteDC(hdcMem); 
1319
1320             rcBitmap.left = lpdis->rcItem.left + XBITMAP + 2; 
1321             rcBitmap.top = lpdis->rcItem.top; 
1322             rcBitmap.right = lpdis->rcItem.right; 
1323             rcBitmap.bottom = lpdis->rcItem.top + YBITMAP; 
1324
1325             if (lpdis->itemState & ODS_SELECTED) 
1326             { 
1327                 if (g_hBmpPicture == g_hBmpStop)
1328                 {
1329                     Button_Enable(GetDlgItem(hDlg, IDC_SSTART), TRUE);
1330                     Button_Enable(GetDlgItem(hDlg, IDC_SSTOP), FALSE);
1331                     Button_Enable(GetDlgItem(hDlg, IDC_SRESTART), FALSE);
1332                 }
1333                 else if (g_hBmpPicture == g_hBmpStart) 
1334                 {
1335                     Button_Enable(GetDlgItem(hDlg, IDC_SSTART), FALSE);
1336                     Button_Enable(GetDlgItem(hDlg, IDC_SSTOP), TRUE);
1337                     Button_Enable(GetDlgItem(hDlg, IDC_SRESTART), TRUE);
1338                 }
1339                 else {
1340                     Button_Enable(GetDlgItem(hDlg, IDC_SSTART), FALSE);
1341                     Button_Enable(GetDlgItem(hDlg, IDC_SSTOP), FALSE);
1342                     Button_Enable(GetDlgItem(hDlg, IDC_SRESTART), FALSE);
1343                 }
1344                 if (strcmp(g_stServices[lpdis->itemID].szComputerName, 
1345                            g_szLocalHost) == 0) {
1346                     Button_Enable(GetDlgItem(hDlg, IDC_SDISCONN), FALSE);
1347                 }
1348                 else {
1349                     Button_Enable(GetDlgItem(hDlg, IDC_SDISCONN), TRUE);
1350                 }
1351
1352                 if (g_stServices[lpdis->itemID].szDescription) {
1353                     SendMessage(hStatusBar, SB_SETTEXT, 0, 
1354                             (LPARAM)g_stServices[lpdis->itemID].szDescription);
1355                 }
1356                 else {
1357                     SendMessage(hStatusBar, SB_SETTEXT, 0, (LPARAM)"");
1358                 }
1359                 SetTextColor(lpdis->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT)); 
1360                 SetBkColor(lpdis->hDC, GetSysColor(COLOR_HIGHLIGHT)); 
1361                 FillRect(lpdis->hDC, &rcBitmap, (HBRUSH)(COLOR_HIGHLIGHTTEXT));
1362             } 
1363             else
1364             {
1365                SetTextColor(lpdis->hDC, GetSysColor(COLOR_MENUTEXT)); 
1366                SetBkColor(lpdis->hDC, GetSysColor(COLOR_WINDOW)); 
1367                FillRect(lpdis->hDC, &rcBitmap, (HBRUSH)(COLOR_WINDOW+1)); 
1368             }
1369             TextOut(lpdis->hDC, XBITMAP + 6, y, szBuf, strlen(szBuf)); 
1370             break; 
1371
1372         case ODA_FOCUS: 
1373             break; 
1374         } 
1375         return TRUE;
1376     case WM_COMMAND: 
1377         switch (LOWORD(wParam)) 
1378         { 
1379         case IDL_SERVICES:
1380             switch (HIWORD(wParam))
1381             {
1382             case LBN_DBLCLK:
1383                 /* if started then stop, if stopped then start */
1384                 hListBox = GetDlgItem(hDlg, IDL_SERVICES); 
1385                 nItem = SendMessage(hListBox, LB_GETCURSEL, 0, 0);
1386                 if (nItem != LB_ERR)
1387                 {
1388                     g_hBmpPicture = (HBITMAP)SendMessage(hListBox, 
1389                                                          LB_GETITEMDATA,
1390                                                          nItem, (LPARAM) 0);
1391                     if (g_hBmpPicture == g_hBmpStop) {
1392                         SendMessage(hDlg, WM_MANAGEMESSAGE, nItem, 
1393                                     SERVICE_CONTROL_CONTINUE);
1394                     }
1395                     else {
1396                         SendMessage(hDlg, WM_MANAGEMESSAGE, nItem, 
1397                                     SERVICE_CONTROL_STOP);
1398                     }
1399
1400                 }
1401                 return TRUE;
1402             }
1403             break;
1404
1405         case IDOK: 
1406             EndDialog(hDlg, TRUE); 
1407             return TRUE; 
1408
1409         case IDC_SSTART: 
1410             Button_Enable(GetDlgItem(hDlg, IDC_SSTART), FALSE);
1411             hListBox = GetDlgItem(hDlg, IDL_SERVICES); 
1412             nItem = SendMessage(hListBox, LB_GETCURSEL, 0, 0); 
1413             if (nItem != LB_ERR) {
1414                 SendMessage(hDlg, WM_MANAGEMESSAGE, nItem, 
1415                             SERVICE_CONTROL_CONTINUE);
1416             }
1417             Button_Enable(GetDlgItem(hDlg, IDC_SSTART), TRUE);
1418             return TRUE;
1419
1420         case IDC_SSTOP: 
1421             Button_Enable(GetDlgItem(hDlg, IDC_SSTOP), FALSE);
1422             hListBox = GetDlgItem(hDlg, IDL_SERVICES); 
1423             nItem = SendMessage(hListBox, LB_GETCURSEL, 0, 0); 
1424             if (nItem != LB_ERR) {
1425                 SendMessage(hDlg, WM_MANAGEMESSAGE, nItem, 
1426                             SERVICE_CONTROL_STOP);
1427             }
1428             Button_Enable(GetDlgItem(hDlg, IDC_SSTOP), TRUE);
1429             return TRUE;
1430
1431         case IDC_SRESTART: 
1432             Button_Enable(GetDlgItem(hDlg, IDC_SRESTART), FALSE);
1433             hListBox = GetDlgItem(hDlg, IDL_SERVICES); 
1434             nItem = SendMessage(hListBox, LB_GETCURSEL, 0, 0); 
1435             if (nItem != LB_ERR) {
1436                 SendMessage(hDlg, WM_MANAGEMESSAGE, nItem, 
1437                             SERVICE_APACHE_RESTART);
1438             }
1439             Button_Enable(GetDlgItem(hDlg, IDC_SRESTART), TRUE);
1440             return TRUE;
1441
1442         case IDC_SMANAGER: 
1443             if (g_dwOSVersion >= OS_VERSION_WIN2K) {
1444                 ShellExecute(hDlg, "open", "services.msc", "/s",
1445                              NULL, SW_NORMAL);
1446             }
1447             else {
1448                 WinExec("Control.exe SrvMgr.cpl Services", SW_NORMAL);
1449             }
1450             return TRUE;
1451
1452         case IDC_SEXIT: 
1453             EndDialog(hDlg, TRUE);
1454             SendMessage(g_hwndMain, WM_COMMAND, (WPARAM)IDM_EXIT, 0);
1455             return TRUE;
1456
1457         case IDC_SCONNECT: 
1458             DialogBox(g_hInstance, MAKEINTRESOURCE(IDD_DLGCONNECT),
1459                       hDlg, (DLGPROC)ConnectDlgProc);
1460             return TRUE;
1461
1462         case IDC_SDISCONN: 
1463             hListBox = GetDlgItem(hDlg, IDL_SERVICES); 
1464             nItem = SendMessage(hListBox, LB_GETCURSEL, 0, 0); 
1465             if (nItem != LB_ERR) {
1466                 am_DisconnectComputer(g_stServices[nItem].szComputerName);
1467                 SendMessage(g_hwndMain, WM_TIMER, WM_TIMER_RESCAN, 0);
1468             }
1469             return TRUE;
1470         }
1471         break;
1472
1473     case WM_SIZE:
1474         switch (LOWORD(wParam)) 
1475         { 
1476         case SIZE_MINIMIZED:
1477             EndDialog(hDlg, TRUE); 
1478             return TRUE; 
1479             break;
1480         }
1481         break;
1482
1483     case WM_QUIT:
1484     case WM_CLOSE: 
1485         EndDialog(hDlg, TRUE);
1486         return TRUE;
1487
1488     default:
1489         return FALSE;
1490     }
1491     return FALSE;
1492 }
1493
1494
1495 LRESULT CALLBACK WndProc(HWND hWnd, UINT message,
1496                           WPARAM wParam, LPARAM lParam)
1497 {
1498     if (message == g_bUiTaskbarCreated)
1499     {
1500         /* restore the tray icon on shell restart */
1501         ShowNotifyIcon(hWnd, NIM_ADD);
1502         return DefWindowProc(hWnd, message, wParam, lParam);
1503     }
1504     switch (message) 
1505     {
1506     case WM_CREATE:
1507         GetApacheServicesStatus();
1508         ShowNotifyIcon(hWnd, NIM_ADD);
1509         SetTimer(hWnd, WM_TIMER_REFRESH, REFRESH_TIME, NULL);
1510         SetTimer(hWnd, WM_TIMER_RESCAN,  RESCAN_TIME, NULL);
1511         break;
1512
1513     case WM_TIMER:
1514         switch (wParam)
1515         {
1516         case WM_TIMER_RESCAN:
1517         {
1518             int nPrev = 0, nNew = 0;
1519             EnterCriticalSection(&g_stcSection);
1520             if (FindRunningServices() || g_bRescanServices)
1521             {
1522                 ShowNotifyIcon(hWnd, NIM_MODIFY);
1523                 if (g_hwndServiceDlg)
1524                     PostMessage(g_hwndServiceDlg, WM_UPDATEMESSAGE, 0, 0);
1525             }
1526             /* check if services list changed */
1527             while (g_stServices[nPrev].szServiceName != NULL)
1528                 ++nPrev;
1529             GetApacheServicesStatus();
1530             while (g_stServices[nNew].szServiceName != NULL)
1531                 ++nNew;
1532             if (nPrev != nNew)
1533             {
1534                 ShowNotifyIcon(hWnd, NIM_MODIFY);
1535                 if (g_hwndServiceDlg) {
1536                     PostMessage(g_hwndServiceDlg, WM_UPDATEMESSAGE, 0, 0);
1537                 }
1538             }
1539             LeaveCriticalSection(&g_stcSection);
1540             break;
1541         }
1542
1543         case WM_TIMER_REFRESH:
1544         {
1545             int nPrev = 0, nNew = 0;
1546             EnterCriticalSection(&g_stcSection);
1547             if (g_bRescanServices)
1548             {
1549                 GetApacheServicesStatus();
1550                 ShowNotifyIcon(hWnd, NIM_MODIFY);
1551                 if (g_hwndServiceDlg) {
1552                     PostMessage(g_hwndServiceDlg, WM_UPDATEMESSAGE, 0, 0);
1553                 }
1554             }
1555             else if (FindRunningServices())
1556             {
1557                 ShowNotifyIcon(hWnd, NIM_MODIFY);
1558                 if (g_hwndServiceDlg) {
1559                     PostMessage(g_hwndServiceDlg, WM_UPDATEMESSAGE, 0, 0);
1560                 }
1561             }
1562             LeaveCriticalSection(&g_stcSection);
1563             break;
1564         }
1565         }
1566         break;
1567
1568     case WM_QUIT:
1569         ShowNotifyIcon(hWnd, NIM_DELETE);
1570         break;
1571
1572     case WM_TRAYMESSAGE:
1573         switch (lParam)
1574         {
1575         case WM_LBUTTONDBLCLK:
1576             if (!g_bDlgServiceOn)
1577             {
1578                 g_bDlgServiceOn = TRUE;
1579                 DialogBox(g_hInstance, MAKEINTRESOURCE(IDD_DLGSERVICES),
1580                           hWnd, (DLGPROC)ServiceDlgProc);
1581                 g_bDlgServiceOn = FALSE;
1582                 g_hwndServiceDlg = NULL;
1583             }
1584             else if (IsWindow(g_hwndServiceDlg))
1585             {
1586                 /* Dirty hack to bring the window to the foreground */
1587                 SetWindowPos(g_hwndServiceDlg, HWND_TOPMOST, 0, 0, 0, 0,
1588                              SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);
1589                 SetWindowPos(g_hwndServiceDlg, HWND_NOTOPMOST, 0, 0, 0, 0,
1590                              SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);
1591                 SetFocus(g_hwndServiceDlg);
1592             }
1593             break;
1594
1595         case WM_LBUTTONUP:
1596             ShowTryServicesMenu(hWnd);
1597             break;
1598
1599         case WM_RBUTTONUP:
1600             ShowTryPopupMenu(hWnd);
1601             break;
1602         }
1603         break;
1604
1605     case WM_COMMAND:
1606         if ((LOWORD(wParam) & IDM_SM_START) == IDM_SM_START)
1607         {
1608             ApacheManageService(g_stServices[LOWORD(wParam) 
1609                                            - IDM_SM_START].szServiceName,
1610                                 g_stServices[LOWORD(wParam) 
1611                                            - IDM_SM_START].szImagePath,
1612                                 g_stServices[LOWORD(wParam) 
1613                                            - IDM_SM_START].szComputerName,
1614                                 SERVICE_CONTROL_CONTINUE);
1615             return TRUE;
1616         }
1617         else if ((LOWORD(wParam) & IDM_SM_STOP) == IDM_SM_STOP)
1618         {
1619             ApacheManageService(g_stServices[LOWORD(wParam) 
1620                                            - IDM_SM_STOP].szServiceName,
1621                                 g_stServices[LOWORD(wParam) 
1622                                            - IDM_SM_STOP].szImagePath,
1623                                 g_stServices[LOWORD(wParam) 
1624                                            - IDM_SM_STOP].szComputerName,
1625                                 SERVICE_CONTROL_STOP);
1626             return TRUE;
1627         }
1628         else if ((LOWORD(wParam) & IDM_SM_RESTART) == IDM_SM_RESTART)
1629         {
1630             ApacheManageService(g_stServices[LOWORD(wParam) 
1631                                            - IDM_SM_RESTART].szServiceName,
1632                                 g_stServices[LOWORD(wParam) 
1633                                            - IDM_SM_RESTART].szImagePath,
1634                                 g_stServices[LOWORD(wParam) 
1635                                            - IDM_SM_RESTART].szComputerName,
1636                                 SERVICE_APACHE_RESTART);
1637             return TRUE;
1638         }
1639         switch (LOWORD(wParam))
1640         {
1641         case IDM_RESTORE:
1642             if (!g_bDlgServiceOn)
1643             {
1644                 g_bDlgServiceOn = TRUE;
1645                 DialogBox(g_hInstance, MAKEINTRESOURCE(IDD_DLGSERVICES),
1646                           hWnd, (DLGPROC)ServiceDlgProc);
1647                 g_bDlgServiceOn = FALSE;
1648                 g_hwndServiceDlg = NULL;
1649             }
1650             else if (IsWindow(g_hwndServiceDlg)) {
1651                 SetFocus(g_hwndServiceDlg);
1652             }
1653             break;
1654
1655         case IDC_SMANAGER: 
1656             if (g_dwOSVersion >= OS_VERSION_WIN2K) {
1657                 ShellExecute(NULL, "open", "services.msc", "/s",
1658                              NULL, SW_NORMAL);
1659             }
1660             else {
1661                 WinExec("Control.exe SrvMgr.cpl Services", SW_NORMAL);
1662             }
1663             return TRUE;
1664
1665         case IDM_EXIT:
1666             ShowNotifyIcon(hWnd, NIM_DELETE);
1667             PostQuitMessage(0);
1668             return TRUE;
1669         }
1670
1671     default:
1672         return DefWindowProc(hWnd, message, wParam, lParam);
1673     }
1674
1675     return FALSE;
1676 }
1677
1678
1679 /* Create main invisible window */
1680 HWND CreateMainWindow(HINSTANCE hInstance)
1681 {
1682     HWND hWnd = NULL;
1683     WNDCLASSEX wcex;
1684
1685     if (!GetSystemOSVersion(&g_dwOSVersion))
1686     {
1687         ErrorMessage(NULL, TRUE);
1688         return hWnd;
1689     }
1690
1691     wcex.cbSize = sizeof(WNDCLASSEX); 
1692
1693     wcex.style          = CS_HREDRAW | CS_VREDRAW;
1694     wcex.lpfnWndProc    = (WNDPROC)WndProc;
1695     wcex.cbClsExtra     = 0;
1696     wcex.cbWndExtra     = 0;
1697     wcex.hInstance      = hInstance;
1698     wcex.hIcon   = (HICON)LoadImage(hInstance, MAKEINTRESOURCE(IDI_APSRVMON),
1699                                     IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR);
1700     wcex.hCursor        = g_hCursorArrow;
1701     wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
1702     wcex.lpszMenuName   = 0;
1703     wcex.lpszClassName  = g_szWindowClass;
1704     wcex.hIconSm = (HICON)LoadImage(hInstance, MAKEINTRESOURCE(IDI_APSRVMON),
1705                                     IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
1706
1707     if (RegisterClassEx(&wcex)) {
1708         hWnd = CreateWindow(g_szWindowClass, g_szTitle,
1709                             0, 0, 0, 0, 0,
1710                             NULL, NULL, hInstance, NULL);
1711     }
1712     return hWnd;
1713
1714 }
1715
1716
1717 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
1718                    LPSTR lpCmdLine, int nCmdShow)
1719 {
1720     CHAR szTmp[MAX_LOADSTRING];
1721     CHAR szCmp[MAX_COMPUTERNAME_LENGTH+4];
1722     MSG msg;
1723     /* single instance mutex */
1724     HANDLE hMutex;
1725     int i;
1726     DWORD d;
1727
1728     g_LangID = GetUserDefaultLangID();
1729     if ((g_LangID & 0xFF) != LANG_ENGLISH) {
1730         g_LangID = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
1731     }
1732     for (i = IDS_MSG_FIRST; i <= IDS_MSG_LAST; ++i) {
1733         LoadString(hInstance, i, szTmp, MAX_LOADSTRING);
1734         g_lpMsg[i - IDS_MSG_FIRST] = strdup(szTmp);
1735     }
1736     LoadString(hInstance, IDS_APMONITORTITLE, szTmp, MAX_LOADSTRING);
1737     d = MAX_COMPUTERNAME_LENGTH+1;
1738     strcpy(szCmp, "\\\\");
1739     GetComputerName(szCmp + 2, &d);
1740     strupr(szCmp);
1741     g_szLocalHost = strdup(szCmp);
1742
1743     memset(g_stComputers, 0, sizeof(ST_MONITORED_COMP) * MAX_APACHE_COMPUTERS);
1744     g_stComputers[0].szComputerName = strdup(szCmp);
1745     g_stComputers[0].hRegistry = HKEY_LOCAL_MACHINE;
1746     g_szTitle = strdup(szTmp);
1747     LoadString(hInstance, IDS_APMONITORCLASS, szTmp, MAX_LOADSTRING);
1748     g_szWindowClass = strdup(szTmp);
1749
1750     g_icoStop          = LoadImage(hInstance, MAKEINTRESOURCE(IDI_ICOSTOP),
1751                                    IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
1752     g_icoRun           = LoadImage(hInstance, MAKEINTRESOURCE(IDI_ICORUN),
1753                                    IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
1754     g_hCursorHourglass = LoadImage(NULL, MAKEINTRESOURCE(OCR_WAIT), 
1755                                    IMAGE_CURSOR, LR_DEFAULTSIZE, 
1756                                    LR_DEFAULTSIZE, LR_SHARED);
1757     g_hCursorArrow     = LoadImage(NULL, MAKEINTRESOURCE(OCR_NORMAL), 
1758                                    IMAGE_CURSOR, LR_DEFAULTSIZE, 
1759                                    LR_DEFAULTSIZE, LR_SHARED);
1760     g_hBmpStart        = LoadImage(hInstance, MAKEINTRESOURCE(IDB_BMPRUN),
1761                                    IMAGE_BITMAP, XBITMAP, YBITMAP, 
1762                                    LR_DEFAULTCOLOR);
1763     g_hBmpStop         = LoadImage(hInstance, MAKEINTRESOURCE(IDB_BMPSTOP),
1764                                    IMAGE_BITMAP, XBITMAP, YBITMAP, 
1765                                    LR_DEFAULTCOLOR);
1766
1767     hMutex = CreateMutex(NULL, FALSE, "APSRVMON_MUTEX");
1768     if ((hMutex == NULL) || (GetLastError() == ERROR_ALREADY_EXISTS))
1769     {
1770         ErrorMessage(g_lpMsg[IDS_MSG_APPRUNNING - IDS_MSG_FIRST], FALSE);
1771         if (hMutex) {
1772             CloseHandle(hMutex);
1773         }
1774         return 0;
1775     }
1776
1777     memset(g_stServices, 0, sizeof(ST_APACHE_SERVICE) * MAX_APACHE_SERVICES);
1778     CoInitialize(NULL);
1779     InitCommonControls();
1780     g_hInstance = hInstance;
1781     g_hwndMain = CreateMainWindow(hInstance);
1782     g_bUiTaskbarCreated = RegisterWindowMessage("TaskbarCreated");
1783     InitializeCriticalSection(&g_stcSection);
1784     g_hwndServiceDlg = NULL;
1785     if (g_hwndMain != NULL)
1786     {
1787         while (GetMessage(&msg, NULL, 0, 0) == TRUE) 
1788         {
1789             TranslateMessage(&msg);
1790             DispatchMessage(&msg);
1791         }
1792         am_ClearServicesSt();
1793     }
1794     am_ClearComputersSt();
1795     DeleteCriticalSection(&g_stcSection);
1796     CloseHandle(hMutex);
1797     DestroyIcon(g_icoStop);
1798     DestroyIcon(g_icoRun);
1799     DestroyCursor(g_hCursorHourglass);
1800     DestroyCursor(g_hCursorArrow);
1801     DeleteObject(g_hBmpStart); 
1802     DeleteObject(g_hBmpStop); 
1803     CoUninitialize();
1804     return 0;
1805 }