]> granicus.if.org Git - apache/blobdiff - support/win32/ApacheMonitor.c
cppCheck: unreadVariable - 'serviceFlag' is not used in the function, so remove it
[apache] / support / win32 / ApacheMonitor.c
index 927d14008df0b1f53cd4d67a23b16a334e4e7874..c6021f3b19b0b728599aaf045356e9b63722abbc 100644 (file)
-/* ====================================================================
- * The Apache Software License, Version 1.1
- *
- * Copyright (c) 2000 The Apache Software Foundation.  All rights
- * reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * 3. The end-user documentation included with the redistribution,
- *    if any, must include the following acknowledgment:
- *       "This product includes software developed by the
- *        Apache Software Foundation (http://www.apache.org/)."
- *    Alternately, this acknowledgment may appear in the software itself,
- *    if and wherever such third-party acknowledgments normally appear.
- *
- * 4. The names "Apache" and "Apache Software Foundation" must
- *    not be used to endorse or promote products derived from this
- *    software without prior written permission. For written
- *    permission, please contact apache@apache.org.
- *
- * 5. Products derived from this software may not be called "Apache",
- *    nor may "Apache" appear in their name, without prior written
- *    permission of the Apache Software Foundation.
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
  *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation.  For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Portions of this software are based upon public domain software
- * originally written at the National Center for Supercomputing Applications,
- * University of Illinois, Urbana-Champaign.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  */
 
 /* ====================================================================
  * ApacheMonitor.c Simple program to manage and monitor Apache services.
  *
- * Contributed by Mladen Turk <mturk@mappingsoft.com>
+ * Contributed by Mladen Turk <mturk mappingsoft.com>
  *
  * 05 Aug 2001
- * ==================================================================== 
+ * ====================================================================
  */
 
-#define _WIN32_WINNT 0x0400
+#define _WIN32_WINNT 0x0500
 #ifndef STRICT
 #define STRICT
 #endif
+#ifndef OEMRESOURCE
+#define OEMRESOURCE
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+#define _CRT_SECURE_NO_DEPRECATE
+#endif
 
 #include <windows.h>
 #include <windowsx.h>
 #include <commctrl.h>
+#include <objbase.h>
+#include <shlobj.h>
 #include <stdlib.h>
 #include <stdio.h>
+#include <WtsApi32.h>
+#include <tchar.h>
 #include "ApacheMonitor.h"
 
+#ifndef AM_STRINGIFY
+/** Properly quote a value as a string in the C preprocessor */
+#define AM_STRINGIFY(n) AM_STRINGIFY_HELPER(n)
+/** Helper macro for AM_STRINGIFY */
+#define AM_STRINGIFY_HELPER(n) #n
+#endif
 
-#define OS_VERSION_WINNT    1
-#define OS_VERSION_WIN9X    2
+#define OS_VERSION_WINNT    2
 #define OS_VERSION_WIN2K    3
+
 /* Should be enough */
 #define MAX_APACHE_SERVICES 128
+#define MAX_APACHE_COMPUTERS 32
 
 #define WM_TRAYMESSAGE         (WM_APP+1)
 #define WM_UPDATEMESSAGE       (WM_USER+1)
+#define WM_MANAGEMESSAGE       (WM_USER+2)
 #define WM_TIMER_REFRESH       10
 #define WM_TIMER_RESCAN        11
 #define SERVICE_APACHE_RESTART 128
 #define XBITMAP                16
-#define YBITMAP                16 
+#define YBITMAP                16
 #define MAX_LOADSTRING         100
-#define REFRESH_TIME           1000           /* service refresh time (ms) */
-#define RESCAN_TIME            10000          /* registry rescan time (ms) */
+#define REFRESH_TIME           2000           /* service refresh time (ms) */
+#define RESCAN_TIME            20000          /* registry rescan time (ms) */
 
 typedef struct _st_APACHE_SERVICE
 {
-    LPSTR    szServiceName;
-    LPSTR    szDisplayName;
-    LPSTR    szDescription;
-    LPSTR    szImagePath;
+    LPTSTR   szServiceName;
+    LPTSTR   szDisplayName;
+    LPTSTR   szDescription;
+    LPTSTR   szImagePath;
+    LPTSTR   szComputerName;
     DWORD    dwPid;
 } ST_APACHE_SERVICE;
 
+typedef struct _st_MONITORED_COMPUTERS
+{
+    LPTSTR  szComputerName;
+    HKEY    hRegistry;
+} ST_MONITORED_COMP;
+
 /* Global variables */
-HINSTANCE         ap_hInstance = NULL;
-HWND              ap_hwndAboutDlg = NULL;
-TCHAR             szTitle[MAX_LOADSTRING];          /* The title bar text */
-TCHAR             szWindowClass[MAX_LOADSTRING];    /* Window Class Name  */
-HICON             ap_icoStop;
-HICON             ap_icoRun;
-UINT              ap_uiTaskbarCreated;
-DWORD             ap_OSVersion;
-BOOL              dlgAboutOn = FALSE;
-BOOL              dlgServiceOn = FALSE;
-BOOL              ap_consoleRun = FALSE;
-ST_APACHE_SERVICE ap_stServices[MAX_APACHE_SERVICES];
-
-HBITMAP           hbmpStart, hbmpStop; 
-HBITMAP           hbmpPicture, hbmpOld; 
-BOOL              ap_rescanServices;
-HWND              ap_hServiceDlg;
-HWND              ap_hMainWnd;
-HWND              ap_hStdoutWnd;
-HCURSOR           ap_cHourglass;
-HCURSOR           ap_cArrow;
-
-HANDLE            h_stdOutR;
-HANDLE            h_stdOutW;
-HANDLE            h_stdInR;
-HANDLE            h_stdInW;
-HANDLE            h_stdErr;
-PROCESS_INFORMATION ap_redirectedPI;
-
-void ap_ClearServicesSt()
+HINSTANCE         g_hInstance = NULL;
+TCHAR            *g_szTitle;          /* The title bar text */
+TCHAR            *g_szWindowClass;    /* Window Class Name  */
+HICON             g_icoStop;
+HICON             g_icoRun;
+UINT              g_bUiTaskbarCreated;
+DWORD             g_dwOSVersion;
+BOOL              g_bDlgServiceOn = FALSE;
+BOOL              g_bConsoleRun = FALSE;
+ST_APACHE_SERVICE g_stServices[MAX_APACHE_SERVICES];
+ST_MONITORED_COMP g_stComputers[MAX_APACHE_COMPUTERS];
+
+HBITMAP           g_hBmpStart, g_hBmpStop;
+HBITMAP           g_hBmpPicture, g_hBmpOld;
+BOOL              g_bRescanServices;
+HWND              g_hwndServiceDlg;
+HWND              g_hwndMain;
+HWND              g_hwndStdoutList;
+HWND              g_hwndConnectDlg;
+HCURSOR           g_hCursorHourglass;
+HCURSOR           g_hCursorArrow;
+
+LANGID            g_LangID;
+CRITICAL_SECTION  g_stcSection;
+LPTSTR            g_szLocalHost;
+
+/* locale language support */
+static TCHAR *g_lpMsg[IDS_MSG_LAST - IDS_MSG_FIRST + 1];
+
+
+void am_ClearServicesSt()
 {
     int i;
     for (i = 0; i < MAX_APACHE_SERVICES; i++)
     {
-        if (ap_stServices[i].szServiceName)
-            free(ap_stServices[i].szServiceName);
-        if (ap_stServices[i].szDisplayName)
-            free(ap_stServices[i].szDisplayName);
-        if (ap_stServices[i].szDescription)
-            free(ap_stServices[i].szDescription);
-        if (ap_stServices[i].szImagePath)
-            free(ap_stServices[i].szImagePath);
+        if (g_stServices[i].szServiceName) {
+            free(g_stServices[i].szServiceName);
+        }
+        if (g_stServices[i].szDisplayName) {
+            free(g_stServices[i].szDisplayName);
+        }
+        if (g_stServices[i].szDescription) {
+            free(g_stServices[i].szDescription);
+        }
+        if (g_stServices[i].szImagePath) {
+            free(g_stServices[i].szImagePath);
+        }
+        if (g_stServices[i].szComputerName) {
+            free(g_stServices[i].szComputerName);
+        }
+
+    }
+    memset(g_stServices, 0, sizeof(ST_APACHE_SERVICE) * MAX_APACHE_SERVICES);
+
+}
+
+
+void am_ClearComputersSt()
+{
+    int i;
+    for (i = 0; i < MAX_APACHE_COMPUTERS; i++) {
+        if (g_stComputers[i].szComputerName) {
+            free(g_stComputers[i].szComputerName);
+            RegCloseKey(g_stComputers[i].hRegistry);
+        }
+    }
+    memset(g_stComputers, 0, sizeof(ST_MONITORED_COMP) * MAX_APACHE_COMPUTERS);
+
+}
+
+
+BOOL am_IsComputerConnected(LPTSTR szComputerName)
+{
+    int i = 0;
+    while (g_stComputers[i].szComputerName != NULL) {
+        if (_tcscmp(g_stComputers[i].szComputerName, szComputerName) == 0) {
+            return TRUE;
+        }
+        ++i;
+    }
+    return FALSE;
+}
+
+
+void am_DisconnectComputer(LPTSTR szComputerName)
+{
+    int i = 0, j;
+    while (g_stComputers[i].szComputerName != NULL) {
+        if (_tcscmp(g_stComputers[i].szComputerName, szComputerName) == 0) {
+            break;
+        }
+        ++i;
+    }
+    if (g_stComputers[i].szComputerName != NULL) {
+        free(g_stComputers[i].szComputerName);
+        RegCloseKey(g_stComputers[i].hRegistry);
+        for (j = i; j < MAX_APACHE_COMPUTERS - 1; j++) {
+            g_stComputers[j].szComputerName= g_stComputers[j+1].szComputerName;
+            g_stComputers[j].hRegistry = g_stComputers[j+1].hRegistry;
+        }
+        g_stComputers[j].szComputerName = NULL;
+        g_stComputers[j].hRegistry = NULL;
+    }
+}
+
+
+void ErrorMessage(LPCTSTR szError, BOOL bFatal)
+{
+    LPVOID lpMsgBuf = NULL;
+    if (szError) {
+        MessageBox(NULL, szError, g_lpMsg[IDS_MSG_ERROR - IDS_MSG_FIRST],
+                   MB_OK | (bFatal ? MB_ICONERROR : MB_ICONEXCLAMATION));
+    }
+    else {
+        FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+                      FORMAT_MESSAGE_FROM_SYSTEM |
+                      FORMAT_MESSAGE_IGNORE_INSERTS,
+                      NULL, GetLastError(), g_LangID,
+                      (LPTSTR) &lpMsgBuf, 0, NULL);
+        MessageBox(NULL, (LPCTSTR)lpMsgBuf,
+                   g_lpMsg[IDS_MSG_ERROR - IDS_MSG_FIRST],
+                   MB_OK | (bFatal ? MB_ICONERROR : MB_ICONEXCLAMATION));
+        LocalFree(lpMsgBuf);
+    }
+    if (bFatal) {
+        PostQuitMessage(0);
+    }
+}
+
+
+int am_RespawnAsUserAdmin(HWND hwnd, DWORD op, LPCTSTR szService,
+                          LPCTSTR szComputerName)
+{
+    TCHAR args[MAX_PATH + MAX_COMPUTERNAME_LENGTH + 12];
+
+    if (g_dwOSVersion < OS_VERSION_WIN2K) {
+        ErrorMessage(g_lpMsg[IDS_MSG_SRVFAILED - IDS_MSG_FIRST], FALSE);
+        return 0;
+    }
 
+    _sntprintf(args, sizeof(args) / sizeof(TCHAR),
+               _T("%d \"%s\" \"%s\""), op, szService,
+               szComputerName ? szComputerName : _T(""));
+    if (!ShellExecute(hwnd, _T("runas"), __targv[0], args, NULL, SW_NORMAL)) {
+        ErrorMessage(g_lpMsg[IDS_MSG_SRVFAILED - IDS_MSG_FIRST],
+                     FALSE);
+        return 0;
     }
-    ZeroMemory(ap_stServices, sizeof(ST_APACHE_SERVICE) * MAX_APACHE_SERVICES);
 
+    return 1;
 }
 
-void ErrorMessage(DWORD dwError)
+
+BOOL am_ConnectComputer(LPTSTR szComputerName)
 {
-    LPVOID lpMsgBuf;
-    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
-                  FORMAT_MESSAGE_FROM_SYSTEM |
-                  FORMAT_MESSAGE_IGNORE_INSERTS,
-                  NULL,
-                  dwError == ERROR_SUCCESS ? GetLastError() : dwError,
-                  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
-                  (LPTSTR) &lpMsgBuf, 0, NULL);
-    MessageBox(NULL, (LPCTSTR)lpMsgBuf, "Error", MB_OK | MB_ICONERROR);
-    LocalFree(lpMsgBuf);
+    int i = 0;
+    HKEY hKeyRemote;
+    TCHAR szTmp[MAX_PATH];
 
+    while (g_stComputers[i].szComputerName != NULL) {
+        if (_tcscmp(g_stComputers[i].szComputerName, szComputerName) == 0) {
+            return FALSE;
+        }
+        ++i;
+    }
+    if (i > MAX_APACHE_COMPUTERS - 1) {
+        return FALSE;
+    }
+    if (RegConnectRegistry(szComputerName, HKEY_LOCAL_MACHINE, &hKeyRemote)
+            != ERROR_SUCCESS) {
+        _sntprintf(szTmp, sizeof(szTmp) / sizeof(TCHAR),
+                   g_lpMsg[IDS_MSG_ECONNECT - IDS_MSG_FIRST],
+                   szComputerName);
+        ErrorMessage(szTmp, FALSE);
+        return FALSE;
+    }
+    else {
+        g_stComputers[i].szComputerName = _tcsdup(szComputerName);
+        g_stComputers[i].hRegistry = hKeyRemote;
+        return TRUE;
+    }
 }
 
+
 LPTSTR GetStringRes(int id)
 {
-  static TCHAR buffer[MAX_PATH];
+    static TCHAR buffer[MAX_PATH];
 
-  buffer[0] = 0;
-  LoadString(GetModuleHandle (NULL), id, buffer, MAX_PATH);
-  return buffer;
+    buffer[0] = 0;
+    LoadString(GetModuleHandle(NULL), id, buffer, MAX_PATH);
+    return buffer;
 }
 
-BOOL GetSystemOSVersion(LPSTR szVersion, LPDWORD dwVersion)
+
+BOOL GetSystemOSVersion(LPDWORD dwVersion)
 {
-    OSVERSIONINFOEX osvi;
-    BOOL    bOsVersionInfoEx;
-    char    szBuff[256];
-    HKEY    hKey;
-    char    szProductType[80];
-    DWORD   dwBufLen;
-    
-    /* 
+    OSVERSIONINFO osvi;
+    /*
     Try calling GetVersionEx using the OSVERSIONINFOEX structure.
     If that fails, try using the OSVERSIONINFO structure.
     */
-    ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
-    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
-    
-    if (!(bOsVersionInfoEx = GetVersionEx((OSVERSIONINFO *) &osvi)))
-    {
-        /* If OSVERSIONINFOEX doesn't work, try OSVERSIONINFO. */        
-        osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
-        if (!GetVersionEx((OSVERSIONINFO *) &osvi)) 
-            return FALSE;
+    memset(&osvi, 0, sizeof(OSVERSIONINFO));
+    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+
+    if (!GetVersionEx(&osvi)) {
+        return FALSE;
     }
-    
+
     switch (osvi.dwPlatformId)
     {
-    case VER_PLATFORM_WIN32_NT:        
-        /* Test for the product. */        
-        if (szVersion!= NULL)
-        {
-            if (osvi.dwMajorVersion <= 4)
-                strcpy(szVersion, "MS Windows NT ");
-            else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0)
-                strcpy(szVersion, "MS Windows 2000 ");
-            else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1)
-                strcpy(szVersion, "MS Windows XP ");
-            /* Test for product type.*/            
-#ifdef VER_VORKSTATION_NT
-            if (bOsVersionInfoEx)
-            {
-                if (osvi.wProductType == VER_NT_WORKSTATION)
-                {
-#ifdef VER_SUITE_PERSONAL
-                    if (osvi.wSuiteMask & VER_SUITE_PERSONAL)
-                        strcat(szVersion, "Personal ");
-                    else
-#endif
-                    strcat(szVersion, "Professional ");
-                }                
-                else if (osvi.wProductType == VER_NT_SERVER)
-                {
-                    if (osvi.wSuiteMask & VER_SUITE_DATACENTER)
-                        strcat(szVersion, "DataCenter Server ");
-                    else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE)
-                        strcat(szVersion, "Advanced Server ");
-                    else
-                        strcat(szVersion, "Server ");
-                }
-            }
-            else
-            {
-#endif                
-                RegOpenKeyEx(HKEY_LOCAL_MACHINE,
-                    "SYSTEM\\CurrentControlSet\\Control\\ProductOptions",
-                    0, KEY_QUERY_VALUE, &hKey);
-                RegQueryValueEx(hKey, "ProductType", NULL, NULL,
-                    (LPBYTE) szProductType, &dwBufLen);
-                RegCloseKey(hKey);
-                if (lstrcmpi("WINNT", szProductType) == 0)
-                    strcat(szVersion, "Workstation ");
-                if (lstrcmpi("SERVERNT", szProductType) == 0)
-                    strcat(szVersion, "Server ");
-#ifdef VER_VORKSTATION_NT
-            }            
-#endif
-            /* Get version, service pack (if any), and build number. */
-            if (osvi.dwMajorVersion <= 4)
-            {
-                sprintf(szBuff, "version %d.%d %s (Build-%d)\n",
-                        osvi.dwMajorVersion,
-                        osvi.dwMinorVersion,
-                        osvi.szCSDVersion,
-                        osvi.dwBuildNumber & 0xFFFF);
-            }
-            else
-            { 
-                sprintf(szBuff, "%s (Build-%d)\n",
-                    osvi.szCSDVersion,
-                    osvi.dwBuildNumber & 0xFFFF);
-            }
-            strcat(szVersion, szBuff);
-        }
-        else if (dwVersion != NULL)
-        {
-            if (osvi.dwMajorVersion <= 4)
-                *dwVersion = OS_VERSION_WINNT;
-            else if (osvi.dwMajorVersion == 5)
-                *dwVersion = OS_VERSION_WIN2K;
-            else
-                return FALSE;
-            
-        }
+    case VER_PLATFORM_WIN32_NT:
+        if (osvi.dwMajorVersion >= 5)
+            *dwVersion = OS_VERSION_WIN2K;
+        else
+            *dwVersion = OS_VERSION_WINNT;
         break;
-        
+
     case VER_PLATFORM_WIN32_WINDOWS:
-        if (szVersion != NULL)
-        {
-            if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0)
-            {
-                strcpy(szVersion, "MS Windows 95 ");
-                if (osvi.szCSDVersion[1] == 'C')
-                    strcat(szVersion, "OSR2 ");
-            } 
-            
-            if(osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10)
-            {
-                strcpy(szVersion, "MS Windows 98 ");
-                if (osvi.szCSDVersion[1] == 'A')
-                    strcat(szVersion, "SE ");
-            } 
-            
-            if(osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90)
-            {
-                strcpy(szVersion, "MS Windows Me ");
-            }
-        }
-        if (dwVersion != NULL)
-            *dwVersion = OS_VERSION_WIN9X;
-        
-        break;
-        
     case VER_PLATFORM_WIN32s:
-        if (szVersion != NULL)
-            strcpy(szVersion, "Microsoft Win32s ");
-        if (dwVersion != NULL)
-            *dwVersion = OS_VERSION_WIN9X;
-        break;
     default:
+        *dwVersion = 0;
         return FALSE;
-        break;
-   }
-   return TRUE; 
+    }
+    return TRUE;
 }
 
+
 static VOID ShowNotifyIcon(HWND hWnd, DWORD dwMessage)
 {
-    
     NOTIFYICONDATA nid;
-    int  i = 0, n = 0;
+    int i = 0, n = 0;
 
-    ZeroMemory(&nid,sizeof(nid));
+    memset(&nid, 0, sizeof(nid));
     nid.cbSize = sizeof(NOTIFYICONDATA);
     nid.hWnd = hWnd;
     nid.uID = 0xFF;
     nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
     nid.uCallbackMessage = WM_TRAYMESSAGE;
-    
-    while (ap_stServices[i].szServiceName != NULL)
-    {    
-        if (ap_stServices[i].dwPid != 0)
+
+    while (g_stServices[i].szServiceName != NULL)
+    {
+        if (g_stServices[i].dwPid != 0) {
             ++n;
+        }
         ++i;
     }
     if (dwMessage != NIM_DELETE)
     {
-        if (n)
-            nid.hIcon = ap_icoRun;
-        else
-            nid.hIcon = ap_icoStop;
+        if (n) {
+            nid.hIcon = g_icoRun;
+        }
+        else {
+            nid.hIcon = g_icoStop;
+        }
     }
-    else
+    else {
         nid.hIcon = NULL;
-    if (n == i)
-        lstrcpy(nid.szTip, "Running all Apache services");
-    else if (n)
-        sprintf(nid.szTip, "Running %d from %d Apache services", n, i);
-    else
-        sprintf(nid.szTip, "Running none from %d Apache services", n, i);
-
+    }
+    if (n == i && n > 0) {
+        _tcscpy(nid.szTip, g_lpMsg[IDS_MSG_RUNNINGALL - IDS_MSG_FIRST]);
+    }
+    else if (n) {
+        _sntprintf(nid.szTip, sizeof(nid.szTip) / sizeof(TCHAR),
+                  g_lpMsg[IDS_MSG_RUNNING - IDS_MSG_FIRST], n, i);
+    }
+    else if (i) {
+        _sntprintf(nid.szTip, sizeof(nid.szTip) / sizeof(TCHAR),
+                  g_lpMsg[IDS_MSG_RUNNINGNONE - IDS_MSG_FIRST], i);
+    }
+    else {
+        _tcscpy(nid.szTip, g_lpMsg[IDS_MSG_NOSERVICES - IDS_MSG_FIRST]);
+    }
     Shell_NotifyIcon(dwMessage, &nid);
-    
 }
 
-void appendMenuItem(HMENU hMenu, UINT uMenuId, LPSTR szName, BOOL fDefault)
+
+void appendMenuItem(HMENU hMenu, UINT uMenuId, LPTSTR szName,
+                    BOOL fDefault, BOOL fEnabled)
 {
     MENUITEMINFO mii;
-    
-    ZeroMemory(&mii, sizeof(MENUITEMINFO));
+
+    memset(&mii, 0, sizeof(MENUITEMINFO));
     mii.cbSize = sizeof(MENUITEMINFO);
     mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE;
-    if (lstrlen(szName))
+    if (_tcslen(szName))
     {
         mii.fType = MFT_STRING;
         mii.wID = uMenuId;
-        if (fDefault)
+        if (fDefault) {
             mii.fState = MFS_DEFAULT;
+        }
+        if (!fEnabled) {
+            mii.fState |= MFS_DISABLED;
+        }
         mii.dwTypeData = szName;
     }
-    else
+    else {
         mii.fType = MFT_SEPARATOR;
+    }
     InsertMenuItem(hMenu, uMenuId, FALSE, &mii);
 }
 
+
+void appendServiceMenu(HMENU hMenu, UINT uMenuId,
+                       LPTSTR szServiceName, BOOL fRunning)
+{
+    MENUITEMINFO mii;
+    HMENU smh;
+
+    smh = CreatePopupMenu();
+
+    appendMenuItem(smh, IDM_SM_START + uMenuId,
+                   g_lpMsg[IDS_MSG_SSTART - IDS_MSG_FIRST], FALSE, !fRunning);
+    appendMenuItem(smh, IDM_SM_STOP + uMenuId,
+                   g_lpMsg[IDS_MSG_SSTOP - IDS_MSG_FIRST], FALSE, fRunning);
+    appendMenuItem(smh, IDM_SM_RESTART + uMenuId,
+                   g_lpMsg[IDS_MSG_SRESTART - IDS_MSG_FIRST], FALSE, fRunning);
+
+    memset(&mii, 0, sizeof(MENUITEMINFO));
+    mii.cbSize = sizeof(MENUITEMINFO);
+    mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE | MIIM_SUBMENU
+              | MIIM_CHECKMARKS;
+    mii.fType = MFT_STRING;
+    mii.wID = uMenuId;
+    mii.hbmpChecked = g_hBmpStart;
+    mii.hbmpUnchecked = g_hBmpStop;
+    mii.dwTypeData = szServiceName;
+    mii.hSubMenu = smh;
+    mii.fState = fRunning ? MFS_CHECKED : MFS_UNCHECKED;
+    InsertMenuItem(hMenu, IDM_SM_SERVICE + uMenuId, FALSE, &mii);
+}
+
+
 void ShowTryPopupMenu(HWND hWnd)
 {
     /* create popup menu */
@@ -388,23 +430,63 @@ void ShowTryPopupMenu(HWND hWnd)
 
     if (hMenu)
     {
-        appendMenuItem(hMenu,  IDM_ABOUT, "&About...", FALSE);
-        appendMenuItem(hMenu,  IDM_RESTORE, "&Show Services...", TRUE);
-        appendMenuItem(hMenu,  0, "", FALSE);
-        appendMenuItem(hMenu,  IDM_EXIT,  "&Exit...", FALSE);
-
+        appendMenuItem(hMenu, IDM_RESTORE,
+                       g_lpMsg[IDS_MSG_MNUSHOW - IDS_MSG_FIRST],
+                       TRUE, TRUE);
+        appendMenuItem(hMenu, IDC_SMANAGER,
+                       g_lpMsg[IDS_MSG_MNUSERVICES - IDS_MSG_FIRST],
+                       FALSE, TRUE);
+        appendMenuItem(hMenu, 0, _T(""), FALSE, TRUE);
+        appendMenuItem(hMenu, IDM_EXIT,
+                       g_lpMsg[IDS_MSG_MNUEXIT - IDS_MSG_FIRST],
+                       FALSE, TRUE);
+
+        if (!SetForegroundWindow(hWnd)) {
+            SetForegroundWindow(NULL);
+        }
         GetCursorPos(&pt);
-        SetForegroundWindow(NULL);
-        TrackPopupMenu(hMenu, TPM_LEFTALIGN|TPM_RIGHTBUTTON, pt.x, pt.y, 0, hWnd, NULL);
+        TrackPopupMenu(hMenu, TPM_LEFTALIGN|TPM_RIGHTBUTTON,
+                       pt.x, pt.y, 0, hWnd, NULL);
+        DestroyMenu(hMenu);
+    }
+}
+
+
+void ShowTryServicesMenu(HWND hWnd)
+{
+    /* create services list popup menu and submenus */
+    HMENU hMenu = CreatePopupMenu();
+    POINT pt;
+    int i = 0;
+
+    if (hMenu)
+    {
+        while (g_stServices[i].szServiceName != NULL)
+        {
+            appendServiceMenu(hMenu, i, g_stServices[i].szDisplayName,
+                              g_stServices[i].dwPid != 0);
+            ++i;
+        }
+        if (i)
+        {
+            if (!SetForegroundWindow(hWnd)) {
+                SetForegroundWindow(NULL);
+            }
+            GetCursorPos(&pt);
+            TrackPopupMenu(hMenu, TPM_LEFTALIGN|TPM_RIGHTBUTTON,
+                           pt.x, pt.y, 0, hWnd, NULL);
+            DestroyMenu(hMenu);
+        }
     }
 }
 
+
 BOOL CenterWindow(HWND hwndChild)
 {
-   RECT    rChild, rWorkArea;
-   int     wChild, hChild;
-   int     xNew, yNew;
-   BOOL    bResult;
+   RECT rChild, rWorkArea;
+   int wChild, hChild;
+   int xNew, yNew;
+   BOOL bResult;
 
    /* Get the Height and Width of the child window */
    GetWindowRect(hwndChild, &rChild);
@@ -412,11 +494,8 @@ BOOL CenterWindow(HWND hwndChild)
    hChild = rChild.bottom - rChild.top;
 
    /* Get the limits of the 'workarea' */
-   bResult = SystemParametersInfo(
-      SPI_GETWORKAREA,
-      sizeof(RECT),
-      &rWorkArea,
-      0);
+   bResult = SystemParametersInfo(SPI_GETWORKAREA, sizeof(RECT),
+                                  &rWorkArea, 0);
    if (!bResult) {
       rWorkArea.left = rWorkArea.top = 0;
       rWorkArea.right = GetSystemMetrics(SM_CXSCREEN);
@@ -424,1103 +503,1167 @@ BOOL CenterWindow(HWND hwndChild)
    }
 
    /* Calculate new X and Y position*/
-   xNew = (rWorkArea.right - wChild)/2;
-   yNew = (rWorkArea.bottom - hChild)/2;
-   return SetWindowPos (hwndChild, HWND_TOP, xNew, yNew, 0, 0, SWP_NOSIZE | SWP_SHOWWINDOW);
+   xNew = (rWorkArea.right - wChild) / 2;
+   yNew = (rWorkArea.bottom - hChild) / 2;
+   return SetWindowPos(hwndChild, HWND_TOP, xNew, yNew, 0, 0,
+                       SWP_NOSIZE | SWP_SHOWWINDOW);
 }
 
-static void addItem(HWND hDlg, LPSTR lpStr, HBITMAP hBmp) 
-{ 
-    int nItem; 
-    nItem = SendMessage(hDlg, LB_ADDSTRING, 0, (LPARAM)lpStr); 
-    SendMessage(hDlg, LB_SETITEMDATA, nItem, (LPARAM)hBmp); 
-} 
 
-static DWORD WINAPI ConsoleOutputThread(LPVOID lpThreadParameter)
+static void addListBoxItem(HWND hDlg, LPTSTR lpStr, HBITMAP hBmp)
 {
-    static BYTE lpBuffer[513];
-    LPSTR lpBuf = lpBuffer;
-    BYTE  ch;
-    DWORD dwReaded;
-
-    while (ReadFile(h_stdOutR, &ch, 1, &dwReaded, NULL) == TRUE) 
-    {
-        if (dwReaded > 0) 
-        {
-            if (ch == '\n') 
-            {
-                *lpBuf = '\0';
-                ListBox_SetCurSel(ap_hStdoutWnd,
-                                  ListBox_AddString(ap_hStdoutWnd, lpBuffer));
-                lpBuf = lpBuffer;
-            } 
-            else if (ch == '\t') 
-            {
-                int i, t;
-                t = ((int)lpBuf - (int)lpBuffer) % 8;
-                for (i = 0; i < 8 - t; ++i)
-                    *lpBuf++ = ' ';
-            }
-            else if (ch != '\r')
-                *lpBuf++ = ch;
-        }
-    }
-    CloseHandle(h_stdInW);
-    CloseHandle(h_stdOutR);
-    CloseHandle(h_stdErr);
-    return 0;
-}
-
+    LRESULT nItem;
 
-DWORD WINAPI ConsoleWaitingThread(LPVOID lpThreadParameter)
-{
-    WaitForSingleObject(ap_redirectedPI.hThread, INFINITE);
-    CloseHandle(ap_redirectedPI.hThread);
-    MessageBeep(100);
-    ap_consoleRun = FALSE;
-    SetCursor(ap_cArrow);
-    return 0;
+    nItem = SendMessage(hDlg, LB_ADDSTRING, 0, (LPARAM)lpStr);
+    SendMessage(hDlg, LB_SETITEMDATA, nItem, (LPARAM)hBmp);
 }
 
 
-BOOL RunRedirectedConsole(LPTSTR szCmdLine, LPDWORD nRetValue)
+static void addListBoxString(HWND hListBox, LPTSTR lpStr)
 {
-    
-    DWORD  dwThreadId;
-    HANDLE hProc;
-    STARTUPINFO stInfo;
-    BOOL bResult;
-    ZeroMemory(&stInfo, sizeof(stInfo));
-    stInfo.cb = sizeof(stInfo);
-    stInfo.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
-    stInfo.wShowWindow = SW_HIDE;
-    
-    hProc = GetCurrentProcess();
-
-    if (!CreatePipe(&h_stdInR, &h_stdInW, NULL, MAX_PATH))
-        ErrorMessage(ERROR_SUCCESS);
-    if (!CreatePipe(&h_stdOutR, &h_stdOutW, NULL, MAX_PATH*8))
-        ErrorMessage(ERROR_SUCCESS);
-        
-    DuplicateHandle(hProc, h_stdInR, hProc, &h_stdInR, 0, TRUE, 
-                    DUPLICATE_CLOSE_SOURCE|DUPLICATE_SAME_ACCESS);
-    DuplicateHandle(hProc, h_stdOutW, hProc, &h_stdOutW, 0, TRUE, 
-                    DUPLICATE_CLOSE_SOURCE|DUPLICATE_SAME_ACCESS);
-    DuplicateHandle(hProc, h_stdOutW, hProc, &h_stdErr, 0, TRUE, 
-                    DUPLICATE_SAME_ACCESS);
-    
-    stInfo.hStdInput  = h_stdInR;
-    stInfo.hStdOutput = h_stdOutW;
-    stInfo.hStdError  = h_stdErr;
-
-    bResult = CreateProcess(NULL,
-        szCmdLine,
-        NULL,
-        NULL,
-        TRUE,
-        CREATE_SUSPENDED,
-        NULL,
-        NULL ,
-        &stInfo,
-        &ap_redirectedPI);
-
-
-    CloseHandle(h_stdInR);
-    CloseHandle(h_stdOutW);
-    CloseHandle(h_stdErr);
-
-    if (!bResult)
-    {     
-        if (nRetValue)
-            *nRetValue = GetLastError();
-        CloseHandle(h_stdInW);
-        CloseHandle(h_stdOutR);
-        CloseHandle(h_stdErr);
-        return FALSE;
+    static int nItems = 0;
+    if (!g_bDlgServiceOn) {
+        return;
     }
+    ++nItems;
+    if (nItems > MAX_LOADSTRING)
+    {
+        SendMessage(hListBox, LB_RESETCONTENT, 0, 0);
+        nItems = 1;
+    }
+    ListBox_SetCurSel(hListBox,
+                      ListBox_AddString(hListBox, lpStr));
 
-    CloseHandle(CreateThread(NULL, 0, ConsoleOutputThread, 0, 0, &dwThreadId));
-    ResumeThread(ap_redirectedPI.hThread);
-    CloseHandle(CreateThread(NULL, 0, ConsoleWaitingThread, 0, 0, &dwThreadId));
-
-    return TRUE;
 }
 
-BOOL RunAndForgetConsole(LPTSTR szCmdLine,
-                         LPDWORD nRetValue,
-                         BOOL  bRedirectConsole)
-{
-        
-    STARTUPINFO stInfo;
-    PROCESS_INFORMATION prInfo;
-    BOOL bResult;
-    
-    if (bRedirectConsole)
-        return RunRedirectedConsole(szCmdLine, nRetValue);
-
-    
-    ZeroMemory(&stInfo, sizeof(stInfo));
-    stInfo.cb = sizeof(stInfo);
-    stInfo.dwFlags = STARTF_USESHOWWINDOW;
-    stInfo.wShowWindow = SW_HIDE;
-
-    bResult = CreateProcess(NULL,
-        szCmdLine,
-        NULL,
-        NULL,
-        TRUE,
-        CREATE_NEW_CONSOLE,
-        NULL,
-        NULL ,
-        &stInfo,
-        &prInfo);
-
-    if (!bResult)
-    {     
-        if (nRetValue)
-            *nRetValue = GetLastError();
-        return FALSE;
-    }
-    if (ap_OSVersion == OS_VERSION_WIN9X) /* give some time to rescan the status */
-        Sleep(2000);
-    CloseHandle(prInfo.hThread);
-    CloseHandle(prInfo.hProcess);
-    return TRUE;
-}
 
-BOOL ApacheManageService(LPCSTR szServiceName, LPCSTR szImagePath, DWORD dwCommand)
+BOOL ApacheManageService(LPCTSTR szServiceName, LPCTSTR szImagePath,
+                         LPTSTR szComputerName, DWORD dwCommand)
 {
-    
-    CHAR      szBuf[MAX_PATH];
-    CHAR      szMsg[MAX_PATH];
-    LPSTR     sPos;
-    DWORD     retCode;
-    BOOL      retValue;
-    BOOL      serviceFlag = TRUE;
+    TCHAR szMsg[MAX_PATH];
+    BOOL retValue;
     SC_HANDLE schService;
-    SC_HANDLE schSCManager;    
+    SC_HANDLE schSCManager;
     SERVICE_STATUS schSStatus;
-    LPSTR     *args;
-    int       ticks;
+    int ticks;
 
-    if (ap_OSVersion == OS_VERSION_WIN9X)
+    schSCManager = OpenSCManager(szComputerName, NULL,
+                                 SC_MANAGER_CONNECT);
+    if (!schSCManager) {
+        ErrorMessage(g_lpMsg[IDS_MSG_SRVFAILED - IDS_MSG_FIRST],
+                     FALSE);
+        return FALSE;
+    }
+
+    schService = OpenService(schSCManager, szServiceName,
+                             SERVICE_QUERY_STATUS | SERVICE_START |
+                             SERVICE_STOP | SERVICE_USER_DEFINED_CONTROL);
+    if (schService == NULL)
     {
-        sPos = strstr(szImagePath, "-k start");
-        if (sPos)
-        {
-            lstrcpyn(szBuf, szImagePath, sPos - szImagePath);
-            switch (dwCommand)
-            {
-            case SERVICE_CONTROL_STOP:
-                lstrcat(szBuf, " -k stop -n ");
-                break;
-            case SERVICE_CONTROL_CONTINUE:
-                sprintf(szMsg, "The %s is starting.", szServiceName);
-                ListBox_SetCurSel(ap_hStdoutWnd,
-                                   ListBox_AddString(ap_hStdoutWnd, szMsg));
-                lstrcat(szBuf, " -k start -n ");
-                serviceFlag = FALSE;
-                break;
-            case SERVICE_APACHE_RESTART:
-                lstrcat(szBuf, " -k restart -n ");
-                break;
-            default:
-                return FALSE;
-            }
-            lstrcat(szBuf, szServiceName);
-        }
-        else
-            return FALSE;
-        ap_consoleRun = TRUE;
-        SetCursor(ap_cHourglass);
-        if (!RunAndForgetConsole(szBuf, &retCode, serviceFlag))
-        {
-            ErrorMessage(retCode);
-            ap_consoleRun = FALSE;
-            SetCursor(ap_cArrow);
-            return FALSE;
+        /* Avoid recursion of ImagePath NULL (from this Respawn) */
+        if (szImagePath) {
+            am_RespawnAsUserAdmin(g_hwndMain, dwCommand,
+                                  szServiceName, szComputerName);
         }
-        else if (!serviceFlag)
-        {
-            sprintf(szMsg, "The %s has started.", szServiceName);
-            ListBox_SetCurSel(ap_hStdoutWnd,
-                              ListBox_AddString(ap_hStdoutWnd, szMsg));
-
-            ap_consoleRun = FALSE;
-            SetCursor(ap_cArrow);
-            return TRUE;
+        else {
+            ErrorMessage(g_lpMsg[IDS_MSG_SRVFAILED - IDS_MSG_FIRST],
+                         FALSE);
         }
+        CloseServiceHandle(schSCManager);
+        return FALSE;
     }
     else
     {
-        /* Apache 2.0 uses '-k runservice' as cmdline parameter */
-        sPos = strstr(szImagePath, "--ntservice");
-        if (!sPos)
+        retValue = FALSE;
+        g_bConsoleRun = TRUE;
+        SetCursor(g_hCursorHourglass);
+        switch (dwCommand)
         {
-            sPos = strstr(szImagePath, "-k runservice");
-            serviceFlag = FALSE;
-        }
-        if (sPos)
-            lstrcpyn(szBuf, szImagePath, sPos - szImagePath);
-        else
-            return FALSE;
-        schSCManager = OpenSCManager(
-            NULL,
-            NULL,
-            SC_MANAGER_ALL_ACCESS
-           );
-        if (!schSCManager)
-            return FALSE;
-        
-        schService = OpenService(schSCManager, szServiceName, SERVICE_ALL_ACCESS);
-        if (schService != NULL)
-        {
-            retValue = FALSE;
-            ap_consoleRun = TRUE;
-            SetCursor(ap_cHourglass);
-            switch (dwCommand)
-            {
-                case SERVICE_CONTROL_STOP:
-                    sprintf(szMsg, "The %s is stopping.", szServiceName);
-                    ListBox_SetCurSel(ap_hStdoutWnd,
-                                      ListBox_AddString(ap_hStdoutWnd, szMsg));
-                    if(ControlService(schService, SERVICE_CONTROL_STOP, &schSStatus)) 
+          case SERVICE_CONTROL_STOP:
+            _sntprintf(szMsg, sizeof(szMsg) / sizeof(TCHAR),
+                       g_lpMsg[IDS_MSG_SRVSTOP - IDS_MSG_FIRST],
+                       szServiceName);
+            addListBoxString(g_hwndStdoutList, szMsg);
+            if (ControlService(schService, SERVICE_CONTROL_STOP,
+                               &schSStatus)) {
+                Sleep(1000);
+                while (QueryServiceStatus(schService, &schSStatus))
+                {
+                    if (schSStatus.dwCurrentState == SERVICE_STOP_PENDING)
                     {
                         Sleep(1000);
-                        while (QueryServiceStatus(schService, &schSStatus)) 
-                        {
-                            if (schSStatus.dwCurrentState == SERVICE_STOP_PENDING)
-                                Sleep(1000);
-                            else
-                                break;
-                        }
-                    }
-                    if (QueryServiceStatus(schService, &schSStatus))
-                    {
-                        if(schSStatus.dwCurrentState == SERVICE_STOPPED)
-                        {
-                            retValue = TRUE;
-                            sprintf(szMsg, "The %s has stopped.", szServiceName);
-                            ListBox_SetCurSel(ap_hStdoutWnd,
-                                              ListBox_AddString(ap_hStdoutWnd, szMsg));
-                        }
                     }
-                break;                
-                case SERVICE_CONTROL_CONTINUE:
-                    sprintf(szMsg, "The %s is starting.", szServiceName);
-                    ListBox_SetCurSel(ap_hStdoutWnd,
-                                      ListBox_AddString(ap_hStdoutWnd, szMsg));
-                    args = (char **)malloc(3 * sizeof(char*));
-                    args[0] = szBuf;
-                    if (serviceFlag)
-                        args[1] = "--ntservice";
-                    else
-                    {
-                        args[1] = "-k";
-                        args[2] = "runservice";
+                    else {
+                        break;
                     }
-                    if(StartService(schService, serviceFlag ? 2 : 3, args)) 
+                }
+            }
+            if (QueryServiceStatus(schService, &schSStatus))
+            {
+                if (schSStatus.dwCurrentState == SERVICE_STOPPED)
+                {
+                    retValue = TRUE;
+                    _sntprintf(szMsg, sizeof(szMsg) / sizeof(TCHAR),
+                               g_lpMsg[IDS_MSG_SRVSTOPPED - IDS_MSG_FIRST],
+                               szServiceName);
+                    addListBoxString(g_hwndStdoutList, szMsg);
+                }
+            }
+            break;
+
+          case SERVICE_CONTROL_CONTINUE:
+            _sntprintf(szMsg, sizeof(szMsg) / sizeof(TCHAR),
+                       g_lpMsg[IDS_MSG_SRVSTART - IDS_MSG_FIRST],
+                       szServiceName);
+            addListBoxString(g_hwndStdoutList, szMsg);
+
+            if (StartService(schService, 0, NULL))
+            {
+                Sleep(1000);
+                while (QueryServiceStatus(schService, &schSStatus))
+                {
+                    if (schSStatus.dwCurrentState == SERVICE_START_PENDING)
                     {
                         Sleep(1000);
-                        while (QueryServiceStatus(schService, &schSStatus)) 
-                        {
-                            if (schSStatus.dwCurrentState == SERVICE_START_PENDING)
-                                Sleep(1000);
-                            else
-                                break;
-                        }
                     }
-                    if (QueryServiceStatus(schService, &schSStatus))
-                    {
-                        if(schSStatus.dwCurrentState == SERVICE_RUNNING)
-                        {
-                            retValue = TRUE;
-                            sprintf(szMsg, "The %s has started.", szServiceName);
-                            ListBox_SetCurSel(ap_hStdoutWnd,
-                                              ListBox_AddString(ap_hStdoutWnd, szMsg));
-                        }
+                    else {
+                        break;
                     }
-                    /* is this OK to do? */
-                    free(args);
-                break;                
-                case SERVICE_APACHE_RESTART:
-                    sprintf(szMsg, "The %s is restarting.", szServiceName);
-                    ListBox_SetCurSel(ap_hStdoutWnd,
-                                      ListBox_AddString(ap_hStdoutWnd, szMsg));
-                    if(ControlService(schService, SERVICE_APACHE_RESTART, &schSStatus)) 
+                }
+            }
+            if (QueryServiceStatus(schService, &schSStatus))
+            {
+                if (schSStatus.dwCurrentState == SERVICE_RUNNING)
+                {
+                    retValue = TRUE;
+                    _sntprintf(szMsg, sizeof(szMsg) / sizeof(TCHAR),
+                               g_lpMsg[IDS_MSG_SRVSTARTED - IDS_MSG_FIRST],
+                               szServiceName);
+                    addListBoxString(g_hwndStdoutList, szMsg);
+                }
+            }
+            break;
+
+          case SERVICE_APACHE_RESTART:
+            _sntprintf(szMsg, sizeof(szMsg) / sizeof(TCHAR),
+                       g_lpMsg[IDS_MSG_SRVRESTART - IDS_MSG_FIRST],
+                       szServiceName);
+            addListBoxString(g_hwndStdoutList, szMsg);
+            if (ControlService(schService, SERVICE_APACHE_RESTART,
+                               &schSStatus))
+            {
+                ticks = 60;
+                while (schSStatus.dwCurrentState == SERVICE_START_PENDING)
+                {
+                    Sleep(1000);
+                    if (!QueryServiceStatus(schService, &schSStatus))
                     {
-                        ticks = 60;
-                        while(schSStatus.dwCurrentState == SERVICE_START_PENDING) 
-                        {
-                            Sleep(1000);
-                            if(!QueryServiceStatus(schService, &schSStatus))
-                            {
-                                CloseServiceHandle(schService);
-                                CloseServiceHandle(schSCManager);
-                                ap_consoleRun = FALSE;
-                                SetCursor(ap_cArrow);
-                                return FALSE;
-                            }
-                            if (!--ticks)
-                                break;
-                        }
+                        CloseServiceHandle(schService);
+                        CloseServiceHandle(schSCManager);
+                        g_bConsoleRun = FALSE;
+                        SetCursor(g_hCursorArrow);
+                        return FALSE;
                     }
-                    if(schSStatus.dwCurrentState == SERVICE_RUNNING)
-                    {
-                        retValue = TRUE;
-                        sprintf(szMsg, "The %s has restarted.", szServiceName);
-                        ListBox_SetCurSel(ap_hStdoutWnd,
-                                          ListBox_AddString(ap_hStdoutWnd, szMsg));
+                    if (!--ticks) {
+                        break;
                     }
-                break;                
+                }
             }
-            CloseServiceHandle(schService);
-            CloseServiceHandle(schSCManager);
-            if (!retValue)
-                ErrorMessage(ERROR_SUCCESS);
-            ap_consoleRun = FALSE;
-            SetCursor(ap_cArrow);
-            return retValue;
-            
+            if (schSStatus.dwCurrentState == SERVICE_RUNNING)
+            {
+                retValue = TRUE;
+                _sntprintf(szMsg, sizeof(szMsg) / sizeof(TCHAR),
+                           g_lpMsg[IDS_MSG_SRVRESTARTED - IDS_MSG_FIRST],
+                           szServiceName);
+                addListBoxString(g_hwndStdoutList, szMsg);
+            }
+            break;
         }
-        else
-            ap_rescanServices = TRUE;
-        
+        CloseServiceHandle(schService);
         CloseServiceHandle(schSCManager);
-        return FALSE;
+        if (!retValue) {
+            ErrorMessage(g_lpMsg[IDS_MSG_SRVFAILED - IDS_MSG_FIRST],
+                         FALSE);
+        }
+        g_bConsoleRun = FALSE;
+        SetCursor(g_hCursorArrow);
+        return retValue;
     }
-    
     return FALSE;
 }
 
-BOOL IsServiceRunning(LPCSTR szServiceName, LPDWORD lpdwPid)
-{
 
-    DWORD                   dwPid;
-    HWND                    hWnd;
-    SC_HANDLE               schService;
-    SC_HANDLE               schSCManager;    
-    SERVICE_STATUS          schSStatus;
+BOOL IsServiceRunning(LPCTSTR szServiceName, LPCTSTR szComputerName,
+                      LPDWORD lpdwPid)
+{
+    DWORD dwPid;
+    SC_HANDLE schService;
+    SC_HANDLE schSCManager;
+    SERVICE_STATUS schSStatus;
 
-    if (ap_OSVersion == OS_VERSION_WIN9X)
-    {
-        hWnd = FindWindow("ApacheWin95ServiceMonitor", szServiceName);
-        if (hWnd && GetWindowThreadProcessId(hWnd, &dwPid))
-        {
-            *lpdwPid = 1;
-            return TRUE;
-        }
-        else
-            return FALSE;
+    dwPid = 0;
+    schSCManager = OpenSCManager(szComputerName, NULL,
+                                SC_MANAGER_CONNECT);
+    if (!schSCManager) {
+        return FALSE;
     }
-    else
-    {
 
-        dwPid = 0;
-        schSCManager = OpenSCManager(
-                            NULL,
-                            NULL,
-                            SC_MANAGER_ALL_ACCESS
-                           );
-        if (!schSCManager)
-            return FALSE;
-
-        schService = OpenService(schSCManager, szServiceName, SERVICE_QUERY_STATUS);
-        if (schService != NULL)
+    schService = OpenService(schSCManager, szServiceName,
+                             SERVICE_QUERY_STATUS);
+    if (schService != NULL)
+    {
+        if (QueryServiceStatus(schService, &schSStatus))
         {
-            if (QueryServiceStatus(schService, &schSStatus))
-            {
-                
-                dwPid = schSStatus.dwCurrentState;
-                if (lpdwPid)
-                    *lpdwPid = 1;
+            dwPid = schSStatus.dwCurrentState;
+            if (lpdwPid) {
+                *lpdwPid = 1;
             }
-            CloseServiceHandle(schService);
-            CloseServiceHandle(schSCManager);
-            return dwPid == SERVICE_RUNNING ? TRUE : FALSE;
         }
-        else
-            ap_rescanServices = TRUE;
-
+        CloseServiceHandle(schService);
         CloseServiceHandle(schSCManager);
-        return FALSE;
-
+        return dwPid == SERVICE_RUNNING ? TRUE : FALSE;
     }
-
+    else {
+        g_bRescanServices = TRUE;
+    }
+    CloseServiceHandle(schSCManager);
     return FALSE;
 }
 
-BOOL FindRunningServices()
+
+BOOL FindRunningServices(void)
 {
     int i = 0;
     DWORD dwPid;
     BOOL rv = FALSE;
-    while (ap_stServices[i].szServiceName != NULL)
-    {    
-        if (!IsServiceRunning(ap_stServices[i].szServiceName, &dwPid))
+    while (g_stServices[i].szServiceName != NULL)
+    {
+        if (!IsServiceRunning(g_stServices[i].szServiceName,
+                              g_stServices[i].szComputerName, &dwPid)) {
             dwPid = 0;
-        if (ap_stServices[i].dwPid != dwPid)
+        }
+        if (g_stServices[i].dwPid != dwPid) {
             rv = TRUE;
-        ap_stServices[i].dwPid = dwPid;
+        }
+        g_stServices[i].dwPid = dwPid;
         ++i;
-    }                        
+    }
     return rv;
 }
 
+
 BOOL GetApacheServicesStatus()
 {
-
-    CHAR    szKey[MAX_PATH];
-    CHAR    achKey[MAX_PATH];
-    CHAR    szImagePath[MAX_PATH];
-    CHAR    szBuf[MAX_PATH];
-
-    HKEY    hKey, hSubKey;
-    DWORD   retCode, rv, dwKeyType;
-    DWORD   dwBufLen = MAX_PATH;
-    int     i, stPos = 0;
-
-    ap_rescanServices = FALSE;
-
-    retCode = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
-                            "System\\CurrentControlSet\\Services\\",
-                            0, KEY_READ, &hKey);
-    if (retCode != ERROR_SUCCESS)
-    {
-        ErrorMessage(retCode);
-        return FALSE;
-    }
-    ap_ClearServicesSt();
-    for (i = 0, retCode = ERROR_SUCCESS; retCode == ERROR_SUCCESS; i++)
-    {
-
-        retCode = RegEnumKey(hKey, i, achKey, MAX_PATH);
-        if (retCode == ERROR_SUCCESS)
+    TCHAR szKey[MAX_PATH];
+    TCHAR achKey[MAX_PATH];
+    TCHAR szImagePath[MAX_PATH];
+    TCHAR szBuf[MAX_PATH];
+    TCHAR szTmp[MAX_PATH];
+    HKEY hKey, hSubKey, hKeyRemote;
+    DWORD retCode, rv, dwKeyType;
+    DWORD dwBufLen = MAX_PATH;
+    int i, stPos = 0;
+    int computers = 0;
+
+    g_bRescanServices = FALSE;
+
+    am_ClearServicesSt();
+    while (g_stComputers[computers].szComputerName != NULL) {
+        hKeyRemote = g_stComputers[computers].hRegistry;
+        retCode = RegOpenKeyEx(hKeyRemote,
+                               _T("System\\CurrentControlSet\\Services\\"),
+                               0, KEY_READ, &hKey);
+        if (retCode != ERROR_SUCCESS)
         {
-            lstrcpy(szKey, "System\\CurrentControlSet\\Services\\");
-            lstrcat(szKey, achKey);
-
-            if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKey, 0, 
-                KEY_QUERY_VALUE, &hSubKey) == ERROR_SUCCESS)
+            ErrorMessage(NULL, FALSE);
+            return FALSE;
+        }
+        for (i = 0, retCode = ERROR_SUCCESS; retCode == ERROR_SUCCESS; i++)
+        {
+            retCode = RegEnumKey(hKey, i, achKey, MAX_PATH);
+            if (retCode == ERROR_SUCCESS)
             {
-                dwBufLen = MAX_PATH;
-                rv = RegQueryValueEx(hSubKey, "ImagePath", NULL,
-                                      &dwKeyType, szImagePath, &dwBufLen);
+                _tcscpy(szKey, _T("System\\CurrentControlSet\\Services\\"));
+                _tcscat(szKey, achKey);
 
-                if (rv == ERROR_SUCCESS && (dwKeyType == REG_SZ  || dwKeyType == REG_EXPAND_SZ) && dwBufLen)
+                if (RegOpenKeyEx(hKeyRemote, szKey, 0,
+                                 KEY_QUERY_VALUE, &hSubKey) == ERROR_SUCCESS)
                 {
-                    lstrcpy(szBuf, szImagePath);
-                    CharLower(szBuf);
-                    if (strstr(szBuf, "\\apache.exe") != NULL)
+                    dwBufLen = MAX_PATH;
+                    rv = RegQueryValueEx(hSubKey, _T("ImagePath"), NULL,
+                                         &dwKeyType, (LPBYTE)szImagePath, &dwBufLen);
+
+                    if (rv == ERROR_SUCCESS
+                            && (dwKeyType == REG_SZ
+                             || dwKeyType == REG_EXPAND_SZ)
+                            && dwBufLen)
                     {
-                        ap_stServices[stPos].szServiceName = strdup(achKey);
-                        ap_stServices[stPos].szImagePath = strdup(szImagePath);
-                        dwBufLen = MAX_PATH;
-                        if (RegQueryValueEx(hSubKey, "Description", NULL,
-                                      &dwKeyType, szBuf, &dwBufLen) == ERROR_SUCCESS)
-                            ap_stServices[stPos].szDescription = strdup(szBuf);
-
-                        dwBufLen = MAX_PATH;
-                        if (RegQueryValueEx(hSubKey, "DisplayName", NULL,
-                                      &dwKeyType, szBuf, &dwBufLen) == ERROR_SUCCESS)
-                            ap_stServices[stPos].szDisplayName= strdup(szBuf);
-                        ++stPos;
-                        if (stPos >= MAX_APACHE_SERVICES)
-                            retCode = !ERROR_SUCCESS;
+                        _tcscpy(szBuf, szImagePath);
+                        CharLower(szBuf);
+                        /* the service name could be httpd*.exe or Apache*.exe */
+                        if (((_tcsstr(szBuf, _T("\\apache")) != NULL)
+                             || (_tcsstr(szBuf, _T("\\httpd")) != NULL))
+                                && _tcsstr(szBuf, _T(".exe"))
+                                && (_tcsstr(szBuf, _T("--ntservice")) != NULL
+                                       || _tcsstr(szBuf, _T("-k ")) != NULL))
+                        {
+                            g_stServices[stPos].szServiceName = _tcsdup(achKey);
+                            g_stServices[stPos].szImagePath = _tcsdup(szImagePath);
+                            g_stServices[stPos].szComputerName =
+                                _tcsdup(g_stComputers[computers].szComputerName);
+                            dwBufLen = MAX_PATH;
+                            if (RegQueryValueEx(hSubKey, _T("Description"), NULL,
+                                                &dwKeyType, (LPBYTE)szBuf, &dwBufLen)
+                                    == ERROR_SUCCESS) {
+                                g_stServices[stPos].szDescription = _tcsdup(szBuf);
+                            }
+                            dwBufLen = MAX_PATH;
+                            if (RegQueryValueEx(hSubKey, _T("DisplayName"), NULL,
+                                                &dwKeyType, (LPBYTE)szBuf, &dwBufLen)
+                                    == ERROR_SUCCESS)
+                            {
+                                if (_tcscmp(g_stComputers[computers]
+                                        .szComputerName, g_szLocalHost) != 0)
+                                {
+                                    _tcscpy(szTmp, g_stComputers[computers]
+                                                      .szComputerName + 2);
+                                    _tcscat(szTmp, _T("@"));
+                                    _tcscat(szTmp, szBuf);
+                                }
+                                else {
+                                    _tcscpy(szTmp, szBuf);
+                                }
+                                g_stServices[stPos].szDisplayName = _tcsdup(szTmp);
+
+                            }
+                            ++stPos;
+                            if (stPos >= MAX_APACHE_SERVICES) {
+                                retCode = !ERROR_SUCCESS;
+                            }
+                        }
                     }
+                    RegCloseKey(hSubKey);
                 }
-                RegCloseKey(hSubKey);
             }
         }
+        ++computers;
+        RegCloseKey(hKey);
     }
-    RegCloseKey(hKey);
     FindRunningServices();
     return TRUE;
 }
 
-LRESULT CALLBACK AboutDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
+
+LRESULT CALLBACK ConnectDlgProc(HWND hDlg, UINT message,
+                                WPARAM wParam, LPARAM lParam)
 {
-    static  HFONT hfontDlg;    /* Font for dialog text */
-    static  HFONT hFinePrint;  /* Font for 'fine print' in dialog */
-    DWORD   dwVerInfoSize;     /* Size of version information block */
-    LPSTR   lpVersion;         /* String pointer to 'version' text */
-    DWORD   dwVerHnd=0;        /* An 'ignored' parameter, always '0' */
-    UINT    uVersionLen;
-    WORD    wRootLen;
-    BOOL    bRetCode;
-    int     i;
-    char    szFullPath[256];
-    char    szResult[256];
-    char    szGetName[256];
-    char    szVersion[256];
-    DWORD   dwResult;
-    
-    switch (message) {
+    TCHAR szCmp[MAX_COMPUTERNAME_LENGTH+4];
+    switch (message)
+    {
     case WM_INITDIALOG:
         ShowWindow(hDlg, SW_HIDE);
-        ap_hwndAboutDlg = hDlg;
-        
-        hfontDlg = CreateFont(13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-            VARIABLE_PITCH | FF_SWISS, "");
-        hFinePrint = CreateFont(11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-            VARIABLE_PITCH | FF_SWISS, "");
-
+        g_hwndConnectDlg = hDlg;
         CenterWindow(hDlg);
-        GetModuleFileName(ap_hInstance, szFullPath, sizeof(szFullPath));
-        
-        /* Now lets dive in and pull out the version information: */
-        dwVerInfoSize = GetFileVersionInfoSize(szFullPath, &dwVerHnd);
-        if (dwVerInfoSize) {
-            LPSTR   lpstrVffInfo;
-            HANDLE  hMem;
-            hMem = GlobalAlloc(GMEM_MOVEABLE, dwVerInfoSize);
-            lpstrVffInfo  = GlobalLock(hMem);
-            GetFileVersionInfo(szFullPath, dwVerHnd, dwVerInfoSize, lpstrVffInfo);
-            lstrcpy(szGetName, GetStringRes(IDS_VER_INFO_LANG));
-            
-            wRootLen = lstrlen(szGetName); /* Save this position */
-            
-            /* Set the title of the dialog: */
-            lstrcat(szGetName, "ProductName");
-            bRetCode = VerQueryValue((LPVOID)lpstrVffInfo,
-                (LPSTR)szGetName,
-                (LPVOID)&lpVersion,
-                (UINT *)&uVersionLen);
-            
-            /* Notice order of version and string... */
-            lstrcpy(szResult, "About ");
-            lstrcat(szResult, lpVersion);
-            
-            SetWindowText(hDlg, szResult);
-            
-            /* Walk through the dialog items that we want to replace: */
-            for (i = DLG_VERFIRST; i <= DLG_VERLAST; i++) {
-                GetDlgItemText(hDlg, i, szResult, sizeof(szResult));
-                szGetName[wRootLen] = (char)0;
-                lstrcat(szGetName, szResult);
-                uVersionLen   = 0;
-                lpVersion     = NULL;
-                bRetCode      =  VerQueryValue((LPVOID)lpstrVffInfo,
-                    (LPSTR)szGetName,
-                    (LPVOID)&lpVersion,
-                    (UINT *)&uVersionLen);
-                
-                if (bRetCode && uVersionLen && lpVersion) {
-                    /* Replace dialog item text with version info */
-                    lstrcpy(szResult, lpVersion);
-                    SetDlgItemText(hDlg, i, szResult);
-                }
-                else
-                {
-                    dwResult = GetLastError();
-                    
-                    wsprintf(szResult, GetStringRes(IDS_VERSION_ERROR), dwResult);
-                    SetDlgItemText(hDlg, i, szResult);
-                }
-                SendMessage(GetDlgItem(hDlg, i), WM_SETFONT,
-                    (UINT)((i==DLG_VERLAST)?hFinePrint:hfontDlg),
-                    TRUE);
-            }
-            
-            
-            GlobalUnlock(hMem);
-            GlobalFree(hMem);
-            
-        } 
-        
-        SendMessage(GetDlgItem(hDlg, IDC_LABEL), WM_SETFONT,
-            (WPARAM)hfontDlg,(LPARAM)TRUE);
-        if (!GetSystemOSVersion(szVersion, NULL))
-            strcpy(szVersion, "Unknown Version");
-        SetWindowText(GetDlgItem(hDlg, IDC_OSVERSION), szVersion);
         ShowWindow(hDlg, SW_SHOW);
-        return (TRUE);
-        
-      case WM_COMMAND:
-          if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) {
-              EndDialog(hDlg, TRUE);
-              DeleteObject(hfontDlg);
-              DeleteObject(hFinePrint);
-              return (TRUE);
-          }
-          break;
-   }
-   
-   return FALSE;
-}
+        SetFocus(GetDlgItem(hDlg, IDC_COMPUTER));
+        return TRUE;
 
-LRESULT CALLBACK ServiceDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
-{
+    case WM_COMMAND:
+        switch (LOWORD(wParam))
+        {
+        case IDOK:
+            memset(szCmp, 0, sizeof(szCmp));
+            _tcscpy(szCmp, _T("\\\\"));
+            SendMessage(GetDlgItem(hDlg, IDC_COMPUTER), WM_GETTEXT,
+                        (WPARAM) MAX_COMPUTERNAME_LENGTH,
+                        (LPARAM) szCmp+2);
+
+            _tcsupr(szCmp);
+            if (_tcslen(szCmp) < 3) {
+                EndDialog(hDlg, TRUE);
+                return TRUE;
+            }
+            am_ConnectComputer(szCmp);
+            SendMessage(g_hwndMain, WM_TIMER, WM_TIMER_RESCAN, 0);
 
-    CHAR        tchBuffer[MAX_PATH]; 
-    CHAR        tsbBuffer[MAX_PATH];
-    HWND        hListBox;
-    static HWND hStatusBar; 
-    TEXTMETRIC  tm; 
-    int         i, y; 
-    HDC         hdcMem; 
-    RECT        rcBitmap; 
-    UINT        nItem;
-    LPMEASUREITEMSTRUCT lpmis; 
-    LPDRAWITEMSTRUCT    lpdis; 
-
-    ZeroMemory(tchBuffer, MAX_PATH);
-    ZeroMemory(tsbBuffer, MAX_PATH);
-    switch (message) 
-    { 
-        case WM_INITDIALOG: 
-            ShowWindow(hDlg, SW_HIDE);
-            ap_hServiceDlg = hDlg;
-            hbmpStart = LoadBitmap(ap_hInstance, MAKEINTRESOURCE(IDB_BMPRUN)); 
-            hbmpStop  = LoadBitmap(ap_hInstance, MAKEINTRESOURCE(IDB_BMPSTOP)); 
+        case IDCANCEL:
+            EndDialog(hDlg, TRUE);
+            return TRUE;
 
-            Button_Enable(GetDlgItem(hDlg, IDC_SSTART), FALSE);
-            Button_Enable(GetDlgItem(hDlg, IDC_SSTOP), FALSE);
-            Button_Enable(GetDlgItem(hDlg, IDC_SRESTART), FALSE);
-            hListBox = GetDlgItem(hDlg, IDL_SERVICES); 
-            ap_hStdoutWnd = GetDlgItem(hDlg, IDL_STDOUT);
-            hStatusBar = CreateStatusWindow(SBT_TOOLTIPS | WS_CHILD | WS_VISIBLE,
-                                            "", hDlg, IDC_STATBAR);            
-            if (GetApacheServicesStatus())
-            {
-                i = 0;
-                while (ap_stServices[i].szServiceName != NULL)
-                {    
-                    addItem(hListBox, ap_stServices[i].szDisplayName, 
-                        ap_stServices[i].dwPid == 0 ? hbmpStop : hbmpStart);
-                    ++i;
-                }
+        case IDC_LBROWSE:
+        {
+            BROWSEINFO bi;
+            ITEMIDLIST *il;
+            LPMALLOC pMalloc;
+            memset(&bi, 0, sizeof(BROWSEINFO));
+            SHGetSpecialFolderLocation(hDlg, CSIDL_NETWORK, &il);
+
+            bi.lpszTitle      = _T("ApacheMonitor :\nSelect Network Computer!");
+            bi.pszDisplayName = szCmp;
+            bi.hwndOwner =      hDlg;
+            bi.ulFlags =        BIF_BROWSEFORCOMPUTER;
+            bi.lpfn =           NULL;
+            bi.lParam =         0;
+            bi.iImage =         0;
+            bi.pidlRoot =       il;
+
+            if (SHBrowseForFolder(&bi) != NULL) {
+                SendMessage(GetDlgItem(hDlg, IDC_COMPUTER),
+                            WM_SETTEXT,
+                            (WPARAM) NULL, (LPARAM) szCmp);
+            }
+            if (SHGetMalloc(&pMalloc)) {
+                pMalloc->lpVtbl->Free(pMalloc, il);
+                pMalloc->lpVtbl->Release(pMalloc);
             }
-            CenterWindow(hDlg);
-            ShowWindow(hDlg, SW_SHOW);
-            SetFocus(hListBox); 
-            SendMessage(hListBox, LB_SETCURSEL, 0, 0); 
             return TRUE;
+        }
+        }
         break;
-        case WM_UPDATEMESSAGE:
-            hListBox = GetDlgItem(hDlg, IDL_SERVICES); 
-            SendMessage(hListBox, LB_RESETCONTENT, 0, 0); 
-            Button_Enable(GetDlgItem(hDlg, IDC_SSTART), FALSE);
-            Button_Enable(GetDlgItem(hDlg, IDC_SSTOP), FALSE);
-            Button_Enable(GetDlgItem(hDlg, IDC_SRESTART), FALSE);
+
+    case WM_QUIT:
+    case WM_CLOSE:
+        EndDialog(hDlg, TRUE);
+        return TRUE;
+
+    default:
+        return FALSE;
+    }
+    return FALSE;
+
+}
+
+
+LRESULT CALLBACK ServiceDlgProc(HWND hDlg, UINT message,
+                                WPARAM wParam, LPARAM lParam)
+{
+    TCHAR szBuf[MAX_PATH];
+    HWND hListBox;
+    static HWND hStatusBar;
+    TEXTMETRIC tm;
+    int i, y;
+    HDC hdcMem;
+    RECT rcBitmap;
+    LRESULT nItem;
+    LPMEASUREITEMSTRUCT lpmis;
+    LPDRAWITEMSTRUCT lpdis;
+
+    memset(szBuf, 0, sizeof(szBuf));
+    switch (message)
+    {
+    case WM_INITDIALOG:
+        ShowWindow(hDlg, SW_HIDE);
+        g_hwndServiceDlg = hDlg;
+        SetWindowText(hDlg, g_szTitle);
+        Button_Enable(GetDlgItem(hDlg, IDC_SSTART), FALSE);
+        Button_Enable(GetDlgItem(hDlg, IDC_SSTOP), FALSE);
+        Button_Enable(GetDlgItem(hDlg, IDC_SRESTART), FALSE);
+        Button_Enable(GetDlgItem(hDlg, IDC_SDISCONN), FALSE);
+        SetWindowText(GetDlgItem(hDlg, IDC_SSTART),
+                      g_lpMsg[IDS_MSG_SSTART - IDS_MSG_FIRST]);
+        SetWindowText(GetDlgItem(hDlg, IDC_SSTOP),
+                      g_lpMsg[IDS_MSG_SSTOP - IDS_MSG_FIRST]);
+        SetWindowText(GetDlgItem(hDlg, IDC_SRESTART),
+                      g_lpMsg[IDS_MSG_SRESTART - IDS_MSG_FIRST]);
+        SetWindowText(GetDlgItem(hDlg, IDC_SMANAGER),
+                      g_lpMsg[IDS_MSG_SERVICES - IDS_MSG_FIRST]);
+        SetWindowText(GetDlgItem(hDlg, IDC_SCONNECT),
+                      g_lpMsg[IDS_MSG_CONNECT - IDS_MSG_FIRST]);
+        SetWindowText(GetDlgItem(hDlg, IDCANCEL),
+                      g_lpMsg[IDS_MSG_OK - IDS_MSG_FIRST]);
+        hListBox = GetDlgItem(hDlg, IDL_SERVICES);
+        g_hwndStdoutList = GetDlgItem(hDlg, IDL_STDOUT);
+        hStatusBar = CreateStatusWindow(0x0800 /* SBT_TOOLTIPS */
+                                      | WS_CHILD | WS_VISIBLE,
+                                        _T(""), hDlg, IDC_STATBAR);
+        if (GetApacheServicesStatus())
+        {
             i = 0;
-            while (ap_stServices[i].szServiceName != NULL)
-            {    
-                addItem(hListBox, ap_stServices[i].szDisplayName, 
-                    ap_stServices[i].dwPid == 0 ? hbmpStop : hbmpStart);
+            while (g_stServices[i].szServiceName != NULL)
+            {
+                addListBoxItem(hListBox, g_stServices[i].szDisplayName,
+                               g_stServices[i].dwPid == 0 ? g_hBmpStop
+                                                          : g_hBmpStart);
                 ++i;
             }
-            SendMessage(hListBox, LB_SETCURSEL, 0, 0); 
-            /* Dirty hack to bring the window to the foreground */
-            SetWindowPos(hDlg, HWND_TOPMOST, 0, 0, 0, 0,
-                                    SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);
-            SetWindowPos(hDlg, HWND_NOTOPMOST, 0, 0, 0, 0,
-                                    SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);
-            SetFocus(hListBox); 
-            return TRUE;
+        }
+        CenterWindow(hDlg);
+        ShowWindow(hDlg, SW_SHOW);
+        SetFocus(hListBox);
+        SendMessage(hListBox, LB_SETCURSEL, 0, 0);
+        return TRUE;
         break;
-        case WM_MEASUREITEM: 
-            lpmis = (LPMEASUREITEMSTRUCT) lParam; 
-            lpmis->itemHeight = 16; 
-            return TRUE; 
-        case WM_SETCURSOR:
-            if (ap_consoleRun)
-                SetCursor(ap_cHourglass);
-            else
-                SetCursor(ap_cArrow);
-            return TRUE;
-        case WM_DRAWITEM: 
-            lpdis = (LPDRAWITEMSTRUCT) lParam; 
-            if (lpdis->itemID == -1) 
-            { 
-                break; 
-            } 
-            switch (lpdis->itemAction) 
-            { 
-                case ODA_SELECT: 
-                case ODA_DRAWENTIRE: 
-                    hbmpPicture = (HBITMAP)SendMessage(lpdis->hwndItem, 
-                        LB_GETITEMDATA, lpdis->itemID, (LPARAM) 0); 
-                    hdcMem = CreateCompatibleDC(lpdis->hDC); 
-                    hbmpOld = SelectObject(hdcMem, hbmpPicture); 
-                    BitBlt(lpdis->hDC, 
-                        lpdis->rcItem.left, lpdis->rcItem.top, 
-                        lpdis->rcItem.right - lpdis->rcItem.left, 
-                        lpdis->rcItem.bottom - lpdis->rcItem.top, 
-                        hdcMem, 0, 0, SRCCOPY); 
-                    SendMessage(lpdis->hwndItem, LB_GETTEXT, 
-                        lpdis->itemID, (LPARAM) tchBuffer); 
-                    GetTextMetrics(lpdis->hDC, &tm);  
-                    y = (lpdis->rcItem.bottom + lpdis->rcItem.top - 
-                        tm.tmHeight) / 2; 
-  
-                    SelectObject(hdcMem, hbmpOld); 
-                    DeleteDC(hdcMem); 
-                    rcBitmap.left = lpdis->rcItem.left + XBITMAP + 2; 
-                    rcBitmap.top = lpdis->rcItem.top; 
-                    rcBitmap.right = lpdis->rcItem.right; 
-                    rcBitmap.bottom = lpdis->rcItem.top + YBITMAP; 
-
-                    if (lpdis->itemState & ODS_SELECTED) 
-                    { 
-                        if (hbmpPicture == hbmpStop)
-                        {
-                            Button_Enable(GetDlgItem(hDlg, IDC_SSTART), TRUE);
-                            Button_Enable(GetDlgItem(hDlg, IDC_SSTOP), FALSE);
-                            Button_Enable(GetDlgItem(hDlg, IDC_SRESTART), FALSE);
-                        }
-                        else if (hbmpPicture == hbmpStart) 
-                        {
-                            Button_Enable(GetDlgItem(hDlg, IDC_SSTART), FALSE);
-                            Button_Enable(GetDlgItem(hDlg, IDC_SSTOP), TRUE);
-                            Button_Enable(GetDlgItem(hDlg, IDC_SRESTART), TRUE);
-                        }
-                        if (ap_stServices[lpdis->itemID].szDescription)
-                            lstrcpy(tsbBuffer, ap_stServices[lpdis->itemID].szDescription); 
-                        SendMessage(hStatusBar, SB_SETTEXT, 0, (LPARAM)tsbBuffer);
-                        
-                        SetTextColor(lpdis->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT)); 
-                        SetBkColor(lpdis->hDC, GetSysColor(COLOR_HIGHLIGHT)); 
-                        FillRect(lpdis->hDC, &rcBitmap, (HBRUSH)(COLOR_HIGHLIGHTTEXT)); 
-                    } 
-                    else
-                    {
-                       SetTextColor(lpdis->hDC, GetSysColor(COLOR_MENUTEXT)); 
-                       SetBkColor(lpdis->hDC, GetSysColor(COLOR_WINDOW)); 
-                       FillRect(lpdis->hDC, &rcBitmap, (HBRUSH)(COLOR_WINDOW+1)); 
-                    }
-                    TextOut(lpdis->hDC, 
-                        XBITMAP + 6, 
-                        y, 
-                        tchBuffer, 
-                        strlen(tchBuffer)); 
-                    break; 
-                case ODA_FOCUS: 
-                    break; 
-            } 
-            return TRUE;  
-        case WM_COMMAND: 
-            switch (LOWORD(wParam)) 
-            { 
-                case IDL_SERVICES:
-                    switch (HIWORD(wParam))
-                    {
-                        case LBN_DBLCLK:
-                            /* if started then stop, if stopped the start the service */
-                            hListBox = GetDlgItem(hDlg, IDL_SERVICES); 
-                            nItem = SendMessage(hListBox, LB_GETCURSEL, 0, 0); 
-                            if (nItem != LB_ERR)
-                            {
-                                hbmpPicture = (HBITMAP)SendMessage(hListBox, LB_GETITEMDATA,
-                                                               nItem, (LPARAM) 0); 
-                                if (hbmpPicture == hbmpStop)
-                                {
-                                    ApacheManageService(ap_stServices[nItem].szServiceName,
-                                                ap_stServices[nItem].szImagePath,
-                                                SERVICE_CONTROL_CONTINUE);
-                                }
-                                else
-                                    ApacheManageService(ap_stServices[nItem].szServiceName,
-                                                ap_stServices[nItem].szImagePath,
-                                                SERVICE_CONTROL_STOP);
 
-                            }
-                            return TRUE;
-                        break;
-                     }
-                break;
-                case IDOK: 
-                    EndDialog(hDlg, TRUE); 
-                    return TRUE; 
-                break;
-                case IDC_SSTART: 
-                    Button_Enable(GetDlgItem(hDlg, IDC_SSTART), FALSE);
-                    hListBox = GetDlgItem(hDlg, IDL_SERVICES); 
-                    nItem = SendMessage(hListBox, LB_GETCURSEL, 0, 0); 
-                    if (nItem != LB_ERR)
-                    {
-                        ApacheManageService(ap_stServices[nItem].szServiceName,
-                                             ap_stServices[nItem].szImagePath,
-                                             SERVICE_CONTROL_CONTINUE);
-                    }
+    case WM_MANAGEMESSAGE:
+        ApacheManageService(g_stServices[LOWORD(wParam)].szServiceName,
+                    g_stServices[LOWORD(wParam)].szImagePath,
+                    g_stServices[LOWORD(wParam)].szComputerName,
+                    LOWORD(lParam));
+
+        return TRUE;
+        break;
+
+    case WM_UPDATEMESSAGE:
+        hListBox = GetDlgItem(hDlg, IDL_SERVICES);
+        SendMessage(hListBox, LB_RESETCONTENT, 0, 0);
+        SendMessage(hStatusBar, SB_SETTEXT, 0, (LPARAM)_T(""));
+        Button_Enable(GetDlgItem(hDlg, IDC_SSTART), FALSE);
+        Button_Enable(GetDlgItem(hDlg, IDC_SSTOP), FALSE);
+        Button_Enable(GetDlgItem(hDlg, IDC_SRESTART), FALSE);
+        Button_Enable(GetDlgItem(hDlg, IDC_SDISCONN), FALSE);
+        i = 0;
+        while (g_stServices[i].szServiceName != NULL)
+        {
+            addListBoxItem(hListBox, g_stServices[i].szDisplayName,
+                g_stServices[i].dwPid == 0 ? g_hBmpStop : g_hBmpStart);
+            ++i;
+        }
+        SendMessage(hListBox, LB_SETCURSEL, 0, 0);
+        /* Dirty hack to bring the window to the foreground */
+        SetWindowPos(hDlg, HWND_TOPMOST, 0, 0, 0, 0,
+                                SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);
+        SetWindowPos(hDlg, HWND_NOTOPMOST, 0, 0, 0, 0,
+                                SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);
+        SetFocus(hListBox);
+        return TRUE;
+        break;
+
+    case WM_MEASUREITEM:
+        lpmis = (LPMEASUREITEMSTRUCT) lParam;
+        lpmis->itemHeight = YBITMAP;
+        return TRUE;
+
+    case WM_SETCURSOR:
+        if (g_bConsoleRun) {
+            SetCursor(g_hCursorHourglass);
+        }
+        else {
+            SetCursor(g_hCursorArrow);
+        }
+        return TRUE;
+
+    case WM_DRAWITEM:
+        lpdis = (LPDRAWITEMSTRUCT) lParam;
+        if (lpdis->itemID == -1) {
+            break;
+        }
+        switch (lpdis->itemAction)
+        {
+        case ODA_FOCUS:
+        case ODA_SELECT:
+        case ODA_DRAWENTIRE:
+            g_hBmpPicture = (HBITMAP)SendMessage(lpdis->hwndItem,
+                                                 LB_GETITEMDATA,
+                                                 lpdis->itemID, (LPARAM) 0);
+
+            hdcMem = CreateCompatibleDC(lpdis->hDC);
+            g_hBmpOld = SelectObject(hdcMem, g_hBmpPicture);
+
+            BitBlt(lpdis->hDC, lpdis->rcItem.left, lpdis->rcItem.top,
+                   lpdis->rcItem.right - lpdis->rcItem.left,
+                   lpdis->rcItem.bottom - lpdis->rcItem.top,
+                   hdcMem, 0, 0, SRCCOPY);
+            SendMessage(lpdis->hwndItem, LB_GETTEXT,
+                        lpdis->itemID, (LPARAM) szBuf);
+
+            GetTextMetrics(lpdis->hDC, &tm);
+            y = (lpdis->rcItem.bottom + lpdis->rcItem.top - tm.tmHeight) / 2;
+
+            SelectObject(hdcMem, g_hBmpOld);
+            DeleteDC(hdcMem);
+
+            rcBitmap.left = lpdis->rcItem.left + XBITMAP + 2;
+            rcBitmap.top = lpdis->rcItem.top;
+            rcBitmap.right = lpdis->rcItem.right;
+            rcBitmap.bottom = lpdis->rcItem.top + YBITMAP;
+
+            if (lpdis->itemState & ODS_SELECTED)
+            {
+                if (g_hBmpPicture == g_hBmpStop)
+                {
                     Button_Enable(GetDlgItem(hDlg, IDC_SSTART), TRUE);
-                    return TRUE;
-                break;
-                case IDC_SSTOP: 
+                    Button_SetStyle(GetDlgItem(hDlg, IDC_SSTART), BS_DEFPUSHBUTTON, TRUE);
                     Button_Enable(GetDlgItem(hDlg, IDC_SSTOP), FALSE);
-                    hListBox = GetDlgItem(hDlg, IDL_SERVICES); 
-                    nItem = SendMessage(hListBox, LB_GETCURSEL, 0, 0); 
-                    if (nItem != LB_ERR)
-                    {
-                        ApacheManageService(ap_stServices[nItem].szServiceName,
-                                             ap_stServices[nItem].szImagePath,
-                                             SERVICE_CONTROL_STOP);
-                    }
+                    Button_Enable(GetDlgItem(hDlg, IDC_SRESTART), FALSE);
+                }
+                else if (g_hBmpPicture == g_hBmpStart)
+                {
+                    Button_Enable(GetDlgItem(hDlg, IDC_SSTART), FALSE);
                     Button_Enable(GetDlgItem(hDlg, IDC_SSTOP), TRUE);
-                    return TRUE;
-                break;
-                case IDC_SRESTART: 
+                    Button_SetStyle(GetDlgItem(hDlg, IDC_SSTOP), BS_DEFPUSHBUTTON, TRUE);
+                    Button_Enable(GetDlgItem(hDlg, IDC_SRESTART), TRUE);
+                }
+                else {
+                    Button_Enable(GetDlgItem(hDlg, IDC_SSTART), FALSE);
+                    Button_Enable(GetDlgItem(hDlg, IDC_SSTOP), FALSE);
                     Button_Enable(GetDlgItem(hDlg, IDC_SRESTART), FALSE);
-                    hListBox = GetDlgItem(hDlg, IDL_SERVICES); 
-                    nItem = SendMessage(hListBox, LB_GETCURSEL, 0, 0); 
-                    if (nItem != LB_ERR)
-                    {
-                        ApacheManageService(ap_stServices[nItem].szServiceName,
-                                             ap_stServices[nItem].szImagePath,
-                                             SERVICE_APACHE_RESTART);
+                }
+                if (_tcscmp(g_stServices[lpdis->itemID].szComputerName,
+                           g_szLocalHost) == 0) {
+                    Button_Enable(GetDlgItem(hDlg, IDC_SDISCONN), FALSE);
+                }
+                else {
+                    Button_Enable(GetDlgItem(hDlg, IDC_SDISCONN), TRUE);
+                }
+
+                if (g_stServices[lpdis->itemID].szDescription) {
+                    SendMessage(hStatusBar, SB_SETTEXT, 0,
+                            (LPARAM)g_stServices[lpdis->itemID].szDescription);
+                }
+                else {
+                    SendMessage(hStatusBar, SB_SETTEXT, 0, (LPARAM)_T(""));
+                }
+                if (lpdis->itemState & ODS_FOCUS) {
+                    SetTextColor(lpdis->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
+                    SetBkColor(lpdis->hDC, GetSysColor(COLOR_HIGHLIGHT));
+                    FillRect(lpdis->hDC, &rcBitmap, (HBRUSH)(COLOR_HIGHLIGHT+1));
+                }
+                else {
+                    SetTextColor(lpdis->hDC, GetSysColor(COLOR_INACTIVECAPTIONTEXT));
+                    SetBkColor(lpdis->hDC, GetSysColor(COLOR_INACTIVECAPTION));
+                    FillRect(lpdis->hDC, &rcBitmap, (HBRUSH)(COLOR_INACTIVECAPTION+1));
+                }
+            }
+            else
+            {
+               SetTextColor(lpdis->hDC, GetSysColor(COLOR_MENUTEXT));
+               SetBkColor(lpdis->hDC, GetSysColor(COLOR_WINDOW));
+               FillRect(lpdis->hDC, &rcBitmap, (HBRUSH)(COLOR_WINDOW+1));
+            }
+            TextOut(lpdis->hDC, XBITMAP + 6, y, szBuf, (int)_tcslen(szBuf));
+            break;
+        }
+        return TRUE;
+    case WM_COMMAND:
+        switch (LOWORD(wParam))
+        {
+        case IDL_SERVICES:
+            switch (HIWORD(wParam))
+            {
+            case LBN_DBLCLK:
+                /* if started then stop, if stopped then start */
+                hListBox = GetDlgItem(hDlg, IDL_SERVICES);
+                nItem = SendMessage(hListBox, LB_GETCURSEL, 0, 0);
+                if (nItem != LB_ERR)
+                {
+                    g_hBmpPicture = (HBITMAP)SendMessage(hListBox,
+                                                         LB_GETITEMDATA,
+                                                         nItem, (LPARAM) 0);
+                    if (g_hBmpPicture == g_hBmpStop) {
+                        SendMessage(hDlg, WM_MANAGEMESSAGE, nItem,
+                                    SERVICE_CONTROL_CONTINUE);
                     }
-                    Button_Enable(GetDlgItem(hDlg, IDC_SRESTART), TRUE);
-                    return TRUE;
-                break;
-                case IDC_SABOUT: 
-                   if (!dlgAboutOn)
-                   {
-                      dlgAboutOn = TRUE;
-                      DialogBox(ap_hInstance, MAKEINTRESOURCE(IDD_ABOUTBOX),
-                             ap_hMainWnd, (DLGPROC)AboutDlgProc);
-                      dlgAboutOn = FALSE;
-                      ap_hwndAboutDlg = NULL;                      
-                   }
-                   else if (ap_hwndAboutDlg)
-                       SetFocus(ap_hwndAboutDlg);
-                    return TRUE;
-                break;
-             }
-        break;
-        case WM_SIZE:
-            switch (LOWORD(wParam)) 
-            { 
-                case SIZE_MINIMIZED:
-                    EndDialog(hDlg, TRUE); 
-                    return TRUE; 
-                break;
+                    else {
+                        SendMessage(hDlg, WM_MANAGEMESSAGE, nItem,
+                                    SERVICE_CONTROL_STOP);
+                    }
+
+                }
+                return TRUE;
             }
-        break;
-        case WM_CLOSE: 
+            break;
+
+        case IDCANCEL:
             EndDialog(hDlg, TRUE);
             return TRUE;
-        case WM_DESTROY: 
-            DeleteObject(hbmpStart); 
-            DeleteObject(hbmpStop); 
-            return TRUE; 
-        default:
-            return FALSE;
-    }
-    return FALSE;
-}
 
+        case IDC_SSTART:
+            Button_Enable(GetDlgItem(hDlg, IDC_SSTART), FALSE);
+            hListBox = GetDlgItem(hDlg, IDL_SERVICES);
+            nItem = SendMessage(hListBox, LB_GETCURSEL, 0, 0);
+            if (nItem != LB_ERR) {
+                SendMessage(hDlg, WM_MANAGEMESSAGE, nItem,
+                            SERVICE_CONTROL_CONTINUE);
+            }
+            Button_Enable(GetDlgItem(hDlg, IDC_SSTART), TRUE);
+            return TRUE;
 
-VOID CALLBACK MainTimerProc(HWND hWnd, UINT uMsg, UINT idEvent, DWORD dwTime)
-{
-    int nPrev = 0, nNew = 0;
-    if (idEvent == WM_TIMER_RESCAN)
-    {
-        if (FindRunningServices() || ap_rescanServices)
-        {
-            ShowNotifyIcon(hWnd, NIM_MODIFY);
-            if (ap_hServiceDlg)
-                PostMessage(ap_hServiceDlg, WM_UPDATEMESSAGE, 0, 0);
-        }
-        /* check if services list changed */
-        while (ap_stServices[nPrev].szServiceName != NULL)
-            ++nPrev;
-        GetApacheServicesStatus();
-        while (ap_stServices[nNew].szServiceName != NULL)
-            ++nNew;
-        if (nPrev != nNew)
-        {
-            ShowNotifyIcon(hWnd, NIM_MODIFY);
-            if (ap_hServiceDlg)
-                PostMessage(ap_hServiceDlg, WM_UPDATEMESSAGE, 0, 0);
-        }
-    }
-    else if (idEvent == WM_TIMER_REFRESH)
-    {
-        if (ap_rescanServices)
-        {
-            GetApacheServicesStatus();
-            ShowNotifyIcon(hWnd, NIM_MODIFY);
-            if (ap_hServiceDlg)
-                PostMessage(ap_hServiceDlg, WM_UPDATEMESSAGE, 0, 0);
+        case IDC_SSTOP:
+            Button_Enable(GetDlgItem(hDlg, IDC_SSTOP), FALSE);
+            hListBox = GetDlgItem(hDlg, IDL_SERVICES);
+            nItem = SendMessage(hListBox, LB_GETCURSEL, 0, 0);
+            if (nItem != LB_ERR) {
+                SendMessage(hDlg, WM_MANAGEMESSAGE, nItem,
+                            SERVICE_CONTROL_STOP);
+            }
+            Button_Enable(GetDlgItem(hDlg, IDC_SSTOP), TRUE);
+            return TRUE;
+
+        case IDC_SRESTART:
+            Button_Enable(GetDlgItem(hDlg, IDC_SRESTART), FALSE);
+            hListBox = GetDlgItem(hDlg, IDL_SERVICES);
+            nItem = SendMessage(hListBox, LB_GETCURSEL, 0, 0);
+            if (nItem != LB_ERR) {
+                SendMessage(hDlg, WM_MANAGEMESSAGE, nItem,
+                            SERVICE_APACHE_RESTART);
+            }
+            Button_Enable(GetDlgItem(hDlg, IDC_SRESTART), TRUE);
+            return TRUE;
+
+        case IDC_SMANAGER:
+            if (g_dwOSVersion >= OS_VERSION_WIN2K) {
+                ShellExecute(hDlg, _T("open"), _T("services.msc"), _T("/s"),
+                             NULL, SW_NORMAL);
+            }
+            else {
+                WinExec("Control.exe SrvMgr.cpl Services", SW_NORMAL);
+            }
+            return TRUE;
+
+        case IDC_SCONNECT:
+            DialogBox(g_hInstance, MAKEINTRESOURCE(IDD_DLGCONNECT),
+                      hDlg, (DLGPROC)ConnectDlgProc);
+            return TRUE;
+
+        case IDC_SDISCONN:
+            hListBox = GetDlgItem(hDlg, IDL_SERVICES);
+            nItem = SendMessage(hListBox, LB_GETCURSEL, 0, 0);
+            if (nItem != LB_ERR) {
+                am_DisconnectComputer(g_stServices[nItem].szComputerName);
+                SendMessage(g_hwndMain, WM_TIMER, WM_TIMER_RESCAN, 0);
+            }
+            return TRUE;
         }
-        else if (FindRunningServices())
+        break;
+
+    case WM_SIZE:
+        switch (LOWORD(wParam))
         {
-            ShowNotifyIcon(hWnd, NIM_MODIFY);
-            if (ap_hServiceDlg)
-                PostMessage(ap_hServiceDlg, WM_UPDATEMESSAGE, 0, 0);
+        case SIZE_MINIMIZED:
+            EndDialog(hDlg, TRUE);
+            return TRUE;
+            break;
         }
+        break;
+
+    case WM_QUIT:
+    case WM_CLOSE:
+        EndDialog(hDlg, TRUE);
+        return TRUE;
+
+    default:
+        return FALSE;
     }
+    return FALSE;
 }
 
 
 LRESULT CALLBACK WndProc(HWND hWnd, UINT message,
                           WPARAM wParam, LPARAM lParam)
 {
-    
-    if (message == ap_uiTaskbarCreated)
+    if (message == g_bUiTaskbarCreated)
     {
         /* restore the tray icon on shell restart */
         ShowNotifyIcon(hWnd, NIM_ADD);
         return DefWindowProc(hWnd, message, wParam, lParam);
     }
-    switch (message) 
+    switch (message)
     {
-        case WM_CREATE:
-            GetSystemOSVersion(NULL, &ap_OSVersion);
+    case WM_CREATE:
+        GetApacheServicesStatus();
+        ShowNotifyIcon(hWnd, NIM_ADD);
+        SetTimer(hWnd, WM_TIMER_REFRESH, REFRESH_TIME, NULL);
+        SetTimer(hWnd, WM_TIMER_RESCAN,  RESCAN_TIME, NULL);
+        break;
+
+    case WM_TIMER:
+        switch (wParam)
+        {
+        case WM_TIMER_RESCAN:
+        {
+            int nPrev = 0, nNew = 0;
+            EnterCriticalSection(&g_stcSection);
+            if (FindRunningServices() || g_bRescanServices)
+            {
+                ShowNotifyIcon(hWnd, NIM_MODIFY);
+                if (g_hwndServiceDlg)
+                    PostMessage(g_hwndServiceDlg, WM_UPDATEMESSAGE, 0, 0);
+            }
+            /* check if services list changed */
+            while (g_stServices[nPrev].szServiceName != NULL)
+                ++nPrev;
             GetApacheServicesStatus();
-            ShowNotifyIcon(hWnd, NIM_ADD);
-            SetTimer(hWnd, WM_TIMER_REFRESH, REFRESH_TIME, (TIMERPROC)MainTimerProc);
-            SetTimer(hWnd, WM_TIMER_RESCAN,  RESCAN_TIME, (TIMERPROC)MainTimerProc);
-            ap_hServiceDlg = NULL;                      
+            while (g_stServices[nNew].szServiceName != NULL)
+                ++nNew;
+            if (nPrev != nNew)
+            {
+                ShowNotifyIcon(hWnd, NIM_MODIFY);
+                if (g_hwndServiceDlg) {
+                    PostMessage(g_hwndServiceDlg, WM_UPDATEMESSAGE, 0, 0);
+                }
+            }
+            LeaveCriticalSection(&g_stcSection);
+            break;
+        }
+
+        case WM_TIMER_REFRESH:
+        {
+            EnterCriticalSection(&g_stcSection);
+            if (g_bRescanServices)
+            {
+                GetApacheServicesStatus();
+                ShowNotifyIcon(hWnd, NIM_MODIFY);
+                if (g_hwndServiceDlg) {
+                    PostMessage(g_hwndServiceDlg, WM_UPDATEMESSAGE, 0, 0);
+                }
+            }
+            else if (FindRunningServices())
+            {
+                ShowNotifyIcon(hWnd, NIM_MODIFY);
+                if (g_hwndServiceDlg) {
+                    PostMessage(g_hwndServiceDlg, WM_UPDATEMESSAGE, 0, 0);
+                }
+            }
+            LeaveCriticalSection(&g_stcSection);
+            break;
+        }
+        }
         break;
-        case WM_QUIT:
-            ShowNotifyIcon(hWnd, NIM_DELETE);
+
+    case WM_QUIT:
+        ShowNotifyIcon(hWnd, NIM_DELETE);
         break;
-        case WM_TRAYMESSAGE:
-            switch(lParam)
+
+    case WM_TRAYMESSAGE:
+        switch (lParam)
+        {
+        case WM_LBUTTONDBLCLK:
+            if (!g_bDlgServiceOn)
+            {
+                g_bDlgServiceOn = TRUE;
+                DialogBox(g_hInstance, MAKEINTRESOURCE(IDD_DLGSERVICES),
+                          hWnd, (DLGPROC)ServiceDlgProc);
+                g_bDlgServiceOn = FALSE;
+                g_hwndServiceDlg = NULL;
+            }
+            else if (IsWindow(g_hwndServiceDlg))
             {
-                case WM_LBUTTONDBLCLK:
-                   if (!dlgServiceOn)
-                   {
-                       dlgServiceOn = TRUE;
-                       DialogBox(ap_hInstance, MAKEINTRESOURCE(IDD_APSRVMON_DIALOG),
-                             hWnd, (DLGPROC)ServiceDlgProc);
-                       dlgServiceOn = FALSE;
-                       ap_hServiceDlg = NULL;
-                   }
-                   else if (ap_hServiceDlg)
-                   {
-                       /* Dirty hack to bring the window to the foreground */
-                       SetWindowPos(ap_hServiceDlg, HWND_TOPMOST, 0, 0, 0, 0,
-                                    SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);
-                       SetWindowPos(ap_hServiceDlg, HWND_NOTOPMOST, 0, 0, 0, 0,
-                                    SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);
-                       SetFocus(ap_hServiceDlg);
-                   }
-                break;
-                case WM_RBUTTONUP:
-                    ShowTryPopupMenu(hWnd);
-                break;    
+                /* Dirty hack to bring the window to the foreground */
+                SetWindowPos(g_hwndServiceDlg, HWND_TOPMOST, 0, 0, 0, 0,
+                             SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);
+                SetWindowPos(g_hwndServiceDlg, HWND_NOTOPMOST, 0, 0, 0, 0,
+                             SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);
+                SetFocus(g_hwndServiceDlg);
             }
             break;
-        case WM_COMMAND:
-            switch (LOWORD(wParam))
+
+        case WM_LBUTTONUP:
+            ShowTryServicesMenu(hWnd);
+            break;
+
+        case WM_RBUTTONUP:
+            ShowTryPopupMenu(hWnd);
+            break;
+        }
+        break;
+
+    case WM_COMMAND:
+        if ((LOWORD(wParam) & IDM_SM_START) == IDM_SM_START)
+        {
+            ApacheManageService(g_stServices[LOWORD(wParam)
+                                           - IDM_SM_START].szServiceName,
+                                g_stServices[LOWORD(wParam)
+                                           - IDM_SM_START].szImagePath,
+                                g_stServices[LOWORD(wParam)
+                                           - IDM_SM_START].szComputerName,
+                                SERVICE_CONTROL_CONTINUE);
+            return TRUE;
+        }
+        else if ((LOWORD(wParam) & IDM_SM_STOP) == IDM_SM_STOP)
+        {
+            ApacheManageService(g_stServices[LOWORD(wParam)
+                                           - IDM_SM_STOP].szServiceName,
+                                g_stServices[LOWORD(wParam)
+                                           - IDM_SM_STOP].szImagePath,
+                                g_stServices[LOWORD(wParam)
+                                           - IDM_SM_STOP].szComputerName,
+                                SERVICE_CONTROL_STOP);
+            return TRUE;
+        }
+        else if ((LOWORD(wParam) & IDM_SM_RESTART) == IDM_SM_RESTART)
+        {
+            ApacheManageService(g_stServices[LOWORD(wParam)
+                                           - IDM_SM_RESTART].szServiceName,
+                                g_stServices[LOWORD(wParam)
+                                           - IDM_SM_RESTART].szImagePath,
+                                g_stServices[LOWORD(wParam)
+                                           - IDM_SM_RESTART].szComputerName,
+                                SERVICE_APACHE_RESTART);
+            return TRUE;
+        }
+        switch (LOWORD(wParam))
+        {
+        case IDM_RESTORE:
+            if (!g_bDlgServiceOn)
             {
-               case IDM_RESTORE:
-                   if (!dlgServiceOn)
-                   {
-                       dlgServiceOn = TRUE;
-                       DialogBox(ap_hInstance, MAKEINTRESOURCE(IDD_APSRVMON_DIALOG),
-                             hWnd, (DLGPROC)ServiceDlgProc);
-                       dlgServiceOn = FALSE;
-                       ap_hServiceDlg = NULL;
-                   }
-                   else if (ap_hServiceDlg)
-                       SetFocus(ap_hServiceDlg);
-               break;
-               case IDM_ABOUT:
-                   if (!dlgAboutOn)
-                   {
-                      dlgAboutOn = TRUE;
-                      DialogBox(ap_hInstance, MAKEINTRESOURCE(IDD_ABOUTBOX),
-                             hWnd, (DLGPROC)AboutDlgProc);
-                      dlgAboutOn = FALSE;
-                      ap_hwndAboutDlg = NULL;                      
-                   }
-                   else if (ap_hwndAboutDlg)
-                       SetFocus(ap_hwndAboutDlg);
-                break;
-                case IDM_EXIT:
-                    ShowNotifyIcon(hWnd, NIM_DELETE);
-                    PostQuitMessage(0);
-                    return TRUE;
-                break;
+                g_bDlgServiceOn = TRUE;
+                DialogBox(g_hInstance, MAKEINTRESOURCE(IDD_DLGSERVICES),
+                          hWnd, (DLGPROC)ServiceDlgProc);
+                g_bDlgServiceOn = FALSE;
+                g_hwndServiceDlg = NULL;
+            }
+            else if (IsWindow(g_hwndServiceDlg)) {
+                SetFocus(g_hwndServiceDlg);
+            }
+            break;
+
+        case IDC_SMANAGER:
+            if (g_dwOSVersion >= OS_VERSION_WIN2K) {
+                ShellExecute(NULL, _T("open"), _T("services.msc"), _T("/s"),
+                             NULL, SW_NORMAL);
+            }
+            else {
+                WinExec("Control.exe SrvMgr.cpl Services", SW_NORMAL);
             }
-        default:
-            return DefWindowProc(hWnd, message, wParam, lParam);
+            return TRUE;
+
+        case IDM_EXIT:
+            ShowNotifyIcon(hWnd, NIM_DELETE);
+            PostQuitMessage(0);
+            return TRUE;
+        }
+
+    default:
+        return DefWindowProc(hWnd, message, wParam, lParam);
     }
 
     return FALSE;
 }
 
+
+static int KillAWindow(HWND appwindow)
+{
+    HANDLE appproc;
+    DWORD procid;
+    BOOL postres;
+
+    SetLastError(0);
+    GetWindowThreadProcessId(appwindow, &procid);
+    if (GetLastError())
+        return(2);
+
+    appproc = OpenProcess(SYNCHRONIZE, 0, procid);
+    postres = PostMessage(appwindow, WM_COMMAND, IDM_EXIT, 0);
+    if (appproc && postres) {
+        if (WaitForSingleObject(appproc, 10 /* seconds */ * 1000)
+                == WAIT_OBJECT_0) {
+            CloseHandle(appproc);
+            return (0);
+        }
+    }
+    if (appproc)
+        CloseHandle(appproc);
+
+    if ((appproc = OpenProcess(PROCESS_TERMINATE, 0, procid)) != NULL) {
+        if (TerminateProcess(appproc, 0)) {
+            CloseHandle(appproc);
+            return (0);
+        }
+        CloseHandle(appproc);
+    }
+
+    /* Perhaps we were short of permissions? */
+    return (2);
+}
+
+
+static int KillAllMonitors(void)
+{
+    HWND appwindow;
+    int exitcode = 0;
+    PWTS_PROCESS_INFO tsProcs;
+    DWORD tsProcCount, i;
+    DWORD thisProcId;
+
+    /* This is graceful, close our own Window, clearing the icon */
+    if ((appwindow = FindWindow(g_szWindowClass, g_szTitle)) != NULL)
+        exitcode = KillAWindow(appwindow);
+
+    if (g_dwOSVersion < OS_VERSION_WIN2K)
+        return exitcode;
+
+    thisProcId = GetCurrentProcessId();
+
+    if (!WTSEnumerateProcesses(WTS_CURRENT_SERVER_HANDLE, 0, 1,
+                               &tsProcs, &tsProcCount))
+        return exitcode;
+
+    /* This is ungraceful; close other Windows, with a lingering icon.
+     * Since on terminal server it's not possible to post the message
+     * to exit across sessions, we have to suffer this side effect
+     * of a taskbar 'icon' which will evaporate the next time that
+     * the user hovers over it or when the taskbar area is updated.
+     */
+    for (i = 0; i < tsProcCount; ++i) {
+        if (_tcscmp(tsProcs[i].pProcessName, _T(AM_STRINGIFY(BIN_NAME))) == 0
+                && tsProcs[i].ProcessId != thisProcId)
+            WTSTerminateProcess(WTS_CURRENT_SERVER_HANDLE,
+                                tsProcs[i].ProcessId, 1);
+    }
+    WTSFreeMemory(tsProcs);
+    return exitcode;
+}
+
+
 /* Create main invisible window */
 HWND CreateMainWindow(HINSTANCE hInstance)
 {
-    HWND       hWnd = NULL;
+    HWND hWnd = NULL;
     WNDCLASSEX wcex;
 
-    wcex.cbSize = sizeof(WNDCLASSEX); 
+    wcex.cbSize = sizeof(WNDCLASSEX);
 
     wcex.style          = CS_HREDRAW | CS_VREDRAW;
     wcex.lpfnWndProc    = (WNDPROC)WndProc;
     wcex.cbClsExtra     = 0;
     wcex.cbWndExtra     = 0;
     wcex.hInstance      = hInstance;
-    wcex.hIcon          = LoadIcon(hInstance, (LPCTSTR)IDI_APSRVMON);
-    wcex.hCursor        = ap_cArrow;
+    wcex.hIcon   = (HICON)LoadImage(hInstance, MAKEINTRESOURCE(IDI_APSRVMON),
+                                    IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR);
+    wcex.hCursor        = g_hCursorArrow;
     wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
-    wcex.lpszMenuName   = (LPCSTR)IDC_APSRVMON;
-    wcex.lpszClassName  = szWindowClass;
-    wcex.hIconSm        = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_APSMALL);
-
-    if (RegisterClassEx(&wcex))
-    {
-        hWnd = CreateWindow(szWindowClass, szTitle,
-                             0, 0, 0, 0, 0,
-                             NULL, NULL, hInstance, NULL);
+    wcex.lpszMenuName   = 0;
+    wcex.lpszClassName  = g_szWindowClass;
+    wcex.hIconSm = (HICON)LoadImage(hInstance, MAKEINTRESOURCE(IDI_APSRVMON),
+                                    IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
+
+    if (RegisterClassEx(&wcex)) {
+        hWnd = CreateWindow(g_szWindowClass, g_szTitle,
+                            0, 0, 0, 0, 0,
+                            NULL, NULL, hInstance, NULL);
     }
-
     return hWnd;
-
 }
 
 
-int WINAPI WinMain(HINSTANCE hInstance,
-                    HINSTANCE hPrevInstance,
-                    LPTSTR lpCmdLine,
-                    int nCmdShow)
+#ifndef UNICODE
+/* Borrowed from CRT internal.h for _MBCS argc/argv parsing in this GUI app */
+int  __cdecl _setargv(void);
+#endif
+
+int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
+                   LPSTR lpCmdLine, int nCmdShow)
 {
-    MSG     msg;
-    /* single instance mutex */
-    HANDLE hMutex = CreateMutex(NULL, FALSE, "APSRVMON_MUTEX");
-    if((hMutex == NULL) || (GetLastError() == ERROR_ALREADY_EXISTS))
+    TCHAR szTmp[MAX_LOADSTRING];
+    TCHAR szCmp[MAX_COMPUTERNAME_LENGTH+4];
+    MSG msg;
+    /* existing window */
+    HWND appwindow;
+    DWORD dwControl;
+    int i;
+    DWORD d;
+
+    if (!GetSystemOSVersion(&g_dwOSVersion))
+    {
+        ErrorMessage(NULL, TRUE);
+        return 1;
+    }
+
+    g_LangID = GetUserDefaultLangID();
+    if ((g_LangID & 0xFF) != LANG_ENGLISH) {
+        g_LangID = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
+    }
+    for (i = IDS_MSG_FIRST; i <= IDS_MSG_LAST; ++i) {
+        LoadString(hInstance, i, szTmp, MAX_LOADSTRING);
+        g_lpMsg[i - IDS_MSG_FIRST] = _tcsdup(szTmp);
+    }
+    LoadString(hInstance, IDS_APMONITORTITLE, szTmp, MAX_LOADSTRING);
+    d = MAX_COMPUTERNAME_LENGTH+1;
+    _tcscpy(szCmp, _T("\\\\"));
+    GetComputerName(szCmp + 2, &d);
+    _tcsupr(szCmp);
+    g_szLocalHost = _tcsdup(szCmp);
+
+    memset(g_stComputers, 0, sizeof(ST_MONITORED_COMP) * MAX_APACHE_COMPUTERS);
+    g_stComputers[0].szComputerName = _tcsdup(szCmp);
+    g_stComputers[0].hRegistry = HKEY_LOCAL_MACHINE;
+    g_szTitle = _tcsdup(szTmp);
+    LoadString(hInstance, IDS_APMONITORCLASS, szTmp, MAX_LOADSTRING);
+    g_szWindowClass = _tcsdup(szTmp);
+
+    appwindow = FindWindow(g_szWindowClass, g_szTitle);
+
+#ifdef UNICODE
+    __wargv = CommandLineToArgvW(GetCommandLineW(), &__argc);
+#else
+    _setargv();
+#endif
+
+    if ((__argc == 2) && (_tcscmp(__targv[1], _T("--kill")) == 0))
+    {
+        /* Off to chase and close up every ApacheMonitor taskbar window */
+        return KillAllMonitors();
+    }
+    else if ((__argc == 4) && (g_dwOSVersion >= OS_VERSION_WIN2K))
     {
-        if (hMutex)
-            CloseHandle(hMutex);
+        dwControl = _ttoi(__targv[1]);
+        if ((dwControl != SERVICE_CONTROL_CONTINUE) &&
+            (dwControl != SERVICE_APACHE_RESTART) &&
+            (dwControl != SERVICE_CONTROL_STOP))
+        {
+            return 1;
+        }
 
+        /* Chase down and close up our session's previous window */
+        if ((appwindow) != NULL)
+            KillAWindow(appwindow);
+    }
+    else if (__argc != 1) {
+        return 1;
+    }
+    else if (appwindow)
+    {
+        ErrorMessage(g_lpMsg[IDS_MSG_APPRUNNING - IDS_MSG_FIRST], FALSE);
         return 0;
     }
+
+    g_icoStop          = LoadImage(hInstance, MAKEINTRESOURCE(IDI_ICOSTOP),
+                                   IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
+    g_icoRun           = LoadImage(hInstance, MAKEINTRESOURCE(IDI_ICORUN),
+                                   IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
+    g_hCursorHourglass = LoadImage(NULL, MAKEINTRESOURCE(OCR_WAIT),
+                                   IMAGE_CURSOR, LR_DEFAULTSIZE,
+                                   LR_DEFAULTSIZE, LR_SHARED);
+    g_hCursorArrow     = LoadImage(NULL, MAKEINTRESOURCE(OCR_NORMAL),
+                                   IMAGE_CURSOR, LR_DEFAULTSIZE,
+                                   LR_DEFAULTSIZE, LR_SHARED);
+    g_hBmpStart        = LoadImage(hInstance, MAKEINTRESOURCE(IDB_BMPRUN),
+                                   IMAGE_BITMAP, XBITMAP, YBITMAP,
+                                   LR_DEFAULTCOLOR);
+    g_hBmpStop         = LoadImage(hInstance, MAKEINTRESOURCE(IDB_BMPSTOP),
+                                   IMAGE_BITMAP, XBITMAP, YBITMAP,
+                                   LR_DEFAULTCOLOR);
+
+    memset(g_stServices, 0, sizeof(ST_APACHE_SERVICE) * MAX_APACHE_SERVICES);
+    CoInitialize(NULL);
     InitCommonControls();
-    ap_hInstance = hInstance;
-
-    LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
-    LoadString(hInstance, IDC_APSRVMON,  szWindowClass, MAX_LOADSTRING);
-    ap_icoStop  = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICOSTOP));
-    ap_icoRun   = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICORUN));
-    ap_cHourglass = LoadCursor(NULL, IDC_WAIT);
-    ap_cArrow     = LoadCursor(NULL, IDC_ARROW);
-
-    ZeroMemory(ap_stServices, sizeof(ST_APACHE_SERVICE) * MAX_APACHE_SERVICES);
-    ap_hMainWnd = CreateMainWindow(hInstance);
-    if (ap_hMainWnd != NULL)
+    g_hInstance = hInstance;
+    g_hwndMain = CreateMainWindow(hInstance);
+    g_bUiTaskbarCreated = RegisterWindowMessage(_T("TaskbarCreated"));
+    InitializeCriticalSection(&g_stcSection);
+    g_hwndServiceDlg = NULL;
+    if (g_hwndMain != NULL)
     {
-        ap_uiTaskbarCreated = RegisterWindowMessage("TaskbarCreated");
-        while (GetMessage(&msg, NULL, 0, 0) == TRUE) 
+        /* To avoid recursion, pass ImagePath NULL (a noop on NT and later) */
+        if ((__argc == 4) && (g_dwOSVersion >= OS_VERSION_WIN2K))
+            ApacheManageService(__targv[2], NULL, __targv[3], dwControl);
+
+        while (GetMessage(&msg, NULL, 0, 0) == TRUE)
         {
             TranslateMessage(&msg);
             DispatchMessage(&msg);
-        }    
-        ap_ClearServicesSt();
+        }
+        am_ClearServicesSt();
     }
-    CloseHandle(hMutex);
+    am_ClearComputersSt();
+    DeleteCriticalSection(&g_stcSection);
+    DestroyIcon(g_icoStop);
+    DestroyIcon(g_icoRun);
+    DestroyCursor(g_hCursorHourglass);
+    DestroyCursor(g_hCursorArrow);
+    DeleteObject(g_hBmpStart);
+    DeleteObject(g_hBmpStop);
+    CoUninitialize();
     return 0;
 }
+