Append .dll extension in all cases (spotted by Mike Hearn).
[wine/wine-kai.git] / dlls / advapi32 / service.c
blobb338634f0b5a41f628c40a86d14c6eaeeb8630a8
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 "heap.h"
32 #include "wine/debug.h"
33 #include "winternl.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',
41 'L','O','C','K',0};
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 */
47 DWORD argc;
48 /* variable part of SEB contains service arguments */
51 /******************************************************************************
52 * SC_HANDLEs
55 #define MAX_SERVICE_NAME 256
57 typedef enum { SC_HTYPE_MANAGER, SC_HTYPE_SERVICE } SC_HANDLE_TYPE;
59 struct sc_handle;
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 ];
75 struct sc_handle
77 SC_HANDLE_TYPE htype;
78 union
80 struct sc_manager manager;
81 struct sc_service service;
82 } u;
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) );
90 if( retval != NULL )
92 retval->htype = htype;
94 TRACE("SC_HANDLE type=%d -> %p\n",htype,retval);
95 return retval;
98 static void free_sc_handle( struct sc_handle* handle )
100 if( NULL == handle )
101 return;
103 switch( handle->htype )
105 case SC_HTYPE_MANAGER:
107 if( InterlockedDecrement( &handle->u.manager.ref_count ) )
108 /* there are references to this handle */
109 return;
111 if( handle->u.manager.hkey_scm_db )
112 RegCloseKey( handle->u.manager.hkey_scm_db );
113 break;
116 case SC_HTYPE_SERVICE:
118 struct sc_handle *h = handle->u.service.sc_manager;
120 if( h )
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 );
136 break;
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 static inline LPWSTR SERV_dup( LPCSTR str )
160 UINT len;
161 LPWSTR wstr;
163 if( !str )
164 return NULL;
165 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
166 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
167 MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
168 return wstr;
171 static inline LPWSTR SERV_dupmulti( LPCSTR str )
173 UINT len = 0, n = 0;
174 LPWSTR wstr;
176 if( !str )
177 return NULL;
178 do {
179 len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
180 n += (strlen( &str[n] ) + 1);
181 } while (str[n]);
182 len++;
183 n++;
185 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
186 MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
187 return wstr;
190 static inline VOID SERV_free( LPWSTR wstr )
192 HeapFree( GetProcessHeap(), 0, wstr );
195 /******************************************************************************
196 * EnumServicesStatusA [ADVAPI32.@]
198 BOOL WINAPI
199 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
200 DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
201 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
202 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
203 { FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
204 dwServiceType, dwServiceState, lpServices, cbBufSize,
205 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
206 SetLastError (ERROR_ACCESS_DENIED);
207 return FALSE;
210 /******************************************************************************
211 * EnumServicesStatusW [ADVAPI32.@]
213 BOOL WINAPI
214 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
215 DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
216 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
217 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
218 { FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
219 dwServiceType, dwServiceState, lpServices, cbBufSize,
220 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
221 SetLastError (ERROR_ACCESS_DENIED);
222 return FALSE;
225 /******************************************************************************
226 * read_scm_lock_data
228 * helper function for StartServiceCtrlDispatcherA/W
230 * SCM database is locked by StartService;
231 * open global SCM lock object and read service name
233 static BOOL read_scm_lock_data( LPWSTR buffer )
235 HANDLE hLock;
236 LPWSTR argptr;
238 hLock = OpenFileMappingW( FILE_MAP_ALL_ACCESS, FALSE, szSCMLock );
239 if( NULL == hLock )
241 SetLastError( ERROR_FAILED_SERVICE_CONTROLLER_CONNECT );
242 return FALSE;
244 argptr = MapViewOfFile( hLock, FILE_MAP_ALL_ACCESS,
245 0, 0, MAX_SERVICE_NAME * sizeof(WCHAR) );
246 if( NULL == argptr )
248 CloseHandle( hLock );
249 return FALSE;
251 strcpyW( buffer, argptr );
252 UnmapViewOfFile( argptr );
253 CloseHandle( hLock );
254 return TRUE;
257 /******************************************************************************
258 * open_seb_shmem
260 * helper function for StartServiceCtrlDispatcherA/W
262 static struct SEB* open_seb_shmem( LPWSTR service_name, HANDLE* hServiceShmem )
264 WCHAR object_name[ MAX_PATH ];
265 HANDLE hmem;
266 struct SEB *ret;
268 snprintfW( object_name, MAX_PATH, szServiceShmemNameFmtW, service_name );
269 hmem = OpenFileMappingW( FILE_MAP_ALL_ACCESS, FALSE, object_name );
270 if( NULL == hmem )
271 return NULL;
273 ret = MapViewOfFile( hmem, FILE_MAP_ALL_ACCESS, 0, 0, 0 );
274 if( NULL == ret )
275 CloseHandle( hmem );
276 else
277 *hServiceShmem = hmem;
278 return ret;
281 /******************************************************************************
282 * build_arg_vectors
284 * helper function for StartServiceCtrlDispatcherA/W
286 * Allocate and initialize array of LPWSTRs to arguments in variable part
287 * of service environment block.
288 * First entry in the array is reserved for service name and not initialized.
290 static LPWSTR* build_arg_vectors( struct SEB* seb )
292 LPWSTR *ret;
293 LPWSTR argptr;
294 DWORD i;
296 ret = HeapAlloc( GetProcessHeap(), 0, (1 + seb->argc) * sizeof(LPWSTR) );
297 if( NULL == ret )
298 return NULL;
300 argptr = (LPWSTR) &seb[1];
301 for( i = 0; i < seb->argc; i++ )
303 ret[ 1 + i ] = argptr;
304 argptr += 1 + strlenW( argptr );
306 return ret;
309 /******************************************************************************
310 * StartServiceCtrlDispatcherA [ADVAPI32.@]
312 BOOL WINAPI
313 StartServiceCtrlDispatcherA( LPSERVICE_TABLE_ENTRYA servent )
315 LPSERVICE_MAIN_FUNCTIONA fpMain;
316 WCHAR service_name[ MAX_SERVICE_NAME ];
317 HANDLE hServiceShmem = NULL;
318 struct SEB *seb = NULL;
319 DWORD dwNumServiceArgs = 0;
320 LPWSTR *lpArgVecW = NULL;
321 LPSTR *lpArgVecA = NULL;
322 unsigned int i;
323 BOOL ret = FALSE;
325 TRACE("(%p)\n", servent);
327 if( ! read_scm_lock_data( service_name ) )
329 /* FIXME: Instead of exiting we allow
330 service to be executed as ordinary program.
331 This behaviour was specially introduced in the patch
332 submitted against revision 1.45 and so preserved here.
334 FIXME("should fail with ERROR_FAILED_SERVICE_CONTROLLER_CONNECT\n");
335 servent->lpServiceProc( 0, NULL );
336 return TRUE;
339 seb = open_seb_shmem( service_name, &hServiceShmem );
340 if( NULL == seb )
341 return FALSE;
343 lpArgVecW = build_arg_vectors( seb );
344 if( NULL == lpArgVecW )
345 goto done;
347 lpArgVecW[0] = service_name;
348 dwNumServiceArgs = seb->argc + 1;
350 /* Convert the Unicode arg vectors back to ASCII */
351 lpArgVecA = (LPSTR*) HeapAlloc( GetProcessHeap(), 0,
352 dwNumServiceArgs*sizeof(LPSTR) );
353 for(i=0; i<dwNumServiceArgs; i++)
354 lpArgVecA[i]=HEAP_strdupWtoA(GetProcessHeap(), 0, lpArgVecW[i]);
356 /* FIXME: find service entry by name if SERVICE_WIN32_SHARE_PROCESS */
357 TRACE("%s at %p)\n", debugstr_a(servent->lpServiceName),servent);
358 fpMain = servent->lpServiceProc;
360 /* try to start the service */
361 fpMain( dwNumServiceArgs, lpArgVecA);
363 done:
364 if(dwNumServiceArgs)
366 /* free arg strings */
367 for(i=0; i<dwNumServiceArgs; i++)
368 HeapFree(GetProcessHeap(), 0, lpArgVecA[i]);
369 HeapFree(GetProcessHeap(), 0, lpArgVecA);
372 if( lpArgVecW ) HeapFree( GetProcessHeap(), 0, lpArgVecW );
373 if( seb ) UnmapViewOfFile( seb );
374 if( hServiceShmem ) CloseHandle( hServiceShmem );
375 return ret;
378 /******************************************************************************
379 * StartServiceCtrlDispatcherW [ADVAPI32.@]
381 * PARAMS
382 * servent []
384 BOOL WINAPI
385 StartServiceCtrlDispatcherW( LPSERVICE_TABLE_ENTRYW servent )
387 LPSERVICE_MAIN_FUNCTIONW fpMain;
388 WCHAR service_name[ MAX_SERVICE_NAME ];
389 HANDLE hServiceShmem = NULL;
390 struct SEB *seb;
391 DWORD dwNumServiceArgs ;
392 LPWSTR *lpServiceArgVectors ;
394 TRACE("(%p)\n", servent);
396 if( ! read_scm_lock_data( service_name ) )
397 return FALSE;
399 seb = open_seb_shmem( service_name, &hServiceShmem );
400 if( NULL == seb )
401 return FALSE;
403 lpServiceArgVectors = build_arg_vectors( seb );
404 if( NULL == lpServiceArgVectors )
406 UnmapViewOfFile( seb );
407 CloseHandle( hServiceShmem );
408 return FALSE;
410 lpServiceArgVectors[0] = service_name;
411 dwNumServiceArgs = seb->argc + 1;
413 /* FIXME: find service entry by name if SERVICE_WIN32_SHARE_PROCESS */
414 TRACE("%s at %p)\n", debugstr_w(servent->lpServiceName),servent);
415 fpMain = servent->lpServiceProc;
417 /* try to start the service */
418 fpMain( dwNumServiceArgs, lpServiceArgVectors);
420 HeapFree( GetProcessHeap(), 0, lpServiceArgVectors );
421 UnmapViewOfFile( seb );
422 CloseHandle( hServiceShmem );
423 return TRUE;
426 /******************************************************************************
427 * LockServiceDatabase [ADVAPI32.@]
429 LPVOID WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
431 HANDLE ret;
433 TRACE("%p\n",hSCManager);
435 ret = CreateFileMappingW( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
436 0, MAX_SERVICE_NAME * sizeof(WCHAR), szSCMLock );
437 if( ret && GetLastError() == ERROR_ALREADY_EXISTS )
439 CloseHandle( ret );
440 ret = NULL;
441 SetLastError( ERROR_SERVICE_DATABASE_LOCKED );
444 TRACE("returning %p\n", ret);
446 return ret;
449 /******************************************************************************
450 * UnlockServiceDatabase [ADVAPI32.@]
452 BOOL WINAPI UnlockServiceDatabase (LPVOID ScLock)
454 TRACE("%p\n",ScLock);
456 return CloseHandle( (HANDLE) ScLock );
459 /******************************************************************************
460 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
462 SERVICE_STATUS_HANDLE WINAPI
463 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName,
464 LPHANDLER_FUNCTION lpfHandler )
465 { FIXME("%s %p\n", lpServiceName, lpfHandler);
466 return 0xcacacafe;
469 /******************************************************************************
470 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
472 * PARAMS
473 * lpServiceName []
474 * lpfHandler []
476 SERVICE_STATUS_HANDLE WINAPI
477 RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName,
478 LPHANDLER_FUNCTION lpfHandler )
479 { FIXME("%s %p\n", debugstr_w(lpServiceName), lpfHandler);
480 return 0xcacacafe;
483 /******************************************************************************
484 * SetServiceStatus [ADVAPI32.@]
486 * PARAMS
487 * hService []
488 * lpStatus []
490 BOOL WINAPI
491 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
492 { FIXME("0x%lx %p\n",hService, lpStatus);
493 TRACE("\tType:%lx\n",lpStatus->dwServiceType);
494 TRACE("\tState:%lx\n",lpStatus->dwCurrentState);
495 TRACE("\tControlAccepted:%lx\n",lpStatus->dwControlsAccepted);
496 TRACE("\tExitCode:%lx\n",lpStatus->dwWin32ExitCode);
497 TRACE("\tServiceExitCode:%lx\n",lpStatus->dwServiceSpecificExitCode);
498 TRACE("\tCheckPoint:%lx\n",lpStatus->dwCheckPoint);
499 TRACE("\tWaitHint:%lx\n",lpStatus->dwWaitHint);
500 return TRUE;
503 /******************************************************************************
504 * OpenSCManagerA [ADVAPI32.@]
506 * Establish a connection to the service control manager and open its database.
508 * PARAMS
509 * lpMachineName [I] Pointer to machine name string
510 * lpDatabaseName [I] Pointer to database name string
511 * dwDesiredAccess [I] Type of access
513 * RETURNS
514 * Success: A Handle to the service control manager database
515 * Failure: NULL
517 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
518 DWORD dwDesiredAccess )
520 UNICODE_STRING lpMachineNameW;
521 UNICODE_STRING lpDatabaseNameW;
522 SC_HANDLE ret;
524 RtlCreateUnicodeStringFromAsciiz (&lpMachineNameW,lpMachineName);
525 RtlCreateUnicodeStringFromAsciiz (&lpDatabaseNameW,lpDatabaseName);
526 ret = OpenSCManagerW(lpMachineNameW.Buffer,lpDatabaseNameW.Buffer, dwDesiredAccess);
527 RtlFreeUnicodeString(&lpDatabaseNameW);
528 RtlFreeUnicodeString(&lpMachineNameW);
529 return ret;
532 /******************************************************************************
533 * OpenSCManagerW [ADVAPI32.@]
535 * See OpenSCManagerA.
537 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
538 DWORD dwDesiredAccess )
540 struct sc_handle *retval;
541 HKEY hReg;
542 LONG r;
544 TRACE("(%s,%s,0x%08lx)\n", debugstr_w(lpMachineName),
545 debugstr_w(lpDatabaseName), dwDesiredAccess);
548 * FIXME: what is lpDatabaseName?
549 * It should be set to "SERVICES_ACTIVE_DATABASE" according to
550 * docs, but what if it isn't?
553 retval = alloc_sc_handle( SC_HTYPE_MANAGER );
554 if( NULL == retval ) return NULL;
556 retval->u.manager.ref_count = 1;
558 r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
559 if (r!=ERROR_SUCCESS)
560 goto error;
562 r = RegOpenKeyExW(hReg, szServiceManagerKey,
563 0, KEY_ALL_ACCESS, &retval->u.manager.hkey_scm_db);
564 RegCloseKey( hReg );
565 if (r!=ERROR_SUCCESS)
566 goto error;
568 TRACE("returning %p\n", retval);
570 return (SC_HANDLE) retval;
572 error:
573 free_sc_handle( retval );
574 return NULL;
577 /******************************************************************************
578 * ControlService [ADVAPI32.@]
580 * Send a control code to a service.
582 * PARAMS
583 * hService [I] Handle of the service control manager database
584 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
585 * lpServiceStatus [O] Destination for the status of the service, if available
587 * RETURNS
588 * Success: TRUE.
589 * Failure: FALSE.
591 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
592 LPSERVICE_STATUS lpServiceStatus )
594 FIXME("(%p,%ld,%p): stub\n",hService,dwControl,lpServiceStatus);
595 return TRUE;
599 /******************************************************************************
600 * CloseServiceHandle [ADVAPI32.@]
602 * Close a handle to a service or the service control manager database.
604 * PARAMS
605 * hSCObject [I] Handle to service or service control manager database
607 * RETURNS
608 * Success: TRUE
609 * Failure: FALSE
611 BOOL WINAPI
612 CloseServiceHandle( SC_HANDLE hSCObject )
614 TRACE("(%p)\n", hSCObject);
616 free_sc_handle( (struct sc_handle*) hSCObject );
618 return TRUE;
622 /******************************************************************************
623 * OpenServiceA [ADVAPI32.@]
625 * Open a handle to a service.
627 * PARAMS
628 * hSCManager [I] Handle of the service control manager database
629 * lpServiceName [I] Name of the service to open
630 * dwDesiredAccess [I] Access required to the service
632 * RETURNS
633 * Success: Handle to the service
634 * Failure: NULL
636 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
637 DWORD dwDesiredAccess )
639 UNICODE_STRING lpServiceNameW;
640 SC_HANDLE ret;
641 RtlCreateUnicodeStringFromAsciiz (&lpServiceNameW,lpServiceName);
642 if(lpServiceName)
643 TRACE("Request for service %s\n",lpServiceName);
644 else
645 return FALSE;
646 ret = OpenServiceW( hSCManager, lpServiceNameW.Buffer, dwDesiredAccess);
647 RtlFreeUnicodeString(&lpServiceNameW);
648 return ret;
652 /******************************************************************************
653 * OpenServiceW [ADVAPI32.@]
655 * See OpenServiceA.
657 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
658 DWORD dwDesiredAccess)
660 struct sc_handle *hscm = hSCManager;
661 struct sc_handle *retval;
662 HKEY hKey;
663 long r;
665 TRACE("(%p,%p,%ld)\n",hSCManager, lpServiceName,
666 dwDesiredAccess);
668 retval = alloc_sc_handle( SC_HTYPE_SERVICE );
669 if( NULL == retval )
670 return NULL;
672 r = RegOpenKeyExW( hscm->u.manager.hkey_scm_db,
673 lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
674 if (r!=ERROR_SUCCESS)
676 free_sc_handle( retval );
677 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
678 return NULL;
681 init_service_handle( retval, hscm, hKey, lpServiceName );
683 TRACE("returning %p\n",retval);
685 return (SC_HANDLE) retval;
688 /******************************************************************************
689 * CreateServiceW [ADVAPI32.@]
691 SC_HANDLE WINAPI
692 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
693 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
694 DWORD dwServiceType, DWORD dwStartType,
695 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
696 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
697 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
698 LPCWSTR lpPassword )
700 struct sc_handle *hscm = hSCManager;
701 struct sc_handle *retval;
702 HKEY hKey;
703 LONG r;
704 DWORD dp;
705 static const WCHAR szDisplayName[] = { 'D','i','s','p','l','a','y','N','a','m','e', 0 };
706 static const WCHAR szType[] = {'T','y','p','e',0};
707 static const WCHAR szStart[] = {'S','t','a','r','t',0};
708 static const WCHAR szError[] = {'E','r','r','o','r','C','o','n','t','r','o','l', 0};
709 static const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
710 static const WCHAR szGroup[] = {'G','r','o','u','p',0};
711 static const WCHAR szDependencies[] = { 'D','e','p','e','n','d','e','n','c','i','e','s',0};
713 FIXME("%p %s %s\n", hSCManager,
714 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
716 retval = alloc_sc_handle( SC_HTYPE_SERVICE );
717 if( NULL == retval )
718 return NULL;
720 r = RegCreateKeyExW(hscm->u.manager.hkey_scm_db, lpServiceName, 0, NULL,
721 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
722 if (r!=ERROR_SUCCESS)
723 goto error;
725 init_service_handle( retval, hscm, hKey, lpServiceName );
727 if (dp != REG_CREATED_NEW_KEY)
728 goto error;
730 if(lpDisplayName)
732 r = RegSetValueExW(hKey, szDisplayName, 0, REG_SZ, (LPBYTE)lpDisplayName,
733 (strlenW(lpDisplayName)+1)*sizeof(WCHAR) );
734 if (r!=ERROR_SUCCESS)
735 goto error;
738 r = RegSetValueExW(hKey, szType, 0, REG_DWORD, (LPVOID)&dwServiceType, sizeof (DWORD) );
739 if (r!=ERROR_SUCCESS)
740 goto error;
742 r = RegSetValueExW(hKey, szStart, 0, REG_DWORD, (LPVOID)&dwStartType, sizeof (DWORD) );
743 if (r!=ERROR_SUCCESS)
744 goto error;
746 r = RegSetValueExW(hKey, szError, 0, REG_DWORD,
747 (LPVOID)&dwErrorControl, sizeof (DWORD) );
748 if (r!=ERROR_SUCCESS)
749 goto error;
751 if(lpBinaryPathName)
753 r = RegSetValueExW(hKey, szImagePath, 0, REG_SZ, (LPBYTE)lpBinaryPathName,
754 (strlenW(lpBinaryPathName)+1)*sizeof(WCHAR) );
755 if (r!=ERROR_SUCCESS)
756 goto error;
759 if(lpLoadOrderGroup)
761 r = RegSetValueExW(hKey, szGroup, 0, REG_SZ, (LPBYTE)lpLoadOrderGroup,
762 (strlenW(lpLoadOrderGroup)+1)*sizeof(WCHAR) );
763 if (r!=ERROR_SUCCESS)
764 goto error;
767 if(lpDependencies)
769 DWORD len = 0;
771 /* determine the length of a double null terminated multi string */
772 do {
773 len += (strlenW(&lpDependencies[len])+1);
774 } while (lpDependencies[len++]);
776 r = RegSetValueExW(hKey, szDependencies, 0, REG_MULTI_SZ,
777 (LPBYTE)lpDependencies, len );
778 if (r!=ERROR_SUCCESS)
779 goto error;
782 if(lpPassword)
784 FIXME("Don't know how to add a Password for a service.\n");
787 if(lpServiceStartName)
789 FIXME("Don't know how to add a ServiceStartName for a service.\n");
792 return (SC_HANDLE) retval;
794 error:
795 free_sc_handle( retval );
796 return NULL;
800 /******************************************************************************
801 * CreateServiceA [ADVAPI32.@]
803 SC_HANDLE WINAPI
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,
810 LPCSTR lpPassword )
812 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
813 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
814 SC_HANDLE r;
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 );
840 return r;
844 /******************************************************************************
845 * DeleteService [ADVAPI32.@]
847 * Delete a service from the service control manager database.
849 * PARAMS
850 * hService [I] Handle of the service to delete
852 * RETURNS
853 * Success: TRUE
854 * Failure: FALSE
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];
861 INT index = 0;
862 LONG rc;
863 DWORD size;
865 size = 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);
871 index++;
872 size = MAX_PATH+1;
873 rc = RegEnumValueW(hKey, index, valname, &size,0,0,0,0);
876 RegCloseKey(hKey);
877 hsvc->u.service.hkey = NULL;
879 /* delete the key */
880 RegDeleteKeyW(hsvc->u.service.sc_manager->u.manager.hkey_scm_db,
881 hsvc->u.service.name);
883 return TRUE;
887 /******************************************************************************
888 * StartServiceA [ADVAPI32.@]
890 * Start a service
892 * PARAMS
893 * hService [I] Handle of service
894 * dwNumServiceArgs [I] Number of arguments
895 * lpServiceArgVectors [I] Address of array of argument strings
897 * NOTES
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.
906 * RETURNS
907 * Success: TRUE.
908 * Failure: FALSE
910 BOOL WINAPI
911 StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
912 LPCSTR *lpServiceArgVectors )
914 LPWSTR *lpwstr=NULL;
915 UNICODE_STRING usBuffer;
916 unsigned int i;
918 TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
920 if(dwNumServiceArgs)
921 lpwstr = (LPWSTR*) HeapAlloc( GetProcessHeap(), 0,
922 dwNumServiceArgs*sizeof(LPWSTR) );
923 else
924 lpwstr = NULL;
926 for(i=0; i<dwNumServiceArgs; i++)
928 RtlCreateUnicodeStringFromAsciiz (&usBuffer,lpServiceArgVectors[i]);
929 lpwstr[i]=usBuffer.Buffer;
932 StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
934 if(dwNumServiceArgs)
936 for(i=0; i<dwNumServiceArgs; i++)
937 HeapFree(GetProcessHeap(), 0, lpwstr[i]);
938 HeapFree(GetProcessHeap(), 0, lpwstr);
941 return TRUE;
945 /******************************************************************************
946 * StartServiceW [ADVAPI32.@]
948 * See StartServiceA.
950 BOOL WINAPI
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];
961 DWORD type,size;
962 DWORD i;
963 long r;
964 HANDLE hLock;
965 HANDLE hServiceShmem = NULL;
966 HANDLE wait = NULL;
967 LPWSTR shmem_lock = NULL;
968 struct SEB *seb = NULL;
969 LPWSTR argptr;
970 PROCESS_INFORMATION procinfo;
971 STARTUPINFOW startupinfo;
972 BOOL ret = FALSE;
974 TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,
975 lpServiceArgVectors);
977 size = sizeof(str);
978 r = RegQueryValueExW(hsvc->u.service.hkey, _ImagePathW, NULL, &type, (LPVOID)str, &size);
979 if (r!=ERROR_SUCCESS)
980 return FALSE;
981 ExpandEnvironmentStringsW(str,path,sizeof(path));
983 TRACE("Starting service %s\n", debugstr_w(path) );
985 hLock = LockServiceDatabase( hsvc->u.service.sc_manager );
986 if( NULL == hLock )
987 return FALSE;
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");
999 goto done;
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");
1014 goto done;
1016 if( GetLastError() == ERROR_ALREADY_EXISTS )
1018 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
1019 goto done;
1021 seb = MapViewOfFile( hServiceShmem, FILE_MAP_ALL_ACCESS, 0, 0, 0 );
1022 if( NULL == seb )
1024 ERR("Couldn't map shared memory\n");
1025 goto done;
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);
1038 if (!wait)
1040 ERR("Couldn't create wait semaphore\n");
1041 goto done;
1044 ZeroMemory(&startupinfo,sizeof(STARTUPINFOW));
1045 startupinfo.cb = sizeof(STARTUPINFOW);
1047 r = CreateProcessW(NULL,
1048 path,
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 */
1058 if(r == FALSE)
1060 ERR("Couldn't start process\n");
1061 goto done;
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 );
1070 goto done;
1073 /* allright */
1074 CloseHandle( procinfo.hProcess );
1075 ret = TRUE;
1077 done:
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 );
1083 return ret;
1086 /******************************************************************************
1087 * QueryServiceStatus [ADVAPI32.@]
1089 * PARAMS
1090 * hService []
1091 * lpservicestatus []
1094 BOOL WINAPI
1095 QueryServiceStatus( SC_HANDLE hService, LPSERVICE_STATUS lpservicestatus )
1097 struct sc_handle *hsvc = hService;
1098 LONG r;
1099 DWORD type, val, size;
1100 WCHAR str[MAX_PATH];
1101 HANDLE hServiceShmem = NULL;
1103 FIXME("(%p,%p) partial\n",hService,lpservicestatus);
1105 /* read the service type from the registry */
1106 size = sizeof(val);
1107 r = RegQueryValueExA(hsvc->u.service.hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1108 if(type!=REG_DWORD)
1110 ERR("invalid Type\n");
1111 return FALSE;
1113 lpservicestatus->dwServiceType = val;
1114 /* FIXME: how are these determined or read from the registry? */
1115 /* SERVICE: unavailable=0, stopped=1, starting=2, running=3? */
1117 /* Determine if currently running via named shared memory */
1118 snprintfW( str, MAX_PATH, szServiceShmemNameFmtW, hsvc->u.service.name );
1119 hServiceShmem = CreateFileMappingW( INVALID_HANDLE_VALUE,
1120 NULL, PAGE_READWRITE, 0, size, str );
1121 if( NULL == hServiceShmem )
1123 lpservicestatus->dwCurrentState = 1;
1124 } else {
1125 if( GetLastError() == ERROR_ALREADY_EXISTS )
1127 lpservicestatus->dwCurrentState = 3;
1128 } else {
1129 lpservicestatus->dwCurrentState = 1;
1131 CloseHandle( hServiceShmem );
1134 lpservicestatus->dwControlsAccepted = 0;
1135 lpservicestatus->dwWin32ExitCode = NO_ERROR;
1136 lpservicestatus->dwServiceSpecificExitCode = 0;
1137 lpservicestatus->dwCheckPoint = 0;
1138 lpservicestatus->dwWaitHint = 0;
1140 return TRUE;
1143 /******************************************************************************
1144 * QueryServiceStatusEx [ADVAPI32.@]
1146 * Get information about a service.
1148 * PARAMS
1149 * hService [I] Handle to service to get information about
1150 * InfoLevel [I] Level of information to get
1151 * lpBuffer [O] Destination for requested information
1152 * cbBufSize [I] Size of lpBuffer in bytes
1153 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1155 * RETURNS
1156 * Success: TRUE
1157 * FAILURE: FALSE
1159 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1160 LPBYTE lpBuffer, DWORD cbBufSize,
1161 LPDWORD pcbBytesNeeded)
1163 FIXME("stub\n");
1164 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1165 return FALSE;
1168 /******************************************************************************
1169 * QueryServiceConfigA [ADVAPI32.@]
1171 BOOL WINAPI
1172 QueryServiceConfigA( SC_HANDLE hService,
1173 LPQUERY_SERVICE_CONFIGA lpServiceConfig,
1174 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1176 static const CHAR szDisplayName[] = "DisplayName";
1177 static const CHAR szType[] = "Type";
1178 static const CHAR szStart[] = "Start";
1179 static const CHAR szError[] = "ErrorControl";
1180 static const CHAR szImagePath[] = "ImagePath";
1181 static const CHAR szGroup[] = "Group";
1182 static const CHAR szDependencies[] = "Dependencies";
1183 HKEY hKey = ((struct sc_handle*) hService)->u.service.hkey;
1184 CHAR str_buffer[ MAX_PATH ];
1185 LONG r;
1186 DWORD type, val, sz, total, n;
1187 LPBYTE p;
1189 TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
1190 cbBufSize, pcbBytesNeeded);
1192 /* calculate the size required first */
1193 total = sizeof (QUERY_SERVICE_CONFIGA);
1195 sz = sizeof(str_buffer);
1196 r = RegQueryValueExA( hKey, szImagePath, 0, &type, str_buffer, &sz );
1197 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1199 sz = ExpandEnvironmentStringsA(str_buffer,NULL,0);
1200 if( 0 == sz ) return FALSE;
1202 total += sz;
1204 else
1206 /* FIXME: set last error */
1207 return FALSE;
1210 sz = 0;
1211 r = RegQueryValueExA( hKey, szGroup, 0, &type, NULL, &sz );
1212 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1213 total += sz;
1215 sz = 0;
1216 r = RegQueryValueExA( hKey, szDependencies, 0, &type, NULL, &sz );
1217 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1218 total += sz;
1220 sz = 0;
1221 r = RegQueryValueExA( hKey, szStart, 0, &type, NULL, &sz );
1222 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1223 total += sz;
1225 sz = 0;
1226 r = RegQueryValueExA( hKey, szDisplayName, 0, &type, NULL, &sz );
1227 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1228 total += sz;
1230 /* if there's not enough memory, return an error */
1231 if( total > *pcbBytesNeeded )
1233 *pcbBytesNeeded = total;
1234 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1235 return FALSE;
1238 *pcbBytesNeeded = total;
1239 ZeroMemory( lpServiceConfig, total );
1241 sz = sizeof val;
1242 r = RegQueryValueExA( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1243 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1244 lpServiceConfig->dwServiceType = val;
1246 sz = sizeof val;
1247 r = RegQueryValueExA( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1248 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1249 lpServiceConfig->dwStartType = val;
1251 sz = sizeof val;
1252 r = RegQueryValueExA( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1253 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1254 lpServiceConfig->dwErrorControl = val;
1256 /* now do the strings */
1257 p = (LPBYTE) &lpServiceConfig[1];
1258 n = total - sizeof (QUERY_SERVICE_CONFIGA);
1260 sz = sizeof(str_buffer);
1261 r = RegQueryValueExA( hKey, szImagePath, 0, &type, str_buffer, &sz );
1262 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1264 sz = ExpandEnvironmentStringsA(str_buffer, p, n);
1265 if( 0 == sz || sz > n ) return FALSE;
1267 lpServiceConfig->lpBinaryPathName = (LPSTR) p;
1268 p += sz;
1269 n -= sz;
1271 else
1273 /* FIXME: set last error */
1274 return FALSE;
1277 sz = n;
1278 r = RegQueryValueExA( hKey, szGroup, 0, &type, p, &sz );
1279 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1281 lpServiceConfig->lpLoadOrderGroup = (LPSTR) p;
1282 p += sz;
1283 n -= sz;
1286 sz = n;
1287 r = RegQueryValueExA( hKey, szDependencies, 0, &type, p, &sz );
1288 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1290 lpServiceConfig->lpDependencies = (LPSTR) p;
1291 p += sz;
1292 n -= sz;
1295 if( n < 0 )
1296 ERR("Buffer overflow!\n");
1298 TRACE("Image path = %s\n", lpServiceConfig->lpBinaryPathName );
1299 TRACE("Group = %s\n", lpServiceConfig->lpLoadOrderGroup );
1301 return TRUE;
1304 /******************************************************************************
1305 * QueryServiceConfigW [ADVAPI32.@]
1307 BOOL WINAPI
1308 QueryServiceConfigW( SC_HANDLE hService,
1309 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1310 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1312 static const WCHAR szDisplayName[] = {
1313 'D','i','s','p','l','a','y','N','a','m','e', 0 };
1314 static const WCHAR szType[] = {'T','y','p','e',0};
1315 static const WCHAR szStart[] = {'S','t','a','r','t',0};
1316 static const WCHAR szError[] = {
1317 'E','r','r','o','r','C','o','n','t','r','o','l', 0};
1318 static const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
1319 static const WCHAR szGroup[] = {'G','r','o','u','p',0};
1320 static const WCHAR szDependencies[] = {
1321 'D','e','p','e','n','d','e','n','c','i','e','s',0};
1322 HKEY hKey = ((struct sc_handle*) hService)->u.service.hkey;
1323 WCHAR str_buffer[ MAX_PATH ];
1324 LONG r;
1325 DWORD type, val, sz, total, n;
1326 LPBYTE p;
1328 TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
1329 cbBufSize, pcbBytesNeeded);
1331 /* calculate the size required first */
1332 total = sizeof (QUERY_SERVICE_CONFIGW);
1334 sz = sizeof(str_buffer);
1335 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1336 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1338 sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1339 if( 0 == sz ) return FALSE;
1341 total += sizeof(WCHAR) * sz;
1343 else
1345 /* FIXME: set last error */
1346 return FALSE;
1349 sz = 0;
1350 r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1351 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1352 total += sz;
1354 sz = 0;
1355 r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1356 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1357 total += sz;
1359 sz = 0;
1360 r = RegQueryValueExW( hKey, szStart, 0, &type, NULL, &sz );
1361 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1362 total += sz;
1364 sz = 0;
1365 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1366 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1367 total += sz;
1369 /* if there's not enough memory, return an error */
1370 if( total > *pcbBytesNeeded )
1372 *pcbBytesNeeded = total;
1373 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1374 return FALSE;
1377 *pcbBytesNeeded = total;
1378 ZeroMemory( lpServiceConfig, total );
1380 sz = sizeof val;
1381 r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1382 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1383 lpServiceConfig->dwServiceType = val;
1385 sz = sizeof val;
1386 r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1387 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1388 lpServiceConfig->dwStartType = val;
1390 sz = sizeof val;
1391 r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1392 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1393 lpServiceConfig->dwErrorControl = val;
1395 /* now do the strings */
1396 p = (LPBYTE) &lpServiceConfig[1];
1397 n = total - sizeof (QUERY_SERVICE_CONFIGW);
1399 sz = sizeof(str_buffer);
1400 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1401 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1403 sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
1404 sz *= sizeof(WCHAR);
1405 if( 0 == sz || sz > n ) return FALSE;
1407 lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
1408 p += sz;
1409 n -= sz;
1411 else
1413 /* FIXME: set last error */
1414 return FALSE;
1417 sz = n;
1418 r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
1419 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1421 lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
1422 p += sz;
1423 n -= sz;
1426 sz = n;
1427 r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
1428 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1430 lpServiceConfig->lpDependencies = (LPWSTR) p;
1431 p += sz;
1432 n -= sz;
1435 if( n < 0 )
1436 ERR("Buffer overflow!\n");
1438 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1439 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1441 return TRUE;
1444 /******************************************************************************
1445 * ChangeServiceConfigW [ADVAPI32.@]
1447 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
1448 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1449 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
1450 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
1452 FIXME("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
1453 hService, dwServiceType, dwStartType, dwErrorControl,
1454 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
1455 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
1456 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
1457 return TRUE;
1460 /******************************************************************************
1461 * ChangeServiceConfigA [ADVAPI32.@]
1463 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
1464 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1465 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
1466 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
1468 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
1469 LPWSTR wServiceStartName, wPassword, wDisplayName;
1470 BOOL r;
1472 TRACE("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
1473 hService, dwServiceType, dwStartType, dwErrorControl,
1474 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
1475 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
1476 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
1478 wBinaryPathName = SERV_dup( lpBinaryPathName );
1479 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
1480 wDependencies = SERV_dupmulti( lpDependencies );
1481 wServiceStartName = SERV_dup( lpServiceStartName );
1482 wPassword = SERV_dup( lpPassword );
1483 wDisplayName = SERV_dup( lpDisplayName );
1485 r = ChangeServiceConfigW( hService, dwServiceType,
1486 dwStartType, dwErrorControl, wBinaryPathName,
1487 wLoadOrderGroup, lpdwTagId, wDependencies,
1488 wServiceStartName, wPassword, wDisplayName);
1490 SERV_free( wBinaryPathName );
1491 SERV_free( wLoadOrderGroup );
1492 SERV_free( wDependencies );
1493 SERV_free( wServiceStartName );
1494 SERV_free( wPassword );
1495 SERV_free( wDisplayName );
1497 return r;
1500 /******************************************************************************
1501 * ChangeServiceConfig2A [ADVAPI32.@]
1503 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
1504 LPVOID lpInfo)
1506 BOOL r = FALSE;
1508 TRACE("%p %ld %p\n",hService, dwInfoLevel, lpInfo);
1510 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
1512 LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
1513 SERVICE_DESCRIPTIONW sdw;
1515 sdw.lpDescription = SERV_dup( sd->lpDescription );
1517 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
1519 SERV_free( sdw.lpDescription );
1521 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
1523 LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
1524 SERVICE_FAILURE_ACTIONSW faw;
1526 faw.dwResetPeriod = fa->dwResetPeriod;
1527 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
1528 faw.lpCommand = SERV_dup( fa->lpCommand );
1529 faw.cActions = fa->cActions;
1530 faw.lpsaActions = fa->lpsaActions;
1532 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
1534 SERV_free( faw.lpRebootMsg );
1535 SERV_free( faw.lpCommand );
1537 else
1538 SetLastError( ERROR_INVALID_PARAMETER );
1540 return r;
1543 /******************************************************************************
1544 * ChangeServiceConfig2W [ADVAPI32.@]
1546 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
1547 LPVOID lpInfo)
1549 HKEY hKey = ((struct sc_handle*) hService)->u.service.hkey;
1551 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
1553 static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
1554 LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
1555 if (sd->lpDescription)
1557 TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
1558 if (sd->lpDescription[0] == 0)
1559 RegDeleteValueW(hKey,szDescription);
1560 else
1561 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
1562 (LPVOID)sd->lpDescription,
1563 sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
1566 else
1567 FIXME("STUB: %p %ld %p\n",hService, dwInfoLevel, lpInfo);
1568 return TRUE;
1571 /******************************************************************************
1572 * QueryServiceObjectSecurity [ADVAPI32.@]
1574 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
1575 SECURITY_INFORMATION dwSecurityInformation,
1576 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
1577 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1579 PACL pACL = NULL;
1580 FIXME("%p %ld %p %lu %p\n", hService, dwSecurityInformation,
1581 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
1584 InitializeSecurityDescriptor(lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
1586 pACL = HeapAlloc( GetProcessHeap(), 0, sizeof(ACL) );
1587 InitializeAcl(pACL, sizeof(ACL), ACL_REVISION);
1588 SetSecurityDescriptorDacl(lpSecurityDescriptor, TRUE, pACL, TRUE);
1589 return TRUE;
1592 /******************************************************************************
1593 * SetServiceObjectSecurity [ADVAPI32.@]
1595 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
1596 SECURITY_INFORMATION dwSecurityInformation,
1597 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
1599 FIXME("%p %ld %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
1600 return TRUE;