Commit 010dcb16 authored by Mikołaj Zalewski's avatar Mikołaj Zalewski Committed by Alexandre Julliard

services: Move GetServiceDisplayName to services.exe and implement GetServiceKeyName.

parent 76d4eeeb
...@@ -2135,8 +2135,44 @@ EnumServicesStatusExW(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServ ...@@ -2135,8 +2135,44 @@ EnumServicesStatusExW(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServ
BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName, BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
LPSTR lpServiceName, LPDWORD lpcchBuffer ) LPSTR lpServiceName, LPDWORD lpcchBuffer )
{ {
FIXME("%p %s %p %p\n", hSCManager, debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer); LPWSTR lpDisplayNameW, lpServiceNameW;
return FALSE; 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, ...@@ -2145,8 +2181,31 @@ BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName, BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
LPWSTR lpServiceName, LPDWORD lpcchBuffer ) LPWSTR lpServiceName, LPDWORD lpcchBuffer )
{ {
FIXME("%p %s %p %p\n", hSCManager, debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer); 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; 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, ...@@ -2195,6 +2254,8 @@ BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
sizeW = *lpcchBuffer; sizeW = *lpcchBuffer;
if (!GetServiceDisplayNameW(hSCManager, lpServiceNameW, lpDisplayNameW, &sizeW)) 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 */ *lpcchBuffer = sizeW*2; /* we can only provide an upper estimation of string length */
goto cleanup; goto cleanup;
} }
...@@ -2202,6 +2263,8 @@ BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName, ...@@ -2202,6 +2263,8 @@ BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
if (!WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, (sizeW + 1), lpDisplayName, if (!WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, (sizeW + 1), lpDisplayName,
*lpcchBuffer, NULL, NULL )) *lpcchBuffer, NULL, NULL ))
{ {
if (*lpcchBuffer && lpDisplayName)
lpDisplayName[0] = 0;
*lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, -1, NULL, 0, NULL, NULL); *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, -1, NULL, 0, NULL, NULL);
goto cleanup; goto cleanup;
} }
...@@ -2223,8 +2286,7 @@ BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName, ...@@ -2223,8 +2286,7 @@ BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
LPWSTR lpDisplayName, LPDWORD lpcchBuffer) LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
{ {
struct sc_manager *hscm; struct sc_manager *hscm;
DWORD type, size; DWORD err;
LONG ret;
TRACE("%p %s %p %p\n", hSCManager, TRACE("%p %s %p %p\n", hSCManager,
debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer); debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
...@@ -2242,56 +2304,12 @@ BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName, ...@@ -2242,56 +2304,12 @@ BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
return FALSE; return FALSE;
} }
size = *lpcchBuffer * sizeof(WCHAR); err = svcctl_GetServiceDisplayNameW(hscm->hdr.server_handle,
ret = RegGetValueW(hscm->hkey, lpServiceName, szDisplayName, RRF_RT_REG_SZ, &type, lpDisplayName, &size); lpServiceName, lpDisplayName, lpDisplayName ? *lpcchBuffer : 0, lpcchBuffer);
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))
{
UINT len = lstrlenW(lpServiceName);
BOOL r = FALSE;
if ((*lpcchBuffer <= len) || (!lpDisplayName && *lpcchBuffer)) if (err)
SetLastError(ERROR_INSUFFICIENT_BUFFER); SetLastError(err);
else if (lpDisplayName && *lpcchBuffer) return err == ERROR_SUCCESS;
{
/* 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;
} }
/****************************************************************************** /******************************************************************************
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include "winerror.h" #include "winerror.h"
#include "winreg.h" #include "winreg.h"
#include "winsvc.h" #include "winsvc.h"
#include "winnls.h"
#include "lmcons.h" #include "lmcons.h"
#include "wine/test.h" #include "wine/test.h"
...@@ -614,45 +615,77 @@ static void test_get_servicekeyname(void) ...@@ -614,45 +615,77 @@ static void test_get_servicekeyname(void)
SC_HANDLE scm_handle, svc_handle; SC_HANDLE scm_handle, svc_handle;
CHAR servicename[4096]; CHAR servicename[4096];
CHAR displayname[4096]; CHAR displayname[4096];
WCHAR servicenameW[4096];
WCHAR displaynameW[4096];
DWORD servicesize, displaysize, tempsize; DWORD servicesize, displaysize, tempsize;
BOOL ret; BOOL ret;
static const CHAR deadbeef[] = "Deadbeef"; 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 */ /* Having NULL for the size of the buffer will crash on W2K3 */
SetLastError(0xdeadbeef); SetLastError(0xdeadbeef);
ret = GetServiceKeyNameA(NULL, NULL, NULL, &servicesize); ret = GetServiceKeyNameA(NULL, NULL, NULL, &servicesize);
ok(!ret, "Expected failure\n"); ok(!ret, "Expected failure\n");
todo_wine
ok(GetLastError() == ERROR_INVALID_HANDLE, ok(GetLastError() == ERROR_INVALID_HANDLE,
"Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
scm_handle = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT); scm_handle = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT);
servicesize = 200;
SetLastError(0xdeadbeef); SetLastError(0xdeadbeef);
ret = GetServiceKeyNameA(scm_handle, NULL, NULL, &servicesize); ret = GetServiceKeyNameA(scm_handle, NULL, NULL, &servicesize);
ok(!ret, "Expected failure\n"); ok(!ret, "Expected failure\n");
todo_wine
ok(GetLastError() == ERROR_INVALID_ADDRESS /* W2K, XP, W2K3, Vista */ || ok(GetLastError() == ERROR_INVALID_ADDRESS /* W2K, XP, W2K3, Vista */ ||
GetLastError() == ERROR_INVALID_PARAMETER /* NT4 */, GetLastError() == ERROR_INVALID_PARAMETER /* NT4 */,
"Expected ERROR_INVALID_ADDRESS or ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); "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 */ /* Valid handle and buffer but no displayname */
servicesize = 200;
SetLastError(0xdeadbeef); SetLastError(0xdeadbeef);
ret = GetServiceKeyNameA(scm_handle, NULL, servicename, &servicesize); ret = GetServiceKeyNameA(scm_handle, NULL, servicename, &servicesize);
ok(!ret, "Expected failure\n"); ok(!ret, "Expected failure\n");
todo_wine
ok(GetLastError() == ERROR_INVALID_ADDRESS /* W2K, XP, W2K3, Vista */ || ok(GetLastError() == ERROR_INVALID_ADDRESS /* W2K, XP, W2K3, Vista */ ||
GetLastError() == ERROR_INVALID_PARAMETER /* NT4 */, GetLastError() == ERROR_INVALID_PARAMETER /* NT4 */,
"Expected ERROR_INVALID_ADDRESS or ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); "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 */ /* Test for nonexistent displayname */
SetLastError(0xdeadbeef); SetLastError(0xdeadbeef);
ret = GetServiceKeyNameA(scm_handle, deadbeef, NULL, &servicesize); ret = GetServiceKeyNameA(scm_handle, deadbeef, NULL, &servicesize);
ok(!ret, "Expected failure\n"); ok(!ret, "Expected failure\n");
todo_wine
ok(GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST, ok(GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST,
"Expected ERROR_SERVICE_DOES_NOT_EXIST, got %d\n", GetLastError()); "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 */ /* Check if 'Spooler' exists */
svc_handle = OpenServiceA(scm_handle, spooler, GENERIC_READ); svc_handle = OpenServiceA(scm_handle, spooler, GENERIC_READ);
...@@ -673,7 +706,6 @@ static void test_get_servicekeyname(void) ...@@ -673,7 +706,6 @@ static void test_get_servicekeyname(void)
servicesize = 0; servicesize = 0;
ret = GetServiceKeyNameA(scm_handle, displayname, NULL, &servicesize); ret = GetServiceKeyNameA(scm_handle, displayname, NULL, &servicesize);
ok(!ret, "Expected failure\n"); ok(!ret, "Expected failure\n");
todo_wine
ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
"Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError()); "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
...@@ -682,7 +714,6 @@ static void test_get_servicekeyname(void) ...@@ -682,7 +714,6 @@ static void test_get_servicekeyname(void)
tempsize = servicesize; tempsize = servicesize;
servicesize *= 2; servicesize *= 2;
ret = GetServiceKeyNameA(scm_handle, displayname, servicename, &servicesize); ret = GetServiceKeyNameA(scm_handle, displayname, servicename, &servicesize);
todo_wine
ok(ret, "Expected success\n"); ok(ret, "Expected success\n");
ok(GetLastError() == ERROR_SUCCESS /* W2K3 */ || ok(GetLastError() == ERROR_SUCCESS /* W2K3 */ ||
GetLastError() == ERROR_IO_PENDING /* W2K */ || GetLastError() == ERROR_IO_PENDING /* W2K */ ||
...@@ -693,8 +724,35 @@ static void test_get_servicekeyname(void) ...@@ -693,8 +724,35 @@ static void test_get_servicekeyname(void)
ok(lstrlen(servicename) == tempsize/2, ok(lstrlen(servicename) == tempsize/2,
"Expected the buffer to be twice the length of the string\n") ; "Expected the buffer to be twice the length of the string\n") ;
ok(!lstrcmpi(servicename, spooler), "Expected %s, got %s\n", spooler, servicename); 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); CloseServiceHandle(scm_handle);
} }
......
...@@ -127,4 +127,19 @@ cpp_quote("#endif") ...@@ -127,4 +127,19 @@ cpp_quote("#endif")
[in] SC_RPC_HANDLE hService, [in] SC_RPC_HANDLE hService,
[out] QUERY_SERVICE_CONFIGW *config); [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);
} }
...@@ -183,6 +183,93 @@ static void SC_RPC_HANDLE_destroy(SC_RPC_HANDLE handle) ...@@ -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) static DWORD create_handle_for_service(struct service_entry *entry, DWORD dwDesiredAccess, SC_RPC_HANDLE *phService)
{ {
struct sc_service *service; struct sc_service *service;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment