]> granicus.if.org Git - apache/commitdiff
Fixes to allow Apache to run as a Win95 service... highlights
authorWilliam A. Rowe Jr <wrowe@apache.org>
Fri, 19 May 2000 05:01:53 +0000 (05:01 +0000)
committerWilliam A. Rowe Jr <wrowe@apache.org>
Fri, 19 May 2000 05:01:53 +0000 (05:01 +0000)
  main_win32.h : Moved delarations to a header, by request
  ap_listen.h :  References types declared in http_config.h
  http_main.h :  Add the Win32 flavor entry point declaration
  apr.hw :       Cleanup the redundancy department of redundancy
  win32/proc.c : Double null termination was required here

  Everything else should be obvious and isolated to Win32.
  Build files will be committed seperately.

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@85253 13f79535-47bb-0310-9956-ffa450edef68

include/ap_listen.h
include/http_main.h
os/win32/main_win32.h [new file with mode: 0644]
server/mpm/winnt/mpm_winnt.c
server/mpm/winnt/mpm_winnt.h
server/mpm/winnt/registry.c
server/mpm/winnt/service.c

index 089dcb5372e624333795bc8852f5f1743537d2c1..d611c2953ee08e522a567bb5ec65c62a7dcec37b 100644 (file)
@@ -56,6 +56,7 @@
 #define AP_LISTEN_H
 
 #include "apr_network_io.h"
+#include "http_config.h"
 
 typedef struct ap_listen_rec ap_listen_rec;
 struct ap_listen_rec {
index 42ce25e52fc0536f6843acb7382b307fa8600f89..fecd5be56c71dba45cb9a43b27ecd0e1d2c7931d 100644 (file)
@@ -71,6 +71,10 @@ extern ap_array_header_t *ap_server_pre_read_config;
 extern ap_array_header_t *ap_server_post_read_config;
 extern ap_array_header_t *ap_server_config_defines;
 
+#ifdef WIN32
+API_EXPORT(int) apache_main(int argc, char *argv[]);
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/os/win32/main_win32.h b/os/win32/main_win32.h
new file mode 100644 (file)
index 0000000..97459d0
--- /dev/null
@@ -0,0 +1,80 @@
+/* ====================================================================
+ * 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.
+ *
+ * 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/>.
+ *
+ * Portions of this software are based upon public domain software
+ * originally written at the National Center for Supercomputing Applications,
+ * University of Illinois, Urbana-Champaign.
+ */
+
+/*
+ * Declarations for users of the functions defined in registry.c
+ */
+
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0400
+#endif
+#ifndef NOGDI
+#define NOGDI
+#endif
+#ifndef NONLS
+#define NONLS
+#endif
+#ifndef NOMCX
+#define NOMCX
+#endif
+#ifndef NOIME
+#define NOIME
+#endif
+#include <windows.h>
+#include <winsock2.h>
+#include <mswsock.h>
index 0be5f8b2668c45e6a3eb6b2fc8905cf9e0eacec7..baae88fd4f9d3d6dd0763ffcbda0f51e2299da39 100644 (file)
 #include "ap_config.h"
 #include "ap_listen.h"
 #include "mpm_default.h"
-//#include "service.h"
 #include "iol_socket.h"
 #include "winnt.h"
 
-
 /*
  * Definitions of WINNT MPM specific config globals
  */
@@ -105,9 +103,8 @@ int ap_daemons_to_start=0;
 static event *exit_event;
 HANDLE maintenance_event;
 ap_lock_t *start_mutex;
-int my_pid;
-int parent_pid;
-typedef void (CALLBACK *ap_completion_t)();
+DWORD my_pid;
+DWORD parent_pid;
 API_VAR_EXPORT ap_completion_t ap_mpm_init_complete = NULL;
 
 static ap_status_t socket_cleanup(void *sock)
@@ -299,15 +296,19 @@ static void signal_parent(int type)
     }
     CloseHandle(e);
 }
+
 static int volatile is_graceful = 0;
+
 API_EXPORT(int) ap_graceful_stop_signalled(void)
 {
     return is_graceful;
 }
-void ap_start_shutdown(void)
+
+API_EXPORT(void) ap_start_shutdown(void)
 {
     signal_parent(0);
 }
+
 /*
  * Initialise the signal names, in the global variables signal_name_prefix, 
  * signal_restart_name and signal_shutdown_name.
@@ -354,6 +355,7 @@ static void sock_disable_nagle(int s)
  * Routines to deal with managing the list of listening sockets.
  */
 static ap_listen_rec *head_listener;
+
 static ap_inline ap_listen_rec *find_ready_listener(fd_set * main_fds)
 {
     ap_listen_rec *lr;
@@ -371,6 +373,7 @@ static ap_inline ap_listen_rec *find_ready_listener(fd_set * main_fds)
     }
     return NULL;
 }
+
 static int setup_listeners(server_rec *s)
 {
     ap_listen_rec *lr;
@@ -1390,7 +1393,10 @@ static int create_process(ap_pool_t *p, HANDLE *handles, HANDLE *events, int *pr
     int rv;
     char buf[1024];
     char *pCommand;
+    char *pEnvVar;
+    char *pEnvBlock;
     int i;
+    int iEnvBlockLen;
     STARTUPINFO si;           /* Filled in prior to call to CreateProcess */
     PROCESS_INFORMATION pi;   /* filled in on call to CreateProces */
 
@@ -1425,6 +1431,32 @@ static int create_process(ap_pool_t *p, HANDLE *handles, HANDLE *events, int *pr
         pCommand = ap_pstrcat(p, pCommand, " \"", server_conf->process->argv[i], "\"", NULL);
     }
 
+    /* Build the environment, since Win9x disrespects the active env */
+    // SetEnvironmentVariable("AP_PARENT_PID",ap_psprintf(p,"%l",parent_pid));
+    pEnvVar = ap_psprintf(p, "AP_PARENT_PID=%i", parent_pid);
+    /*
+     * Win32's CreateProcess call requires that the environment
+     * be passed in an environment block, a null terminated block of
+     * null terminated strings.
+     */  
+    i = 0;
+    iEnvBlockLen = 1;
+    while (_environ[i]) {
+        iEnvBlockLen += strlen(_environ[i]) + 1;
+        i++;
+    }
+
+    pEnvBlock = (char *)ap_pcalloc(p, iEnvBlockLen + strlen(pEnvVar) + 1);
+    strcpy(pEnvBlock, pEnvVar);
+    pEnvVar = strchr(pEnvBlock, '\0') + 1;
+
+    i = 0;
+    while (_environ[i]) {
+        strcpy(pEnvVar, _environ[i]);
+        pEnvVar = strchr(pEnvVar, '\0') + 1;
+        i++;
+    }
+    pEnvVar = '\0';
     /* Create a pipe to send socket info to the child */
     if (!CreatePipe(&hPipeRead, &hPipeWrite, &sa, 0)) {
         ap_log_error(APLOG_MARK, APLOG_CRIT, GetLastError(), server_conf,
@@ -1432,8 +1464,6 @@ static int create_process(ap_pool_t *p, HANDLE *handles, HANDLE *events, int *pr
         return -1;
     }
 
-    SetEnvironmentVariable("AP_PARENT_PID",ap_psprintf(p,"%d",parent_pid));
-
     /* Give the read end of the pipe (hPipeRead) to the child as stdin. The 
      * parent will write the socket data to the child on this pipe.
      */
@@ -1447,7 +1477,7 @@ static int create_process(ap_pool_t *p, HANDLE *handles, HANDLE *events, int *pr
     if (!CreateProcess(NULL, pCommand, NULL, NULL, 
                        TRUE,               /* Inherit handles */
                        CREATE_SUSPENDED,   /* Creation flags */
-                       NULL,               /* Environment block */
+                       pEnvBlock,          /* Environment block */
                        NULL,
                        &si, &pi)) {
         ap_log_error(APLOG_MARK, APLOG_CRIT, GetLastError(), server_conf,
@@ -1694,12 +1724,12 @@ static void winnt_pre_config(ap_pool_t *pconf, ap_pool_t *plog, ap_pool_t *ptemp
     pid = getenv("AP_PARENT_PID");
     if (pid) {
         /* This is the child */
-        parent_pid = atoi(pid);
-        my_pid = getpid();
+        parent_pid = (DWORD) atol(pid);
+        my_pid = GetCurrentProcessId();
     }
     else {
         /* This is the parent */
-        parent_pid = my_pid = getpid();
+        parent_pid = my_pid = GetCurrentProcessId();
     }
 
     ap_listen_pre_config();
@@ -1806,7 +1836,7 @@ API_EXPORT(int) ap_mpm_run(ap_pool_t *_pconf, ap_pool_t *plog, server_rec *s )
             if (pidfile != NULL && unlink(pidfile) == 0) {
                 ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO,APR_SUCCESS,
                              server_conf, "removed PID file %s (pid=%ld)",
-                             pidfile, (long)getpid());
+                             pidfile, GetCurrentProcessId());
             }
             ap_destroy_lock(start_mutex);
 
index ca1b3c67a936b9ad85e85023fe1f6d8b3908ed24..9dcba61076c743c0cb79709246db3ebe3e078eeb 100644 (file)
 #ifndef APACHE_MPM_WINNT_H
 #define APACHE_MPM_WINNT_H
 
+#include "ap_listen.h"
+
 extern int ap_threads_per_child;
 extern int ap_max_requests_per_child;
 extern int ap_extended_status;
 extern void clean_child_exit(int);
 
+typedef void (CALLBACK *ap_completion_t)();
+API_VAR_IMPORT ap_completion_t ap_mpm_init_complete;
+
+API_EXPORT(void) ap_start_shutdown(void);
 
 typedef struct CompContext {
     OVERLAPPED Overlapped;
index 02a452c69faf7e98f42918dce9d56569f65354c7..ed41d485643a7e009ebb6d05885fde9bcf6e1f35 100644 (file)
 #define SERVICEKEYPRE  "System\\CurrentControlSet\\Services\\"
 #define SERVICEKEYPOST "\\Parameters"
 
+#define SERVICELAUNCH9X "Software\\Microsoft\\Windows\\CurrentVersion\\RunServices\\"
 /*
  * The Windows API registry key functions don't set the last error
  * value (the windows equivalent of errno). So we need to set it
@@ -253,19 +254,6 @@ static int ap_registry_get_key_int(ap_pool_t *p, char *key, char *name, char *pB
  * dir will contain an empty string), or -1 if there was
  * an error getting the key.
  */
-#if 0
-int ap_registry_get_server_root(ap_pool_t *p, char *dir, int size)
-{
-    int rv;
-
-    rv = ap_registry_get_key_int(p, REGKEY, "ServerRoot", dir, size, NULL);
-    if (rv < 0) {
-       dir[0] = '\0';
-    }
-
-    return (rv < -1) ? -1 : 0;
-}
-#else
 int ap_registry_get_server_root(ap_pool_t *p, char **buf)
 {
     int rv;
@@ -277,7 +265,7 @@ int ap_registry_get_server_root(ap_pool_t *p, char **buf)
 
     return (rv < -1) ? -1 : 0;
 }
-#endif
+
 char *ap_get_service_key(char *display_name)
 {
     size_t keylen = strlen(display_name);
@@ -290,21 +278,7 @@ char *ap_get_service_key(char *display_name)
     
     return(key);
 }
-#if 0
-int ap_registry_get_service_conf(ap_pool_t *p, char *dir, int size, char *display_name)
-{
-    int rv;
-    char *key = ap_get_service_key(display_name);
-
-    rv = ap_registry_get_key_int(p, key, "ConfPath", dir, size, NULL);
-    if (rv < 0) {
-    dir[0] = '\0';
-    }
 
-    free(key);
-    return (rv < -1) ? -1 : 0;
-}
-#else
 int ap_registry_get_service_conf(ap_pool_t *p, char **buf, char *service_name)
 {
     int rv;
@@ -318,7 +292,6 @@ int ap_registry_get_service_conf(ap_pool_t *p, char **buf, char *service_name)
     free(key);
     return (rv < -1) ? -1 : 0;
 }
-#endif
 
 /**********************************************************************
  * The rest of this file deals with storing keys or values in the registry
@@ -552,4 +525,3 @@ int ap_registry_set_server_root(char *dir)
 
     return rv < 0 ? -1 : 0;
 }
-
index e60b8a01695f0cc1b09264d6ff79055a8f0f58b2..412f25d04600c5f61b935d4a8979d6537cffc450 100644 (file)
 
 #ifdef WIN32
 
-#include "os.h"
-#include <stdlib.h>
-#include <direct.h>
-
 #define  CORE_PRIVATE 
+
+#include "main_win32.h"
 #include "httpd.h"
 #include "http_conf_globals.h"
 #include "http_log.h"
-#include "http_main.h"
 #include "service.h"
 #include "registry.h"
 #include "ap_mpm.h"
+#include "..\..\modules\mpm\winnt\winnt.h"
 
 typedef void (CALLBACK *ap_completion_t)();
 API_VAR_IMPORT ap_completion_t ap_mpm_init_complete;
+API_VAR_IMPORT char *ap_server_argv0;
 
 static struct
 {
@@ -85,6 +84,8 @@ static struct
     SERVICE_STATUS ssStatus;
     FILE *logFile;
     char *service_dir;
+    HANDLE threadService;
+    HANDLE threadMonitor;
 } globdat;
 
 static void WINAPI service_main_fn(DWORD, LPTSTR *);
@@ -93,54 +94,137 @@ static int ReportStatusToSCMgr(int currentState, int exitCode, int waitHint);
 static int ap_start_service(SC_HANDLE);
 static int ap_stop_service(SC_HANDLE);
 
-static void CALLBACK report_service95_running()
+static LRESULT CALLBACK MonitorWin9xWndProc(HWND hWnd, UINT msg, 
+                                            WPARAM wParam, LPARAM lParam)
 {
-    FreeConsole();
+/* This is the WndProc procedure for our invisible window.
+ * When the user shuts down the system, this window is sent
+ * a signal WM_ENDSESSION. We clean up by signaling Apache
+ * to shut down, and idle until Apache's primary thread quits.
+ */
+    if ((msg == WM_ENDSESSION) && (lParam != ENDSESSION_LOGOFF))
+    {
+        ap_start_shutdown();
+       if (wParam)
+           WaitForSingleObject(globdat.threadService, 30000);
+        return 0;
+    }
+    return (DefWindowProc(hWnd, msg, wParam, lParam));
+}
+
+static DWORD WINAPI MonitorWin9xEvents(LPVOID initEvent)
+{
+/* When running on Windows 9x, the ConsoleCtrlHandler is _NOT_ 
+ * called when the system is shutdown.  So create an invisible 
+ * window to watch for the WM_ENDSESSION message, and watch for
+ * the WM_CLOSE message to shut the window down.
+ */
+    WNDCLASS wc;
+    HWND hwndMain;
+
+    wc.style         = CS_GLOBALCLASS;
+    wc.lpfnWndProc   = MonitorWin9xWndProc; 
+    wc.cbClsExtra    = 0;
+    wc.cbWndExtra    = 0; 
+    wc.hInstance     = NULL;
+    wc.hIcon         = NULL;
+    wc.hCursor       = NULL;
+    wc.hbrBackground = NULL;
+    wc.lpszMenuName  = NULL;
+    wc.lpszClassName = "ApacheWin9xService";
+    if (RegisterClass(&wc)) 
+    {
+        /* Create an invisible window */
+        hwndMain = CreateWindow("ApacheWin9xService", "Apache", 
+                               WS_OVERLAPPEDWINDOW & ~WS_VISIBLE, 
+                                CW_USEDEFAULT, CW_USEDEFAULT, 
+                                CW_USEDEFAULT, CW_USEDEFAULT, 
+                                NULL, NULL, NULL, NULL);
+        if (hwndMain)
+        {
+           MSG msg;
+           /* If we succeed, eliminate the console window.
+             * Signal the parent we are all set up, and
+             * watch the message queue while the window lives.
+             */
+           FreeConsole();
+            SetEvent((HANDLE) initEvent);
+            while (GetMessage(&msg, NULL, 0, 0)) 
+            {
+                if (msg.message == WM_CLOSE)
+                    DestroyWindow(hwndMain); 
+                else {
+                   TranslateMessage(&msg);
+                   DispatchMessage(&msg);
+                }
+            }
+            globdat.threadMonitor = 0;
+            return(0);
+        }
+    }
+    /* We failed or are soon to die... 
+     * we won't need this much longer 
+     */
+    SetEvent((HANDLE) initEvent);
+    globdat.threadMonitor = 0;
+    return(0);
+}
 
-    /* We do this only once, ever */
-    ap_mpm_init_complete = NULL;
+static void CALLBACK report_service9x_running()
+{
 }
 
-int service95_main(int (*main_fn)(int, char **), int argc, char **argv )
+int service9x_main(int (*main_fn)(int, char **), int argc, char **argv )
 {
-    HINSTANCE hkernel;
     DWORD (WINAPI *RegisterServiceProcess)(DWORD, DWORD);
+    HINSTANCE hkernel;
+    DWORD threadId;
+    
+    globdat.threadService = GetCurrentThread();
     
     /* Obtain a handle to the kernel library */
     hkernel = LoadLibrary("KERNEL32.DLL");
-    if (!hkernel)
-        return -1;
-    
-    /* Find the RegisterServiceProcess function */
-    RegisterServiceProcess = (DWORD (WINAPI *)(DWORD, DWORD))
-                             GetProcAddress(hkernel, "RegisterServiceProcess");
-    if (RegisterServiceProcess == NULL)
-        return -1;
-       
-    /* Register this process as a service */
-    if (!RegisterServiceProcess((DWORD)NULL, 1))
-        return -1;
-
-    /* Eliminate the console for the remainer of the service session */
-    ap_mpm_init_complete = report_service95_running;
+    if (hkernel) {
+        /* Find the RegisterServiceProcess function */
+        RegisterServiceProcess = (DWORD (WINAPI *)(DWORD, DWORD))
+                                 GetProcAddress(hkernel, "RegisterServiceProcess");
+        if (RegisterServiceProcess) {
+            if (RegisterServiceProcess((DWORD)NULL, 1)) {
+                HANDLE installed = CreateEvent(NULL, FALSE, FALSE, NULL);
+                globdat.threadMonitor = CreateThread(NULL, 0,
+                                                     MonitorWin9xEvents, 
+                                                     (LPVOID) installed,
+                                                     0, &threadId);
+                WaitForSingleObject(installed, 30000);
+                CloseHandle(installed);
+            }
+        }
+    }
 
     /* Run the service */
     globdat.exit_status = main_fn(argc, argv);
 
+    /* Still have a thread & window to clean up, so signal now */
+    if (globdat.threadMonitor)
+    {
+       PostThreadMessage(threadId, WM_CLOSE, 0, 0);
+        WaitForSingleObject(globdat.threadMonitor, 30000);
+    }
+
     /* When the service quits, remove it from the 
        system service table */
-    RegisterServiceProcess((DWORD)NULL, 0);
+    if (RegisterServiceProcess)
+       RegisterServiceProcess((DWORD)NULL, 0);
 
     /* Free the kernel library */
-    // Worthless, methinks, since it won't be reclaimed
-    // FreeLibrary(hkernel);
+    if (hkernel)
+        FreeLibrary(hkernel);
 
-    /* We have to quit right here to avoid an invalid page fault */
-    // But, this is worth experimenting with!
     return (globdat.exit_status);
 }
 
-int service_main(int (*main_fn)(int, char **), int argc, char **argv )
+int servicent_main(int (*main_fn)(int, char **), int argc, char **argv )
 {
     SERVICE_TABLE_ENTRY dispatchTable[] =
     {
@@ -166,24 +250,12 @@ int service_main(int (*main_fn)(int, char **), int argc, char **argv )
     }
 }
 
-void service_cd()
-{
-    /* change to the drive with the executable */
-    char buf[300];
-    GetModuleFileName(NULL, buf, 300);
-    buf[2] = 0;
-    chdir(buf);
-}
-
-static void CALLBACK report_service_started()
+static void CALLBACK report_servicent_started()
 {
     ReportStatusToSCMgr(
         SERVICE_RUNNING,    // service state
         NO_ERROR,           // exit code
         0);                 // wait hint
-    
-    /* This is only reported once, ever! */
-    ap_mpm_init_complete = NULL;
 }
 
 void __stdcall service_main_fn(DWORD argc, LPTSTR *argv)
@@ -218,9 +290,7 @@ void __stdcall service_main_fn(DWORD argc, LPTSTR *argv)
         NO_ERROR,              // exit code
         3000);                 // wait hint
 
-    ap_mpm_init_complete = report_service_started;
-
-    service_cd();
+    ap_mpm_init_complete = report_servicent_started;
 
     /* Fetch server_conf from the registry 
      *  Rebuild argv and argc adding the -d server_root and -f server_conf then 
@@ -274,7 +344,6 @@ VOID WINAPI service_ctrl(DWORD dwCtrlCode)
 {
     int state;
 
-
     state = globdat.ssStatus.dwCurrentState;
     switch(dwCtrlCode)
     {
@@ -342,7 +411,7 @@ int ReportStatusToSCMgr(int currentState, int exitCode, int waitHint)
     return(1);
 }
 
-void InstallService(char *display_name, char *conf)
+void InstallServiceNT(char *display_name, char *conf)
 {
     SC_HANDLE   schService;
     SC_HANDLE   schSCManager;
@@ -415,7 +484,7 @@ void InstallService(char *display_name, char *conf)
 }
 
 
-void RemoveService(char *display_name)
+void RemoveServiceNT(char *display_name)
 {
     SC_HANDLE   schService;
     SC_HANDLE   schSCManager;
@@ -473,16 +542,27 @@ BOOL isProcessService() {
 }
 
 /* Determine is service_name is a valid service
+ * Simplify by testing the registry rather than the SCM
+ * as this will work on both WinNT and Win9x.
  */
 
-BOOL isValidService(char *display_name) {
-    SC_HANDLE schSCM, schSVC;
+BOOL isValidService(ap_pool_t *p, char *display_name) {
     char service_name[256];
-    int Err;
+    char *service_conf;
 
     /* Remove spaces from display name to create service name */
     ap_collapse_spaces(service_name, display_name);
 
+    if(ap_registry_get_service_conf(p, &service_conf, service_name)) {
+        return TRUE;
+    }
+    
+    return FALSE;
+
+#if 0
+    SC_HANDLE schSCM, schSVC;
+    int Err;
+
     if (!(schSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS))) {
         ap_log_error(APLOG_MARK, APLOG_ERR, GetLastError(), NULL,
                      "OpenSCManager failed");
@@ -501,8 +581,12 @@ BOOL isValidService(char *display_name) {
                      "OpenService failed");
 
     return FALSE;
+#endif
 }
 
+/* Although the Win9x service enhancement added -k startservice,
+ * it is never processed here, so we still ignore that param.
+ */
 int send_signal_to_service(char *display_name, char *sig) {
     SC_HANDLE   schService;
     SC_HANDLE   schSCManager;
@@ -607,6 +691,6 @@ int ap_start_service(SC_HANDLE schService) {
             return TRUE;
     return FALSE;
 }
-           
+
 #endif /* WIN32 */