wine/dlls/advapi32/tests/service.c

974 lines
42 KiB
C

/*
* Unit tests for service functions
*
* Copyright (c) 2007 Paul Vriens
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <stdarg.h>
#include <stdio.h>
#include "windef.h"
#include "winbase.h"
#include "winerror.h"
#include "winreg.h"
#include "winsvc.h"
#include "lmcons.h"
#include "wine/test.h"
static const CHAR spooler[] = "Spooler"; /* Should be available on all platforms */
static void test_open_scm(void)
{
SC_HANDLE scm_handle;
/* No access rights */
SetLastError(0xdeadbeef);
scm_handle = OpenSCManagerA(NULL, NULL, 0);
ok(scm_handle != NULL, "Expected success\n");
ok(GetLastError() == ERROR_SUCCESS /* W2K3, Vista */ ||
GetLastError() == 0xdeadbeef /* NT4, XP */ ||
GetLastError() == ERROR_IO_PENDING /* W2K */,
"Expected ERROR_SUCCESS, ERROR_IO_PENDING or 0xdeadbeef, got %d\n", GetLastError());
CloseServiceHandle(scm_handle);
/* Unknown database name */
SetLastError(0xdeadbeef);
scm_handle = OpenSCManagerA(NULL, "DoesNotExist", SC_MANAGER_CONNECT);
ok(!scm_handle, "Expected failure\n");
ok(GetLastError() == ERROR_INVALID_NAME, "Expected ERROR_INVALID_NAME, got %d\n", GetLastError());
CloseServiceHandle(scm_handle); /* Just in case */
/* MSDN says only ServiceActive is allowed, or NULL */
SetLastError(0xdeadbeef);
scm_handle = OpenSCManagerA(NULL, SERVICES_FAILED_DATABASEA, SC_MANAGER_CONNECT);
ok(!scm_handle, "Expected failure\n");
ok(GetLastError() == ERROR_DATABASE_DOES_NOT_EXIST, "Expected ERROR_DATABASE_DOES_NOT_EXIST, got %d\n", GetLastError());
CloseServiceHandle(scm_handle); /* Just in case */
/* Remote unknown host */
SetLastError(0xdeadbeef);
scm_handle = OpenSCManagerA("DOESNOTEXIST", SERVICES_ACTIVE_DATABASEA, SC_MANAGER_CONNECT);
ok(!scm_handle, "Expected failure\n");
todo_wine
ok(GetLastError() == RPC_S_SERVER_UNAVAILABLE, "Expected RPC_S_SERVER_UNAVAILABLE, got %d\n", GetLastError());
CloseServiceHandle(scm_handle); /* Just in case */
/* Proper call with an empty hostname */
SetLastError(0xdeadbeef);
scm_handle = OpenSCManagerA("", SERVICES_ACTIVE_DATABASEA, SC_MANAGER_CONNECT);
ok(scm_handle != NULL, "Expected success\n");
ok(GetLastError() == ERROR_SUCCESS /* W2K3, Vista */ ||
GetLastError() == ERROR_ENVVAR_NOT_FOUND /* NT4 */ ||
GetLastError() == 0xdeadbeef /* XP */ ||
GetLastError() == ERROR_IO_PENDING /* W2K */,
"Expected ERROR_SUCCESS, ERROR_IO_PENDING, ERROR_ENVVAR_NOT_FOUND or 0xdeadbeef, got %d\n", GetLastError());
CloseServiceHandle(scm_handle);
/* Again a correct one */
SetLastError(0xdeadbeef);
scm_handle = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT);
ok(scm_handle != NULL, "Expected success\n");
ok(GetLastError() == ERROR_SUCCESS /* W2K3, Vista */ ||
GetLastError() == 0xdeadbeef /* NT4, XP */ ||
GetLastError() == ERROR_IO_PENDING /* W2K */,
"Expected ERROR_SUCCESS, ERROR_IO_PENDING or 0xdeadbeef, got %d\n", GetLastError());
CloseServiceHandle(scm_handle);
}
static void test_open_svc(void)
{
SC_HANDLE scm_handle, svc_handle;
/* All NULL (invalid access rights) */
SetLastError(0xdeadbeef);
svc_handle = OpenServiceA(NULL, NULL, 0);
ok(!svc_handle, "Expected failure\n");
ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
/* TODO: Add some tests with invalid handles. These produce errors on Windows but crash on Wine */
/* NULL service */
scm_handle = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT);
SetLastError(0xdeadbeef);
svc_handle = OpenServiceA(scm_handle, NULL, GENERIC_READ);
ok(!svc_handle, "Expected failure\n");
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());
/* Nonexistent service */
scm_handle = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT);
SetLastError(0xdeadbeef);
svc_handle = OpenServiceA(scm_handle, "deadbeef", GENERIC_READ);
ok(!svc_handle, "Expected failure\n");
ok(GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST, "Expected ERROR_SERVICE_DOES_NOT_EXIST, got %d\n", GetLastError());
CloseServiceHandle(scm_handle);
/* Proper SCM handle but different access rights */
scm_handle = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT);
SetLastError(0xdeadbeef);
svc_handle = OpenServiceA(scm_handle, "Spooler", GENERIC_WRITE);
if (!svc_handle && (GetLastError() == ERROR_ACCESS_DENIED))
skip("Not enough rights to get a handle to the service\n");
else
{
ok(svc_handle != NULL, "Expected success\n");
ok(GetLastError() == ERROR_SUCCESS /* W2K3, Vista */ ||
GetLastError() == ERROR_IO_PENDING /* W2K */ ||
GetLastError() == 0xdeadbeef /* XP, NT4 */,
"Expected ERROR_SUCCESS or 0xdeadbeef, got %d\n", GetLastError());
CloseServiceHandle(svc_handle);
}
CloseServiceHandle(scm_handle);
}
static void test_create_delete_svc(void)
{
SC_HANDLE scm_handle, svc_handle1;
CHAR username[UNLEN + 1], domain[MAX_PATH];
DWORD user_size = UNLEN + 1;
CHAR account[UNLEN + 3];
static const CHAR servicename [] = "Winetest";
static const CHAR pathname [] = "we_dont_care.exe";
static const CHAR empty [] = "";
static const CHAR password [] = "secret";
BOOL spooler_exists = FALSE;
BOOL ret;
CHAR display[4096];
DWORD display_size = sizeof(display);
/* Get the username and turn it into an account to be used in some tests */
GetUserNameA(username, &user_size);
/* Get the domainname to cater for that situation */
if (GetEnvironmentVariableA("USERDOMAIN", domain, MAX_PATH))
sprintf(account, "%s\\%s", domain, username);
else
sprintf(account, ".\\%s", username);
/* All NULL */
SetLastError(0xdeadbeef);
svc_handle1 = CreateServiceA(NULL, NULL, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL);
ok(!svc_handle1, "Expected failure\n");
ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
scm_handle = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT);
/* Only a valid handle to the Service Control Manager */
SetLastError(0xdeadbeef);
svc_handle1 = CreateServiceA(scm_handle, NULL, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL);
ok(!svc_handle1, "Expected failure\n");
ok(GetLastError() == ERROR_INVALID_ADDRESS /* W2K, W2K3, XP, Vista */ ||
GetLastError() == ERROR_INVALID_PARAMETER /* NT4 */,
"Expected ERROR_INVALID_ADDRESS or ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
/* Now with a servicename */
SetLastError(0xdeadbeef);
svc_handle1 = CreateServiceA(scm_handle, servicename, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL);
ok(!svc_handle1, "Expected failure\n");
ok(GetLastError() == ERROR_INVALID_ADDRESS /* W2K, W2K3, XP, Vista */ ||
GetLastError() == ERROR_INVALID_PARAMETER /* NT4 */,
"Expected ERROR_INVALID_ADDRESS or ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
/* Or just a binary name */
SetLastError(0xdeadbeef);
svc_handle1 = CreateServiceA(scm_handle, NULL, NULL, 0, 0, 0, 0, pathname, NULL, NULL, NULL, NULL, NULL);
ok(!svc_handle1, "Expected failure\n");
ok(GetLastError() == ERROR_INVALID_ADDRESS /* W2K, W2K3, XP, Vista */ ||
GetLastError() == ERROR_INVALID_PARAMETER /* NT4 */,
"Expected ERROR_INVALID_ADDRESS or ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
/* Both servicename and binary name (We only have connect rights) */
SetLastError(0xdeadbeef);
svc_handle1 = CreateServiceA(scm_handle, servicename, NULL, 0, 0, 0, 0, pathname, NULL, NULL, NULL, NULL, NULL);
ok(!svc_handle1, "Expected failure\n");
ok(GetLastError() == ERROR_ACCESS_DENIED, "Expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
/* They can even be empty at this stage of parameter checking */
SetLastError(0xdeadbeef);
svc_handle1 = CreateServiceA(scm_handle, empty, NULL, 0, 0, 0, 0, pathname, NULL, NULL, NULL, NULL, NULL);
ok(!svc_handle1, "Expected failure\n");
ok(GetLastError() == ERROR_ACCESS_DENIED, "Expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
SetLastError(0xdeadbeef);
svc_handle1 = CreateServiceA(scm_handle, servicename, NULL, 0, 0, 0, 0, empty, NULL, NULL, NULL, NULL, NULL);
ok(!svc_handle1, "Expected failure\n");
ok(GetLastError() == ERROR_ACCESS_DENIED, "Expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
/* Open the Service Control Manager with minimal rights for creation
* (Verified with 'SC_MANAGER_ALL_ACCESS &~ SC_MANAGER_CREATE_SERVICE')
*/
CloseServiceHandle(scm_handle);
SetLastError(0xdeadbeef);
scm_handle = OpenSCManagerA(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
if (!scm_handle && (GetLastError() == ERROR_ACCESS_DENIED))
{
skip("Not enough rights to get a handle to the manager\n");
return;
}
/* TODO: It looks like account (ServiceStartName) and (maybe) password are checked at this place */
/* Empty strings for servicename and binary name are checked */
SetLastError(0xdeadbeef);
svc_handle1 = CreateServiceA(scm_handle, empty, NULL, 0, 0, 0, 0, pathname, NULL, NULL, NULL, NULL, NULL);
ok(!svc_handle1, "Expected failure\n");
ok(GetLastError() == ERROR_INVALID_NAME, "Expected ERROR_INVALID_NAME, got %d\n", GetLastError());
SetLastError(0xdeadbeef);
svc_handle1 = CreateServiceA(scm_handle, servicename, NULL, 0, 0, 0, 0, empty, NULL, NULL, NULL, NULL, NULL);
ok(!svc_handle1, "Expected failure\n");
ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
SetLastError(0xdeadbeef);
svc_handle1 = CreateServiceA(scm_handle, empty, NULL, 0, 0, 0, 0, empty, NULL, NULL, NULL, NULL, NULL);
ok(!svc_handle1, "Expected failure\n");
ok(GetLastError() == ERROR_INVALID_NAME, "Expected ERROR_INVALID_NAME, got %d\n", GetLastError());
/* Valid call (as we will see later) except for the empty binary name (to proof it's indeed
* an ERROR_INVALID_PARAMETER)
*/
SetLastError(0xdeadbeef);
svc_handle1 = CreateServiceA(scm_handle, servicename, NULL, 0, SERVICE_WIN32_OWN_PROCESS,
SERVICE_DISABLED, 0, empty, NULL, NULL, NULL, NULL, NULL);
ok(!svc_handle1, "Expected failure\n");
ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
/* Windows checks if the 'service type', 'access type' and the combination of them are valid, so let's test that */
/* Illegal (service-type, which is used as a mask can't have a mix. Except the one with
* SERVICE_INTERACTIVE_PROCESS which will be tested below in a valid call)
*/
SetLastError(0xdeadbeef);
svc_handle1 = CreateServiceA(scm_handle, servicename, NULL, GENERIC_ALL, SERVICE_WIN32_OWN_PROCESS | SERVICE_WIN32_SHARE_PROCESS,
SERVICE_DISABLED, 0, pathname, NULL, NULL, NULL, NULL, NULL);
ok(!svc_handle1, "Expected failure\n");
ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
/* Illegal (SERVICE_INTERACTIVE_PROCESS is only allowed with SERVICE_WIN32_OWN_PROCESS or SERVICE_WIN32_SHARE_PROCESS) */
SetLastError(0xdeadbeef);
svc_handle1 = CreateServiceA(scm_handle, servicename, NULL, GENERIC_ALL, SERVICE_FILE_SYSTEM_DRIVER | SERVICE_INTERACTIVE_PROCESS,
SERVICE_DISABLED, 0, pathname, NULL, NULL, NULL, NULL, NULL);
ok(!svc_handle1, "Expected failure\n");
ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
/* Illegal (this combination is only allowed when the LocalSystem account (ServiceStartName) is used)
* Not having a correct account would have resulted in an ERROR_INVALID_SERVICE_ACCOUNT.
*/
SetLastError(0xdeadbeef);
svc_handle1 = CreateServiceA(scm_handle, servicename, NULL, GENERIC_ALL, SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
SERVICE_DISABLED, 0, pathname, NULL, NULL, NULL, account, password);
ok(!svc_handle1, "Expected failure\n");
ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
/* Illegal (start-type is not a mask and should only be one of the possibilities)
* Remark : 'OR'-ing them could result in a valid possibility (but doesn't make sense as
* it's most likely not the wanted start-type)
*/
SetLastError(0xdeadbeef);
svc_handle1 = CreateServiceA(scm_handle, servicename, NULL, GENERIC_ALL, SERVICE_WIN32_OWN_PROCESS,
SERVICE_AUTO_START | SERVICE_DISABLED, 0, pathname, NULL, NULL, NULL, NULL, NULL);
ok(!svc_handle1, "Expected failure\n");
ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
/* Illegal (SERVICE_BOOT_START and SERVICE_SYSTEM_START are only allowed for driver services) */
SetLastError(0xdeadbeef);
svc_handle1 = CreateServiceA(scm_handle, servicename, NULL, 0, SERVICE_WIN32_OWN_PROCESS,
SERVICE_BOOT_START, 0, pathname, NULL, NULL, NULL, NULL, NULL);
ok(!svc_handle1, "Expected failure\n");
ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
/* The service already exists (check first, just in case) */
svc_handle1 = OpenServiceA(scm_handle, spooler, GENERIC_READ);
if (svc_handle1)
{
spooler_exists = TRUE;
CloseServiceHandle(svc_handle1);
SetLastError(0xdeadbeef);
svc_handle1 = CreateServiceA(scm_handle, spooler, NULL, 0, SERVICE_WIN32_OWN_PROCESS,
SERVICE_DISABLED, 0, pathname, NULL, NULL, NULL, NULL, NULL);
ok(!svc_handle1, "Expected failure\n");
ok(GetLastError() == ERROR_SERVICE_EXISTS, "Expected ERROR_SERVICE_EXISTS, got %d\n", GetLastError());
}
else
skip("Spooler service doesn't exist\n");
/* To find an existing displayname we check the 'Spooler' service. Although the registry
* doesn't show DisplayName on NT4, this call will return a displayname which is equal
* to the servicename and can't be used as well for a new displayname.
*/
if (spooler_exists)
{
ret = GetServiceDisplayNameA(scm_handle, spooler, display, &display_size);
if (!ret)
skip("Could not retrieve a displayname for the Spooler service\n");
else
{
svc_handle1 = CreateServiceA(scm_handle, servicename, display, 0, SERVICE_WIN32_OWN_PROCESS,
SERVICE_DISABLED, 0, pathname, NULL, NULL, NULL, NULL, NULL);
ok(!svc_handle1, "Expected failure\n");
ok(GetLastError() == ERROR_DUPLICATE_SERVICE_NAME,
"Expected ERROR_DUPLICATE_SERVICE_NAME, got %d\n", GetLastError());
}
}
else
skip("Could not retrieve a displayname (Spooler service doesn't exist)\n");
/* Windows doesn't care about the access rights for creation (which makes
* sense as there is no service yet) as long as there are sufficient
* rights to the manager.
*/
SetLastError(0xdeadbeef);
svc_handle1 = CreateServiceA(scm_handle, servicename, NULL, 0, SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
SERVICE_DISABLED, 0, pathname, NULL, NULL, NULL, NULL, NULL);
ok(svc_handle1 != NULL, "Could not create the service : %d\n", GetLastError());
ok(GetLastError() == ERROR_SUCCESS /* W2K3, Vista */ ||
GetLastError() == 0xdeadbeef /* NT4, XP */ ||
GetLastError() == ERROR_IO_PENDING /* W2K */,
"Expected ERROR_SUCCESS, ERROR_IO_PENDING or 0xdeadbeef, got %d\n", GetLastError());
/* DeleteService however must have proper rights */
SetLastError(0xdeadbeef);
ret = DeleteService(svc_handle1);
ok(!ret, "Expected failure\n");
ok(GetLastError() == ERROR_ACCESS_DENIED,
"Expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
/* Open the service with minimal rights for deletion.
* (Verified with 'SERVICE_ALL_ACCESS &~ DELETE')
*/
CloseServiceHandle(svc_handle1);
svc_handle1 = OpenServiceA(scm_handle, servicename, DELETE);
/* Now that we have the proper rights, we should be able to delete */
SetLastError(0xdeadbeef);
ret = DeleteService(svc_handle1);
ok(ret, "Expected success\n");
ok(GetLastError() == ERROR_SUCCESS /* W2K3 */ ||
GetLastError() == 0xdeadbeef /* NT4, XP, Vista */ ||
GetLastError() == ERROR_IO_PENDING /* W2K */,
"Expected ERROR_SUCCESS, ERROR_IO_PENDING or 0xdeadbeef, got %d\n", GetLastError());
CloseServiceHandle(svc_handle1);
CloseServiceHandle(scm_handle);
/* Wait a while. One of the following tests also does a CreateService for the
* same servicename and this would result in an ERROR_SERVICE_MARKED_FOR_DELETE
* error if we do this to quick. Vista seems more picky then the others.
*/
Sleep(1000);
/* And a final NULL check */
SetLastError(0xdeadbeef);
ret = DeleteService(NULL);
ok(!ret, "Expected failure\n");
ok(GetLastError() == ERROR_INVALID_HANDLE,
"Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
}
static void test_get_displayname(void)
{
SC_HANDLE scm_handle, svc_handle;
BOOL ret;
CHAR displayname[4096];
WCHAR displaynameW[2048];
DWORD displaysize, tempsize, tempsizeW;
static const CHAR deadbeef[] = "Deadbeef";
static const WCHAR spoolerW[] = {'S','p','o','o','l','e','r',0};
static const CHAR servicename[] = "Winetest";
static const CHAR pathname[] = "we_dont_care.exe";
/* Having NULL for the size of the buffer will crash on W2K3 */
SetLastError(0xdeadbeef);
ret = GetServiceDisplayNameA(NULL, NULL, NULL, &displaysize);
ok(!ret, "Expected failure\n");
ok(GetLastError() == ERROR_INVALID_HANDLE,
"Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
scm_handle = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT);
SetLastError(0xdeadbeef);
ret = GetServiceDisplayNameA(scm_handle, NULL, NULL, &displaysize);
ok(!ret, "Expected failure\n");
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());
SetLastError(0xdeadbeef);
displaysize = sizeof(displayname);
ret = GetServiceDisplayNameA(scm_handle, NULL, displayname, &displaysize);
ok(!ret, "Expected failure\n");
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());
/* Test for nonexistent service */
SetLastError(0xdeadbeef);
displaysize = -1;
ret = GetServiceDisplayNameA(scm_handle, deadbeef, NULL, &displaysize);
ok(!ret, "Expected failure\n");
ok(GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST,
"Expected ERROR_SERVICE_DOES_NOT_EXIST, got %d\n", GetLastError());
/* Check if 'Spooler' exists */
svc_handle = OpenServiceA(scm_handle, spooler, GENERIC_READ);
if (!svc_handle)
{
skip("Spooler service doesn't exist\n");
CloseServiceHandle(scm_handle);
return;
}
CloseServiceHandle(svc_handle);
/* Retrieve the needed size for the buffer */
SetLastError(0xdeadbeef);
displaysize = -1;
ret = GetServiceDisplayNameA(scm_handle, spooler, NULL, &displaysize);
ok(!ret, "Expected failure\n");
ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
"Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
tempsize = displaysize;
displaysize = 0;
ret = GetServiceDisplayNameA(scm_handle, spooler, NULL, &displaysize);
ok(!ret, "Expected failure\n");
ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
"Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
ok(displaysize == tempsize, "Buffer size mismatch (%d vs %d)\n", tempsize, displaysize);
/* Buffer is too small */
SetLastError(0xdeadbeef);
displaysize = (tempsize / 2);
ret = GetServiceDisplayNameA(scm_handle, spooler, displayname, &displaysize);
ok(!ret, "Expected failure\n");
ok(displaysize == tempsize, "Expected the needed buffersize\n");
ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
"Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
/* First try with a buffer that should be big enough to hold
* the ANSI string (and terminating character). This succeeds on Windows
* although when asked (see above 2 tests) it will return twice the needed size.
*/
SetLastError(0xdeadbeef);
displaysize = (tempsize / 2) + 1;
ret = GetServiceDisplayNameA(scm_handle, spooler, displayname, &displaysize);
ok(ret, "Expected success\n");
ok(displaysize == ((tempsize / 2) + 1), "Expected no change for the needed buffer size\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());
/* Now with the original returned size */
SetLastError(0xdeadbeef);
displaysize = tempsize;
ret = GetServiceDisplayNameA(scm_handle, spooler, displayname, &displaysize);
ok(ret, "Expected success\n");
ok(displaysize == tempsize, "Expected no change for the needed buffer size\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());
/* And with a bigger than needed buffer */
SetLastError(0xdeadbeef);
displaysize = tempsize * 2;
ret = GetServiceDisplayNameA(scm_handle, spooler, displayname, &displaysize);
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());
/* Test that shows that if the buffersize is enough, it's not changed */
ok(displaysize == tempsize * 2, "Expected no change for the needed buffer size\n");
ok(lstrlen(displayname) == tempsize/2,
"Expected the buffer to be twice the length of the string\n") ;
/* Do the buffer(size) tests also for GetServiceDisplayNameW */
SetLastError(0xdeadbeef);
displaysize = -1;
ret = GetServiceDisplayNameW(scm_handle, spoolerW, NULL, &displaysize);
ok(!ret, "Expected failure\n");
ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
"Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
/* Buffer is too small */
SetLastError(0xdeadbeef);
tempsizeW = displaysize;
displaysize = tempsizeW / 2;
ret = GetServiceDisplayNameW(scm_handle, spoolerW, displaynameW, &displaysize);
ok(!ret, "Expected failure\n");
ok(displaysize = tempsizeW, "Expected the needed buffersize\n");
ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
"Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
/* Now with the original returned size */
SetLastError(0xdeadbeef);
displaysize = tempsizeW;
ret = GetServiceDisplayNameW(scm_handle, spoolerW, displaynameW, &displaysize);
ok(!ret, "Expected failure\n");
ok(displaysize = tempsizeW, "Expected the needed buffersize\n");
ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
"Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
/* And with a bigger than needed buffer */
SetLastError(0xdeadbeef);
displaysize = tempsizeW + 1; /* This caters for the null terminating character */
ret = GetServiceDisplayNameW(scm_handle, spoolerW, displaynameW, &displaysize);
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());
ok(displaysize == tempsizeW, "Expected the needed buffersize\n");
ok(lstrlenW(displaynameW) == displaysize,
"Expected the buffer to be the length of the string\n") ;
ok(tempsize / 2 == tempsizeW,
"Expected the needed buffersize (in bytes) to be the same for the A and W call\n");
CloseServiceHandle(scm_handle);
/* Test for a service without a displayname (which is valid). This should return
* the servicename itself.
*/
SetLastError(0xdeadbeef);
scm_handle = OpenSCManagerA(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
if (!scm_handle && (GetLastError() == ERROR_ACCESS_DENIED))
{
skip("Not enough rights to get a handle to the manager\n");
return;
}
SetLastError(0xdeadbeef);
svc_handle = CreateServiceA(scm_handle, servicename, NULL, DELETE,
SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
SERVICE_DISABLED, 0, pathname, NULL, NULL, NULL, NULL, NULL);
ok(svc_handle != NULL, "Could not create the service : %d\n", GetLastError());
if (!svc_handle)
{
CloseServiceHandle(scm_handle);
return;
}
/* Retrieve the needed size for the buffer */
SetLastError(0xdeadbeef);
displaysize = -1;
ret = GetServiceDisplayNameA(scm_handle, servicename, NULL, &displaysize);
ok(!ret, "Expected failure\n");
ok(displaysize == lstrlen(servicename) * 2,
"Expected the displaysize to be twice the size of the servicename\n");
ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
"Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
/* Buffer is too small */
SetLastError(0xdeadbeef);
tempsize = displaysize;
displaysize = (tempsize / 2);
ret = GetServiceDisplayNameA(scm_handle, servicename, displayname, &displaysize);
ok(!ret, "Expected failure\n");
ok(displaysize == tempsize, "Expected the needed buffersize\n");
ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
"Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
/* Get the displayname */
SetLastError(0xdeadbeef);
ret = GetServiceDisplayNameA(scm_handle, servicename, displayname, &displaysize);
ok(ret, "Expected success\n");
ok(!lstrcmpi(displayname, servicename),
"Expected displayname to be %s, got %s\n", servicename, displayname);
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());
/* Delete the service */
ret = DeleteService(svc_handle);
ok(ret, "Expected success\n");
CloseServiceHandle(svc_handle);
CloseServiceHandle(scm_handle);
/* Wait a while. Just in case one of the following tests does a CreateService again */
Sleep(1000);
}
static void test_get_servicekeyname(void)
{
SC_HANDLE scm_handle, svc_handle;
CHAR servicename[4096];
CHAR displayname[4096];
DWORD servicesize, displaysize, tempsize;
BOOL ret;
static const CHAR deadbeef[] = "Deadbeef";
/* 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);
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());
/* Valid handle and buffer but no displayname */
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());
/* 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());
/* Check if 'Spooler' exists */
svc_handle = OpenServiceA(scm_handle, spooler, GENERIC_READ);
if (!svc_handle)
{
skip("Spooler service doesn't exist\n");
CloseServiceHandle(scm_handle);
return;
}
CloseServiceHandle(svc_handle);
/* Get the displayname for the 'Spooler' service */
GetServiceDisplayNameA(scm_handle, spooler, NULL, &displaysize);
GetServiceDisplayNameA(scm_handle, spooler, displayname, &displaysize);
/* Retrieve the needed size for the buffer */
SetLastError(0xdeadbeef);
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());
/* Valid call with the correct buffersize */
SetLastError(0xdeadbeef);
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 */ ||
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(!lstrcmpi(servicename, spooler), "Expected %s, got %s\n", spooler, servicename);
}
CloseServiceHandle(scm_handle);
}
static void test_close(void)
{
SC_HANDLE handle;
BOOL ret;
/* NULL handle */
SetLastError(0xdeadbeef);
ret = CloseServiceHandle(NULL);
todo_wine
{
ok(!ret, "Expected failure\n");
ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
}
/* TODO: Add some tests with invalid handles. These produce errors on Windows but crash on Wine */
/* Proper call */
handle = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT);
SetLastError(0xdeadbeef);
ret = CloseServiceHandle(handle);
ok(ret, "Expected success\n");
ok(GetLastError() == ERROR_IO_PENDING /* W2K */ ||
GetLastError() == ERROR_SUCCESS /* W2K3 */ ||
GetLastError() == 0xdeadbeef /* NT4, XP, Vista */,
"Expected ERROR_SUCCESS, ERROR_IO_PENDING or 0xdeadbeef, got %d\n", GetLastError());
}
static void test_sequence(void)
{
SC_HANDLE scm_handle, svc_handle;
BOOL ret;
QUERY_SERVICE_CONFIGA *config;
DWORD given, needed;
static const CHAR servicename [] = "Winetest";
static const CHAR displayname [] = "Winetest dummy service";
static const CHAR pathname [] = "we_dont_care.exe";
static const CHAR dependencies[] = "Master1\0Master2\0+MasterGroup1\0";
static const CHAR password [] = "";
static const CHAR empty [] = "";
static const CHAR localsystem [] = "LocalSystem";
SetLastError(0xdeadbeef);
scm_handle = OpenSCManagerA(NULL, NULL, GENERIC_ALL);
if (!scm_handle && (GetLastError() == ERROR_ACCESS_DENIED))
{
skip("Not enough rights to get a handle to the manager\n");
return;
}
else
ok(scm_handle != NULL, "Could not get a handle to the manager: %d\n", GetLastError());
if (!scm_handle) return;
/* Create a dummy service */
SetLastError(0xdeadbeef);
svc_handle = CreateServiceA(scm_handle, servicename, displayname, GENERIC_ALL,
SERVICE_INTERACTIVE_PROCESS | SERVICE_WIN32_OWN_PROCESS, SERVICE_DISABLED, SERVICE_ERROR_IGNORE,
pathname, NULL, NULL, dependencies, NULL, password);
if (!svc_handle && (GetLastError() == ERROR_SERVICE_EXISTS))
{
/* We try and open the service and do the rest of the tests. Some could
* fail if the tests were changed between these runs.
*/
trace("Deletion probably didn't work last time\n");
SetLastError(0xdeadbeef);
svc_handle = OpenServiceA(scm_handle, servicename, GENERIC_ALL);
if (!svc_handle && (GetLastError() == ERROR_ACCESS_DENIED))
{
skip("Not enough rights to open the service\n");
CloseServiceHandle(scm_handle);
return;
}
ok(svc_handle != NULL, "Could not open the service : %d\n", GetLastError());
}
else if (!svc_handle && (GetLastError() == ERROR_ACCESS_DENIED))
{
skip("Not enough rights to create the service\n");
CloseServiceHandle(scm_handle);
return;
}
else
ok(svc_handle != NULL, "Could not create the service : %d\n", GetLastError());
if (!svc_handle) return;
/* TODO:
* Before we do a QueryServiceConfig we should check the registry. This will make sure
* that the correct keys are used.
*/
/* Request the size for the buffer */
SetLastError(0xdeadbeef);
ret = QueryServiceConfigA(svc_handle, NULL, 0, &needed);
ok(!ret, "Expected failure\n");
ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
config = HeapAlloc(GetProcessHeap(), 0, needed);
given = needed;
SetLastError(0xdeadbeef);
ret = QueryServiceConfigA(svc_handle, config, given, &needed);
ok(ret, "Expected success\n");
todo_wine
{
ok(GetLastError() == ERROR_SUCCESS /* W2K3 */||
GetLastError() == 0xdeadbeef /* NT4, XP, Vista */ ||
GetLastError() == ERROR_IO_PENDING /* W2K */,
"Expected ERROR_SUCCESS, ERROR_IO_PENDING or 0xdeadbeef, got %d\n", GetLastError());
ok(given == needed, "Expected the given (%d) and needed (%d) buffersizes to be equal\n", given, needed);
}
ok(config->lpBinaryPathName && config->lpLoadOrderGroup && config->lpDependencies && config->lpServiceStartName &&
config->lpDisplayName, "Expected all string struct members to be non-NULL\n");
ok(config->dwServiceType == (SERVICE_INTERACTIVE_PROCESS | SERVICE_WIN32_OWN_PROCESS),
"Expected SERVICE_INTERACTIVE_PROCESS | SERVICE_WIN32_OWN_PROCESS, got %d\n", config->dwServiceType);
ok(config->dwStartType == SERVICE_DISABLED, "Expected SERVICE_DISABLED, got %d\n", config->dwStartType);
ok(config->dwErrorControl == SERVICE_ERROR_IGNORE, "Expected SERVICE_ERROR_IGNORE, got %d\n", config->dwErrorControl);
ok(!strcmp(config->lpBinaryPathName, pathname), "Expected '%s', got '%s'\n", pathname, config->lpBinaryPathName);
ok(!strcmp(config->lpLoadOrderGroup, empty), "Expected an empty string, got '%s'\n", config->lpLoadOrderGroup);
ok(config->dwTagId == 0, "Expected 0, got %d\n", config->dwTagId);
/* TODO: Show the double 0 terminated string */
todo_wine
{
ok(!memcmp(config->lpDependencies, dependencies, sizeof(dependencies)), "Wrong string\n");
}
ok(!strcmp(config->lpServiceStartName, localsystem), "Expected 'LocalSystem', got '%s'\n", config->lpServiceStartName);
ok(!strcmp(config->lpDisplayName, displayname), "Expected '%s', got '%s'\n", displayname, config->lpDisplayName);
SetLastError(0xdeadbeef);
ret = DeleteService(svc_handle);
ok(ret, "Expected success\n");
ok(GetLastError() == ERROR_SUCCESS /* W2K3 */||
GetLastError() == 0xdeadbeef /* NT4, XP, Vista */ ||
GetLastError() == ERROR_IO_PENDING /* W2K */,
"Expected ERROR_SUCCESS, ERROR_IO_PENDING or 0xdeadbeef, got %d\n", GetLastError());
CloseServiceHandle(svc_handle);
/* Wait a while. The following test does a CreateService again */
Sleep(1000);
CloseServiceHandle(scm_handle);
}
static void test_refcount(void)
{
SC_HANDLE scm_handle, svc_handle1, svc_handle2, svc_handle3, svc_handle4, svc_handle5;
static const CHAR servicename [] = "Winetest";
static const CHAR pathname [] = "we_dont_care.exe";
BOOL ret;
/* Get a handle to the Service Control Manager */
SetLastError(0xdeadbeef);
scm_handle = OpenSCManagerA(NULL, NULL, GENERIC_ALL);
if (!scm_handle && (GetLastError() == ERROR_ACCESS_DENIED))
{
skip("Not enough rights to get a handle to the manager\n");
return;
}
/* Create a service */
svc_handle1 = CreateServiceA(scm_handle, servicename, NULL, GENERIC_ALL,
SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
SERVICE_DISABLED, 0, pathname, NULL, NULL, NULL, NULL, NULL);
ok(svc_handle1 != NULL, "Expected success\n");
/* Get a handle to this new service */
svc_handle2 = OpenServiceA(scm_handle, servicename, GENERIC_READ);
ok(svc_handle2 != NULL, "Expected success\n");
/* Get another handle to this new service */
svc_handle3 = OpenServiceA(scm_handle, servicename, GENERIC_READ);
ok(svc_handle3 != NULL, "Expected success\n");
/* Check if we can close the handle to the Service Control Manager */
ret = CloseServiceHandle(scm_handle);
ok(ret, "Expected success\n");
/* Get a new handle to the Service Control Manager */
scm_handle = OpenSCManagerA(NULL, NULL, GENERIC_ALL);
ok(scm_handle != NULL, "Expected success\n");
/* Get a handle to this new service */
svc_handle4 = OpenServiceA(scm_handle, servicename, GENERIC_ALL);
ok(svc_handle4 != NULL, "Expected success\n");
/* Delete the service */
ret = DeleteService(svc_handle4);
ok(ret, "Expected success\n");
/* We cannot create the same service again as it's still marked as 'being deleted'.
* The reason is that we still have 4 open handles to this service even though we
* closed the handle to the Service Control Manager in between.
*/
SetLastError(0xdeadbeef);
svc_handle5 = CreateServiceA(scm_handle, servicename, NULL, GENERIC_ALL,
SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
SERVICE_DISABLED, 0, pathname, NULL, NULL, NULL, NULL, NULL);
todo_wine
{
ok(!svc_handle5, "Expected failure\n");
ok(GetLastError() == ERROR_SERVICE_MARKED_FOR_DELETE,
"Expected ERROR_SERVICE_MARKED_FOR_DELETE, got %d\n", GetLastError());
}
/* FIXME: Remove this when Wine is fixed */
if (svc_handle5)
{
DeleteService(svc_handle5);
CloseServiceHandle(svc_handle5);
}
/* Close all the handles to the service and try again */
ret = CloseServiceHandle(svc_handle4);
ok(ret, "Expected success\n");
ret = CloseServiceHandle(svc_handle3);
ok(ret, "Expected success\n");
ret = CloseServiceHandle(svc_handle2);
ok(ret, "Expected success\n");
ret = CloseServiceHandle(svc_handle1);
ok(ret, "Expected success\n");
/* Wait a while. Doing a CreateService too soon will result again
* in an ERROR_SERVICE_MARKED_FOR_DELETE error.
*/
Sleep(1000);
/* We succeed now as all handles are closed (tested this also with a long SLeep() */
svc_handle5 = CreateServiceA(scm_handle, servicename, NULL, GENERIC_ALL,
SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
SERVICE_DISABLED, 0, pathname, NULL, NULL, NULL, NULL, NULL);
ok(svc_handle5 != NULL, "Expected success\n");
/* Delete the service */
ret = DeleteService(svc_handle5);
ok(ret, "Expected success\n");
/* Wait a while. Just in case one of the following tests does a CreateService again */
Sleep(1000);
CloseServiceHandle(svc_handle5);
CloseServiceHandle(scm_handle);
}
START_TEST(service)
{
SC_HANDLE scm_handle;
/* Bail out if we are on win98 */
SetLastError(0xdeadbeef);
scm_handle = OpenSCManagerA(NULL, NULL, GENERIC_ALL);
if (!scm_handle && (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED))
{
skip("OpenSCManagerA is not implemented, we are most likely on win9x\n");
return;
}
CloseServiceHandle(scm_handle);
/* First some parameter checking */
test_open_scm();
test_open_svc();
test_create_delete_svc();
test_get_displayname();
test_get_servicekeyname();
test_close();
/* Test the creation, querying and deletion of a service */
test_sequence();
/* The main reason for this test is to check if any refcounting is used
* and what the rules are
*/
test_refcount();
}