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