Const correctness fixes.
[wine/multimedia.git] / dlls / advapi32 / service.c
blob0193b2463a0b83ff428242015bdf70204a6634e4
1 /*
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
21 #include <stdarg.h>
22 #include <string.h>
23 #include <time.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winsvc.h"
28 #include "winerror.h"
29 #include "winreg.h"
30 #include "wine/unicode.h"
31 #include "wine/debug.h"
32 #include "winternl.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',
40 'L','O','C','K',0};
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 */
46 DWORD argc;
47 /* variable part of SEB contains service arguments */
50 /******************************************************************************
51 * SC_HANDLEs
54 #define MAX_SERVICE_NAME 256
56 typedef enum { SC_HTYPE_MANAGER, SC_HTYPE_SERVICE } SC_HANDLE_TYPE;
58 struct sc_handle;
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 ];
74 struct sc_handle
76 SC_HANDLE_TYPE htype;
77 union
79 struct sc_manager manager;
80 struct sc_service service;
81 } u;
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) );
89 if( retval != NULL )
91 retval->htype = htype;
93 TRACE("SC_HANDLE type=%d -> %p\n",htype,retval);
94 return retval;
97 static void free_sc_handle( struct sc_handle* handle )
99 if( NULL == handle )
100 return;
102 switch( handle->htype )
104 case SC_HTYPE_MANAGER:
106 if( InterlockedDecrement( &handle->u.manager.ref_count ) )
107 /* there are references to this handle */
108 return;
110 if( handle->u.manager.hkey_scm_db )
111 RegCloseKey( handle->u.manager.hkey_scm_db );
112 break;
115 case SC_HTYPE_SERVICE:
117 struct sc_handle *h = handle->u.service.sc_manager;
119 if( h )
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 );
135 break;
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 )
159 UINT len;
160 LPWSTR wstr;
162 if( !str )
163 return NULL;
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 );
167 return wstr;
170 static inline LPWSTR SERV_dupmulti( LPCSTR str )
172 UINT len = 0, n = 0;
173 LPWSTR wstr;
175 if( !str )
176 return NULL;
177 do {
178 len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
179 n += (strlen( &str[n] ) + 1);
180 } while (str[n]);
181 len++;
182 n++;
184 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
185 MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
186 return wstr;
189 static inline VOID SERV_free( LPWSTR wstr )
191 HeapFree( GetProcessHeap(), 0, wstr );
194 /******************************************************************************
195 * EnumServicesStatusA [ADVAPI32.@]
197 BOOL WINAPI
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);
206 return FALSE;
209 /******************************************************************************
210 * EnumServicesStatusW [ADVAPI32.@]
212 BOOL WINAPI
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);
221 return FALSE;
224 /******************************************************************************
225 * read_scm_lock_data
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 )
234 HANDLE hLock;
235 LPWSTR argptr;
237 hLock = OpenFileMappingW( FILE_MAP_ALL_ACCESS, FALSE, szSCMLock );
238 if( NULL == hLock )
240 SetLastError( ERROR_FAILED_SERVICE_CONTROLLER_CONNECT );
241 return FALSE;
243 argptr = MapViewOfFile( hLock, FILE_MAP_ALL_ACCESS,
244 0, 0, MAX_SERVICE_NAME * sizeof(WCHAR) );
245 if( NULL == argptr )
247 CloseHandle( hLock );
248 return FALSE;
250 strcpyW( buffer, argptr );
251 UnmapViewOfFile( argptr );
252 CloseHandle( hLock );
253 return TRUE;
256 /******************************************************************************
257 * open_seb_shmem
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 ];
264 HANDLE hmem;
265 struct SEB *ret;
267 snprintfW( object_name, MAX_PATH, szServiceShmemNameFmtW, service_name );
268 hmem = OpenFileMappingW( FILE_MAP_ALL_ACCESS, FALSE, object_name );
269 if( NULL == hmem )
270 return NULL;
272 ret = MapViewOfFile( hmem, FILE_MAP_ALL_ACCESS, 0, 0, 0 );
273 if( NULL == ret )
274 CloseHandle( hmem );
275 else
276 *hServiceShmem = hmem;
277 return ret;
280 /******************************************************************************
281 * build_arg_vectors
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 )
291 LPWSTR *ret;
292 LPWSTR argptr;
293 DWORD i;
295 ret = HeapAlloc( GetProcessHeap(), 0, (1 + seb->argc) * sizeof(LPWSTR) );
296 if( NULL == ret )
297 return NULL;
299 argptr = (LPWSTR) &seb[1];
300 for( i = 0; i < seb->argc; i++ )
302 ret[ 1 + i ] = argptr;
303 argptr += 1 + strlenW( argptr );
305 return ret;
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;
320 unsigned int i;
321 BOOL ret = FALSE;
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 );
332 return TRUE;
335 seb = open_seb_shmem( service_name, &hServiceShmem );
336 if( NULL == seb )
337 return FALSE;
339 lpArgVecW = build_arg_vectors( seb );
340 if( NULL == lpArgVecW )
341 goto done;
343 lpArgVecW[0] = service_name;
344 dwNumServiceArgs = seb->argc + 1;
346 if( ascii )
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 );
353 if( NULL == dest )
354 goto done;
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);
363 ret = TRUE;
365 done:
366 if( lpArgVecW ) HeapFree( GetProcessHeap(), 0, lpArgVecW );
367 if( seb ) UnmapViewOfFile( seb );
368 if( hServiceShmem ) CloseHandle( hServiceShmem );
369 return ret;
372 /******************************************************************************
373 * StartServiceCtrlDispatcherA [ADVAPI32.@]
375 BOOL WINAPI
376 StartServiceCtrlDispatcherA( LPSERVICE_TABLE_ENTRYA servent )
378 int count, i;
379 LPSERVICE_TABLE_ENTRYW ServiceTableW;
380 BOOL ret;
382 TRACE("(%p)\n", servent);
384 /* convert service table to unicode */
385 for( count = 0; servent[ count ].lpServiceName; )
386 count++;
387 ServiceTableW = HeapAlloc( GetProcessHeap(), 0, (count + 1) * sizeof(SERVICE_TABLE_ENTRYW) );
388 if( NULL == ServiceTableW )
389 return FALSE;
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 );
406 return ret;
409 /******************************************************************************
410 * StartServiceCtrlDispatcherW [ADVAPI32.@]
412 * PARAMS
413 * servent []
415 BOOL WINAPI
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)
427 HANDLE ret;
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 )
435 CloseHandle( ret );
436 ret = NULL;
437 SetLastError( ERROR_SERVICE_DATABASE_LOCKED );
440 TRACE("returning %p\n", ret);
442 return 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);
462 return 0xcacacafe;
465 /******************************************************************************
466 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
468 * PARAMS
469 * lpServiceName []
470 * lpfHandler []
472 SERVICE_STATUS_HANDLE WINAPI
473 RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName,
474 LPHANDLER_FUNCTION lpfHandler )
475 { FIXME("%s %p\n", debugstr_w(lpServiceName), lpfHandler);
476 return 0xcacacafe;
479 /******************************************************************************
480 * SetServiceStatus [ADVAPI32.@]
482 * PARAMS
483 * hService []
484 * lpStatus []
486 BOOL WINAPI
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);
496 return TRUE;
499 /******************************************************************************
500 * OpenSCManagerA [ADVAPI32.@]
502 * Establish a connection to the service control manager and open its database.
504 * PARAMS
505 * lpMachineName [I] Pointer to machine name string
506 * lpDatabaseName [I] Pointer to database name string
507 * dwDesiredAccess [I] Type of access
509 * RETURNS
510 * Success: A Handle to the service control manager database
511 * Failure: NULL
513 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
514 DWORD dwDesiredAccess )
516 UNICODE_STRING lpMachineNameW;
517 UNICODE_STRING lpDatabaseNameW;
518 SC_HANDLE ret;
520 RtlCreateUnicodeStringFromAsciiz (&lpMachineNameW,lpMachineName);
521 RtlCreateUnicodeStringFromAsciiz (&lpDatabaseNameW,lpDatabaseName);
522 ret = OpenSCManagerW(lpMachineNameW.Buffer,lpDatabaseNameW.Buffer, dwDesiredAccess);
523 RtlFreeUnicodeString(&lpDatabaseNameW);
524 RtlFreeUnicodeString(&lpMachineNameW);
525 return ret;
528 /******************************************************************************
529 * OpenSCManagerW [ADVAPI32.@]
531 * See OpenSCManagerA.
533 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
534 DWORD dwDesiredAccess )
536 struct sc_handle *retval;
537 HKEY hReg;
538 LONG r;
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)
556 goto error;
558 r = RegOpenKeyExW(hReg, szServiceManagerKey,
559 0, KEY_ALL_ACCESS, &retval->u.manager.hkey_scm_db);
560 RegCloseKey( hReg );
561 if (r!=ERROR_SUCCESS)
562 goto error;
564 TRACE("returning %p\n", retval);
566 return (SC_HANDLE) retval;
568 error:
569 free_sc_handle( retval );
570 return NULL;
573 /******************************************************************************
574 * ControlService [ADVAPI32.@]
576 * Send a control code to a service.
578 * PARAMS
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
583 * RETURNS
584 * Success: TRUE.
585 * Failure: FALSE.
587 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
588 LPSERVICE_STATUS lpServiceStatus )
590 FIXME("(%p,%ld,%p): stub\n",hService,dwControl,lpServiceStatus);
591 return TRUE;
595 /******************************************************************************
596 * CloseServiceHandle [ADVAPI32.@]
598 * Close a handle to a service or the service control manager database.
600 * PARAMS
601 * hSCObject [I] Handle to service or service control manager database
603 * RETURNS
604 * Success: TRUE
605 * Failure: FALSE
607 BOOL WINAPI
608 CloseServiceHandle( SC_HANDLE hSCObject )
610 TRACE("(%p)\n", hSCObject);
612 free_sc_handle( (struct sc_handle*) hSCObject );
614 return TRUE;
618 /******************************************************************************
619 * OpenServiceA [ADVAPI32.@]
621 * Open a handle to a service.
623 * PARAMS
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
628 * RETURNS
629 * Success: Handle to the service
630 * Failure: NULL
632 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
633 DWORD dwDesiredAccess )
635 UNICODE_STRING lpServiceNameW;
636 SC_HANDLE ret;
637 RtlCreateUnicodeStringFromAsciiz (&lpServiceNameW,lpServiceName);
638 if(lpServiceName)
639 TRACE("Request for service %s\n",lpServiceName);
640 else
641 return FALSE;
642 ret = OpenServiceW( hSCManager, lpServiceNameW.Buffer, dwDesiredAccess);
643 RtlFreeUnicodeString(&lpServiceNameW);
644 return ret;
648 /******************************************************************************
649 * OpenServiceW [ADVAPI32.@]
651 * See OpenServiceA.
653 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
654 DWORD dwDesiredAccess)
656 struct sc_handle *hscm = hSCManager;
657 struct sc_handle *retval;
658 HKEY hKey;
659 long r;
661 TRACE("(%p,%p,%ld)\n",hSCManager, lpServiceName,
662 dwDesiredAccess);
664 retval = alloc_sc_handle( SC_HTYPE_SERVICE );
665 if( NULL == retval )
666 return NULL;
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 );
674 return NULL;
677 init_service_handle( retval, hscm, hKey, lpServiceName );
679 TRACE("returning %p\n",retval);
681 return (SC_HANDLE) retval;
684 /******************************************************************************
685 * CreateServiceW [ADVAPI32.@]
687 SC_HANDLE WINAPI
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,
694 LPCWSTR lpPassword )
696 struct sc_handle *hscm = hSCManager;
697 struct sc_handle *retval;
698 HKEY hKey;
699 LONG r;
700 DWORD dp;
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 );
713 if( NULL == retval )
714 return NULL;
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)
719 goto error;
721 init_service_handle( retval, hscm, hKey, lpServiceName );
723 if (dp != REG_CREATED_NEW_KEY)
724 goto error;
726 if(lpDisplayName)
728 r = RegSetValueExW(hKey, szDisplayName, 0, REG_SZ, (const BYTE*)lpDisplayName,
729 (strlenW(lpDisplayName)+1)*sizeof(WCHAR) );
730 if (r!=ERROR_SUCCESS)
731 goto error;
734 r = RegSetValueExW(hKey, szType, 0, REG_DWORD, (LPVOID)&dwServiceType, sizeof (DWORD) );
735 if (r!=ERROR_SUCCESS)
736 goto error;
738 r = RegSetValueExW(hKey, szStart, 0, REG_DWORD, (LPVOID)&dwStartType, sizeof (DWORD) );
739 if (r!=ERROR_SUCCESS)
740 goto error;
742 r = RegSetValueExW(hKey, szError, 0, REG_DWORD,
743 (LPVOID)&dwErrorControl, sizeof (DWORD) );
744 if (r!=ERROR_SUCCESS)
745 goto error;
747 if(lpBinaryPathName)
749 r = RegSetValueExW(hKey, szImagePath, 0, REG_SZ, (const BYTE*)lpBinaryPathName,
750 (strlenW(lpBinaryPathName)+1)*sizeof(WCHAR) );
751 if (r!=ERROR_SUCCESS)
752 goto error;
755 if(lpLoadOrderGroup)
757 r = RegSetValueExW(hKey, szGroup, 0, REG_SZ, (const BYTE*)lpLoadOrderGroup,
758 (strlenW(lpLoadOrderGroup)+1)*sizeof(WCHAR) );
759 if (r!=ERROR_SUCCESS)
760 goto error;
763 if(lpDependencies)
765 DWORD len = 0;
767 /* determine the length of a double null terminated multi string */
768 do {
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)
775 goto error;
778 if(lpPassword)
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;
790 error:
791 free_sc_handle( retval );
792 return NULL;
796 /******************************************************************************
797 * CreateServiceA [ADVAPI32.@]
799 SC_HANDLE WINAPI
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,
806 LPCSTR lpPassword )
808 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
809 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
810 SC_HANDLE r;
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 );
836 return r;
840 /******************************************************************************
841 * DeleteService [ADVAPI32.@]
843 * Delete a service from the service control manager database.
845 * PARAMS
846 * hService [I] Handle of the service to delete
848 * RETURNS
849 * Success: TRUE
850 * Failure: FALSE
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];
857 INT index = 0;
858 LONG rc;
859 DWORD size;
861 size = 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);
867 index++;
868 size = MAX_PATH+1;
869 rc = RegEnumValueW(hKey, index, valname, &size,0,0,0,0);
872 RegCloseKey(hKey);
873 hsvc->u.service.hkey = NULL;
875 /* delete the key */
876 RegDeleteKeyW(hsvc->u.service.sc_manager->u.manager.hkey_scm_db,
877 hsvc->u.service.name);
879 return TRUE;
883 /******************************************************************************
884 * StartServiceA [ADVAPI32.@]
886 * Start a service
888 * PARAMS
889 * hService [I] Handle of service
890 * dwNumServiceArgs [I] Number of arguments
891 * lpServiceArgVectors [I] Address of array of argument strings
893 * NOTES
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.
902 * RETURNS
903 * Success: TRUE.
904 * Failure: FALSE
906 BOOL WINAPI
907 StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
908 LPCSTR *lpServiceArgVectors )
910 LPWSTR *lpwstr=NULL;
911 UNICODE_STRING usBuffer;
912 unsigned int i;
914 TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
916 if(dwNumServiceArgs)
917 lpwstr = (LPWSTR*) HeapAlloc( GetProcessHeap(), 0,
918 dwNumServiceArgs*sizeof(LPWSTR) );
919 else
920 lpwstr = NULL;
922 for(i=0; i<dwNumServiceArgs; i++)
924 RtlCreateUnicodeStringFromAsciiz (&usBuffer,lpServiceArgVectors[i]);
925 lpwstr[i]=usBuffer.Buffer;
928 StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
930 if(dwNumServiceArgs)
932 for(i=0; i<dwNumServiceArgs; i++)
933 HeapFree(GetProcessHeap(), 0, lpwstr[i]);
934 HeapFree(GetProcessHeap(), 0, lpwstr);
937 return TRUE;
941 /******************************************************************************
942 * StartServiceW [ADVAPI32.@]
944 * See StartServiceA.
946 BOOL WINAPI
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];
957 DWORD type,size;
958 DWORD i;
959 long r;
960 HANDLE hLock;
961 HANDLE hServiceShmem = NULL;
962 HANDLE wait = NULL;
963 LPWSTR shmem_lock = NULL;
964 struct SEB *seb = NULL;
965 LPWSTR argptr;
966 PROCESS_INFORMATION procinfo;
967 STARTUPINFOW startupinfo;
968 BOOL ret = FALSE;
970 TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,
971 lpServiceArgVectors);
973 size = sizeof(str);
974 r = RegQueryValueExW(hsvc->u.service.hkey, _ImagePathW, NULL, &type, (LPVOID)str, &size);
975 if (r!=ERROR_SUCCESS)
976 return FALSE;
977 ExpandEnvironmentStringsW(str,path,sizeof(path));
979 TRACE("Starting service %s\n", debugstr_w(path) );
981 hLock = LockServiceDatabase( hsvc->u.service.sc_manager );
982 if( NULL == hLock )
983 return FALSE;
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");
995 goto done;
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");
1010 goto done;
1012 if( GetLastError() == ERROR_ALREADY_EXISTS )
1014 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
1015 goto done;
1017 seb = MapViewOfFile( hServiceShmem, FILE_MAP_ALL_ACCESS, 0, 0, 0 );
1018 if( NULL == seb )
1020 ERR("Couldn't map shared memory\n");
1021 goto done;
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);
1034 if (!wait)
1036 ERR("Couldn't create wait semaphore\n");
1037 goto done;
1040 ZeroMemory(&startupinfo,sizeof(STARTUPINFOW));
1041 startupinfo.cb = sizeof(STARTUPINFOW);
1043 r = CreateProcessW(NULL,
1044 path,
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 */
1054 if(r == FALSE)
1056 ERR("Couldn't start process\n");
1057 goto done;
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 );
1066 goto done;
1069 /* allright */
1070 CloseHandle( procinfo.hProcess );
1071 ret = TRUE;
1073 done:
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 );
1079 return ret;
1082 /******************************************************************************
1083 * QueryServiceStatus [ADVAPI32.@]
1085 * PARAMS
1086 * hService []
1087 * lpservicestatus []
1090 BOOL WINAPI
1091 QueryServiceStatus( SC_HANDLE hService, LPSERVICE_STATUS lpservicestatus )
1093 struct sc_handle *hsvc = hService;
1094 LONG r;
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 */
1102 size = sizeof(val);
1103 r = RegQueryValueExA(hsvc->u.service.hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1104 if(type!=REG_DWORD)
1106 ERR("invalid Type\n");
1107 return FALSE;
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;
1120 } else {
1121 if( GetLastError() == ERROR_ALREADY_EXISTS )
1123 lpservicestatus->dwCurrentState = 3;
1124 } else {
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;
1136 return TRUE;
1139 /******************************************************************************
1140 * QueryServiceStatusEx [ADVAPI32.@]
1142 * Get information about a service.
1144 * PARAMS
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
1151 * RETURNS
1152 * Success: TRUE
1153 * FAILURE: FALSE
1155 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1156 LPBYTE lpBuffer, DWORD cbBufSize,
1157 LPDWORD pcbBytesNeeded)
1159 FIXME("stub\n");
1160 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1161 return FALSE;
1164 /******************************************************************************
1165 * QueryServiceConfigA [ADVAPI32.@]
1167 BOOL WINAPI
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 ];
1181 LONG r;
1182 DWORD type, val, sz, total, n;
1183 LPBYTE p;
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;
1198 total += sz;
1200 else
1202 /* FIXME: set last error */
1203 return FALSE;
1206 sz = 0;
1207 r = RegQueryValueExA( hKey, szGroup, 0, &type, NULL, &sz );
1208 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1209 total += sz;
1211 sz = 0;
1212 r = RegQueryValueExA( hKey, szDependencies, 0, &type, NULL, &sz );
1213 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1214 total += sz;
1216 sz = 0;
1217 r = RegQueryValueExA( hKey, szStart, 0, &type, NULL, &sz );
1218 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1219 total += sz;
1221 sz = 0;
1222 r = RegQueryValueExA( hKey, szDisplayName, 0, &type, NULL, &sz );
1223 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1224 total += sz;
1226 /* if there's not enough memory, return an error */
1227 if( total > *pcbBytesNeeded )
1229 *pcbBytesNeeded = total;
1230 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1231 return FALSE;
1234 *pcbBytesNeeded = total;
1235 ZeroMemory( lpServiceConfig, total );
1237 sz = sizeof val;
1238 r = RegQueryValueExA( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1239 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1240 lpServiceConfig->dwServiceType = val;
1242 sz = sizeof val;
1243 r = RegQueryValueExA( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1244 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1245 lpServiceConfig->dwStartType = val;
1247 sz = sizeof 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;
1264 p += sz;
1265 n -= sz;
1267 else
1269 /* FIXME: set last error */
1270 return FALSE;
1273 sz = n;
1274 r = RegQueryValueExA( hKey, szGroup, 0, &type, p, &sz );
1275 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1277 lpServiceConfig->lpLoadOrderGroup = (LPSTR) p;
1278 p += sz;
1279 n -= sz;
1282 sz = n;
1283 r = RegQueryValueExA( hKey, szDependencies, 0, &type, p, &sz );
1284 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1286 lpServiceConfig->lpDependencies = (LPSTR) p;
1287 p += sz;
1288 n -= sz;
1291 if( n < 0 )
1292 ERR("Buffer overflow!\n");
1294 TRACE("Image path = %s\n", lpServiceConfig->lpBinaryPathName );
1295 TRACE("Group = %s\n", lpServiceConfig->lpLoadOrderGroup );
1297 return TRUE;
1300 /******************************************************************************
1301 * QueryServiceConfigW [ADVAPI32.@]
1303 BOOL WINAPI
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 ];
1320 LONG r;
1321 DWORD type, val, sz, total, n;
1322 LPBYTE p;
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;
1339 else
1341 /* FIXME: set last error */
1342 return FALSE;
1345 sz = 0;
1346 r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1347 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1348 total += sz;
1350 sz = 0;
1351 r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1352 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1353 total += sz;
1355 sz = 0;
1356 r = RegQueryValueExW( hKey, szStart, 0, &type, NULL, &sz );
1357 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1358 total += sz;
1360 sz = 0;
1361 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1362 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1363 total += sz;
1365 /* if there's not enough memory, return an error */
1366 if( total > *pcbBytesNeeded )
1368 *pcbBytesNeeded = total;
1369 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1370 return FALSE;
1373 *pcbBytesNeeded = total;
1374 ZeroMemory( lpServiceConfig, total );
1376 sz = sizeof val;
1377 r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1378 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1379 lpServiceConfig->dwServiceType = val;
1381 sz = sizeof val;
1382 r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1383 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1384 lpServiceConfig->dwStartType = val;
1386 sz = sizeof 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;
1404 p += sz;
1405 n -= sz;
1407 else
1409 /* FIXME: set last error */
1410 return FALSE;
1413 sz = n;
1414 r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
1415 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1417 lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
1418 p += sz;
1419 n -= sz;
1422 sz = n;
1423 r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
1424 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1426 lpServiceConfig->lpDependencies = (LPWSTR) p;
1427 p += sz;
1428 n -= sz;
1431 if( n < 0 )
1432 ERR("Buffer overflow!\n");
1434 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1435 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1437 return TRUE;
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) );
1453 return TRUE;
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;
1466 BOOL r;
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 );
1493 return r;
1496 /******************************************************************************
1497 * ChangeServiceConfig2A [ADVAPI32.@]
1499 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
1500 LPVOID lpInfo)
1502 BOOL r = FALSE;
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 );
1533 else
1534 SetLastError( ERROR_INVALID_PARAMETER );
1536 return r;
1539 /******************************************************************************
1540 * ChangeServiceConfig2W [ADVAPI32.@]
1542 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
1543 LPVOID lpInfo)
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);
1556 else
1557 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
1558 (LPVOID)sd->lpDescription,
1559 sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
1562 else
1563 FIXME("STUB: %p %ld %p\n",hService, dwInfoLevel, lpInfo);
1564 return TRUE;
1567 /******************************************************************************
1568 * QueryServiceObjectSecurity [ADVAPI32.@]
1570 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
1571 SECURITY_INFORMATION dwSecurityInformation,
1572 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
1573 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1575 PACL pACL = NULL;
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);
1585 return 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);
1596 return TRUE;