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