[PATCH] services.exe/advapi32: move GetServiceDisplayName to services.exe and implement GetServiceKeyName

Mikołaj Zalewski mikolaj at zalewski.pl
Sun Mar 16 16:12:08 CDT 2008


---
 dlls/advapi32/service.c       |  128 +++++++++++++++++++++++------------------
 dlls/advapi32/tests/service.c |   70 ++++++++++++++++++++--
 include/wine/svcctl.idl       |   17 ++++++
 programs/services/rpc.c       |   89 ++++++++++++++++++++++++++++
 4 files changed, 243 insertions(+), 61 deletions(-)

diff --git a/dlls/advapi32/service.c b/dlls/advapi32/service.c
index 5fc73c9..2d31554 100644
--- a/dlls/advapi32/service.c
+++ b/dlls/advapi32/service.c
@@ -2030,8 +2030,44 @@ EnumServicesStatusExW(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServ
 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
                                 LPSTR lpServiceName, LPDWORD lpcchBuffer )
 {
-    FIXME("%p %s %p %p\n", hSCManager, debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
-    return FALSE;
+    LPWSTR lpDisplayNameW, lpServiceNameW;
+    DWORD sizeW;
+    BOOL ret = FALSE;
+
+    TRACE("%p %s %p %p\n", hSCManager,
+          debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
+
+    lpDisplayNameW = SERV_dup(lpDisplayName);
+    if (lpServiceName)
+        lpServiceNameW = HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer * sizeof(WCHAR));
+    else
+        lpServiceNameW = NULL;
+
+    sizeW = *lpcchBuffer;
+    if (!GetServiceKeyNameW(hSCManager, lpDisplayNameW, lpServiceNameW, &sizeW))
+    {
+        if (*lpcchBuffer && lpServiceName)
+            lpServiceName[0] = 0;
+        *lpcchBuffer = sizeW*2;  /* we can only provide an upper estimation of string length */
+        goto cleanup;
+    }
+
+    if (!WideCharToMultiByte(CP_ACP, 0, lpServiceNameW, (sizeW + 1), lpServiceName,
+                        *lpcchBuffer, NULL, NULL ))
+    {
+        if (*lpcchBuffer && lpServiceName)
+            lpServiceName[0] = 0;
+        *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpServiceNameW, -1, NULL, 0, NULL, NULL);
+        goto cleanup;
+    }
+
+    /* lpcchBuffer not updated - same as in GetServiceDisplayNameA */
+    ret = TRUE;
+    
+cleanup:
+    HeapFree(GetProcessHeap(), 0, lpServiceNameW);
+    HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
+    return ret;
 }
 
 /******************************************************************************
@@ -2040,8 +2076,31 @@ BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
                                 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
 {
-    FIXME("%p %s %p %p\n", hSCManager, debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
-    return FALSE;
+    struct sc_manager *hscm;
+    DWORD err;
+
+    TRACE("%p %s %p %p\n", hSCManager,
+          debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
+
+    hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
+    if (!hscm)
+    {
+        SetLastError(ERROR_INVALID_HANDLE);
+        return FALSE;
+    }
+
+    if (!lpDisplayName)
+    {
+        SetLastError(ERROR_INVALID_ADDRESS);
+        return FALSE;
+    }
+
+    err = svcctl_GetServiceKeyNameW(hscm->hdr.rpc_handle, &hscm->hdr.server_handle,
+            lpDisplayName, lpServiceName, lpServiceName ? *lpcchBuffer : 0, lpcchBuffer);
+
+    if (err)
+        SetLastError(err);
+    return err == ERROR_SUCCESS;
 }
 
 /******************************************************************************
@@ -2090,6 +2149,8 @@ BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
     sizeW = *lpcchBuffer;
     if (!GetServiceDisplayNameW(hSCManager, lpServiceNameW, lpDisplayNameW, &sizeW))
     {
+        if (*lpcchBuffer && lpDisplayName)
+            lpDisplayName[0] = 0;
         *lpcchBuffer = sizeW*2;  /* we can only provide an upper estimation of string length */
         goto cleanup;
     }
@@ -2097,6 +2158,8 @@ BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
     if (!WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, (sizeW + 1), lpDisplayName,
                         *lpcchBuffer, NULL, NULL ))
     {
+        if (*lpcchBuffer && lpDisplayName)
+            lpDisplayName[0] = 0;
         *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, -1, NULL, 0, NULL, NULL);
         goto cleanup;
     }
@@ -2118,8 +2181,7 @@ BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
   LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
 {
     struct sc_manager *hscm;
-    DWORD type, size;
-    LONG ret;
+    DWORD err;
 
     TRACE("%p %s %p %p\n", hSCManager,
           debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
@@ -2137,56 +2199,12 @@ BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
         return FALSE;
     }
 
-    size = *lpcchBuffer * sizeof(WCHAR);
-    ret = RegGetValueW(hscm->hkey, lpServiceName, szDisplayName, RRF_RT_REG_SZ, &type, lpDisplayName, &size);
-    if (!ret && !lpDisplayName && size)
-        ret = ERROR_MORE_DATA;
+    err = svcctl_GetServiceDisplayNameW(hscm->hdr.rpc_handle, &hscm->hdr.server_handle,
+            lpServiceName, lpDisplayName, lpDisplayName ? *lpcchBuffer : 0, lpcchBuffer);
 
-    if (ret)
-    {
-        if (lpDisplayName && *lpcchBuffer) *lpDisplayName = 0;
-
-        if (ret == ERROR_MORE_DATA)
-        {
-            SetLastError(ERROR_INSUFFICIENT_BUFFER);
-            *lpcchBuffer = (size / sizeof(WCHAR)) - 1;
-        }
-        else if (ret == ERROR_FILE_NOT_FOUND)
-        {
-            HKEY hkey;
-
-            if (!RegOpenKeyW(hscm->hkey, lpServiceName, &hkey))
-            {
-                UINT len = lstrlenW(lpServiceName);
-                BOOL r = FALSE;
-
-                if ((*lpcchBuffer <= len) || (!lpDisplayName && *lpcchBuffer))
-                    SetLastError(ERROR_INSUFFICIENT_BUFFER);
-                else if (lpDisplayName && *lpcchBuffer)
-                {
-                    /* No displayname, but the service exists and the buffer
-                     * is big enough. We should return the servicename.
-                     */
-                    lstrcpyW(lpDisplayName, lpServiceName);
-                    r = TRUE;
-                }
-
-                *lpcchBuffer = len;
-                RegCloseKey(hkey);
-                return r;
-            }
-            else
-                SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
-        }
-        else
-            SetLastError(ret);
-        return FALSE;
-    }
-
-    /* Always return the correct needed size on success */
-    *lpcchBuffer = (size / sizeof(WCHAR)) - 1;
-
-    return TRUE;
+    if (err)
+        SetLastError(err);
+    return err == ERROR_SUCCESS;
 }
 
 /******************************************************************************
diff --git a/dlls/advapi32/tests/service.c b/dlls/advapi32/tests/service.c
index be6bd79..77799dd 100644
--- a/dlls/advapi32/tests/service.c
+++ b/dlls/advapi32/tests/service.c
@@ -26,6 +26,7 @@
 #include "winerror.h"
 #include "winreg.h"
 #include "winsvc.h"
+#include "winnls.h"
 #include "lmcons.h"
 
 #include "wine/test.h"
@@ -614,45 +615,77 @@ static void test_get_servicekeyname(void)
     SC_HANDLE scm_handle, svc_handle;
     CHAR servicename[4096];
     CHAR displayname[4096];
+    WCHAR servicenameW[4096];
+    WCHAR displaynameW[4096];
     DWORD servicesize, displaysize, tempsize;
     BOOL ret;
     static const CHAR deadbeef[] = "Deadbeef";
+    static const WCHAR deadbeefW[] = {'D','e','a','d','b','e','e','f',0};
 
     /* Having NULL for the size of the buffer will crash on W2K3 */
 
     SetLastError(0xdeadbeef);
     ret = GetServiceKeyNameA(NULL, NULL, NULL, &servicesize);
     ok(!ret, "Expected failure\n");
-    todo_wine
     ok(GetLastError() == ERROR_INVALID_HANDLE,
        "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
 
     scm_handle = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT);
 
+    servicesize = 200;
     SetLastError(0xdeadbeef);
     ret = GetServiceKeyNameA(scm_handle, NULL, NULL, &servicesize);
     ok(!ret, "Expected failure\n");
-    todo_wine
     ok(GetLastError() == ERROR_INVALID_ADDRESS   /* W2K, XP, W2K3, Vista */ ||
        GetLastError() == ERROR_INVALID_PARAMETER /* NT4 */,
        "Expected ERROR_INVALID_ADDRESS or ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
+    todo_wine ok(servicesize == 1, "Service size expected 1, got %d\n", servicesize);
 
     /* Valid handle and buffer but no displayname */
+    servicesize = 200;
     SetLastError(0xdeadbeef);
     ret = GetServiceKeyNameA(scm_handle, NULL, servicename, &servicesize);
     ok(!ret, "Expected failure\n");
-    todo_wine
     ok(GetLastError() == ERROR_INVALID_ADDRESS   /* W2K, XP, W2K3, Vista */ ||
        GetLastError() == ERROR_INVALID_PARAMETER /* NT4 */,
        "Expected ERROR_INVALID_ADDRESS or ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
+    todo_wine ok(servicesize == 200, "Service size expected 1, got %d\n", servicesize);
 
     /* Test for nonexistent displayname */
     SetLastError(0xdeadbeef);
     ret = GetServiceKeyNameA(scm_handle, deadbeef, NULL, &servicesize);
     ok(!ret, "Expected failure\n");
-    todo_wine
     ok(GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST,
        "Expected ERROR_SERVICE_DOES_NOT_EXIST, got %d\n", GetLastError());
+    todo_wine ok(servicesize == 1, "Service size expected 1, got %d\n", servicesize);
+
+    servicesize = 15;
+    strcpy(servicename, "ABC");
+    ret = GetServiceKeyNameA(scm_handle, deadbeef, servicename, &servicesize);
+    ok(!ret, "Expected failure\n");
+    todo_wine ok(servicesize == 15, "Service size expected 15, got %d\n", servicesize);
+    ok(servicename[0] == 0, "Service name not empty\n");
+
+    servicesize = 15;
+    servicenameW[0] = 'A';
+    ret = GetServiceKeyNameW(scm_handle, deadbeefW, servicenameW, &servicesize);
+    ok(!ret, "Expected failure\n");
+    todo_wine ok(servicesize == 15, "Service size expected 15, got %d\n", servicesize);
+    ok(servicenameW[0] == 0, "Service name not empty\n");
+
+    servicesize = 0;
+    strcpy(servicename, "ABC");
+    ret = GetServiceKeyNameA(scm_handle, deadbeef, servicename, &servicesize);
+    ok(!ret, "Expected failure\n");
+    todo_wine ok(servicesize == 1, "Service size expected 1, got %d\n", servicesize);
+    ok(servicename[0] == 'A', "Service name changed\n");
+
+    servicesize = 0;
+    servicenameW[0] = 'A';
+    ret = GetServiceKeyNameW(scm_handle, deadbeefW, servicenameW, &servicesize);
+    ok(!ret, "Expected failure\n");
+    todo_wine ok(servicesize == 2, "Service size expected 2, got %d\n", servicesize);
+    ok(servicenameW[0] == 'A', "Service name changed\n");
 
     /* Check if 'Spooler' exists */
     svc_handle = OpenServiceA(scm_handle, spooler, GENERIC_READ);
@@ -673,7 +706,6 @@ static void test_get_servicekeyname(void)
     servicesize = 0;
     ret = GetServiceKeyNameA(scm_handle, displayname, NULL, &servicesize);
     ok(!ret, "Expected failure\n");
-    todo_wine
     ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
        "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
 
@@ -682,7 +714,6 @@ static void test_get_servicekeyname(void)
     tempsize = servicesize;
     servicesize *= 2;
     ret = GetServiceKeyNameA(scm_handle, displayname, servicename, &servicesize);
-    todo_wine
     ok(ret, "Expected success\n");
     ok(GetLastError() == ERROR_SUCCESS    /* W2K3 */ ||
        GetLastError() == ERROR_IO_PENDING /* W2K */ ||
@@ -693,8 +724,35 @@ static void test_get_servicekeyname(void)
         ok(lstrlen(servicename) == tempsize/2,
            "Expected the buffer to be twice the length of the string\n") ;
         ok(!lstrcmpi(servicename, spooler), "Expected %s, got %s\n", spooler, servicename);
+        ok(servicesize == (tempsize * 2),
+           "Expected servicesize not to change if buffer not insufficient\n") ;
+    }
+
+    MultiByteToWideChar(CP_ACP, 0, displayname, -1, displaynameW, sizeof(displaynameW)/2);
+    SetLastError(0xdeadbeef);
+    servicesize *= 2;
+    ret = GetServiceKeyNameW(scm_handle, displaynameW, servicenameW, &servicesize);
+    ok(ret, "Expected success\n");
+    ok(GetLastError() == ERROR_SUCCESS    /* W2K3 */ ||
+       GetLastError() == ERROR_IO_PENDING /* W2K */ ||
+       GetLastError() == 0xdeadbeef       /* NT4, XP, Vista */,
+       "Expected ERROR_SUCCESS, ERROR_IO_PENDING or 0xdeadbeef, got %d\n", GetLastError());
+    if (ret)
+    {
+        ok(lstrlen(servicename) == tempsize/2,
+           "Expected the buffer to be twice the length of the string\n") ;
+        ok(servicesize == lstrlenW(servicenameW),
+           "Expected servicesize not to change if buffer not insufficient\n") ;
     }
 
+    SetLastError(0xdeadbeef);
+    servicesize = 3;
+    ret = GetServiceKeyNameW(scm_handle, displaynameW, servicenameW, &servicesize);
+    ok(!ret, "Expected failure\n");
+    ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
+       "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
+    ok(servicenameW[0] == 0, "Buffer not empty\n");
+
     CloseServiceHandle(scm_handle);
 }
 
diff --git a/include/wine/svcctl.idl b/include/wine/svcctl.idl
index fa94315..6676035 100644
--- a/include/wine/svcctl.idl
+++ b/include/wine/svcctl.idl
@@ -144,4 +144,21 @@ cpp_quote("#endif")
         [in] POLICY_HANDLE *handle,
         [out] QUERY_SERVICE_CONFIGW *config);
 
+    /* Windows function 0x14 must be using a different prototype - not compatible */
+    DWORD svcctl_GetServiceDisplayNameW(
+        SvcCtlRpcHandle rpc_handle,
+        [in] POLICY_HANDLE *hSCManager,
+        [in] LPCWSTR lpServiceName,
+        [in,out,size_is(cchBufSize)] WCHAR lpBuffer[],
+        [in] DWORD cchBufSize,
+        [out] DWORD *cchLength);
+
+    /* Windows function 0x15 must be using a different prototype - not compatible */
+    DWORD svcctl_GetServiceKeyNameW(
+        SvcCtlRpcHandle rpc_handle,
+        [in] POLICY_HANDLE *hSCManager,
+        [in] LPCWSTR lpServiceDisplayName,
+        [in,out,size_is(cchBufSize)] WCHAR lpBuffer[],
+        [in] DWORD cchBufSize,
+        [out] DWORD *cchLength);
 }
diff --git a/programs/services/rpc.c b/programs/services/rpc.c
index b2bb1f9..6c29767 100644
--- a/programs/services/rpc.c
+++ b/programs/services/rpc.c
@@ -201,6 +201,91 @@ DWORD svcctl_OpenSCManagerW(
     return ERROR_SUCCESS;
 }
 
+DWORD svcctl_GetServiceDisplayNameW(
+    SvcCtlRpcHandle rpc_handle,
+    POLICY_HANDLE *hSCManager,
+    LPCWSTR lpServiceName,
+    WCHAR *lpBuffer,
+    DWORD cchBufSize,
+    DWORD *cchLength)
+{
+    service_entry *entry;
+    DWORD err;
+
+    WINE_TRACE("conn=%p (%s, %s, %d)\n", rpc_handle, wine_dbgstr_guid(&hSCManager->uuid), wine_dbgstr_w(lpServiceName), cchBufSize);
+    if ((err = validate_scm_handle(hSCManager, 0)) != 0)
+        return err;
+
+    lock_services();
+
+    entry = find_service(lpServiceName);
+    if (entry != NULL)
+    {
+        LPCWSTR name = get_display_name(entry);
+        *cchLength = strlenW(name);
+        if (*cchLength < cchBufSize)
+        {
+            err = ERROR_SUCCESS;
+            lstrcpyW(lpBuffer, name);
+        }
+        else
+            err = ERROR_INSUFFICIENT_BUFFER;
+    }
+    else
+    {
+        *cchLength = 1;
+        err = ERROR_SERVICE_DOES_NOT_EXIST;
+    }
+
+    if (err != ERROR_SUCCESS && cchBufSize > 0)
+        lpBuffer[0] = 0;
+    unlock_services();
+
+    return err;
+}
+
+DWORD svcctl_GetServiceKeyNameW(
+    SvcCtlRpcHandle rpc_handle,
+    POLICY_HANDLE *hSCManager,
+    LPCWSTR lpServiceDisplayName,
+    WCHAR *lpBuffer,
+    DWORD cchBufSize,
+    DWORD *cchLength)
+{
+    service_entry *entry;
+    DWORD err;
+
+    WINE_TRACE("conn=%p (%s, %s, %d)\n", rpc_handle, wine_dbgstr_guid(&hSCManager->uuid), wine_dbgstr_w(lpServiceDisplayName), cchBufSize);
+    if ((err = validate_scm_handle(hSCManager, 0)) != 0)
+        return err;
+
+    lock_services();
+
+    entry = find_service_by_displayname(lpServiceDisplayName);
+    if (entry != NULL)
+    {
+        *cchLength = strlenW(entry->name);
+        if (*cchLength < cchBufSize)
+        {
+            err = ERROR_SUCCESS;
+            lstrcpyW(lpBuffer, entry->name);
+        }
+        else
+            err = ERROR_INSUFFICIENT_BUFFER;
+    }
+    else
+    {
+        *cchLength = 1;
+        err = ERROR_SERVICE_DOES_NOT_EXIST;
+    }
+
+    if (err != ERROR_SUCCESS && cchBufSize > 0)
+        lpBuffer[0] = 0;
+    unlock_services();
+
+    return err;
+}
+
 static DWORD create_handle_for_service(service_entry *entry, DWORD dwDesiredAccess, POLICY_HANDLE *phService)
 {
     handle_data *service_data;
@@ -385,6 +470,10 @@ DWORD svcctl_QueryServiceConfigW(
     config->lpServiceStartName = strdupW(service->config.lpServiceStartName);
     config->lpDisplayName = strdupW(service->config.lpDisplayName);
     unlock_services();
+
+    WINE_TRACE("str: %s, %s, %s, %s\n", wine_dbgstr_w(config->lpBinaryPathName),
+        wine_dbgstr_w(config->lpLoadOrderGroup), wine_dbgstr_w(config->lpServiceStartName),
+        wine_dbgstr_w(config->lpDisplayName));
     return ERROR_SUCCESS;
 }
 
-- 
1.5.4


--------------090901080105030806010208--



More information about the wine-patches mailing list