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 const WCHAR szServiceManagerKey[] = { 'S','y','s','t','e','m','\\',
38 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
39 'S','e','r','v','i','c','e','s','\\',0 };
40 static const WCHAR szSCMLock[] = {'A','D','V','A','P','I','_','S','C','M',
42 static const WCHAR szServiceShmemNameFmtW[] = {'A','D','V','A','P','I','_',
43 'S','E','B','_','%','s',0};
45 struct SEB /* service environment block */
46 { /* resides in service's shared memory object */
48 /* variable part of SEB contains service arguments */
51 /******************************************************************************
55 #define MAX_SERVICE_NAME 256
57 typedef enum { SC_HTYPE_MANAGER, SC_HTYPE_SERVICE } SC_HANDLE_TYPE;
61 struct sc_manager /* SCM handle */
63 HKEY hkey_scm_db; /* handle to services database in the registry */
64 LONG ref_count; /* handle must remain alive until any related service */
65 /* handle exists because DeleteService requires it */
68 struct sc_service /* service handle */
70 HKEY hkey; /* handle to service entry in the registry (under hkey_scm_db) */
71 struct sc_handle *sc_manager; /* pointer to SCM handle */
72 WCHAR name[ MAX_SERVICE_NAME ];
80 struct sc_manager manager;
81 struct sc_service service;
85 static struct sc_handle* alloc_sc_handle( SC_HANDLE_TYPE htype )
87 struct sc_handle *retval;
89 retval = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct sc_handle) );
92 retval->htype = htype;
94 TRACE("SC_HANDLE type=%d -> %p\n",htype,retval);
98 static void free_sc_handle( struct sc_handle* handle )
103 switch( handle->htype )
105 case SC_HTYPE_MANAGER:
107 if( InterlockedDecrement( &handle->u.manager.ref_count ) )
108 /* there are references to this handle */
111 if( handle->u.manager.hkey_scm_db )
112 RegCloseKey( handle->u.manager.hkey_scm_db );
116 case SC_HTYPE_SERVICE:
118 struct sc_handle *h = handle->u.service.sc_manager;
122 /* release SCM handle */
123 if( 0 == InterlockedDecrement( &h->u.manager.ref_count ) )
125 /* it's time to destroy SCM handle */
126 if( h->u.manager.hkey_scm_db )
127 RegCloseKey( h->u.manager.hkey_scm_db );
129 TRACE("SC_HANDLE (SCM) %p type=%d\n",h,h->htype);
131 HeapFree( GetProcessHeap(), 0, h );
134 if( handle->u.service.hkey )
135 RegCloseKey( handle->u.service.hkey );
140 TRACE("SC_HANDLE %p type=%d\n",handle,handle->htype);
142 HeapFree( GetProcessHeap(), 0, handle );
145 static void init_service_handle( struct sc_handle* handle,
146 struct sc_handle* sc_manager,
147 HKEY hKey, LPCWSTR lpServiceName )
149 /* init sc_service structure */
150 handle->u.service.hkey = hKey;
151 lstrcpynW( handle->u.service.name, lpServiceName, MAX_SERVICE_NAME );
153 /* add reference to SCM handle */
154 InterlockedIncrement( &sc_manager->u.manager.ref_count );
155 handle->u.service.sc_manager = sc_manager;
158 /******************************************************************************
159 * EnumServicesStatusA [ADVAPI32.@]
162 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
163 DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
164 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
165 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
166 { FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
167 dwServiceType, dwServiceState, lpServices, cbBufSize,
168 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
169 SetLastError (ERROR_ACCESS_DENIED);
173 /******************************************************************************
174 * EnumServicesStatusW [ADVAPI32.@]
177 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
178 DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
179 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
180 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
181 { FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
182 dwServiceType, dwServiceState, lpServices, cbBufSize,
183 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
184 SetLastError (ERROR_ACCESS_DENIED);
188 /******************************************************************************
191 * helper function for StartServiceCtrlDispatcherA/W
193 * SCM database is locked by StartService;
194 * open global SCM lock object and read service name
196 static BOOL read_scm_lock_data( LPWSTR buffer )
201 hLock = OpenFileMappingW( FILE_MAP_ALL_ACCESS, FALSE, szSCMLock );
204 SetLastError( ERROR_FAILED_SERVICE_CONTROLLER_CONNECT );
207 argptr = MapViewOfFile( hLock, FILE_MAP_ALL_ACCESS,
208 0, 0, MAX_SERVICE_NAME * sizeof(WCHAR) );
211 CloseHandle( hLock );
214 strcpyW( buffer, argptr );
215 UnmapViewOfFile( argptr );
216 CloseHandle( hLock );
220 /******************************************************************************
223 * helper function for StartServiceCtrlDispatcherA/W
225 static struct SEB* open_seb_shmem( LPWSTR service_name, HANDLE* hServiceShmem )
227 WCHAR object_name[ MAX_PATH ];
231 snprintfW( object_name, MAX_PATH, szServiceShmemNameFmtW, service_name );
232 hmem = OpenFileMappingW( FILE_MAP_ALL_ACCESS, FALSE, object_name );
236 ret = MapViewOfFile( hmem, FILE_MAP_ALL_ACCESS, 0, 0, 0 );
240 *hServiceShmem = hmem;
244 /******************************************************************************
247 * helper function for StartServiceCtrlDispatcherA/W
249 * Allocate and initialize array of LPWSTRs to arguments in variable part
250 * of service environment block.
251 * First entry in the array is reserved for service name and not initialized.
253 static LPWSTR* build_arg_vectors( struct SEB* seb )
259 ret = HeapAlloc( GetProcessHeap(), 0, (1 + seb->argc) * sizeof(LPWSTR) );
263 argptr = (LPWSTR) &seb[1];
264 for( i = 0; i < seb->argc; i++ )
266 ret[ 1 + i ] = argptr;
267 argptr += 1 + strlenW( argptr );
272 /******************************************************************************
273 * StartServiceCtrlDispatcherA [ADVAPI32.@]
276 StartServiceCtrlDispatcherA( LPSERVICE_TABLE_ENTRYA servent )
278 LPSERVICE_MAIN_FUNCTIONA fpMain;
279 WCHAR service_name[ MAX_SERVICE_NAME ];
280 HANDLE hServiceShmem = NULL;
281 struct SEB *seb = NULL;
282 DWORD dwNumServiceArgs = 0;
283 LPWSTR *lpArgVecW = NULL;
284 LPSTR *lpArgVecA = NULL;
288 TRACE("(%p)\n", servent);
290 if( ! read_scm_lock_data( service_name ) )
292 /* FIXME: Instead of exiting we allow
293 service to be executed as ordinary program.
294 This behaviour was specially introduced in the patch
295 submitted against revision 1.45 and so preserved here.
297 FIXME("should fail with ERROR_FAILED_SERVICE_CONTROLLER_CONNECT\n");
298 servent->lpServiceProc( 0, NULL );
302 seb = open_seb_shmem( service_name, &hServiceShmem );
306 lpArgVecW = build_arg_vectors( seb );
307 if( NULL == lpArgVecW )
310 lpArgVecW[0] = service_name;
311 dwNumServiceArgs = seb->argc + 1;
313 /* Convert the Unicode arg vectors back to ASCII */
314 lpArgVecA = (LPSTR*) HeapAlloc( GetProcessHeap(), 0,
315 dwNumServiceArgs*sizeof(LPSTR) );
316 for(i=0; i<dwNumServiceArgs; i++)
317 lpArgVecA[i]=HEAP_strdupWtoA(GetProcessHeap(), 0, lpArgVecW[i]);
319 /* FIXME: find service entry by name if SERVICE_WIN32_SHARE_PROCESS */
320 TRACE("%s at %p)\n", debugstr_a(servent->lpServiceName),servent);
321 fpMain = servent->lpServiceProc;
323 /* try to start the service */
324 fpMain( dwNumServiceArgs, lpArgVecA);
329 /* free arg strings */
330 for(i=0; i<dwNumServiceArgs; i++)
331 HeapFree(GetProcessHeap(), 0, lpArgVecA[i]);
332 HeapFree(GetProcessHeap(), 0, lpArgVecA);
335 if( lpArgVecW ) HeapFree( GetProcessHeap(), 0, lpArgVecW );
336 if( seb ) UnmapViewOfFile( seb );
337 if( hServiceShmem ) CloseHandle( hServiceShmem );
341 /******************************************************************************
342 * StartServiceCtrlDispatcherW [ADVAPI32.@]
348 StartServiceCtrlDispatcherW( LPSERVICE_TABLE_ENTRYW servent )
350 LPSERVICE_MAIN_FUNCTIONW fpMain;
351 WCHAR service_name[ MAX_SERVICE_NAME ];
352 HANDLE hServiceShmem = NULL;
354 DWORD dwNumServiceArgs ;
355 LPWSTR *lpServiceArgVectors ;
357 TRACE("(%p)\n", servent);
359 if( ! read_scm_lock_data( service_name ) )
362 seb = open_seb_shmem( service_name, &hServiceShmem );
366 lpServiceArgVectors = build_arg_vectors( seb );
367 if( NULL == lpServiceArgVectors )
369 UnmapViewOfFile( seb );
370 CloseHandle( hServiceShmem );
373 lpServiceArgVectors[0] = service_name;
374 dwNumServiceArgs = seb->argc + 1;
376 /* FIXME: find service entry by name if SERVICE_WIN32_SHARE_PROCESS */
377 TRACE("%s at %p)\n", debugstr_w(servent->lpServiceName),servent);
378 fpMain = servent->lpServiceProc;
380 /* try to start the service */
381 fpMain( dwNumServiceArgs, lpServiceArgVectors);
383 HeapFree( GetProcessHeap(), 0, lpServiceArgVectors );
384 UnmapViewOfFile( seb );
385 CloseHandle( hServiceShmem );
389 /******************************************************************************
390 * LockServiceDatabase [ADVAPI32.@]
392 LPVOID WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
396 TRACE("%p\n",hSCManager);
398 ret = CreateFileMappingW( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
399 0, MAX_SERVICE_NAME * sizeof(WCHAR), szSCMLock );
400 if( ret && GetLastError() == ERROR_ALREADY_EXISTS )
404 SetLastError( ERROR_SERVICE_DATABASE_LOCKED );
407 TRACE("returning %p\n", ret);
412 /******************************************************************************
413 * UnlockServiceDatabase [ADVAPI32.@]
415 BOOL WINAPI UnlockServiceDatabase (LPVOID ScLock)
417 TRACE("%p\n",ScLock);
419 return CloseHandle( (HANDLE) ScLock );
422 /******************************************************************************
423 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
425 SERVICE_STATUS_HANDLE WINAPI
426 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName,
427 LPHANDLER_FUNCTION lpfHandler )
428 { FIXME("%s %p\n", lpServiceName, lpfHandler);
432 /******************************************************************************
433 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
439 SERVICE_STATUS_HANDLE WINAPI
440 RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName,
441 LPHANDLER_FUNCTION lpfHandler )
442 { FIXME("%s %p\n", debugstr_w(lpServiceName), lpfHandler);
446 /******************************************************************************
447 * SetServiceStatus [ADVAPI32.@]
454 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
455 { FIXME("0x%lx %p\n",hService, lpStatus);
456 TRACE("\tType:%lx\n",lpStatus->dwServiceType);
457 TRACE("\tState:%lx\n",lpStatus->dwCurrentState);
458 TRACE("\tControlAccepted:%lx\n",lpStatus->dwControlsAccepted);
459 TRACE("\tExitCode:%lx\n",lpStatus->dwWin32ExitCode);
460 TRACE("\tServiceExitCode:%lx\n",lpStatus->dwServiceSpecificExitCode);
461 TRACE("\tCheckPoint:%lx\n",lpStatus->dwCheckPoint);
462 TRACE("\tWaitHint:%lx\n",lpStatus->dwWaitHint);
466 /******************************************************************************
467 * OpenSCManagerA [ADVAPI32.@]
469 * Establish a connection to the service control manager and open its database.
472 * lpMachineName [I] Pointer to machine name string
473 * lpDatabaseName [I] Pointer to database name string
474 * dwDesiredAccess [I] Type of access
477 * Success: A Handle to the service control manager database
480 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
481 DWORD dwDesiredAccess )
483 UNICODE_STRING lpMachineNameW;
484 UNICODE_STRING lpDatabaseNameW;
487 RtlCreateUnicodeStringFromAsciiz (&lpMachineNameW,lpMachineName);
488 RtlCreateUnicodeStringFromAsciiz (&lpDatabaseNameW,lpDatabaseName);
489 ret = OpenSCManagerW(lpMachineNameW.Buffer,lpDatabaseNameW.Buffer, dwDesiredAccess);
490 RtlFreeUnicodeString(&lpDatabaseNameW);
491 RtlFreeUnicodeString(&lpMachineNameW);
495 /******************************************************************************
496 * OpenSCManagerW [ADVAPI32.@]
498 * See OpenSCManagerA.
500 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
501 DWORD dwDesiredAccess )
503 struct sc_handle *retval;
507 TRACE("(%s,%s,0x%08lx)\n", debugstr_w(lpMachineName),
508 debugstr_w(lpDatabaseName), dwDesiredAccess);
511 * FIXME: what is lpDatabaseName?
512 * It should be set to "SERVICES_ACTIVE_DATABASE" according to
513 * docs, but what if it isn't?
516 retval = alloc_sc_handle( SC_HTYPE_MANAGER );
517 if( NULL == retval ) return NULL;
519 retval->u.manager.ref_count = 1;
521 r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
522 if (r!=ERROR_SUCCESS)
525 r = RegOpenKeyExW(hReg, szServiceManagerKey,
526 0, KEY_ALL_ACCESS, &retval->u.manager.hkey_scm_db);
528 if (r!=ERROR_SUCCESS)
531 TRACE("returning %p\n", retval);
533 return (SC_HANDLE) retval;
536 free_sc_handle( retval );
540 /******************************************************************************
541 * ControlService [ADVAPI32.@]
543 * Send a control code to a service.
546 * hService [I] Handle of the service control manager database
547 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
548 * lpServiceStatus [O] Destination for the status of the service, if available
554 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
555 LPSERVICE_STATUS lpServiceStatus )
557 FIXME("(%p,%ld,%p): stub\n",hService,dwControl,lpServiceStatus);
562 /******************************************************************************
563 * CloseServiceHandle [ADVAPI32.@]
565 * Close a handle to a service or the service control manager database.
568 * hSCObject [I] Handle to service or service control manager database
575 CloseServiceHandle( SC_HANDLE hSCObject )
577 TRACE("(%p)\n", hSCObject);
579 free_sc_handle( (struct sc_handle*) hSCObject );
585 /******************************************************************************
586 * OpenServiceA [ADVAPI32.@]
588 * Open a handle to a service.
591 * hSCManager [I] Handle of the service control manager database
592 * lpServiceName [I] Name of the service to open
593 * dwDesiredAccess [I] Access required to the service
596 * Success: Handle to the service
599 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
600 DWORD dwDesiredAccess )
602 UNICODE_STRING lpServiceNameW;
604 RtlCreateUnicodeStringFromAsciiz (&lpServiceNameW,lpServiceName);
606 TRACE("Request for service %s\n",lpServiceName);
609 ret = OpenServiceW( hSCManager, lpServiceNameW.Buffer, dwDesiredAccess);
610 RtlFreeUnicodeString(&lpServiceNameW);
615 /******************************************************************************
616 * OpenServiceW [ADVAPI32.@]
620 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
621 DWORD dwDesiredAccess)
623 struct sc_handle *hscm = hSCManager;
624 struct sc_handle *retval;
628 TRACE("(%p,%p,%ld)\n",hSCManager, lpServiceName,
631 retval = alloc_sc_handle( SC_HTYPE_SERVICE );
635 r = RegOpenKeyExW( hscm->u.manager.hkey_scm_db,
636 lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
637 if (r!=ERROR_SUCCESS)
639 free_sc_handle( retval );
640 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
644 init_service_handle( retval, hscm, hKey, lpServiceName );
646 TRACE("returning %p\n",retval);
648 return (SC_HANDLE) retval;
651 /******************************************************************************
652 * CreateServiceW [ADVAPI32.@]
655 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
656 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
657 DWORD dwServiceType, DWORD dwStartType,
658 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
659 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
660 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
663 struct sc_handle *hscm = hSCManager;
664 struct sc_handle *retval;
668 static const WCHAR szDisplayName[] = { 'D','i','s','p','l','a','y','N','a','m','e', 0 };
669 static const WCHAR szType[] = {'T','y','p','e',0};
670 static const WCHAR szStart[] = {'S','t','a','r','t',0};
671 static const WCHAR szError[] = {'E','r','r','o','r','C','o','n','t','r','o','l', 0};
672 static const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
673 static const WCHAR szGroup[] = {'G','r','o','u','p',0};
674 static const WCHAR szDependencies[] = { 'D','e','p','e','n','d','e','n','c','i','e','s',0};
676 FIXME("%p %s %s\n", hSCManager,
677 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
679 retval = alloc_sc_handle( SC_HTYPE_SERVICE );
683 r = RegCreateKeyExW(hscm->u.manager.hkey_scm_db, lpServiceName, 0, NULL,
684 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
685 if (r!=ERROR_SUCCESS)
688 init_service_handle( retval, hscm, hKey, lpServiceName );
690 if (dp != REG_CREATED_NEW_KEY)
695 r = RegSetValueExW(hKey, szDisplayName, 0, REG_SZ, (LPBYTE)lpDisplayName,
696 (strlenW(lpDisplayName)+1)*sizeof(WCHAR) );
697 if (r!=ERROR_SUCCESS)
701 r = RegSetValueExW(hKey, szType, 0, REG_DWORD, (LPVOID)&dwServiceType, sizeof (DWORD) );
702 if (r!=ERROR_SUCCESS)
705 r = RegSetValueExW(hKey, szStart, 0, REG_DWORD, (LPVOID)&dwStartType, sizeof (DWORD) );
706 if (r!=ERROR_SUCCESS)
709 r = RegSetValueExW(hKey, szError, 0, REG_DWORD,
710 (LPVOID)&dwErrorControl, sizeof (DWORD) );
711 if (r!=ERROR_SUCCESS)
716 r = RegSetValueExW(hKey, szImagePath, 0, REG_SZ, (LPBYTE)lpBinaryPathName,
717 (strlenW(lpBinaryPathName)+1)*sizeof(WCHAR) );
718 if (r!=ERROR_SUCCESS)
724 r = RegSetValueExW(hKey, szGroup, 0, REG_SZ, (LPBYTE)lpLoadOrderGroup,
725 (strlenW(lpLoadOrderGroup)+1)*sizeof(WCHAR) );
726 if (r!=ERROR_SUCCESS)
734 /* determine the length of a double null terminated multi string */
736 len += (strlenW(&lpDependencies[len])+1);
737 } while (lpDependencies[len++]);
739 r = RegSetValueExW(hKey, szDependencies, 0, REG_MULTI_SZ,
740 (LPBYTE)lpDependencies, len );
741 if (r!=ERROR_SUCCESS)
747 FIXME("Don't know how to add a Password for a service.\n");
750 if(lpServiceStartName)
752 FIXME("Don't know how to add a ServiceStartName for a service.\n");
755 return (SC_HANDLE) retval;
758 free_sc_handle( retval );
763 static inline LPWSTR SERV_dup( LPCSTR str )
770 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
771 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
772 MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
776 static inline LPWSTR SERV_dupmulti( LPCSTR str )
784 len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
785 n += (strlen( &str[n] ) + 1);
790 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
791 MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
795 static inline VOID SERV_free( LPWSTR wstr )
797 HeapFree( GetProcessHeap(), 0, wstr );
800 /******************************************************************************
801 * CreateServiceA [ADVAPI32.@]
804 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
805 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
806 DWORD dwServiceType, DWORD dwStartType,
807 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
808 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
809 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
812 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
813 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
816 TRACE("%p %s %s\n", hSCManager,
817 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
819 lpServiceNameW = SERV_dup( lpServiceName );
820 lpDisplayNameW = SERV_dup( lpDisplayName );
821 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
822 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
823 lpDependenciesW = SERV_dupmulti( lpDependencies );
824 lpServiceStartNameW = SERV_dup( lpServiceStartName );
825 lpPasswordW = SERV_dup( lpPassword );
827 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
828 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
829 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
830 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
832 SERV_free( lpServiceNameW );
833 SERV_free( lpDisplayNameW );
834 SERV_free( lpBinaryPathNameW );
835 SERV_free( lpLoadOrderGroupW );
836 SERV_free( lpDependenciesW );
837 SERV_free( lpServiceStartNameW );
838 SERV_free( lpPasswordW );
844 /******************************************************************************
845 * DeleteService [ADVAPI32.@]
847 * Delete a service from the service control manager database.
850 * hService [I] Handle of the service to delete
856 BOOL WINAPI DeleteService( SC_HANDLE hService )
858 struct sc_handle *hsvc = hService;
859 HKEY hKey = hsvc->u.service.hkey;
860 WCHAR valname[MAX_PATH+1];
866 /* Clean out the values */
867 rc = RegEnumValueW(hKey, index, valname,&size,0,0,0,0);
868 while (rc == ERROR_SUCCESS)
870 RegDeleteValueW(hKey,valname);
873 rc = RegEnumValueW(hKey, index, valname, &size,0,0,0,0);
877 hsvc->u.service.hkey = NULL;
880 RegDeleteKeyW(hsvc->u.service.sc_manager->u.manager.hkey_scm_db,
881 hsvc->u.service.name);
887 /******************************************************************************
888 * StartServiceA [ADVAPI32.@]
893 * hService [I] Handle of service
894 * dwNumServiceArgs [I] Number of arguments
895 * lpServiceArgVectors [I] Address of array of argument strings
898 * - NT implements this function using an obscure RPC call.
899 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
900 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
901 * - This will only work for shared address space. How should the service
902 * args be transferred when address spaces are separated?
903 * - Can only start one service at a time.
904 * - Has no concept of privilege.
911 StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
912 LPCSTR *lpServiceArgVectors )
915 UNICODE_STRING usBuffer;
918 TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
921 lpwstr = (LPWSTR*) HeapAlloc( GetProcessHeap(), 0,
922 dwNumServiceArgs*sizeof(LPWSTR) );
926 for(i=0; i<dwNumServiceArgs; i++)
928 RtlCreateUnicodeStringFromAsciiz (&usBuffer,lpServiceArgVectors[i]);
929 lpwstr[i]=usBuffer.Buffer;
932 StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
936 for(i=0; i<dwNumServiceArgs; i++)
937 HeapFree(GetProcessHeap(), 0, lpwstr[i]);
938 HeapFree(GetProcessHeap(), 0, lpwstr);
945 /******************************************************************************
946 * StartServiceW [ADVAPI32.@]
951 StartServiceW( SC_HANDLE hService, DWORD dwNumServiceArgs,
952 LPCWSTR *lpServiceArgVectors )
954 static const WCHAR _WaitServiceStartW[] = {'A','D','V','A','P','I','_','W',
955 'a','i','t','S','e','r','v','i',
956 'c','e','S','t','a','r','t',0};
957 static const WCHAR _ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0};
959 struct sc_handle *hsvc = hService;
960 WCHAR path[MAX_PATH],str[MAX_PATH];
965 HANDLE hServiceShmem = NULL;
967 LPWSTR shmem_lock = NULL;
968 struct SEB *seb = NULL;
970 PROCESS_INFORMATION procinfo;
971 STARTUPINFOW startupinfo;
974 TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,
975 lpServiceArgVectors);
978 r = RegQueryValueExW(hsvc->u.service.hkey, _ImagePathW, NULL, &type, (LPVOID)str, &size);
979 if (r!=ERROR_SUCCESS)
981 ExpandEnvironmentStringsW(str,path,sizeof(path));
983 TRACE("Starting service %s\n", debugstr_w(path) );
985 hLock = LockServiceDatabase( hsvc->u.service.sc_manager );
990 * FIXME: start dependent services
993 /* pass argv[0] (service name) to the service via global SCM lock object */
994 shmem_lock = MapViewOfFile( hLock, FILE_MAP_ALL_ACCESS,
995 0, 0, MAX_SERVICE_NAME * sizeof(WCHAR) );
996 if( NULL == shmem_lock )
998 ERR("Couldn't map shared memory\n");
1001 strcpyW( shmem_lock, hsvc->u.service.name );
1003 /* create service environment block */
1004 size = sizeof(struct SEB);
1005 for( i = 0; i < dwNumServiceArgs; i++ )
1006 size += sizeof(WCHAR) * (1 + strlenW( lpServiceArgVectors[ i ] ));
1008 snprintfW( str, MAX_PATH, szServiceShmemNameFmtW, hsvc->u.service.name );
1009 hServiceShmem = CreateFileMappingW( INVALID_HANDLE_VALUE,
1010 NULL, PAGE_READWRITE, 0, size, str );
1011 if( NULL == hServiceShmem )
1013 ERR("Couldn't create shared memory object\n");
1016 if( GetLastError() == ERROR_ALREADY_EXISTS )
1018 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
1021 seb = MapViewOfFile( hServiceShmem, FILE_MAP_ALL_ACCESS, 0, 0, 0 );
1024 ERR("Couldn't map shared memory\n");
1028 /* copy service args to SEB */
1029 seb->argc = dwNumServiceArgs;
1030 argptr = (LPWSTR) &seb[1];
1031 for( i = 0; i < dwNumServiceArgs; i++ )
1033 strcpyW( argptr, lpServiceArgVectors[ i ] );
1034 argptr += 1 + strlenW( argptr );
1037 wait = CreateSemaphoreW(NULL,0,1,_WaitServiceStartW);
1040 ERR("Couldn't create wait semaphore\n");
1044 ZeroMemory(&startupinfo,sizeof(STARTUPINFOW));
1045 startupinfo.cb = sizeof(STARTUPINFOW);
1047 r = CreateProcessW(NULL,
1049 NULL, /* process security attribs */
1050 NULL, /* thread security attribs */
1051 FALSE, /* inherit handles */
1052 0, /* creation flags */
1053 NULL, /* environment */
1054 NULL, /* current directory */
1055 &startupinfo, /* startup info */
1056 &procinfo); /* process info */
1060 ERR("Couldn't start process\n");
1063 CloseHandle( procinfo.hThread );
1065 /* docs for StartServiceCtrlDispatcher say this should be 30 sec */
1066 r = WaitForSingleObject(wait,30000);
1067 if( WAIT_FAILED == r )
1069 CloseHandle( procinfo.hProcess );
1074 CloseHandle( procinfo.hProcess );
1078 if( wait ) CloseHandle( wait );
1079 if( seb != NULL ) UnmapViewOfFile( seb );
1080 if( hServiceShmem != NULL ) CloseHandle( hServiceShmem );
1081 if( shmem_lock != NULL ) UnmapViewOfFile( shmem_lock );
1082 UnlockServiceDatabase( hLock );
1086 /******************************************************************************
1087 * QueryServiceStatus [ADVAPI32.@]
1091 * lpservicestatus []
1095 QueryServiceStatus( SC_HANDLE hService, LPSERVICE_STATUS lpservicestatus )
1097 struct sc_handle *hsvc = hService;
1099 DWORD type, val, size;
1101 FIXME("(%p,%p) partial\n",hService,lpservicestatus);
1103 /* read the service type from the registry */
1105 r = RegQueryValueExA(hsvc->u.service.hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1108 ERR("invalid Type\n");
1111 lpservicestatus->dwServiceType = val;
1112 /* FIXME: how are these determined or read from the registry? */
1113 /* SERVICE: unavailable=0, stopped=1, starting=2, running=3? */;
1114 lpservicestatus->dwCurrentState = 1;
1115 lpservicestatus->dwControlsAccepted = 0;
1116 lpservicestatus->dwWin32ExitCode = NO_ERROR;
1117 lpservicestatus->dwServiceSpecificExitCode = 0;
1118 lpservicestatus->dwCheckPoint = 0;
1119 lpservicestatus->dwWaitHint = 0;
1124 /******************************************************************************
1125 * QueryServiceStatusEx [ADVAPI32.@]
1127 * Get information about a service.
1130 * hService [I] Handle to service to get information about
1131 * InfoLevel [I] Level of information to get
1132 * lpBuffer [O] Destination for requested information
1133 * cbBufSize [I] Size of lpBuffer in bytes
1134 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1140 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1141 LPBYTE lpBuffer, DWORD cbBufSize,
1142 LPDWORD pcbBytesNeeded)
1145 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1149 /******************************************************************************
1150 * QueryServiceConfigA [ADVAPI32.@]
1153 QueryServiceConfigA( SC_HANDLE hService,
1154 LPQUERY_SERVICE_CONFIGA lpServiceConfig,
1155 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1157 static const CHAR szDisplayName[] = "DisplayName";
1158 static const CHAR szType[] = "Type";
1159 static const CHAR szStart[] = "Start";
1160 static const CHAR szError[] = "ErrorControl";
1161 static const CHAR szImagePath[] = "ImagePath";
1162 static const CHAR szGroup[] = "Group";
1163 static const CHAR szDependencies[] = "Dependencies";
1164 HKEY hKey = ((struct sc_handle*) hService)->u.service.hkey;
1165 CHAR str_buffer[ MAX_PATH ];
1167 DWORD type, val, sz, total, n;
1170 TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
1171 cbBufSize, pcbBytesNeeded);
1173 /* calculate the size required first */
1174 total = sizeof (QUERY_SERVICE_CONFIGA);
1176 sz = sizeof(str_buffer);
1177 r = RegQueryValueExA( hKey, szImagePath, 0, &type, str_buffer, &sz );
1178 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1180 sz = ExpandEnvironmentStringsA(str_buffer,NULL,0);
1181 if( 0 == sz ) return FALSE;
1187 /* FIXME: set last error */
1192 r = RegQueryValueExA( hKey, szGroup, 0, &type, NULL, &sz );
1193 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1197 r = RegQueryValueExA( hKey, szDependencies, 0, &type, NULL, &sz );
1198 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1202 r = RegQueryValueExA( hKey, szStart, 0, &type, NULL, &sz );
1203 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1207 r = RegQueryValueExA( hKey, szDisplayName, 0, &type, NULL, &sz );
1208 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1211 /* if there's not enough memory, return an error */
1212 if( total > *pcbBytesNeeded )
1214 *pcbBytesNeeded = total;
1215 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1219 *pcbBytesNeeded = total;
1220 ZeroMemory( lpServiceConfig, total );
1223 r = RegQueryValueExA( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1224 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1225 lpServiceConfig->dwServiceType = val;
1228 r = RegQueryValueExA( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1229 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1230 lpServiceConfig->dwStartType = val;
1233 r = RegQueryValueExA( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1234 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1235 lpServiceConfig->dwErrorControl = val;
1237 /* now do the strings */
1238 p = (LPBYTE) &lpServiceConfig[1];
1239 n = total - sizeof (QUERY_SERVICE_CONFIGA);
1241 sz = sizeof(str_buffer);
1242 r = RegQueryValueExA( hKey, szImagePath, 0, &type, str_buffer, &sz );
1243 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1245 sz = ExpandEnvironmentStringsA(str_buffer, p, n);
1246 if( 0 == sz || sz > n ) return FALSE;
1248 lpServiceConfig->lpBinaryPathName = (LPSTR) p;
1254 /* FIXME: set last error */
1259 r = RegQueryValueExA( hKey, szGroup, 0, &type, p, &sz );
1260 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1262 lpServiceConfig->lpLoadOrderGroup = (LPSTR) p;
1268 r = RegQueryValueExA( hKey, szDependencies, 0, &type, p, &sz );
1269 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1271 lpServiceConfig->lpDependencies = (LPSTR) p;
1277 ERR("Buffer overflow!\n");
1279 TRACE("Image path = %s\n", lpServiceConfig->lpBinaryPathName );
1280 TRACE("Group = %s\n", lpServiceConfig->lpLoadOrderGroup );
1285 /******************************************************************************
1286 * QueryServiceConfigW [ADVAPI32.@]
1289 QueryServiceConfigW( SC_HANDLE hService,
1290 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1291 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1293 static const WCHAR szDisplayName[] = {
1294 'D','i','s','p','l','a','y','N','a','m','e', 0 };
1295 static const WCHAR szType[] = {'T','y','p','e',0};
1296 static const WCHAR szStart[] = {'S','t','a','r','t',0};
1297 static const WCHAR szError[] = {
1298 'E','r','r','o','r','C','o','n','t','r','o','l', 0};
1299 static const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
1300 static const WCHAR szGroup[] = {'G','r','o','u','p',0};
1301 static const WCHAR szDependencies[] = {
1302 'D','e','p','e','n','d','e','n','c','i','e','s',0};
1303 HKEY hKey = ((struct sc_handle*) hService)->u.service.hkey;
1304 WCHAR str_buffer[ MAX_PATH ];
1306 DWORD type, val, sz, total, n;
1309 TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
1310 cbBufSize, pcbBytesNeeded);
1312 /* calculate the size required first */
1313 total = sizeof (QUERY_SERVICE_CONFIGW);
1315 sz = sizeof(str_buffer);
1316 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1317 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1319 sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1320 if( 0 == sz ) return FALSE;
1322 total += sizeof(WCHAR) * sz;
1326 /* FIXME: set last error */
1331 r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1332 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1336 r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1337 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1341 r = RegQueryValueExW( hKey, szStart, 0, &type, NULL, &sz );
1342 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1346 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1347 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1350 /* if there's not enough memory, return an error */
1351 if( total > *pcbBytesNeeded )
1353 *pcbBytesNeeded = total;
1354 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1358 *pcbBytesNeeded = total;
1359 ZeroMemory( lpServiceConfig, total );
1362 r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1363 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1364 lpServiceConfig->dwServiceType = val;
1367 r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1368 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1369 lpServiceConfig->dwStartType = val;
1372 r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1373 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1374 lpServiceConfig->dwErrorControl = val;
1376 /* now do the strings */
1377 p = (LPBYTE) &lpServiceConfig[1];
1378 n = total - sizeof (QUERY_SERVICE_CONFIGW);
1380 sz = sizeof(str_buffer);
1381 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1382 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1384 sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
1385 sz *= sizeof(WCHAR);
1386 if( 0 == sz || sz > n ) return FALSE;
1388 lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
1394 /* FIXME: set last error */
1399 r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
1400 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1402 lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
1408 r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
1409 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1411 lpServiceConfig->lpDependencies = (LPWSTR) p;
1417 ERR("Buffer overflow!\n");
1419 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1420 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1425 /******************************************************************************
1426 * ChangeServiceConfigW [ADVAPI32.@]
1428 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
1429 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1430 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
1431 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
1433 FIXME("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
1434 hService, dwServiceType, dwStartType, dwErrorControl,
1435 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
1436 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
1437 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
1441 /******************************************************************************
1442 * ChangeServiceConfigA [ADVAPI32.@]
1444 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
1445 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1446 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
1447 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
1449 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
1450 LPWSTR wServiceStartName, wPassword, wDisplayName;
1453 TRACE("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
1454 hService, dwServiceType, dwStartType, dwErrorControl,
1455 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
1456 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
1457 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
1459 wBinaryPathName = SERV_dup( lpBinaryPathName );
1460 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
1461 wDependencies = SERV_dupmulti( lpDependencies );
1462 wServiceStartName = SERV_dup( lpServiceStartName );
1463 wPassword = SERV_dup( lpPassword );
1464 wDisplayName = SERV_dup( lpDisplayName );
1466 r = ChangeServiceConfigW( hService, dwServiceType,
1467 dwStartType, dwErrorControl, wBinaryPathName,
1468 wLoadOrderGroup, lpdwTagId, wDependencies,
1469 wServiceStartName, wPassword, wDisplayName);
1471 SERV_free( wBinaryPathName );
1472 SERV_free( wLoadOrderGroup );
1473 SERV_free( wDependencies );
1474 SERV_free( wServiceStartName );
1475 SERV_free( wPassword );
1476 SERV_free( wDisplayName );
1481 /******************************************************************************
1482 * ChangeServiceConfig2A [ADVAPI32.@]
1484 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
1489 TRACE("%p %ld %p\n",hService, dwInfoLevel, lpInfo);
1491 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
1493 LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
1494 SERVICE_DESCRIPTIONW sdw;
1496 sdw.lpDescription = SERV_dup( sd->lpDescription );
1498 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
1500 SERV_free( sdw.lpDescription );
1502 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
1504 LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
1505 SERVICE_FAILURE_ACTIONSW faw;
1507 faw.dwResetPeriod = fa->dwResetPeriod;
1508 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
1509 faw.lpCommand = SERV_dup( fa->lpCommand );
1510 faw.cActions = fa->cActions;
1511 faw.lpsaActions = fa->lpsaActions;
1513 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
1515 SERV_free( faw.lpRebootMsg );
1516 SERV_free( faw.lpCommand );
1519 SetLastError( ERROR_INVALID_PARAMETER );
1524 /******************************************************************************
1525 * ChangeServiceConfig2W [ADVAPI32.@]
1527 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
1530 HKEY hKey = ((struct sc_handle*) hService)->u.service.hkey;
1532 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
1534 static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
1535 LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
1536 if (sd->lpDescription)
1538 TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
1539 if (sd->lpDescription[0] == 0)
1540 RegDeleteValueW(hKey,szDescription);
1542 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
1543 (LPVOID)sd->lpDescription,
1544 sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
1548 FIXME("STUB: %p %ld %p\n",hService, dwInfoLevel, lpInfo);
1552 /******************************************************************************
1553 * QueryServiceObjectSecurity [ADVAPI32.@]
1555 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
1556 SECURITY_INFORMATION dwSecurityInformation,
1557 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
1558 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1560 FIXME("%p %ld %p %lu %p\n", hService, dwSecurityInformation,
1561 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
1562 return ERROR_CALL_NOT_IMPLEMENTED;