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