Proper finalization in StartServiceW.
[wine] / dlls / advapi32 / service.c
1 /*
2  * Win32 advapi functions
3  *
4  * Copyright 1995 Sven Verdoolaege
5  *
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.
10  *
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.
15  *
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
19  */
20
21 #include <stdarg.h>
22 #include <string.h>
23 #include <time.h>
24
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"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(advapi);
36
37 static DWORD   start_dwNumServiceArgs;
38 static LPWSTR *start_lpServiceArgVectors;
39
40 static const WCHAR _ServiceStartDataW[]  = {'A','D','V','A','P','I','_','S',
41                                             'e','r','v','i','c','e','S','t',
42                                             'a','r','t','D','a','t','a',0};
43 static const WCHAR szServiceManagerKey[] = { 'S','y','s','t','e','m','\\',
44       'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
45       'S','e','r','v','i','c','e','s','\\',0 };
46 static const WCHAR  szSCMLock[] = {'A','D','V','A','P','I','_','S','C','M',
47                                    'L','O','C','K',0};
48
49 /******************************************************************************
50  * SC_HANDLEs
51  */
52
53 #define MAX_SERVICE_NAME 256
54
55 typedef enum { SC_HTYPE_MANAGER, SC_HTYPE_SERVICE } SC_HANDLE_TYPE;
56
57 struct sc_handle;
58
59 struct sc_manager       /* SCM handle */
60 {
61     HKEY hkey_scm_db;   /* handle to services database in the registry */
62     LONG ref_count;     /* handle must remain alive until any related service */
63                         /* handle exists because DeleteService requires it */
64 };
65
66 struct sc_service       /* service handle */
67 {
68     HKEY hkey;          /* handle to service entry in the registry (under hkey_scm_db) */
69     struct sc_handle *sc_manager;  /* pointer to SCM handle */
70     WCHAR name[ MAX_SERVICE_NAME ];
71 };
72
73 struct sc_handle
74 {
75     SC_HANDLE_TYPE htype;
76     union
77     {
78         struct sc_manager manager;
79         struct sc_service service;
80     } u;
81 };
82
83 static struct sc_handle* alloc_sc_handle( SC_HANDLE_TYPE htype )
84 {
85     struct sc_handle *retval;
86
87     retval = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct sc_handle) );
88     if( retval != NULL )
89     {
90         retval->htype = htype;
91     }
92     TRACE("SC_HANDLE type=%d -> %p\n",htype,retval);
93     return retval;
94 }
95
96 static void free_sc_handle( struct sc_handle* handle )
97 {
98     if( NULL == handle )
99         return;
100
101     switch( handle->htype )
102     {
103         case SC_HTYPE_MANAGER:
104         {
105             if( InterlockedDecrement( &handle->u.manager.ref_count ) )
106                 /* there are references to this handle */
107                 return;
108
109             if( handle->u.manager.hkey_scm_db )
110                 RegCloseKey( handle->u.manager.hkey_scm_db );
111             break;
112         }
113
114         case SC_HTYPE_SERVICE:
115         {
116             struct sc_handle *h = handle->u.service.sc_manager;
117
118             if( h )
119             {
120                 /* release SCM handle */
121                 if( 0 == InterlockedDecrement( &h->u.manager.ref_count ) )
122                 {
123                     /* it's time to destroy SCM handle */
124                     if( h->u.manager.hkey_scm_db )
125                         RegCloseKey( h->u.manager.hkey_scm_db );
126                     
127                     TRACE("SC_HANDLE (SCM) %p type=%d\n",h,h->htype);
128                     
129                     HeapFree( GetProcessHeap(), 0, h );
130                 }
131             }
132             if( handle->u.service.hkey )
133                 RegCloseKey( handle->u.service.hkey );
134             break;
135         }
136     }
137
138     TRACE("SC_HANDLE %p type=%d\n",handle,handle->htype);
139
140     HeapFree( GetProcessHeap(), 0, handle );
141 }
142
143 static void init_service_handle( struct sc_handle* handle,
144                                  struct sc_handle* sc_manager,
145                                  HKEY hKey, LPCWSTR lpServiceName )
146 {
147     /* init sc_service structure */
148     handle->u.service.hkey = hKey;
149     lstrcpynW( handle->u.service.name, lpServiceName, MAX_SERVICE_NAME );
150
151     /* add reference to SCM handle */
152     InterlockedIncrement( &sc_manager->u.manager.ref_count );
153     handle->u.service.sc_manager = sc_manager;
154 }
155
156 /******************************************************************************
157  * EnumServicesStatusA [ADVAPI32.@]
158  */
159 BOOL WINAPI
160 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
161                      DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
162                      DWORD cbBufSize, LPDWORD pcbBytesNeeded,
163                      LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
164 {       FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
165                 dwServiceType, dwServiceState, lpServices, cbBufSize,
166                 pcbBytesNeeded, lpServicesReturned,  lpResumeHandle);
167         SetLastError (ERROR_ACCESS_DENIED);
168         return FALSE;
169 }
170
171 /******************************************************************************
172  * EnumServicesStatusW [ADVAPI32.@]
173  */
174 BOOL WINAPI
175 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
176                      DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
177                      DWORD cbBufSize, LPDWORD pcbBytesNeeded,
178                      LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
179 {       FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
180                 dwServiceType, dwServiceState, lpServices, cbBufSize,
181                 pcbBytesNeeded, lpServicesReturned,  lpResumeHandle);
182         SetLastError (ERROR_ACCESS_DENIED);
183         return FALSE;
184 }
185
186 /******************************************************************************
187  * StartServiceCtrlDispatcherA [ADVAPI32.@]
188  */
189 BOOL WINAPI
190 StartServiceCtrlDispatcherA( LPSERVICE_TABLE_ENTRYA servent )
191 {
192     LPSERVICE_MAIN_FUNCTIONA fpMain;
193     HANDLE wait;
194     DWORD  dwNumServiceArgs ;
195     LPWSTR *lpArgVecW;
196     LPSTR  *lpArgVecA;
197     unsigned int i;
198
199     TRACE("(%p)\n", servent);
200     wait = CreateSemaphoreW(NULL,1,1,_ServiceStartDataW);
201     if (!wait)
202     {
203         ERR("Couldn't create data semaphore\n");
204         return FALSE;
205     }
206
207     dwNumServiceArgs = start_dwNumServiceArgs;
208     lpArgVecW        = start_lpServiceArgVectors;
209
210     ReleaseSemaphore(wait, 1, NULL);
211
212     /* Convert the Unicode arg vectors back to ASCII */
213     if(dwNumServiceArgs)
214         lpArgVecA = (LPSTR*) HeapAlloc( GetProcessHeap(), 0,
215                                    dwNumServiceArgs*sizeof(LPSTR) );
216     else
217         lpArgVecA = NULL;
218
219     for(i=0; i<dwNumServiceArgs; i++)
220         lpArgVecA[i]=HEAP_strdupWtoA(GetProcessHeap(), 0, lpArgVecW[i]);
221
222     /* FIXME: should we blindly start all services? */
223     while (servent->lpServiceName) {
224         TRACE("%s at %p)\n", debugstr_a(servent->lpServiceName),servent);
225         fpMain = servent->lpServiceProc;
226
227         /* try to start the service */
228         fpMain( dwNumServiceArgs, lpArgVecA);
229
230         servent++;
231     }
232
233     if(dwNumServiceArgs)
234     {
235         /* free arg strings */
236         for(i=0; i<dwNumServiceArgs; i++)
237             HeapFree(GetProcessHeap(), 0, lpArgVecA[i]);
238         HeapFree(GetProcessHeap(), 0, lpArgVecA);
239     }
240
241     return TRUE;
242 }
243
244 /******************************************************************************
245  * StartServiceCtrlDispatcherW [ADVAPI32.@]
246  *
247  * PARAMS
248  *   servent []
249  */
250 BOOL WINAPI
251 StartServiceCtrlDispatcherW( LPSERVICE_TABLE_ENTRYW servent )
252 {
253     LPSERVICE_MAIN_FUNCTIONW fpMain;
254     HANDLE wait;
255     DWORD  dwNumServiceArgs ;
256     LPWSTR *lpServiceArgVectors ;
257
258     TRACE("(%p)\n", servent);
259     wait = OpenSemaphoreW(SEMAPHORE_ALL_ACCESS, FALSE, _ServiceStartDataW);
260     if(wait == 0)
261     {
262         ERR("Couldn't find wait semaphore\n");
263         ERR("perhaps you need to start services using StartService\n");
264         return FALSE;
265     }
266
267     dwNumServiceArgs    = start_dwNumServiceArgs;
268     lpServiceArgVectors = start_lpServiceArgVectors;
269
270     ReleaseSemaphore(wait, 1, NULL);
271
272     /* FIXME: should we blindly start all services? */
273     while (servent->lpServiceName) {
274         TRACE("%s at %p)\n", debugstr_w(servent->lpServiceName),servent);
275         fpMain = servent->lpServiceProc;
276
277         /* try to start the service */
278         fpMain( dwNumServiceArgs, lpServiceArgVectors);
279
280         servent++;
281     }
282
283     return TRUE;
284 }
285
286 /******************************************************************************
287  * LockServiceDatabase  [ADVAPI32.@]
288  */
289 LPVOID WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
290 {
291     HANDLE ret;
292
293     TRACE("%p\n",hSCManager);
294
295     ret = CreateFileMappingW( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
296                               0, MAX_SERVICE_NAME * sizeof(WCHAR), szSCMLock );
297     if( ret && GetLastError() == ERROR_ALREADY_EXISTS )
298     {
299         CloseHandle( ret );
300         ret = NULL;
301         SetLastError( ERROR_SERVICE_DATABASE_LOCKED );
302     }
303
304     TRACE("returning %p\n", ret);
305
306     return ret;
307 }
308
309 /******************************************************************************
310  * UnlockServiceDatabase  [ADVAPI32.@]
311  */
312 BOOL WINAPI UnlockServiceDatabase (LPVOID ScLock)
313 {
314     TRACE("%p\n",ScLock);
315
316     return CloseHandle( (HANDLE) ScLock );
317 }
318
319 /******************************************************************************
320  * RegisterServiceCtrlHandlerA [ADVAPI32.@]
321  */
322 SERVICE_STATUS_HANDLE WINAPI
323 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName,
324                              LPHANDLER_FUNCTION lpfHandler )
325 {       FIXME("%s %p\n", lpServiceName, lpfHandler);
326         return 0xcacacafe;
327 }
328
329 /******************************************************************************
330  * RegisterServiceCtrlHandlerW [ADVAPI32.@]
331  *
332  * PARAMS
333  *   lpServiceName []
334  *   lpfHandler    []
335  */
336 SERVICE_STATUS_HANDLE WINAPI
337 RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName,
338                              LPHANDLER_FUNCTION lpfHandler )
339 {       FIXME("%s %p\n", debugstr_w(lpServiceName), lpfHandler);
340         return 0xcacacafe;
341 }
342
343 /******************************************************************************
344  * SetServiceStatus [ADVAPI32.@]
345  *
346  * PARAMS
347  *   hService []
348  *   lpStatus []
349  */
350 BOOL WINAPI
351 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
352 {       FIXME("0x%lx %p\n",hService, lpStatus);
353         TRACE("\tType:%lx\n",lpStatus->dwServiceType);
354         TRACE("\tState:%lx\n",lpStatus->dwCurrentState);
355         TRACE("\tControlAccepted:%lx\n",lpStatus->dwControlsAccepted);
356         TRACE("\tExitCode:%lx\n",lpStatus->dwWin32ExitCode);
357         TRACE("\tServiceExitCode:%lx\n",lpStatus->dwServiceSpecificExitCode);
358         TRACE("\tCheckPoint:%lx\n",lpStatus->dwCheckPoint);
359         TRACE("\tWaitHint:%lx\n",lpStatus->dwWaitHint);
360         return TRUE;
361 }
362
363 /******************************************************************************
364  * OpenSCManagerA [ADVAPI32.@]
365  *
366  * Establish a connection to the service control manager and open its database.
367  *
368  * PARAMS
369  *   lpMachineName   [I] Pointer to machine name string
370  *   lpDatabaseName  [I] Pointer to database name string
371  *   dwDesiredAccess [I] Type of access
372  *
373  * RETURNS
374  *   Success: A Handle to the service control manager database
375  *   Failure: NULL
376  */
377 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
378                                  DWORD dwDesiredAccess )
379 {
380     UNICODE_STRING lpMachineNameW;
381     UNICODE_STRING lpDatabaseNameW;
382     SC_HANDLE ret;
383
384     RtlCreateUnicodeStringFromAsciiz (&lpMachineNameW,lpMachineName);
385     RtlCreateUnicodeStringFromAsciiz (&lpDatabaseNameW,lpDatabaseName);
386     ret = OpenSCManagerW(lpMachineNameW.Buffer,lpDatabaseNameW.Buffer, dwDesiredAccess);
387     RtlFreeUnicodeString(&lpDatabaseNameW);
388     RtlFreeUnicodeString(&lpMachineNameW);
389     return ret;
390 }
391
392 /******************************************************************************
393  * OpenSCManagerW [ADVAPI32.@]
394  *
395  * See OpenSCManagerA.
396  */
397 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
398                                  DWORD dwDesiredAccess )
399 {
400     struct sc_handle *retval;
401     HKEY hReg;
402     LONG r;
403
404     TRACE("(%s,%s,0x%08lx)\n", debugstr_w(lpMachineName),
405           debugstr_w(lpDatabaseName), dwDesiredAccess);
406
407     /*
408      * FIXME: what is lpDatabaseName?
409      * It should be set to "SERVICES_ACTIVE_DATABASE" according to
410      * docs, but what if it isn't?
411      */
412
413     retval = alloc_sc_handle( SC_HTYPE_MANAGER );
414     if( NULL == retval ) return NULL;
415
416     retval->u.manager.ref_count = 1;
417
418     r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
419     if (r!=ERROR_SUCCESS)
420         goto error;
421
422     r = RegOpenKeyExW(hReg, szServiceManagerKey,
423                       0, KEY_ALL_ACCESS, &retval->u.manager.hkey_scm_db);
424     RegCloseKey( hReg );
425     if (r!=ERROR_SUCCESS)
426         goto error;
427
428     TRACE("returning %p\n", retval);
429
430     return (SC_HANDLE) retval;
431
432 error:
433     free_sc_handle( retval );
434     return NULL;
435 }
436
437
438 /******************************************************************************
439  * AllocateLocallyUniqueId [ADVAPI32.@]
440  *
441  * PARAMS
442  *   lpluid []
443  */
444 BOOL WINAPI
445 AllocateLocallyUniqueId( PLUID lpluid )
446 {
447         lpluid->LowPart = time(NULL);
448         lpluid->HighPart = 0;
449         return TRUE;
450 }
451
452
453 /******************************************************************************
454  * ControlService [ADVAPI32.@]
455  *
456  * Send a control code to a service.
457  *
458  * PARAMS
459  *   hService        [I] Handle of the service control manager database
460  *   dwControl       [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
461  *   lpServiceStatus [O] Destination for the status of the service, if available
462  *
463  * RETURNS
464  *   Success: TRUE.
465  *   Failure: FALSE.
466  */
467 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
468                             LPSERVICE_STATUS lpServiceStatus )
469 {
470     FIXME("(%p,%ld,%p): stub\n",hService,dwControl,lpServiceStatus);
471     return TRUE;
472 }
473
474
475 /******************************************************************************
476  * CloseServiceHandle [ADVAPI32.@]
477  * 
478  * Close a handle to a service or the service control manager database.
479  *
480  * PARAMS
481  *   hSCObject [I] Handle to service or service control manager database
482  *
483  * RETURNS
484  *  Success: TRUE
485  *  Failure: FALSE
486  */
487 BOOL WINAPI
488 CloseServiceHandle( SC_HANDLE hSCObject )
489 {
490     TRACE("(%p)\n", hSCObject);
491
492     free_sc_handle( (struct sc_handle*) hSCObject );
493
494     return TRUE;
495 }
496
497
498 /******************************************************************************
499  * OpenServiceA [ADVAPI32.@]
500  *
501  * Open a handle to a service.
502  *
503  * PARAMS
504  *   hSCManager      [I] Handle of the service control manager database
505  *   lpServiceName   [I] Name of the service to open
506  *   dwDesiredAccess [I] Access required to the service
507  *
508  * RETURNS
509  *    Success: Handle to the service
510  *    Failure: NULL
511  */
512 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
513                                DWORD dwDesiredAccess )
514 {
515     UNICODE_STRING lpServiceNameW;
516     SC_HANDLE ret;
517     RtlCreateUnicodeStringFromAsciiz (&lpServiceNameW,lpServiceName);
518     if(lpServiceName)
519         TRACE("Request for service %s\n",lpServiceName);
520     else
521         return FALSE;
522     ret = OpenServiceW( hSCManager, lpServiceNameW.Buffer, dwDesiredAccess);
523     RtlFreeUnicodeString(&lpServiceNameW);
524     return ret;
525 }
526
527
528 /******************************************************************************
529  * OpenServiceW [ADVAPI32.@]
530  *
531  * See OpenServiceA.
532  */
533 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
534                                DWORD dwDesiredAccess)
535 {
536     struct sc_handle *hscm = hSCManager;
537     struct sc_handle *retval;
538     HKEY hKey;
539     long r;
540
541     TRACE("(%p,%p,%ld)\n",hSCManager, lpServiceName,
542           dwDesiredAccess);
543
544     retval = alloc_sc_handle( SC_HTYPE_SERVICE );
545     if( NULL == retval )
546         return NULL;
547
548     r = RegOpenKeyExW( hscm->u.manager.hkey_scm_db,
549                        lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
550     if (r!=ERROR_SUCCESS)
551     {
552         free_sc_handle( retval );
553         SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
554         return NULL;
555     }
556     
557     init_service_handle( retval, hscm, hKey, lpServiceName );
558
559     TRACE("returning %p\n",retval);
560
561     return (SC_HANDLE) retval;
562 }
563
564 /******************************************************************************
565  * CreateServiceW [ADVAPI32.@]
566  */
567 SC_HANDLE WINAPI
568 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
569                   LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
570                   DWORD dwServiceType, DWORD dwStartType,
571                   DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
572                   LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
573                   LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
574                   LPCWSTR lpPassword )
575 {
576     struct sc_handle *hscm = hSCManager;
577     struct sc_handle *retval;
578     HKEY hKey;
579     LONG r;
580     DWORD dp;
581     static const WCHAR szDisplayName[] = { 'D','i','s','p','l','a','y','N','a','m','e', 0 };
582     static const WCHAR szType[] = {'T','y','p','e',0};
583     static const WCHAR szStart[] = {'S','t','a','r','t',0};
584     static const WCHAR szError[] = {'E','r','r','o','r','C','o','n','t','r','o','l', 0};
585     static const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
586     static const WCHAR szGroup[] = {'G','r','o','u','p',0};
587     static const WCHAR szDependencies[] = { 'D','e','p','e','n','d','e','n','c','i','e','s',0};
588
589     FIXME("%p %s %s\n", hSCManager, 
590           debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
591
592     retval = alloc_sc_handle( SC_HTYPE_SERVICE );
593     if( NULL == retval )
594         return NULL;
595
596     r = RegCreateKeyExW(hscm->u.manager.hkey_scm_db, lpServiceName, 0, NULL,
597                        REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
598     if (r!=ERROR_SUCCESS)
599         goto error;
600
601     init_service_handle( retval, hscm, hKey, lpServiceName );
602
603     if (dp != REG_CREATED_NEW_KEY)
604         goto error;
605
606     if(lpDisplayName)
607     {
608         r = RegSetValueExW(hKey, szDisplayName, 0, REG_SZ, (LPBYTE)lpDisplayName,
609                            (strlenW(lpDisplayName)+1)*sizeof(WCHAR) );
610         if (r!=ERROR_SUCCESS)
611             goto error;
612     }
613
614     r = RegSetValueExW(hKey, szType, 0, REG_DWORD, (LPVOID)&dwServiceType, sizeof (DWORD) );
615     if (r!=ERROR_SUCCESS)
616         goto error;
617
618     r = RegSetValueExW(hKey, szStart, 0, REG_DWORD, (LPVOID)&dwStartType, sizeof (DWORD) );
619     if (r!=ERROR_SUCCESS)
620         goto error;
621
622     r = RegSetValueExW(hKey, szError, 0, REG_DWORD,
623                            (LPVOID)&dwErrorControl, sizeof (DWORD) );
624     if (r!=ERROR_SUCCESS)
625         goto error;
626
627     if(lpBinaryPathName)
628     {
629         r = RegSetValueExW(hKey, szImagePath, 0, REG_SZ, (LPBYTE)lpBinaryPathName,
630                            (strlenW(lpBinaryPathName)+1)*sizeof(WCHAR) );
631         if (r!=ERROR_SUCCESS)
632             goto error;
633     }
634
635     if(lpLoadOrderGroup)
636     {
637         r = RegSetValueExW(hKey, szGroup, 0, REG_SZ, (LPBYTE)lpLoadOrderGroup,
638                            (strlenW(lpLoadOrderGroup)+1)*sizeof(WCHAR) );
639         if (r!=ERROR_SUCCESS)
640             goto error;
641     }
642
643     if(lpDependencies)
644     {
645         DWORD len = 0;
646
647         /* determine the length of a double null terminated multi string */
648         do {
649             len += (strlenW(&lpDependencies[len])+1);
650         } while (lpDependencies[len++]);
651
652         r = RegSetValueExW(hKey, szDependencies, 0, REG_MULTI_SZ,
653                            (LPBYTE)lpDependencies, len );
654         if (r!=ERROR_SUCCESS)
655             goto error;
656     }
657
658     if(lpPassword)
659     {
660         FIXME("Don't know how to add a Password for a service.\n");
661     }
662
663     if(lpServiceStartName)
664     {
665         FIXME("Don't know how to add a ServiceStartName for a service.\n");
666     }
667
668     return (SC_HANDLE) retval;
669     
670 error:
671     free_sc_handle( retval );
672     return NULL;
673 }
674
675
676 static inline LPWSTR SERV_dup( LPCSTR str )
677 {
678     UINT len;
679     LPWSTR wstr;
680
681     if( !str )
682         return NULL;
683     len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
684     wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
685     MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
686     return wstr;
687 }
688
689 static inline LPWSTR SERV_dupmulti( LPCSTR str )
690 {
691     UINT len = 0, n = 0;
692     LPWSTR wstr;
693
694     if( !str )
695         return NULL;
696     do {
697         len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
698         n += (strlen( &str[n] ) + 1);
699     } while (str[n]);
700     len++;
701     n++;
702     
703     wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
704     MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
705     return wstr;
706 }
707
708 static inline VOID SERV_free( LPWSTR wstr )
709 {
710     HeapFree( GetProcessHeap(), 0, wstr );
711 }
712
713 /******************************************************************************
714  * CreateServiceA [ADVAPI32.@]
715  */
716 SC_HANDLE WINAPI
717 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
718                   LPCSTR lpDisplayName, DWORD dwDesiredAccess,
719                   DWORD dwServiceType, DWORD dwStartType,
720                   DWORD dwErrorControl, LPCSTR lpBinaryPathName,
721                   LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
722                   LPCSTR lpDependencies, LPCSTR lpServiceStartName,
723                   LPCSTR lpPassword )
724 {
725     LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
726         lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
727     SC_HANDLE r;
728
729     TRACE("%p %s %s\n", hSCManager,
730           debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
731
732     lpServiceNameW = SERV_dup( lpServiceName );
733     lpDisplayNameW = SERV_dup( lpDisplayName );
734     lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
735     lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
736     lpDependenciesW = SERV_dupmulti( lpDependencies );
737     lpServiceStartNameW = SERV_dup( lpServiceStartName );
738     lpPasswordW = SERV_dup( lpPassword );
739
740     r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
741             dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
742             lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
743             lpDependenciesW, lpServiceStartNameW, lpPasswordW );
744
745     SERV_free( lpServiceNameW );
746     SERV_free( lpDisplayNameW );
747     SERV_free( lpBinaryPathNameW );
748     SERV_free( lpLoadOrderGroupW );
749     SERV_free( lpDependenciesW );
750     SERV_free( lpServiceStartNameW );
751     SERV_free( lpPasswordW );
752
753     return r;
754 }
755
756
757 /******************************************************************************
758  * DeleteService [ADVAPI32.@]
759  *
760  * Delete a service from the service control manager database.
761  *
762  * PARAMS
763  *    hService [I] Handle of the service to delete
764  *
765  * RETURNS
766  *  Success: TRUE
767  *  Failure: FALSE
768  */
769 BOOL WINAPI DeleteService( SC_HANDLE hService )
770 {
771     struct sc_handle *hsvc = hService;
772     HKEY hKey = hsvc->u.service.hkey;
773     WCHAR valname[MAX_PATH+1];
774     INT index = 0;
775     LONG rc;
776     DWORD size;
777
778     size = MAX_PATH+1; 
779     /* Clean out the values */
780     rc = RegEnumValueW(hKey, index, valname,&size,0,0,0,0);
781     while (rc == ERROR_SUCCESS)
782     {
783         RegDeleteValueW(hKey,valname);
784         index++;
785         size = MAX_PATH+1; 
786         rc = RegEnumValueW(hKey, index, valname, &size,0,0,0,0);
787     }
788
789     RegCloseKey(hKey);
790     hsvc->u.service.hkey = NULL;
791
792     /* delete the key */
793     RegDeleteKeyW(hsvc->u.service.sc_manager->u.manager.hkey_scm_db,
794                   hsvc->u.service.name);
795
796     return TRUE;
797 }
798
799
800 /******************************************************************************
801  * StartServiceA [ADVAPI32.@]
802  *
803  * Start a service
804  *
805  * PARAMS
806  *   hService            [I] Handle of service
807  *   dwNumServiceArgs    [I] Number of arguments
808  *   lpServiceArgVectors [I] Address of array of argument strings
809  *
810  * NOTES
811  *  - NT implements this function using an obscure RPC call.
812  *  - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
813  *    to get things like "%SystemRoot%\\System32\\service.exe" to load.
814  *  - This will only work for shared address space. How should the service
815  *    args be transferred when address spaces are separated?
816  *  - Can only start one service at a time.
817  *  - Has no concept of privilege.
818  *
819  * RETURNS
820  *   Success: TRUE.
821  *   Failure: FALSE
822  */
823 BOOL WINAPI
824 StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
825                  LPCSTR *lpServiceArgVectors )
826 {
827     LPWSTR *lpwstr=NULL;
828     UNICODE_STRING usBuffer;
829     unsigned int i;
830
831     TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
832
833     if(dwNumServiceArgs)
834         lpwstr = (LPWSTR*) HeapAlloc( GetProcessHeap(), 0,
835                                    dwNumServiceArgs*sizeof(LPWSTR) );
836     else
837         lpwstr = NULL;
838
839     for(i=0; i<dwNumServiceArgs; i++)
840     {
841         RtlCreateUnicodeStringFromAsciiz (&usBuffer,lpServiceArgVectors[i]);
842         lpwstr[i]=usBuffer.Buffer;
843     }
844
845     StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
846
847     if(dwNumServiceArgs)
848     {
849         for(i=0; i<dwNumServiceArgs; i++)
850             HeapFree(GetProcessHeap(), 0, lpwstr[i]);
851         HeapFree(GetProcessHeap(), 0, lpwstr);
852     }
853
854     return TRUE;
855 }
856
857
858 /******************************************************************************
859  * StartServiceW [ADVAPI32.@]
860  * 
861  * See StartServiceA.
862  */
863 BOOL WINAPI
864 StartServiceW( SC_HANDLE hService, DWORD dwNumServiceArgs,
865                  LPCWSTR *lpServiceArgVectors )
866 {
867     static const WCHAR  _WaitServiceStartW[]  = {'A','D','V','A','P','I','_','W',
868                                                 'a','i','t','S','e','r','v','i',
869                                                 'c','e','S','t','a','r','t',0};
870     static const WCHAR  _ImagePathW[]  = {'I','m','a','g','e','P','a','t','h',0};
871                                                 
872     struct sc_handle *hsvc = hService;
873     WCHAR path[MAX_PATH],str[MAX_PATH];
874     DWORD type,size;
875     long r;
876     HANDLE data,wait;
877     PROCESS_INFORMATION procinfo;
878     STARTUPINFOW startupinfo;
879     BOOL ret = FALSE;
880
881     TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,
882           lpServiceArgVectors);
883
884     size = sizeof(str);
885     r = RegQueryValueExW(hsvc->u.service.hkey, _ImagePathW, NULL, &type, (LPVOID)str, &size);
886     if (r!=ERROR_SUCCESS)
887         return FALSE;
888     ExpandEnvironmentStringsW(str,path,sizeof(path));
889
890     TRACE("Starting service %s\n", debugstr_w(path) );
891
892     data = CreateSemaphoreW(NULL,1,1,_ServiceStartDataW);
893     if (!data)
894     {
895         ERR("Couldn't create data semaphore\n");
896         return FALSE;
897     }
898     wait = CreateSemaphoreW(NULL,0,1,_WaitServiceStartW);
899     if (!wait)
900     {
901         ERR("Couldn't create wait semaphore\n");
902         return FALSE;
903     }
904
905     /*
906      * FIXME: lpServiceArgsVectors need to be stored and returned to
907      *        the service when it calls StartServiceCtrlDispatcher
908      *
909      * Chuck these in a global (yuk) so we can pass them to
910      * another process - address space separation will break this.
911      */
912
913     r = WaitForSingleObject(data,INFINITE);
914
915     if( r == WAIT_FAILED)
916         return FALSE;
917
918     FIXME("problematic because of address space separation.\n");
919     start_dwNumServiceArgs    = dwNumServiceArgs;
920     start_lpServiceArgVectors = (LPWSTR *)lpServiceArgVectors;
921
922     ZeroMemory(&startupinfo,sizeof(STARTUPINFOW));
923     startupinfo.cb = sizeof(STARTUPINFOW);
924
925     r = CreateProcessW(NULL,
926                    path,
927                    NULL,  /* process security attribs */
928                    NULL,  /* thread security attribs */
929                    FALSE, /* inherit handles */
930                    0,     /* creation flags */
931                    NULL,  /* environment */
932                    NULL,  /* current directory */
933                    &startupinfo,  /* startup info */
934                    &procinfo); /* process info */
935
936     if(r == FALSE)
937     {
938         ERR("Couldn't start process\n");
939         goto done;
940     }
941     CloseHandle( procinfo.hThread );
942
943     /* docs for StartServiceCtrlDispatcher say this should be 30 sec */
944     r = WaitForSingleObject(wait,30000);
945     if( WAIT_FAILED == r )
946     {
947         CloseHandle( procinfo.hProcess );
948         goto done;
949     }
950
951     /* allright */
952     CloseHandle( procinfo.hProcess );
953     ret = TRUE;
954
955 done:
956     CloseHandle( wait );
957     ReleaseSemaphore(data, 1, NULL);
958     CloseHandle( data );
959     return ret;
960 }
961
962 /******************************************************************************
963  * QueryServiceStatus [ADVAPI32.@]
964  *
965  * PARAMS
966  *   hService        []
967  *   lpservicestatus []
968  *
969  */
970 BOOL WINAPI
971 QueryServiceStatus( SC_HANDLE hService, LPSERVICE_STATUS lpservicestatus )
972 {
973     struct sc_handle *hsvc = hService;
974     LONG r;
975     DWORD type, val, size;
976
977     FIXME("(%p,%p) partial\n",hService,lpservicestatus);
978
979     /* read the service type from the registry */
980     size = sizeof(val);
981     r = RegQueryValueExA(hsvc->u.service.hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
982     if(type!=REG_DWORD)
983     {
984         ERR("invalid Type\n");
985         return FALSE;
986     }
987     lpservicestatus->dwServiceType = val;
988     /* FIXME: how are these determined or read from the registry? */
989     /* SERVICE: unavailable=0, stopped=1, starting=2, running=3? */;
990     lpservicestatus->dwCurrentState            = 1;
991     lpservicestatus->dwControlsAccepted        = 0;
992     lpservicestatus->dwWin32ExitCode           = NO_ERROR;
993     lpservicestatus->dwServiceSpecificExitCode = 0;
994     lpservicestatus->dwCheckPoint              = 0;
995     lpservicestatus->dwWaitHint                = 0;
996
997     return TRUE;
998 }
999
1000 /******************************************************************************
1001  * QueryServiceStatusEx [ADVAPI32.@]
1002  *
1003  * Get information about a service.
1004  *
1005  * PARAMS
1006  *   hService       [I] Handle to service to get information about
1007  *   InfoLevel      [I] Level of information to get
1008  *   lpBuffer       [O] Destination for requested information
1009  *   cbBufSize      [I] Size of lpBuffer in bytes
1010  *   pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1011  *
1012  * RETURNS
1013  *  Success: TRUE
1014  *  FAILURE: FALSE
1015  */
1016 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1017                         LPBYTE lpBuffer, DWORD cbBufSize,
1018                         LPDWORD pcbBytesNeeded)
1019 {
1020     FIXME("stub\n");
1021     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1022     return FALSE;
1023 }
1024
1025 /******************************************************************************
1026  * QueryServiceConfigA [ADVAPI32.@]
1027  */
1028 BOOL WINAPI 
1029 QueryServiceConfigA( SC_HANDLE hService,
1030                      LPQUERY_SERVICE_CONFIGA lpServiceConfig,
1031                      DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1032 {
1033     static const CHAR szDisplayName[] = "DisplayName";
1034     static const CHAR szType[] = "Type";
1035     static const CHAR szStart[] = "Start";
1036     static const CHAR szError[] = "ErrorControl";
1037     static const CHAR szImagePath[] = "ImagePath";
1038     static const CHAR szGroup[] = "Group";
1039     static const CHAR szDependencies[] = "Dependencies";
1040     HKEY hKey = ((struct sc_handle*) hService)->u.service.hkey;
1041     CHAR str_buffer[ MAX_PATH ];
1042     LONG r;
1043     DWORD type, val, sz, total, n;
1044     LPBYTE p;
1045
1046     TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
1047            cbBufSize, pcbBytesNeeded);
1048
1049     /* calculate the size required first */
1050     total = sizeof (QUERY_SERVICE_CONFIGA);
1051
1052     sz = sizeof(str_buffer);
1053     r = RegQueryValueExA( hKey, szImagePath, 0, &type, str_buffer, &sz );
1054     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1055     {
1056         sz = ExpandEnvironmentStringsA(str_buffer,NULL,0);
1057         if( 0 == sz ) return FALSE;
1058
1059         total += sz;
1060     }
1061     else
1062     {
1063         /* FIXME: set last error */
1064         return FALSE;
1065     }
1066
1067     sz = 0;
1068     r = RegQueryValueExA( hKey, szGroup, 0, &type, NULL, &sz );
1069     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1070         total += sz;
1071
1072     sz = 0;
1073     r = RegQueryValueExA( hKey, szDependencies, 0, &type, NULL, &sz );
1074     if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1075         total += sz;
1076
1077     sz = 0;
1078     r = RegQueryValueExA( hKey, szStart, 0, &type, NULL, &sz );
1079     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1080         total += sz;
1081
1082     sz = 0;
1083     r = RegQueryValueExA( hKey, szDisplayName, 0, &type, NULL, &sz );
1084     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1085         total += sz;
1086
1087     /* if there's not enough memory, return an error */
1088     if( total > *pcbBytesNeeded )
1089     {
1090         *pcbBytesNeeded = total;
1091         SetLastError( ERROR_INSUFFICIENT_BUFFER );
1092         return FALSE;
1093     }
1094
1095     *pcbBytesNeeded = total;
1096     ZeroMemory( lpServiceConfig, total );
1097
1098     sz = sizeof val;
1099     r = RegQueryValueExA( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1100     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1101         lpServiceConfig->dwServiceType = val;
1102
1103     sz = sizeof val;
1104     r = RegQueryValueExA( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1105     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1106         lpServiceConfig->dwStartType = val;
1107
1108     sz = sizeof val;
1109     r = RegQueryValueExA( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1110     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1111         lpServiceConfig->dwErrorControl = val;
1112
1113     /* now do the strings */
1114     p = (LPBYTE) &lpServiceConfig[1];
1115     n = total - sizeof (QUERY_SERVICE_CONFIGA);
1116
1117     sz = sizeof(str_buffer);
1118     r = RegQueryValueExA( hKey, szImagePath, 0, &type, str_buffer, &sz );
1119     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1120     {
1121         sz = ExpandEnvironmentStringsA(str_buffer, p, n);
1122         if( 0 == sz || sz > n ) return FALSE;
1123
1124         lpServiceConfig->lpBinaryPathName = (LPSTR) p;
1125         p += sz;
1126         n -= sz;
1127     }
1128     else
1129     {
1130         /* FIXME: set last error */
1131         return FALSE;
1132     }
1133
1134     sz = n;
1135     r = RegQueryValueExA( hKey, szGroup, 0, &type, p, &sz );
1136     if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1137     {
1138         lpServiceConfig->lpLoadOrderGroup = (LPSTR) p;
1139         p += sz;
1140         n -= sz;
1141     }
1142
1143     sz = n;
1144     r = RegQueryValueExA( hKey, szDependencies, 0, &type, p, &sz );
1145     if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1146     {
1147         lpServiceConfig->lpDependencies = (LPSTR) p;
1148         p += sz;
1149         n -= sz;
1150     }
1151
1152     if( n < 0 )
1153         ERR("Buffer overflow!\n");
1154
1155     TRACE("Image path = %s\n", lpServiceConfig->lpBinaryPathName );
1156     TRACE("Group      = %s\n", lpServiceConfig->lpLoadOrderGroup );
1157
1158     return TRUE;
1159 }
1160
1161 /******************************************************************************
1162  * QueryServiceConfigW [ADVAPI32.@]
1163  */
1164 BOOL WINAPI 
1165 QueryServiceConfigW( SC_HANDLE hService,
1166                      LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1167                      DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1168 {
1169     static const WCHAR szDisplayName[] = {
1170         'D','i','s','p','l','a','y','N','a','m','e', 0 };
1171     static const WCHAR szType[] = {'T','y','p','e',0};
1172     static const WCHAR szStart[] = {'S','t','a','r','t',0};
1173     static const WCHAR szError[] = {
1174         'E','r','r','o','r','C','o','n','t','r','o','l', 0};
1175     static const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
1176     static const WCHAR szGroup[] = {'G','r','o','u','p',0};
1177     static const WCHAR szDependencies[] = {
1178         'D','e','p','e','n','d','e','n','c','i','e','s',0};
1179     HKEY hKey = ((struct sc_handle*) hService)->u.service.hkey;
1180     WCHAR str_buffer[ MAX_PATH ];
1181     LONG r;
1182     DWORD type, val, sz, total, n;
1183     LPBYTE p;
1184
1185     TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
1186            cbBufSize, pcbBytesNeeded);
1187
1188     /* calculate the size required first */
1189     total = sizeof (QUERY_SERVICE_CONFIGW);
1190
1191     sz = sizeof(str_buffer);
1192     r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1193     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1194     {
1195         sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1196         if( 0 == sz ) return FALSE;
1197
1198         total += sizeof(WCHAR) * sz;
1199     }
1200     else
1201     {
1202        /* FIXME: set last error */
1203        return FALSE;
1204     }
1205
1206     sz = 0;
1207     r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1208     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1209         total += sz;
1210
1211     sz = 0;
1212     r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1213     if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1214         total += sz;
1215
1216     sz = 0;
1217     r = RegQueryValueExW( hKey, szStart, 0, &type, NULL, &sz );
1218     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1219         total += sz;
1220
1221     sz = 0;
1222     r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1223     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1224         total += sz;
1225
1226     /* if there's not enough memory, return an error */
1227     if( total > *pcbBytesNeeded )
1228     {
1229         *pcbBytesNeeded = total;
1230         SetLastError( ERROR_INSUFFICIENT_BUFFER );
1231         return FALSE;
1232     }
1233
1234     *pcbBytesNeeded = total;
1235     ZeroMemory( lpServiceConfig, total );
1236
1237     sz = sizeof val;
1238     r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1239     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1240         lpServiceConfig->dwServiceType = val;
1241
1242     sz = sizeof val;
1243     r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1244     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1245         lpServiceConfig->dwStartType = val;
1246
1247     sz = sizeof val;
1248     r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1249     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1250         lpServiceConfig->dwErrorControl = val;
1251
1252     /* now do the strings */
1253     p = (LPBYTE) &lpServiceConfig[1];
1254     n = total - sizeof (QUERY_SERVICE_CONFIGW);
1255
1256     sz = sizeof(str_buffer);
1257     r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1258     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1259     {
1260         sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
1261         sz *= sizeof(WCHAR);
1262         if( 0 == sz || sz > n ) return FALSE;
1263
1264         lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
1265         p += sz;
1266         n -= sz;
1267     }
1268     else
1269     {
1270        /* FIXME: set last error */
1271        return FALSE;
1272     }
1273
1274     sz = n;
1275     r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
1276     if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1277     {
1278         lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
1279         p += sz;
1280         n -= sz;
1281     }
1282
1283     sz = n;
1284     r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
1285     if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1286     {
1287         lpServiceConfig->lpDependencies = (LPWSTR) p;
1288         p += sz;
1289         n -= sz;
1290     }
1291
1292     if( n < 0 )
1293         ERR("Buffer overflow!\n");
1294
1295     TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1296     TRACE("Group      = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1297
1298     return TRUE;
1299 }
1300
1301 /******************************************************************************
1302  * ChangeServiceConfigW  [ADVAPI32.@]
1303  */
1304 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
1305   DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1306   LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
1307   LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
1308 {
1309     FIXME("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
1310           hService, dwServiceType, dwStartType, dwErrorControl, 
1311           debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
1312           lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
1313           debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
1314     return TRUE;
1315 }
1316
1317 /******************************************************************************
1318  * ChangeServiceConfigA  [ADVAPI32.@]
1319  */
1320 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
1321   DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1322   LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
1323   LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
1324 {
1325     FIXME("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
1326           hService, dwServiceType, dwStartType, dwErrorControl, 
1327           debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
1328           lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
1329           debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
1330     return TRUE;
1331 }
1332
1333 /******************************************************************************
1334  * ChangeServiceConfig2A  [ADVAPI32.@]
1335  */
1336 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel, 
1337     LPVOID lpInfo)
1338 {
1339     FIXME("STUB: %p %ld %p\n",hService, dwInfoLevel, lpInfo);
1340     return TRUE;
1341 }
1342
1343 /******************************************************************************
1344  * ChangeServiceConfig2W  [ADVAPI32.@]
1345  */
1346 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel, 
1347     LPVOID lpInfo)
1348 {
1349     HKEY hKey = ((struct sc_handle*) hService)->u.service.hkey;
1350
1351     if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
1352     {
1353         static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
1354         LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
1355         if (sd->lpDescription)
1356         {
1357             TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
1358             if (sd->lpDescription[0] == 0)
1359                 RegDeleteValueW(hKey,szDescription);
1360             else
1361                 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
1362                                         (LPVOID)sd->lpDescription,
1363                                  sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
1364         }
1365     }
1366     else   
1367         FIXME("STUB: %p %ld %p\n",hService, dwInfoLevel, lpInfo);
1368     return TRUE;
1369 }
1370
1371 /******************************************************************************
1372  * QueryServiceObjectSecurity [ADVAPI32.@]
1373  */
1374 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
1375        SECURITY_INFORMATION dwSecurityInformation,
1376        PSECURITY_DESCRIPTOR lpSecurityDescriptor,
1377        DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1378 {
1379     FIXME("%p %ld %p %lu %p\n", hService, dwSecurityInformation,
1380           lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
1381     return ERROR_CALL_NOT_IMPLEMENTED;
1382 }