[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