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