From bfcba8a97ef617778ae1681ccfd1086a0fccc3c5 Mon Sep 17 00:00:00 2001 From: Mikolaj Zalewski Date: Tue, 25 Sep 2007 19:58:46 -0700 Subject: [PATCH] services.exe/advapi32: implement GetServiceKeyName --- dlls/advapi32/service.c | 121 ++++++++++++++++++++++------------------- dlls/advapi32/tests/service.c | 6 -- include/wine/svcctl.idl | 17 ++++++ programs/services/rpc.c | 78 ++++++++++++++++++++++++++ 4 files changed, 161 insertions(+), 61 deletions(-) diff --git a/dlls/advapi32/service.c b/dlls/advapi32/service.c index 2fac7e9..7a238d0 100644 --- a/dlls/advapi32/service.c +++ b/dlls/advapi32/service.c @@ -2084,8 +2084,41 @@ EnumServicesStatusExW(SC_HANDLE hSCManag 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)) + { + *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 )) + { + *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; + } /****************************************************************************** @@ -2094,8 +2127,31 @@ BOOL WINAPI GetServiceKeyNameA( SC_HANDL 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; } /****************************************************************************** @@ -2172,8 +2228,7 @@ BOOL WINAPI GetServiceDisplayNameW( SC_H 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); @@ -2191,56 +2246,12 @@ BOOL WINAPI GetServiceDisplayNameW( SC_H 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; - - 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)) - { - INT 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; + err = svcctl_GetServiceDisplayNameW(hscm->hdr.rpc_handle, &hscm->hdr.server_handle, + lpServiceName, lpDisplayName, lpDisplayName ? *lpcchBuffer : 0, lpcchBuffer); - 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 d98d67e..e71999f 100644 --- a/dlls/advapi32/tests/service.c +++ b/dlls/advapi32/tests/service.c @@ -623,7 +623,6 @@ static void test_get_servicekeyname(void 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()); @@ -632,7 +631,6 @@ static void test_get_servicekeyname(void 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()); @@ -641,7 +639,6 @@ static void test_get_servicekeyname(void 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()); @@ -650,7 +647,6 @@ static void test_get_servicekeyname(void 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()); @@ -673,7 +669,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 +677,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 */ || diff --git a/include/wine/svcctl.idl b/include/wine/svcctl.idl index 479eaf2..ccce9a9 100644 --- a/include/wine/svcctl.idl +++ b/include/wine/svcctl.idl @@ -142,4 +142,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 eefd849..c9644ef 100644 --- a/programs/services/rpc.c +++ b/programs/services/rpc.c @@ -201,6 +201,84 @@ 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); + lstrcpynW(lpBuffer, name, cchBufSize); + if (*cchLength < cchBufSize) + err = ERROR_SUCCESS; + else + err = ERROR_INSUFFICIENT_BUFFER; + } + else + { + *cchLength = 1; + err = ERROR_SERVICE_DOES_NOT_EXIST; + } + + 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); + WINE_FIXME("Searching %s - found %p\n", wine_dbgstr_w(lpServiceDisplayName), entry); + if (entry != NULL) + { + *cchLength = strlenW(entry->name); + lstrcpynW(lpBuffer, entry->name, cchBufSize); + if (*cchLength < cchBufSize) + err = ERROR_SUCCESS; + else + err = ERROR_INSUFFICIENT_BUFFER; + } + else + { + *cchLength = 1; + err = ERROR_SERVICE_DOES_NOT_EXIST; + } + + unlock_services(); + + return err; +} + static DWORD create_handle_for_service(service_entry *entry, DWORD dwDesiredAccess, POLICY_HANDLE *phService) { handle_data *service_data; -- 1.4.1