Fix subclassing to support nested messages.
[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     /* FIXME: dwDesiredAccess may need some processing */
404     r = RegOpenKeyExW(hSCManager, lpServiceName, 0, dwDesiredAccess, &hKey );
405     if (r!=ERROR_SUCCESS)
406         return 0;
407
408     TRACE("returning %p\n",hKey);
409
410     return hKey;
411 }
412
413 /******************************************************************************
414  * CreateServiceW [ADVAPI32.@]
415  */
416 SC_HANDLE WINAPI
417 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
418                   LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
419                   DWORD dwServiceType, DWORD dwStartType,
420                   DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
421                   LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
422                   LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
423                   LPCWSTR lpPassword )
424 {
425     HKEY hKey;
426     LONG r;
427     DWORD dp;
428     const WCHAR szDisplayName[] = { 'D','i','s','p','l','a','y','N','a','m','e', 0 };
429     const WCHAR szType[] = {'T','y','p','e',0};
430     const WCHAR szStart[] = {'S','t','a','r','t',0};
431     const WCHAR szError[] = {'E','r','r','o','r','C','o','n','t','r','o','l', 0};
432     const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
433     const WCHAR szGroup[] = {'G','r','o','u','p',0};
434     const WCHAR szDependencies[] = { 'D','e','p','e','n','d','e','n','c','i','e','s',0};
435
436     FIXME("%p %s %s\n", hSCManager, 
437           debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
438
439     r = RegCreateKeyExW(hSCManager, lpServiceName, 0, NULL,
440                        REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
441     if (r!=ERROR_SUCCESS)
442         return 0;
443
444     if (dp != REG_CREATED_NEW_KEY)
445         return 0;
446
447     if(lpDisplayName)
448     {
449         r = RegSetValueExW(hKey, szDisplayName, 0, REG_SZ, (LPBYTE)lpDisplayName,
450                            (strlenW(lpDisplayName)+1)*sizeof(WCHAR) );
451         if (r!=ERROR_SUCCESS)
452             return 0;
453     }
454
455     r = RegSetValueExW(hKey, szType, 0, REG_DWORD, (LPVOID)&dwServiceType, sizeof (DWORD) );
456     if (r!=ERROR_SUCCESS)
457         return 0;
458
459     r = RegSetValueExW(hKey, szStart, 0, REG_DWORD, (LPVOID)&dwStartType, sizeof (DWORD) );
460     if (r!=ERROR_SUCCESS)
461         return 0;
462
463     r = RegSetValueExW(hKey, szError, 0, REG_DWORD,
464                            (LPVOID)&dwErrorControl, sizeof (DWORD) );
465     if (r!=ERROR_SUCCESS)
466         return 0;
467
468     if(lpBinaryPathName)
469     {
470         r = RegSetValueExW(hKey, szImagePath, 0, REG_SZ, (LPBYTE)lpBinaryPathName,
471                            (strlenW(lpBinaryPathName)+1)*sizeof(WCHAR) );
472         if (r!=ERROR_SUCCESS)
473             return 0;
474     }
475
476     if(lpLoadOrderGroup)
477     {
478         r = RegSetValueExW(hKey, szGroup, 0, REG_SZ, (LPBYTE)lpLoadOrderGroup,
479                            (strlenW(lpLoadOrderGroup)+1)*sizeof(WCHAR) );
480         if (r!=ERROR_SUCCESS)
481             return 0;
482     }
483
484     if(lpDependencies)
485     {
486         DWORD len = 0;
487
488         /* determine the length of a double null terminated multi string */
489         do {
490             len += (strlenW(&lpDependencies[len])+1);
491         } while (lpDependencies[len++]);
492
493         r = RegSetValueExW(hKey, szDependencies, 0, REG_MULTI_SZ,
494                            (LPBYTE)lpDependencies, len );
495         if (r!=ERROR_SUCCESS)
496             return 0;
497     }
498
499     if(lpPassword)
500     {
501         FIXME("Don't know how to add a Password for a service.\n");
502     }
503
504     if(lpServiceStartName)
505     {
506         FIXME("Don't know how to add a ServiceStartName for a service.\n");
507     }
508
509     return hKey;
510 }
511
512
513 static inline LPWSTR SERV_dup( LPCSTR str )
514 {
515     UINT len;
516     LPWSTR wstr;
517
518     if( !str )
519         return NULL;
520     len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
521     wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
522     MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
523     return wstr;
524 }
525
526 static inline LPWSTR SERV_dupmulti( LPCSTR str )
527 {
528     UINT len = 0, n = 0;
529     LPWSTR wstr;
530
531     if( !str )
532         return NULL;
533     do {
534         len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
535         n += (strlen( &str[n] ) + 1);
536     } while (str[n]);
537     len++;
538     n++;
539     
540     wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
541     MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
542     return wstr;
543 }
544
545 static inline VOID SERV_free( LPWSTR wstr )
546 {
547     HeapFree( GetProcessHeap(), 0, wstr );
548 }
549
550 /******************************************************************************
551  * CreateServiceA [ADVAPI32.@]
552  */
553 SC_HANDLE WINAPI
554 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
555                   LPCSTR lpDisplayName, DWORD dwDesiredAccess,
556                   DWORD dwServiceType, DWORD dwStartType,
557                   DWORD dwErrorControl, LPCSTR lpBinaryPathName,
558                   LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
559                   LPCSTR lpDependencies, LPCSTR lpServiceStartName,
560                   LPCSTR lpPassword )
561 {
562     LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
563         lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
564     SC_HANDLE r;
565
566     TRACE("%p %s %s\n", hSCManager,
567           debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
568
569     lpServiceNameW = SERV_dup( lpServiceName );
570     lpDisplayNameW = SERV_dup( lpDisplayName );
571     lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
572     lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
573     lpDependenciesW = SERV_dupmulti( lpDependencies );
574     lpServiceStartNameW = SERV_dup( lpServiceStartName );
575     lpPasswordW = SERV_dup( lpPassword );
576
577     r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
578             dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
579             lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
580             lpDependenciesW, lpServiceStartNameW, lpPasswordW );
581
582     SERV_free( lpServiceNameW );
583     SERV_free( lpDisplayNameW );
584     SERV_free( lpBinaryPathNameW );
585     SERV_free( lpLoadOrderGroupW );
586     SERV_free( lpDependenciesW );
587     SERV_free( lpServiceStartNameW );
588     SERV_free( lpPasswordW );
589
590     return r;
591 }
592
593
594 /******************************************************************************
595  * DeleteService [ADVAPI32.@]
596  *
597  * PARAMS
598  *    hService [I] Handle to service
599  *
600  * RETURNS STD
601  *
602  */
603 BOOL WINAPI
604 DeleteService( SC_HANDLE hService )
605 {
606     WCHAR valname[MAX_PATH+1];
607     INT index = 0;
608     LONG rc;
609     DWORD value = 0x1;
610     DWORD size;
611     HKEY hKey;
612
613     static const WCHAR szDeleted[] = {'D','e','l','e','t','e','d',0};
614
615     FIXME("(%p): stub\n",hService);
616    
617     size = MAX_PATH+1; 
618     /* Clean out the values */
619     rc = RegEnumValueW(hService, index, valname,&size,0,0,0,0);
620     while (rc == ERROR_SUCCESS)
621     {
622         RegDeleteValueW(hService,valname);
623         index++;
624         size = MAX_PATH+1; 
625         rc = RegEnumValueW(hService, index, valname, &size,0,0,0,0);
626     }
627
628     /* tag for deletion */
629     RegSetValueExW(hService, szDeleted, 0, REG_DWORD, (LPVOID)&value, 
630                     sizeof (DWORD) );
631
632     RegCloseKey(hService);
633
634     /* find and delete the key */
635     rc = RegOpenKeyExW(HKEY_LOCAL_MACHINE, szServiceManagerKey,0,
636                         KEY_ALL_ACCESS, &hKey );
637     index = 0;
638     size = MAX_PATH+1; 
639     rc = RegEnumKeyExW(hKey,0, valname, &size, 0, 0, 0, 0);
640     while (rc == ERROR_SUCCESS)
641     {
642         HKEY checking;
643         rc = RegOpenKeyExW(hKey,valname,0,KEY_ALL_ACCESS,&checking);
644         if (rc == ERROR_SUCCESS)
645         {
646             DWORD deleted = 0;
647             DWORD size = sizeof(DWORD);
648             rc = RegQueryValueExW(checking, szDeleted , NULL, NULL,
649                                   (LPVOID)&deleted, &size);
650             if (deleted)
651             {
652                 RegDeleteValueW(checking,szDeleted);
653                 RegDeleteKeyW(hKey,valname);
654             }
655             else
656                 index ++;
657             RegCloseKey(checking);
658         }
659         size = MAX_PATH+1; 
660         rc = RegEnumKeyExW(hKey, index, valname, &size, 0, 0, 0, 0);
661     }
662     RegCloseKey(hKey);
663
664     return TRUE;
665 }
666
667
668 /******************************************************************************
669  * StartServiceA [ADVAPI32.@]
670  *
671  */
672 BOOL WINAPI
673 StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
674                  LPCSTR *lpServiceArgVectors )
675 {
676     LPWSTR *lpwstr=NULL;
677     UNICODE_STRING usBuffer;
678     int i;
679
680     TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
681
682     if(dwNumServiceArgs)
683         lpwstr = (LPWSTR*) HeapAlloc( GetProcessHeap(), 0,
684                                    dwNumServiceArgs*sizeof(LPWSTR) );
685     else
686         lpwstr = NULL;
687
688     for(i=0; i<dwNumServiceArgs; i++)
689     {
690         RtlCreateUnicodeStringFromAsciiz (&usBuffer,lpServiceArgVectors[i]);
691         lpwstr[i]=usBuffer.Buffer;
692     }
693
694     StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
695
696     if(dwNumServiceArgs)
697     {
698         for(i=0; i<dwNumServiceArgs; i++)
699             HeapFree(GetProcessHeap(), 0, lpwstr[i]);
700         HeapFree(GetProcessHeap(), 0, lpwstr);
701     }
702
703     return TRUE;
704 }
705
706
707 /******************************************************************************
708  * StartServiceW [ADVAPI32.@]
709  * Starts a service
710  *
711  * PARAMS
712  *   hService            [I] Handle of service
713  *   dwNumServiceArgs    [I] Number of arguments
714  *   lpServiceArgVectors [I] Address of array of argument string pointers
715  *
716  * NOTES
717  *
718  * NT implements this function using an obscure RPC call...
719  *
720  * Might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
721  *   to get things like %SystemRoot%\\System32\\service.exe to load.
722  *
723  * Will only work for shared address space. How should the service
724  *  args be transferred when address spaces are separated?
725  *
726  * Can only start one service at a time.
727  *
728  * Has no concept of privilege.
729  *
730  * RETURNS STD
731  *
732  */
733 BOOL WINAPI
734 StartServiceW( SC_HANDLE hService, DWORD dwNumServiceArgs,
735                  LPCWSTR *lpServiceArgVectors )
736 {
737     static const WCHAR  _WaitServiceStartW[]  = {'A','D','V','A','P','I','_','W',
738                                                 'a','i','t','S','e','r','v','i',
739                                                 'c','e','S','t','a','r','t',0};
740     static const WCHAR  _ImagePathW[]  = {'I','m','a','g','e','P','a','t','h',0};
741                                                 
742     WCHAR path[MAX_PATH],str[MAX_PATH];
743     DWORD type,size;
744     long r;
745     HANDLE data,wait;
746     PROCESS_INFORMATION procinfo;
747     STARTUPINFOW startupinfo;
748     TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,
749           lpServiceArgVectors);
750
751     size = sizeof(str);
752     r = RegQueryValueExW(hService, _ImagePathW, NULL, &type, (LPVOID)str, &size);
753     if (r!=ERROR_SUCCESS)
754         return FALSE;
755     ExpandEnvironmentStringsW(str,path,sizeof(path));
756
757     TRACE("Starting service %s\n", debugstr_w(path) );
758
759     data = CreateSemaphoreW(NULL,1,1,_ServiceStartDataW);
760     if (!data)
761     {
762         ERR("Couldn't create data semaphore\n");
763         return FALSE;
764     }
765     wait = CreateSemaphoreW(NULL,0,1,_WaitServiceStartW);
766     if (!wait)
767     {
768         ERR("Couldn't create wait semaphore\n");
769         return FALSE;
770     }
771
772     /*
773      * FIXME: lpServiceArgsVectors need to be stored and returned to
774      *        the service when it calls StartServiceCtrlDispatcher
775      *
776      * Chuck these in a global (yuk) so we can pass them to
777      * another process - address space separation will break this.
778      */
779
780     r = WaitForSingleObject(data,INFINITE);
781
782     if( r == WAIT_FAILED)
783         return FALSE;
784
785     FIXME("problematic because of address space separation.\n");
786     start_dwNumServiceArgs    = dwNumServiceArgs;
787     start_lpServiceArgVectors = (LPWSTR *)lpServiceArgVectors;
788
789     ZeroMemory(&startupinfo,sizeof(STARTUPINFOW));
790     startupinfo.cb = sizeof(STARTUPINFOW);
791
792     r = CreateProcessW(path,
793                    NULL,
794                    NULL,  /* process security attribs */
795                    NULL,  /* thread security attribs */
796                    FALSE, /* inherit handles */
797                    0,     /* creation flags */
798                    NULL,  /* environment */
799                    NULL,  /* current directory */
800                    &startupinfo,  /* startup info */
801                    &procinfo); /* process info */
802
803     if(r == FALSE)
804     {
805         ERR("Couldn't start process\n");
806         /* ReleaseSemaphore(data, 1, NULL);
807         return FALSE; */
808     }
809
810     /* docs for StartServiceCtrlDispatcher say this should be 30 sec */
811     r = WaitForSingleObject(wait,30000);
812
813     ReleaseSemaphore(data, 1, NULL);
814
815     if( r == WAIT_FAILED)
816         return FALSE;
817
818     return TRUE;
819 }
820
821 /******************************************************************************
822  * QueryServiceStatus [ADVAPI32.@]
823  *
824  * PARAMS
825  *   hService        []
826  *   lpservicestatus []
827  *
828  */
829 BOOL WINAPI
830 QueryServiceStatus( SC_HANDLE hService, LPSERVICE_STATUS lpservicestatus )
831 {
832     LONG r;
833     DWORD type, val, size;
834
835     FIXME("(%p,%p) partial\n",hService,lpservicestatus);
836
837     /* read the service type from the registry */
838     size = sizeof(val);
839     r = RegQueryValueExA(hService, "Type", NULL, &type, (LPBYTE)&val, &size);
840     if(type!=REG_DWORD)
841     {
842         ERR("invalid Type\n");
843         return FALSE;
844     }
845     lpservicestatus->dwServiceType = val;
846     /* FIXME: how are these determined or read from the registry? */
847     /* SERVICE: unavailable=0, stopped=1, starting=2, running=3? */;
848     lpservicestatus->dwCurrentState            = 1;
849     lpservicestatus->dwControlsAccepted        = 0;
850     lpservicestatus->dwWin32ExitCode           = NO_ERROR;
851     lpservicestatus->dwServiceSpecificExitCode = 0;
852     lpservicestatus->dwCheckPoint              = 0;
853     lpservicestatus->dwWaitHint                = 0;
854
855     return TRUE;
856 }
857
858 /******************************************************************************
859  * QueryServiceStatusEx [ADVAPI32.@]
860  *
861  * PARAMS
862  *   hService       [handle to service]
863  *   InfoLevel      [information level]
864  *   lpBuffer       [buffer]
865  *   cbBufSize      [size of buffer]
866  *   pcbBytesNeeded [bytes needed]
867 */
868 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
869                         LPBYTE lpBuffer, DWORD cbBufSize,
870                         LPDWORD pcbBytesNeeded)
871 {
872     FIXME("stub\n");
873     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
874     return FALSE;
875 }
876
877 /******************************************************************************
878  * QueryServiceConfigA [ADVAPI32.@]
879  */
880 BOOL WINAPI 
881 QueryServiceConfigA( SC_HANDLE hService,
882                      LPQUERY_SERVICE_CONFIGA lpServiceConfig,
883                      DWORD cbBufSize, LPDWORD pcbBytesNeeded)
884 {
885     FIXME("%p %p %ld %p\n", hService, lpServiceConfig,
886            cbBufSize, pcbBytesNeeded);
887     return FALSE;
888 }
889
890 /******************************************************************************
891  * QueryServiceConfigW [ADVAPI32.@]
892  */
893 BOOL WINAPI 
894 QueryServiceConfigW( SC_HANDLE hService,
895                      LPQUERY_SERVICE_CONFIGW lpServiceConfig,
896                      DWORD cbBufSize, LPDWORD pcbBytesNeeded)
897 {
898     const WCHAR szDisplayName[] = {
899         'D','i','s','p','l','a','y','N','a','m','e', 0 };
900     const WCHAR szType[] = {'T','y','p','e',0};
901     const WCHAR szStart[] = {'S','t','a','r','t',0};
902     const WCHAR szError[] = {
903         'E','r','r','o','r','C','o','n','t','r','o','l', 0};
904     const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
905     const WCHAR szGroup[] = {'G','r','o','u','p',0};
906     const WCHAR szDependencies[] = { 
907         'D','e','p','e','n','d','e','n','c','i','e','s',0};
908     LONG r;
909     DWORD type, val, sz, total, n;
910     LPBYTE p;
911
912     TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
913            cbBufSize, pcbBytesNeeded);
914
915     /* calculate the size required first */
916     total = sizeof (QUERY_SERVICE_CONFIGW);
917
918     sz = 0;
919     r = RegQueryValueExW( hService, szImagePath, 0, &type, NULL, &sz );
920     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
921         total += sz;
922
923     sz = 0;
924     r = RegQueryValueExW( hService, szGroup, 0, &type, NULL, &sz );
925     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
926         total += sz;
927
928     sz = 0;
929     r = RegQueryValueExW( hService, szDependencies, 0, &type, NULL, &sz );
930     if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
931         total += sz;
932
933     sz = 0;
934     r = RegQueryValueExW( hService, szStart, 0, &type, NULL, &sz );
935     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
936         total += sz;
937
938     sz = 0;
939     r = RegQueryValueExW( hService, szDisplayName, 0, &type, NULL, &sz );
940     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
941         total += sz;
942
943     /* if there's not enough memory, return an error */
944     if( total > *pcbBytesNeeded )
945     {
946         *pcbBytesNeeded = total;
947         SetLastError( ERROR_INSUFFICIENT_BUFFER );
948         return FALSE;
949     }
950
951     *pcbBytesNeeded = total;
952     ZeroMemory( lpServiceConfig, total );
953
954     sz = sizeof val;
955     r = RegQueryValueExW( hService, szType, 0, &type, (LPBYTE)&val, &sz );
956     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
957         lpServiceConfig->dwServiceType = val;
958
959     sz = sizeof val;
960     r = RegQueryValueExW( hService, szStart, 0, &type, (LPBYTE)&val, &sz );
961     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
962         lpServiceConfig->dwStartType = val;
963
964     sz = sizeof val;
965     r = RegQueryValueExW( hService, szError, 0, &type, (LPBYTE)&val, &sz );
966     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
967         lpServiceConfig->dwErrorControl = val;
968
969     /* now do the strings */
970     p = (LPBYTE) &lpServiceConfig[1];
971     n = total - sizeof (QUERY_SERVICE_CONFIGW);
972
973     sz = n;
974     r = RegQueryValueExW( hService, szImagePath, 0, &type, p, &sz );
975     if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
976     {
977         lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
978         p += sz;
979         n -= sz;
980     }
981
982     sz = n;
983     r = RegQueryValueExW( hService, szGroup, 0, &type, p, &sz );
984     if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
985     {
986         lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
987         p += sz;
988         n -= sz;
989     }
990
991     sz = n;
992     r = RegQueryValueExW( hService, szDependencies, 0, &type, p, &sz );
993     if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
994     {
995         lpServiceConfig->lpDependencies = (LPWSTR) p;
996         p += sz;
997         n -= sz;
998     }
999
1000     if( n < 0 )
1001         ERR("Buffer overflow!\n");
1002
1003     TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1004     TRACE("Group      = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1005
1006     return TRUE;
1007 }
1008
1009 /******************************************************************************
1010  * ChangeServiceConfigW  [ADVAPI32.@]
1011  */
1012 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
1013   DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1014   LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
1015   LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
1016 {
1017     FIXME("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
1018           hService, dwServiceType, dwStartType, dwErrorControl, 
1019           debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
1020           lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
1021           debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
1022     return TRUE;
1023 }
1024
1025 /******************************************************************************
1026  * ChangeServiceConfigA  [ADVAPI32.@]
1027  */
1028 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
1029   DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1030   LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
1031   LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
1032 {
1033     FIXME("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
1034           hService, dwServiceType, dwStartType, dwErrorControl, 
1035           debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
1036           lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
1037           debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
1038     return TRUE;
1039 }
1040
1041 /******************************************************************************
1042  * ChangeServiceConfig2A  [ADVAPI32.@]
1043  */
1044 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel, 
1045     LPVOID lpInfo)
1046 {
1047     FIXME("STUB: %p %ld %p\n",hService, dwInfoLevel, lpInfo);
1048     return TRUE;
1049 }
1050
1051 /******************************************************************************
1052  * ChangeServiceConfig2W  [ADVAPI32.@]
1053  */
1054 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel, 
1055     LPVOID lpInfo)
1056 {
1057     if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
1058     {
1059         static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
1060         LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
1061         if (sd->lpDescription)
1062         {
1063             TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
1064             if (sd->lpDescription[0] == 0)
1065                 RegDeleteValueW(hService,szDescription);
1066             else
1067                 RegSetValueExW(hService, szDescription, 0, REG_SZ,
1068                                         (LPVOID)sd->lpDescription,
1069                                  sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
1070         }
1071     }
1072     else   
1073         FIXME("STUB: %p %ld %p\n",hService, dwInfoLevel, lpInfo);
1074     return TRUE;
1075 }