[SERVICES] Revert f6d81f22 because it breaks the advapi32 LockServiceDatabase test.
[reactos.git] / base / system / services / rpcserver.c
index 2e6e808..7f251c8 100644 (file)
@@ -97,6 +97,7 @@ ScmServiceMapping = {SERVICE_READ,
                      SERVICE_EXECUTE,
                      SERVICE_ALL_ACCESS};
 
+DWORD g_dwServiceBits = 0;
 
 /* FUNCTIONS ***************************************************************/
 
@@ -462,7 +463,6 @@ ScmConvertToBootPathName(wchar_t *CanonName, wchar_t **RelativeName)
 
     /* Get buffer size needed for expanding env strings */
     BufferSize = ExpandEnvironmentStringsW(L"%SystemRoot%\\", &Dest, 1);
-
     if (BufferSize <= 1)
     {
         DPRINT("Error during a call to ExpandEnvironmentStringsW()\n");
@@ -1017,7 +1017,7 @@ RCloseServiceHandle(
                                            &pcbBytesNeeded,
                                            &dwServicesReturned);
 
-                /* if pcbBytesNeeded returned a value then there are services running that are dependent on this service */
+                /* If pcbBytesNeeded returned a value then there are services running that are dependent on this service */
                 if (pcbBytesNeeded)
                 {
                     DPRINT("Deletion failed due to running dependencies.\n");
@@ -1496,7 +1496,9 @@ RSetServiceObjectSecurity(
     if (dwSecurityInformation == 0 ||
         dwSecurityInformation & ~(OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION
         | DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION))
+    {
         return ERROR_INVALID_PARAMETER;
+    }
 
     if (!RtlValidSecurityDescriptor((PSECURITY_DESCRIPTOR)lpSecurityDescriptor))
         return ERROR_INVALID_PARAMETER;
@@ -1512,11 +1514,15 @@ RSetServiceObjectSecurity(
 
     if ((dwSecurityInformation & OWNER_SECURITY_INFORMATION) &&
         (((PISECURITY_DESCRIPTOR)lpSecurityDescriptor)->Owner == NULL))
+    {
         return ERROR_INVALID_PARAMETER;
+    }
 
     if ((dwSecurityInformation & GROUP_SECURITY_INFORMATION) &&
         (((PISECURITY_DESCRIPTOR)lpSecurityDescriptor)->Group == NULL))
+    {
         return ERROR_INVALID_PARAMETER;
+    }
 
     if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
                                   DesiredAccess))
@@ -1884,14 +1890,20 @@ RI_ScSetServiceBitsW(
     if (bSetBitsOn)
     {
         DPRINT("Old service bits: %08lx\n", pService->dwServiceBits);
+        DPRINT("Old global service bits: %08lx\n", g_dwServiceBits);
         pService->dwServiceBits |= dwServiceBits;
+        g_dwServiceBits |= dwServiceBits;
         DPRINT("New service bits: %08lx\n", pService->dwServiceBits);
+        DPRINT("New global service bits: %08lx\n", g_dwServiceBits);
     }
     else
     {
         DPRINT("Old service bits: %08lx\n", pService->dwServiceBits);
+        DPRINT("Old global service bits: %08lx\n", g_dwServiceBits);
         pService->dwServiceBits &= ~dwServiceBits;
+        g_dwServiceBits &= ~dwServiceBits;
         DPRINT("New service bits: %08lx\n", pService->dwServiceBits);
+        DPRINT("New global service bits: %08lx\n", g_dwServiceBits);
     }
 
     return ERROR_SUCCESS;
@@ -1922,6 +1934,7 @@ RChangeServiceConfigW(
     HKEY hServiceKey = NULL;
     LPWSTR lpDisplayNameW = NULL;
     LPWSTR lpImagePathW = NULL;
+    LPWSTR lpClearTextPassword = NULL;
 
     DPRINT("RChangeServiceConfigW() called\n");
     DPRINT("dwServiceType = 0x%lx\n", dwServiceType);
@@ -1929,6 +1942,9 @@ RChangeServiceConfigW(
     DPRINT("dwErrorControl = %lu\n", dwErrorControl);
     DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName);
     DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup);
+    DPRINT("lpServiceStartName = %S\n", lpServiceStartName);
+    DPRINT("lpPassword = %p\n", lpPassword);
+    DPRINT("dwPwSite = %lu\n", dwPwSize);
     DPRINT("lpDisplayName = %S\n", lpDisplayName);
 
     if (ScmShutdown)
@@ -1954,7 +1970,9 @@ RChangeServiceConfigW(
         (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER) &&
         ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_OWN_PROCESS) &&
         ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_SHARE_PROCESS))
-            return ERROR_INVALID_PARAMETER;
+    {
+        return ERROR_INVALID_PARAMETER;
+    }
 
     /* Check for invalid start type value */
     if ((dwStartType != SERVICE_NO_CHANGE) &&
@@ -1963,7 +1981,9 @@ RChangeServiceConfigW(
         (dwStartType != SERVICE_AUTO_START) &&
         (dwStartType != SERVICE_DEMAND_START) &&
         (dwStartType != SERVICE_DISABLED))
+    {
         return ERROR_INVALID_PARAMETER;
+    }
 
     /* Only drivers can be boot start or system start services */
     if ((dwStartType == SERVICE_BOOT_START) ||
@@ -1980,7 +2000,14 @@ RChangeServiceConfigW(
         (dwErrorControl != SERVICE_ERROR_NORMAL) &&
         (dwErrorControl != SERVICE_ERROR_SEVERE) &&
         (dwErrorControl != SERVICE_ERROR_CRITICAL))
+    {
         return ERROR_INVALID_PARAMETER;
+    }
+
+    if (lpdwTagId && (!lpLoadOrderGroup || !*lpLoadOrderGroup))
+    {
+        return ERROR_INVALID_PARAMETER;
+    }
 
     lpService = hSvc->ServiceEntry;
     if (lpService == NULL)
@@ -2007,6 +2034,7 @@ RChangeServiceConfigW(
         goto done;
 
     /* Write service data to the registry */
+
     /* Set the display name */
     if (lpDisplayName != NULL && *lpDisplayName != 0)
     {
@@ -2155,32 +2183,72 @@ RChangeServiceConfigW(
             goto done;
     }
 
-    if (lpPassword != NULL)
+    /* Start name and password are only used by Win32 services */
+    if (lpService->Status.dwServiceType & SERVICE_WIN32)
     {
-        if (wcslen((LPWSTR)lpPassword) != 0)
+        /* Write service start name */
+        if (lpServiceStartName != NULL && *lpServiceStartName != 0)
         {
-            /* FIXME: Decrypt the password */
-
-            /* Write the password */
-            dwError = ScmSetServicePassword(lpService->szServiceName,
-                                            (LPCWSTR)lpPassword);
+            dwError = RegSetValueExW(hServiceKey,
+                                     L"ObjectName",
+                                     0,
+                                     REG_SZ,
+                                     (LPBYTE)lpServiceStartName,
+                                     (DWORD)((wcslen(lpServiceStartName) + 1) * sizeof(WCHAR)));
             if (dwError != ERROR_SUCCESS)
                 goto done;
         }
-        else
+
+        if (lpPassword != NULL)
         {
-            /* Delete the password */
-            dwError = ScmSetServicePassword(lpService->szServiceName,
-                                            NULL);
-            if (dwError == ERROR_FILE_NOT_FOUND)
-                dwError = ERROR_SUCCESS;
+            if (*(LPWSTR)lpPassword != 0)
+            {
+                /* Decrypt the password */
+                dwError = ScmDecryptPassword(lpPassword,
+                                             dwPwSize,
+                                             &lpClearTextPassword);
+                if (dwError != ERROR_SUCCESS)
+                {
+                    DPRINT1("ScmDecryptPassword failed (Error %lu)\n", dwError);
+                    goto done;
+                }
+                DPRINT1("Clear text password: %S\n", lpClearTextPassword);
 
-            if (dwError != ERROR_SUCCESS)
-                goto done;
+                /* Write the password */
+                dwError = ScmSetServicePassword(lpService->szServiceName,
+                                                lpClearTextPassword);
+                if (dwError != ERROR_SUCCESS)
+                {
+                    DPRINT1("ScmSetServicePassword failed (Error %lu)\n", dwError);
+                    goto done;
+                }
+            }
+            else
+            {
+                /* Delete the password */
+                dwError = ScmSetServicePassword(lpService->szServiceName,
+                                                NULL);
+                if (dwError == ERROR_FILE_NOT_FOUND)
+                    dwError = ERROR_SUCCESS;
+
+                if (dwError != ERROR_SUCCESS)
+                {
+                    DPRINT1("ScmSetServicePassword failed (Error %lu)\n", dwError);
+                    goto done;
+                }
+            }
         }
     }
 
 done:
+    if (lpClearTextPassword != NULL)
+    {
+        /* Wipe and release the password buffer */
+        SecureZeroMemory(lpClearTextPassword,
+                         (wcslen(lpClearTextPassword) + 1) * sizeof(WCHAR));
+        HeapFree(GetProcessHeap(), 0, lpClearTextPassword);
+    }
+
     if (hServiceKey != NULL)
         RegCloseKey(hServiceKey);
 
@@ -2219,6 +2287,7 @@ RCreateServiceW(
     PSERVICE lpService = NULL;
     SC_HANDLE hServiceHandle = NULL;
     LPWSTR lpImagePath = NULL;
+    LPWSTR lpClearTextPassword = NULL;
     HKEY hServiceKey = NULL;
     LPWSTR lpObjectName;
 
@@ -2252,22 +2321,20 @@ RCreateServiceW(
         return ERROR_ACCESS_DENIED;
     }
 
-    if (wcslen(lpServiceName) == 0)
-    {
+    if (*lpServiceName == 0)
         return ERROR_INVALID_NAME;
-    }
 
-    if (wcslen(lpBinaryPathName) == 0)
-    {
+    if (*lpBinaryPathName == 0)
         return ERROR_INVALID_PARAMETER;
-    }
 
     /* Check for invalid service type value */
     if ((dwServiceType != SERVICE_KERNEL_DRIVER) &&
         (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER) &&
         ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_OWN_PROCESS) &&
         ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_SHARE_PROCESS))
-            return ERROR_INVALID_PARAMETER;
+    {
+        return ERROR_INVALID_PARAMETER;
+    }
 
     /* Check for invalid start type value */
     if ((dwStartType != SERVICE_BOOT_START) &&
@@ -2275,7 +2342,9 @@ RCreateServiceW(
         (dwStartType != SERVICE_AUTO_START) &&
         (dwStartType != SERVICE_DEMAND_START) &&
         (dwStartType != SERVICE_DISABLED))
+    {
         return ERROR_INVALID_PARAMETER;
+    }
 
     /* Only drivers can be boot start or system start services */
     if ((dwStartType == SERVICE_BOOT_START) ||
@@ -2283,7 +2352,9 @@ RCreateServiceW(
     {
         if ((dwServiceType != SERVICE_KERNEL_DRIVER) &&
             (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER))
+        {
             return ERROR_INVALID_PARAMETER;
+        }
     }
 
     /* Check for invalid error control value */
@@ -2291,7 +2362,9 @@ RCreateServiceW(
         (dwErrorControl != SERVICE_ERROR_NORMAL) &&
         (dwErrorControl != SERVICE_ERROR_SEVERE) &&
         (dwErrorControl != SERVICE_ERROR_CRITICAL))
+    {
         return ERROR_INVALID_PARAMETER;
+    }
 
     if ((dwServiceType == (SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS)) &&
         (lpServiceStartName))
@@ -2321,7 +2394,7 @@ RCreateServiceW(
         if (lpService->bDeleted)
             return ERROR_SERVICE_MARKED_FOR_DELETE;
 
-        /* Return Error exist */
+        /* Return service-exists error */
         return ERROR_SERVICE_EXISTS;
     }
 
@@ -2529,18 +2602,22 @@ RCreateServiceW(
         if (dwError != ERROR_SUCCESS)
             goto done;
 
-        if (lpPassword != NULL && wcslen((LPWSTR)lpPassword) != 0)
+        if (lpPassword != NULL && *(LPWSTR)lpPassword != 0)
         {
-            /* FIXME: Decrypt the password */
+            /* Decrypt the password */
+            dwError = ScmDecryptPassword(lpPassword,
+                                         dwPwSize,
+                                         &lpClearTextPassword);
+            if (dwError != ERROR_SUCCESS)
+                goto done;
 
             /* Write the password */
             dwError = ScmSetServicePassword(lpServiceName,
-                                            (LPCWSTR)lpPassword);
+                                            lpClearTextPassword);
             if (dwError != ERROR_SUCCESS)
                 goto done;
         }
 
-DPRINT1("\n");
         /* Write the security descriptor */
         dwError = ScmWriteSecurityDescriptor(hServiceKey,
                                              lpService->pSecurityDescriptor);
@@ -2568,6 +2645,14 @@ done:
     if (hServiceKey != NULL)
         RegCloseKey(hServiceKey);
 
+    if (lpClearTextPassword != NULL)
+    {
+        /* Wipe and release the password buffer */
+        SecureZeroMemory(lpClearTextPassword,
+                         (wcslen(lpClearTextPassword) + 1) * sizeof(WCHAR));
+        HeapFree(GetProcessHeap(), 0, lpClearTextPassword);
+    }
+
     if (dwError == ERROR_SUCCESS)
     {
         DPRINT("hService %p\n", hServiceHandle);
@@ -2862,7 +2947,7 @@ ROpenServiceW(
     lpService = ScmGetServiceEntryByName(lpServiceName);
     if (lpService == NULL)
     {
-        DPRINT("Could not find a service!\n");
+        DPRINT("Could not find the service!\n");
         dwError = ERROR_SERVICE_DOES_NOT_EXIST;
         goto Done;
     }
@@ -2921,7 +3006,6 @@ RQueryServiceConfigW(
     LPWSTR lpDependencies = NULL;
     DWORD dwDependenciesLength = 0;
     DWORD dwRequiredSize;
-    WCHAR lpEmptyString[] = {0,0};
     LPWSTR lpStr;
 
     DPRINT("RQueryServiceConfigW() called\n");
@@ -3023,7 +3107,7 @@ RQueryServiceConfigW(
         }
         else
         {
-            wcscpy(lpStr, lpEmptyString);
+            *lpStr = 0;
         }
 
         lpServiceConfig->lpBinaryPathName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
@@ -3036,7 +3120,7 @@ RQueryServiceConfigW(
         }
         else
         {
-            wcscpy(lpStr, lpEmptyString);
+            *lpStr = 0;
         }
 
         lpServiceConfig->lpLoadOrderGroup = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
@@ -3051,7 +3135,7 @@ RQueryServiceConfigW(
         }
         else
         {
-            wcscpy(lpStr, lpEmptyString);
+            *lpStr = 0;
         }
 
         lpServiceConfig->lpDependencies = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
@@ -3067,7 +3151,7 @@ RQueryServiceConfigW(
         }
         else
         {
-            wcscpy(lpStr, lpEmptyString);
+            *lpStr = 0;
         }
 
         lpServiceConfig->lpServiceStartName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
@@ -3080,7 +3164,7 @@ RQueryServiceConfigW(
         }
         else
         {
-            wcscpy(lpStr, lpEmptyString);
+            *lpStr = 0;
         }
 
         lpServiceConfig->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
@@ -3226,8 +3310,9 @@ RGetServiceDisplayNameW(
     LPWSTR lpDisplayName,
     DWORD *lpcchBuffer)
 {
-//    PMANAGER_HANDLE hManager;
+    // PMANAGER_HANDLE hManager;
     PSERVICE lpService;
+    LPCWSTR lpSvcDisplayName;
     DWORD dwLength;
     DWORD dwError;
 
@@ -3237,56 +3322,42 @@ RGetServiceDisplayNameW(
     DPRINT("lpDisplayName: %p\n", lpDisplayName);
     DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
 
-//    hManager = (PMANAGER_HANDLE)hSCManager;
-//    if (hManager->Handle.Tag != MANAGER_TAG)
-//    {
-//        DPRINT("Invalid manager handle!\n");
-//        return ERROR_INVALID_HANDLE;
-//    }
+#if 0
+    hManager = (PMANAGER_HANDLE)hSCManager;
+    if (hManager->Handle.Tag != MANAGER_TAG)
+    {
+        DPRINT("Invalid manager handle!\n");
+        return ERROR_INVALID_HANDLE;
+    }
+#endif
 
     /* Get service database entry */
     lpService = ScmGetServiceEntryByName(lpServiceName);
     if (lpService == NULL)
     {
-        DPRINT("Could not find a service!\n");
-
-        /* If the service could not be found and lpcchBuffer is less than 2, windows
-           puts null in lpDisplayName and puts 2 in lpcchBuffer */
-        if (*lpcchBuffer < 2)
-        {
-            *lpcchBuffer = 2;
-            if (lpDisplayName != NULL)
-            {
-                *lpDisplayName = 0;
-            }
-        }
-
+        DPRINT("Could not find the service!\n");
         return ERROR_SERVICE_DOES_NOT_EXIST;
     }
 
-    if (!lpService->lpDisplayName)
+    if (lpService->lpDisplayName)
+        lpSvcDisplayName = lpService->lpDisplayName;
+    else
+        lpSvcDisplayName = lpService->lpServiceName;
+
+    dwLength = (DWORD)wcslen(lpSvcDisplayName);
+
+    if (*lpcchBuffer > dwLength)
     {
-        dwLength = (DWORD)wcslen(lpService->lpServiceName);
+        if (lpDisplayName != NULL)
+            wcscpy(lpDisplayName, lpSvcDisplayName);
 
-        if (lpDisplayName != NULL &&
-            *lpcchBuffer > dwLength)
-        {
-            wcscpy(lpDisplayName, lpService->lpServiceName);
-        }
+        dwError = ERROR_SUCCESS;
     }
     else
     {
-        dwLength = (DWORD)wcslen(lpService->lpDisplayName);
-
-        if (lpDisplayName != NULL &&
-            *lpcchBuffer > dwLength)
-        {
-            wcscpy(lpDisplayName, lpService->lpDisplayName);
-        }
+        dwError = ERROR_INSUFFICIENT_BUFFER;
     }
 
-    dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
-
     *lpcchBuffer = dwLength;
 
     return dwError;
@@ -3302,7 +3373,7 @@ RGetServiceKeyNameW(
     LPWSTR lpServiceName,
     DWORD *lpcchBuffer)
 {
-//    PMANAGER_HANDLE hManager;
+    // PMANAGER_HANDLE hManager;
     PSERVICE lpService;
     DWORD dwLength;
     DWORD dwError;
@@ -3313,44 +3384,36 @@ RGetServiceKeyNameW(
     DPRINT("lpServiceName: %p\n", lpServiceName);
     DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
 
-//    hManager = (PMANAGER_HANDLE)hSCManager;
-//    if (hManager->Handle.Tag != MANAGER_TAG)
-//    {
-//        DPRINT("Invalid manager handle!\n");
-//        return ERROR_INVALID_HANDLE;
-//    }
+#if 0
+    hManager = (PMANAGER_HANDLE)hSCManager;
+    if (hManager->Handle.Tag != MANAGER_TAG)
+    {
+        DPRINT("Invalid manager handle!\n");
+        return ERROR_INVALID_HANDLE;
+    }
+#endif
 
     /* Get service database entry */
     lpService = ScmGetServiceEntryByDisplayName(lpDisplayName);
     if (lpService == NULL)
     {
-        DPRINT("Could not find a service!\n");
-
-        /* If the service could not be found and lpcchBuffer is less than 2, windows
-           puts null in lpDisplayName and puts 2 in lpcchBuffer */
-        if (*lpcchBuffer < 2)
-        {
-            *lpcchBuffer = 2;
-            if (lpServiceName != NULL)
-            {
-                *lpServiceName = 0;
-            }
-        }
-
+        DPRINT("Could not find the service!\n");
         return ERROR_SERVICE_DOES_NOT_EXIST;
     }
 
     dwLength = (DWORD)wcslen(lpService->lpServiceName);
 
-    if (lpServiceName != NULL &&
-        *lpcchBuffer > dwLength)
+    if (*lpcchBuffer > dwLength)
     {
-        wcscpy(lpServiceName, lpService->lpServiceName);
-        *lpcchBuffer = dwLength;
-        return ERROR_SUCCESS;
-    }
+        if (lpServiceName != NULL)
+            wcscpy(lpServiceName, lpService->lpServiceName);
 
-    dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
+        dwError = ERROR_SUCCESS;
+    }
+    else
+    {
+        dwError = ERROR_INSUFFICIENT_BUFFER;
+    }
 
     *lpcchBuffer = dwLength;
 
@@ -3401,310 +3464,113 @@ RChangeServiceConfigA(
     LPSTR lpDisplayName)
 {
     DWORD dwError = ERROR_SUCCESS;
-    PSERVICE_HANDLE hSvc;
-    PSERVICE lpService = NULL;
-    HKEY hServiceKey = NULL;
-    LPWSTR lpDisplayNameW = NULL;
     LPWSTR lpBinaryPathNameW = NULL;
-    LPWSTR lpCanonicalImagePathW = NULL;
     LPWSTR lpLoadOrderGroupW = NULL;
     LPWSTR lpDependenciesW = NULL;
+    LPWSTR lpServiceStartNameW = NULL;
+    LPWSTR lpDisplayNameW = NULL;
+    DWORD dwDependenciesLength = 0;
+    SIZE_T cchLength;
+    int len;
+    LPCSTR lpStr;
 
-    DPRINT("RChangeServiceConfigA() called\n");
-    DPRINT("dwServiceType = %lu\n", dwServiceType);
-    DPRINT("dwStartType = %lu\n", dwStartType);
-    DPRINT("dwErrorControl = %lu\n", dwErrorControl);
-    DPRINT("lpBinaryPathName = %s\n", lpBinaryPathName);
-    DPRINT("lpLoadOrderGroup = %s\n", lpLoadOrderGroup);
-    DPRINT("lpDisplayName = %s\n", lpDisplayName);
-
-    if (ScmShutdown)
-        return ERROR_SHUTDOWN_IN_PROGRESS;
-
-    hSvc = ScmGetServiceFromHandle(hService);
-    if (hSvc == NULL)
-    {
-        DPRINT1("Invalid service handle!\n");
-        return ERROR_INVALID_HANDLE;
-    }
-
-    if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
-                                  SERVICE_CHANGE_CONFIG))
-    {
-        DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
-        return ERROR_ACCESS_DENIED;
-    }
-
-    lpService = hSvc->ServiceEntry;
-    if (lpService == NULL)
-    {
-        DPRINT("lpService == NULL!\n");
-        return ERROR_INVALID_HANDLE;
-    }
-
-    /* Lock the service database exclusively */
-    ScmLockDatabaseExclusive();
-
-    if (lpService->bDeleted)
-    {
-        DPRINT("The service has already been marked for delete!\n");
-        dwError = ERROR_SERVICE_MARKED_FOR_DELETE;
-        goto done;
-    }
-
-    /* Open the service key */
-    dwError = ScmOpenServiceKey(lpService->szServiceName,
-                                KEY_SET_VALUE,
-                                &hServiceKey);
-    if (dwError != ERROR_SUCCESS)
-        goto done;
-
-    /* Write service data to the registry */
-
-    if (lpDisplayName != NULL && *lpDisplayName != 0)
+    if (lpBinaryPathName)
     {
-        /* Set the display name */
-        lpDisplayNameW = HeapAlloc(GetProcessHeap(),
-                                   HEAP_ZERO_MEMORY,
-                                   (strlen(lpDisplayName) + 1) * sizeof(WCHAR));
-        if (lpDisplayNameW == NULL)
+        len = MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, NULL, 0);
+        lpBinaryPathNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
+        if (!lpBinaryPathNameW)
         {
-            dwError = ERROR_NOT_ENOUGH_MEMORY;
-            goto done;
+            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+            goto cleanup;
         }
-
-        MultiByteToWideChar(CP_ACP,
-                            0,
-                            lpDisplayName,
-                            -1,
-                            lpDisplayNameW,
-                            (int)(strlen(lpDisplayName) + 1));
-
-        RegSetValueExW(hServiceKey,
-                       L"DisplayName",
-                       0,
-                       REG_SZ,
-                       (LPBYTE)lpDisplayNameW,
-                       (DWORD)((wcslen(lpDisplayNameW) + 1) * sizeof(WCHAR)));
-
-        /* Update lpService->lpDisplayName */
-        if (lpService->lpDisplayName)
-            HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
-
-        lpService->lpDisplayName = lpDisplayNameW;
-    }
-
-    if (dwServiceType != SERVICE_NO_CHANGE)
-    {
-        /* Set the service type */
-        dwError = RegSetValueExW(hServiceKey,
-                                 L"Type",
-                                 0,
-                                 REG_DWORD,
-                                 (LPBYTE)&dwServiceType,
-                                 sizeof(DWORD));
-        if (dwError != ERROR_SUCCESS)
-            goto done;
-
-        lpService->Status.dwServiceType = dwServiceType;
-    }
-
-    if (dwStartType != SERVICE_NO_CHANGE)
-    {
-        /* Set the start value */
-        dwError = RegSetValueExW(hServiceKey,
-                                 L"Start",
-                                 0,
-                                 REG_DWORD,
-                                 (LPBYTE)&dwStartType,
-                                 sizeof(DWORD));
-        if (dwError != ERROR_SUCCESS)
-            goto done;
-
-        lpService->dwStartType = dwStartType;
-    }
-
-    if (dwErrorControl != SERVICE_NO_CHANGE)
-    {
-        /* Set the error control value */
-        dwError = RegSetValueExW(hServiceKey,
-                                 L"ErrorControl",
-                                 0,
-                                 REG_DWORD,
-                                 (LPBYTE)&dwErrorControl,
-                                 sizeof(DWORD));
-        if (dwError != ERROR_SUCCESS)
-            goto done;
-
-        lpService->dwErrorControl = dwErrorControl;
+        MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, lpBinaryPathNameW, len);
     }
 
-    if (lpBinaryPathName != NULL && *lpBinaryPathName != 0)
+    if (lpLoadOrderGroup)
     {
-        /* Set the image path */
-        lpBinaryPathNameW = HeapAlloc(GetProcessHeap(),
-                                      HEAP_ZERO_MEMORY,
-                                      (strlen(lpBinaryPathName) + 1) * sizeof(WCHAR));
-        if (lpBinaryPathNameW == NULL)
-        {
-            dwError = ERROR_NOT_ENOUGH_MEMORY;
-            goto done;
-        }
-
-        MultiByteToWideChar(CP_ACP,
-                            0,
-                            lpBinaryPathName,
-                            -1,
-                            lpBinaryPathNameW,
-                            (int)(strlen(lpBinaryPathName) + 1));
-
-        if (lpService->Status.dwServiceType & SERVICE_DRIVER)
+        len = MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, NULL, 0);
+        lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
+        if (!lpLoadOrderGroupW)
         {
-            dwError = ScmCanonDriverImagePath(lpService->dwStartType,
-                                              lpBinaryPathNameW,
-                                              &lpCanonicalImagePathW);
-
-            HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW);
-
-            if (dwError != ERROR_SUCCESS)
-                goto done;
-
-            lpBinaryPathNameW = lpCanonicalImagePathW;
+            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+            goto cleanup;
         }
-
-        dwError = RegSetValueExW(hServiceKey,
-                                 L"ImagePath",
-                                 0,
-                                 REG_EXPAND_SZ,
-                                 (LPBYTE)lpBinaryPathNameW,
-                                 (DWORD)((wcslen(lpBinaryPathNameW) + 1) * sizeof(WCHAR)));
-
-        HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW);
-
-        if (dwError != ERROR_SUCCESS)
-            goto done;
+        MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, lpLoadOrderGroupW, len);
     }
 
-    /* Set the group name */
-    if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
+    if (lpDependencies)
     {
-        lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(),
-                                      HEAP_ZERO_MEMORY,
-                                      (strlen(lpLoadOrderGroup) + 1) * sizeof(WCHAR));
-        if (lpLoadOrderGroupW == NULL)
+        lpStr = (LPCSTR)lpDependencies;
+        while (*lpStr)
         {
-            dwError = ERROR_NOT_ENOUGH_MEMORY;
-            goto done;
+            cchLength = strlen(lpStr) + 1;
+            dwDependenciesLength += (DWORD)cchLength;
+            lpStr = lpStr + cchLength;
         }
+        dwDependenciesLength++;
 
-        MultiByteToWideChar(CP_ACP,
-                            0,
-                            lpLoadOrderGroup,
-                            -1,
-                            lpLoadOrderGroupW,
-                            (int)(strlen(lpLoadOrderGroup) + 1));
-
-        dwError = RegSetValueExW(hServiceKey,
-                                 L"Group",
-                                 0,
-                                 REG_SZ,
-                                 (LPBYTE)lpLoadOrderGroupW,
-                                 (DWORD)((wcslen(lpLoadOrderGroupW) + 1) * sizeof(WCHAR)));
-        if (dwError != ERROR_SUCCESS)
+        lpDependenciesW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwDependenciesLength * sizeof(WCHAR));
+        if (!lpDependenciesW)
         {
-            HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
-            goto done;
+            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+            goto cleanup;
         }
-
-        dwError = ScmSetServiceGroup(lpService,
-                                     lpLoadOrderGroupW);
-
-        HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
-
-        if (dwError != ERROR_SUCCESS)
-            goto done;
+        MultiByteToWideChar(CP_ACP, 0, (LPCSTR)lpDependencies, dwDependenciesLength, lpDependenciesW, dwDependenciesLength);
     }
 
-    if (lpdwTagId != NULL)
+    if (lpServiceStartName)
     {
-        dwError = ScmAssignNewTag(lpService);
-        if (dwError != ERROR_SUCCESS)
-            goto done;
-
-        dwError = RegSetValueExW(hServiceKey,
-                                 L"Tag",
-                                 0,
-                                 REG_DWORD,
-                                 (LPBYTE)&lpService->dwTag,
-                                 sizeof(DWORD));
-        if (dwError != ERROR_SUCCESS)
-            goto done;
-
-        *lpdwTagId = lpService->dwTag;
+        len = MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, NULL, 0);
+        lpServiceStartNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
+        if (!lpServiceStartNameW)
+        {
+            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+            goto cleanup;
+        }
+        MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, lpServiceStartNameW, len);
     }
 
-    /* Write dependencies */
-    if (lpDependencies != NULL && *lpDependencies != 0)
+    if (lpDisplayName)
     {
-        lpDependenciesW = HeapAlloc(GetProcessHeap(),
-                                    HEAP_ZERO_MEMORY,
-                                    (strlen((LPSTR)lpDependencies) + 1) * sizeof(WCHAR));
-        if (lpDependenciesW == NULL)
+        len = MultiByteToWideChar(CP_ACP, 0, lpDisplayName, -1, NULL, 0);
+        lpDisplayNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
+        if (!lpDisplayNameW)
         {
-            dwError = ERROR_NOT_ENOUGH_MEMORY;
-            goto done;
+            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+            goto cleanup;
         }
-
-        MultiByteToWideChar(CP_ACP,
-                            0,
-                            (LPSTR)lpDependencies,
-                            dwDependSize,
-                            lpDependenciesW,
-                            (int)(strlen((LPSTR)lpDependencies) + 1));
-
-        dwError = ScmWriteDependencies(hServiceKey,
-                                       (LPWSTR)lpDependenciesW,
-                                       dwDependSize);
-
-        HeapFree(GetProcessHeap(), 0, lpDependenciesW);
-
-        if (dwError != ERROR_SUCCESS)
-            goto done;
+        MultiByteToWideChar(CP_ACP, 0, lpDisplayName, -1, lpDisplayNameW, len);
     }
 
-    if (lpPassword != NULL)
-    {
-        if (wcslen((LPWSTR)lpPassword) != 0)
-        {
-            /* FIXME: Decrypt the password */
+    dwError = RChangeServiceConfigW(hService,
+                                    dwServiceType,
+                                    dwStartType,
+                                    dwErrorControl,
+                                    lpBinaryPathNameW,
+                                    lpLoadOrderGroupW,
+                                    lpdwTagId,
+                                    (LPBYTE)lpDependenciesW,
+                                    dwDependenciesLength,
+                                    lpServiceStartNameW,
+                                    lpPassword,
+                                    dwPwSize,
+                                    lpDisplayNameW);
 
-            /* Write the password */
-            dwError = ScmSetServicePassword(lpService->szServiceName,
-                                            (LPCWSTR)lpPassword);
-            if (dwError != ERROR_SUCCESS)
-                goto done;
-        }
-        else
-        {
-            /* Delete the password */
-            dwError = ScmSetServicePassword(lpService->szServiceName,
-                                            NULL);
-            if (dwError == ERROR_FILE_NOT_FOUND)
-                dwError = ERROR_SUCCESS;
+cleanup:
+    if (lpBinaryPathNameW != NULL)
+        HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW);
 
-            if (dwError != ERROR_SUCCESS)
-                goto done;
-        }
-    }
+    if (lpLoadOrderGroupW != NULL)
+        HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
 
-done:
-    /* Unlock the service database */
-    ScmUnlockDatabase();
+    if (lpDependenciesW != NULL)
+        HeapFree(GetProcessHeap(), 0, lpDependenciesW);
 
-    if (hServiceKey != NULL)
-        RegCloseKey(hServiceKey);
+    if (lpServiceStartNameW != NULL)
+        HeapFree(GetProcessHeap(), 0, lpServiceStartNameW);
 
-    DPRINT("RChangeServiceConfigA() done (Error %lu)\n", dwError);
+    if (lpDisplayNameW != NULL)
+        HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
 
     return dwError;
 }
@@ -4211,7 +4077,6 @@ RQueryServiceConfigA(
     LPWSTR lpDependencies = NULL;
     DWORD dwDependenciesLength = 0;
     DWORD dwRequiredSize;
-    CHAR lpEmptyString[]={0,0};
     LPSTR lpStr;
 
     DPRINT("RQueryServiceConfigA() called\n");
@@ -4271,28 +4136,28 @@ RQueryServiceConfigA(
     if (lpImagePath != NULL)
         dwRequiredSize += (DWORD)(wcslen(lpImagePath) + 1);
     else
-        dwRequiredSize += 2;
+        dwRequiredSize += 2 * sizeof(CHAR);
 
     if ((lpService->lpGroup != NULL) && (lpService->lpGroup->lpGroupName != NULL))
         dwRequiredSize += (DWORD)(wcslen(lpService->lpGroup->lpGroupName) + 1);
     else
-        dwRequiredSize += 2;
+        dwRequiredSize += 2 * sizeof(CHAR);
 
     /* Add Dependencies length */
     if (lpDependencies != NULL)
         dwRequiredSize += dwDependenciesLength;
     else
-        dwRequiredSize += 2;
+        dwRequiredSize += 2 * sizeof(CHAR);
 
     if (lpServiceStartName != NULL)
         dwRequiredSize += (DWORD)(wcslen(lpServiceStartName) + 1);
     else
-        dwRequiredSize += 2;
+        dwRequiredSize += 2 * sizeof(CHAR);
 
     if (lpService->lpDisplayName != NULL)
         dwRequiredSize += (DWORD)(wcslen(lpService->lpDisplayName) + 1);
     else
-        dwRequiredSize += 2;
+        dwRequiredSize += 2 * sizeof(CHAR);
 
     if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize)
     {
@@ -4323,7 +4188,7 @@ RQueryServiceConfigA(
         }
         else
         {
-            strcpy(lpStr, lpEmptyString);
+            *lpStr = 0;
         }
 
         lpServiceConfig->lpBinaryPathName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
@@ -4342,7 +4207,7 @@ RQueryServiceConfigA(
         }
         else
         {
-            strcpy(lpStr, lpEmptyString);
+            *lpStr = 0;
         }
 
         lpServiceConfig->lpLoadOrderGroup = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
@@ -4362,7 +4227,7 @@ RQueryServiceConfigA(
         }
         else
         {
-            strcpy(lpStr, lpEmptyString);
+            *lpStr = 0;
         }
 
         lpServiceConfig->lpDependencies = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
@@ -4384,7 +4249,7 @@ RQueryServiceConfigA(
         }
         else
         {
-            strcpy(lpStr, lpEmptyString);
+            *lpStr = 0;
         }
 
         lpServiceConfig->lpServiceStartName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
@@ -4403,7 +4268,7 @@ RQueryServiceConfigA(
         }
         else
         {
-            strcpy(lpStr, lpEmptyString);
+            *lpStr = 0;
         }
 
         lpServiceConfig->lpDisplayName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
@@ -4588,11 +4453,11 @@ RGetServiceDisplayNameA(
     LPSTR lpDisplayName,
     LPBOUNDED_DWORD_4K lpcchBuffer)
 {
-//    PMANAGER_HANDLE hManager;
+    // PMANAGER_HANDLE hManager;
     PSERVICE lpService = NULL;
-    DWORD dwLength;
-    DWORD dwError;
+    LPCWSTR lpSvcDisplayName;
     LPWSTR lpServiceNameW;
+    DWORD dwLength;
 
     DPRINT("RGetServiceDisplayNameA() called\n");
     DPRINT("hSCManager = %p\n", hSCManager);
@@ -4600,13 +4465,16 @@ RGetServiceDisplayNameA(
     DPRINT("lpDisplayName: %p\n", lpDisplayName);
     DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
 
-//    hManager = (PMANAGER_HANDLE)hSCManager;
-//    if (hManager->Handle.Tag != MANAGER_TAG)
-//    {
-//        DPRINT("Invalid manager handle!\n");
-//        return ERROR_INVALID_HANDLE;
-//    }
+#if 0
+    hManager = (PMANAGER_HANDLE)hSCManager;
+    if (hManager->Handle.Tag != MANAGER_TAG)
+    {
+        DPRINT("Invalid manager handle!\n");
+        return ERROR_INVALID_HANDLE;
+    }
+#endif
 
+    /* Get service database entry */
     if (lpServiceName != NULL)
     {
         dwLength = (DWORD)(strlen(lpServiceName) + 1);
@@ -4630,61 +4498,71 @@ RGetServiceDisplayNameA(
 
     if (lpService == NULL)
     {
-        DPRINT("Could not find a service!\n");
-
-        /* If the service could not be found and lpcchBuffer is 0, windows
-           puts null in lpDisplayName and puts 1 in lpcchBuffer */
-        if (*lpcchBuffer == 0)
-        {
-            *lpcchBuffer = 1;
-            if (lpDisplayName != NULL)
-            {
-                *lpDisplayName = 0;
-            }
-        }
+        DPRINT("Could not find the service!\n");
         return ERROR_SERVICE_DOES_NOT_EXIST;
     }
 
-    if (!lpService->lpDisplayName)
+    if (lpService->lpDisplayName)
+        lpSvcDisplayName = lpService->lpDisplayName;
+    else
+        lpSvcDisplayName = lpService->lpServiceName;
+
+    /*
+     * NOTE: On Windows the comparison on *lpcchBuffer is made against
+     * the number of (wide) characters of the UNICODE display name, and
+     * not against the number of bytes needed to store the ANSI string.
+     */
+    dwLength = (DWORD)wcslen(lpSvcDisplayName);
+
+    if (*lpcchBuffer > dwLength)
     {
-        dwLength = (DWORD)wcslen(lpService->lpServiceName);
         if (lpDisplayName != NULL &&
-            *lpcchBuffer > dwLength)
-        {
             WideCharToMultiByte(CP_ACP,
                                 0,
-                                lpService->lpServiceName,
-                                (int)wcslen(lpService->lpServiceName),
+                                lpSvcDisplayName,
+                                -1,
                                 lpDisplayName,
-                                dwLength + 1,
+                                (int)*lpcchBuffer,
                                 NULL,
-                                NULL);
-            return ERROR_SUCCESS;
+                                NULL) == 0)
+        {
+            /*
+             * But then, if *lpcchBuffer was greater than the number of
+             * (wide) characters of the UNICODE display name, yet smaller
+             * than the number of bytes needed due to the possible presence
+             * of DBCS characters, the *exact* number of bytes is returned
+             * (without the NULL terminator).
+             */
+            dwLength = (DWORD)WideCharToMultiByte(CP_ACP,
+                                                  0,
+                                                  lpSvcDisplayName,
+                                                  (int)dwLength,
+                                                  NULL,
+                                                  0,
+                                                  NULL,
+                                                  NULL);
+            *lpDisplayName = 0;
+            *lpcchBuffer = dwLength;
+            return ERROR_INSUFFICIENT_BUFFER;
         }
+
+        /*
+         * NOTE: On Windows, RGetServiceDisplayNameA() does not update
+         * *lpcchBuffer on success, contrary to RGetServiceDisplayNameW().
+         */
+        return ERROR_SUCCESS;
     }
     else
     {
-        dwLength = (DWORD)wcslen(lpService->lpDisplayName);
-        if (lpDisplayName != NULL &&
-            *lpcchBuffer > dwLength)
-        {
-            WideCharToMultiByte(CP_ACP,
-                                0,
-                                lpService->lpDisplayName,
-                                (int)wcslen(lpService->lpDisplayName),
-                                lpDisplayName,
-                                dwLength + 1,
-                                NULL,
-                                NULL);
-            return ERROR_SUCCESS;
-        }
+        /*
+         * NOTE: On Windows, if *lpcchBuffer is smaller than the number of
+         * (wide) characters of the UNICODE display name, only an upper
+         * estimation is returned by doubling the string length, to account
+         * for the presence of any possible DBCS characters.
+         */
+        *lpcchBuffer = dwLength * sizeof(WCHAR);
+        return ERROR_INSUFFICIENT_BUFFER;
     }
-
-    dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
-
-    *lpcchBuffer = dwLength * 2;
-
-    return dwError;
 }
 
 
@@ -4697,10 +4575,10 @@ RGetServiceKeyNameA(
     LPSTR lpServiceName,
     LPBOUNDED_DWORD_4K lpcchBuffer)
 {
+    // PMANAGER_HANDLE hManager;
     PSERVICE lpService;
-    DWORD dwLength;
-    DWORD dwError;
     LPWSTR lpDisplayNameW;
+    DWORD dwLength;
 
     DPRINT("RGetServiceKeyNameA() called\n");
     DPRINT("hSCManager = %p\n", hSCManager);
@@ -4708,6 +4586,17 @@ RGetServiceKeyNameA(
     DPRINT("lpServiceName: %p\n", lpServiceName);
     DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
 
+#if 0
+    hManager = (PMANAGER_HANDLE)hSCManager;
+    if (hManager->Handle.Tag != MANAGER_TAG)
+    {
+        DPRINT("Invalid manager handle!\n");
+        return ERROR_INVALID_HANDLE;
+    }
+#endif
+
+    /* Get service database entry */
+
     dwLength = (DWORD)(strlen(lpDisplayName) + 1);
     lpDisplayNameW = HeapAlloc(GetProcessHeap(),
                                HEAP_ZERO_MEMORY,
@@ -4729,41 +4618,65 @@ RGetServiceKeyNameA(
     if (lpService == NULL)
     {
         DPRINT("Could not find the service!\n");
-
-        /* If the service could not be found and lpcchBuffer is 0,
-           put null in lpDisplayName and puts 1 in lpcchBuffer, verified WINXP. */
-        if (*lpcchBuffer == 0)
-        {
-            *lpcchBuffer = 1;
-            if (lpServiceName != NULL)
-            {
-                *lpServiceName = 0;
-            }
-        }
-
         return ERROR_SERVICE_DOES_NOT_EXIST;
     }
 
+    /*
+     * NOTE: On Windows the comparison on *lpcchBuffer is made against
+     * the number of (wide) characters of the UNICODE service name, and
+     * not against the number of bytes needed to store the ANSI string.
+     */
     dwLength = (DWORD)wcslen(lpService->lpServiceName);
-    if (lpServiceName != NULL &&
-        *lpcchBuffer > dwLength)
+
+    if (*lpcchBuffer > dwLength)
     {
-        WideCharToMultiByte(CP_ACP,
-                            0,
-                            lpService->lpServiceName,
-                            (int)wcslen(lpService->lpServiceName),
-                            lpServiceName,
-                            dwLength + 1,
-                            NULL,
-                            NULL);
+        if (lpServiceName != NULL &&
+            WideCharToMultiByte(CP_ACP,
+                                0,
+                                lpService->lpServiceName,
+                                -1,
+                                lpServiceName,
+                                (int)*lpcchBuffer,
+                                NULL,
+                                NULL) == 0)
+        {
+            /*
+             * But then, if *lpcchBuffer was greater than the number of
+             * (wide) characters of the UNICODE service name, yet smaller
+             * than the number of bytes needed due to the possible presence
+             * of DBCS characters, the *exact* number of bytes is returned
+             * (without the NULL terminator).
+             */
+            dwLength = (DWORD)WideCharToMultiByte(CP_ACP,
+                                                  0,
+                                                  lpService->lpServiceName,
+                                                  (int)dwLength,
+                                                  NULL,
+                                                  0,
+                                                  NULL,
+                                                  NULL);
+            *lpServiceName = 0;
+            *lpcchBuffer = dwLength;
+            return ERROR_INSUFFICIENT_BUFFER;
+        }
+
+        /*
+         * NOTE: On Windows, RGetServiceKeyNameA() does not update
+         * *lpcchBuffer on success, contrary to RGetServiceKeyNameW().
+         */
         return ERROR_SUCCESS;
     }
-
-    dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
-
-    *lpcchBuffer = dwLength * 2;
-
-    return dwError;
+    else
+    {
+        /*
+         * NOTE: On Windows, if *lpcchBuffer is smaller than the number of
+         * (wide) characters of the UNICODE service name, only an upper
+         * estimation is returned by doubling the string length, to account
+         * for the presence of any possible DBCS characters.
+         */
+        *lpcchBuffer = dwLength * sizeof(WCHAR);
+        return ERROR_INSUFFICIENT_BUFFER;
+    }
 }
 
 
@@ -5097,7 +5010,7 @@ RChangeServiceConfig2A(
     SC_RPC_HANDLE hService,
     SC_RPC_CONFIG_INFOA Info)
 {
-    SC_RPC_CONFIG_INFOW InfoW;
+    SC_RPC_CONFIG_INFOW InfoW = { 0 };
     DWORD dwRet, dwLength;
     PVOID ptr = NULL;
 
@@ -5106,7 +5019,9 @@ RChangeServiceConfig2A(
 
     if ((Info.dwInfoLevel < SERVICE_CONFIG_DESCRIPTION) ||
         (Info.dwInfoLevel > SERVICE_CONFIG_FAILURE_ACTIONS))
+    {
         return ERROR_INVALID_LEVEL;
+    }
 
     InfoW.dwInfoLevel = Info.dwInfoLevel;
 
@@ -5291,11 +5206,13 @@ ScmSetFailureActions(HKEY hServiceKey,
                                NULL,
                                &dwType,
                                NULL,
-                              &dwRequiredSize);
+                               &dwRequiredSize);
     if (dwError != ERROR_SUCCESS &&
         dwError != ERROR_MORE_DATA &&
         dwError != ERROR_FILE_NOT_FOUND)
+    {
         return dwError;
+    }
 
     dwRequiredSize = (dwType == REG_BINARY) ? max(sizeof(SERVICE_FAILURE_ACTIONSW), dwRequiredSize)
                                             : sizeof(SERVICE_FAILURE_ACTIONSW);
@@ -5508,7 +5425,9 @@ RChangeServiceConfig2W(
 
     if ((Info.dwInfoLevel < SERVICE_CONFIG_DESCRIPTION) ||
         (Info.dwInfoLevel > SERVICE_CONFIG_FAILURE_ACTIONS))
+    {
         return ERROR_INVALID_LEVEL;
+    }
 
     hSvc = ScmGetServiceFromHandle(hService);
     if (hSvc == NULL)
@@ -5648,7 +5567,9 @@ RQueryServiceConfig2A(
 
     if ((dwInfoLevel < SERVICE_CONFIG_DESCRIPTION) ||
         (dwInfoLevel > SERVICE_CONFIG_FAILURE_ACTIONS))
+    {
         return ERROR_INVALID_LEVEL;
+    }
 
     hSvc = ScmGetServiceFromHandle(hService);
     if (hSvc == NULL)
@@ -5736,7 +5657,9 @@ RQueryServiceConfig2A(
         if (dwError != ERROR_SUCCESS &&
             dwError != ERROR_MORE_DATA &&
             dwError != ERROR_FILE_NOT_FOUND)
+        {
             goto done;
+        }
 
         dwRequiredSize = (dwType == REG_BINARY) ? max(sizeof(SERVICE_FAILURE_ACTIONSA), dwRequiredSize)
                                                 : sizeof(SERVICE_FAILURE_ACTIONSA);
@@ -5890,7 +5813,9 @@ RQueryServiceConfig2W(
 
     if ((dwInfoLevel < SERVICE_CONFIG_DESCRIPTION) ||
         (dwInfoLevel > SERVICE_CONFIG_FAILURE_ACTIONS))
+    {
         return ERROR_INVALID_LEVEL;
+    }
 
     hSvc = ScmGetServiceFromHandle(hService);
     if (hSvc == NULL)
@@ -5970,7 +5895,9 @@ RQueryServiceConfig2W(
         if (dwError != ERROR_SUCCESS &&
             dwError != ERROR_MORE_DATA &&
             dwError != ERROR_FILE_NOT_FOUND)
+        {
             goto done;
+        }
 
         dwRequiredSize = (dwType == REG_BINARY) ? max(sizeof(SERVICE_FAILURE_ACTIONSW), dwRequiredSize)
                                                 : sizeof(SERVICE_FAILURE_ACTIONSW);
@@ -6144,7 +6071,7 @@ RQueryServiceStatusEx(
     else
         lpStatus->dwProcessId = lpService->lpImage->dwProcessId;
 
-    lpStatus->dwServiceFlags = 0;                      /* FIXME */
+    lpStatus->dwServiceFlags = 0;   /* FIXME */
 
     /* Unlock the service database */
     ScmUnlockDatabase();