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"
31 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(advapi);
36 static const WCHAR szServiceManagerKey[] = { 'S','y','s','t','e','m','\\',
37 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
38 'S','e','r','v','i','c','e','s','\\',0 };
39 static const WCHAR szSCMLock[] = {'A','D','V','A','P','I','_','S','C','M',
41 static const WCHAR szServiceShmemNameFmtW[] = {'A','D','V','A','P','I','_',
42 'S','E','B','_','%','s',0};
44 struct SEB /* service environment block */
45 { /* resides in service's shared memory object */
47 /* variable part of SEB contains service arguments */
50 /******************************************************************************
54 #define MAX_SERVICE_NAME 256
56 typedef enum { SC_HTYPE_MANAGER, SC_HTYPE_SERVICE } SC_HANDLE_TYPE;
60 struct sc_manager /* SCM handle */
62 HKEY hkey_scm_db; /* handle to services database in the registry */
63 LONG ref_count; /* handle must remain alive until any related service */
64 /* handle exists because DeleteService requires it */
67 struct sc_service /* service handle */
69 HKEY hkey; /* handle to service entry in the registry (under hkey_scm_db) */
70 struct sc_handle *sc_manager; /* pointer to SCM handle */
71 WCHAR name[ MAX_SERVICE_NAME ];
79 struct sc_manager manager;
80 struct sc_service service;
84 static struct sc_handle* alloc_sc_handle( SC_HANDLE_TYPE htype )
86 struct sc_handle *retval;
88 retval = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct sc_handle) );
91 retval->htype = htype;
93 TRACE("SC_HANDLE type=%d -> %p\n",htype,retval);
97 static void free_sc_handle( struct sc_handle* handle )
102 switch( handle->htype )
104 case SC_HTYPE_MANAGER:
106 if( InterlockedDecrement( &handle->u.manager.ref_count ) )
107 /* there are references to this handle */
110 if( handle->u.manager.hkey_scm_db )
111 RegCloseKey( handle->u.manager.hkey_scm_db );
115 case SC_HTYPE_SERVICE:
117 struct sc_handle *h = handle->u.service.sc_manager;
121 /* release SCM handle */
122 if( 0 == InterlockedDecrement( &h->u.manager.ref_count ) )
124 /* it's time to destroy SCM handle */
125 if( h->u.manager.hkey_scm_db )
126 RegCloseKey( h->u.manager.hkey_scm_db );
128 TRACE("SC_HANDLE (SCM) %p type=%d\n",h,h->htype);
130 HeapFree( GetProcessHeap(), 0, h );
133 if( handle->u.service.hkey )
134 RegCloseKey( handle->u.service.hkey );
139 TRACE("SC_HANDLE %p type=%d\n",handle,handle->htype);
141 HeapFree( GetProcessHeap(), 0, handle );
144 static void init_service_handle( struct sc_handle* handle,
145 struct sc_handle* sc_manager,
146 HKEY hKey, LPCWSTR lpServiceName )
148 /* init sc_service structure */
149 handle->u.service.hkey = hKey;
150 lstrcpynW( handle->u.service.name, lpServiceName, MAX_SERVICE_NAME );
152 /* add reference to SCM handle */
153 InterlockedIncrement( &sc_manager->u.manager.ref_count );
154 handle->u.service.sc_manager = sc_manager;
157 static inline LPWSTR SERV_dup( LPCSTR str )
164 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
165 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
166 MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
170 static inline LPWSTR SERV_dupmulti( LPCSTR str )
178 len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
179 n += (strlen( &str[n] ) + 1);
184 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
185 MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
189 static inline VOID SERV_free( LPWSTR wstr )
191 HeapFree( GetProcessHeap(), 0, wstr );
194 /******************************************************************************
195 * EnumServicesStatusA [ADVAPI32.@]
198 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
199 DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
200 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
201 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
202 { FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
203 dwServiceType, dwServiceState, lpServices, cbBufSize,
204 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
205 SetLastError (ERROR_ACCESS_DENIED);
209 /******************************************************************************
210 * EnumServicesStatusW [ADVAPI32.@]
213 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
214 DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
215 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
216 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
217 { FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
218 dwServiceType, dwServiceState, lpServices, cbBufSize,
219 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
220 SetLastError (ERROR_ACCESS_DENIED);
224 /******************************************************************************
227 * helper function for service control dispatcher
229 * SCM database is locked by StartService;
230 * open global SCM lock object and read service name
232 static BOOL read_scm_lock_data( LPWSTR buffer )
237 hLock = OpenFileMappingW( FILE_MAP_ALL_ACCESS, FALSE, szSCMLock );
240 SetLastError( ERROR_FAILED_SERVICE_CONTROLLER_CONNECT );
243 argptr = MapViewOfFile( hLock, FILE_MAP_ALL_ACCESS,
244 0, 0, MAX_SERVICE_NAME * sizeof(WCHAR) );
247 CloseHandle( hLock );
250 strcpyW( buffer, argptr );
251 UnmapViewOfFile( argptr );
252 CloseHandle( hLock );
256 /******************************************************************************
259 * helper function for service control dispatcher
261 static struct SEB* open_seb_shmem( LPWSTR service_name, HANDLE* hServiceShmem )
263 WCHAR object_name[ MAX_PATH ];
267 snprintfW( object_name, MAX_PATH, szServiceShmemNameFmtW, service_name );
268 hmem = OpenFileMappingW( FILE_MAP_ALL_ACCESS, FALSE, object_name );
272 ret = MapViewOfFile( hmem, FILE_MAP_ALL_ACCESS, 0, 0, 0 );
276 *hServiceShmem = hmem;
280 /******************************************************************************
283 * helper function for service control dispatcher
285 * Allocate and initialize array of LPWSTRs to arguments in variable part
286 * of service environment block.
287 * First entry in the array is reserved for service name and not initialized.
289 static LPWSTR* build_arg_vectors( struct SEB* seb )
295 ret = HeapAlloc( GetProcessHeap(), 0, (1 + seb->argc) * sizeof(LPWSTR) );
299 argptr = (LPWSTR) &seb[1];
300 for( i = 0; i < seb->argc; i++ )
302 ret[ 1 + i ] = argptr;
303 argptr += 1 + strlenW( argptr );
308 /******************************************************************************
309 * service_ctrl_dispatcher
311 * helper function for StartServiceCtrlDispatcherA/W
313 static BOOL service_ctrl_dispatcher( LPSERVICE_TABLE_ENTRYW servent, BOOL ascii )
315 WCHAR service_name[ MAX_SERVICE_NAME ];
316 HANDLE hServiceShmem = NULL;
317 struct SEB *seb = NULL;
318 DWORD dwNumServiceArgs;
319 LPWSTR *lpArgVecW = NULL;
323 if( ! read_scm_lock_data( service_name ) )
325 /* FIXME: Instead of exiting we allow
326 service to be executed as ordinary program.
327 This behaviour was specially introduced in the patch
328 submitted against revision 1.45 and so preserved here.
330 FIXME("should fail with ERROR_FAILED_SERVICE_CONTROLLER_CONNECT\n");
331 servent->lpServiceProc( 0, NULL );
335 seb = open_seb_shmem( service_name, &hServiceShmem );
339 lpArgVecW = build_arg_vectors( seb );
340 if( NULL == lpArgVecW )
343 lpArgVecW[0] = service_name;
344 dwNumServiceArgs = seb->argc + 1;
347 /* Convert the Unicode arg vectors back to ASCII */
348 for(i=0; i<dwNumServiceArgs; i++)
350 LPWSTR src = lpArgVecW[i];
351 int len = WideCharToMultiByte( CP_ACP, 0, src, -1, NULL, 0, NULL, NULL );
352 LPSTR dest = HeapAlloc( GetProcessHeap(), 0, len );
355 WideCharToMultiByte( CP_ACP, 0, src, -1, dest, len, NULL, NULL );
356 /* copy converted string back */
357 memcpy( src, dest, len );
358 HeapFree( GetProcessHeap(), 0, dest );
361 /* try to start the service */
362 servent->lpServiceProc( dwNumServiceArgs, lpArgVecW);
366 if( lpArgVecW ) HeapFree( GetProcessHeap(), 0, lpArgVecW );
367 if( seb ) UnmapViewOfFile( seb );
368 if( hServiceShmem ) CloseHandle( hServiceShmem );
372 /******************************************************************************
373 * StartServiceCtrlDispatcherA [ADVAPI32.@]
376 StartServiceCtrlDispatcherA( LPSERVICE_TABLE_ENTRYA servent )
379 LPSERVICE_TABLE_ENTRYW ServiceTableW;
382 TRACE("(%p)\n", servent);
384 /* convert service table to unicode */
385 for( count = 0; servent[ count ].lpServiceName; )
387 ServiceTableW = HeapAlloc( GetProcessHeap(), 0, (count + 1) * sizeof(SERVICE_TABLE_ENTRYW) );
388 if( NULL == ServiceTableW )
391 for( i = 0; i < count; i++ )
393 ServiceTableW[ i ].lpServiceName = SERV_dup( servent[ i ].lpServiceName );
394 ServiceTableW[ i ].lpServiceProc = (LPSERVICE_MAIN_FUNCTIONW) servent[ i ].lpServiceProc;
396 ServiceTableW[ count ].lpServiceName = NULL;
397 ServiceTableW[ count ].lpServiceProc = NULL;
399 /* start dispatcher */
400 ret = service_ctrl_dispatcher( ServiceTableW, TRUE );
402 /* free service table */
403 for( i = 0; i < count; i++ )
404 SERV_free( ServiceTableW[ i ].lpServiceName );
405 HeapFree( GetProcessHeap(), 0, ServiceTableW );
409 /******************************************************************************
410 * StartServiceCtrlDispatcherW [ADVAPI32.@]
416 StartServiceCtrlDispatcherW( LPSERVICE_TABLE_ENTRYW servent )
418 TRACE("(%p)\n", servent);
419 return service_ctrl_dispatcher( servent, FALSE );
422 /******************************************************************************
423 * LockServiceDatabase [ADVAPI32.@]
425 LPVOID WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
429 TRACE("%p\n",hSCManager);
431 ret = CreateFileMappingW( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
432 0, MAX_SERVICE_NAME * sizeof(WCHAR), szSCMLock );
433 if( ret && GetLastError() == ERROR_ALREADY_EXISTS )
437 SetLastError( ERROR_SERVICE_DATABASE_LOCKED );
440 TRACE("returning %p\n", ret);
445 /******************************************************************************
446 * UnlockServiceDatabase [ADVAPI32.@]
448 BOOL WINAPI UnlockServiceDatabase (LPVOID ScLock)
450 TRACE("%p\n",ScLock);
452 return CloseHandle( (HANDLE) ScLock );
455 /******************************************************************************
456 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
458 SERVICE_STATUS_HANDLE WINAPI
459 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName,
460 LPHANDLER_FUNCTION lpfHandler )
461 { FIXME("%s %p\n", lpServiceName, lpfHandler);
465 /******************************************************************************
466 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
472 SERVICE_STATUS_HANDLE WINAPI
473 RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName,
474 LPHANDLER_FUNCTION lpfHandler )
475 { FIXME("%s %p\n", debugstr_w(lpServiceName), lpfHandler);
479 /******************************************************************************
480 * SetServiceStatus [ADVAPI32.@]
487 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
488 { FIXME("0x%lx %p\n",hService, lpStatus);
489 TRACE("\tType:%lx\n",lpStatus->dwServiceType);
490 TRACE("\tState:%lx\n",lpStatus->dwCurrentState);
491 TRACE("\tControlAccepted:%lx\n",lpStatus->dwControlsAccepted);
492 TRACE("\tExitCode:%lx\n",lpStatus->dwWin32ExitCode);
493 TRACE("\tServiceExitCode:%lx\n",lpStatus->dwServiceSpecificExitCode);
494 TRACE("\tCheckPoint:%lx\n",lpStatus->dwCheckPoint);
495 TRACE("\tWaitHint:%lx\n",lpStatus->dwWaitHint);
499 /******************************************************************************
500 * OpenSCManagerA [ADVAPI32.@]
502 * Establish a connection to the service control manager and open its database.
505 * lpMachineName [I] Pointer to machine name string
506 * lpDatabaseName [I] Pointer to database name string
507 * dwDesiredAccess [I] Type of access
510 * Success: A Handle to the service control manager database
513 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
514 DWORD dwDesiredAccess )
516 UNICODE_STRING lpMachineNameW;
517 UNICODE_STRING lpDatabaseNameW;
520 RtlCreateUnicodeStringFromAsciiz (&lpMachineNameW,lpMachineName);
521 RtlCreateUnicodeStringFromAsciiz (&lpDatabaseNameW,lpDatabaseName);
522 ret = OpenSCManagerW(lpMachineNameW.Buffer,lpDatabaseNameW.Buffer, dwDesiredAccess);
523 RtlFreeUnicodeString(&lpDatabaseNameW);
524 RtlFreeUnicodeString(&lpMachineNameW);
528 /******************************************************************************
529 * OpenSCManagerW [ADVAPI32.@]
531 * See OpenSCManagerA.
533 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
534 DWORD dwDesiredAccess )
536 struct sc_handle *retval;
540 TRACE("(%s,%s,0x%08lx)\n", debugstr_w(lpMachineName),
541 debugstr_w(lpDatabaseName), dwDesiredAccess);
544 * FIXME: what is lpDatabaseName?
545 * It should be set to "SERVICES_ACTIVE_DATABASE" according to
546 * docs, but what if it isn't?
549 retval = alloc_sc_handle( SC_HTYPE_MANAGER );
550 if( NULL == retval ) return NULL;
552 retval->u.manager.ref_count = 1;
554 r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
555 if (r!=ERROR_SUCCESS)
558 r = RegOpenKeyExW(hReg, szServiceManagerKey,
559 0, KEY_ALL_ACCESS, &retval->u.manager.hkey_scm_db);
561 if (r!=ERROR_SUCCESS)
564 TRACE("returning %p\n", retval);
566 return (SC_HANDLE) retval;
569 free_sc_handle( retval );
573 /******************************************************************************
574 * ControlService [ADVAPI32.@]
576 * Send a control code to a service.
579 * hService [I] Handle of the service control manager database
580 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
581 * lpServiceStatus [O] Destination for the status of the service, if available
587 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
588 LPSERVICE_STATUS lpServiceStatus )
590 FIXME("(%p,%ld,%p): stub\n",hService,dwControl,lpServiceStatus);
595 /******************************************************************************
596 * CloseServiceHandle [ADVAPI32.@]
598 * Close a handle to a service or the service control manager database.
601 * hSCObject [I] Handle to service or service control manager database
608 CloseServiceHandle( SC_HANDLE hSCObject )
610 TRACE("(%p)\n", hSCObject);
612 free_sc_handle( (struct sc_handle*) hSCObject );
618 /******************************************************************************
619 * OpenServiceA [ADVAPI32.@]
621 * Open a handle to a service.
624 * hSCManager [I] Handle of the service control manager database
625 * lpServiceName [I] Name of the service to open
626 * dwDesiredAccess [I] Access required to the service
629 * Success: Handle to the service
632 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
633 DWORD dwDesiredAccess )
635 UNICODE_STRING lpServiceNameW;
637 RtlCreateUnicodeStringFromAsciiz (&lpServiceNameW,lpServiceName);
639 TRACE("Request for service %s\n",lpServiceName);
642 ret = OpenServiceW( hSCManager, lpServiceNameW.Buffer, dwDesiredAccess);
643 RtlFreeUnicodeString(&lpServiceNameW);
648 /******************************************************************************
649 * OpenServiceW [ADVAPI32.@]
653 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
654 DWORD dwDesiredAccess)
656 struct sc_handle *hscm = hSCManager;
657 struct sc_handle *retval;
661 TRACE("(%p,%p,%ld)\n",hSCManager, lpServiceName,
664 retval = alloc_sc_handle( SC_HTYPE_SERVICE );
668 r = RegOpenKeyExW( hscm->u.manager.hkey_scm_db,
669 lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
670 if (r!=ERROR_SUCCESS)
672 free_sc_handle( retval );
673 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
677 init_service_handle( retval, hscm, hKey, lpServiceName );
679 TRACE("returning %p\n",retval);
681 return (SC_HANDLE) retval;
684 /******************************************************************************
685 * CreateServiceW [ADVAPI32.@]
688 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
689 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
690 DWORD dwServiceType, DWORD dwStartType,
691 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
692 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
693 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
696 struct sc_handle *hscm = hSCManager;
697 struct sc_handle *retval;
701 static const WCHAR szDisplayName[] = { 'D','i','s','p','l','a','y','N','a','m','e', 0 };
702 static const WCHAR szType[] = {'T','y','p','e',0};
703 static const WCHAR szStart[] = {'S','t','a','r','t',0};
704 static const WCHAR szError[] = {'E','r','r','o','r','C','o','n','t','r','o','l', 0};
705 static const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
706 static const WCHAR szGroup[] = {'G','r','o','u','p',0};
707 static const WCHAR szDependencies[] = { 'D','e','p','e','n','d','e','n','c','i','e','s',0};
709 FIXME("%p %s %s\n", hSCManager,
710 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
712 retval = alloc_sc_handle( SC_HTYPE_SERVICE );
716 r = RegCreateKeyExW(hscm->u.manager.hkey_scm_db, lpServiceName, 0, NULL,
717 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
718 if (r!=ERROR_SUCCESS)
721 init_service_handle( retval, hscm, hKey, lpServiceName );
723 if (dp != REG_CREATED_NEW_KEY)
728 r = RegSetValueExW(hKey, szDisplayName, 0, REG_SZ, (const BYTE*)lpDisplayName,
729 (strlenW(lpDisplayName)+1)*sizeof(WCHAR) );
730 if (r!=ERROR_SUCCESS)
734 r = RegSetValueExW(hKey, szType, 0, REG_DWORD, (LPVOID)&dwServiceType, sizeof (DWORD) );
735 if (r!=ERROR_SUCCESS)
738 r = RegSetValueExW(hKey, szStart, 0, REG_DWORD, (LPVOID)&dwStartType, sizeof (DWORD) );
739 if (r!=ERROR_SUCCESS)
742 r = RegSetValueExW(hKey, szError, 0, REG_DWORD,
743 (LPVOID)&dwErrorControl, sizeof (DWORD) );
744 if (r!=ERROR_SUCCESS)
749 r = RegSetValueExW(hKey, szImagePath, 0, REG_SZ, (const BYTE*)lpBinaryPathName,
750 (strlenW(lpBinaryPathName)+1)*sizeof(WCHAR) );
751 if (r!=ERROR_SUCCESS)
757 r = RegSetValueExW(hKey, szGroup, 0, REG_SZ, (const BYTE*)lpLoadOrderGroup,
758 (strlenW(lpLoadOrderGroup)+1)*sizeof(WCHAR) );
759 if (r!=ERROR_SUCCESS)
767 /* determine the length of a double null terminated multi string */
769 len += (strlenW(&lpDependencies[len])+1);
770 } while (lpDependencies[len++]);
772 r = RegSetValueExW(hKey, szDependencies, 0, REG_MULTI_SZ,
773 (const BYTE*)lpDependencies, len );
774 if (r!=ERROR_SUCCESS)
780 FIXME("Don't know how to add a Password for a service.\n");
783 if(lpServiceStartName)
785 FIXME("Don't know how to add a ServiceStartName for a service.\n");
788 return (SC_HANDLE) retval;
791 free_sc_handle( retval );
796 /******************************************************************************
797 * CreateServiceA [ADVAPI32.@]
800 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
801 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
802 DWORD dwServiceType, DWORD dwStartType,
803 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
804 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
805 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
808 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
809 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
812 TRACE("%p %s %s\n", hSCManager,
813 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
815 lpServiceNameW = SERV_dup( lpServiceName );
816 lpDisplayNameW = SERV_dup( lpDisplayName );
817 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
818 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
819 lpDependenciesW = SERV_dupmulti( lpDependencies );
820 lpServiceStartNameW = SERV_dup( lpServiceStartName );
821 lpPasswordW = SERV_dup( lpPassword );
823 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
824 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
825 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
826 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
828 SERV_free( lpServiceNameW );
829 SERV_free( lpDisplayNameW );
830 SERV_free( lpBinaryPathNameW );
831 SERV_free( lpLoadOrderGroupW );
832 SERV_free( lpDependenciesW );
833 SERV_free( lpServiceStartNameW );
834 SERV_free( lpPasswordW );
840 /******************************************************************************
841 * DeleteService [ADVAPI32.@]
843 * Delete a service from the service control manager database.
846 * hService [I] Handle of the service to delete
852 BOOL WINAPI DeleteService( SC_HANDLE hService )
854 struct sc_handle *hsvc = hService;
855 HKEY hKey = hsvc->u.service.hkey;
856 WCHAR valname[MAX_PATH+1];
862 /* Clean out the values */
863 rc = RegEnumValueW(hKey, index, valname,&size,0,0,0,0);
864 while (rc == ERROR_SUCCESS)
866 RegDeleteValueW(hKey,valname);
869 rc = RegEnumValueW(hKey, index, valname, &size,0,0,0,0);
873 hsvc->u.service.hkey = NULL;
876 RegDeleteKeyW(hsvc->u.service.sc_manager->u.manager.hkey_scm_db,
877 hsvc->u.service.name);
883 /******************************************************************************
884 * StartServiceA [ADVAPI32.@]
889 * hService [I] Handle of service
890 * dwNumServiceArgs [I] Number of arguments
891 * lpServiceArgVectors [I] Address of array of argument strings
894 * - NT implements this function using an obscure RPC call.
895 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
896 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
897 * - This will only work for shared address space. How should the service
898 * args be transferred when address spaces are separated?
899 * - Can only start one service at a time.
900 * - Has no concept of privilege.
907 StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
908 LPCSTR *lpServiceArgVectors )
911 UNICODE_STRING usBuffer;
914 TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
917 lpwstr = (LPWSTR*) HeapAlloc( GetProcessHeap(), 0,
918 dwNumServiceArgs*sizeof(LPWSTR) );
922 for(i=0; i<dwNumServiceArgs; i++)
924 RtlCreateUnicodeStringFromAsciiz (&usBuffer,lpServiceArgVectors[i]);
925 lpwstr[i]=usBuffer.Buffer;
928 StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
932 for(i=0; i<dwNumServiceArgs; i++)
933 HeapFree(GetProcessHeap(), 0, lpwstr[i]);
934 HeapFree(GetProcessHeap(), 0, lpwstr);
941 /******************************************************************************
942 * StartServiceW [ADVAPI32.@]
947 StartServiceW( SC_HANDLE hService, DWORD dwNumServiceArgs,
948 LPCWSTR *lpServiceArgVectors )
950 static const WCHAR _WaitServiceStartW[] = {'A','D','V','A','P','I','_','W',
951 'a','i','t','S','e','r','v','i',
952 'c','e','S','t','a','r','t',0};
953 static const WCHAR _ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0};
955 struct sc_handle *hsvc = hService;
956 WCHAR path[MAX_PATH],str[MAX_PATH];
961 HANDLE hServiceShmem = NULL;
963 LPWSTR shmem_lock = NULL;
964 struct SEB *seb = NULL;
966 PROCESS_INFORMATION procinfo;
967 STARTUPINFOW startupinfo;
970 TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,
971 lpServiceArgVectors);
974 r = RegQueryValueExW(hsvc->u.service.hkey, _ImagePathW, NULL, &type, (LPVOID)str, &size);
975 if (r!=ERROR_SUCCESS)
977 ExpandEnvironmentStringsW(str,path,sizeof(path));
979 TRACE("Starting service %s\n", debugstr_w(path) );
981 hLock = LockServiceDatabase( hsvc->u.service.sc_manager );
986 * FIXME: start dependent services
989 /* pass argv[0] (service name) to the service via global SCM lock object */
990 shmem_lock = MapViewOfFile( hLock, FILE_MAP_ALL_ACCESS,
991 0, 0, MAX_SERVICE_NAME * sizeof(WCHAR) );
992 if( NULL == shmem_lock )
994 ERR("Couldn't map shared memory\n");
997 strcpyW( shmem_lock, hsvc->u.service.name );
999 /* create service environment block */
1000 size = sizeof(struct SEB);
1001 for( i = 0; i < dwNumServiceArgs; i++ )
1002 size += sizeof(WCHAR) * (1 + strlenW( lpServiceArgVectors[ i ] ));
1004 snprintfW( str, MAX_PATH, szServiceShmemNameFmtW, hsvc->u.service.name );
1005 hServiceShmem = CreateFileMappingW( INVALID_HANDLE_VALUE,
1006 NULL, PAGE_READWRITE, 0, size, str );
1007 if( NULL == hServiceShmem )
1009 ERR("Couldn't create shared memory object\n");
1012 if( GetLastError() == ERROR_ALREADY_EXISTS )
1014 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
1017 seb = MapViewOfFile( hServiceShmem, FILE_MAP_ALL_ACCESS, 0, 0, 0 );
1020 ERR("Couldn't map shared memory\n");
1024 /* copy service args to SEB */
1025 seb->argc = dwNumServiceArgs;
1026 argptr = (LPWSTR) &seb[1];
1027 for( i = 0; i < dwNumServiceArgs; i++ )
1029 strcpyW( argptr, lpServiceArgVectors[ i ] );
1030 argptr += 1 + strlenW( argptr );
1033 wait = CreateSemaphoreW(NULL,0,1,_WaitServiceStartW);
1036 ERR("Couldn't create wait semaphore\n");
1040 ZeroMemory(&startupinfo,sizeof(STARTUPINFOW));
1041 startupinfo.cb = sizeof(STARTUPINFOW);
1043 r = CreateProcessW(NULL,
1045 NULL, /* process security attribs */
1046 NULL, /* thread security attribs */
1047 FALSE, /* inherit handles */
1048 0, /* creation flags */
1049 NULL, /* environment */
1050 NULL, /* current directory */
1051 &startupinfo, /* startup info */
1052 &procinfo); /* process info */
1056 ERR("Couldn't start process\n");
1059 CloseHandle( procinfo.hThread );
1061 /* docs for StartServiceCtrlDispatcher say this should be 30 sec */
1062 r = WaitForSingleObject(wait,30000);
1063 if( WAIT_FAILED == r )
1065 CloseHandle( procinfo.hProcess );
1070 CloseHandle( procinfo.hProcess );
1074 if( wait ) CloseHandle( wait );
1075 if( seb != NULL ) UnmapViewOfFile( seb );
1076 if( hServiceShmem != NULL ) CloseHandle( hServiceShmem );
1077 if( shmem_lock != NULL ) UnmapViewOfFile( shmem_lock );
1078 UnlockServiceDatabase( hLock );
1082 /******************************************************************************
1083 * QueryServiceStatus [ADVAPI32.@]
1087 * lpservicestatus []
1091 QueryServiceStatus( SC_HANDLE hService, LPSERVICE_STATUS lpservicestatus )
1093 struct sc_handle *hsvc = hService;
1095 DWORD type, val, size;
1096 WCHAR str[MAX_PATH];
1097 HANDLE hServiceShmem = NULL;
1099 FIXME("(%p,%p) partial\n",hService,lpservicestatus);
1101 /* read the service type from the registry */
1103 r = RegQueryValueExA(hsvc->u.service.hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1106 ERR("invalid Type\n");
1109 lpservicestatus->dwServiceType = val;
1110 /* FIXME: how are these determined or read from the registry? */
1111 /* SERVICE: unavailable=0, stopped=1, starting=2, running=3? */
1113 /* Determine if currently running via named shared memory */
1114 snprintfW( str, MAX_PATH, szServiceShmemNameFmtW, hsvc->u.service.name );
1115 hServiceShmem = CreateFileMappingW( INVALID_HANDLE_VALUE,
1116 NULL, PAGE_READWRITE, 0, size, str );
1117 if( NULL == hServiceShmem )
1119 lpservicestatus->dwCurrentState = 1;
1121 if( GetLastError() == ERROR_ALREADY_EXISTS )
1123 lpservicestatus->dwCurrentState = 3;
1125 lpservicestatus->dwCurrentState = 1;
1127 CloseHandle( hServiceShmem );
1130 lpservicestatus->dwControlsAccepted = 0;
1131 lpservicestatus->dwWin32ExitCode = NO_ERROR;
1132 lpservicestatus->dwServiceSpecificExitCode = 0;
1133 lpservicestatus->dwCheckPoint = 0;
1134 lpservicestatus->dwWaitHint = 0;
1139 /******************************************************************************
1140 * QueryServiceStatusEx [ADVAPI32.@]
1142 * Get information about a service.
1145 * hService [I] Handle to service to get information about
1146 * InfoLevel [I] Level of information to get
1147 * lpBuffer [O] Destination for requested information
1148 * cbBufSize [I] Size of lpBuffer in bytes
1149 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1155 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1156 LPBYTE lpBuffer, DWORD cbBufSize,
1157 LPDWORD pcbBytesNeeded)
1160 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1164 /******************************************************************************
1165 * QueryServiceConfigA [ADVAPI32.@]
1168 QueryServiceConfigA( SC_HANDLE hService,
1169 LPQUERY_SERVICE_CONFIGA lpServiceConfig,
1170 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1172 static const CHAR szDisplayName[] = "DisplayName";
1173 static const CHAR szType[] = "Type";
1174 static const CHAR szStart[] = "Start";
1175 static const CHAR szError[] = "ErrorControl";
1176 static const CHAR szImagePath[] = "ImagePath";
1177 static const CHAR szGroup[] = "Group";
1178 static const CHAR szDependencies[] = "Dependencies";
1179 HKEY hKey = ((struct sc_handle*) hService)->u.service.hkey;
1180 CHAR str_buffer[ MAX_PATH ];
1182 DWORD type, val, sz, total, n;
1185 TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
1186 cbBufSize, pcbBytesNeeded);
1188 /* calculate the size required first */
1189 total = sizeof (QUERY_SERVICE_CONFIGA);
1191 sz = sizeof(str_buffer);
1192 r = RegQueryValueExA( hKey, szImagePath, 0, &type, str_buffer, &sz );
1193 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1195 sz = ExpandEnvironmentStringsA(str_buffer,NULL,0);
1196 if( 0 == sz ) return FALSE;
1202 /* FIXME: set last error */
1207 r = RegQueryValueExA( hKey, szGroup, 0, &type, NULL, &sz );
1208 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1212 r = RegQueryValueExA( hKey, szDependencies, 0, &type, NULL, &sz );
1213 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1217 r = RegQueryValueExA( hKey, szStart, 0, &type, NULL, &sz );
1218 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1222 r = RegQueryValueExA( hKey, szDisplayName, 0, &type, NULL, &sz );
1223 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1226 /* if there's not enough memory, return an error */
1227 if( total > *pcbBytesNeeded )
1229 *pcbBytesNeeded = total;
1230 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1234 *pcbBytesNeeded = total;
1235 ZeroMemory( lpServiceConfig, total );
1238 r = RegQueryValueExA( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1239 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1240 lpServiceConfig->dwServiceType = val;
1243 r = RegQueryValueExA( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1244 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1245 lpServiceConfig->dwStartType = val;
1248 r = RegQueryValueExA( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1249 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1250 lpServiceConfig->dwErrorControl = val;
1252 /* now do the strings */
1253 p = (LPBYTE) &lpServiceConfig[1];
1254 n = total - sizeof (QUERY_SERVICE_CONFIGA);
1256 sz = sizeof(str_buffer);
1257 r = RegQueryValueExA( hKey, szImagePath, 0, &type, str_buffer, &sz );
1258 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1260 sz = ExpandEnvironmentStringsA(str_buffer, p, n);
1261 if( 0 == sz || sz > n ) return FALSE;
1263 lpServiceConfig->lpBinaryPathName = (LPSTR) p;
1269 /* FIXME: set last error */
1274 r = RegQueryValueExA( hKey, szGroup, 0, &type, p, &sz );
1275 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1277 lpServiceConfig->lpLoadOrderGroup = (LPSTR) p;
1283 r = RegQueryValueExA( hKey, szDependencies, 0, &type, p, &sz );
1284 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1286 lpServiceConfig->lpDependencies = (LPSTR) p;
1292 ERR("Buffer overflow!\n");
1294 TRACE("Image path = %s\n", lpServiceConfig->lpBinaryPathName );
1295 TRACE("Group = %s\n", lpServiceConfig->lpLoadOrderGroup );
1300 /******************************************************************************
1301 * QueryServiceConfigW [ADVAPI32.@]
1304 QueryServiceConfigW( SC_HANDLE hService,
1305 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1306 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1308 static const WCHAR szDisplayName[] = {
1309 'D','i','s','p','l','a','y','N','a','m','e', 0 };
1310 static const WCHAR szType[] = {'T','y','p','e',0};
1311 static const WCHAR szStart[] = {'S','t','a','r','t',0};
1312 static const WCHAR szError[] = {
1313 'E','r','r','o','r','C','o','n','t','r','o','l', 0};
1314 static const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
1315 static const WCHAR szGroup[] = {'G','r','o','u','p',0};
1316 static const WCHAR szDependencies[] = {
1317 'D','e','p','e','n','d','e','n','c','i','e','s',0};
1318 HKEY hKey = ((struct sc_handle*) hService)->u.service.hkey;
1319 WCHAR str_buffer[ MAX_PATH ];
1321 DWORD type, val, sz, total, n;
1324 TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
1325 cbBufSize, pcbBytesNeeded);
1327 /* calculate the size required first */
1328 total = sizeof (QUERY_SERVICE_CONFIGW);
1330 sz = sizeof(str_buffer);
1331 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1332 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1334 sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1335 if( 0 == sz ) return FALSE;
1337 total += sizeof(WCHAR) * sz;
1341 /* FIXME: set last error */
1346 r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1347 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1351 r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1352 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1356 r = RegQueryValueExW( hKey, szStart, 0, &type, NULL, &sz );
1357 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1361 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1362 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1365 /* if there's not enough memory, return an error */
1366 if( total > *pcbBytesNeeded )
1368 *pcbBytesNeeded = total;
1369 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1373 *pcbBytesNeeded = total;
1374 ZeroMemory( lpServiceConfig, total );
1377 r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1378 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1379 lpServiceConfig->dwServiceType = val;
1382 r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1383 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1384 lpServiceConfig->dwStartType = val;
1387 r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1388 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1389 lpServiceConfig->dwErrorControl = val;
1391 /* now do the strings */
1392 p = (LPBYTE) &lpServiceConfig[1];
1393 n = total - sizeof (QUERY_SERVICE_CONFIGW);
1395 sz = sizeof(str_buffer);
1396 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1397 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1399 sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
1400 sz *= sizeof(WCHAR);
1401 if( 0 == sz || sz > n ) return FALSE;
1403 lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
1409 /* FIXME: set last error */
1414 r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
1415 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1417 lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
1423 r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
1424 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1426 lpServiceConfig->lpDependencies = (LPWSTR) p;
1432 ERR("Buffer overflow!\n");
1434 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1435 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1440 /******************************************************************************
1441 * ChangeServiceConfigW [ADVAPI32.@]
1443 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
1444 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1445 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
1446 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
1448 FIXME("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
1449 hService, dwServiceType, dwStartType, dwErrorControl,
1450 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
1451 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
1452 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
1456 /******************************************************************************
1457 * ChangeServiceConfigA [ADVAPI32.@]
1459 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
1460 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1461 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
1462 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
1464 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
1465 LPWSTR wServiceStartName, wPassword, wDisplayName;
1468 TRACE("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
1469 hService, dwServiceType, dwStartType, dwErrorControl,
1470 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
1471 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
1472 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
1474 wBinaryPathName = SERV_dup( lpBinaryPathName );
1475 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
1476 wDependencies = SERV_dupmulti( lpDependencies );
1477 wServiceStartName = SERV_dup( lpServiceStartName );
1478 wPassword = SERV_dup( lpPassword );
1479 wDisplayName = SERV_dup( lpDisplayName );
1481 r = ChangeServiceConfigW( hService, dwServiceType,
1482 dwStartType, dwErrorControl, wBinaryPathName,
1483 wLoadOrderGroup, lpdwTagId, wDependencies,
1484 wServiceStartName, wPassword, wDisplayName);
1486 SERV_free( wBinaryPathName );
1487 SERV_free( wLoadOrderGroup );
1488 SERV_free( wDependencies );
1489 SERV_free( wServiceStartName );
1490 SERV_free( wPassword );
1491 SERV_free( wDisplayName );
1496 /******************************************************************************
1497 * ChangeServiceConfig2A [ADVAPI32.@]
1499 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
1504 TRACE("%p %ld %p\n",hService, dwInfoLevel, lpInfo);
1506 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
1508 LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
1509 SERVICE_DESCRIPTIONW sdw;
1511 sdw.lpDescription = SERV_dup( sd->lpDescription );
1513 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
1515 SERV_free( sdw.lpDescription );
1517 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
1519 LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
1520 SERVICE_FAILURE_ACTIONSW faw;
1522 faw.dwResetPeriod = fa->dwResetPeriod;
1523 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
1524 faw.lpCommand = SERV_dup( fa->lpCommand );
1525 faw.cActions = fa->cActions;
1526 faw.lpsaActions = fa->lpsaActions;
1528 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
1530 SERV_free( faw.lpRebootMsg );
1531 SERV_free( faw.lpCommand );
1534 SetLastError( ERROR_INVALID_PARAMETER );
1539 /******************************************************************************
1540 * ChangeServiceConfig2W [ADVAPI32.@]
1542 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
1545 HKEY hKey = ((struct sc_handle*) hService)->u.service.hkey;
1547 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
1549 static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
1550 LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
1551 if (sd->lpDescription)
1553 TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
1554 if (sd->lpDescription[0] == 0)
1555 RegDeleteValueW(hKey,szDescription);
1557 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
1558 (LPVOID)sd->lpDescription,
1559 sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
1563 FIXME("STUB: %p %ld %p\n",hService, dwInfoLevel, lpInfo);
1567 /******************************************************************************
1568 * QueryServiceObjectSecurity [ADVAPI32.@]
1570 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
1571 SECURITY_INFORMATION dwSecurityInformation,
1572 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
1573 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1576 FIXME("%p %ld %p %lu %p\n", hService, dwSecurityInformation,
1577 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
1580 InitializeSecurityDescriptor(lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
1582 pACL = HeapAlloc( GetProcessHeap(), 0, sizeof(ACL) );
1583 InitializeAcl(pACL, sizeof(ACL), ACL_REVISION);
1584 SetSecurityDescriptorDacl(lpSecurityDescriptor, TRUE, pACL, TRUE);
1588 /******************************************************************************
1589 * SetServiceObjectSecurity [ADVAPI32.@]
1591 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
1592 SECURITY_INFORMATION dwSecurityInformation,
1593 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
1595 FIXME("%p %ld %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);