|  | /* | 
|  | * Win32 advapi functions | 
|  | * | 
|  | * Copyright 1995 Sven Verdoolaege | 
|  | */ | 
|  |  | 
|  | #include <time.h> | 
|  |  | 
|  | #include "windef.h" | 
|  | #include "winsvc.h" | 
|  | #include "winerror.h" | 
|  | #include "winreg.h" | 
|  | #include "wine/unicode.h" | 
|  | #include "heap.h" | 
|  | #include "debugtools.h" | 
|  |  | 
|  | DEFAULT_DEBUG_CHANNEL(advapi); | 
|  |  | 
|  | static DWORD   start_dwNumServiceArgs; | 
|  | static LPWSTR *start_lpServiceArgVectors; | 
|  |  | 
|  | /****************************************************************************** | 
|  | * EnumServicesStatusA [ADVAPI32.@] | 
|  | */ | 
|  | BOOL WINAPI | 
|  | EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType, | 
|  | DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices, | 
|  | DWORD cbBufSize, LPDWORD pcbBytesNeeded, | 
|  | LPDWORD lpServicesReturned, LPDWORD lpResumeHandle ) | 
|  | {	FIXME("%x type=%lx state=%lx %p %lx %p %p %p\n", hSCManager, | 
|  | dwServiceType, dwServiceState, lpServices, cbBufSize, | 
|  | pcbBytesNeeded, lpServicesReturned,  lpResumeHandle); | 
|  | SetLastError (ERROR_ACCESS_DENIED); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /****************************************************************************** | 
|  | * EnumServicesStatusW [ADVAPI32.@] | 
|  | */ | 
|  | BOOL WINAPI | 
|  | EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType, | 
|  | DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices, | 
|  | DWORD cbBufSize, LPDWORD pcbBytesNeeded, | 
|  | LPDWORD lpServicesReturned, LPDWORD lpResumeHandle ) | 
|  | {	FIXME("%x type=%lx state=%lx %p %lx %p %p %p\n", hSCManager, | 
|  | dwServiceType, dwServiceState, lpServices, cbBufSize, | 
|  | pcbBytesNeeded, lpServicesReturned,  lpResumeHandle); | 
|  | SetLastError (ERROR_ACCESS_DENIED); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /****************************************************************************** | 
|  | * StartServiceCtrlDispatcherA [ADVAPI32.196] | 
|  | */ | 
|  | BOOL WINAPI | 
|  | StartServiceCtrlDispatcherA( LPSERVICE_TABLE_ENTRYA servent ) | 
|  | { | 
|  | LPSERVICE_MAIN_FUNCTIONA fpMain; | 
|  | HANDLE wait; | 
|  | DWORD  dwNumServiceArgs ; | 
|  | LPWSTR *lpArgVecW; | 
|  | LPSTR  *lpArgVecA; | 
|  | int i; | 
|  |  | 
|  | TRACE("(%p)\n", servent); | 
|  | wait = OpenSemaphoreA(SEMAPHORE_ALL_ACCESS, FALSE, "ADVAPI32_ServiceStartData"); | 
|  | if(wait == 0) | 
|  | { | 
|  | ERR("Couldn't find wait semaphore\n"); | 
|  | ERR("perhaps you need to start services using StartService\n"); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | dwNumServiceArgs = start_dwNumServiceArgs; | 
|  | lpArgVecW        = start_lpServiceArgVectors; | 
|  |  | 
|  | ReleaseSemaphore(wait, 1, NULL); | 
|  |  | 
|  | /* Convert the Unicode arg vectors back to ASCII */ | 
|  | if(dwNumServiceArgs) | 
|  | lpArgVecA = (LPSTR*) HeapAlloc( GetProcessHeap(), 0, | 
|  | dwNumServiceArgs*sizeof(LPSTR) ); | 
|  | else | 
|  | lpArgVecA = NULL; | 
|  |  | 
|  | for(i=0; i<dwNumServiceArgs; i++) | 
|  | lpArgVecA[i]=HEAP_strdupWtoA(GetProcessHeap(), 0, lpArgVecW[i]); | 
|  |  | 
|  | /* FIXME: should we blindly start all services? */ | 
|  | while (servent->lpServiceName) { | 
|  | TRACE("%s at %p)\n", debugstr_a(servent->lpServiceName),servent); | 
|  | fpMain = servent->lpServiceProc; | 
|  |  | 
|  | /* try to start the service */ | 
|  | fpMain( dwNumServiceArgs, lpArgVecA); | 
|  |  | 
|  | servent++; | 
|  | } | 
|  |  | 
|  | if(dwNumServiceArgs) | 
|  | { | 
|  | /* free arg strings */ | 
|  | for(i=0; i<dwNumServiceArgs; i++) | 
|  | HeapFree(GetProcessHeap(), 0, lpArgVecA[i]); | 
|  | HeapFree(GetProcessHeap(), 0, lpArgVecA); | 
|  | } | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | /****************************************************************************** | 
|  | * StartServiceCtrlDispatcherW [ADVAPI32.197] | 
|  | * | 
|  | * PARAMS | 
|  | *   servent [] | 
|  | */ | 
|  | BOOL WINAPI | 
|  | StartServiceCtrlDispatcherW( LPSERVICE_TABLE_ENTRYW servent ) | 
|  | { | 
|  | LPSERVICE_MAIN_FUNCTIONW fpMain; | 
|  | HANDLE wait; | 
|  | DWORD  dwNumServiceArgs ; | 
|  | LPWSTR *lpServiceArgVectors ; | 
|  |  | 
|  | TRACE("(%p)\n", servent); | 
|  | wait = OpenSemaphoreA(SEMAPHORE_ALL_ACCESS, FALSE, "ADVAPI32_ServiceStartData"); | 
|  | if(wait == 0) | 
|  | { | 
|  | ERR("Couldn't find wait semaphore\n"); | 
|  | ERR("perhaps you need to start services using StartService\n"); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | dwNumServiceArgs    = start_dwNumServiceArgs; | 
|  | lpServiceArgVectors = start_lpServiceArgVectors; | 
|  |  | 
|  | ReleaseSemaphore(wait, 1, NULL); | 
|  |  | 
|  | /* FIXME: should we blindly start all services? */ | 
|  | while (servent->lpServiceName) { | 
|  | TRACE("%s at %p)\n", debugstr_w(servent->lpServiceName),servent); | 
|  | fpMain = servent->lpServiceProc; | 
|  |  | 
|  | /* try to start the service */ | 
|  | fpMain( dwNumServiceArgs, lpServiceArgVectors); | 
|  |  | 
|  | servent++; | 
|  | } | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | /****************************************************************************** | 
|  | * RegisterServiceCtrlHandlerA [ADVAPI32.176] | 
|  | */ | 
|  | SERVICE_STATUS_HANDLE WINAPI | 
|  | RegisterServiceCtrlHandlerA( LPCSTR lpServiceName, | 
|  | LPHANDLER_FUNCTION lpfHandler ) | 
|  | {	FIXME("%s %p\n", lpServiceName, lpfHandler); | 
|  | return 0xcacacafe; | 
|  | } | 
|  |  | 
|  | /****************************************************************************** | 
|  | * RegisterServiceCtrlHandlerW [ADVAPI32.177] | 
|  | * | 
|  | * PARAMS | 
|  | *   lpServiceName [] | 
|  | *   lpfHandler    [] | 
|  | */ | 
|  | SERVICE_STATUS_HANDLE WINAPI | 
|  | RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName, | 
|  | LPHANDLER_FUNCTION lpfHandler ) | 
|  | {	FIXME("%s %p\n", debugstr_w(lpServiceName), lpfHandler); | 
|  | return 0xcacacafe; | 
|  | } | 
|  |  | 
|  | /****************************************************************************** | 
|  | * SetServiceStatus [ADVAPI32.192] | 
|  | * | 
|  | * PARAMS | 
|  | *   hService [] | 
|  | *   lpStatus [] | 
|  | */ | 
|  | BOOL WINAPI | 
|  | SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus ) | 
|  | {	FIXME("%lx %p\n",hService, lpStatus); | 
|  | TRACE("\tType:%lx\n",lpStatus->dwServiceType); | 
|  | TRACE("\tState:%lx\n",lpStatus->dwCurrentState); | 
|  | TRACE("\tControlAccepted:%lx\n",lpStatus->dwControlsAccepted); | 
|  | TRACE("\tExitCode:%lx\n",lpStatus->dwWin32ExitCode); | 
|  | TRACE("\tServiceExitCode:%lx\n",lpStatus->dwServiceSpecificExitCode); | 
|  | TRACE("\tCheckPoint:%lx\n",lpStatus->dwCheckPoint); | 
|  | TRACE("\tWaitHint:%lx\n",lpStatus->dwWaitHint); | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | /****************************************************************************** | 
|  | * OpenSCManagerA [ADVAPI32.110] | 
|  | */ | 
|  | SC_HANDLE WINAPI | 
|  | OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName, | 
|  | DWORD dwDesiredAccess ) | 
|  | { | 
|  | LPWSTR lpMachineNameW = HEAP_strdupAtoW(GetProcessHeap(),0,lpMachineName); | 
|  | LPWSTR lpDatabaseNameW = HEAP_strdupAtoW(GetProcessHeap(),0,lpDatabaseName); | 
|  | DWORD ret = OpenSCManagerW(lpMachineNameW,lpDatabaseNameW, | 
|  | dwDesiredAccess); | 
|  | HeapFree(GetProcessHeap(),0,lpDatabaseNameW); | 
|  | HeapFree(GetProcessHeap(),0,lpMachineNameW); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /****************************************************************************** | 
|  | * OpenSCManagerW [ADVAPI32.111] | 
|  | * Establishes a connection to the service control manager and opens database | 
|  | * | 
|  | * NOTES | 
|  | *   This should return a SC_HANDLE | 
|  | * | 
|  | * PARAMS | 
|  | *   lpMachineName   [I] Pointer to machine name string | 
|  | *   lpDatabaseName  [I] Pointer to database name string | 
|  | *   dwDesiredAccess [I] Type of access | 
|  | * | 
|  | * RETURNS | 
|  | *   Success: Handle to service control manager database | 
|  | *   Failure: NULL | 
|  | */ | 
|  | SC_HANDLE WINAPI | 
|  | OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName, | 
|  | DWORD dwDesiredAccess ) | 
|  | { | 
|  | HKEY hKey; | 
|  | LONG r; | 
|  |  | 
|  | TRACE("(%s,%s,0x%08lx)\n", debugstr_w(lpMachineName), | 
|  | debugstr_w(lpDatabaseName), dwDesiredAccess); | 
|  |  | 
|  | /* | 
|  | * FIXME: what is lpDatabaseName? | 
|  | * It should be set to "SERVICES_ACTIVE_DATABASE" according to | 
|  | * docs, but what if it isn't? | 
|  | */ | 
|  |  | 
|  | r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hKey); | 
|  | if (r!=ERROR_SUCCESS) | 
|  | return 0; | 
|  |  | 
|  | TRACE("returning %x\n",hKey); | 
|  |  | 
|  | return hKey; | 
|  | } | 
|  |  | 
|  |  | 
|  | /****************************************************************************** | 
|  | * AllocateLocallyUniqueId [ADVAPI32.12] | 
|  | * | 
|  | * PARAMS | 
|  | *   lpluid [] | 
|  | */ | 
|  | BOOL WINAPI | 
|  | AllocateLocallyUniqueId( PLUID lpluid ) | 
|  | { | 
|  | lpluid->s.LowPart = time(NULL); | 
|  | lpluid->s.HighPart = 0; | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  |  | 
|  | /****************************************************************************** | 
|  | * ControlService [ADVAPI32.23] | 
|  | * Sends a control code to a Win32-based service. | 
|  | * | 
|  | * PARAMS | 
|  | *   hService        [] | 
|  | *   dwControl       [] | 
|  | *   lpServiceStatus [] | 
|  | * | 
|  | * RETURNS STD | 
|  | */ | 
|  | BOOL WINAPI | 
|  | ControlService( SC_HANDLE hService, DWORD dwControl, | 
|  | LPSERVICE_STATUS lpServiceStatus ) | 
|  | { | 
|  | FIXME("(%d,%ld,%p): stub\n",hService,dwControl,lpServiceStatus); | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  |  | 
|  | /****************************************************************************** | 
|  | * CloseServiceHandle [ADVAPI32.22] | 
|  | * Close handle to service or service control manager | 
|  | * | 
|  | * PARAMS | 
|  | *   hSCObject [I] Handle to service or service control manager database | 
|  | * | 
|  | * RETURNS STD | 
|  | */ | 
|  | BOOL WINAPI | 
|  | CloseServiceHandle( SC_HANDLE hSCObject ) | 
|  | { | 
|  | TRACE("(%x)\n", hSCObject); | 
|  |  | 
|  | RegCloseKey(hSCObject); | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  |  | 
|  | /****************************************************************************** | 
|  | * OpenServiceA [ADVAPI32.112] | 
|  | */ | 
|  | SC_HANDLE WINAPI | 
|  | OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName, | 
|  | DWORD dwDesiredAccess ) | 
|  | { | 
|  | LPWSTR lpServiceNameW = HEAP_strdupAtoW(GetProcessHeap(),0,lpServiceName); | 
|  | DWORD ret; | 
|  |  | 
|  | if(lpServiceName) | 
|  | TRACE("Request for service %s\n",lpServiceName); | 
|  | else | 
|  | return FALSE; | 
|  | ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess); | 
|  | HeapFree(GetProcessHeap(),0,lpServiceNameW); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  |  | 
|  | /****************************************************************************** | 
|  | * OpenServiceW [ADVAPI32.113] | 
|  | * Opens a handle to an existing service | 
|  | * | 
|  | * PARAMS | 
|  | *   hSCManager      [] | 
|  | *   lpServiceName   [] | 
|  | *   dwDesiredAccess [] | 
|  | * | 
|  | * RETURNS | 
|  | *    Success: Handle to the service | 
|  | *    Failure: NULL | 
|  | */ | 
|  | SC_HANDLE WINAPI | 
|  | OpenServiceW(SC_HANDLE hSCManager, LPCWSTR lpServiceName, | 
|  | DWORD dwDesiredAccess) | 
|  | { | 
|  | const char *str = "System\\CurrentControlSet\\Services\\"; | 
|  | WCHAR lpServiceKey[80]; /* FIXME: this should be dynamically allocated */ | 
|  | HKEY hKey; | 
|  | long r; | 
|  |  | 
|  | TRACE("(%d,%p,%ld)\n",hSCManager, lpServiceName, | 
|  | dwDesiredAccess); | 
|  |  | 
|  | lstrcpyAtoW(lpServiceKey,str); | 
|  | strcatW(lpServiceKey,lpServiceName); | 
|  |  | 
|  | TRACE("Opening reg key %s\n", debugstr_w(lpServiceKey)); | 
|  |  | 
|  | /* FIXME: dwDesiredAccess may need some processing */ | 
|  | r = RegOpenKeyExW(hSCManager, lpServiceKey, 0, dwDesiredAccess, &hKey ); | 
|  | if (r!=ERROR_SUCCESS) | 
|  | return 0; | 
|  |  | 
|  | TRACE("returning %x\n",hKey); | 
|  |  | 
|  | return hKey; | 
|  | } | 
|  |  | 
|  | /****************************************************************************** | 
|  | * CreateServiceW [ADVAPI32.29] | 
|  | */ | 
|  | SC_HANDLE WINAPI | 
|  | CreateServiceW( DWORD 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 ) | 
|  | { | 
|  | FIXME("(%ld,%s,%s,...)\n", hSCManager, debugstr_w(lpServiceName), debugstr_w(lpDisplayName)); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  |  | 
|  | /****************************************************************************** | 
|  | * CreateServiceA [ADVAPI32.28] | 
|  | */ | 
|  | SC_HANDLE WINAPI | 
|  | CreateServiceA( DWORD 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 hKey; | 
|  | LONG r; | 
|  | DWORD dp; | 
|  |  | 
|  | TRACE("(%ld,%s,%s,...)\n", hSCManager, debugstr_a(lpServiceName), debugstr_a(lpDisplayName)); | 
|  |  | 
|  | r = RegCreateKeyExA(hSCManager, lpServiceName, 0, NULL, | 
|  | REG_OPTION_NON_VOLATILE, dwDesiredAccess, NULL, &hKey, &dp); | 
|  | if (r!=ERROR_SUCCESS) | 
|  | return 0; | 
|  | if (dp != REG_CREATED_NEW_KEY) | 
|  | return 0; | 
|  |  | 
|  | if(lpDisplayName) | 
|  | { | 
|  | r = RegSetValueExA(hKey, "DisplayName", 0, REG_SZ, lpDisplayName, strlen(lpDisplayName) ); | 
|  | if (r!=ERROR_SUCCESS) | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | r = RegSetValueExA(hKey, "Type", 0, REG_DWORD, (LPVOID)&dwServiceType, sizeof (DWORD) ); | 
|  | if (r!=ERROR_SUCCESS) | 
|  | return 0; | 
|  |  | 
|  | r = RegSetValueExA(hKey, "Start", 0, REG_DWORD, (LPVOID)&dwStartType, sizeof (DWORD) ); | 
|  | if (r!=ERROR_SUCCESS) | 
|  | return 0; | 
|  |  | 
|  | r = RegSetValueExA(hKey, "ErrorControl", 0, REG_DWORD, | 
|  | (LPVOID)&dwErrorControl, sizeof (DWORD) ); | 
|  | if (r!=ERROR_SUCCESS) | 
|  | return 0; | 
|  |  | 
|  | if(lpBinaryPathName) | 
|  | { | 
|  | r = RegSetValueExA(hKey, "ImagePath", 0, REG_SZ, | 
|  | lpBinaryPathName,strlen(lpBinaryPathName)+1 ); | 
|  | if (r!=ERROR_SUCCESS) | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | if(lpLoadOrderGroup) | 
|  | { | 
|  | r = RegSetValueExA(hKey, "Group", 0, REG_SZ, | 
|  | lpLoadOrderGroup, strlen(lpLoadOrderGroup)+1 ); | 
|  | if (r!=ERROR_SUCCESS) | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | r = RegSetValueExA(hKey, "ErrorControl", 0, REG_DWORD, | 
|  | (LPVOID)&dwErrorControl, sizeof (DWORD) ); | 
|  | if (r!=ERROR_SUCCESS) | 
|  | return 0; | 
|  |  | 
|  | if(lpDependencies) | 
|  | { | 
|  | DWORD len = 0; | 
|  |  | 
|  | /* determine the length of a double null terminated multi string */ | 
|  | do { | 
|  | len += (strlen(&lpDependencies[len])+1); | 
|  | } while (lpDependencies[len++]); | 
|  |  | 
|  | /* fixme: this should be unicode */ | 
|  | r = RegSetValueExA(hKey, "Dependencies", 0, REG_MULTI_SZ, | 
|  | lpDependencies, len ); | 
|  | if (r!=ERROR_SUCCESS) | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | if(lpPassword) | 
|  | { | 
|  | FIXME("Don't know how to add a Password for a service.\n"); | 
|  | } | 
|  |  | 
|  | if(lpServiceStartName) | 
|  | { | 
|  | FIXME("Don't know how to add a ServiceStartName for a service.\n"); | 
|  | } | 
|  |  | 
|  | return hKey; | 
|  | } | 
|  |  | 
|  |  | 
|  | /****************************************************************************** | 
|  | * DeleteService [ADVAPI32.31] | 
|  | * | 
|  | * PARAMS | 
|  | *    hService [I] Handle to service | 
|  | * | 
|  | * RETURNS STD | 
|  | * | 
|  | */ | 
|  | BOOL WINAPI | 
|  | DeleteService( SC_HANDLE hService ) | 
|  | { | 
|  | FIXME("(%d): stub\n",hService); | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  |  | 
|  | /****************************************************************************** | 
|  | * StartServiceA [ADVAPI32.195] | 
|  | * | 
|  | */ | 
|  | BOOL WINAPI | 
|  | StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs, | 
|  | LPCSTR *lpServiceArgVectors ) | 
|  | { | 
|  | LPWSTR *lpwstr=NULL; | 
|  | int i; | 
|  |  | 
|  | TRACE("(%d,%ld,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors); | 
|  |  | 
|  | if(dwNumServiceArgs) | 
|  | lpwstr = (LPWSTR*) HeapAlloc( GetProcessHeap(), 0, | 
|  | dwNumServiceArgs*sizeof(LPWSTR) ); | 
|  | else | 
|  | lpwstr = NULL; | 
|  |  | 
|  | for(i=0; i<dwNumServiceArgs; i++) | 
|  | lpwstr[i]=HEAP_strdupAtoW(GetProcessHeap(), 0, lpServiceArgVectors[i]); | 
|  |  | 
|  | StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr); | 
|  |  | 
|  | if(dwNumServiceArgs) | 
|  | { | 
|  | for(i=0; i<dwNumServiceArgs; i++) | 
|  | HeapFree(GetProcessHeap(), 0, lpwstr[i]); | 
|  | HeapFree(GetProcessHeap(), 0, lpwstr); | 
|  | } | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  |  | 
|  | /****************************************************************************** | 
|  | * StartServiceW [ADVAPI32.198] | 
|  | * Starts a service | 
|  | * | 
|  | * PARAMS | 
|  | *   hService            [I] Handle of service | 
|  | *   dwNumServiceArgs    [I] Number of arguments | 
|  | *   lpServiceArgVectors [I] Address of array of argument string pointers | 
|  | * | 
|  | * NOTES | 
|  | * | 
|  | * NT implements this function using an obscure RPC call... | 
|  | * | 
|  | * Might need to do a "setenv SystemRoot \\WINNT" in your .cshrc | 
|  | *   to get things like %SystemRoot%\\System32\\service.exe to load. | 
|  | * | 
|  | * Will only work for shared address space. How should the service | 
|  | *  args be transferred when address spaces are separated? | 
|  | * | 
|  | * Can only start one service at a time. | 
|  | * | 
|  | * Has no concept of priviledge. | 
|  | * | 
|  | * RETURNS STD | 
|  | * | 
|  | */ | 
|  | BOOL WINAPI | 
|  | StartServiceW( SC_HANDLE hService, DWORD dwNumServiceArgs, | 
|  | LPCWSTR *lpServiceArgVectors ) | 
|  | { | 
|  | CHAR path[MAX_PATH],str[MAX_PATH]; | 
|  | DWORD type,size; | 
|  | long r; | 
|  | HANDLE data,wait; | 
|  | PROCESS_INFORMATION procinfo; | 
|  | STARTUPINFOA startupinfo; | 
|  |  | 
|  | TRACE("(%d,%ld,%p)\n",hService,dwNumServiceArgs, | 
|  | lpServiceArgVectors); | 
|  |  | 
|  | size = sizeof str; | 
|  | r = RegQueryValueExA(hService, "ImagePath", NULL, &type, (LPVOID)str, &size); | 
|  | if (r!=ERROR_SUCCESS) | 
|  | return FALSE; | 
|  | ExpandEnvironmentStringsA(str,path,sizeof path); | 
|  |  | 
|  | TRACE("Starting service %s\n", debugstr_a(path) ); | 
|  |  | 
|  | data = CreateSemaphoreA(NULL,1,1,"ADVAPI32_ServiceStartData"); | 
|  | if(data == ERROR_INVALID_HANDLE) | 
|  | { | 
|  | data = OpenSemaphoreA(SEMAPHORE_ALL_ACCESS, FALSE, "ADVAPI32_ServiceStartData"); | 
|  | if(data == 0) | 
|  | { | 
|  | ERR("Couldn't create data semaphore\n"); | 
|  | return FALSE; | 
|  | } | 
|  | } | 
|  | wait = CreateSemaphoreA(NULL,0,1,"ADVAPI32_WaitServiceStart"); | 
|  | { | 
|  | wait = OpenSemaphoreA(SEMAPHORE_ALL_ACCESS, FALSE, "ADVAPI32_ServiceStartData"); | 
|  | if(wait == 0) | 
|  | { | 
|  | ERR("Couldn't create wait semaphore\n"); | 
|  | return FALSE; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* | 
|  | * FIXME: lpServiceArgsVectors need to be stored and returned to | 
|  | *        the service when it calls StartServiceCtrlDispatcher | 
|  | * | 
|  | * Chuck these in a global (yuk) so we can pass them to | 
|  | * another process - address space separation will break this. | 
|  | */ | 
|  |  | 
|  | r = WaitForSingleObject(data,INFINITE); | 
|  |  | 
|  | if( r == WAIT_FAILED) | 
|  | return FALSE; | 
|  |  | 
|  | start_dwNumServiceArgs    = dwNumServiceArgs; | 
|  | start_lpServiceArgVectors = (LPWSTR *)lpServiceArgVectors; | 
|  |  | 
|  | ZeroMemory(&startupinfo,sizeof(STARTUPINFOA)); | 
|  | startupinfo.cb = sizeof(STARTUPINFOA); | 
|  |  | 
|  | r = CreateProcessA(path, | 
|  | NULL, | 
|  | NULL,  /* process security attribs */ | 
|  | NULL,  /* thread security attribs */ | 
|  | FALSE, /* inherit handles */ | 
|  | 0,     /* creation flags */ | 
|  | NULL,  /* environment */ | 
|  | NULL,  /* current directory */ | 
|  | &startupinfo,  /* startup info */ | 
|  | &procinfo); /* process info */ | 
|  |  | 
|  | if(r == FALSE) | 
|  | { | 
|  | ERR("Couldn't start process\n"); | 
|  | /* ReleaseSemaphore(data, 1, NULL); | 
|  | return FALSE; */ | 
|  | } | 
|  |  | 
|  | /* docs for StartServiceCtrlDispatcher say this should be 30 sec */ | 
|  | r = WaitForSingleObject(wait,30000); | 
|  |  | 
|  | ReleaseSemaphore(data, 1, NULL); | 
|  |  | 
|  | if( r == WAIT_FAILED) | 
|  | return FALSE; | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | /****************************************************************************** | 
|  | * QueryServiceStatus [ADVAPI32.123] | 
|  | * | 
|  | * PARAMS | 
|  | *   hService        [] | 
|  | *   lpservicestatus [] | 
|  | * | 
|  | */ | 
|  | BOOL WINAPI | 
|  | QueryServiceStatus( SC_HANDLE hService, LPSERVICE_STATUS lpservicestatus ) | 
|  | { | 
|  | LONG r; | 
|  | DWORD type, val, size; | 
|  |  | 
|  | FIXME("(%x,%p) partial\n",hService,lpservicestatus); | 
|  |  | 
|  | /* read the service type from the registry */ | 
|  | size = sizeof val; | 
|  | r = RegQueryValueExA(hService, "Type", NULL, &type, (LPBYTE)&val, &size); | 
|  | if(type!=REG_DWORD) | 
|  | { | 
|  | ERR("invalid Type\n"); | 
|  | return FALSE; | 
|  | } | 
|  | lpservicestatus->dwServiceType = val; | 
|  | /* FIXME: how are these determined or read from the registry? */ | 
|  | /* SERVICE: unavailable=0, stopped=1, starting=2, running=3? */; | 
|  | lpservicestatus->dwCurrentState            = 1; | 
|  | lpservicestatus->dwControlsAccepted        = 0; | 
|  | lpservicestatus->dwWin32ExitCode           = NO_ERROR; | 
|  | lpservicestatus->dwServiceSpecificExitCode = 0; | 
|  | lpservicestatus->dwCheckPoint              = 0; | 
|  | lpservicestatus->dwWaitHint                = 0; | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  |