OpenServiceW: don't use the requested service access rights for the
[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
47
48 /******************************************************************************
49  * EnumServicesStatusA [ADVAPI32.@]
50  */
51 BOOL WINAPI
52 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
53                      DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
54                      DWORD cbBufSize, LPDWORD pcbBytesNeeded,
55                      LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
56 {       FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
57                 dwServiceType, dwServiceState, lpServices, cbBufSize,
58                 pcbBytesNeeded, lpServicesReturned,  lpResumeHandle);
59         SetLastError (ERROR_ACCESS_DENIED);
60         return FALSE;
61 }
62
63 /******************************************************************************
64  * EnumServicesStatusW [ADVAPI32.@]
65  */
66 BOOL WINAPI
67 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
68                      DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
69                      DWORD cbBufSize, LPDWORD pcbBytesNeeded,
70                      LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
71 {       FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
72                 dwServiceType, dwServiceState, lpServices, cbBufSize,
73                 pcbBytesNeeded, lpServicesReturned,  lpResumeHandle);
74         SetLastError (ERROR_ACCESS_DENIED);
75         return FALSE;
76 }
77
78 /******************************************************************************
79  * StartServiceCtrlDispatcherA [ADVAPI32.@]
80  */
81 BOOL WINAPI
82 StartServiceCtrlDispatcherA( LPSERVICE_TABLE_ENTRYA servent )
83 {
84     LPSERVICE_MAIN_FUNCTIONA fpMain;
85     HANDLE wait;
86     DWORD  dwNumServiceArgs ;
87     LPWSTR *lpArgVecW;
88     LPSTR  *lpArgVecA;
89     int i;
90
91     TRACE("(%p)\n", servent);
92     wait = OpenSemaphoreW(SEMAPHORE_ALL_ACCESS, FALSE, _ServiceStartDataW);
93     if(wait == 0)
94     {
95         ERR("Couldn't find wait semaphore\n");
96         ERR("perhaps you need to start services using StartService\n");
97         return FALSE;
98     }
99
100     dwNumServiceArgs = start_dwNumServiceArgs;
101     lpArgVecW        = start_lpServiceArgVectors;
102
103     ReleaseSemaphore(wait, 1, NULL);
104
105     /* Convert the Unicode arg vectors back to ASCII */
106     if(dwNumServiceArgs)
107         lpArgVecA = (LPSTR*) HeapAlloc( GetProcessHeap(), 0,
108                                    dwNumServiceArgs*sizeof(LPSTR) );
109     else
110         lpArgVecA = NULL;
111
112     for(i=0; i<dwNumServiceArgs; i++)
113         lpArgVecA[i]=HEAP_strdupWtoA(GetProcessHeap(), 0, lpArgVecW[i]);
114
115     /* FIXME: should we blindly start all services? */
116     while (servent->lpServiceName) {
117         TRACE("%s at %p)\n", debugstr_a(servent->lpServiceName),servent);
118         fpMain = servent->lpServiceProc;
119
120         /* try to start the service */
121         fpMain( dwNumServiceArgs, lpArgVecA);
122
123         servent++;
124     }
125
126     if(dwNumServiceArgs)
127     {
128         /* free arg strings */
129         for(i=0; i<dwNumServiceArgs; i++)
130             HeapFree(GetProcessHeap(), 0, lpArgVecA[i]);
131         HeapFree(GetProcessHeap(), 0, lpArgVecA);
132     }
133
134     return TRUE;
135 }
136
137 /******************************************************************************
138  * StartServiceCtrlDispatcherW [ADVAPI32.@]
139  *
140  * PARAMS
141  *   servent []
142  */
143 BOOL WINAPI
144 StartServiceCtrlDispatcherW( LPSERVICE_TABLE_ENTRYW servent )
145 {
146     LPSERVICE_MAIN_FUNCTIONW fpMain;
147     HANDLE wait;
148     DWORD  dwNumServiceArgs ;
149     LPWSTR *lpServiceArgVectors ;
150
151     TRACE("(%p)\n", servent);
152     wait = OpenSemaphoreW(SEMAPHORE_ALL_ACCESS, FALSE, _ServiceStartDataW);
153     if(wait == 0)
154     {
155         ERR("Couldn't find wait semaphore\n");
156         ERR("perhaps you need to start services using StartService\n");
157         return FALSE;
158     }
159
160     dwNumServiceArgs    = start_dwNumServiceArgs;
161     lpServiceArgVectors = start_lpServiceArgVectors;
162
163     ReleaseSemaphore(wait, 1, NULL);
164
165     /* FIXME: should we blindly start all services? */
166     while (servent->lpServiceName) {
167         TRACE("%s at %p)\n", debugstr_w(servent->lpServiceName),servent);
168         fpMain = servent->lpServiceProc;
169
170         /* try to start the service */
171         fpMain( dwNumServiceArgs, lpServiceArgVectors);
172
173         servent++;
174     }
175
176     return TRUE;
177 }
178
179 /******************************************************************************
180  * LockServiceDatabase  [ADVAPI32.@]
181  */
182 LPVOID WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
183 {
184         FIXME("%p\n",hSCManager);
185         return (SC_HANDLE)0xcacacafe;
186 }
187
188 /******************************************************************************
189  * UnlockServiceDatabase  [ADVAPI32.@]
190  */
191 BOOL WINAPI UnlockServiceDatabase (LPVOID ScLock)
192 {
193         FIXME(": %p\n",ScLock);
194         return TRUE;
195 }
196
197 /******************************************************************************
198  * RegisterServiceCtrlHandlerA [ADVAPI32.@]
199  */
200 SERVICE_STATUS_HANDLE WINAPI
201 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName,
202                              LPHANDLER_FUNCTION lpfHandler )
203 {       FIXME("%s %p\n", lpServiceName, lpfHandler);
204         return 0xcacacafe;
205 }
206
207 /******************************************************************************
208  * RegisterServiceCtrlHandlerW [ADVAPI32.@]
209  *
210  * PARAMS
211  *   lpServiceName []
212  *   lpfHandler    []
213  */
214 SERVICE_STATUS_HANDLE WINAPI
215 RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName,
216                              LPHANDLER_FUNCTION lpfHandler )
217 {       FIXME("%s %p\n", debugstr_w(lpServiceName), lpfHandler);
218         return 0xcacacafe;
219 }
220
221 /******************************************************************************
222  * SetServiceStatus [ADVAPI32.@]
223  *
224  * PARAMS
225  *   hService []
226  *   lpStatus []
227  */
228 BOOL WINAPI
229 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
230 {       FIXME("0x%lx %p\n",hService, lpStatus);
231         TRACE("\tType:%lx\n",lpStatus->dwServiceType);
232         TRACE("\tState:%lx\n",lpStatus->dwCurrentState);
233         TRACE("\tControlAccepted:%lx\n",lpStatus->dwControlsAccepted);
234         TRACE("\tExitCode:%lx\n",lpStatus->dwWin32ExitCode);
235         TRACE("\tServiceExitCode:%lx\n",lpStatus->dwServiceSpecificExitCode);
236         TRACE("\tCheckPoint:%lx\n",lpStatus->dwCheckPoint);
237         TRACE("\tWaitHint:%lx\n",lpStatus->dwWaitHint);
238         return TRUE;
239 }
240
241 /******************************************************************************
242  * OpenSCManagerA [ADVAPI32.@]
243  */
244 SC_HANDLE WINAPI
245 OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
246                   DWORD dwDesiredAccess )
247 {
248     UNICODE_STRING lpMachineNameW;
249     UNICODE_STRING lpDatabaseNameW;
250     SC_HANDLE ret;
251
252     RtlCreateUnicodeStringFromAsciiz (&lpMachineNameW,lpMachineName);
253     RtlCreateUnicodeStringFromAsciiz (&lpDatabaseNameW,lpDatabaseName);
254     ret = OpenSCManagerW(lpMachineNameW.Buffer,lpDatabaseNameW.Buffer, dwDesiredAccess);
255     RtlFreeUnicodeString(&lpDatabaseNameW);
256     RtlFreeUnicodeString(&lpMachineNameW);
257     return ret;
258 }
259
260 /******************************************************************************
261  * OpenSCManagerW [ADVAPI32.@]
262  * Establishes a connection to the service control manager and opens database
263  *
264  * NOTES
265  *   This should return a SC_HANDLE
266  *
267  * PARAMS
268  *   lpMachineName   [I] Pointer to machine name string
269  *   lpDatabaseName  [I] Pointer to database name string
270  *   dwDesiredAccess [I] Type of access
271  *
272  * RETURNS
273  *   Success: Handle to service control manager database
274  *   Failure: NULL
275  */
276 SC_HANDLE WINAPI
277 OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
278                   DWORD dwDesiredAccess )
279 {
280     HKEY hReg, hKey = NULL;
281     LONG r;
282
283     TRACE("(%s,%s,0x%08lx)\n", debugstr_w(lpMachineName),
284           debugstr_w(lpDatabaseName), dwDesiredAccess);
285
286     /*
287      * FIXME: what is lpDatabaseName?
288      * It should be set to "SERVICES_ACTIVE_DATABASE" according to
289      * docs, but what if it isn't?
290      */
291
292     r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
293     if (r==ERROR_SUCCESS)
294     {
295         r = RegOpenKeyExW(hReg, szServiceManagerKey,0, dwDesiredAccess, &hKey );
296         RegCloseKey( hReg );
297     }
298
299     TRACE("returning %p\n", hKey);
300
301     return hKey;
302 }
303
304
305 /******************************************************************************
306  * AllocateLocallyUniqueId [ADVAPI32.@]
307  *
308  * PARAMS
309  *   lpluid []
310  */
311 BOOL WINAPI
312 AllocateLocallyUniqueId( PLUID lpluid )
313 {
314         lpluid->LowPart = time(NULL);
315         lpluid->HighPart = 0;
316         return TRUE;
317 }
318
319
320 /******************************************************************************
321  * ControlService [ADVAPI32.@]
322  * Sends a control code to a Win32-based service.
323  *
324  * PARAMS
325  *   hService        []
326  *   dwControl       []
327  *   lpServiceStatus []
328  *
329  * RETURNS STD
330  */
331 BOOL WINAPI
332 ControlService( SC_HANDLE hService, DWORD dwControl,
333                 LPSERVICE_STATUS lpServiceStatus )
334 {
335     FIXME("(%p,%ld,%p): stub\n",hService,dwControl,lpServiceStatus);
336     return TRUE;
337 }
338
339
340 /******************************************************************************
341  * CloseServiceHandle [ADVAPI32.@]
342  * Close handle to service or service control manager
343  *
344  * PARAMS
345  *   hSCObject [I] Handle to service or service control manager database
346  *
347  * RETURNS STD
348  */
349 BOOL WINAPI
350 CloseServiceHandle( SC_HANDLE hSCObject )
351 {
352     TRACE("(%p)\n", hSCObject);
353
354     RegCloseKey(hSCObject);
355
356     return TRUE;
357 }
358
359
360 /******************************************************************************
361  * OpenServiceA [ADVAPI32.@]
362  */
363 SC_HANDLE WINAPI
364 OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
365                 DWORD dwDesiredAccess )
366 {
367     UNICODE_STRING lpServiceNameW;
368     SC_HANDLE ret;
369     RtlCreateUnicodeStringFromAsciiz (&lpServiceNameW,lpServiceName);
370     if(lpServiceName)
371         TRACE("Request for service %s\n",lpServiceName);
372     else
373         return FALSE;
374     ret = OpenServiceW( hSCManager, lpServiceNameW.Buffer, dwDesiredAccess);
375     RtlFreeUnicodeString(&lpServiceNameW);
376     return ret;
377 }
378
379
380 /******************************************************************************
381  * OpenServiceW [ADVAPI32.@]
382  * Opens a handle to an existing service
383  *
384  * PARAMS
385  *   hSCManager      []
386  *   lpServiceName   []
387  *   dwDesiredAccess []
388  *
389  * RETURNS
390  *    Success: Handle to the service
391  *    Failure: NULL
392  */
393 SC_HANDLE WINAPI
394 OpenServiceW(SC_HANDLE hSCManager, LPCWSTR lpServiceName,
395                DWORD dwDesiredAccess)
396 {
397     HKEY hKey;
398     long r;
399
400     TRACE("(%p,%p,%ld)\n",hSCManager, lpServiceName,
401           dwDesiredAccess);
402
403     r = RegOpenKeyExW(hSCManager, lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
404     if (r!=ERROR_SUCCESS)
405         return 0;
406
407     TRACE("returning %p\n",hKey);
408
409     return hKey;
410 }
411
412 /******************************************************************************
413  * CreateServiceW [ADVAPI32.@]
414  */
415 SC_HANDLE WINAPI
416 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
417                   LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
418                   DWORD dwServiceType, DWORD dwStartType,
419                   DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
420                   LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
421                   LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
422                   LPCWSTR lpPassword )
423 {
424     HKEY hKey;
425     LONG r;
426     DWORD dp;
427     const WCHAR szDisplayName[] = { 'D','i','s','p','l','a','y','N','a','m','e', 0 };
428     const WCHAR szType[] = {'T','y','p','e',0};
429     const WCHAR szStart[] = {'S','t','a','r','t',0};
430     const WCHAR szError[] = {'E','r','r','o','r','C','o','n','t','r','o','l', 0};
431     const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
432     const WCHAR szGroup[] = {'G','r','o','u','p',0};
433     const WCHAR szDependencies[] = { 'D','e','p','e','n','d','e','n','c','i','e','s',0};
434
435     FIXME("%p %s %s\n", hSCManager, 
436           debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
437
438     r = RegCreateKeyExW(hSCManager, lpServiceName, 0, NULL,
439                        REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
440     if (r!=ERROR_SUCCESS)
441         return 0;
442
443     if (dp != REG_CREATED_NEW_KEY)
444         return 0;
445
446     if(lpDisplayName)
447     {
448         r = RegSetValueExW(hKey, szDisplayName, 0, REG_SZ, (LPBYTE)lpDisplayName,
449                            (strlenW(lpDisplayName)+1)*sizeof(WCHAR) );
450         if (r!=ERROR_SUCCESS)
451             return 0;
452     }
453
454     r = RegSetValueExW(hKey, szType, 0, REG_DWORD, (LPVOID)&dwServiceType, sizeof (DWORD) );
455     if (r!=ERROR_SUCCESS)
456         return 0;
457
458     r = RegSetValueExW(hKey, szStart, 0, REG_DWORD, (LPVOID)&dwStartType, sizeof (DWORD) );
459     if (r!=ERROR_SUCCESS)
460         return 0;
461
462     r = RegSetValueExW(hKey, szError, 0, REG_DWORD,
463                            (LPVOID)&dwErrorControl, sizeof (DWORD) );
464     if (r!=ERROR_SUCCESS)
465         return 0;
466
467     if(lpBinaryPathName)
468     {
469         r = RegSetValueExW(hKey, szImagePath, 0, REG_SZ, (LPBYTE)lpBinaryPathName,
470                            (strlenW(lpBinaryPathName)+1)*sizeof(WCHAR) );
471         if (r!=ERROR_SUCCESS)
472             return 0;
473     }
474
475     if(lpLoadOrderGroup)
476     {
477         r = RegSetValueExW(hKey, szGroup, 0, REG_SZ, (LPBYTE)lpLoadOrderGroup,
478                            (strlenW(lpLoadOrderGroup)+1)*sizeof(WCHAR) );
479         if (r!=ERROR_SUCCESS)
480             return 0;
481     }
482
483     if(lpDependencies)
484     {
485         DWORD len = 0;
486
487         /* determine the length of a double null terminated multi string */
488         do {
489             len += (strlenW(&lpDependencies[len])+1);
490         } while (lpDependencies[len++]);
491
492         r = RegSetValueExW(hKey, szDependencies, 0, REG_MULTI_SZ,
493                            (LPBYTE)lpDependencies, len );
494         if (r!=ERROR_SUCCESS)
495             return 0;
496     }
497
498     if(lpPassword)
499     {
500         FIXME("Don't know how to add a Password for a service.\n");
501     }
502
503     if(lpServiceStartName)
504     {
505         FIXME("Don't know how to add a ServiceStartName for a service.\n");
506     }
507
508     return hKey;
509 }
510
511
512 static inline LPWSTR SERV_dup( LPCSTR str )
513 {
514     UINT len;
515     LPWSTR wstr;
516
517     if( !str )
518         return NULL;
519     len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
520     wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
521     MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
522     return wstr;
523 }
524
525 static inline LPWSTR SERV_dupmulti( LPCSTR str )
526 {
527     UINT len = 0, n = 0;
528     LPWSTR wstr;
529
530     if( !str )
531         return NULL;
532     do {
533         len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
534         n += (strlen( &str[n] ) + 1);
535     } while (str[n]);
536     len++;
537     n++;
538     
539     wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
540     MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
541     return wstr;
542 }
543
544 static inline VOID SERV_free( LPWSTR wstr )
545 {
546     HeapFree( GetProcessHeap(), 0, wstr );
547 }
548
549 /******************************************************************************
550  * CreateServiceA [ADVAPI32.@]
551  */
552 SC_HANDLE WINAPI
553 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
554                   LPCSTR lpDisplayName, DWORD dwDesiredAccess,
555                   DWORD dwServiceType, DWORD dwStartType,
556                   DWORD dwErrorControl, LPCSTR lpBinaryPathName,
557                   LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
558                   LPCSTR lpDependencies, LPCSTR lpServiceStartName,
559                   LPCSTR lpPassword )
560 {
561     LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
562         lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
563     SC_HANDLE r;
564
565     TRACE("%p %s %s\n", hSCManager,
566           debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
567
568     lpServiceNameW = SERV_dup( lpServiceName );
569     lpDisplayNameW = SERV_dup( lpDisplayName );
570     lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
571     lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
572     lpDependenciesW = SERV_dupmulti( lpDependencies );
573     lpServiceStartNameW = SERV_dup( lpServiceStartName );
574     lpPasswordW = SERV_dup( lpPassword );
575
576     r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
577             dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
578             lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
579             lpDependenciesW, lpServiceStartNameW, lpPasswordW );
580
581     SERV_free( lpServiceNameW );
582     SERV_free( lpDisplayNameW );
583     SERV_free( lpBinaryPathNameW );
584     SERV_free( lpLoadOrderGroupW );
585     SERV_free( lpDependenciesW );
586     SERV_free( lpServiceStartNameW );
587     SERV_free( lpPasswordW );
588
589     return r;
590 }
591
592
593 /******************************************************************************
594  * DeleteService [ADVAPI32.@]
595  *
596  * PARAMS
597  *    hService [I] Handle to service
598  *
599  * RETURNS STD
600  *
601  */
602 BOOL WINAPI
603 DeleteService( SC_HANDLE hService )
604 {
605     WCHAR valname[MAX_PATH+1];
606     INT index = 0;
607     LONG rc;
608     DWORD value = 0x1;
609     DWORD size;
610     HKEY hKey;
611
612     static const WCHAR szDeleted[] = {'D','e','l','e','t','e','d',0};
613
614     FIXME("(%p): stub\n",hService);
615    
616     size = MAX_PATH+1; 
617     /* Clean out the values */
618     rc = RegEnumValueW(hService, index, valname,&size,0,0,0,0);
619     while (rc == ERROR_SUCCESS)
620     {
621         RegDeleteValueW(hService,valname);
622         index++;
623         size = MAX_PATH+1; 
624         rc = RegEnumValueW(hService, index, valname, &size,0,0,0,0);
625     }
626
627     /* tag for deletion */
628     RegSetValueExW(hService, szDeleted, 0, REG_DWORD, (LPVOID)&value, 
629                     sizeof (DWORD) );
630
631     RegCloseKey(hService);
632
633     /* find and delete the key */
634     rc = RegOpenKeyExW(HKEY_LOCAL_MACHINE, szServiceManagerKey,0,
635                         KEY_ALL_ACCESS, &hKey );
636     index = 0;
637     size = MAX_PATH+1; 
638     rc = RegEnumKeyExW(hKey,0, valname, &size, 0, 0, 0, 0);
639     while (rc == ERROR_SUCCESS)
640     {
641         HKEY checking;
642         rc = RegOpenKeyExW(hKey,valname,0,KEY_ALL_ACCESS,&checking);
643         if (rc == ERROR_SUCCESS)
644         {
645             DWORD deleted = 0;
646             DWORD size = sizeof(DWORD);
647             rc = RegQueryValueExW(checking, szDeleted , NULL, NULL,
648                                   (LPVOID)&deleted, &size);
649             if (deleted)
650             {
651                 RegDeleteValueW(checking,szDeleted);
652                 RegDeleteKeyW(hKey,valname);
653             }
654             else
655                 index ++;
656             RegCloseKey(checking);
657         }
658         size = MAX_PATH+1; 
659         rc = RegEnumKeyExW(hKey, index, valname, &size, 0, 0, 0, 0);
660     }
661     RegCloseKey(hKey);
662
663     return TRUE;
664 }
665
666
667 /******************************************************************************
668  * StartServiceA [ADVAPI32.@]
669  *
670  */
671 BOOL WINAPI
672 StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
673                  LPCSTR *lpServiceArgVectors )
674 {
675     LPWSTR *lpwstr=NULL;
676     UNICODE_STRING usBuffer;
677     int i;
678
679     TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
680
681     if(dwNumServiceArgs)
682         lpwstr = (LPWSTR*) HeapAlloc( GetProcessHeap(), 0,
683                                    dwNumServiceArgs*sizeof(LPWSTR) );
684     else
685         lpwstr = NULL;
686
687     for(i=0; i<dwNumServiceArgs; i++)
688     {
689         RtlCreateUnicodeStringFromAsciiz (&usBuffer,lpServiceArgVectors[i]);
690         lpwstr[i]=usBuffer.Buffer;
691     }
692
693     StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
694
695     if(dwNumServiceArgs)
696     {
697         for(i=0; i<dwNumServiceArgs; i++)
698             HeapFree(GetProcessHeap(), 0, lpwstr[i]);
699         HeapFree(GetProcessHeap(), 0, lpwstr);
700     }
701
702     return TRUE;
703 }
704
705
706 /******************************************************************************
707  * StartServiceW [ADVAPI32.@]
708  * Starts a service
709  *
710  * PARAMS
711  *   hService            [I] Handle of service
712  *   dwNumServiceArgs    [I] Number of arguments
713  *   lpServiceArgVectors [I] Address of array of argument string pointers
714  *
715  * NOTES
716  *
717  * NT implements this function using an obscure RPC call...
718  *
719  * Might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
720  *   to get things like %SystemRoot%\\System32\\service.exe to load.
721  *
722  * Will only work for shared address space. How should the service
723  *  args be transferred when address spaces are separated?
724  *
725  * Can only start one service at a time.
726  *
727  * Has no concept of privilege.
728  *
729  * RETURNS STD
730  *
731  */
732 BOOL WINAPI
733 StartServiceW( SC_HANDLE hService, DWORD dwNumServiceArgs,
734                  LPCWSTR *lpServiceArgVectors )
735 {
736     static const WCHAR  _WaitServiceStartW[]  = {'A','D','V','A','P','I','_','W',
737                                                 'a','i','t','S','e','r','v','i',
738                                                 'c','e','S','t','a','r','t',0};
739     static const WCHAR  _ImagePathW[]  = {'I','m','a','g','e','P','a','t','h',0};
740                                                 
741     WCHAR path[MAX_PATH],str[MAX_PATH];
742     DWORD type,size;
743     long r;
744     HANDLE data,wait;
745     PROCESS_INFORMATION procinfo;
746     STARTUPINFOW startupinfo;
747     TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,
748           lpServiceArgVectors);
749
750     size = sizeof(str);
751     r = RegQueryValueExW(hService, _ImagePathW, NULL, &type, (LPVOID)str, &size);
752     if (r!=ERROR_SUCCESS)
753         return FALSE;
754     ExpandEnvironmentStringsW(str,path,sizeof(path));
755
756     TRACE("Starting service %s\n", debugstr_w(path) );
757
758     data = CreateSemaphoreW(NULL,1,1,_ServiceStartDataW);
759     if (!data)
760     {
761         ERR("Couldn't create data semaphore\n");
762         return FALSE;
763     }
764     wait = CreateSemaphoreW(NULL,0,1,_WaitServiceStartW);
765     if (!wait)
766     {
767         ERR("Couldn't create wait semaphore\n");
768         return FALSE;
769     }
770
771     /*
772      * FIXME: lpServiceArgsVectors need to be stored and returned to
773      *        the service when it calls StartServiceCtrlDispatcher
774      *
775      * Chuck these in a global (yuk) so we can pass them to
776      * another process - address space separation will break this.
777      */
778
779     r = WaitForSingleObject(data,INFINITE);
780
781     if( r == WAIT_FAILED)
782         return FALSE;
783
784     FIXME("problematic because of address space separation.\n");
785     start_dwNumServiceArgs    = dwNumServiceArgs;
786     start_lpServiceArgVectors = (LPWSTR *)lpServiceArgVectors;
787
788     ZeroMemory(&startupinfo,sizeof(STARTUPINFOW));
789     startupinfo.cb = sizeof(STARTUPINFOW);
790
791     r = CreateProcessW(path,
792                    NULL,
793                    NULL,  /* process security attribs */
794                    NULL,  /* thread security attribs */
795                    FALSE, /* inherit handles */
796                    0,     /* creation flags */
797                    NULL,  /* environment */
798                    NULL,  /* current directory */
799                    &startupinfo,  /* startup info */
800                    &procinfo); /* process info */
801
802     if(r == FALSE)
803     {
804         ERR("Couldn't start process\n");
805         /* ReleaseSemaphore(data, 1, NULL);
806         return FALSE; */
807     }
808
809     /* docs for StartServiceCtrlDispatcher say this should be 30 sec */
810     r = WaitForSingleObject(wait,30000);
811
812     ReleaseSemaphore(data, 1, NULL);
813
814     if( r == WAIT_FAILED)
815         return FALSE;
816
817     return TRUE;
818 }
819
820 /******************************************************************************
821  * QueryServiceStatus [ADVAPI32.@]
822  *
823  * PARAMS
824  *   hService        []
825  *   lpservicestatus []
826  *
827  */
828 BOOL WINAPI
829 QueryServiceStatus( SC_HANDLE hService, LPSERVICE_STATUS lpservicestatus )
830 {
831     LONG r;
832     DWORD type, val, size;
833
834     FIXME("(%p,%p) partial\n",hService,lpservicestatus);
835
836     /* read the service type from the registry */
837     size = sizeof(val);
838     r = RegQueryValueExA(hService, "Type", NULL, &type, (LPBYTE)&val, &size);
839     if(type!=REG_DWORD)
840     {
841         ERR("invalid Type\n");
842         return FALSE;
843     }
844     lpservicestatus->dwServiceType = val;
845     /* FIXME: how are these determined or read from the registry? */
846     /* SERVICE: unavailable=0, stopped=1, starting=2, running=3? */;
847     lpservicestatus->dwCurrentState            = 1;
848     lpservicestatus->dwControlsAccepted        = 0;
849     lpservicestatus->dwWin32ExitCode           = NO_ERROR;
850     lpservicestatus->dwServiceSpecificExitCode = 0;
851     lpservicestatus->dwCheckPoint              = 0;
852     lpservicestatus->dwWaitHint                = 0;
853
854     return TRUE;
855 }
856
857 /******************************************************************************
858  * QueryServiceStatusEx [ADVAPI32.@]
859  *
860  * PARAMS
861  *   hService       [handle to service]
862  *   InfoLevel      [information level]
863  *   lpBuffer       [buffer]
864  *   cbBufSize      [size of buffer]
865  *   pcbBytesNeeded [bytes needed]
866 */
867 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
868                         LPBYTE lpBuffer, DWORD cbBufSize,
869                         LPDWORD pcbBytesNeeded)
870 {
871     FIXME("stub\n");
872     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
873     return FALSE;
874 }
875
876 /******************************************************************************
877  * QueryServiceConfigA [ADVAPI32.@]
878  */
879 BOOL WINAPI 
880 QueryServiceConfigA( SC_HANDLE hService,
881                      LPQUERY_SERVICE_CONFIGA lpServiceConfig,
882                      DWORD cbBufSize, LPDWORD pcbBytesNeeded)
883 {
884     FIXME("%p %p %ld %p\n", hService, lpServiceConfig,
885            cbBufSize, pcbBytesNeeded);
886     return FALSE;
887 }
888
889 /******************************************************************************
890  * QueryServiceConfigW [ADVAPI32.@]
891  */
892 BOOL WINAPI 
893 QueryServiceConfigW( SC_HANDLE hService,
894                      LPQUERY_SERVICE_CONFIGW lpServiceConfig,
895                      DWORD cbBufSize, LPDWORD pcbBytesNeeded)
896 {
897     const WCHAR szDisplayName[] = {
898         'D','i','s','p','l','a','y','N','a','m','e', 0 };
899     const WCHAR szType[] = {'T','y','p','e',0};
900     const WCHAR szStart[] = {'S','t','a','r','t',0};
901     const WCHAR szError[] = {
902         'E','r','r','o','r','C','o','n','t','r','o','l', 0};
903     const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
904     const WCHAR szGroup[] = {'G','r','o','u','p',0};
905     const WCHAR szDependencies[] = { 
906         'D','e','p','e','n','d','e','n','c','i','e','s',0};
907     LONG r;
908     DWORD type, val, sz, total, n;
909     LPBYTE p;
910
911     TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
912            cbBufSize, pcbBytesNeeded);
913
914     /* calculate the size required first */
915     total = sizeof (QUERY_SERVICE_CONFIGW);
916
917     sz = 0;
918     r = RegQueryValueExW( hService, szImagePath, 0, &type, NULL, &sz );
919     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
920         total += sz;
921
922     sz = 0;
923     r = RegQueryValueExW( hService, szGroup, 0, &type, NULL, &sz );
924     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
925         total += sz;
926
927     sz = 0;
928     r = RegQueryValueExW( hService, szDependencies, 0, &type, NULL, &sz );
929     if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
930         total += sz;
931
932     sz = 0;
933     r = RegQueryValueExW( hService, szStart, 0, &type, NULL, &sz );
934     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
935         total += sz;
936
937     sz = 0;
938     r = RegQueryValueExW( hService, szDisplayName, 0, &type, NULL, &sz );
939     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
940         total += sz;
941
942     /* if there's not enough memory, return an error */
943     if( total > *pcbBytesNeeded )
944     {
945         *pcbBytesNeeded = total;
946         SetLastError( ERROR_INSUFFICIENT_BUFFER );
947         return FALSE;
948     }
949
950     *pcbBytesNeeded = total;
951     ZeroMemory( lpServiceConfig, total );
952
953     sz = sizeof val;
954     r = RegQueryValueExW( hService, szType, 0, &type, (LPBYTE)&val, &sz );
955     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
956         lpServiceConfig->dwServiceType = val;
957
958     sz = sizeof val;
959     r = RegQueryValueExW( hService, szStart, 0, &type, (LPBYTE)&val, &sz );
960     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
961         lpServiceConfig->dwStartType = val;
962
963     sz = sizeof val;
964     r = RegQueryValueExW( hService, szError, 0, &type, (LPBYTE)&val, &sz );
965     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
966         lpServiceConfig->dwErrorControl = val;
967
968     /* now do the strings */
969     p = (LPBYTE) &lpServiceConfig[1];
970     n = total - sizeof (QUERY_SERVICE_CONFIGW);
971
972     sz = n;
973     r = RegQueryValueExW( hService, szImagePath, 0, &type, p, &sz );
974     if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
975     {
976         lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
977         p += sz;
978         n -= sz;
979     }
980
981     sz = n;
982     r = RegQueryValueExW( hService, szGroup, 0, &type, p, &sz );
983     if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
984     {
985         lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
986         p += sz;
987         n -= sz;
988     }
989
990     sz = n;
991     r = RegQueryValueExW( hService, szDependencies, 0, &type, p, &sz );
992     if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
993     {
994         lpServiceConfig->lpDependencies = (LPWSTR) p;
995         p += sz;
996         n -= sz;
997     }
998
999     if( n < 0 )
1000         ERR("Buffer overflow!\n");
1001
1002     TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1003     TRACE("Group      = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1004
1005     return TRUE;
1006 }
1007
1008 /******************************************************************************
1009  * ChangeServiceConfigW  [ADVAPI32.@]
1010  */
1011 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
1012   DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1013   LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
1014   LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
1015 {
1016     FIXME("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
1017           hService, dwServiceType, dwStartType, dwErrorControl, 
1018           debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
1019           lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
1020           debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
1021     return TRUE;
1022 }
1023
1024 /******************************************************************************
1025  * ChangeServiceConfigA  [ADVAPI32.@]
1026  */
1027 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
1028   DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1029   LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
1030   LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
1031 {
1032     FIXME("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
1033           hService, dwServiceType, dwStartType, dwErrorControl, 
1034           debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
1035           lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
1036           debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
1037     return TRUE;
1038 }
1039
1040 /******************************************************************************
1041  * ChangeServiceConfig2A  [ADVAPI32.@]
1042  */
1043 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel, 
1044     LPVOID lpInfo)
1045 {
1046     FIXME("STUB: %p %ld %p\n",hService, dwInfoLevel, lpInfo);
1047     return TRUE;
1048 }
1049
1050 /******************************************************************************
1051  * ChangeServiceConfig2W  [ADVAPI32.@]
1052  */
1053 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel, 
1054     LPVOID lpInfo)
1055 {
1056     if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
1057     {
1058         static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
1059         LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
1060         if (sd->lpDescription)
1061         {
1062             TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
1063             if (sd->lpDescription[0] == 0)
1064                 RegDeleteValueW(hService,szDescription);
1065             else
1066                 RegSetValueExW(hService, szDescription, 0, REG_SZ,
1067                                         (LPVOID)sd->lpDescription,
1068                                  sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
1069         }
1070     }
1071     else   
1072         FIXME("STUB: %p %ld %p\n",hService, dwInfoLevel, lpInfo);
1073     return TRUE;
1074 }