Intern all the atoms we'll need in one step to avoid multiple server
[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
44 /******************************************************************************
45  * EnumServicesStatusA [ADVAPI32.@]
46  */
47 BOOL WINAPI
48 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
49                      DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
50                      DWORD cbBufSize, LPDWORD pcbBytesNeeded,
51                      LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
52 {       FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
53                 dwServiceType, dwServiceState, lpServices, cbBufSize,
54                 pcbBytesNeeded, lpServicesReturned,  lpResumeHandle);
55         SetLastError (ERROR_ACCESS_DENIED);
56         return FALSE;
57 }
58
59 /******************************************************************************
60  * EnumServicesStatusW [ADVAPI32.@]
61  */
62 BOOL WINAPI
63 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
64                      DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
65                      DWORD cbBufSize, LPDWORD pcbBytesNeeded,
66                      LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
67 {       FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
68                 dwServiceType, dwServiceState, lpServices, cbBufSize,
69                 pcbBytesNeeded, lpServicesReturned,  lpResumeHandle);
70         SetLastError (ERROR_ACCESS_DENIED);
71         return FALSE;
72 }
73
74 /******************************************************************************
75  * StartServiceCtrlDispatcherA [ADVAPI32.@]
76  */
77 BOOL WINAPI
78 StartServiceCtrlDispatcherA( LPSERVICE_TABLE_ENTRYA servent )
79 {
80     LPSERVICE_MAIN_FUNCTIONA fpMain;
81     HANDLE wait;
82     DWORD  dwNumServiceArgs ;
83     LPWSTR *lpArgVecW;
84     LPSTR  *lpArgVecA;
85     int i;
86
87     TRACE("(%p)\n", servent);
88     wait = OpenSemaphoreW(SEMAPHORE_ALL_ACCESS, FALSE, _ServiceStartDataW);
89     if(wait == 0)
90     {
91         ERR("Couldn't find wait semaphore\n");
92         ERR("perhaps you need to start services using StartService\n");
93         return FALSE;
94     }
95
96     dwNumServiceArgs = start_dwNumServiceArgs;
97     lpArgVecW        = start_lpServiceArgVectors;
98
99     ReleaseSemaphore(wait, 1, NULL);
100
101     /* Convert the Unicode arg vectors back to ASCII */
102     if(dwNumServiceArgs)
103         lpArgVecA = (LPSTR*) HeapAlloc( GetProcessHeap(), 0,
104                                    dwNumServiceArgs*sizeof(LPSTR) );
105     else
106         lpArgVecA = NULL;
107
108     for(i=0; i<dwNumServiceArgs; i++)
109         lpArgVecA[i]=HEAP_strdupWtoA(GetProcessHeap(), 0, lpArgVecW[i]);
110
111     /* FIXME: should we blindly start all services? */
112     while (servent->lpServiceName) {
113         TRACE("%s at %p)\n", debugstr_a(servent->lpServiceName),servent);
114         fpMain = servent->lpServiceProc;
115
116         /* try to start the service */
117         fpMain( dwNumServiceArgs, lpArgVecA);
118
119         servent++;
120     }
121
122     if(dwNumServiceArgs)
123     {
124         /* free arg strings */
125         for(i=0; i<dwNumServiceArgs; i++)
126             HeapFree(GetProcessHeap(), 0, lpArgVecA[i]);
127         HeapFree(GetProcessHeap(), 0, lpArgVecA);
128     }
129
130     return TRUE;
131 }
132
133 /******************************************************************************
134  * StartServiceCtrlDispatcherW [ADVAPI32.@]
135  *
136  * PARAMS
137  *   servent []
138  */
139 BOOL WINAPI
140 StartServiceCtrlDispatcherW( LPSERVICE_TABLE_ENTRYW servent )
141 {
142     LPSERVICE_MAIN_FUNCTIONW fpMain;
143     HANDLE wait;
144     DWORD  dwNumServiceArgs ;
145     LPWSTR *lpServiceArgVectors ;
146
147     TRACE("(%p)\n", servent);
148     wait = OpenSemaphoreW(SEMAPHORE_ALL_ACCESS, FALSE, _ServiceStartDataW);
149     if(wait == 0)
150     {
151         ERR("Couldn't find wait semaphore\n");
152         ERR("perhaps you need to start services using StartService\n");
153         return FALSE;
154     }
155
156     dwNumServiceArgs    = start_dwNumServiceArgs;
157     lpServiceArgVectors = start_lpServiceArgVectors;
158
159     ReleaseSemaphore(wait, 1, NULL);
160
161     /* FIXME: should we blindly start all services? */
162     while (servent->lpServiceName) {
163         TRACE("%s at %p)\n", debugstr_w(servent->lpServiceName),servent);
164         fpMain = servent->lpServiceProc;
165
166         /* try to start the service */
167         fpMain( dwNumServiceArgs, lpServiceArgVectors);
168
169         servent++;
170     }
171
172     return TRUE;
173 }
174
175 /******************************************************************************
176  * LockServiceDatabase  [ADVAPI32.@]
177  */
178 LPVOID WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
179 {
180         FIXME("%p\n",hSCManager);
181         return (SC_HANDLE)0xcacacafe;
182 }
183
184 /******************************************************************************
185  * UnlockServiceDatabase  [ADVAPI32.@]
186  */
187 BOOL WINAPI UnlockServiceDatabase (LPVOID ScLock)
188 {
189         FIXME(": %p\n",ScLock);
190         return TRUE;
191 }
192
193 /******************************************************************************
194  * RegisterServiceCtrlHandlerA [ADVAPI32.@]
195  */
196 SERVICE_STATUS_HANDLE WINAPI
197 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName,
198                              LPHANDLER_FUNCTION lpfHandler )
199 {       FIXME("%s %p\n", lpServiceName, lpfHandler);
200         return 0xcacacafe;
201 }
202
203 /******************************************************************************
204  * RegisterServiceCtrlHandlerW [ADVAPI32.@]
205  *
206  * PARAMS
207  *   lpServiceName []
208  *   lpfHandler    []
209  */
210 SERVICE_STATUS_HANDLE WINAPI
211 RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName,
212                              LPHANDLER_FUNCTION lpfHandler )
213 {       FIXME("%s %p\n", debugstr_w(lpServiceName), lpfHandler);
214         return 0xcacacafe;
215 }
216
217 /******************************************************************************
218  * SetServiceStatus [ADVAPI32.@]
219  *
220  * PARAMS
221  *   hService []
222  *   lpStatus []
223  */
224 BOOL WINAPI
225 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
226 {       FIXME("0x%lx %p\n",hService, lpStatus);
227         TRACE("\tType:%lx\n",lpStatus->dwServiceType);
228         TRACE("\tState:%lx\n",lpStatus->dwCurrentState);
229         TRACE("\tControlAccepted:%lx\n",lpStatus->dwControlsAccepted);
230         TRACE("\tExitCode:%lx\n",lpStatus->dwWin32ExitCode);
231         TRACE("\tServiceExitCode:%lx\n",lpStatus->dwServiceSpecificExitCode);
232         TRACE("\tCheckPoint:%lx\n",lpStatus->dwCheckPoint);
233         TRACE("\tWaitHint:%lx\n",lpStatus->dwWaitHint);
234         return TRUE;
235 }
236
237 /******************************************************************************
238  * OpenSCManagerA [ADVAPI32.@]
239  */
240 SC_HANDLE WINAPI
241 OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
242                   DWORD dwDesiredAccess )
243 {
244     UNICODE_STRING lpMachineNameW;
245     UNICODE_STRING lpDatabaseNameW;
246     SC_HANDLE ret;
247
248     RtlCreateUnicodeStringFromAsciiz (&lpMachineNameW,lpMachineName);
249     RtlCreateUnicodeStringFromAsciiz (&lpDatabaseNameW,lpDatabaseName);
250     ret = OpenSCManagerW(lpMachineNameW.Buffer,lpDatabaseNameW.Buffer, dwDesiredAccess);
251     RtlFreeUnicodeString(&lpDatabaseNameW);
252     RtlFreeUnicodeString(&lpMachineNameW);
253     return ret;
254 }
255
256 /******************************************************************************
257  * OpenSCManagerW [ADVAPI32.@]
258  * Establishes a connection to the service control manager and opens database
259  *
260  * NOTES
261  *   This should return a SC_HANDLE
262  *
263  * PARAMS
264  *   lpMachineName   [I] Pointer to machine name string
265  *   lpDatabaseName  [I] Pointer to database name string
266  *   dwDesiredAccess [I] Type of access
267  *
268  * RETURNS
269  *   Success: Handle to service control manager database
270  *   Failure: NULL
271  */
272 SC_HANDLE WINAPI
273 OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
274                   DWORD dwDesiredAccess )
275 {
276     HKEY hKey;
277     LONG r;
278
279     TRACE("(%s,%s,0x%08lx)\n", debugstr_w(lpMachineName),
280           debugstr_w(lpDatabaseName), dwDesiredAccess);
281
282     /*
283      * FIXME: what is lpDatabaseName?
284      * It should be set to "SERVICES_ACTIVE_DATABASE" according to
285      * docs, but what if it isn't?
286      */
287
288     r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hKey);
289     if (r!=ERROR_SUCCESS)
290         return 0;
291
292     TRACE("returning %p\n",hKey);
293
294     return hKey;
295 }
296
297
298 /******************************************************************************
299  * AllocateLocallyUniqueId [ADVAPI32.@]
300  *
301  * PARAMS
302  *   lpluid []
303  */
304 BOOL WINAPI
305 AllocateLocallyUniqueId( PLUID lpluid )
306 {
307         lpluid->LowPart = time(NULL);
308         lpluid->HighPart = 0;
309         return TRUE;
310 }
311
312
313 /******************************************************************************
314  * ControlService [ADVAPI32.@]
315  * Sends a control code to a Win32-based service.
316  *
317  * PARAMS
318  *   hService        []
319  *   dwControl       []
320  *   lpServiceStatus []
321  *
322  * RETURNS STD
323  */
324 BOOL WINAPI
325 ControlService( SC_HANDLE hService, DWORD dwControl,
326                 LPSERVICE_STATUS lpServiceStatus )
327 {
328     FIXME("(%p,%ld,%p): stub\n",hService,dwControl,lpServiceStatus);
329     return TRUE;
330 }
331
332
333 /******************************************************************************
334  * CloseServiceHandle [ADVAPI32.@]
335  * Close handle to service or service control manager
336  *
337  * PARAMS
338  *   hSCObject [I] Handle to service or service control manager database
339  *
340  * RETURNS STD
341  */
342 BOOL WINAPI
343 CloseServiceHandle( SC_HANDLE hSCObject )
344 {
345     TRACE("(%p)\n", hSCObject);
346
347     RegCloseKey(hSCObject);
348
349     return TRUE;
350 }
351
352
353 /******************************************************************************
354  * OpenServiceA [ADVAPI32.@]
355  */
356 SC_HANDLE WINAPI
357 OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
358                 DWORD dwDesiredAccess )
359 {
360     UNICODE_STRING lpServiceNameW;
361     SC_HANDLE ret;
362     RtlCreateUnicodeStringFromAsciiz (&lpServiceNameW,lpServiceName);
363     if(lpServiceName)
364         TRACE("Request for service %s\n",lpServiceName);
365     else
366         return FALSE;
367     ret = OpenServiceW( hSCManager, lpServiceNameW.Buffer, dwDesiredAccess);
368     RtlFreeUnicodeString(&lpServiceNameW);
369     return ret;
370 }
371
372
373 /******************************************************************************
374  * OpenServiceW [ADVAPI32.@]
375  * Opens a handle to an existing service
376  *
377  * PARAMS
378  *   hSCManager      []
379  *   lpServiceName   []
380  *   dwDesiredAccess []
381  *
382  * RETURNS
383  *    Success: Handle to the service
384  *    Failure: NULL
385  */
386 SC_HANDLE WINAPI
387 OpenServiceW(SC_HANDLE hSCManager, LPCWSTR lpServiceName,
388                DWORD dwDesiredAccess)
389 {
390     const char *str = "System\\CurrentControlSet\\Services\\";
391     WCHAR lpServiceKey[80]; /* FIXME: this should be dynamically allocated */
392     HKEY hKey;
393     long r;
394
395     TRACE("(%p,%p,%ld)\n",hSCManager, lpServiceName,
396           dwDesiredAccess);
397
398     MultiByteToWideChar( CP_ACP, 0, str, -1, lpServiceKey, sizeof(lpServiceKey)/sizeof(WCHAR) );
399     strcatW(lpServiceKey,lpServiceName);
400
401     TRACE("Opening reg key %s\n", debugstr_w(lpServiceKey));
402
403     /* FIXME: dwDesiredAccess may need some processing */
404     r = RegOpenKeyExW(hSCManager, lpServiceKey, 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     FIXME("(%p,%s,%s,...)\n", hSCManager, debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
426     return 0;
427 }
428
429
430 /******************************************************************************
431  * CreateServiceA [ADVAPI32.@]
432  */
433 SC_HANDLE WINAPI
434 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
435                   LPCSTR lpDisplayName, DWORD dwDesiredAccess,
436                   DWORD dwServiceType, DWORD dwStartType,
437                   DWORD dwErrorControl, LPCSTR lpBinaryPathName,
438                   LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
439                   LPCSTR lpDependencies, LPCSTR lpServiceStartName,
440                   LPCSTR lpPassword )
441 {
442     HKEY hKey;
443     LONG r;
444     DWORD dp;
445
446     TRACE("(%p,%s,%s,...)\n", hSCManager, debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
447
448     r = RegCreateKeyExA(hSCManager, lpServiceName, 0, NULL,
449                        REG_OPTION_NON_VOLATILE, dwDesiredAccess, NULL, &hKey, &dp);
450     if (r!=ERROR_SUCCESS)
451         return 0;
452     if (dp != REG_CREATED_NEW_KEY)
453         return 0;
454
455     if(lpDisplayName)
456     {
457         r = RegSetValueExA(hKey, "DisplayName", 0, REG_SZ, lpDisplayName, strlen(lpDisplayName) );
458         if (r!=ERROR_SUCCESS)
459             return 0;
460     }
461
462     r = RegSetValueExA(hKey, "Type", 0, REG_DWORD, (LPVOID)&dwServiceType, sizeof (DWORD) );
463     if (r!=ERROR_SUCCESS)
464         return 0;
465
466     r = RegSetValueExA(hKey, "Start", 0, REG_DWORD, (LPVOID)&dwStartType, sizeof (DWORD) );
467     if (r!=ERROR_SUCCESS)
468         return 0;
469
470     r = RegSetValueExA(hKey, "ErrorControl", 0, REG_DWORD,
471                            (LPVOID)&dwErrorControl, sizeof (DWORD) );
472     if (r!=ERROR_SUCCESS)
473         return 0;
474
475     if(lpBinaryPathName)
476     {
477         r = RegSetValueExA(hKey, "ImagePath", 0, REG_SZ,
478                            lpBinaryPathName,strlen(lpBinaryPathName)+1 );
479         if (r!=ERROR_SUCCESS)
480             return 0;
481     }
482
483     if(lpLoadOrderGroup)
484     {
485         r = RegSetValueExA(hKey, "Group", 0, REG_SZ,
486                            lpLoadOrderGroup, strlen(lpLoadOrderGroup)+1 );
487         if (r!=ERROR_SUCCESS)
488             return 0;
489     }
490
491     r = RegSetValueExA(hKey, "ErrorControl", 0, REG_DWORD,
492                        (LPVOID)&dwErrorControl, sizeof (DWORD) );
493     if (r!=ERROR_SUCCESS)
494         return 0;
495
496     if(lpDependencies)
497     {
498         DWORD len = 0;
499
500         /* determine the length of a double null terminated multi string */
501         do {
502             len += (strlen(&lpDependencies[len])+1);
503         } while (lpDependencies[len++]);
504
505         /* FIXME: this should be unicode */
506         r = RegSetValueExA(hKey, "Dependencies", 0, REG_MULTI_SZ,
507                            lpDependencies, len );
508         if (r!=ERROR_SUCCESS)
509             return 0;
510     }
511
512     if(lpPassword)
513     {
514         FIXME("Don't know how to add a Password for a service.\n");
515     }
516
517     if(lpServiceStartName)
518     {
519         FIXME("Don't know how to add a ServiceStartName for a service.\n");
520     }
521
522     return hKey;
523 }
524
525
526 /******************************************************************************
527  * DeleteService [ADVAPI32.@]
528  *
529  * PARAMS
530  *    hService [I] Handle to service
531  *
532  * RETURNS STD
533  *
534  */
535 BOOL WINAPI
536 DeleteService( SC_HANDLE hService )
537 {
538     FIXME("(%p): stub\n",hService);
539     return TRUE;
540 }
541
542
543 /******************************************************************************
544  * StartServiceA [ADVAPI32.@]
545  *
546  */
547 BOOL WINAPI
548 StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
549                  LPCSTR *lpServiceArgVectors )
550 {
551     LPWSTR *lpwstr=NULL;
552     UNICODE_STRING usBuffer;
553     int i;
554
555     TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
556
557     if(dwNumServiceArgs)
558         lpwstr = (LPWSTR*) HeapAlloc( GetProcessHeap(), 0,
559                                    dwNumServiceArgs*sizeof(LPWSTR) );
560     else
561         lpwstr = NULL;
562
563     for(i=0; i<dwNumServiceArgs; i++)
564     {
565         RtlCreateUnicodeStringFromAsciiz (&usBuffer,lpServiceArgVectors[i]);
566         lpwstr[i]=usBuffer.Buffer;
567     }
568
569     StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
570
571     if(dwNumServiceArgs)
572     {
573         for(i=0; i<dwNumServiceArgs; i++)
574             HeapFree(GetProcessHeap(), 0, lpwstr[i]);
575         HeapFree(GetProcessHeap(), 0, lpwstr);
576     }
577
578     return TRUE;
579 }
580
581
582 /******************************************************************************
583  * StartServiceW [ADVAPI32.@]
584  * Starts a service
585  *
586  * PARAMS
587  *   hService            [I] Handle of service
588  *   dwNumServiceArgs    [I] Number of arguments
589  *   lpServiceArgVectors [I] Address of array of argument string pointers
590  *
591  * NOTES
592  *
593  * NT implements this function using an obscure RPC call...
594  *
595  * Might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
596  *   to get things like %SystemRoot%\\System32\\service.exe to load.
597  *
598  * Will only work for shared address space. How should the service
599  *  args be transferred when address spaces are separated?
600  *
601  * Can only start one service at a time.
602  *
603  * Has no concept of privilege.
604  *
605  * RETURNS STD
606  *
607  */
608 BOOL WINAPI
609 StartServiceW( SC_HANDLE hService, DWORD dwNumServiceArgs,
610                  LPCWSTR *lpServiceArgVectors )
611 {
612     static const WCHAR  _WaitServiceStartW[]  = {'A','D','V','A','P','I','_','W',
613                                                 'a','i','t','S','e','r','v','i',
614                                                 'c','e','S','t','a','r','t',0};
615     static const WCHAR  _ImagePathW[]  = {'I','m','a','g','e','P','a','t','h',0};
616                                                 
617     WCHAR path[MAX_PATH],str[MAX_PATH];
618     DWORD type,size;
619     long r;
620     HANDLE data,wait;
621     PROCESS_INFORMATION procinfo;
622     STARTUPINFOW startupinfo;
623     TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,
624           lpServiceArgVectors);
625
626     size = sizeof(str);
627     r = RegQueryValueExW(hService, _ImagePathW, NULL, &type, (LPVOID)str, &size);
628     if (r!=ERROR_SUCCESS)
629         return FALSE;
630     ExpandEnvironmentStringsW(str,path,sizeof(path));
631
632     TRACE("Starting service %s\n", debugstr_w(path) );
633
634     data = CreateSemaphoreW(NULL,1,1,_ServiceStartDataW);
635     if (!data)
636     {
637         ERR("Couldn't create data semaphore\n");
638         return FALSE;
639     }
640     wait = CreateSemaphoreW(NULL,0,1,_WaitServiceStartW);
641     if (!wait)
642     {
643         ERR("Couldn't create wait semaphore\n");
644         return FALSE;
645     }
646
647     /*
648      * FIXME: lpServiceArgsVectors need to be stored and returned to
649      *        the service when it calls StartServiceCtrlDispatcher
650      *
651      * Chuck these in a global (yuk) so we can pass them to
652      * another process - address space separation will break this.
653      */
654
655     r = WaitForSingleObject(data,INFINITE);
656
657     if( r == WAIT_FAILED)
658         return FALSE;
659
660     FIXME("problematic because of address space separation.\n");
661     start_dwNumServiceArgs    = dwNumServiceArgs;
662     start_lpServiceArgVectors = (LPWSTR *)lpServiceArgVectors;
663
664     ZeroMemory(&startupinfo,sizeof(STARTUPINFOW));
665     startupinfo.cb = sizeof(STARTUPINFOW);
666
667     r = CreateProcessW(path,
668                    NULL,
669                    NULL,  /* process security attribs */
670                    NULL,  /* thread security attribs */
671                    FALSE, /* inherit handles */
672                    0,     /* creation flags */
673                    NULL,  /* environment */
674                    NULL,  /* current directory */
675                    &startupinfo,  /* startup info */
676                    &procinfo); /* process info */
677
678     if(r == FALSE)
679     {
680         ERR("Couldn't start process\n");
681         /* ReleaseSemaphore(data, 1, NULL);
682         return FALSE; */
683     }
684
685     /* docs for StartServiceCtrlDispatcher say this should be 30 sec */
686     r = WaitForSingleObject(wait,30000);
687
688     ReleaseSemaphore(data, 1, NULL);
689
690     if( r == WAIT_FAILED)
691         return FALSE;
692
693     return TRUE;
694 }
695
696 /******************************************************************************
697  * QueryServiceStatus [ADVAPI32.@]
698  *
699  * PARAMS
700  *   hService        []
701  *   lpservicestatus []
702  *
703  */
704 BOOL WINAPI
705 QueryServiceStatus( SC_HANDLE hService, LPSERVICE_STATUS lpservicestatus )
706 {
707     LONG r;
708     DWORD type, val, size;
709
710     FIXME("(%p,%p) partial\n",hService,lpservicestatus);
711
712     /* read the service type from the registry */
713     size = sizeof(val);
714     r = RegQueryValueExA(hService, "Type", NULL, &type, (LPBYTE)&val, &size);
715     if(type!=REG_DWORD)
716     {
717         ERR("invalid Type\n");
718         return FALSE;
719     }
720     lpservicestatus->dwServiceType = val;
721     /* FIXME: how are these determined or read from the registry? */
722     /* SERVICE: unavailable=0, stopped=1, starting=2, running=3? */;
723     lpservicestatus->dwCurrentState            = 1;
724     lpservicestatus->dwControlsAccepted        = 0;
725     lpservicestatus->dwWin32ExitCode           = NO_ERROR;
726     lpservicestatus->dwServiceSpecificExitCode = 0;
727     lpservicestatus->dwCheckPoint              = 0;
728     lpservicestatus->dwWaitHint                = 0;
729
730     return TRUE;
731 }
732
733 /******************************************************************************
734  * QueryServiceStatusEx [ADVAPI32.@]
735  *
736  * PARAMS
737  *   hService       [handle to service]
738  *   InfoLevel      [information level]
739  *   lpBuffer       [buffer]
740  *   cbBufSize      [size of buffer]
741  *   pcbBytesNeeded [bytes needed]
742 */
743 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
744                         LPBYTE lpBuffer, DWORD cbBufSize,
745                         LPDWORD pcbBytesNeeded)
746 {
747     FIXME("stub\n");
748     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
749     return FALSE;
750 }