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