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
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);
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;
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;
err = svcctl_GetServiceDisplayNameW(hscm->hdr.server_handle,
lpServiceName, lpDisplayName, lpDisplayName ? *lpcchBuffer : 0, lpcchBuffer);
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;
}
/******************************************************************************
......
......@@ -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);
}
......
......@@ -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);
}
......@@ -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;
......
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