2 * Win32 advapi functions
4 * Copyright 1995 Sven Verdoolaege
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 #include "wine/unicode.h"
32 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(advapi);
37 static DWORD start_dwNumServiceArgs;
38 static LPWSTR *start_lpServiceArgVectors;
40 static const WCHAR _ServiceStartDataW[] = {'A','D','V','A','P','I','_','S',
41 'e','r','v','i','c','e','S','t',
42 'a','r','t','D','a','t','a',0};
43 static const WCHAR szServiceManagerKey[] = { 'S','y','s','t','e','m','\\',
44 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
45 'S','e','r','v','i','c','e','s','\\',0 };
47 /******************************************************************************
51 #define MAX_SERVICE_NAME 256
53 typedef enum { SC_HTYPE_MANAGER, SC_HTYPE_SERVICE } SC_HANDLE_TYPE;
57 struct sc_manager /* SCM handle */
59 HKEY hkey_scm_db; /* handle to services database in the registry */
60 LONG ref_count; /* handle must remain alive until any related service */
61 /* handle exists because DeleteService requires it */
64 struct sc_service /* service handle */
66 HKEY hkey; /* handle to service entry in the registry (under hkey_scm_db) */
67 struct sc_handle *sc_manager; /* pointer to SCM handle */
68 WCHAR name[ MAX_SERVICE_NAME ];
76 struct sc_manager manager;
77 struct sc_service service;
81 static struct sc_handle* alloc_sc_handle( SC_HANDLE_TYPE htype )
83 struct sc_handle *retval;
85 retval = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct sc_handle) );
88 retval->htype = htype;
90 TRACE("SC_HANDLE type=%d -> %p\n",htype,retval);
94 static void free_sc_handle( struct sc_handle* handle )
99 switch( handle->htype )
101 case SC_HTYPE_MANAGER:
103 if( InterlockedDecrement( &handle->u.manager.ref_count ) )
104 /* there are references to this handle */
107 if( handle->u.manager.hkey_scm_db )
108 RegCloseKey( handle->u.manager.hkey_scm_db );
112 case SC_HTYPE_SERVICE:
114 struct sc_handle *h = handle->u.service.sc_manager;
118 /* release SCM handle */
119 if( 0 == InterlockedDecrement( &h->u.manager.ref_count ) )
121 /* it's time to destroy SCM handle */
122 if( h->u.manager.hkey_scm_db )
123 RegCloseKey( h->u.manager.hkey_scm_db );
125 TRACE("SC_HANDLE (SCM) %p type=%d\n",h,h->htype);
127 HeapFree( GetProcessHeap(), 0, h );
130 if( handle->u.service.hkey )
131 RegCloseKey( handle->u.service.hkey );
136 TRACE("SC_HANDLE %p type=%d\n",handle,handle->htype);
138 HeapFree( GetProcessHeap(), 0, handle );
141 static void init_service_handle( struct sc_handle* handle,
142 struct sc_handle* sc_manager,
143 HKEY hKey, LPCWSTR lpServiceName )
145 /* init sc_service structure */
146 handle->u.service.hkey = hKey;
147 lstrcpynW( handle->u.service.name, lpServiceName, MAX_SERVICE_NAME );
149 /* add reference to SCM handle */
150 InterlockedIncrement( &sc_manager->u.manager.ref_count );
151 handle->u.service.sc_manager = sc_manager;
154 /******************************************************************************
155 * EnumServicesStatusA [ADVAPI32.@]
158 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
159 DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
160 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
161 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
162 { FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
163 dwServiceType, dwServiceState, lpServices, cbBufSize,
164 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
165 SetLastError (ERROR_ACCESS_DENIED);
169 /******************************************************************************
170 * EnumServicesStatusW [ADVAPI32.@]
173 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
174 DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
175 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
176 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
177 { FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
178 dwServiceType, dwServiceState, lpServices, cbBufSize,
179 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
180 SetLastError (ERROR_ACCESS_DENIED);
184 /******************************************************************************
185 * StartServiceCtrlDispatcherA [ADVAPI32.@]
188 StartServiceCtrlDispatcherA( LPSERVICE_TABLE_ENTRYA servent )
190 LPSERVICE_MAIN_FUNCTIONA fpMain;
192 DWORD dwNumServiceArgs ;
197 TRACE("(%p)\n", servent);
198 wait = CreateSemaphoreW(NULL,1,1,_ServiceStartDataW);
201 ERR("Couldn't create data semaphore\n");
205 dwNumServiceArgs = start_dwNumServiceArgs;
206 lpArgVecW = start_lpServiceArgVectors;
208 ReleaseSemaphore(wait, 1, NULL);
210 /* Convert the Unicode arg vectors back to ASCII */
212 lpArgVecA = (LPSTR*) HeapAlloc( GetProcessHeap(), 0,
213 dwNumServiceArgs*sizeof(LPSTR) );
217 for(i=0; i<dwNumServiceArgs; i++)
218 lpArgVecA[i]=HEAP_strdupWtoA(GetProcessHeap(), 0, lpArgVecW[i]);
220 /* FIXME: should we blindly start all services? */
221 while (servent->lpServiceName) {
222 TRACE("%s at %p)\n", debugstr_a(servent->lpServiceName),servent);
223 fpMain = servent->lpServiceProc;
225 /* try to start the service */
226 fpMain( dwNumServiceArgs, lpArgVecA);
233 /* free arg strings */
234 for(i=0; i<dwNumServiceArgs; i++)
235 HeapFree(GetProcessHeap(), 0, lpArgVecA[i]);
236 HeapFree(GetProcessHeap(), 0, lpArgVecA);
242 /******************************************************************************
243 * StartServiceCtrlDispatcherW [ADVAPI32.@]
249 StartServiceCtrlDispatcherW( LPSERVICE_TABLE_ENTRYW servent )
251 LPSERVICE_MAIN_FUNCTIONW fpMain;
253 DWORD dwNumServiceArgs ;
254 LPWSTR *lpServiceArgVectors ;
256 TRACE("(%p)\n", servent);
257 wait = OpenSemaphoreW(SEMAPHORE_ALL_ACCESS, FALSE, _ServiceStartDataW);
260 ERR("Couldn't find wait semaphore\n");
261 ERR("perhaps you need to start services using StartService\n");
265 dwNumServiceArgs = start_dwNumServiceArgs;
266 lpServiceArgVectors = start_lpServiceArgVectors;
268 ReleaseSemaphore(wait, 1, NULL);
270 /* FIXME: should we blindly start all services? */
271 while (servent->lpServiceName) {
272 TRACE("%s at %p)\n", debugstr_w(servent->lpServiceName),servent);
273 fpMain = servent->lpServiceProc;
275 /* try to start the service */
276 fpMain( dwNumServiceArgs, lpServiceArgVectors);
284 /******************************************************************************
285 * LockServiceDatabase [ADVAPI32.@]
287 LPVOID WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
289 FIXME("%p\n",hSCManager);
290 return (SC_HANDLE)0xcacacafe;
293 /******************************************************************************
294 * UnlockServiceDatabase [ADVAPI32.@]
296 BOOL WINAPI UnlockServiceDatabase (LPVOID ScLock)
298 FIXME(": %p\n",ScLock);
302 /******************************************************************************
303 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
305 SERVICE_STATUS_HANDLE WINAPI
306 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName,
307 LPHANDLER_FUNCTION lpfHandler )
308 { FIXME("%s %p\n", lpServiceName, lpfHandler);
312 /******************************************************************************
313 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
319 SERVICE_STATUS_HANDLE WINAPI
320 RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName,
321 LPHANDLER_FUNCTION lpfHandler )
322 { FIXME("%s %p\n", debugstr_w(lpServiceName), lpfHandler);
326 /******************************************************************************
327 * SetServiceStatus [ADVAPI32.@]
334 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
335 { FIXME("0x%lx %p\n",hService, lpStatus);
336 TRACE("\tType:%lx\n",lpStatus->dwServiceType);
337 TRACE("\tState:%lx\n",lpStatus->dwCurrentState);
338 TRACE("\tControlAccepted:%lx\n",lpStatus->dwControlsAccepted);
339 TRACE("\tExitCode:%lx\n",lpStatus->dwWin32ExitCode);
340 TRACE("\tServiceExitCode:%lx\n",lpStatus->dwServiceSpecificExitCode);
341 TRACE("\tCheckPoint:%lx\n",lpStatus->dwCheckPoint);
342 TRACE("\tWaitHint:%lx\n",lpStatus->dwWaitHint);
346 /******************************************************************************
347 * OpenSCManagerA [ADVAPI32.@]
349 * Establish a connection to the service control manager and open its database.
352 * lpMachineName [I] Pointer to machine name string
353 * lpDatabaseName [I] Pointer to database name string
354 * dwDesiredAccess [I] Type of access
357 * Success: A Handle to the service control manager database
360 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
361 DWORD dwDesiredAccess )
363 UNICODE_STRING lpMachineNameW;
364 UNICODE_STRING lpDatabaseNameW;
367 RtlCreateUnicodeStringFromAsciiz (&lpMachineNameW,lpMachineName);
368 RtlCreateUnicodeStringFromAsciiz (&lpDatabaseNameW,lpDatabaseName);
369 ret = OpenSCManagerW(lpMachineNameW.Buffer,lpDatabaseNameW.Buffer, dwDesiredAccess);
370 RtlFreeUnicodeString(&lpDatabaseNameW);
371 RtlFreeUnicodeString(&lpMachineNameW);
375 /******************************************************************************
376 * OpenSCManagerW [ADVAPI32.@]
378 * See OpenSCManagerA.
380 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
381 DWORD dwDesiredAccess )
383 struct sc_handle *retval;
387 TRACE("(%s,%s,0x%08lx)\n", debugstr_w(lpMachineName),
388 debugstr_w(lpDatabaseName), dwDesiredAccess);
391 * FIXME: what is lpDatabaseName?
392 * It should be set to "SERVICES_ACTIVE_DATABASE" according to
393 * docs, but what if it isn't?
396 retval = alloc_sc_handle( SC_HTYPE_MANAGER );
397 if( NULL == retval ) return NULL;
399 retval->u.manager.ref_count = 1;
401 r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
402 if (r!=ERROR_SUCCESS)
405 r = RegOpenKeyExW(hReg, szServiceManagerKey,
406 0, KEY_ALL_ACCESS, &retval->u.manager.hkey_scm_db);
408 if (r!=ERROR_SUCCESS)
411 TRACE("returning %p\n", retval);
413 return (SC_HANDLE) retval;
416 free_sc_handle( retval );
421 /******************************************************************************
422 * AllocateLocallyUniqueId [ADVAPI32.@]
428 AllocateLocallyUniqueId( PLUID lpluid )
430 lpluid->LowPart = time(NULL);
431 lpluid->HighPart = 0;
436 /******************************************************************************
437 * ControlService [ADVAPI32.@]
439 * Send a control code to a service.
442 * hService [I] Handle of the service control manager database
443 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
444 * lpServiceStatus [O] Destination for the status of the service, if available
450 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
451 LPSERVICE_STATUS lpServiceStatus )
453 FIXME("(%p,%ld,%p): stub\n",hService,dwControl,lpServiceStatus);
458 /******************************************************************************
459 * CloseServiceHandle [ADVAPI32.@]
461 * Close a handle to a service or the service control manager database.
464 * hSCObject [I] Handle to service or service control manager database
471 CloseServiceHandle( SC_HANDLE hSCObject )
473 TRACE("(%p)\n", hSCObject);
475 free_sc_handle( (struct sc_handle*) hSCObject );
481 /******************************************************************************
482 * OpenServiceA [ADVAPI32.@]
484 * Open a handle to a service.
487 * hSCManager [I] Handle of the service control manager database
488 * lpServiceName [I] Name of the service to open
489 * dwDesiredAccess [I] Access required to the service
492 * Success: Handle to the service
495 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
496 DWORD dwDesiredAccess )
498 UNICODE_STRING lpServiceNameW;
500 RtlCreateUnicodeStringFromAsciiz (&lpServiceNameW,lpServiceName);
502 TRACE("Request for service %s\n",lpServiceName);
505 ret = OpenServiceW( hSCManager, lpServiceNameW.Buffer, dwDesiredAccess);
506 RtlFreeUnicodeString(&lpServiceNameW);
511 /******************************************************************************
512 * OpenServiceW [ADVAPI32.@]
516 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
517 DWORD dwDesiredAccess)
519 struct sc_handle *hscm = hSCManager;
520 struct sc_handle *retval;
524 TRACE("(%p,%p,%ld)\n",hSCManager, lpServiceName,
527 retval = alloc_sc_handle( SC_HTYPE_SERVICE );
531 r = RegOpenKeyExW( hscm->u.manager.hkey_scm_db,
532 lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
533 if (r!=ERROR_SUCCESS)
535 free_sc_handle( retval );
536 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
540 init_service_handle( retval, hscm, hKey, lpServiceName );
542 TRACE("returning %p\n",retval);
544 return (SC_HANDLE) retval;
547 /******************************************************************************
548 * CreateServiceW [ADVAPI32.@]
551 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
552 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
553 DWORD dwServiceType, DWORD dwStartType,
554 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
555 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
556 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
559 struct sc_handle *hscm = hSCManager;
560 struct sc_handle *retval;
564 static const WCHAR szDisplayName[] = { 'D','i','s','p','l','a','y','N','a','m','e', 0 };
565 static const WCHAR szType[] = {'T','y','p','e',0};
566 static const WCHAR szStart[] = {'S','t','a','r','t',0};
567 static const WCHAR szError[] = {'E','r','r','o','r','C','o','n','t','r','o','l', 0};
568 static const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
569 static const WCHAR szGroup[] = {'G','r','o','u','p',0};
570 static const WCHAR szDependencies[] = { 'D','e','p','e','n','d','e','n','c','i','e','s',0};
572 FIXME("%p %s %s\n", hSCManager,
573 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
575 retval = alloc_sc_handle( SC_HTYPE_SERVICE );
579 r = RegCreateKeyExW(hscm->u.manager.hkey_scm_db, lpServiceName, 0, NULL,
580 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
581 if (r!=ERROR_SUCCESS)
584 init_service_handle( retval, hscm, hKey, lpServiceName );
586 if (dp != REG_CREATED_NEW_KEY)
591 r = RegSetValueExW(hKey, szDisplayName, 0, REG_SZ, (LPBYTE)lpDisplayName,
592 (strlenW(lpDisplayName)+1)*sizeof(WCHAR) );
593 if (r!=ERROR_SUCCESS)
597 r = RegSetValueExW(hKey, szType, 0, REG_DWORD, (LPVOID)&dwServiceType, sizeof (DWORD) );
598 if (r!=ERROR_SUCCESS)
601 r = RegSetValueExW(hKey, szStart, 0, REG_DWORD, (LPVOID)&dwStartType, sizeof (DWORD) );
602 if (r!=ERROR_SUCCESS)
605 r = RegSetValueExW(hKey, szError, 0, REG_DWORD,
606 (LPVOID)&dwErrorControl, sizeof (DWORD) );
607 if (r!=ERROR_SUCCESS)
612 r = RegSetValueExW(hKey, szImagePath, 0, REG_SZ, (LPBYTE)lpBinaryPathName,
613 (strlenW(lpBinaryPathName)+1)*sizeof(WCHAR) );
614 if (r!=ERROR_SUCCESS)
620 r = RegSetValueExW(hKey, szGroup, 0, REG_SZ, (LPBYTE)lpLoadOrderGroup,
621 (strlenW(lpLoadOrderGroup)+1)*sizeof(WCHAR) );
622 if (r!=ERROR_SUCCESS)
630 /* determine the length of a double null terminated multi string */
632 len += (strlenW(&lpDependencies[len])+1);
633 } while (lpDependencies[len++]);
635 r = RegSetValueExW(hKey, szDependencies, 0, REG_MULTI_SZ,
636 (LPBYTE)lpDependencies, len );
637 if (r!=ERROR_SUCCESS)
643 FIXME("Don't know how to add a Password for a service.\n");
646 if(lpServiceStartName)
648 FIXME("Don't know how to add a ServiceStartName for a service.\n");
651 return (SC_HANDLE) retval;
654 free_sc_handle( retval );
659 static inline LPWSTR SERV_dup( LPCSTR str )
666 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
667 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
668 MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
672 static inline LPWSTR SERV_dupmulti( LPCSTR str )
680 len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
681 n += (strlen( &str[n] ) + 1);
686 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
687 MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
691 static inline VOID SERV_free( LPWSTR wstr )
693 HeapFree( GetProcessHeap(), 0, wstr );
696 /******************************************************************************
697 * CreateServiceA [ADVAPI32.@]
700 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
701 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
702 DWORD dwServiceType, DWORD dwStartType,
703 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
704 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
705 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
708 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
709 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
712 TRACE("%p %s %s\n", hSCManager,
713 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
715 lpServiceNameW = SERV_dup( lpServiceName );
716 lpDisplayNameW = SERV_dup( lpDisplayName );
717 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
718 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
719 lpDependenciesW = SERV_dupmulti( lpDependencies );
720 lpServiceStartNameW = SERV_dup( lpServiceStartName );
721 lpPasswordW = SERV_dup( lpPassword );
723 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
724 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
725 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
726 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
728 SERV_free( lpServiceNameW );
729 SERV_free( lpDisplayNameW );
730 SERV_free( lpBinaryPathNameW );
731 SERV_free( lpLoadOrderGroupW );
732 SERV_free( lpDependenciesW );
733 SERV_free( lpServiceStartNameW );
734 SERV_free( lpPasswordW );
740 /******************************************************************************
741 * DeleteService [ADVAPI32.@]
743 * Delete a service from the service control manager database.
746 * hService [I] Handle of the service to delete
752 BOOL WINAPI DeleteService( SC_HANDLE hService )
754 struct sc_handle *hsvc = hService;
755 HKEY hKey = hsvc->u.service.hkey;
756 WCHAR valname[MAX_PATH+1];
762 /* Clean out the values */
763 rc = RegEnumValueW(hKey, index, valname,&size,0,0,0,0);
764 while (rc == ERROR_SUCCESS)
766 RegDeleteValueW(hKey,valname);
769 rc = RegEnumValueW(hKey, index, valname, &size,0,0,0,0);
773 hsvc->u.service.hkey = NULL;
776 RegDeleteKeyW(hsvc->u.service.sc_manager->u.manager.hkey_scm_db,
777 hsvc->u.service.name);
783 /******************************************************************************
784 * StartServiceA [ADVAPI32.@]
789 * hService [I] Handle of service
790 * dwNumServiceArgs [I] Number of arguments
791 * lpServiceArgVectors [I] Address of array of argument strings
794 * - NT implements this function using an obscure RPC call.
795 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
796 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
797 * - This will only work for shared address space. How should the service
798 * args be transferred when address spaces are separated?
799 * - Can only start one service at a time.
800 * - Has no concept of privilege.
807 StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
808 LPCSTR *lpServiceArgVectors )
811 UNICODE_STRING usBuffer;
814 TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
817 lpwstr = (LPWSTR*) HeapAlloc( GetProcessHeap(), 0,
818 dwNumServiceArgs*sizeof(LPWSTR) );
822 for(i=0; i<dwNumServiceArgs; i++)
824 RtlCreateUnicodeStringFromAsciiz (&usBuffer,lpServiceArgVectors[i]);
825 lpwstr[i]=usBuffer.Buffer;
828 StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
832 for(i=0; i<dwNumServiceArgs; i++)
833 HeapFree(GetProcessHeap(), 0, lpwstr[i]);
834 HeapFree(GetProcessHeap(), 0, lpwstr);
841 /******************************************************************************
842 * StartServiceW [ADVAPI32.@]
847 StartServiceW( SC_HANDLE hService, DWORD dwNumServiceArgs,
848 LPCWSTR *lpServiceArgVectors )
850 static const WCHAR _WaitServiceStartW[] = {'A','D','V','A','P','I','_','W',
851 'a','i','t','S','e','r','v','i',
852 'c','e','S','t','a','r','t',0};
853 static const WCHAR _ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0};
855 struct sc_handle *hsvc = hService;
856 WCHAR path[MAX_PATH],str[MAX_PATH];
860 PROCESS_INFORMATION procinfo;
861 STARTUPINFOW startupinfo;
862 TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,
863 lpServiceArgVectors);
866 r = RegQueryValueExW(hsvc->u.service.hkey, _ImagePathW, NULL, &type, (LPVOID)str, &size);
867 if (r!=ERROR_SUCCESS)
869 ExpandEnvironmentStringsW(str,path,sizeof(path));
871 TRACE("Starting service %s\n", debugstr_w(path) );
873 data = CreateSemaphoreW(NULL,1,1,_ServiceStartDataW);
876 ERR("Couldn't create data semaphore\n");
879 wait = CreateSemaphoreW(NULL,0,1,_WaitServiceStartW);
882 ERR("Couldn't create wait semaphore\n");
887 * FIXME: lpServiceArgsVectors need to be stored and returned to
888 * the service when it calls StartServiceCtrlDispatcher
890 * Chuck these in a global (yuk) so we can pass them to
891 * another process - address space separation will break this.
894 r = WaitForSingleObject(data,INFINITE);
896 if( r == WAIT_FAILED)
899 FIXME("problematic because of address space separation.\n");
900 start_dwNumServiceArgs = dwNumServiceArgs;
901 start_lpServiceArgVectors = (LPWSTR *)lpServiceArgVectors;
903 ZeroMemory(&startupinfo,sizeof(STARTUPINFOW));
904 startupinfo.cb = sizeof(STARTUPINFOW);
906 r = CreateProcessW(NULL,
908 NULL, /* process security attribs */
909 NULL, /* thread security attribs */
910 FALSE, /* inherit handles */
911 0, /* creation flags */
912 NULL, /* environment */
913 NULL, /* current directory */
914 &startupinfo, /* startup info */
915 &procinfo); /* process info */
919 ERR("Couldn't start process\n");
920 /* ReleaseSemaphore(data, 1, NULL);
924 /* docs for StartServiceCtrlDispatcher say this should be 30 sec */
925 r = WaitForSingleObject(wait,30000);
927 ReleaseSemaphore(data, 1, NULL);
929 if( r == WAIT_FAILED)
935 /******************************************************************************
936 * QueryServiceStatus [ADVAPI32.@]
944 QueryServiceStatus( SC_HANDLE hService, LPSERVICE_STATUS lpservicestatus )
946 struct sc_handle *hsvc = hService;
948 DWORD type, val, size;
950 FIXME("(%p,%p) partial\n",hService,lpservicestatus);
952 /* read the service type from the registry */
954 r = RegQueryValueExA(hsvc->u.service.hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
957 ERR("invalid Type\n");
960 lpservicestatus->dwServiceType = val;
961 /* FIXME: how are these determined or read from the registry? */
962 /* SERVICE: unavailable=0, stopped=1, starting=2, running=3? */;
963 lpservicestatus->dwCurrentState = 1;
964 lpservicestatus->dwControlsAccepted = 0;
965 lpservicestatus->dwWin32ExitCode = NO_ERROR;
966 lpservicestatus->dwServiceSpecificExitCode = 0;
967 lpservicestatus->dwCheckPoint = 0;
968 lpservicestatus->dwWaitHint = 0;
973 /******************************************************************************
974 * QueryServiceStatusEx [ADVAPI32.@]
976 * Get information about a service.
979 * hService [I] Handle to service to get information about
980 * InfoLevel [I] Level of information to get
981 * lpBuffer [O] Destination for requested information
982 * cbBufSize [I] Size of lpBuffer in bytes
983 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
989 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
990 LPBYTE lpBuffer, DWORD cbBufSize,
991 LPDWORD pcbBytesNeeded)
994 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
998 /******************************************************************************
999 * QueryServiceConfigA [ADVAPI32.@]
1002 QueryServiceConfigA( SC_HANDLE hService,
1003 LPQUERY_SERVICE_CONFIGA lpServiceConfig,
1004 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1006 static const CHAR szDisplayName[] = "DisplayName";
1007 static const CHAR szType[] = "Type";
1008 static const CHAR szStart[] = "Start";
1009 static const CHAR szError[] = "ErrorControl";
1010 static const CHAR szImagePath[] = "ImagePath";
1011 static const CHAR szGroup[] = "Group";
1012 static const CHAR szDependencies[] = "Dependencies";
1013 HKEY hKey = ((struct sc_handle*) hService)->u.service.hkey;
1014 CHAR str_buffer[ MAX_PATH ];
1016 DWORD type, val, sz, total, n;
1019 TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
1020 cbBufSize, pcbBytesNeeded);
1022 /* calculate the size required first */
1023 total = sizeof (QUERY_SERVICE_CONFIGA);
1025 sz = sizeof(str_buffer);
1026 r = RegQueryValueExA( hKey, szImagePath, 0, &type, str_buffer, &sz );
1027 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1029 sz = ExpandEnvironmentStringsA(str_buffer,NULL,0);
1030 if( 0 == sz ) return FALSE;
1036 /* FIXME: set last error */
1041 r = RegQueryValueExA( hKey, szGroup, 0, &type, NULL, &sz );
1042 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1046 r = RegQueryValueExA( hKey, szDependencies, 0, &type, NULL, &sz );
1047 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1051 r = RegQueryValueExA( hKey, szStart, 0, &type, NULL, &sz );
1052 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1056 r = RegQueryValueExA( hKey, szDisplayName, 0, &type, NULL, &sz );
1057 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1060 /* if there's not enough memory, return an error */
1061 if( total > *pcbBytesNeeded )
1063 *pcbBytesNeeded = total;
1064 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1068 *pcbBytesNeeded = total;
1069 ZeroMemory( lpServiceConfig, total );
1072 r = RegQueryValueExA( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1073 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1074 lpServiceConfig->dwServiceType = val;
1077 r = RegQueryValueExA( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1078 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1079 lpServiceConfig->dwStartType = val;
1082 r = RegQueryValueExA( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1083 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1084 lpServiceConfig->dwErrorControl = val;
1086 /* now do the strings */
1087 p = (LPBYTE) &lpServiceConfig[1];
1088 n = total - sizeof (QUERY_SERVICE_CONFIGA);
1090 sz = sizeof(str_buffer);
1091 r = RegQueryValueExA( hKey, szImagePath, 0, &type, str_buffer, &sz );
1092 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1094 sz = ExpandEnvironmentStringsA(str_buffer, p, n);
1095 if( 0 == sz || sz > n ) return FALSE;
1097 lpServiceConfig->lpBinaryPathName = (LPSTR) p;
1103 /* FIXME: set last error */
1108 r = RegQueryValueExA( hKey, szGroup, 0, &type, p, &sz );
1109 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1111 lpServiceConfig->lpLoadOrderGroup = (LPSTR) p;
1117 r = RegQueryValueExA( hKey, szDependencies, 0, &type, p, &sz );
1118 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1120 lpServiceConfig->lpDependencies = (LPSTR) p;
1126 ERR("Buffer overflow!\n");
1128 TRACE("Image path = %s\n", lpServiceConfig->lpBinaryPathName );
1129 TRACE("Group = %s\n", lpServiceConfig->lpLoadOrderGroup );
1134 /******************************************************************************
1135 * QueryServiceConfigW [ADVAPI32.@]
1138 QueryServiceConfigW( SC_HANDLE hService,
1139 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1140 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1142 static const WCHAR szDisplayName[] = {
1143 'D','i','s','p','l','a','y','N','a','m','e', 0 };
1144 static const WCHAR szType[] = {'T','y','p','e',0};
1145 static const WCHAR szStart[] = {'S','t','a','r','t',0};
1146 static const WCHAR szError[] = {
1147 'E','r','r','o','r','C','o','n','t','r','o','l', 0};
1148 static const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
1149 static const WCHAR szGroup[] = {'G','r','o','u','p',0};
1150 static const WCHAR szDependencies[] = {
1151 'D','e','p','e','n','d','e','n','c','i','e','s',0};
1152 HKEY hKey = ((struct sc_handle*) hService)->u.service.hkey;
1153 WCHAR str_buffer[ MAX_PATH ];
1155 DWORD type, val, sz, total, n;
1158 TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
1159 cbBufSize, pcbBytesNeeded);
1161 /* calculate the size required first */
1162 total = sizeof (QUERY_SERVICE_CONFIGW);
1164 sz = sizeof(str_buffer);
1165 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1166 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1168 sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1169 if( 0 == sz ) return FALSE;
1171 total += sizeof(WCHAR) * sz;
1175 /* FIXME: set last error */
1180 r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1181 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1185 r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1186 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1190 r = RegQueryValueExW( hKey, szStart, 0, &type, NULL, &sz );
1191 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1195 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1196 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1199 /* if there's not enough memory, return an error */
1200 if( total > *pcbBytesNeeded )
1202 *pcbBytesNeeded = total;
1203 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1207 *pcbBytesNeeded = total;
1208 ZeroMemory( lpServiceConfig, total );
1211 r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1212 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1213 lpServiceConfig->dwServiceType = val;
1216 r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1217 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1218 lpServiceConfig->dwStartType = val;
1221 r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1222 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1223 lpServiceConfig->dwErrorControl = val;
1225 /* now do the strings */
1226 p = (LPBYTE) &lpServiceConfig[1];
1227 n = total - sizeof (QUERY_SERVICE_CONFIGW);
1229 sz = sizeof(str_buffer);
1230 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1231 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1233 sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
1234 sz *= sizeof(WCHAR);
1235 if( 0 == sz || sz > n ) return FALSE;
1237 lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
1243 /* FIXME: set last error */
1248 r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
1249 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1251 lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
1257 r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
1258 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1260 lpServiceConfig->lpDependencies = (LPWSTR) p;
1266 ERR("Buffer overflow!\n");
1268 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1269 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1274 /******************************************************************************
1275 * ChangeServiceConfigW [ADVAPI32.@]
1277 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
1278 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1279 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
1280 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
1282 FIXME("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
1283 hService, dwServiceType, dwStartType, dwErrorControl,
1284 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
1285 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
1286 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
1290 /******************************************************************************
1291 * ChangeServiceConfigA [ADVAPI32.@]
1293 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
1294 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1295 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
1296 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
1298 FIXME("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
1299 hService, dwServiceType, dwStartType, dwErrorControl,
1300 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
1301 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
1302 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
1306 /******************************************************************************
1307 * ChangeServiceConfig2A [ADVAPI32.@]
1309 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
1312 FIXME("STUB: %p %ld %p\n",hService, dwInfoLevel, lpInfo);
1316 /******************************************************************************
1317 * ChangeServiceConfig2W [ADVAPI32.@]
1319 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
1322 HKEY hKey = ((struct sc_handle*) hService)->u.service.hkey;
1324 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
1326 static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
1327 LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
1328 if (sd->lpDescription)
1330 TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
1331 if (sd->lpDescription[0] == 0)
1332 RegDeleteValueW(hKey,szDescription);
1334 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
1335 (LPVOID)sd->lpDescription,
1336 sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
1340 FIXME("STUB: %p %ld %p\n",hService, dwInfoLevel, lpInfo);