/* $Id: service.cpp,v 1.7 2001-06-12 18:24:10 sandervl Exp $ */

/*
 * Win32 advanced API functions for OS/2
 *
 * 1998/06/12
 *
 * Copyright 1998 Sander van Leeuwen
 * Copyright 1998 Patrick Haller
 *
 *
 * TODO: Not done; starting services; control handlers and many other things
 * TODO: Service status handles are the same as service handles
 *
 * NOTE: Uses registry key for service as handle
 *
 * Project Odin Software License can be found in LICENSE.TXT
 *
 */

#include <os2win.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <odinwrap.h>
#include <misc.h>
#include <unicode.h>
#include <win/winreg.h>
#include <win/winsvc.h>
#include <heapstring.h>
#define USE_ODIN_REGISTRY_APIS
#include "advapi32.h"

ODINDEBUGCHANNEL(ADVAPI32-SERVICE)

#define REG_SERVICE_TYPE      		"Start"
#define REG_SERVICE_TYPE_W      	(LPWSTR)L"Start"
#define REG_SERVICE_STARTTYPE 		"Type"
#define REG_SERVICE_STARTTYPE_W 	(LPWSTR)L"Type"
#define REG_SERVICE_ERRORCONTROL	"ErrorControl"
#define REG_SERVICE_ERRORCONTROL_W	(LPWSTR)L"ErrorControl"
#define REG_SERVICE_DISPLAYNAME		"DisplayName"
#define REG_SERVICE_DISPLAYNAME_W	(LPWSTR)L"DisplayName"
#define REG_SERVICE_LOADORDERGROUP	"Group" 	//???
#define REG_SERVICE_LOADORDERGROUP_W	(LPWSTR)L"Group" 	//???
#define REG_SERVICE_DEPENDENCIES        "DependOnGroup"
#define REG_SERVICE_DEPENDENCIES_W      (LPWSTR)L"DependOnGroup"
#define REG_SERVICE_IMAGEPATH		"ImagePath"
#define REG_SERVICE_IMAGEPATH_W		(LPWSTR)L"ImagePath"
#define REG_SERVICE_TAG			"Tag"
#define REG_SERVICE_TAG_W		(LPWSTR)L"Tag"

//Odin key
#define REG_SERVICE_BITS                "ServiceBits"
#define REG_SERVICE_CONTROLS_ACCEPTED   "ServiceControlsAccepted"
#define REG_SERVICE_CHECKPOINT          "dwCheckPoint"
#define REG_SERVICE_WAITHINT            "dwWaitHint"
#define REG_SERVICE_EXITCODE		"dwWin32ExitCode"
#define REG_SERVICE_SPECIFIC_EXITCODE   "dwServiceSpecificExitCode"
#define REG_SERVICE_STATUS		"ServiceStatus"
#define REG_SERVICE_STATUS_W		(LPWSTR)L"ServiceStatus"
//This key exists if DeleteService has been called for a specific service
#define REG_SERVICE_DELETEPENDING	"DeletePending"
//TODO: How can you query the name of a key from the key handle????
#define REG_SERVICE_NAME                "ServiceName"

//Win32 service can call StartServiceCtrlDispatcherA/W only once
static BOOL fServiceCtrlDispatcherStarted = FALSE;

//*****************************************************************************
//TODO: Faster way to checking this
//*****************************************************************************
BOOL CheckServiceHandle(SC_HANDLE hService)
{
 HKEY keyThisService;

  if(RegOpenKeyA((HKEY)hService, NULL, &keyThisService) != 0) {
	return FALSE;
  }
  RegCloseKey(keyThisService);
  return TRUE;
}
/*****************************************************************************
 * Name      : OpenSCManagerA
 * Purpose   : The OpenSCManager function establishes a connection to the
 *             service control manager on the specified computer and opens the
 *             specified database.
 * Parameters: LPCSTR lpszMachineName   address of machine name string
 *             LPCSTR lpszDatabaseName  address of database name string
 *             DWORD   fdwDesiredAccess  type of access
 * Variables :
 * Result    :
 * Remark    :
 * Status    : UNTESTED STUB
 *
 * Author    : SvL
 *****************************************************************************/

SC_HANDLE WIN32API OpenSCManagerA(LPCSTR lpszMachineName,
                                  LPCSTR lpszDatabaseName,
                                  DWORD  fdwDesiredAccess)
{
  dprintf(("ADVAPI32: OpenSCManagerA(%s,%s,%x) not correctly implemented.\n",
           lpszMachineName,
           lpszDatabaseName,
           fdwDesiredAccess));

  if(!lpszMachineName && !lpszDatabaseName) {
	HKEY keyServices;
  	if(RegCreateKeyA(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services", &keyServices) != 0) {
		SetLastError(ERROR_INTERNAL_ERROR);
		return 0;
	}
  	SetLastError(0);
	return keyServices;
  }
  return 0;
}


/*****************************************************************************
 * Name      : OpenSCManagerW
 * Purpose   : The OpenSCManager function establishes a connection to the
 *             service control manager on the specified computer and opens the
 *             specified database.
 * Parameters: LPCWSTR lpszMachineName   address of machine name string
 *             LPCWSTR lpszDatabaseName  address of database name string
 *             DWORD   fdwDesiredAccess  type of access
 * Variables :
 * Result    :
 * Remark    :
 * Status    : UNTESTED STUB
 *
 * Author    : SvL
 *****************************************************************************/

SC_HANDLE WIN32API OpenSCManagerW(LPCWSTR lpszMachineName,
                                  LPCWSTR lpszDatabaseName,
                                  DWORD   fdwDesiredAccess)
{
 LPSTR lpszDataBaseNameA = NULL, lpszMachineNameA = NULL;
 SC_HANDLE hService;

  dprintf(("ADVAPI32: OpenSCManagerW(%x,%x,%x) not correctly implemented.\n",
           lpszMachineName,
           lpszDatabaseName,
           fdwDesiredAccess));

  if(lpszMachineName)
	lpszMachineNameA = HEAP_strdupWtoA(GetProcessHeap(), 0, lpszMachineName);
  if(lpszDatabaseName)
	lpszDataBaseNameA = HEAP_strdupWtoA(GetProcessHeap(), 0, lpszDatabaseName);

  hService = OpenSCManagerA(lpszMachineNameA, lpszDataBaseNameA, fdwDesiredAccess);

  if(lpszMachineNameA)
	HeapFree(GetProcessHeap(), 0, lpszMachineNameA);
  if(lpszDataBaseNameA)
	HeapFree(GetProcessHeap(), 0, lpszDataBaseNameA);

  return hService;
}


/*****************************************************************************
 * Name      : OpenServiceA
 * Purpose   : The OpenService function opens a handle to an existing service.
 * Parameters: SC_HANDLE schSCManager      handle of service control manager database
 *             LPCSTR   lpszServiceName   address of name of service to start
 *             DWORD     fdwDesiredAccess  type of access to service
 * Variables :
 * Result    :
 * Remark    :
 * Status    : UNTESTED STUB
 *
 * Author    : SvL
 *****************************************************************************/

SC_HANDLE WIN32API OpenServiceA(SC_HANDLE schSCManager,
                                LPCSTR   lpszServiceName,
                                DWORD     fdwDesiredAccess)
{
  dprintf(("ADVAPI32: OpenServiceA(%08xh,%s,%08xh) not correctly implemented.\n",
           schSCManager,
           lpszServiceName,
           fdwDesiredAccess));

  if(CheckServiceHandle(schSCManager) == FALSE) {
	SetLastError(ERROR_INVALID_PARAMETER);
	return FALSE;
  }

  if(lpszServiceName == NULL) {
	SetLastError(ERROR_INVALID_PARAMETER);
	return 0;
  }
  HKEY keyThisService;
  if(RegOpenKeyA((HKEY)schSCManager, lpszServiceName, &keyThisService) != 0) {
	SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
	return 0;
  }
  SetLastError(0);
  return keyThisService;
}


/*****************************************************************************
 * Name      : OpenServiceW
 * Purpose   : The OpenService function opens a handle to an existing service.
 * Parameters: SC_HANDLE schSCManager      handle of service control manager database
 *             LPCWSTR   lpszServiceName   address of name of service to start
 *             DWORD     fdwDesiredAccess  type of access to service
 * Variables :
 * Result    :
 * Remark    :
 * Status    : UNTESTED STUB
 *
 * Author    : SvL
 *****************************************************************************/

SC_HANDLE WIN32API OpenServiceW(SC_HANDLE schSCManager,
                                LPCWSTR   lpszServiceName,
                                DWORD     fdwDesiredAccess)
{
 LPSTR lpszServiceNameA = NULL;
 SC_HANDLE hService;

  dprintf(("ADVAPI32: OpenServiceW(%08xh,%s,%08xh) not correctly implemented.\n",
           schSCManager,
           lpszServiceName,
           fdwDesiredAccess));

  if(lpszServiceName == NULL) {
	SetLastError(ERROR_INVALID_PARAMETER);
	return 0;
  }
  lpszServiceNameA = HEAP_strdupWtoA(GetProcessHeap(), 0, lpszServiceName);
  hService = OpenServiceA(schSCManager, lpszServiceNameA, fdwDesiredAccess);
  HeapFree(GetProcessHeap(), 0, lpszServiceNameA);
  return hService;
}

/*****************************************************************************
 * Name      : QueryServiceConfigA
 * Purpose   : The QueryServiceConfig function retrieves the configuration
 *             parameters of the specified service.
 * Parameters: SC_HANDLE              schService       handle of service
 *             LPQUERY_SERVICE_CONFIG lpqscServConfig  address of service config. structure
 *             DWORD                  cbBufSize        size of service configuration buffer
 *             LPDWORD                lpcbBytesNeeded  address of variable for bytes needed
 * Variables :
 * Result    :
 * Remark    :
 * Status    : UNTESTED STUB
 *
 * Author    : SvL
 *****************************************************************************/

BOOL WIN32API QueryServiceConfigA(SC_HANDLE              schService,
                                     LPQUERY_SERVICE_CONFIG lpqscServConfig,
                                     DWORD                  cbBufSize,
                                     LPDWORD                lpcbBytesNeeded)
{
  dprintf(("ADVAPI32: QueryServiceConfigA(%08xh,%08xh,%08xh,%08xh) not implemented.\n",
           schService,
           lpqscServConfig,
           cbBufSize,
           lpcbBytesNeeded));

  return (FALSE); /* signal failure */
}


/*****************************************************************************
 * Name      : QueryServiceConfigW
 * Purpose   : The QueryServiceConfig function retrieves the configuration
 *             parameters of the specified service.
 * Parameters: SC_HANDLE              schService       handle of service
 *             LPQUERY_SERVICE_CONFIG lpqscServConfig  address of service config. structure
 *             DWORD                  cbBufSize        size of service configuration buffer
 *             LPDWORD                lpcbBytesNeeded  address of variable for bytes needed
 * Variables :
 * Result    :
 * Remark    :
 * Status    : UNTESTED STUB
 *
 * Author    : Patrick Haller [Tue, 1998/06/16 23:00]
 *****************************************************************************/

BOOL WIN32API QueryServiceConfigW(SC_HANDLE              schService,
                                     LPQUERY_SERVICE_CONFIG lpqscServConfig,
                                     DWORD                  cbBufSize,
                                     LPDWORD                lpcbBytesNeeded)
{
  dprintf(("ADVAPI32: QueryServiceConfigW(%08xh,%08xh,%08xh,%08xh) not implemented.\n",
           schService,
           lpqscServConfig,
           cbBufSize,
           lpcbBytesNeeded));

  return (FALSE); /* signal failure */
}


/*****************************************************************************
 * Name      : QueryServiceLockStatusA
 * Purpose   : The QueryServiceLockStatus function retrieves the lock status
 *             of the specified service control manager database.
 * Parameters: SC_HANDLE                   schSCManager     handle of svc. ctrl. mgr. database
 *             LPQUERY_SERVICE_LOCK_STATUS lpqslsLockStat   address of lock status structure
 *             DWORD                       cbBufSize        size of service configuration buffer
 *             LPDWORD                     lpcbBytesNeeded  address of variable for bytes needed
 * Variables :
 * Result    :
 * Remark    :
 * Status    : UNTESTED STUB
 *
 * Author    : Patrick Haller [Tue, 1998/06/16 23:00]
 *****************************************************************************/

BOOL WIN32API QueryServiceLockStatusA(SC_HANDLE                   schSCManager,
                                         LPQUERY_SERVICE_LOCK_STATUSA lpqslsLockStat,
                                         DWORD                       cbBufSize,
                                         LPDWORD                     lpcbBytesNeeded)
{
  dprintf(("ADVAPI32: QueryServiceLockStatusA(%08xh,%08xh,%08xh,%08xh) not implemented.\n",
           schSCManager,
           lpqslsLockStat,
           cbBufSize,
           lpcbBytesNeeded));

  return (FALSE); /* signal failure */
}


/*****************************************************************************
 * Name      : QueryServiceLockStatusW
 * Purpose   : The QueryServiceLockStatus function retrieves the lock status
 *             of the specified service control manager database.
 * Parameters: SC_HANDLE                   schSCManager     handle of svc. ctrl. mgr. database
 *             LPQUERY_SERVICE_LOCK_STATUS lpqslsLockStat   address of lock status structure
 *             DWORD                       cbBufSize        size of service configuration buffer
 *             LPDWORD                     lpcbBytesNeeded  address of variable for bytes needed
 * Variables :
 * Result    :
 * Remark    :
 * Status    : UNTESTED STUB
 *
 * Author    : Patrick Haller [Tue, 1998/06/16 23:00]
 *****************************************************************************/

BOOL WIN32API QueryServiceLockStatusW(SC_HANDLE                   schSCManager,
                                         LPQUERY_SERVICE_LOCK_STATUSW lpqslsLockStat,
                                         DWORD                       cbBufSize,
                                         LPDWORD                     lpcbBytesNeeded)
{
  dprintf(("ADVAPI32: QueryServiceLockStatusW(%08xh,%08xh,%08xh,%08xh) not implemented.\n",
           schSCManager,
           lpqslsLockStat,
           cbBufSize,
           lpcbBytesNeeded));

  return (FALSE); /* signal failure */
}

/*****************************************************************************
 * Name      : QueryServiceObjectSecurity
 * Purpose   : The QueryServiceObjectSecurity function retrieves a copy of the
 *             security descriptor protecting a service object.
 * Parameters: SC_HANDLE             schService       handle of service
 *             SECURITY_INFORMATION  fdwSecurityInfo  type of security information requested
 *             PSECURITY_DESCRIPTOR  psdSecurityDesc  address of security descriptor
 *             DWORD                 cbBufSize        size of security descriptor buffer
 *             LPDWORD               lpcbBytesNeeded  address of variable for bytes needed
 * Variables :
 * Result    :
 * Remark    :
 * Status    : UNTESTED STUB
 *
 * Author    : Patrick Haller [Tue, 1998/06/16 23:00]
 *****************************************************************************/

BOOL WIN32API QueryServiceObjectSecurity(SC_HANDLE             schService,
                                            SECURITY_INFORMATION  fdwSecurityInfo,
                                            PSECURITY_DESCRIPTOR  psdSecurityDesc,
                                            DWORD                 cbBufSize,
                                            LPDWORD               lpcbBytesNeeded)
{
  dprintf(("ADVAPI32: QueryServiceObjectSecurity(%08xh,%08xh,%08xh,%08xh,%08xh) not implemented.\n",
           schService,
           fdwSecurityInfo,
           psdSecurityDesc,
           cbBufSize,
           lpcbBytesNeeded));

  return (FALSE); /* signal failure */
}

/*****************************************************************************
 * Name      : SetServiceObjectSecurity
 * Purpose   : The SetServiceObjectSecurity function sets the security
 *             descriptor of a service object.
 * Parameters: SC_HANDLE             schService      handle of service
 *             SECURITY_INFORMATION  fdwSecurityInfo type of security information requested
 *             PSECURITY_DESCRIPTOR  psdSecurityDesc address of security descriptor
 * Variables :
 * Result    :
 * Remark    :
 * Status    : UNTESTED STUB
 *
 * Author    : Patrick Haller [Tue, 1998/06/16 23:00]
 *****************************************************************************/

BOOL WIN32API SetServiceObjectSecurity(SC_HANDLE             schService,
                                          SECURITY_INFORMATION  fdwSecurityInfo,
                                          PSECURITY_DESCRIPTOR  psdSecurityDesc)
{
  dprintf(("ADVAPI32: SetServiceObjectSecurity(%08xh,%08xh,%08xh) not implemented.\n",
           schService,
           fdwSecurityInfo,
           psdSecurityDesc));

  return (FALSE); /* signal failure */
}

/*****************************************************************************
 * Name      : ChangeServiceConfigA
 * Purpose   : The ChangeServiceConfig function changes the configuration
 *             parameters of a service.
 * Parameters: SC_HANDLE hService           handle of service
 *             DWORD     dwServiceType      type of service
 *             DWORD     dwStartType        when to start service
 *             DWORD     dwErrorControl     severity if service fails to start
 *             LPCSTR   lpBinaryPathName   address of service binary file name
 *             LPCSTR   lpLoadOrderGroup   address of load ordering group name
 *             LPDWORD   lpdwTagId          address of variable to get tag identifier
 *             LPCSTR   lpDependencies     address of array of dependency names
 *             LPCSTR   lpServiceStartName address of account name of service
 *             LPCSTR   lpPassword         address of password for service account
 *             LPCSTR   lpDisplayName      address of display name
 * Variables :
 * Result    :
 * Remark    :
 * Status    :
 *
 * Author    : SvL
 *****************************************************************************/

BOOL WIN32API ChangeServiceConfigA(SC_HANDLE hService,
                                      DWORD     dwServiceType,
                                      DWORD     dwStartType,
                                      DWORD     dwErrorControl,
                                      LPCSTR   lpBinaryPathName,
                                      LPCSTR   lpLoadOrderGroup,
                                      LPDWORD   lpdwTagId,
                                      LPCSTR   lpDependencies,
                                      LPCSTR   lpServiceStartName,
                                      LPCSTR   lpPassword,
                                      LPCSTR   lpDisplayName)
{
  dprintf(("ADVAPI32: ChangeServiceConfigA(%08xh,%08xh,%08xh,%08xh,%s,%s,%08xh,%s,%s,%s,%s) not implemented.\n",
           hService,
           dwServiceType,
           dwStartType,
           dwErrorControl,
           lpBinaryPathName,
           lpLoadOrderGroup,
           lpdwTagId,
           lpDependencies,
           lpServiceStartName,
           lpPassword,
           lpDisplayName));

  return (FALSE); /* signal failure */
}


/*****************************************************************************
 * Name      : ChangeServiceConfigW
 * Purpose   : The ChangeServiceConfig function changes the configuration
 *             parameters of a service.
 * Parameters: SC_HANDLE hService           handle of service
 *             DWORD     dwServiceType      type of service
 *             DWORD     dwStartType        when to start service
 *             DWORD     dwErrorControl     severity if service fails to start
 *             LPCWSTR   lpBinaryPathName   address of service binary file name
 *             LPCWSTR   lpLoadOrderGroup   address of load ordering group name
 *             LPDWORD   lpdwTagId          address of variable to get tag identifier
 *             LPCWSTR   lpDependencies     address of array of dependency names
 *             LPCWSTR   lpServiceStartName address of account name of service
 *             LPCWSTR   lpPassword         address of password for service account
 *             LPCWSTR   lpDisplayName      address of display name
 * Variables :
 * Result    :
 * Remark    :
 * Status    :
 *
 * Author    : SvL
 *****************************************************************************/

BOOL WIN32API ChangeServiceConfigW(SC_HANDLE hService,
                                      DWORD     dwServiceType,
                                      DWORD     dwStartType,
                                      DWORD     dwErrorControl,
                                      LPCWSTR   lpBinaryPathName,
                                      LPCWSTR   lpLoadOrderGroup,
                                      LPDWORD   lpdwTagId,
                                      LPCWSTR   lpDependencies,
                                      LPCWSTR   lpServiceStartName,
                                      LPCWSTR   lpPassword,
                                      LPCWSTR   lpDisplayName)
{
 LPSTR lpDisplayNameA = NULL, lpBinaryPathNameA = NULL;
 LPSTR lpDependenciesA = NULL, lpServiceStartNameA = NULL, lpPasswordA = NULL;
 LPSTR lpLoadOrderGroupA = NULL;
 BOOL  fRc;

  dprintf(("ADVAPI32: ChangeServiceConfigW(%08xh,%08xh,%08xh,%08xh,%s,%s,%08xh,%s,%s,%s,%s) not implemented.\n",
           hService,
           dwServiceType,
           dwStartType,
           dwErrorControl,
           lpBinaryPathName,
           lpLoadOrderGroup,
           lpdwTagId,
           lpDependencies,
           lpServiceStartName,
           lpPassword,
           lpDisplayName));

  if(lpDisplayName)
  	lpDisplayNameA = HEAP_strdupWtoA(GetProcessHeap(), 0, lpDisplayName);
  if(lpBinaryPathName)
  	lpBinaryPathNameA = HEAP_strdupWtoA(GetProcessHeap(), 0, lpBinaryPathName);
  if(lpDependencies)
  	lpDependenciesA = HEAP_strdupWtoA(GetProcessHeap(), 0, lpDependencies);
  if(lpServiceStartName)
  	lpServiceStartNameA = HEAP_strdupWtoA(GetProcessHeap(), 0, lpServiceStartName);
  if(lpPassword)
  	lpPasswordA = HEAP_strdupWtoA(GetProcessHeap(), 0, lpPassword);
  if(lpDisplayName)
  	lpDisplayNameA = HEAP_strdupWtoA(GetProcessHeap(), 0, lpDisplayName);
  if(lpLoadOrderGroup)
  	lpLoadOrderGroupA = HEAP_strdupWtoA(GetProcessHeap(), 0, lpLoadOrderGroup);

  fRc = ChangeServiceConfigA(hService,dwServiceType, dwStartType, dwErrorControl,
                             lpBinaryPathNameA,
                             lpLoadOrderGroupA,
                             lpdwTagId,
                             lpDependenciesA,
                             lpServiceStartNameA,
                             lpPasswordA,
                             lpDisplayNameA);

  if(lpDisplayNameA) 		HeapFree(GetProcessHeap(), 0, lpDisplayNameA);
  if(lpBinaryPathNameA)		HeapFree(GetProcessHeap(), 0, lpBinaryPathNameA);
  if(lpDependenciesA) 		HeapFree(GetProcessHeap(), 0, lpDependenciesA);
  if(lpServiceStartNameA) 	HeapFree(GetProcessHeap(), 0, lpServiceStartNameA);
  if(lpPasswordA) 		HeapFree(GetProcessHeap(), 0, lpPasswordA);
  if(lpLoadOrderGroupA) 	HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupA);

  return fRc;
}


/*****************************************************************************
 * Name      : CloseServiceHandle
 * Purpose   : The CloseServiceHandle function closes a handle to a service
 *             control manager database as returned by the OpenSCManager function,
 *             or it closes a handle to a service object as returned by either
 *             the OpenService or CreateService function.
 * Parameters: SC_HANDLE  hSCObject  handle of service or service control manager database
 * Variables :
 * Result    :
 * Remark    :
 * Status    :
 *
 * Author    : SvL
 *****************************************************************************/

BOOL WIN32API CloseServiceHandle(SC_HANDLE hSCObject)
{
  dprintf(("ADVAPI32: CloseServiceHandle(%08xh)",
           hSCObject));

  if(CheckServiceHandle(hSCObject) == FALSE) {
	SetLastError(ERROR_INVALID_PARAMETER);
	return FALSE;
  }

  DWORD deletepending, keytype = REG_DWORD, size = sizeof(DWORD);
  if(!RegQueryValueExA((HKEY)hSCObject, REG_SERVICE_DELETEPENDING, 0, &keytype, (LPBYTE)&deletepending, &size)) {
   CHAR szKeyName[256] = "";

	HKEY keyServices;
  	if(RegCreateKeyA(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services", &keyServices) != 0) {
		SetLastError(ERROR_INTERNAL_ERROR);
		return FALSE;
	}
	keytype = REG_SZ;
	size    = sizeof(szKeyName);
	RegQueryValueExA(hSCObject, REG_SERVICE_NAME, 0, &keytype, (LPBYTE)szKeyName, &size);

  	RegCloseKey((HKEY)hSCObject);
	RegDeleteKeyA(keyServices, szKeyName);
  	RegCloseKey((HKEY)keyServices);
  }

  RegCloseKey((HKEY)hSCObject);
  SetLastError(0);
  return TRUE;
}

/*****************************************************************************
 * Name      : ControlService
 * Purpose   : The ControlService function sends a control code to a Win32 service.
 * Parameters: SC_HANDLE        hService        handle of service
 *             DWORD            dwControl       control code
 *             LPSERVICE_STATUS lpServiceStatus address of service status structure
 * Variables :
 * Result    :
 * Remark    :
 * Status    :
 *
 * Author    : SvL
 *****************************************************************************/

BOOL WIN32API ControlService(SC_HANDLE        hService,
                             DWORD            dwControl,
                             LPSERVICE_STATUS lpServiceStatus)
{
  dprintf(("ADVAPI32: ControlService(%08xh,%08xh,%08xh) not correctly implemented.\n",
           hService,
           dwControl,
           lpServiceStatus));
  HKEY keyThisService;

  if(CheckServiceHandle(hService) == FALSE) {
	SetLastError(ERROR_INVALID_PARAMETER);
	return FALSE;
  }
  SetLastError(0);
  return TRUE;
}


/*****************************************************************************
 * Name      : CreateServiceA
 * Purpose   : The CreateService function creates a service object and adds it
 *             to the specified service control manager database.
 * Parameters: SC_HANDLE hSCManager         handle of service control manager database
 *             LPCSTR   lpServiceName      address of name of service to start
 *             LPCSTR   lpDisplayName      address of display name
 *             DWORD     dwDesiredAccess    type of access to service
 *             DWORD     dwServiceType      type of service
 *             DWORD     dwStartType        when to start service
 *             DWORD     dwErrorControl     severity if service fails to start
 *             LPCSTR   lpBinaryPathName   address of name of binary file
 *             LPCSTR   lpLoadOrderGroup   address of name of load ordering group
 *             LPDWORD   lpdwTagId          address of variable to get tag identifier
 *             LPCSTR   lpDependencies     address of array of dependency names
 *             LPCSTR   lpServiceStartName address of account name of service
 *             LPCSTR   lpPassword         address of password for service account
 * Variables :
 * Result    :
 * Remark    :
 * Status    :
 *
 * Author    : SvL
 *****************************************************************************/

SC_HANDLE WIN32API CreateServiceA(SC_HANDLE hSCManager,
                                  LPCSTR    lpServiceName,
                                  LPCSTR    lpDisplayName,
                                  DWORD     dwDesiredAccess,
                                  DWORD     dwServiceType,
                                  DWORD     dwStartType,
                                  DWORD     dwErrorControl,
                                  LPCSTR    lpBinaryPathName,
                                  LPCSTR    lpLoadOrderGroup,
                                  LPDWORD   lpdwTagId,
                                  LPCSTR    lpDependencies,
                                  LPCSTR    lpServiceStartName,
                                  LPCSTR    lpPassword)
{
 HKEY keyServices, keyThisService;

  dprintf(("ADVAPI32: CreateServiceA(%08xh,%s,%s,%08xh,%08xh,%08xh,%08xh,%s,%s,%08xh,%s,%s,%s) not correctly implemented.\n",
           hSCManager,
           lpServiceName,
           lpDisplayName,
           dwDesiredAccess,
           dwServiceType,
           dwStartType,
           dwErrorControl,
           lpBinaryPathName,
           lpLoadOrderGroup,
           lpdwTagId,
           lpDependencies,
           lpServiceStartName,
           lpPassword));

  //displayname too?
  if(lpServiceName == NULL || lpBinaryPathName == NULL) {
	SetLastError(ERROR_INVALID_PARAMETER);
	return 0;
  }

  if(RegCreateKeyA(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services", &keyServices) != 0) {
	SetLastError(ERROR_INTERNAL_ERROR);
	return 0;
  }
  if(RegCreateKeyA(keyServices, lpServiceName, &keyThisService) != 0) {
	SetLastError(ERROR_INTERNAL_ERROR);
	return 0;
  }
  RegSetValueExA(keyThisService, REG_SERVICE_NAME, 0, REG_SZ, (LPBYTE)lpServiceName, strlen(lpServiceName)+1);
  RegSetValueExA(keyThisService, REG_SERVICE_TYPE, 0, REG_DWORD, (LPBYTE)&dwServiceType, sizeof(DWORD));
  RegSetValueExA(keyThisService, REG_SERVICE_STARTTYPE, 0, REG_DWORD, (LPBYTE)&dwStartType, sizeof(DWORD));
  RegSetValueExA(keyThisService, REG_SERVICE_ERRORCONTROL, 0, REG_DWORD, (LPBYTE)&dwErrorControl, sizeof(DWORD));
  if(lpDisplayName)
	RegSetValueExA(keyThisService, REG_SERVICE_DISPLAYNAME, 0, REG_SZ, (LPBYTE)lpDisplayName, strlen(lpDisplayName)+1);
  if(lpLoadOrderGroup)
	RegSetValueExA(keyThisService, REG_SERVICE_LOADORDERGROUP, 0, REG_SZ, (LPBYTE)lpDisplayName, strlen(lpLoadOrderGroup)+1);
  if(lpDependencies) {
	//seems to need an extra terminating '0'
	int size = strlen(lpDependencies)+2;
	char *dependencies = (char *)malloc(size);
	memset(dependencies, 0, size);
	strcpy(dependencies, lpDependencies);
	RegSetValueExA(keyThisService, REG_SERVICE_DEPENDENCIES, 0, REG_BINARY, (LPBYTE)dependencies, size);
	free(dependencies);
  }
  //TODO: %SystemRoot%
  RegSetValueExA(keyThisService, REG_SERVICE_IMAGEPATH, 0, REG_SZ, (LPBYTE)lpBinaryPathName, strlen(lpBinaryPathName)+1);

  //Pointer to a variable that receives a tag value that is unique in the group specified in the
  //lpLoadOrderGroup parameter. Specify NULL if you are not changing the existing tag.
  DWORD tag = 1; //TODO!!
  RegSetValueExA(keyThisService, REG_SERVICE_TAG, 0, REG_DWORD, (LPBYTE)&tag, sizeof(DWORD));
  if(lpdwTagId)
	*lpdwTagId = tag;

  DWORD state = SERVICE_STOPPED;
  RegSetValueExA(keyThisService, REG_SERVICE_STATUS, 0, REG_DWORD, (LPBYTE)&state, sizeof(DWORD));

  //TODO: What else?

  RegCloseKey(keyServices);
  SetLastError(0);
  return keyThisService;
}


/*****************************************************************************
 * Name      : CreateServiceW
 * Purpose   : The CreateService function creates a service object and adds it
 *             to the specified service control manager database.
 * Parameters: SC_HANDLE hSCManager         handle of service control manager database
 *             LPCWSTR   lpServiceName      address of name of service to start
 *             LPCWSTR   lpDisplayName      address of display name
 *             DWORD     dwDesiredAccess    type of access to service
 *             DWORD     dwServiceType      type of service
 *             DWORD     dwStartType        when to start service
 *             DWORD     dwErrorControl     severity if service fails to start
 *             LPCWSTR   lpBinaryPathName   address of name of binary file
 *             LPCWSTR   lpLoadOrderGroup   address of name of load ordering group
 *             LPDWORD   lpdwTagId          address of variable to get tag identifier
 *             LPCWSTR   lpDependencies     address of array of dependency names
 *             LPCWSTR   lpServiceStartName address of account name of service
 *             LPCWSTR   lpPassword         address of password for service account
 * Variables :
 * Result    :
 * Remark    :
 * Status    :
 *
 * Author    : SvL
 *****************************************************************************/

SC_HANDLE WIN32API CreateServiceW(SC_HANDLE hSCManager,
                                     LPCWSTR   lpServiceName,
                                     LPCWSTR   lpDisplayName,
                                     DWORD     dwDesiredAccess,
                                     DWORD     dwServiceType,
                                     DWORD     dwStartType,
                                     DWORD     dwErrorControl,
                                     LPCWSTR   lpBinaryPathName,
                                     LPCWSTR   lpLoadOrderGroup,
                                     LPDWORD   lpdwTagId,
                                     LPCWSTR   lpDependencies,
                                     LPCWSTR   lpServiceStartName,
                                     LPCWSTR   lpPassword)
{
 LPSTR lpServiceNameA = NULL, lpDisplayNameA = NULL, lpBinaryPathNameA = NULL;
 LPSTR lpDependenciesA = NULL, lpServiceStartNameA = NULL, lpPasswordA = NULL;
 LPSTR lpLoadOrderGroupA = NULL;
 SC_HANDLE hService;

  dprintf(("ADVAPI32: CreateServiceW(%08xh,%s,%s,%08xh,%08xh,%08xh,%08xh,%s,%s,%08xh,%s,%s,%s) not correctly implemented.\n",
           hSCManager,
           lpServiceName,
           lpDisplayName,
           dwDesiredAccess,
           dwServiceType,
           dwStartType,
           dwErrorControl,
           lpBinaryPathName,
           lpLoadOrderGroup,
           lpdwTagId,
           lpDependencies,
           lpServiceStartName,
           lpPassword));

  if(lpServiceName)
  	lpServiceNameA = HEAP_strdupWtoA(GetProcessHeap(), 0, lpServiceName);
  if(lpDisplayName)
  	lpDisplayNameA = HEAP_strdupWtoA(GetProcessHeap(), 0, lpDisplayName);
  if(lpBinaryPathName)
  	lpBinaryPathNameA = HEAP_strdupWtoA(GetProcessHeap(), 0, lpBinaryPathName);
  if(lpDependencies)
  	lpDependenciesA = HEAP_strdupWtoA(GetProcessHeap(), 0, lpDependencies);
  if(lpServiceStartName)
  	lpServiceStartNameA = HEAP_strdupWtoA(GetProcessHeap(), 0, lpServiceStartName);
  if(lpPassword)
  	lpPasswordA = HEAP_strdupWtoA(GetProcessHeap(), 0, lpPassword);
  if(lpDisplayName)
  	lpDisplayNameA = HEAP_strdupWtoA(GetProcessHeap(), 0, lpDisplayName);
  if(lpLoadOrderGroup)
  	lpLoadOrderGroupA = HEAP_strdupWtoA(GetProcessHeap(), 0, lpLoadOrderGroup);

  hService = CreateServiceA(hSCManager,lpServiceNameA, lpDisplayNameA,
                            dwDesiredAccess, dwServiceType, dwStartType,
                            dwErrorControl, lpBinaryPathNameA, lpLoadOrderGroupA,
                            lpdwTagId, lpDependenciesA, lpServiceStartNameA,
                            lpPasswordA);

  if(lpServiceNameA) 		HeapFree(GetProcessHeap(), 0, lpServiceNameA);
  if(lpDisplayNameA) 		HeapFree(GetProcessHeap(), 0, lpDisplayNameA);
  if(lpBinaryPathNameA)		HeapFree(GetProcessHeap(), 0, lpBinaryPathNameA);
  if(lpDependenciesA) 		HeapFree(GetProcessHeap(), 0, lpDependenciesA);
  if(lpServiceStartNameA) 	HeapFree(GetProcessHeap(), 0, lpServiceStartNameA);
  if(lpPasswordA) 		HeapFree(GetProcessHeap(), 0, lpPasswordA);
  if(lpLoadOrderGroupA) 	HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupA);

  return hService;
}

/*****************************************************************************
 * Name      : StartServiceA
 * Purpose   : The StartService function starts the execution of a service.
 * Parameters: SC_HANDLE schService        handle of service
 *             DWORD     dwNumServiceArgs  number of arguments
 *             LPCSTR   *lpszServiceArgs  address of array of argument string pointers
 * Variables :
 * Result    :
 * Remark    :
 * Status    :
 *
 * Author    : SvL
 *****************************************************************************/

BOOL WIN32API StartServiceA(SC_HANDLE schService,
                            DWORD     dwNumServiceArgs,
                            LPCSTR   *lpszServiceArgs)
{
  dprintf(("ADVAPI32: StartServiceA(%08xh,%08xh,%s) not implemented.\n",
           schService,
           dwNumServiceArgs,
           lpszServiceArgs));

  if(CheckServiceHandle(schService) == FALSE) {
	SetLastError(ERROR_INVALID_PARAMETER);
	return FALSE;
  }

  DWORD state = SERVICE_RUNNING;
  if(!RegSetValueExA((HKEY)schService, REG_SERVICE_STATUS, 0, REG_DWORD, (LPBYTE)&state, sizeof(DWORD))) {
  	SetLastError(0);
	return TRUE;
  }

  //TODO: Really start service
  return (FALSE); /* signal failure */
}

/*****************************************************************************
 * Name      : StartServiceW
 * Purpose   : The StartService function starts the execution of a service.
 * Parameters: SC_HANDLE schService        handle of service
 *             DWORD     dwNumServiceArgs  number of arguments
 *             LPCWSTR   *lpszServiceArgs  address of array of argument string pointers
 * Variables :
 * Result    :
 * Remark    :
 * Status    :
 *
 * Author    : SvL
 *****************************************************************************/

BOOL WIN32API StartServiceW(SC_HANDLE schService,
                            DWORD     dwNumServiceArgs,
                            LPCWSTR   *lpszServiceArgs)
{
  dprintf(("ADVAPI32: StartServiceW(%08xh,%08xh,%s) not implemented.\n",
           schService,
           dwNumServiceArgs,
           lpszServiceArgs));

  if(CheckServiceHandle(schService) == FALSE) {
	SetLastError(ERROR_INVALID_PARAMETER);
	return FALSE;
  }

  DWORD state = SERVICE_RUNNING;
  if(!RegSetValueExW((HKEY)schService, REG_SERVICE_STATUS_W, 0, REG_DWORD, (LPBYTE)&state, sizeof(DWORD))) {
	SetLastError(0);
	return TRUE;
  }
  //TODO: Really start service
  return (FALSE); /* signal failure */
}

/*****************************************************************************
 * Name      : DeleteService
 * Purpose   : The DeleteService function marks the specified service for
 *             deletion from the service control manager database.
 * Parameters: SC_HANDLE  hService  handle of service
 * Variables :
 * Result    :
 * Remark    :
 * Status    :
 *
 * Author    : SvL
 *****************************************************************************/

BOOL WIN32API DeleteService(SC_HANDLE hService)
{
  dprintf(("ADVAPI32: DeleteService(%08xh)", hService));

  if(CheckServiceHandle(hService) == FALSE) {
	SetLastError(ERROR_INVALID_PARAMETER);
	return FALSE;
  }
  DWORD deletepending = 1;
  if(!RegSetValueExA((HKEY)hService, REG_SERVICE_DELETEPENDING, 0, REG_DWORD, (LPBYTE)&deletepending, sizeof(DWORD))) {
  	SetLastError(0);
	return TRUE;
  }
  return FALSE;
}

/*****************************************************************************
 * Name      : GetServiceDisplayNameA
 * Purpose   : The GetServiceDisplayName function obtains the display name that
 *             is associated with a particular service name. The service name
 *             is the same as the service's registry key name.
 * Parameters: SC_HANDLE hSCManager     handle to a service control manager database
 *             LPCSTR   lpServiceName  the service name
 *             LPTSTR    lpDisplayName  buffer to receive the service's display name
 *             LPDWORD   lpcchBuffer    size of display name buffer and display name
 * Variables :
 * Result    :
 * Remark    :
 * Status    :
 *
 * Author    : SvL
 *****************************************************************************/

BOOL WIN32API GetServiceDisplayNameA(SC_HANDLE hSCManager,
                                     LPCSTR    lpServiceName,
                                     LPTSTR    lpDisplayName,
                                     LPDWORD   lpcchBuffer)
{
 HKEY keyThisService;
 DWORD size, type;

  dprintf(("ADVAPI32: GetServiceDisplayNameA(%08xh,%08xh,%08xh,%08xh) not implemented.\n",
           hSCManager,
           lpServiceName,
           lpDisplayName,
           lpcchBuffer));

  if(!lpServiceName || !lpDisplayName) {
	SetLastError(ERROR_INVALID_PARAMETER);
	return FALSE;
  }
  if(CheckServiceHandle(hSCManager) == FALSE) {
	SetLastError(ERROR_INVALID_PARAMETER);
	return FALSE;
  }

  if(RegOpenKeyA((HKEY)hSCManager, lpServiceName, &keyThisService) != 0) {
	SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
	return FALSE;
  }
  size = *lpcchBuffer;
  type = REG_SZ;
  if(RegQueryValueExA(keyThisService, REG_SERVICE_DISPLAYNAME, 0, &type, (LPBYTE)lpDisplayName, &size) == ERROR_MORE_DATA)
  {
	SetLastError(ERROR_MORE_DATA);
  	*lpcchBuffer = size;
	return FALSE;
  }
  *lpcchBuffer = size;
  RegCloseKey(keyThisService);
  SetLastError(0);
  return TRUE;
}


/*****************************************************************************
 * Name      : GetServiceDisplayNameW
 * Purpose   : The GetServiceDisplayName function obtains the display name that
 *             is associated with a particular service name. The service name
 *             is the same as the service's registry key name.
 * Parameters: SC_HANDLE hSCManager     handle to a service control manager database
 *             LPCWSTR   lpServiceName  the service name
 *             LPWSTR    lpDisplayName  buffer to receive the service's display name
 *             LPDWORD   lpcchBuffer    size of display name buffer and display name
 * Variables :
 * Result    :
 * Remark    :
 * Status    :
 *
 * Author    : SvL
 *****************************************************************************/

BOOL WIN32API GetServiceDisplayNameW(SC_HANDLE hSCManager,
                                     LPCWSTR   lpServiceName,
                                     LPWSTR    lpDisplayName,
                                     LPDWORD   lpcchBuffer)
{
 HKEY keyThisService;
 DWORD size, type;

  dprintf(("ADVAPI32: GetServiceDisplayNameW(%08xh,%08xh,%08xh,%08xh) not implemented.\n",
           hSCManager,
           lpServiceName,
           lpDisplayName,
           lpcchBuffer));

  if(!lpServiceName || !lpDisplayName) {
	SetLastError(ERROR_INVALID_PARAMETER);
	return FALSE;
  }
  if(CheckServiceHandle(hSCManager) == FALSE) {
	SetLastError(ERROR_INVALID_PARAMETER);
	return FALSE;
  }

  if(RegOpenKeyW((HKEY)hSCManager, lpServiceName, &keyThisService) != 0) {
	SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
	return FALSE;
  }
  size = *lpcchBuffer;
  type = REG_SZ;
  if(RegQueryValueExW(keyThisService, REG_SERVICE_DISPLAYNAME_W, 0, &type, (LPBYTE)lpDisplayName, &size) == ERROR_MORE_DATA)
  {
	SetLastError(ERROR_MORE_DATA);
  	*lpcchBuffer = size;
	return FALSE;
  }
  *lpcchBuffer = size;
  RegCloseKey(keyThisService);
  SetLastError(0);
  return TRUE;
}

/*****************************************************************************
 * Name      : EnumDependentServicesA
 * Purpose   : The EnumDependentServices function enumerates services that
 *             depend on another specified service; that is, the specified
 *             service must be running before the enumerated services can run.
 *             The name and status of each dependent service are provided.
 * Parameters: SC_HANDLE             hService           handle of service
 *             DWORD                 dwServiceState     state of services to enumerate
 *             LPENUM_SERVICE_STATUS lpServices         address of service status buffer
 *             DWORD                 cbBufSize          size of service status buffer
 *             LPDWORD               pcbBytesNeeded     address of variable for bytes needed
 *             LPDWORD               lpServicesReturned address of variable for number returned
 * Variables :
 * Result    :
 * Remark    :
 * Status    : UNTESTED STUB
 *
 * Author    : Patrick Haller [Tue, 1998/06/16 23:00]
 *****************************************************************************/

BOOL WIN32API EnumDependentServicesA(SC_HANDLE             hService,
                                        DWORD                 dwServiceState,
                                        LPENUM_SERVICE_STATUSA lpServices,
                                        DWORD                 cbBufSize,
                                        LPDWORD               pcbBytesNeeded,
                                        LPDWORD               lpServicesReturned)
{
  dprintf(("ADVAPI32: EnumDependentServicesA(%08xh,%08xh,%08xh,%08xh,%08xh,%08xh) not implemented.\n",
           hService,
           dwServiceState,
           lpServices,
           cbBufSize,
           pcbBytesNeeded,
           lpServicesReturned));

  return (FALSE); /* signal failure */
}


/*****************************************************************************
 * Name      : EnumDependentServicesW
 * Purpose   : The EnumDependentServices function enumerates services that
 *             depend on another specified service; that is, the specified
 *             service must be running before the enumerated services can run.
 *             The name and status of each dependent service are provided.
 * Parameters: SC_HANDLE             hService           handle of service
 *             DWORD                 dwServiceState     state of services to enumerate
 *             LPENUM_SERVICE_STATUS lpServices         address of service status buffer
 *             DWORD                 cbBufSize          size of service status buffer
 *             LPDWORD               pcbBytesNeeded     address of variable for bytes needed
 *             LPDWORD               lpServicesReturned address of variable for number returned
 * Variables :
 * Result    :
 * Remark    :
 * Status    : UNTESTED STUB
 *
 * Author    : Patrick Haller [Tue, 1998/06/16 23:00]
 *****************************************************************************/

BOOL WIN32API EnumDependentServicesW(SC_HANDLE             hService,
                                        DWORD                 dwServiceState,
                                        LPENUM_SERVICE_STATUSW lpServices,
                                        DWORD                 cbBufSize,
                                        LPDWORD               pcbBytesNeeded,
                                        LPDWORD               lpServicesReturned)
{
  dprintf(("ADVAPI32: EnumDependentServicesW(%08xh,%08xh,%08xh,%08xh,%08xh,%08xh) not implemented.\n",
           hService,
           dwServiceState,
           lpServices,
           cbBufSize,
           pcbBytesNeeded,
           lpServicesReturned));

  return (FALSE); /* signal failure */
}


/*****************************************************************************
 * Name      : EnumServicesStatusA
 * Purpose   : The EnumServicesStatus function enumerates services in the specified
 *             service control manager database. The name and status of each service are provided.
 * Parameters: SC_HANDLE             hSCManager          handle of service control manager database
 *             DWORD                 dwServiceType       type of services to enumerate
 *             DWORD                 dwServiceState      state of services to enumerate
 *             LPENUM_SERVICE_STATUS lpServices          address of service status buffer
 *             DWORD                 cbBufSize           size of service status buffer
 *             LPDWORD               pcbBytesNeeded      address of variable for bytes needed
 *             LPDWORD               lpServicesReturned  address of variable for number returned
 *             LPDWORD               lpResumeHandle      address of variable for next entry
 * Variables :
 * Result    :
 * Remark    :
 * Status    : UNTESTED STUB
 *
 * Author    : Patrick Haller [Tue, 1998/06/16 23:00]
 *****************************************************************************/

BOOL WIN32API EnumServicesStatusA(SC_HANDLE             hSCManager,
                                  DWORD                 dwServiceType,
                                  DWORD                 dwServiceState,
                                  LPENUM_SERVICE_STATUSA lpServices,
                                  DWORD                 cbBufSize,
                                  LPDWORD               pcbBytesNeeded,
                                  LPDWORD               lpServicesReturned,
                                  LPDWORD               lpResumeHandle)
{
  dprintf(("ADVAPI32: EnumServicesStatusA(%08xh,%08xh,%08xh,%08xh,%08xh,%08xh,%08xh,%08xh) not implemented.\n",
           hSCManager,
           dwServiceType,
           dwServiceState,
           lpServices,
           cbBufSize,
           pcbBytesNeeded,
           lpServicesReturned,
           lpResumeHandle));

  if(lpServicesReturned) {
      *lpServicesReturned = 0;
  }
  if(pcbBytesNeeded) {
      *pcbBytesNeeded = sizeof(ENUM_SERVICE_STATUSA);
  }
  return TRUE; /* signal failure */
}


/*****************************************************************************
 * Name      : EnumServicesStatusW
 * Purpose   : The EnumServicesStatus function enumerates services in the specified
 *             service control manager database. The name and status of each service are provided.
 * Parameters: SC_HANDLE             hSCManager          handle of service control manager database
 *             DWORD                 dwServiceType       type of services to enumerate
 *             DWORD                 dwServiceState      state of services to enumerate
 *             LPENUM_SERVICE_STATUS lpServices          address of service status buffer
 *             DWORD                 cbBufSize           size of service status buffer
 *             LPDWORD               pcbBytesNeeded      address of variable for bytes needed
 *             LPDWORD               lpServicesReturned  address of variable for number returned
 *             LPDWORD               lpResumeHandle      address of variable for next entry
 * Variables :
 * Result    :
 * Remark    :
 * Status    : UNTESTED STUB
 *
 * Author    : Patrick Haller [Tue, 1998/06/16 23:00]
 *****************************************************************************/

BOOL WIN32API EnumServicesStatusW(SC_HANDLE             hSCManager,
                                     DWORD                 dwServiceType,
                                     DWORD                 dwServiceState,
                                     LPENUM_SERVICE_STATUSW lpServices,
                                     DWORD                 cbBufSize,
                                     LPDWORD               pcbBytesNeeded,
                                     LPDWORD               lpServicesReturned,
                                     LPDWORD               lpResumeHandle)
{
  dprintf(("ADVAPI32: EnumServicesStatusW(%08xh,%08xh,%08xh,%08xh,%08xh,%08xh,%08xh,%08xh) not implemented.\n",
           hSCManager,
           dwServiceType,
           dwServiceState,
           lpServices,
           cbBufSize,
           pcbBytesNeeded,
           lpServicesReturned,
           lpResumeHandle));

  if(lpServicesReturned) {
      *lpServicesReturned = 0;
  }
  if(pcbBytesNeeded) {
      *pcbBytesNeeded = sizeof(ENUM_SERVICE_STATUSA);
  }
  return TRUE; /* signal failure */
}

/*****************************************************************************
 * Name      : GetServiceKeyNameA
 * Purpose   : The GetServiceKeyName function obtains the service name that is
 *             associated with a particular service's display name. The service
 *             name is the same as the service's registry key name.
 * Parameters: SC_HANDLE hSCManager     handle to a service control manager database
 *             LPCSTR   lpDisplayName  the service's display name
 *             LPTSTR    lpServiceName  buffer to receive the service name
 *             LPDWORD   lpcchBuffer    size of service name buffer and service name
 * Variables :
 * Result    :
 * Remark    :
 * Status    : UNTESTED STUB
 *
 * Author    : Patrick Haller [Tue, 1998/06/16 23:00]
 *****************************************************************************/

BOOL WIN32API GetServiceKeyNameA(SC_HANDLE hSCManager,
                                 LPCSTR    lpDisplayName,
                                 LPTSTR    lpServiceName,
                                 LPDWORD   lpcchBuffer)
{
  dprintf(("ADVAPI32: GetServiceKeyNameA(%08xh,%08xh,%08xh,%08xh) not implemented.\n",
           hSCManager,
           lpDisplayName,
           lpServiceName,
           lpcchBuffer));

  return (FALSE); /* signal failure */
}


/*****************************************************************************
 * Name      : GetServiceKeyNameW
 * Purpose   : The GetServiceKeyName function obtains the service name that is
 *             associated with a particular service's display name. The service
 *             name is the same as the service's registry key name.
 * Parameters: SC_HANDLE hSCManager     handle to a service control manager database
 *             LPCWSTR   lpDisplayName  the service's display name
 *             LPWSTR    lpServiceName  buffer to receive the service name
 *             LPDWORD   lpcchBuffer    size of service name buffer and service name
 * Variables :
 * Result    :
 * Remark    :
 * Status    : UNTESTED STUB
 *
 * Author    : Patrick Haller [Tue, 1998/06/16 23:00]
 *****************************************************************************/

BOOL WIN32API GetServiceKeyNameW(SC_HANDLE hSCManager,
                                    LPCWSTR   lpDisplayName,
                                    LPWSTR    lpServiceName,
                                    LPDWORD   lpcchBuffer)
{
  dprintf(("ADVAPI32: GetServiceKeyNameW(%08xh,%08xh,%08xh,%08xh) not implemented.\n",
           hSCManager,
           lpDisplayName,
           lpServiceName,
           lpcchBuffer));

  return (FALSE); /* signal failure */
}

/*****************************************************************************
 * Name      : LockServiceDatabase
 * Purpose   : The LockServiceDatabase function locks a specified database.
 * Parameters: SC_HANDLE  hSCManager  handle of service control manager database
 * Variables :
 * Result    :
 * Remark    :
 * Status    : UNTESTED STUB
 *
 * Author    : Patrick Haller [Tue, 1998/06/16 23:00]
 *****************************************************************************/

SC_LOCK WIN32API LockServiceDatabase(SC_HANDLE hSCManager)
{
  dprintf(("ADVAPI32: LockServiceDatabase(%08xh) not implemented.\n",
           hSCManager));

  return 0; /* signal failure */
}

/*****************************************************************************
 * Name      : UnlockServiceDatabase
 * Purpose   : The UnlockServiceDatabase function unlocks a service control
 *             manager database by releasing the specified lock.
 * Parameters: SC_LOCK  sclLock  service control manager database lock to be released
 * Variables :
 * Result    :
 * Remark    :
 * Status    : UNTESTED STUB
 *
 * Author    : Patrick Haller [Tue, 1998/06/16 23:00]

 *****************************************************************************/

BOOL WIN32API UnlockServiceDatabase(SC_LOCK sclLock)
{
  dprintf(("ADVAPI32: UnlockServiceDatabase(%08xh) not implemented.\n",
           sclLock));

  return (FALSE); /* signal failure */
}

//******************************************************************************
//Helper for StartServiceCtrlDispatcherA/W; counts nr or arguments in cmd line
//******************************************************************************
ULONG CountNrArgs(char *cmdline)
{
 char *cmd = cmdline;
 ULONG nrargs = 0;

  while(*cmd == ' ') cmd++; //skip leading spaces
  while(*cmd != 0) {
	while(*cmd != ' ' && *cmd != 0) cmd++; //skip non-space chars
	while(*cmd == ' ' && *cmd != 0) cmd++; //skip spaces
	nrargs++;
  }
  return nrargs;
}

/*****************************************************************************
 * Name      : StartServiceCtrlDispatcherW
 * Purpose   : The StartServiceCtrlDispatcher function connects the main thread
 *             of a service process to the service control manager, which causes
 *             the thread to be the service control dispatcher thread for the calling process.
 * Parameters: LPSERVICE_TABLE_ENTRY  lpsteServiceTable  address of service table
 * Variables :
 * Result    :
 * Remark    :
 * Status    :
 *
 * Author    : SvL
 *****************************************************************************/

BOOL WIN32API StartServiceCtrlDispatcherW(LPSERVICE_TABLE_ENTRYW lpsteServiceTable)
{
 ULONG nrArgs = 0;
 LPWSTR cmdline;

  dprintf(("ADVAPI32: StartServiceCtrlDispatcherW(%x)", lpsteServiceTable));

  if(fServiceCtrlDispatcherStarted == TRUE) {
	SetLastError(ERROR_SERVICE_ALREADY_RUNNING);
	return FALSE;
  }
  fServiceCtrlDispatcherStarted = TRUE;
  if(lpsteServiceTable->lpServiceProc == NULL) {
	SetLastError(ERROR_INVALID_DATA); //or invalid parameter?
	return FALSE;
  }
  while(lpsteServiceTable->lpServiceProc) {
	cmdline = (LPWSTR)GetCommandLineW();
	nrArgs  = CountNrArgs((LPSTR)GetCommandLineA());
	lpsteServiceTable->lpServiceProc(nrArgs, cmdline);
	lpsteServiceTable++; //next service entrypoint
  }
  SetLastError(0);
  return TRUE;
}

/*****************************************************************************
 * Name      : StartServiceCtrlDispatcherA
 * Purpose   : The StartServiceCtrlDispatcher function connects the main thread
 *             of a service process to the service control manager, which causes
 *             the thread to be the service control dispatcher thread for the calling process.
 * Parameters: LPSERVICE_TABLE_ENTRY  lpsteServiceTable  address of service table
 * Variables :
 * Result    :
 * Remark    :
 * Status    :
 *
 * Author    : SvL
 *****************************************************************************/

BOOL WIN32API StartServiceCtrlDispatcherA(LPSERVICE_TABLE_ENTRYA lpsteServiceTable)
{
 ULONG nrArgs = 0;
 LPSTR cmdline;

  dprintf(("ADVAPI32: StartServiceCtrlDispatcherA(%08xh)", lpsteServiceTable));

  if(fServiceCtrlDispatcherStarted == TRUE) {
	SetLastError(ERROR_SERVICE_ALREADY_RUNNING);
	return FALSE;
  }
  fServiceCtrlDispatcherStarted = TRUE;
  if(lpsteServiceTable->lpServiceProc == NULL) {
	SetLastError(ERROR_INVALID_DATA); //or invalid parameter?
	return FALSE;
  }
  while(lpsteServiceTable->lpServiceProc) {
	cmdline = (LPSTR)GetCommandLineA();
	nrArgs  = CountNrArgs(cmdline);
	lpsteServiceTable->lpServiceProc(nrArgs, cmdline);
	lpsteServiceTable++; //next service entrypoint
  }
  SetLastError(0);
  return TRUE;
}

/*****************************************************************************
 * Name      : RegisterServiceCtrlHandlerA
 * Purpose   : The RegisterServiceCtrlHandler function registers a function to
 *             handle service control requests for a service.
 * Parameters: LPCSTR            lpszServiceName address of name of service
 *             LPHANDLER_FUNCTION lpHandlerProc   address of handler function
 * Variables :
 * Result    :
 * Remark    :
 * Status    :
 *
 * Author    : SvL
 *****************************************************************************/

SERVICE_STATUS_HANDLE WIN32API RegisterServiceCtrlHandlerA(LPCSTR            lpszServiceName,
                                                           LPHANDLER_FUNCTION lpHandlerProc)
{
 SC_HANDLE hSCMgr, hService;

  dprintf(("ADVAPI32: RegisterServiceCtrlHandlerA(%s,%08xh) not implemented (FAKED)",
           lpszServiceName,
           lpHandlerProc));

  //Doesn't work for services of type
  if(lpszServiceName == NULL) {
	SetLastError(ERROR_INVALID_NAME);
	return 0;
  }
  hSCMgr = OpenSCManagerA(NULL, NULL, SC_MANAGER_ALL_ACCESS);
  hService = OpenServiceA(hSCMgr, lpszServiceName, SERVICE_ALL_ACCESS);
  if(hService == 0) {
	SetLastError(ERROR_INVALID_NAME);
	return 0;
  }
  CloseServiceHandle(hSCMgr);
  //TODO: Start thread with ctrl handler
  SetLastError(0);
  return hService;
}


/*****************************************************************************
 * Name      : RegisterServiceCtrlHandlerW
 * Purpose   : The RegisterServiceCtrlHandler function registers a function to
 *             handle service control requests for a service.
 * Parameters: LPCWSTR            lpszServiceName address of name of service
 *             LPHANDLER_FUNCTION lpHandlerProc   address of handler function
 * Variables :
 * Result    :
 * Remark    :
 * Status    :
 *
 * Author    : SvL
 *****************************************************************************/

SERVICE_STATUS_HANDLE WIN32API RegisterServiceCtrlHandlerW(LPCWSTR            lpszServiceName,
                                                           LPHANDLER_FUNCTION lpHandlerProc)
{
 SC_HANDLE hSCMgr, hService;

  dprintf(("ADVAPI32: RegisterServiceCtrlHandlerW(%s,%08xh) not implemented (FAKED)",
           lpszServiceName,
           lpHandlerProc));

  //Doesn't work for services of type
  if(lpszServiceName == NULL) {
	SetLastError(ERROR_INVALID_NAME);
	return 0;
  }
  hSCMgr = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
  hService = OpenServiceW(hSCMgr, lpszServiceName, SERVICE_ALL_ACCESS);
  if(hService == 0) {
	SetLastError(ERROR_INVALID_NAME);
	return 0;
  }
  CloseServiceHandle(hSCMgr);
  //TODO: Start thread with ctrl handler
  SetLastError(0);
  return hService;
}

/*****************************************************************************
 * Name      : SetServiceBits
 * Purpose   : The SetServiceBits function registers a service's service type
 *             with the Service Control Manager and the Server service. The
 *             Server service can then announce the registered service type
 *             as one it currently supports. The LAN Manager functions
 *             NetServerGetInfo and NetServerEnum obtain a specified machine's
 *             supported service types.
 *             A service type is represented as a set of bit flags; the
 *             SetServiceBits function sets or clears combinations of those bit flags.
 * Parameters: SERVICE_STATUS_HANDLE hServiceStatus     service status handle
 *             DWORD                 dwServiceBits      service type bits to set or clear
 *             BOOL                  bSetBitsOn         flag to set or clear the service type bits
 *             BOOL                  bUpdateImmediately flag to announce server type immediately
 * Variables :
 * Result    :
 * Remark    :
 * Status    :
 *
 * Author    : SvL
 *****************************************************************************/

BOOL WIN32API SetServiceBits(SERVICE_STATUS_HANDLE hServiceStatus,
                             DWORD              dwServiceBits,
                             BOOL               bSetBitsOn,
                             BOOL               bUpdateImmediately)
{
 ULONG size, keytype, servicebits;

  dprintf(("ADVAPI32: SetServiceBits(%08xh,%08xh,%08xh,%08xh) not correctly implemented",
           hServiceStatus,
           dwServiceBits,
           bSetBitsOn,
           bUpdateImmediately));

  if(CheckServiceHandle(hServiceStatus) == FALSE) {
	SetLastError(ERROR_INVALID_PARAMETER);
	return FALSE;
  }
  //According to the Platform SDK these bits are reserved by MS and we should return
  //ERROR_INVALID_DATA
  if(dwServiceBits & 0xC00F3F7B) {
	SetLastError(ERROR_INVALID_DATA);
	return FALSE;
  }

  size = sizeof(DWORD);
  keytype = REG_DWORD;
  if(RegQueryValueExA((HKEY)hServiceStatus, REG_SERVICE_BITS, 0, &keytype, (LPBYTE)&servicebits, &size)) {
	servicebits = 0;
  }
  if(bSetBitsOn) {
	servicebits |= dwServiceBits;
  }
  else 	servicebits &= (~dwServiceBits);

  if(!RegSetValueExA((HKEY)hServiceStatus, REG_SERVICE_BITS, 0, REG_DWORD, (LPBYTE)&servicebits, sizeof(DWORD))) {
	SetLastError(0);
	return TRUE;
  }
  return (FALSE); /* signal failure */
}

/*****************************************************************************
 * Name      : SetServiceStatus
 * Purpose   : The SetServiceStatus function updates the service control
 *             manager's status information for the calling service.
 * Parameters: SERVICE_STATUS_HANDLE sshServiceStatus  service status handle
 *             LPSERVICE_STATUS      lpssServiceStatus address of status structure
 * Variables :
 * Result    :
 * Remark    : Called from ServiceMain function (registered with RegisterServiceCtrlHandler)
 * Status    :
 *
 * Author    : SvL
 *****************************************************************************/

BOOL WIN32API SetServiceStatus(SERVICE_STATUS_HANDLE sshServiceStatus,
                               LPSERVICE_STATUS      lpssServiceStatus)
{
  dprintf(("ADVAPI32: SetServiceStatus(%08xh,%08xh) not implemented correctly.\n",
           sshServiceStatus,
           lpssServiceStatus));

  if(CheckServiceHandle(sshServiceStatus) == FALSE) {
	SetLastError(ERROR_INVALID_PARAMETER);
	return FALSE;
  }

  RegSetValueExA((HKEY)sshServiceStatus, REG_SERVICE_TYPE, 0, REG_DWORD, (LPBYTE)&lpssServiceStatus->dwServiceType, sizeof(DWORD));
  RegSetValueExA((HKEY)sshServiceStatus, REG_SERVICE_STATUS, 0, REG_DWORD, (LPBYTE)&lpssServiceStatus->dwCurrentState, sizeof(DWORD));
  RegSetValueExA((HKEY)sshServiceStatus, REG_SERVICE_CONTROLS_ACCEPTED, 0, REG_DWORD, (LPBYTE)&lpssServiceStatus->dwControlsAccepted, sizeof(DWORD));

  RegSetValueExA((HKEY)sshServiceStatus, REG_SERVICE_EXITCODE, 0, REG_DWORD, (LPBYTE)&lpssServiceStatus->dwWin32ExitCode, sizeof(DWORD));
  RegSetValueExA((HKEY)sshServiceStatus, REG_SERVICE_SPECIFIC_EXITCODE, 0, REG_DWORD, (LPBYTE)&lpssServiceStatus->dwServiceSpecificExitCode, sizeof(DWORD));

  RegSetValueExA((HKEY)sshServiceStatus, REG_SERVICE_CHECKPOINT, 0, REG_DWORD, (LPBYTE)&lpssServiceStatus->dwCheckPoint, sizeof(DWORD));
  RegSetValueExA((HKEY)sshServiceStatus, REG_SERVICE_WAITHINT, 0, REG_DWORD, (LPBYTE)&lpssServiceStatus->dwWaitHint, sizeof(DWORD));

  SetLastError(0);
  return TRUE;
}

/*****************************************************************************
 * Name      : QueryServiceStatus
 * Purpose   : The QueryServiceStatus function retrieves the current status of
 *             the specified service.
 * Parameters: SC_HANDLE         schService        handle of service
 *             LPSERVICE_STATUS  lpssServiceStatus address of service status structure
 * Variables :
 * Result    :
 * Remark    :
 * Status    :
 *
 * Author    : SvL
 *****************************************************************************/

BOOL WIN32API QueryServiceStatus(SC_HANDLE         schService,
                                 LPSERVICE_STATUS  lpssServiceStatus)
{
 DWORD size, keytype;

  dprintf(("ADVAPI32: QueryServiceStatus(%08xh,%08xh) not correctly implemented.\n",
           schService,
           lpssServiceStatus));

  if(CheckServiceHandle(schService) == FALSE) {
	SetLastError(ERROR_INVALID_PARAMETER);
	return FALSE;
  }

  memset(lpssServiceStatus, 0, sizeof(SERVICE_STATUS));

  size = sizeof(DWORD);
  keytype = REG_DWORD;
  RegQueryValueExA((HKEY)schService, REG_SERVICE_TYPE, 0, &keytype, (LPBYTE)&lpssServiceStatus->dwServiceType, &size);

  size = sizeof(DWORD);
  keytype = REG_DWORD;
  RegQueryValueExA((HKEY)schService, REG_SERVICE_STATUS, 0, &keytype, (LPBYTE)&lpssServiceStatus->dwCurrentState, &size);

  size = sizeof(DWORD);
  keytype = REG_DWORD;
  RegQueryValueExA((HKEY)schService, REG_SERVICE_CONTROLS_ACCEPTED, 0, &keytype, (LPBYTE)&lpssServiceStatus->dwControlsAccepted, &size);

  size = sizeof(DWORD);
  keytype = REG_DWORD;
  RegQueryValueExA((HKEY)schService, REG_SERVICE_EXITCODE, 0, &keytype, (LPBYTE)&lpssServiceStatus->dwWin32ExitCode, &size);

  size = sizeof(DWORD);
  keytype = REG_DWORD;
  RegQueryValueExA((HKEY)schService, REG_SERVICE_SPECIFIC_EXITCODE, 0, &keytype, (LPBYTE)&lpssServiceStatus->dwServiceSpecificExitCode, &size);

  size = sizeof(DWORD);
  keytype = REG_DWORD;
  RegQueryValueExA((HKEY)schService, REG_SERVICE_CHECKPOINT, 0, &keytype, (LPBYTE)&lpssServiceStatus->dwCheckPoint, &size);

  size = sizeof(DWORD);
  keytype = REG_DWORD;
  RegQueryValueExA((HKEY)schService, REG_SERVICE_WAITHINT, 0, &keytype, (LPBYTE)&lpssServiceStatus->dwWaitHint, &size);

  SetLastError(0);
  return TRUE;
}
