Commit 3bccad70 authored by William A. Rowe Jr's avatar William A. Rowe Jr
Browse files

mpm_winnt: Accept utf-8 (Unicode) service names and descriptions for

internationalization.

Backports: 1611165,1611169
Reviewed by: wrowe, gsmith


git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.2.x@1681266 13f79535-47bb-0310-9956-ffa450edef68
parent 051d888b
Loading
Loading
Loading
Loading
+3 −0
Original line number Original line Diff line number Diff line
                                                         -*- coding: utf-8 -*-
                                                         -*- coding: utf-8 -*-
Changes with Apache 2.2.30
Changes with Apache 2.2.30


  *) mpm_winnt: Accept utf-8 (Unicode) service names and descriptions for
     internationalization.  [William Rowe]

  *) mod_log_config: Add "%{UNIT}T" format to output request duration in
  *) mod_log_config: Add "%{UNIT}T" format to output request duration in
     seconds, milliseconds or microseconds depending on UNIT ("s", "ms", "us").
     seconds, milliseconds or microseconds depending on UNIT ("s", "ms", "us").
     [Ben Reser, Rainer Jung]
     [Ben Reser, Rainer Jung]
+0 −6
Original line number Original line Diff line number Diff line
@@ -101,12 +101,6 @@ RELEASE SHOWSTOPPERS:
PATCHES ACCEPTED TO BACKPORT FROM TRUNK:
PATCHES ACCEPTED TO BACKPORT FROM TRUNK:
  [ start all new proposals below, under PATCHES PROPOSED. ]
  [ start all new proposals below, under PATCHES PROPOSED. ]


   * mpm_winnt service.c: Accept utf-8 service names/descriptions for i18n.
     trunk patches: http://svn.apache.org/r1611165
                    http://svn.apache.org/r1611169
     2.2.x patch: http://people.apache.org/~wrowe/httpd-2.2-utf8-servicename.patch
     +1: wrowe, gsmith

   * mod_log_config: Backport get_request_end_time().
   * mod_log_config: Backport get_request_end_time().
     This makes data consistent if a log format uses multiple %{...}T
     This makes data consistent if a log format uses multiple %{...}T
     and/or %D. The end time of a request is only taken once and the
     and/or %D. The end time of a request is only taken once and the
+412 −88
Original line number Original line Diff line number Diff line
@@ -22,11 +22,18 @@
#define CORE_PRIVATE
#define CORE_PRIVATE
#define _WINUSER_
#define _WINUSER_


#include "apr.h"
#include "apr_strings.h"
#include "apr_lib.h"
#if APR_HAS_UNICODE_FS
#include "arch/win32/apr_arch_utf8.h"
#include "arch/win32/apr_arch_misc.h"
#include <wchar.h>
#endif

#include "httpd.h"
#include "httpd.h"
#include "http_log.h"
#include "http_log.h"
#include "mpm_winnt.h"
#include "mpm_winnt.h"
#include "apr_strings.h"
#include "apr_lib.h"
#include "ap_regkey.h"
#include "ap_regkey.h"


#ifdef NOUSER
#ifdef NOUSER
@@ -39,6 +46,10 @@
static char *mpm_service_name = NULL;
static char *mpm_service_name = NULL;
static char *mpm_display_name = NULL;
static char *mpm_display_name = NULL;


#if APR_HAS_UNICODE_FS
static apr_wchar_t *mpm_service_name_w;
#endif

static struct
static struct
{
{
    HANDLE mpm_thread;       /* primary thread handle of the apache server */
    HANDLE mpm_thread;       /* primary thread handle of the apache server */
@@ -53,6 +64,33 @@ static struct
static int ReportStatusToSCMgr(int currentState, int exitCode, int waitHint);
static int ReportStatusToSCMgr(int currentState, int exitCode, int waitHint);




/* Rather than repeat this logic throughout, create an either-or wide or narrow
 * implementation because we don't actually pass strings to OpenSCManager.
 * This election is based on build time defines and runtime os version test.
 */
#undef OpenSCManager
typedef SC_HANDLE (WINAPI *fpt_OpenSCManager)(const void *lpMachine,
                                              const void *lpDatabase,
                                              DWORD dwAccess);
static fpt_OpenSCManager pfn_OpenSCManager = NULL;
static APR_INLINE SC_HANDLE OpenSCManager(const void *lpMachine,
                                          const void *lpDatabase,
                                          DWORD dwAccess)
{
    if (!pfn_OpenSCManager) {
#if APR_HAS_UNICODE_FS
        IF_WIN_OS_IS_UNICODE
            pfn_OpenSCManager = (fpt_OpenSCManager)OpenSCManagerW;
#endif
#if APR_HAS_ANSI_FS
        ELSE_WIN_OS_IS_ANSI
            pfn_OpenSCManager = (fpt_OpenSCManager)OpenSCManagerA;
#endif
    }
    return (*(pfn_OpenSCManager))(lpMachine, lpDatabase, dwAccess); 
}


/* The service configuration's is stored under the following trees:
/* The service configuration's is stored under the following trees:
 *
 *
 * HKLM\System\CurrentControlSet\Services\[service name]
 * HKLM\System\CurrentControlSet\Services\[service name]
@@ -408,18 +446,50 @@ static void set_service_description(void)
          && (ChangeServiceConfig2)
          && (ChangeServiceConfig2)
          && (schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT)))
          && (schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT)))
    {
    {
        SC_HANDLE schService = OpenService(schSCManager, mpm_service_name,
        SC_HANDLE schService;

#if APR_HAS_UNICODE_FS
        IF_WIN_OS_IS_UNICODE
        {
            schService = OpenServiceW(schSCManager, mpm_service_name_w,
                                      SERVICE_CHANGE_CONFIG);
                                      SERVICE_CHANGE_CONFIG);
        }
#endif /* APR_HAS_UNICODE_FS */
#if APR_HAS_ANSI_FS
        ELSE_WIN_OS_IS_ANSI
        {
            schService = OpenService(schSCManager, mpm_service_name,
                                     SERVICE_CHANGE_CONFIG);
        }
#endif
        if (schService) {
        if (schService) {
            /* Cast is necessary, ChangeServiceConfig2 handles multiple
            /* Cast is necessary, ChangeServiceConfig2 handles multiple
             * object types, some volatile, some not.
             * object types, some volatile, some not.
             */
             */
            /* ###: utf-ize */
#if APR_HAS_UNICODE_FS
            IF_WIN_OS_IS_UNICODE
            {
                apr_size_t slen = strlen(full_description) + 1;
                apr_size_t wslen = slen;
                apr_wchar_t *full_description_w = apr_palloc(pconf, wslen * sizeof(apr_wchar_t));
                apr_status_t rv = apr_conv_utf8_to_ucs2(full_description, &slen,
                                                        full_description_w, &wslen);
                if ((rv != APR_SUCCESS) || slen
                        || ChangeServiceConfig2W(schService,
                                                 1 /* SERVICE_CONFIG_DESCRIPTION */,
                                                 (LPVOID) &full_description_w))
                    full_description = NULL;
            }
#endif /* APR_HAS_UNICODE_FS */
#if APR_HAS_ANSI_FS
            ELSE_WIN_OS_IS_ANSI
            {
                if (ChangeServiceConfig2(schService,
                if (ChangeServiceConfig2(schService,
                                         1 /* SERVICE_CONFIG_DESCRIPTION */,
                                         1 /* SERVICE_CONFIG_DESCRIPTION */,
                                     (LPVOID) &full_description)) {
                                         (LPVOID) &full_description))
                    full_description = NULL;
                    full_description = NULL;
            }
            }
#endif
            CloseServiceHandle(schService);
            CloseServiceHandle(schService);
        }
        }
        CloseServiceHandle(schSCManager);
        CloseServiceHandle(schSCManager);
@@ -473,8 +543,82 @@ static VOID WINAPI service_nt_ctrl(DWORD dwCtrlCode)
 */
 */
extern apr_array_header_t *mpm_new_argv;
extern apr_array_header_t *mpm_new_argv;


/* ###: utf-ize */
#if APR_HAS_UNICODE_FS
static void __stdcall service_nt_main_fn(DWORD argc, LPTSTR *argv)
static void __stdcall service_nt_main_fn_w(DWORD argc, LPWSTR *argv)
{
    const char *ignored;
    char *service_name;
    apr_size_t wslen = wcslen(argv[0]) + 1;
    apr_size_t slen = wslen * 3 - 2;

    service_name = malloc(slen);
    (void)apr_conv_ucs2_to_utf8(argv[0], &wslen, service_name, &slen);

    /* args and service names live in the same pool */
    mpm_service_set_name(mpm_new_argv->pool, &ignored, service_name);

    memset(&globdat.ssStatus, 0, sizeof(globdat.ssStatus));
    globdat.ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
    globdat.ssStatus.dwCurrentState = SERVICE_START_PENDING;
    globdat.ssStatus.dwCheckPoint = 1;

    if (!(globdat.hServiceStatus = RegisterServiceCtrlHandlerW(argv[0], service_nt_ctrl)))
    {
        ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, apr_get_os_error(),
                     NULL, "Failure registering service handler");
        return;
    }

    /* Report status, no errors, and buy 3 more seconds */
    ReportStatusToSCMgr(SERVICE_START_PENDING, NO_ERROR, 30000);

    /* We need to append all the command arguments passed via StartService()
     * to our running service... which just got here via the SCM...
     * but we have no interest in argv[0] for the mpm_new_argv list.
     */
    if (argc > 1)
    {
        char **cmb_data, **cmb;
        DWORD i;

        mpm_new_argv->nalloc = mpm_new_argv->nelts + argc - 1;
        cmb_data = malloc(mpm_new_argv->nalloc * sizeof(const char *));

        /* mpm_new_argv remains first (of lower significance) */
        memcpy (cmb_data, mpm_new_argv->elts,
                mpm_new_argv->elt_size * mpm_new_argv->nelts);

        /* Service args follow from StartService() invocation */
        memcpy (cmb_data + mpm_new_argv->nelts, argv + 1,
                mpm_new_argv->elt_size * (argc - 1));

        cmb = cmb_data + mpm_new_argv->nelts;

        for (i = 1; i < argc; ++i)
        {
            wslen = wcslen(argv[i]) + 1;
            slen = wslen * 3 - 2;
            service_name = malloc(slen);
            (void)apr_conv_ucs2_to_utf8(argv[i], &wslen, *(cmb++), &slen);
        }

        /* The replacement arg list is complete */
        mpm_new_argv->elts = (char *)cmb_data;
        mpm_new_argv->nelts = mpm_new_argv->nalloc;
    }

    /* Let the main thread continue now... but hang on to the
     * signal_monitor event so we can take further action
     */
    SetEvent(globdat.service_init);

    WaitForSingleObject(globdat.service_term, INFINITE);
}
#endif /* APR_HAS_UNICODE_FS */


#if APR_HAS_ANSI_FS
static void __stdcall service_nt_main_fn(DWORD argc, LPSTR *argv)
{
{
    const char *ignored;
    const char *ignored;


@@ -486,8 +630,7 @@ static void __stdcall service_nt_main_fn(DWORD argc, LPTSTR *argv)
    globdat.ssStatus.dwCurrentState = SERVICE_START_PENDING;
    globdat.ssStatus.dwCurrentState = SERVICE_START_PENDING;
    globdat.ssStatus.dwCheckPoint = 1;
    globdat.ssStatus.dwCheckPoint = 1;


    /* ###: utf-ize */
    if (!(globdat.hServiceStatus = RegisterServiceCtrlHandlerA(argv[0], service_nt_ctrl)))
    if (!(globdat.hServiceStatus = RegisterServiceCtrlHandler(argv[0], service_nt_ctrl)))
    {
    {
        ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, apr_get_os_error(),
        ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, apr_get_os_error(),
                     NULL, "Failure registering service handler");
                     NULL, "Failure registering service handler");
@@ -499,7 +642,7 @@ static void __stdcall service_nt_main_fn(DWORD argc, LPTSTR *argv)


    /* We need to append all the command arguments passed via StartService()
    /* We need to append all the command arguments passed via StartService()
     * to our running service... which just got here via the SCM...
     * to our running service... which just got here via the SCM...
     * but we hvae no interest in argv[0] for the mpm_new_argv list.
     * but we have no interest in argv[0] for the mpm_new_argv list.
     */
     */
    if (argc > 1)
    if (argc > 1)
    {
    {
@@ -528,27 +671,44 @@ static void __stdcall service_nt_main_fn(DWORD argc, LPTSTR *argv)


    WaitForSingleObject(globdat.service_term, INFINITE);
    WaitForSingleObject(globdat.service_term, INFINITE);
}
}
#endif




static DWORD WINAPI service_nt_dispatch_thread(LPVOID nada)
static DWORD WINAPI service_nt_dispatch_thread(LPVOID nada)
{
{
    apr_status_t rv = APR_SUCCESS;
#if APR_HAS_UNICODE_FS

    SERVICE_TABLE_ENTRYW dispatchTable_w[] =
    SERVICE_TABLE_ENTRY dispatchTable[] =
    {
        { L"", service_nt_main_fn_w },
        { NULL, NULL }
    };
#endif /* APR_HAS_UNICODE_FS */
#if APR_HAS_ANSI_FS
    SERVICE_TABLE_ENTRYA dispatchTable[] =
    {
    {
        { "", service_nt_main_fn },
        { "", service_nt_main_fn },
        { NULL, NULL }
        { NULL, NULL }
    };
    };
#endif
    apr_status_t rv;


    /* ###: utf-ize */
#if APR_HAS_UNICODE_FS
    if (!StartServiceCtrlDispatcher(dispatchTable))
    IF_WIN_OS_IS_UNICODE
    {
        rv = StartServiceCtrlDispatcherW(dispatchTable_w);
#endif
#if APR_HAS_ANSI_FS
    ELSE_WIN_OS_IS_ANSI
         rv = StartServiceCtrlDispatcherA(dispatchTable);
#endif
    if (rv) {
        apr_status_t rv = APR_SUCCESS;
    }
    else {
        /* This is a genuine failure of the SCM. */
        /* This is a genuine failure of the SCM. */
        rv = apr_get_os_error();
        rv = apr_get_os_error();
        ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv, NULL,
        ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv, NULL,
                     "Error starting service control dispatcher");
                     "Error starting service control dispatcher");
    }
    }

    return (rv);
    return (rv);
}
}


@@ -566,6 +726,21 @@ apr_status_t mpm_service_set_name(apr_pool_t *p, const char **display_name,
     */
     */
    mpm_service_name = apr_palloc(p, strlen(set_name) + 1);
    mpm_service_name = apr_palloc(p, strlen(set_name) + 1);
    apr_collapse_spaces((char*) mpm_service_name, set_name);
    apr_collapse_spaces((char*) mpm_service_name, set_name);
#if APR_HAS_UNICODE_FS
    IF_WIN_OS_IS_UNICODE
    {
        apr_size_t slen = strlen(mpm_service_name) + 1;
        apr_size_t wslen = slen;
        mpm_service_name_w = apr_palloc(p, wslen * sizeof(apr_wchar_t));
        rv = apr_conv_utf8_to_ucs2(mpm_service_name, &slen,
                                   mpm_service_name_w, &wslen);
        if (rv != APR_SUCCESS)
            return rv;
        else if (slen)
            return APR_ENAMETOOLONG;
    }
#endif /* APR_HAS_UNICODE_FS */

    apr_snprintf(key_name, sizeof(key_name), SERVICECONFIG, mpm_service_name);
    apr_snprintf(key_name, sizeof(key_name), SERVICECONFIG, mpm_service_name);
    rv = ap_regkey_open(&key, AP_REGKEY_LOCAL_MACHINE, key_name, APR_READ, pconf);
    rv = ap_regkey_open(&key, AP_REGKEY_LOCAL_MACHINE, key_name, APR_READ, pconf);
    if (rv == APR_SUCCESS) {
    if (rv == APR_SUCCESS) {
@@ -577,6 +752,7 @@ apr_status_t mpm_service_set_name(apr_pool_t *p, const char **display_name,
        mpm_display_name = apr_pstrdup(p, set_name);
        mpm_display_name = apr_pstrdup(p, set_name);
    }
    }
    *display_name = mpm_display_name;
    *display_name = mpm_display_name;

    return rv;
    return rv;
}
}


@@ -756,28 +932,56 @@ apr_status_t mpm_service_install(apr_pool_t *ptemp, int argc,
                                 const char * const * argv, int reconfig)
                                 const char * const * argv, int reconfig)
{
{
    char key_name[MAX_PATH];
    char key_name[MAX_PATH];
    char exe_path[MAX_PATH];
    char *launch_cmd;
    ap_regkey_t *key;
    ap_regkey_t *key;
    char        *launch_cmd;
    apr_status_t rv;
    apr_status_t rv;


    fprintf(stderr,reconfig ? "Reconfiguring the %s service\n"
    fprintf(stderr,reconfig ? "Reconfiguring the %s service\n"
                   : "Installing the %s service\n", mpm_display_name);
                   : "Installing the %s service\n", mpm_display_name);


    /* ###: utf-ize */
    if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT)
    if (GetModuleFileName(NULL, exe_path, sizeof(exe_path)) == 0)
    {
    {
        apr_status_t rv = apr_get_os_error();
        SC_HANDLE   schService;
        SC_HANDLE   schSCManager;
        DWORD       rc;
#if APR_HAS_UNICODE_FS
        apr_wchar_t *display_name_w;
        apr_wchar_t *launch_cmd_w;

        IF_WIN_OS_IS_UNICODE
        {
            apr_size_t slen = strlen(mpm_display_name) + 1;
            apr_size_t wslen = slen;
            display_name_w = apr_palloc(ptemp, wslen * sizeof(apr_wchar_t));
            rv = apr_conv_utf8_to_ucs2(mpm_display_name, &slen,
                                       display_name_w, &wslen);
            if (rv != APR_SUCCESS)
                return rv;
            else if (slen)
                return APR_ENAMETOOLONG;

            launch_cmd_w = apr_palloc(ptemp, (MAX_PATH + 17) * sizeof(apr_wchar_t));
            launch_cmd_w[0] = L'"';
            rc = GetModuleFileNameW(NULL, launch_cmd_w + 1, MAX_PATH);
            wcscpy(launch_cmd_w + rc + 1, L"\" -k runservice");
        }
#endif /* APR_HAS_UNICODE_FS */
#if APR_HAS_ANSI_FS
        ELSE_WIN_OS_IS_ANSI
        {
            launch_cmd = apr_palloc(ptemp, MAX_PATH + 17);
            launch_cmd[0] = '"';
            rc = GetModuleFileName(NULL, launch_cmd + 1, MAX_PATH);
            strcpy(launch_cmd + rc + 1, "\" -k runservice");
        }
#endif
        if (rc == 0) {
            rv = apr_get_os_error();
            ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv, NULL,
            ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv, NULL,
                         "GetModuleFileName failed");
                         "GetModuleFileName failed");
            return rv;
            return rv;
        }
        }


    if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT)
    {
        SC_HANDLE   schService;
        SC_HANDLE   schSCManager;

        schSCManager = OpenSCManager(NULL, NULL, /* local, default database */
        schSCManager = OpenSCManager(NULL, NULL, /* local, default database */
                                     SC_MANAGER_CREATE_SERVICE);
                                     SC_MANAGER_CREATE_SERVICE);
        if (!schSCManager) {
        if (!schSCManager) {
@@ -787,25 +991,52 @@ apr_status_t mpm_service_install(apr_pool_t *ptemp, int argc,
            return (rv);
            return (rv);
        }
        }


        launch_cmd = apr_psprintf(ptemp, "\"%s\" -k runservice", exe_path);

        if (reconfig) {
        if (reconfig) {
            /* ###: utf-ize */
#if APR_HAS_UNICODE_FS
            IF_WIN_OS_IS_UNICODE
            {
                schService = OpenServiceW(schSCManager, mpm_service_name_w,
                                      SERVICE_CHANGE_CONFIG);
            }
#endif /* APR_HAS_UNICODE_FS */
#if APR_HAS_ANSI_FS
            ELSE_WIN_OS_IS_ANSI
            {
                schService = OpenService(schSCManager, mpm_service_name,
                schService = OpenService(schSCManager, mpm_service_name,
                                         SERVICE_CHANGE_CONFIG);
                                         SERVICE_CHANGE_CONFIG);
            }
#endif
            if (!schService) {
            if (!schService) {
                ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_ERR,
                ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_ERR,
                             apr_get_os_error(), NULL,
                             apr_get_os_error(), NULL,
                             "OpenService failed");
                             "OpenService failed");
            }
            }
            /* ###: utf-ize */
            else {
            else if (!ChangeServiceConfig(schService,
#if APR_HAS_UNICODE_FS
                IF_WIN_OS_IS_UNICODE
                {
                    rc = ChangeServiceConfigW(schService,
                                              SERVICE_WIN32_OWN_PROCESS,
                                              SERVICE_AUTO_START,
                                              SERVICE_ERROR_NORMAL,
                                              launch_cmd_w, NULL, NULL,
                                              L"Tcpip\0Afd\0", NULL, NULL,
                                              display_name_w);
                }
#endif /* APR_HAS_UNICODE_FS */
#if APR_HAS_ANSI_FS
                ELSE_WIN_OS_IS_ANSI
                {
                    rc = ChangeServiceConfig(schService,
                                             SERVICE_WIN32_OWN_PROCESS,
                                             SERVICE_WIN32_OWN_PROCESS,
                                             SERVICE_AUTO_START,
                                             SERVICE_AUTO_START,
                                             SERVICE_ERROR_NORMAL,
                                             SERVICE_ERROR_NORMAL,
                                             launch_cmd, NULL, NULL,
                                             launch_cmd, NULL, NULL,
                                             "Tcpip\0Afd\0", NULL, NULL,
                                             "Tcpip\0Afd\0", NULL, NULL,
                                          mpm_display_name)) {
                                             mpm_display_name);
                }
#endif
                if (!rc) {
                    ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_ERR,
                    ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_ERR,
                                 apr_get_os_error(), NULL,
                                 apr_get_os_error(), NULL,
                                 "ChangeServiceConfig failed");
                                 "ChangeServiceConfig failed");
@@ -814,6 +1045,7 @@ apr_status_t mpm_service_install(apr_pool_t *ptemp, int argc,
                    schService = NULL;
                    schService = NULL;
                }
                }
            }
            }
        }
        else {
        else {
            /* RPCSS is the Remote Procedure Call (RPC) Locator required
            /* RPCSS is the Remote Procedure Call (RPC) Locator required
             * for DCOM communication pipes.  I am far from convinced we
             * for DCOM communication pipes.  I am far from convinced we
@@ -821,7 +1053,28 @@ apr_status_t mpm_service_install(apr_pool_t *ptemp, int argc,
             * be warned that future apache modules or ISAPI dll's may
             * be warned that future apache modules or ISAPI dll's may
             * depend on it.
             * depend on it.
             */
             */
            /* ###: utf-ize */

#if APR_HAS_UNICODE_FS
            IF_WIN_OS_IS_UNICODE
            {
                schService = CreateServiceW(schSCManager,    // SCManager database
                                 mpm_service_name_w,   // name of service
                                 display_name_w,   // name to display
                                 SERVICE_ALL_ACCESS,   // access required
                                 SERVICE_WIN32_OWN_PROCESS,  // service type
                                 SERVICE_AUTO_START,   // start type
                                 SERVICE_ERROR_NORMAL, // error control type
                                 launch_cmd_w,         // service's binary
                                 NULL,                 // no load svc group
                                 NULL,                 // no tag identifier
                                 L"Tcpip\0Afd\0",      // dependencies
                                 NULL,                 // use SYSTEM account
                                 NULL);                // no password
            }
#endif /* APR_HAS_UNICODE_FS */
#if APR_HAS_ANSI_FS
            ELSE_WIN_OS_IS_ANSI
            {
                schService = CreateService(schSCManager,     // SCManager database
                schService = CreateService(schSCManager,     // SCManager database
                                 mpm_service_name,     // name of service
                                 mpm_service_name,     // name of service
                                 mpm_display_name,     // name to display
                                 mpm_display_name,     // name to display
@@ -835,7 +1088,8 @@ apr_status_t mpm_service_install(apr_pool_t *ptemp, int argc,
                                 "Tcpip\0Afd\0",       // dependencies
                                 "Tcpip\0Afd\0",       // dependencies
                                 NULL,                 // use SYSTEM account
                                 NULL,                 // use SYSTEM account
                                 NULL);                // no password
                                 NULL);                // no password

            }
#endif
            if (!schService)
            if (!schService)
            {
            {
                rv = apr_get_os_error();
                rv = apr_get_os_error();
@@ -851,6 +1105,16 @@ apr_status_t mpm_service_install(apr_pool_t *ptemp, int argc,
    }
    }
    else /* osver.dwPlatformId != VER_PLATFORM_WIN32_NT */
    else /* osver.dwPlatformId != VER_PLATFORM_WIN32_NT */
    {
    {
        char exe_path[MAX_PATH];

        if (GetModuleFileName(NULL, exe_path, sizeof(exe_path)) == 0)
        {
            apr_status_t rv = apr_get_os_error();
            ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv, NULL,
                         "GetModuleFileName failed");
            return rv;
        }

        /* Store the launch command in the registry */
        /* Store the launch command in the registry */
        launch_cmd = apr_psprintf(ptemp, "\"%s\" -n %s -k runservice",
        launch_cmd = apr_psprintf(ptemp, "\"%s\" -n %s -k runservice",
                                 exe_path, mpm_service_name);
                                 exe_path, mpm_service_name);
@@ -939,9 +1203,18 @@ apr_status_t mpm_service_uninstall(void)
            return (rv);
            return (rv);
        }
        }


        /* ###: utf-ize */
#if APR_HAS_UNICODE_FS
        IF_WIN_OS_IS_UNICODE
        {
            schService = OpenServiceW(schSCManager, mpm_service_name_w, DELETE);
        }
#endif /* APR_HAS_UNICODE_FS */
#if APR_HAS_ANSI_FS
        ELSE_WIN_OS_IS_ANSI
        {
            schService = OpenService(schSCManager, mpm_service_name, DELETE);
            schService = OpenService(schSCManager, mpm_service_name, DELETE);

        }
#endif
        if (!schService) {
        if (!schService) {
           rv = apr_get_os_error();
           rv = apr_get_os_error();
           ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv, NULL,
           ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv, NULL,
@@ -1040,7 +1313,6 @@ apr_status_t mpm_service_start(apr_pool_t *ptemp, int argc,


    if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT)
    if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT)
    {
    {
        CHAR **start_argv;
        SC_HANDLE   schService;
        SC_HANDLE   schService;
        SC_HANDLE   schSCManager;
        SC_HANDLE   schSCManager;


@@ -1053,9 +1325,20 @@ apr_status_t mpm_service_start(apr_pool_t *ptemp, int argc,
            return (rv);
            return (rv);
        }
        }


        /* ###: utf-ize */
#if APR_HAS_UNICODE_FS
        IF_WIN_OS_IS_UNICODE
        {
            schService = OpenServiceW(schSCManager, mpm_service_name_w,
                                     SERVICE_START | SERVICE_QUERY_STATUS);
        }
#endif /* APR_HAS_UNICODE_FS */
#if APR_HAS_ANSI_FS
        ELSE_WIN_OS_IS_ANSI
        {
            schService = OpenService(schSCManager, mpm_service_name,
            schService = OpenService(schSCManager, mpm_service_name,
                                     SERVICE_START | SERVICE_QUERY_STATUS);
                                     SERVICE_START | SERVICE_QUERY_STATUS);
        }
#endif
        if (!schService) {
        if (!schService) {
            rv = apr_get_os_error();
            rv = apr_get_os_error();
            ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv, NULL,
            ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv, NULL,
@@ -1073,18 +1356,47 @@ apr_status_t mpm_service_start(apr_pool_t *ptemp, int argc,
            return 0;
            return 0;
        }
        }


        start_argv = malloc((argc + 1) * sizeof(const char **));
        rv = APR_EINIT;
        memcpy(start_argv, argv, argc * sizeof(const char **));
#if APR_HAS_UNICODE_FS
        IF_WIN_OS_IS_UNICODE
        {
            LPWSTR *start_argv_w = malloc((argc + 1) * sizeof(LPCWSTR));
            int i;

            for (i = 0; i < argc; ++i)
            {
                apr_size_t slen = strlen(argv[i]) + 1;
                apr_size_t wslen = slen;
                start_argv_w[i] = malloc(wslen * sizeof(WCHAR));
                rv = apr_conv_utf8_to_ucs2(argv[i], &slen, start_argv_w[i], &wslen);
                if (rv != APR_SUCCESS)
                    return rv;
                else if (slen)
                    return APR_ENAMETOOLONG;
            }
            start_argv_w[argc] = NULL;

            if (StartServiceW(schService, argc, start_argv_w)
                && signal_service_transition(schService, 0, /* test only */
                                             SERVICE_START_PENDING,
                                             SERVICE_RUNNING))
                    rv = APR_SUCCESS;
        }
#endif /* APR_HAS_UNICODE_FS */
#if APR_HAS_ANSI_FS
        ELSE_WIN_OS_IS_ANSI
        {
            char **start_argv = malloc((argc + 1) * sizeof(const char *));
            memcpy(start_argv, argv, argc * sizeof(const char *));
            start_argv[argc] = NULL;
            start_argv[argc] = NULL;


        rv = APR_EINIT;
        /* ###: utf-ize */
            if (StartService(schService, argc, start_argv)
            if (StartService(schService, argc, start_argv)
                && signal_service_transition(schService, 0, /* test only */
                && signal_service_transition(schService, 0, /* test only */
                                             SERVICE_START_PENDING,
                                             SERVICE_START_PENDING,
                                             SERVICE_RUNNING))
                                             SERVICE_RUNNING))
                    rv = APR_SUCCESS;
                    rv = APR_SUCCESS;

        }
#endif
        if (rv != APR_SUCCESS)
        if (rv != APR_SUCCESS)
            rv = apr_get_os_error();
            rv = apr_get_os_error();


@@ -1193,12 +1505,24 @@ void mpm_signal_service(apr_pool_t *ptemp, int signal)
            return;
            return;
        }
        }


        /* ###: utf-ize */
#if APR_HAS_UNICODE_FS
        IF_WIN_OS_IS_UNICODE
        {
            schService = OpenServiceW(schSCManager, mpm_service_name_w,
                                      SERVICE_INTERROGATE | SERVICE_QUERY_STATUS |
                                      SERVICE_USER_DEFINED_CONTROL |
                                      SERVICE_START | SERVICE_STOP);
        }
#endif /* APR_HAS_UNICODE_FS */
#if APR_HAS_ANSI_FS
        ELSE_WIN_OS_IS_ANSI
        {
            schService = OpenService(schSCManager, mpm_service_name,
            schService = OpenService(schSCManager, mpm_service_name,
                                     SERVICE_INTERROGATE | SERVICE_QUERY_STATUS |
                                     SERVICE_INTERROGATE | SERVICE_QUERY_STATUS |
                                     SERVICE_USER_DEFINED_CONTROL |
                                     SERVICE_USER_DEFINED_CONTROL |
                                     SERVICE_START | SERVICE_STOP);
                                     SERVICE_START | SERVICE_STOP);

        }
#endif
        if (schService == NULL) {
        if (schService == NULL) {
            /* Could not open the service */
            /* Could not open the service */
            ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, apr_get_os_error(), NULL,
            ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, apr_get_os_error(), NULL,