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