]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
mpm_winnt: Accept utf-8 (Unicode) service names and descriptions for
authorWilliam A. Rowe Jr <wrowe@apache.org>
Sat, 23 May 2015 05:25:22 +0000 (05:25 +0000)
committerWilliam A. Rowe Jr <wrowe@apache.org>
Sat, 23 May 2015 05:25:22 +0000 (05:25 +0000)
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

CHANGES
STATUS
server/mpm/winnt/service.c

diff --git a/CHANGES b/CHANGES
index d50990451aeb580e84b748d500db57f9853a8df4..600eac02143c958c613b404cf3c0b680205a1812 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,9 @@
                                                          -*- coding: utf-8 -*-
 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
      seconds, milliseconds or microseconds depending on UNIT ("s", "ms", "us").
      [Ben Reser, Rainer Jung]
diff --git a/STATUS b/STATUS
index e7f00a23e6696e43c4b8dea6b08cd17db500b8a2..f17f1bf2816592618eefd0d28c92214197e959e3 100644 (file)
--- a/STATUS
+++ b/STATUS
@@ -101,12 +101,6 @@ RELEASE SHOWSTOPPERS:
 PATCHES ACCEPTED TO BACKPORT FROM TRUNK:
   [ 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().
      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
index aa5291d260d47e4a97b9c3d4c9cbb09f424a1f58..e206b45ae9fbe9a424f2250ff178bf50d904c70c 100644 (file)
 #define CORE_PRIVATE
 #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 "http_log.h"
 #include "mpm_winnt.h"
-#include "apr_strings.h"
-#include "apr_lib.h"
 #include "ap_regkey.h"
 
 #ifdef NOUSER
 static char *mpm_service_name = NULL;
 static char *mpm_display_name = NULL;
 
+#if APR_HAS_UNICODE_FS
+static apr_wchar_t *mpm_service_name_w;
+#endif
+
 static struct
 {
     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);
 
 
+/* 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:
  *
  * HKLM\System\CurrentControlSet\Services\[service name]
@@ -408,18 +446,50 @@ static void set_service_description(void)
           && (ChangeServiceConfig2)
           && (schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT)))
     {
-        SC_HANDLE schService = OpenService(schSCManager, mpm_service_name,
-                                           SERVICE_CHANGE_CONFIG);
+        SC_HANDLE schService;
+
+#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,
+                                     SERVICE_CHANGE_CONFIG);
+        }
+#endif
         if (schService) {
             /* Cast is necessary, ChangeServiceConfig2 handles multiple
              * object types, some volatile, some not.
              */
-            /* ###: utf-ize */
-            if (ChangeServiceConfig2(schService,
-                                     1 /* SERVICE_CONFIG_DESCRIPTION */,
-                                     (LPVOID) &full_description)) {
-                full_description = NULL;
+#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,
+                                         1 /* SERVICE_CONFIG_DESCRIPTION */,
+                                         (LPVOID) &full_description))
+                    full_description = NULL;
+            }
+#endif
             CloseServiceHandle(schService);
         }
         CloseServiceHandle(schSCManager);
@@ -473,8 +543,82 @@ static VOID WINAPI service_nt_ctrl(DWORD dwCtrlCode)
  */
 extern apr_array_header_t *mpm_new_argv;
 
-/* ###: utf-ize */
-static void __stdcall service_nt_main_fn(DWORD argc, LPTSTR *argv)
+#if APR_HAS_UNICODE_FS
+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;
 
@@ -486,8 +630,7 @@ static void __stdcall service_nt_main_fn(DWORD argc, LPTSTR *argv)
     globdat.ssStatus.dwCurrentState = SERVICE_START_PENDING;
     globdat.ssStatus.dwCheckPoint = 1;
 
-    /* ###: utf-ize */
-    if (!(globdat.hServiceStatus = RegisterServiceCtrlHandler(argv[0], service_nt_ctrl)))
+    if (!(globdat.hServiceStatus = RegisterServiceCtrlHandlerA(argv[0], service_nt_ctrl)))
     {
         ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, apr_get_os_error(),
                      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()
      * 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)
     {
@@ -528,27 +671,44 @@ static void __stdcall service_nt_main_fn(DWORD argc, LPTSTR *argv)
 
     WaitForSingleObject(globdat.service_term, INFINITE);
 }
+#endif
 
 
 static DWORD WINAPI service_nt_dispatch_thread(LPVOID nada)
 {
-    apr_status_t rv = APR_SUCCESS;
-
-    SERVICE_TABLE_ENTRY dispatchTable[] =
+#if APR_HAS_UNICODE_FS
+    SERVICE_TABLE_ENTRYW dispatchTable_w[] =
+    {
+        { 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 },
         { NULL, NULL }
     };
+#endif
+    apr_status_t rv;
 
-    /* ###: utf-ize */
-    if (!StartServiceCtrlDispatcher(dispatchTable))
-    {
+#if APR_HAS_UNICODE_FS
+    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. */
         rv = apr_get_os_error();
         ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, rv, NULL,
                      "Error starting service control dispatcher");
     }
-
     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);
     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);
     rv = ap_regkey_open(&key, AP_REGKEY_LOCAL_MACHINE, key_name, APR_READ, pconf);
     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);
     }
     *display_name = mpm_display_name;
+
     return rv;
 }
 
@@ -756,27 +932,55 @@ apr_status_t mpm_service_install(apr_pool_t *ptemp, int argc,
                                  const char * const * argv, int reconfig)
 {
     char key_name[MAX_PATH];
-    char exe_path[MAX_PATH];
-    char *launch_cmd;
     ap_regkey_t *key;
+    char        *launch_cmd;
     apr_status_t rv;
 
     fprintf(stderr,reconfig ? "Reconfiguring the %s service\n"
                    : "Installing the %s service\n", mpm_display_name);
 
-    /* ###: utf-ize */
-    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;
-    }
-
     if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT)
     {
         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,
+                         "GetModuleFileName failed");
+            return rv;
+        }
 
         schSCManager = OpenSCManager(NULL, NULL, /* local, default database */
                                      SC_MANAGER_CREATE_SERVICE);
@@ -787,31 +991,59 @@ apr_status_t mpm_service_install(apr_pool_t *ptemp, int argc,
             return (rv);
         }
 
-        launch_cmd = apr_psprintf(ptemp, "\"%s\" -k runservice", exe_path);
-
         if (reconfig) {
-            /* ###: utf-ize */
-            schService = OpenService(schSCManager, mpm_service_name,
-                                     SERVICE_CHANGE_CONFIG);
+#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,
+                                         SERVICE_CHANGE_CONFIG);
+            }
+#endif
             if (!schService) {
                 ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_ERR,
                              apr_get_os_error(), NULL,
                              "OpenService failed");
             }
-            /* ###: utf-ize */
-            else if (!ChangeServiceConfig(schService,
-                                          SERVICE_WIN32_OWN_PROCESS,
-                                          SERVICE_AUTO_START,
-                                          SERVICE_ERROR_NORMAL,
-                                          launch_cmd, NULL, NULL,
-                                          "Tcpip\0Afd\0", NULL, NULL,
-                                          mpm_display_name)) {
-                ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_ERR,
-                             apr_get_os_error(), NULL,
-                             "ChangeServiceConfig failed");
-                /* !schService aborts configuration below */
-                CloseServiceHandle(schService);
-                schService = NULL;
+            else {
+#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_AUTO_START,
+                                             SERVICE_ERROR_NORMAL,
+                                             launch_cmd, NULL, NULL,
+                                             "Tcpip\0Afd\0", NULL, NULL,
+                                             mpm_display_name);
+                }
+#endif
+                if (!rc) {
+                    ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_ERR,
+                                 apr_get_os_error(), NULL,
+                                 "ChangeServiceConfig failed");
+                    /* !schService aborts configuration below */
+                    CloseServiceHandle(schService);
+                    schService = NULL;
+                }
             }
         }
         else {
@@ -821,21 +1053,43 @@ apr_status_t mpm_service_install(apr_pool_t *ptemp, int argc,
              * be warned that future apache modules or ISAPI dll's may
              * depend on it.
              */
-            /* ###: utf-ize */
-            schService = CreateService(schSCManager,         // SCManager database
-                                   mpm_service_name,     // name of service
-                                   mpm_display_name,     // 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,           // service's binary
-                                   NULL,                 // no load svc group
-                                   NULL,                 // no tag identifier
-                                   "Tcpip\0Afd\0",       // dependencies
-                                   NULL,                 // use SYSTEM account
-                                   NULL);                // no password
 
+#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
+                                 mpm_service_name,     // name of service
+                                 mpm_display_name,     // 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,           // service's binary
+                                 NULL,                 // no load svc group
+                                 NULL,                 // no tag identifier
+                                 "Tcpip\0Afd\0",       // dependencies
+                                 NULL,                 // use SYSTEM account
+                                 NULL);                // no password
+            }
+#endif
             if (!schService)
             {
                 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 */
     {
+        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 */
         launch_cmd = apr_psprintf(ptemp, "\"%s\" -n %s -k runservice",
                                  exe_path, mpm_service_name);
@@ -939,9 +1203,18 @@ apr_status_t mpm_service_uninstall(void)
             return (rv);
         }
 
-        /* ###: utf-ize */
-        schService = OpenService(schSCManager, mpm_service_name, DELETE);
-
+#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);
+        }
+#endif
         if (!schService) {
            rv = apr_get_os_error();
            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)
     {
-        CHAR **start_argv;
         SC_HANDLE   schService;
         SC_HANDLE   schSCManager;
 
@@ -1053,9 +1325,20 @@ apr_status_t mpm_service_start(apr_pool_t *ptemp, int argc,
             return (rv);
         }
 
-        /* ###: utf-ize */
-        schService = OpenService(schSCManager, mpm_service_name,
-                                 SERVICE_START | SERVICE_QUERY_STATUS);
+#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,
+                                     SERVICE_START | SERVICE_QUERY_STATUS);
+        }
+#endif
         if (!schService) {
             rv = apr_get_os_error();
             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;
         }
 
-        start_argv = malloc((argc + 1) * sizeof(const char **));
-        memcpy(start_argv, argv, argc * sizeof(const char **));
-        start_argv[argc] = NULL;
-
         rv = APR_EINIT;
-        /* ###: utf-ize */
-        if (StartService(schService, argc, start_argv)
-            && signal_service_transition(schService, 0, /* test only */
-                                         SERVICE_START_PENDING,
-                                         SERVICE_RUNNING))
-                rv = APR_SUCCESS;
+#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;
+
+            if (StartService(schService, argc, start_argv)
+                && signal_service_transition(schService, 0, /* test only */
+                                             SERVICE_START_PENDING,
+                                             SERVICE_RUNNING))
+                    rv = APR_SUCCESS;
+        }
+#endif
         if (rv != APR_SUCCESS)
             rv = apr_get_os_error();
 
@@ -1193,12 +1505,24 @@ void mpm_signal_service(apr_pool_t *ptemp, int signal)
             return;
         }
 
-        /* ###: utf-ize */
-        schService = OpenService(schSCManager, mpm_service_name,
-                                 SERVICE_INTERROGATE | SERVICE_QUERY_STATUS |
-                                 SERVICE_USER_DEFINED_CONTROL |
-                                 SERVICE_START | SERVICE_STOP);
-
+#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,
+                                     SERVICE_INTERROGATE | SERVICE_QUERY_STATUS |
+                                     SERVICE_USER_DEFINED_CONTROL |
+                                     SERVICE_START | SERVICE_STOP);
+        }
+#endif
         if (schService == NULL) {
             /* Could not open the service */
             ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_STARTUP, apr_get_os_error(), NULL,