services: 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       |   15 +++++
 programs/services/rpc.c       |   87 ++++++++++++++++++++++++++++
 4 files changed, 239 insertions(+), 61 deletions(-)

diff --git a/dlls/advapi32/service.c b/dlls/advapi32/service.c
index 0a78f2d..009fef3 100644
--- a/dlls/advapi32/service.c
+++ b/dlls/advapi32/service.c
@@ -2134,8 +2134,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;
 }
 
 /******************************************************************************
@@ -2144,8 +2180,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.server_handle,
+            lpDisplayName, lpServiceName, lpServiceName ? *lpcchBuffer : 0, lpcchBuffer);
+
+    if (err)
+        SetLastError(err);
+    return err == ERROR_SUCCESS;
 }
 
 /******************************************************************************
@@ -2194,6 +2253,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;
     }
@@ -2201,6 +2262,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;
     }
@@ -2222,8 +2285,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);
@@ -2241,56 +2303,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;
-
-    if (ret)
-    {
-        if (lpDisplayName && *lpcchBuffer) *lpDisplayName = 0;
+    err = svcctl_GetServiceDisplayNameW(hscm->hdr.server_handle,
+            lpServiceName, lpDisplayName, lpDisplayName ? *lpcchBuffer : 0, lpcchBuffer);
 
-        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 006072b..5eaf2f4 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 9313bd7..dc23fe2 100644
--- a/include/wine/svcctl.idl
+++ b/include/wine/svcctl.idl
@@ -127,4 +127,19 @@ cpp_quote("#endif")
         [in] SC_RPC_HANDLE hService,
         [out] QUERY_SERVICE_CONFIGW *config);
 
+    /* Compatible with Windows function 0x14 */
+    DWORD svcctl_GetServiceDisplayNameW(
+        [in] SC_RPC_HANDLE hSCManager,
+        [in] LPCWSTR lpServiceName,
+        [out,size_is(cchBufSize)] WCHAR lpBuffer[],
+        [in] DWORD cchBufSize,
+        [out] DWORD *cchLength);
+
+    /* Compatible with Windows function 0x15 */
+    DWORD svcctl_GetServiceKeyNameW(
+        [in] SC_RPC_HANDLE hSCManager,
+        [in] LPCWSTR lpServiceDisplayName,
+        [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 6c374ee..8462a9a 100644
--- a/programs/services/rpc.c
+++ b/programs/services/rpc.c
@@ -183,6 +183,93 @@ static void SC_RPC_HANDLE_destroy(SC_RPC_HANDLE handle)
     }
 }
 
+DWORD svcctl_GetServiceDisplayNameW(
+    SC_RPC_HANDLE hSCManager,
+    LPCWSTR lpServiceName,
+    WCHAR *lpBuffer,
+    DWORD cchBufSize,
+    DWORD *cchLength)
+{
+    struct sc_manager *manager;
+    struct service_entry *entry;
+    DWORD err;
+
+    WINE_TRACE("(%s, %d)\n", wine_dbgstr_w(lpServiceName), cchBufSize);
+
+    if ((err = validate_scm_handle(hSCManager, 0, &manager)) != ERROR_SUCCESS)
+        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(
+    SC_RPC_HANDLE hSCManager,
+    LPCWSTR lpServiceDisplayName,
+    WCHAR *lpBuffer,
+    DWORD cchBufSize,
+    DWORD *cchLength)
+{
+    struct service_entry *entry;
+    struct sc_manager *manager;
+    DWORD err;
+
+    WINE_TRACE("(%s, %d)\n", wine_dbgstr_w(lpServiceDisplayName), cchBufSize);
+
+    if ((err = validate_scm_handle(hSCManager, 0, &manager)) != ERROR_SUCCESS)
+        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(struct service_entry *entry, DWORD dwDesiredAccess, SC_RPC_HANDLE *phService)
 {
     struct sc_service *service;
-- 
1.5.3.GIT



--------------020503070107080901050600--



More information about the wine-patches mailing list