From 010dcb168b434661c0ad91d47743e9bddb8c07e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Zalewski?= Date: Sun, 16 Mar 2008 22:12:08 +0100 Subject: [PATCH] services: Move GetServiceDisplayName to services.exe and implement GetServiceKeyName. --- 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 ede99165d59..6ca56db13eb 100644 --- a/dlls/advapi32/service.c +++ b/dlls/advapi32/service.c @@ -2135,8 +2135,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; } /****************************************************************************** @@ -2145,8 +2181,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; } /****************************************************************************** @@ -2195,6 +2254,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; } @@ -2202,6 +2263,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; } @@ -2223,8 +2286,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); @@ -2242,56 +2304,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.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 006072be585..5eaf2f491d0 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 7b20c32a987..3c94b391b73 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 5c747692b2c..600e4509fe2 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;