813 lines
23 KiB
C
813 lines
23 KiB
C
/*++
|
|
|
|
Copyright (c) 1992 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
ConfTest.c
|
|
|
|
Abstract:
|
|
|
|
This file contains tests of the Service Controller's config APIs:
|
|
|
|
ChangeServiceConfig
|
|
CreateService
|
|
DeleteService
|
|
QueryServiceConfig
|
|
TestChangeConfig2
|
|
CompareFailureActions
|
|
TestQueryConfig2
|
|
TestConfig2APIs
|
|
|
|
Author:
|
|
|
|
John Rogers (JohnRo) 22-Apr-1992
|
|
|
|
Environment:
|
|
|
|
User Mode - Win32
|
|
|
|
Revision History:
|
|
|
|
22-Apr-1992 JohnRo
|
|
Created.
|
|
17-Oct-1996 AnirudhS
|
|
Added Config2 API tests.
|
|
|
|
--*/
|
|
|
|
|
|
//
|
|
// INCLUDES
|
|
//
|
|
|
|
// #define UNICODE
|
|
|
|
#include <windows.h>
|
|
|
|
#include <assert.h> // assert().
|
|
#include <tchar.h> // _tcscmp
|
|
#include <debugfmt.h> // FORMAT_ equates.
|
|
#include <winsvc.h>
|
|
#include <scdebug.h> // STATIC.
|
|
#include <sctest.h> // TRACE_MSG macros, UNEXPECTED_MSG(), etc.
|
|
#include <stdio.h> // printf()
|
|
|
|
|
|
#define BUF_SIZE 1024 // arbitrary
|
|
|
|
//#define NEW_SERVICE_NAME TEXT("FLARP")
|
|
#define NEW_SERVICE_NAME TEXT("Simple")
|
|
#define TEST_SERVICE_DESCR TEXT("A servile service")
|
|
|
|
#define LENGTH(array) (sizeof(array)/sizeof((array)[0]))
|
|
|
|
#define OPTIONAL_LPTSTR(optStr) \
|
|
( ( (optStr) != NULL ) ? (optStr) : TEXT("(NONE)") )
|
|
|
|
|
|
VOID
|
|
DumpServiceConfig(
|
|
IN LPQUERY_SERVICE_CONFIG Config
|
|
)
|
|
{
|
|
(VOID) printf( "Service config:\n" );
|
|
|
|
(VOID) printf( " Service type: " FORMAT_HEX_DWORD "\n",
|
|
Config->dwServiceType );
|
|
|
|
(VOID) printf( " Start type: " FORMAT_DWORD "\n",
|
|
Config->dwStartType );
|
|
|
|
(VOID) printf( " Error control: " FORMAT_DWORD "\n",
|
|
Config->dwErrorControl );
|
|
|
|
(VOID) printf( " Binary path: " FORMAT_LPTSTR "\n",
|
|
Config->lpBinaryPathName );
|
|
|
|
(VOID) printf( " Load order group: " FORMAT_LPTSTR "\n",
|
|
OPTIONAL_LPTSTR( Config->lpBinaryPathName ) );
|
|
|
|
(VOID) printf( " Dependencies: " FORMAT_LPTSTR "\n",
|
|
OPTIONAL_LPTSTR( Config->lpBinaryPathName ) );
|
|
|
|
(VOID) printf( " Service start name: " FORMAT_LPTSTR "\n",
|
|
Config->lpBinaryPathName );
|
|
|
|
} // DumpServiceConfig
|
|
|
|
|
|
SC_HANDLE
|
|
TestCreateService(
|
|
IN SC_HANDLE hScManager,
|
|
IN LPTSTR ServiceName,
|
|
IN DWORD ExpectedStatus
|
|
)
|
|
{
|
|
DWORD ApiStatus;
|
|
SC_HANDLE hService;
|
|
|
|
hService = CreateService(
|
|
hScManager, // SC manager handle
|
|
ServiceName, // service name
|
|
NULL, // display name
|
|
GENERIC_ALL, // desired access
|
|
SERVICE_WIN32_OWN_PROCESS, // service type
|
|
SERVICE_DISABLED, // start type
|
|
SERVICE_ERROR_NORMAL, // error control
|
|
TEXT("simple.exe"), // binary load path name
|
|
// TEXT("\\nt\\system32\\bogus.exe"),// binary load path name
|
|
NULL, // no load order group
|
|
NULL, // no tag
|
|
NULL, // no dependencies
|
|
NULL, // start name (domain\username)
|
|
// TEXT(".\\JohnRoDaemon"), // start name (domain\username)
|
|
NULL); // no password.
|
|
|
|
if (hService == NULL) {
|
|
ApiStatus = GetLastError();
|
|
} else {
|
|
ApiStatus = NO_ERROR;
|
|
}
|
|
|
|
TRACE_MSG2( "TestCreateService: back from CreateService, "
|
|
"API status is " FORMAT_DWORD ", expecting " FORMAT_DWORD "\n",
|
|
ApiStatus, ExpectedStatus );
|
|
|
|
assert( ApiStatus == ExpectedStatus );
|
|
return (hService);
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
TestDeleteService(
|
|
IN SC_HANDLE hScManager,
|
|
IN LPTSTR ServiceName,
|
|
IN DWORD DesiredAccess,
|
|
IN DWORD OpenExpectedStatus,
|
|
IN DWORD DeleteExpectedStatus
|
|
)
|
|
{
|
|
DWORD ApiStatus = NO_ERROR;
|
|
SC_HANDLE hService;
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
hService = OpenService(
|
|
hScManager,
|
|
ServiceName,
|
|
DesiredAccess );
|
|
if (hService == NULL) {
|
|
ApiStatus = GetLastError();
|
|
}
|
|
|
|
TRACE_MSG2( "TestDeleteService: back from OpenService, "
|
|
"API status is " FORMAT_DWORD ", expecting " FORMAT_DWORD "\n",
|
|
ApiStatus, OpenExpectedStatus );
|
|
|
|
assert( ApiStatus == OpenExpectedStatus );
|
|
|
|
if (ApiStatus != NO_ERROR) {
|
|
return;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
if ( !DeleteService( hService ) ) {
|
|
ApiStatus = GetLastError();
|
|
}
|
|
|
|
TRACE_MSG2( "TestDeleteService: back from DeleteService, "
|
|
"API status is " FORMAT_DWORD ", expecting " FORMAT_DWORD "\n",
|
|
ApiStatus, DeleteExpectedStatus );
|
|
|
|
assert( ApiStatus == DeleteExpectedStatus );
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
if ( !CloseServiceHandle( hService ) ) {
|
|
ApiStatus = GetLastError();
|
|
}
|
|
|
|
TRACE_MSG2( "TestDeleteService: back from CloseService, "
|
|
"API status is " FORMAT_DWORD ", expecting " FORMAT_DWORD "\n",
|
|
ApiStatus, NO_ERROR );
|
|
|
|
assert( ApiStatus == NO_ERROR );
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
TestQueryConfig(
|
|
IN SC_HANDLE hService,
|
|
IN DWORD ExpectedStatus
|
|
)
|
|
{
|
|
DWORD ApiStatus;
|
|
BYTE buffer[BUF_SIZE];
|
|
DWORD sizeNeeded;
|
|
|
|
TRACE_MSG0( "TestQueryConfig: calling QueryServiceConfig...\n" );
|
|
|
|
if ( !QueryServiceConfig(
|
|
hService,
|
|
(LPVOID) buffer,
|
|
BUF_SIZE,
|
|
& sizeNeeded ) ) {
|
|
ApiStatus = GetLastError();
|
|
} else {
|
|
ApiStatus = NO_ERROR;
|
|
}
|
|
|
|
TRACE_MSG1( "TestQueryConfig: back from QueryServiceConfig, "
|
|
"API status is " FORMAT_DWORD "\n", ApiStatus );
|
|
|
|
assert( ApiStatus == ExpectedStatus );
|
|
|
|
if (ApiStatus == NO_ERROR) {
|
|
DumpServiceConfig( (LPVOID) buffer );
|
|
}
|
|
|
|
} // TestQueryConfig
|
|
|
|
|
|
VOID
|
|
TestConfigAPIs(
|
|
VOID
|
|
)
|
|
{
|
|
SC_HANDLE hScManager = NULL;
|
|
SC_HANDLE hService = NULL;
|
|
|
|
TRACE_MSG1( "handle (before anything) is " FORMAT_HEX_DWORD ".\n",
|
|
(DWORD) hScManager );
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
TRACE_MSG0( "calling OpenSCManager (default)...\n" );
|
|
|
|
hScManager = OpenSCManager(
|
|
NULL, // local machine.
|
|
NULL, // no database name.
|
|
GENERIC_ALL ); // desired access.
|
|
|
|
TRACE_MSG1( "back from OpenSCManager, handle is " FORMAT_HEX_DWORD ".\n",
|
|
(DWORD) hScManager );
|
|
|
|
if (hScManager == NULL) {
|
|
UNEXPECTED_MSG( "from OpenSCManager (default)", GetLastError() );
|
|
goto Cleanup;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
#ifdef TEST_BINDING_HANDLES
|
|
TestQueryConfig( NULL, ERROR_INVALID_HANDLE );
|
|
#endif
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
TestDeleteService(
|
|
hScManager,
|
|
NEW_SERVICE_NAME,
|
|
DELETE, // desired access
|
|
ERROR_SERVICE_DOES_NOT_EXIST,
|
|
NO_ERROR );
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
#ifdef TEST_BINDING_HANDLES
|
|
hService = TestCreateService(
|
|
NULL, NEW_SERVICE_NAME, ERROR_INVALID_HANDLE );
|
|
#endif
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
hService = TestCreateService( hScManager, NULL, ERROR_INVALID_NAME );
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
hService = TestCreateService( hScManager, NEW_SERVICE_NAME, NO_ERROR );
|
|
assert( hService != NULL );
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
TestQueryConfig( hService, NO_ERROR );
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
(VOID) TestCreateService( hScManager, NEW_SERVICE_NAME,
|
|
ERROR_SERVICE_EXISTS );
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
TestDeleteService(
|
|
NULL,
|
|
NEW_SERVICE_NAME,
|
|
DELETE, // desired access
|
|
ERROR_INVALID_HANDLE,
|
|
NO_ERROR );
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
TestDeleteService(
|
|
hScManager,
|
|
NULL,
|
|
DELETE, // desired access
|
|
NO_ERROR,
|
|
ERROR_INVALID_NAME );
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
TestDeleteService(
|
|
hScManager,
|
|
NEW_SERVICE_NAME,
|
|
GENERIC_READ, // desired access
|
|
NO_ERROR,
|
|
ERROR_ACCESS_DENIED );
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
TestDeleteService(
|
|
hScManager,
|
|
NEW_SERVICE_NAME,
|
|
DELETE, // desired access
|
|
NO_ERROR,
|
|
NO_ERROR );
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
TestQueryConfig( hService, NO_ERROR );
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
TestDeleteService(
|
|
hScManager,
|
|
NEW_SERVICE_NAME,
|
|
DELETE, // desired access
|
|
ERROR_SERVICE_DOES_NOT_EXIST,
|
|
NO_ERROR );
|
|
|
|
|
|
Cleanup:
|
|
|
|
if (hService != NULL) {
|
|
TRACE_MSG0( "calling CloseServiceHandle(hService)...\n" );
|
|
|
|
if ( !CloseServiceHandle( hService ) ) {
|
|
UNEXPECTED_MSG( "from CloseServiceHandle", GetLastError() );
|
|
}
|
|
|
|
}
|
|
|
|
if (hScManager != NULL) {
|
|
TRACE_MSG0( "calling CloseServiceHandle(hScManager)...\n" );
|
|
|
|
if ( !CloseServiceHandle( hScManager ) ) {
|
|
UNEXPECTED_MSG( "from CloseServiceHandle", GetLastError() );
|
|
}
|
|
|
|
}
|
|
|
|
} // TestConfigAPIs
|
|
|
|
|
|
VOID
|
|
TestChangeConfig2(
|
|
IN SC_HANDLE hService,
|
|
IN DWORD dwInfoLevel,
|
|
IN LPVOID lpInfo,
|
|
IN DWORD ExpectedStatus
|
|
)
|
|
{
|
|
DWORD ApiStatus;
|
|
|
|
TRACE_MSG0( "TestChangeConfig2: Calling ChangeServiceConfig2...\n" );
|
|
|
|
if ( !ChangeServiceConfig2( hService, dwInfoLevel, lpInfo ) ) {
|
|
ApiStatus = GetLastError();
|
|
} else {
|
|
ApiStatus = NO_ERROR;
|
|
}
|
|
|
|
TRACE_MSG2( "TestChangeConfig2: back from ChangeServiceConfig2, "
|
|
"API status %lu, expecting %lu\n", ApiStatus, ExpectedStatus );
|
|
|
|
assert( ApiStatus == ExpectedStatus );
|
|
|
|
/*
|
|
if (ApiStatus == NO_ERROR) {
|
|
DumpServiceConfig( (LPVOID) buffer );
|
|
}
|
|
*/
|
|
|
|
} // TestChangeConfig2
|
|
|
|
|
|
VOID
|
|
CompareFailureActions(
|
|
IN LPSERVICE_FAILURE_ACTIONS psfa1, // Expected result buffer
|
|
IN LPSERVICE_FAILURE_ACTIONS psfa2 // Actual result buffer
|
|
)
|
|
{
|
|
if (psfa1 == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
assert(psfa2 != NULL);
|
|
|
|
assert(psfa1->dwResetPeriod == psfa2->dwResetPeriod);
|
|
|
|
if (psfa1->lpRebootMsg)
|
|
{
|
|
assert(_tcscmp(psfa1->lpRebootMsg, psfa2->lpRebootMsg) == 0);
|
|
}
|
|
else
|
|
{
|
|
assert(psfa2->lpRebootMsg == NULL);
|
|
}
|
|
|
|
if (psfa1->lpCommand)
|
|
{
|
|
assert(_tcscmp(psfa1->lpCommand, psfa2->lpCommand) == 0);
|
|
}
|
|
else
|
|
{
|
|
assert(psfa2->lpCommand == NULL);
|
|
}
|
|
|
|
assert(psfa1->cActions == psfa2->cActions);
|
|
if (psfa1->cActions)
|
|
{
|
|
DWORD i;
|
|
assert(psfa2->lpsaActions != NULL);
|
|
for (i = 0; i < psfa1->cActions; i++)
|
|
{
|
|
assert(psfa1->lpsaActions[i].Type == psfa2->lpsaActions[i].Type);
|
|
assert(psfa1->lpsaActions[i].Delay == psfa2->lpsaActions[i].Delay);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
assert(psfa2->lpsaActions == NULL);
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
TestQueryConfig2(
|
|
IN SC_HANDLE hService,
|
|
IN DWORD dwInfoLevel, // which configuration data is requested
|
|
OUT LPBYTE lpBuffer, // pointer to service configuration buffer
|
|
IN DWORD cbBufSize, // size of service configuration buffer
|
|
OUT LPDWORD pcbBytesNeeded, // address of variable for bytes needed
|
|
IN DWORD ExpectedStatus,
|
|
IN LPVOID ExpectedBuffer
|
|
)
|
|
{
|
|
DWORD ApiStatus;
|
|
|
|
TRACE_MSG0( "TestQueryConfig2: calling QueryServiceConfig2...\n" );
|
|
|
|
if ( !QueryServiceConfig2(
|
|
hService,
|
|
dwInfoLevel,
|
|
lpBuffer,
|
|
cbBufSize,
|
|
pcbBytesNeeded ) ) {
|
|
ApiStatus = GetLastError();
|
|
} else {
|
|
ApiStatus = NO_ERROR;
|
|
}
|
|
|
|
TRACE_MSG2( "TestQueryConfig2: back from QueryServiceConfig2, "
|
|
"API status %lu, expecting %lu\n", ApiStatus, ExpectedStatus );
|
|
|
|
assert( ApiStatus == ExpectedStatus );
|
|
|
|
if (ApiStatus == NO_ERROR)
|
|
{
|
|
switch (dwInfoLevel)
|
|
{
|
|
case SERVICE_CONFIG_DESCRIPTION:
|
|
{
|
|
LPSERVICE_DESCRIPTION psd = (LPSERVICE_DESCRIPTION) lpBuffer;
|
|
if (ExpectedBuffer == NULL)
|
|
{
|
|
assert(psd->lpDescription == NULL);
|
|
}
|
|
else
|
|
{
|
|
assert(psd->lpDescription != NULL);
|
|
assert(_tcscmp(psd->lpDescription, (LPTSTR)ExpectedBuffer) == 0);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SERVICE_CONFIG_FAILURE_ACTIONS:
|
|
CompareFailureActions((LPSERVICE_FAILURE_ACTIONS)ExpectedBuffer,
|
|
(LPSERVICE_FAILURE_ACTIONS)lpBuffer);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
/*
|
|
if (ApiStatus == NO_ERROR) {
|
|
DumpServiceConfig( (LPVOID) buffer );
|
|
}
|
|
*/
|
|
|
|
} // TestQueryConfig2
|
|
|
|
|
|
VOID
|
|
TestConfig2APIs(
|
|
VOID
|
|
)
|
|
{
|
|
SC_HANDLE hScManager = NULL;
|
|
SC_HANDLE hService = NULL;
|
|
SC_ACTION saActions[] =
|
|
{
|
|
{ SC_ACTION_RESTART, 10000 },
|
|
{ SC_ACTION_NONE, 42 },
|
|
{ SC_ACTION_REBOOT, 500 }
|
|
};
|
|
SERVICE_FAILURE_ACTIONS sfa =
|
|
{
|
|
501, // reset period
|
|
TEXT("Put your shoes back on!"), // reboot message
|
|
TEXT("Do badly."), // failure command
|
|
LENGTH(saActions), // number of actions
|
|
saActions // action array
|
|
};
|
|
|
|
BYTE Buffer[200];
|
|
DWORD cbBytesNeeded;
|
|
|
|
|
|
TRACE_MSG1( "handle (before anything) is " FORMAT_HEX_DWORD ".\n",
|
|
(DWORD) hScManager );
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
TRACE_MSG0( "calling OpenSCManagerW (default)...\n" );
|
|
|
|
hScManager = OpenSCManager(
|
|
NULL, // local machine.
|
|
NULL, // no database name.
|
|
GENERIC_ALL ); // desired access.
|
|
|
|
TRACE_MSG1( "back from OpenSCManagerW, handle is " FORMAT_HEX_DWORD ".\n",
|
|
(DWORD) hScManager );
|
|
|
|
if (hScManager == NULL) {
|
|
UNEXPECTED_MSG( "from OpenSCManagerW (default)", GetLastError() );
|
|
goto Cleanup;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
TestDeleteService(
|
|
hScManager,
|
|
NEW_SERVICE_NAME,
|
|
DELETE, // desired access
|
|
ERROR_SERVICE_DOES_NOT_EXIST,
|
|
NO_ERROR );
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
hService = TestCreateService( hScManager, NEW_SERVICE_NAME, NO_ERROR );
|
|
assert( hService != NULL );
|
|
|
|
memset(Buffer, -1, sizeof(Buffer));
|
|
TestQueryConfig2(
|
|
hService,
|
|
SERVICE_CONFIG_DESCRIPTION,
|
|
Buffer,
|
|
sizeof(Buffer),
|
|
&cbBytesNeeded,
|
|
NO_ERROR,
|
|
NULL );
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
printf("Setting service description\n");
|
|
{
|
|
SERVICE_DESCRIPTION sd = { TEST_SERVICE_DESCR };
|
|
|
|
TestChangeConfig2(
|
|
hService,
|
|
SERVICE_CONFIG_DESCRIPTION,
|
|
&sd,
|
|
NO_ERROR );
|
|
}
|
|
|
|
TestQueryConfig2(
|
|
hService,
|
|
SERVICE_CONFIG_DESCRIPTION,
|
|
Buffer,
|
|
sizeof(Buffer),
|
|
&cbBytesNeeded,
|
|
NO_ERROR,
|
|
TEST_SERVICE_DESCR );
|
|
|
|
// For consistency with QueryServiceConfig, the API should set
|
|
// cbBytesNeeded even on a success return, even though this is not
|
|
// documented
|
|
#ifdef UNICODE
|
|
assert(cbBytesNeeded == sizeof(SERVICE_DESCRIPTION) + sizeof(TEST_SERVICE_DESCR));
|
|
#else
|
|
assert(cbBytesNeeded >= sizeof(SERVICE_DESCRIPTION) + sizeof(TEST_SERVICE_DESCR) &&
|
|
cbBytesNeeded <= sizeof(SERVICE_DESCRIPTION) + sizeof(TEST_SERVICE_DESCR)*2);
|
|
#endif
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
printf("Setting service failure actions\n");
|
|
TestChangeConfig2(
|
|
hService,
|
|
SERVICE_CONFIG_FAILURE_ACTIONS,
|
|
&sfa,
|
|
NO_ERROR );
|
|
|
|
TestQueryConfig2(
|
|
hService,
|
|
SERVICE_CONFIG_FAILURE_ACTIONS,
|
|
Buffer,
|
|
sizeof(Buffer),
|
|
&cbBytesNeeded,
|
|
NO_ERROR,
|
|
&sfa );
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
printf("Testing count 3 and NULL pointer to array\n");
|
|
sfa.lpsaActions = NULL;
|
|
TestChangeConfig2(
|
|
hService,
|
|
SERVICE_CONFIG_FAILURE_ACTIONS,
|
|
&sfa,
|
|
NO_ERROR );
|
|
|
|
// Resulting config should not have changed
|
|
sfa.lpsaActions = saActions;
|
|
TestQueryConfig2(
|
|
hService,
|
|
SERVICE_CONFIG_FAILURE_ACTIONS,
|
|
Buffer,
|
|
sizeof(Buffer),
|
|
&cbBytesNeeded,
|
|
NO_ERROR,
|
|
&sfa );
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
printf("Testing count 0 and NULL pointer to array\n");
|
|
sfa.cActions = 0;
|
|
sfa.lpsaActions = NULL;
|
|
TestChangeConfig2(
|
|
hService,
|
|
SERVICE_CONFIG_FAILURE_ACTIONS,
|
|
&sfa,
|
|
NO_ERROR );
|
|
|
|
// Resulting config should not have changed
|
|
sfa.cActions = LENGTH(saActions);
|
|
sfa.lpsaActions = saActions;
|
|
TestQueryConfig2(
|
|
hService,
|
|
SERVICE_CONFIG_FAILURE_ACTIONS,
|
|
Buffer,
|
|
sizeof(Buffer),
|
|
&cbBytesNeeded,
|
|
NO_ERROR,
|
|
&sfa );
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
printf("Testing count 0 and non-NULL pointer to array\n");
|
|
sfa.cActions = 0;
|
|
sfa.lpsaActions = (LPSC_ACTION) 0xfefefefe; // a bad pointer
|
|
TestChangeConfig2(
|
|
hService,
|
|
SERVICE_CONFIG_FAILURE_ACTIONS,
|
|
&sfa,
|
|
NO_ERROR );
|
|
|
|
// Resulting config should have no actions at all
|
|
// However, it should still have a failure command and a reboot message
|
|
sfa.dwResetPeriod = 0;
|
|
sfa.lpsaActions = NULL;
|
|
TestQueryConfig2(
|
|
hService,
|
|
SERVICE_CONFIG_FAILURE_ACTIONS,
|
|
Buffer,
|
|
sizeof(Buffer),
|
|
&cbBytesNeeded,
|
|
NO_ERROR,
|
|
&sfa );
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
printf("Testing empty failure command and unchanged reboot message\n");
|
|
sfa.lpCommand = TEXT("");
|
|
sfa.lpRebootMsg = NULL;
|
|
TestChangeConfig2(
|
|
hService,
|
|
SERVICE_CONFIG_FAILURE_ACTIONS,
|
|
&sfa,
|
|
NO_ERROR );
|
|
|
|
// Resulting config should have an empty failure command
|
|
// However, it should still have a reboot message
|
|
sfa.lpCommand = NULL;
|
|
sfa.lpRebootMsg = TEXT("Put your shoes back on!");
|
|
TestQueryConfig2(
|
|
hService,
|
|
SERVICE_CONFIG_FAILURE_ACTIONS,
|
|
Buffer,
|
|
sizeof(Buffer),
|
|
&cbBytesNeeded,
|
|
NO_ERROR,
|
|
&sfa );
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
printf("Testing invalid level\n");
|
|
TestChangeConfig2(
|
|
hService,
|
|
101,
|
|
&sfa,
|
|
ERROR_INVALID_LEVEL );
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
memset(Buffer, -1, sizeof(Buffer));
|
|
TestQueryConfig2(
|
|
hService,
|
|
SERVICE_CONFIG_DESCRIPTION,
|
|
Buffer,
|
|
sizeof(Buffer), // plenty big buffer
|
|
&cbBytesNeeded,
|
|
NO_ERROR,
|
|
TEST_SERVICE_DESCR );
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
memset(Buffer, -1, sizeof(Buffer));
|
|
TestQueryConfig2(
|
|
hService,
|
|
SERVICE_CONFIG_DESCRIPTION,
|
|
Buffer,
|
|
sizeof(SERVICE_DESCRIPTION) + sizeof(TEST_SERVICE_DESCR),
|
|
// just big enough
|
|
&cbBytesNeeded,
|
|
NO_ERROR,
|
|
TEST_SERVICE_DESCR );
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
memset(Buffer, -1, sizeof(Buffer));
|
|
cbBytesNeeded = 0;
|
|
TestQueryConfig2(
|
|
hService,
|
|
SERVICE_CONFIG_DESCRIPTION,
|
|
Buffer,
|
|
sizeof(SERVICE_DESCRIPTION) + sizeof(TEST_SERVICE_DESCR) - 1,
|
|
// 1 byte too small
|
|
&cbBytesNeeded,
|
|
ERROR_INSUFFICIENT_BUFFER,
|
|
NULL );
|
|
|
|
#ifdef UNICODE
|
|
assert(cbBytesNeeded == sizeof(SERVICE_DESCRIPTION) + sizeof(TEST_SERVICE_DESCR));
|
|
#else
|
|
assert(cbBytesNeeded >= sizeof(SERVICE_DESCRIPTION) + sizeof(TEST_SERVICE_DESCR) &&
|
|
cbBytesNeeded <= sizeof(SERVICE_DESCRIPTION) + sizeof(TEST_SERVICE_DESCR)*2);
|
|
#endif
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
memset(Buffer, -1, sizeof(Buffer));
|
|
cbBytesNeeded = 0;
|
|
TestQueryConfig2(
|
|
hService,
|
|
SERVICE_CONFIG_DESCRIPTION,
|
|
Buffer,
|
|
0, // zero size
|
|
&cbBytesNeeded,
|
|
ERROR_INSUFFICIENT_BUFFER,
|
|
NULL );
|
|
|
|
#ifdef UNICODE
|
|
assert(cbBytesNeeded == sizeof(SERVICE_DESCRIPTION) + sizeof(TEST_SERVICE_DESCR));
|
|
#else
|
|
assert(cbBytesNeeded >= sizeof(SERVICE_DESCRIPTION) + sizeof(TEST_SERVICE_DESCR) &&
|
|
cbBytesNeeded <= sizeof(SERVICE_DESCRIPTION) + sizeof(TEST_SERVICE_DESCR)*2);
|
|
#endif
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
TestDeleteService(
|
|
hScManager,
|
|
NEW_SERVICE_NAME,
|
|
DELETE, // desired access
|
|
NO_ERROR,
|
|
NO_ERROR );
|
|
|
|
Cleanup:
|
|
|
|
if (hService != NULL) {
|
|
TRACE_MSG0( "calling CloseServiceHandle(hService)...\n" );
|
|
|
|
if ( !CloseServiceHandle( hService ) ) {
|
|
UNEXPECTED_MSG( "from CloseServiceHandle", GetLastError() );
|
|
}
|
|
|
|
}
|
|
|
|
if (hScManager != NULL) {
|
|
TRACE_MSG0( "calling CloseServiceHandle(hScManager)...\n" );
|
|
|
|
if ( !CloseServiceHandle( hScManager ) ) {
|
|
UNEXPECTED_MSG( "from CloseServiceHandle", GetLastError() );
|
|
}
|
|
|
|
}
|
|
|
|
} // TestConfig2APIs
|