https://git.reactos.org/?p=reactos.git;a=commitdiff;h=bf164caae8670898de159…
commit bf164caae8670898de1594dc0e30f9c7c2c97891
Author: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
AuthorDate: Sat Sep 22 15:41:17 2018 +0200
Commit: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
CommitDate: Sun Sep 23 18:09:10 2018 +0200
[SERVICES] Simplify the implementation of RGetServiceDisplayNameA/W() and
RGetServiceKeyNameA/W().
Also comment about the observed behaviour of the returned number of
"characters"
returned by the ANSI versions of these APIs (which is tested by
advapi32_winetest:service).
[ADVAPI32:SCM] Add a comment concerning wide characters vs. bytes mismatch.
---
base/system/services/rpcserver.c | 315 +++++++++++++++++++++------------------
dll/win32/advapi32/service/scm.c | 10 ++
2 files changed, 181 insertions(+), 144 deletions(-)
diff --git a/base/system/services/rpcserver.c b/base/system/services/rpcserver.c
index 454181bb66..f21df10e57 100644
--- a/base/system/services/rpcserver.c
+++ b/base/system/services/rpcserver.c
@@ -2947,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;
}
@@ -3310,8 +3310,9 @@ RGetServiceDisplayNameW(
LPWSTR lpDisplayName,
DWORD *lpcchBuffer)
{
-// PMANAGER_HANDLE hManager;
+ // PMANAGER_HANDLE hManager;
PSERVICE lpService;
+ LPCWSTR lpSvcDisplayName;
DWORD dwLength;
DWORD dwError;
@@ -3321,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 < sizeof(WCHAR))
- {
- *lpcchBuffer = sizeof(WCHAR);
- 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;
@@ -3386,7 +3373,7 @@ RGetServiceKeyNameW(
LPWSTR lpServiceName,
DWORD *lpcchBuffer)
{
-// PMANAGER_HANDLE hManager;
+ // PMANAGER_HANDLE hManager;
PSERVICE lpService;
DWORD dwLength;
DWORD dwError;
@@ -3397,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 < sizeof(WCHAR))
- {
- *lpcchBuffer = sizeof(WCHAR);
- 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;
@@ -4474,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);
@@ -4486,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);
@@ -4516,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 = sizeof(CHAR);
- 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;
}
@@ -4583,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);
@@ -4594,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,
@@ -4615,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 = sizeof(CHAR);
- 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;
+ }
}
diff --git a/dll/win32/advapi32/service/scm.c b/dll/win32/advapi32/service/scm.c
index b28055a968..1fe96213a1 100644
--- a/dll/win32/advapi32/service/scm.c
+++ b/dll/win32/advapi32/service/scm.c
@@ -1693,6 +1693,11 @@ GetServiceDisplayNameW(SC_HANDLE hSCManager,
return FALSE;
}
+ /*
+ * NOTE: A size of 1 character would be enough, but tests show that
+ * Windows returns 2 characters instead, certainly due to a WCHAR/bytes
+ * mismatch in their code.
+ */
if (!lpDisplayName || *lpcchBuffer < sizeof(WCHAR))
{
lpNameBuffer = szEmptyName;
@@ -1810,6 +1815,11 @@ GetServiceKeyNameW(SC_HANDLE hSCManager,
return FALSE;
}
+ /*
+ * NOTE: A size of 1 character would be enough, but tests show that
+ * Windows returns 2 characters instead, certainly due to a WCHAR/bytes
+ * mismatch in their code.
+ */
if (!lpServiceName || *lpcchBuffer < sizeof(WCHAR))
{
lpNameBuffer = szEmptyName;