Use shell icon cache instead of an own IExtractIcon implementation.
[wine] / dlls / advapi32 / service.c
1 /*
2  * Win32 advapi functions
3  *
4  * Copyright 1995 Sven Verdoolaege
5  * Copyright 2005 Mike McCormack
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include <stdarg.h>
23 #include <string.h>
24 #include <time.h>
25 #include <assert.h>
26
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winsvc.h"
30 #include "winerror.h"
31 #include "winreg.h"
32 #include "wine/unicode.h"
33 #include "wine/debug.h"
34 #include "winternl.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(advapi);
37
38 static const WCHAR szServiceManagerKey[] = { 'S','y','s','t','e','m','\\',
39       'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
40       'S','e','r','v','i','c','e','s','\\',0 };
41 static const WCHAR  szSCMLock[] = {'A','D','V','A','P','I','_','S','C','M',
42                                    'L','O','C','K',0};
43
44 typedef struct service_start_info_t
45 {
46     DWORD cmd;
47     DWORD size;
48     WCHAR str[1];
49 } service_start_info;
50
51 #define WINESERV_STARTINFO   1
52 #define WINESERV_GETSTATUS   2
53 #define WINESERV_SENDCONTROL 3
54
55 typedef struct service_data_t
56 {
57     struct service_data_t *next;
58     LPHANDLER_FUNCTION handler;
59     SERVICE_STATUS status;
60     HANDLE thread;
61     BOOL unicode;
62     union {
63         LPSERVICE_MAIN_FUNCTIONA a;
64         LPSERVICE_MAIN_FUNCTIONW w;
65     } proc;
66     LPWSTR args;
67     WCHAR name[1];
68 } service_data;
69
70 static CRITICAL_SECTION service_cs;
71 static CRITICAL_SECTION_DEBUG service_cs_debug =
72 {
73     0, 0, &service_cs,
74     { &service_cs_debug.ProcessLocksList, 
75       &service_cs_debug.ProcessLocksList },
76       0, 0, { 0, (DWORD)(__FILE__ ": service_cs") }
77 };
78 static CRITICAL_SECTION service_cs = { &service_cs_debug, -1, 0, 0, 0, 0 };
79
80 service_data *service_list;
81
82 /******************************************************************************
83  * SC_HANDLEs
84  */
85
86 #define MAX_SERVICE_NAME 256
87
88 typedef enum { SC_HTYPE_MANAGER, SC_HTYPE_SERVICE } SC_HANDLE_TYPE;
89
90 struct sc_handle;
91 typedef VOID (*sc_handle_destructor)(struct sc_handle *);
92
93 struct sc_handle
94 {
95     SC_HANDLE_TYPE htype;
96     DWORD ref_count;
97     sc_handle_destructor destroy;
98 };
99
100 struct sc_manager       /* service control manager handle */
101 {
102     struct sc_handle hdr;
103     HKEY   hkey;   /* handle to services database in the registry */
104 };
105
106 struct sc_service       /* service handle */
107 {
108     struct sc_handle hdr;
109     HKEY   hkey;          /* handle to service entry in the registry (under hkey) */
110     struct sc_manager *scm;  /* pointer to SCM handle */
111     WCHAR  name[1];
112 };
113
114 static void *sc_handle_alloc(SC_HANDLE_TYPE htype, DWORD size,
115                              sc_handle_destructor destroy)
116 {
117     struct sc_handle *hdr;
118
119     hdr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
120     if (hdr)
121     {
122         hdr->htype = htype;
123         hdr->ref_count = 1;
124         hdr->destroy = destroy;
125     }
126     TRACE("sc_handle type=%d -> %p\n", htype, hdr);
127     return hdr;
128 }
129
130 static void *sc_handle_get_handle_data(SC_HANDLE handle, DWORD htype)
131 {
132     struct sc_handle *hdr = (struct sc_handle *) handle;
133
134     if (!hdr)
135         return NULL;
136     if (hdr->htype != htype)
137         return NULL;
138     return hdr;
139 }
140
141 static void sc_handle_free(struct sc_handle* hdr)
142 {
143     if (!hdr)
144         return;
145     if (--hdr->ref_count)
146         return;
147     hdr->destroy(hdr);
148     HeapFree(GetProcessHeap(), 0, hdr);
149 }
150
151 static void sc_handle_destroy_manager(struct sc_handle *handle)
152 {
153     struct sc_manager *mgr = (struct sc_manager*) handle;
154
155     TRACE("destroying SC Manager %p\n", mgr);
156     if (mgr->hkey)
157         RegCloseKey(mgr->hkey);
158 }
159
160 static void sc_handle_destroy_service(struct sc_handle *handle)
161 {
162     struct sc_service *svc = (struct sc_service*) handle;
163     
164     TRACE("destroying service %p\n", svc);
165     if (svc->hkey)
166         RegCloseKey(svc->hkey);
167     svc->hkey = NULL;
168     sc_handle_free(&svc->scm->hdr);
169     svc->scm = NULL;
170 }
171
172 /******************************************************************************
173  * String management functions
174  */
175 static inline LPWSTR SERV_dup( LPCSTR str )
176 {
177     UINT len;
178     LPWSTR wstr;
179
180     if( !str )
181         return NULL;
182     len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
183     wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
184     MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
185     return wstr;
186 }
187
188 static inline LPWSTR SERV_dupmulti(LPCSTR str)
189 {
190     UINT len = 0, n = 0;
191     LPWSTR wstr;
192
193     if( !str )
194         return NULL;
195     do {
196         len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
197         n += (strlen( &str[n] ) + 1);
198     } while (str[n]);
199     len++;
200     n++;
201
202     wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
203     MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
204     return wstr;
205 }
206
207 static inline VOID SERV_free( LPWSTR wstr )
208 {
209     HeapFree( GetProcessHeap(), 0, wstr );
210 }
211
212 /******************************************************************************
213  * registry access functions and data
214  */
215 static const WCHAR szDisplayName[] = {
216        'D','i','s','p','l','a','y','N','a','m','e', 0 };
217 static const WCHAR szType[] = {'T','y','p','e',0};
218 static const WCHAR szStart[] = {'S','t','a','r','t',0};
219 static const WCHAR szError[] = {
220        'E','r','r','o','r','C','o','n','t','r','o','l', 0};
221 static const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
222 static const WCHAR szGroup[] = {'G','r','o','u','p',0};
223 static const WCHAR szDependencies[] = {
224        'D','e','p','e','n','d','e','n','c','i','e','s',0};
225 static const WCHAR szDependOnService[] = {
226        'D','e','p','e','n','d','O','n','S','e','r','v','i','c','e',0};
227
228 struct reg_value {
229     DWORD type;
230     DWORD size;
231     LPCWSTR name;
232     LPCVOID data;
233 };
234
235 static inline void service_set_value( struct reg_value *val,
236                         DWORD type, LPCWSTR name, LPCVOID data, DWORD size )
237 {
238     val->name = name;
239     val->type = type;
240     val->data = data;
241     val->size = size;
242 }
243
244 static inline void service_set_dword( struct reg_value *val, 
245                                       LPCWSTR name, DWORD *data )
246 {
247     service_set_value( val, REG_DWORD, name, data, sizeof (DWORD));
248 }
249
250 static inline void service_set_string( struct reg_value *val,
251                                        LPCWSTR name, LPCWSTR string )
252 {
253     DWORD len = (lstrlenW(string)+1) * sizeof (WCHAR);
254     service_set_value( val, REG_SZ, name, string, len );
255 }
256
257 static inline void service_set_multi_string( struct reg_value *val,
258                                              LPCWSTR name, LPCWSTR string )
259 {
260     DWORD len = 0;
261
262     /* determine the length of a double null terminated multi string */
263     do {
264         len += (lstrlenW( &string[ len ] )+1);
265     } while ( string[ len++ ] );
266
267     len *= sizeof (WCHAR);
268     service_set_value( val, REG_MULTI_SZ, name, string, len );
269 }
270
271 static inline LONG service_write_values( HKEY hKey,
272                                          struct reg_value *val, int n )
273 {
274     LONG r = ERROR_SUCCESS;
275     int i;
276
277     for( i=0; i<n; i++ )
278     {
279         r = RegSetValueExW(hKey, val[i].name, 0, val[i].type, 
280                        (const BYTE*)val[i].data, val[i].size );
281         if( r != ERROR_SUCCESS )
282             break;
283     }
284     return r;
285 }
286
287 /******************************************************************************
288  * Service IPC functions
289  */
290 static LPWSTR service_get_pipe_name(LPWSTR service)
291 {
292     static const WCHAR prefix[] = { '\\','\\','.','\\','p','i','p','e','\\',
293                    '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
294     LPWSTR name;
295     DWORD len;
296
297     len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
298     name = HeapAlloc(GetProcessHeap(), 0, len);
299     strcpyW(name, prefix);
300     strcatW(name, service);
301     return name;
302 }
303
304 static HANDLE service_open_pipe(LPWSTR service)
305 {
306     LPWSTR szPipe = service_get_pipe_name( service );
307     HANDLE handle = INVALID_HANDLE_VALUE;
308
309     do {
310         handle = CreateFileW(szPipe, GENERIC_READ|GENERIC_WRITE,
311                          0, NULL, OPEN_ALWAYS, 0, NULL);
312         if (handle != INVALID_HANDLE_VALUE)
313             break;
314         if (GetLastError() != ERROR_PIPE_BUSY)
315             break;
316     } while (WaitNamedPipeW(szPipe, NMPWAIT_WAIT_FOREVER));
317     SERV_free(szPipe);
318
319     return handle;
320 }
321
322 /******************************************************************************
323  * service_get_event_handle
324  */
325 static HANDLE service_get_event_handle(LPWSTR service)
326 {
327     static const WCHAR prefix[] = { 
328            '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
329     LPWSTR name;
330     DWORD len;
331     HANDLE handle;
332
333     len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
334     name = HeapAlloc(GetProcessHeap(), 0, len);
335     strcpyW(name, prefix);
336     strcatW(name, service);
337     handle = CreateEventW(NULL, TRUE, FALSE, name);
338     SERV_free(name);
339     return handle;
340 }
341
342 /******************************************************************************
343  * service_thread
344  *
345  * Call into the main service routine provided by StartServiceCtrlDispatcher.
346  */
347 static DWORD WINAPI service_thread(LPVOID arg)
348 {
349     service_data *info = arg;
350     LPWSTR str = info->args;
351     DWORD argc = 0, len = 0;
352
353     TRACE("%p\n", arg);
354
355     while (str[len])
356     {
357         len += strlenW(&str[len]) + 1;
358         argc++;
359     }
360     
361     if (info->unicode)
362     {
363         LPWSTR *argv, p;
364
365         argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPWSTR));
366         for (argc=0, p=str; *p; p += strlenW(p) + 1)
367             argv[argc++] = p;
368         argv[argc] = NULL;
369
370         info->proc.w(argc, argv);
371         HeapFree(GetProcessHeap(), 0, argv);
372     }
373     else
374     {
375         LPSTR strA, *argv, p;
376         DWORD lenA;
377         
378         lenA = WideCharToMultiByte(CP_ACP,0, str, len, NULL, 0, NULL, NULL);
379         strA = HeapAlloc(GetProcessHeap(), 0, lenA);
380         WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL);
381
382         argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPSTR));
383         for (argc=0, p=strA; *p; p += strlen(p) + 1)
384             argv[argc++] = p;
385         argv[argc] = NULL;
386
387         info->proc.a(argc, argv);
388         HeapFree(GetProcessHeap(), 0, argv);
389         HeapFree(GetProcessHeap(), 0, strA);
390     }
391     return 0;
392 }
393
394 /******************************************************************************
395  * service_handle_start
396  */
397 static BOOL service_handle_start(HANDLE pipe, service_data *service, DWORD count)
398 {
399     DWORD read = 0, result = 0;
400     LPWSTR args;
401     BOOL r;
402
403     TRACE("%p %p %ld\n", pipe, service, count);
404
405     args = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
406     r = ReadFile(pipe, args, count*sizeof(WCHAR), &read, NULL);
407     if (!r || count!=read/sizeof(WCHAR) || args[count-1])
408     {
409         ERR("pipe read failed r = %d count = %ld/%ld args[n-1]=%s\n",
410             r, count, read/sizeof(WCHAR), debugstr_wn(args, count));
411         goto end;
412     }
413
414     if (service->thread)
415     {
416         ERR("service is not stopped\n");
417         goto end;
418     }
419
420     if (service->args)
421         SERV_free(service->args);
422     service->args = args;
423     args = NULL;
424     service->thread = CreateThread( NULL, 0, service_thread,
425                                     service, 0, NULL );
426
427 end:
428     HeapFree(GetProcessHeap(), 0, args);
429     WriteFile( pipe, &result, sizeof result, &read, NULL );
430
431     return TRUE;
432 }
433
434 /******************************************************************************
435  * service_send_start_message
436  */
437 static BOOL service_send_start_message(HANDLE pipe, LPCWSTR *argv, DWORD argc)
438 {
439     DWORD i, len, count, result;
440     service_start_info *ssi;
441     LPWSTR p;
442     BOOL r;
443
444     TRACE("%p %p %ld\n", pipe, argv, argc);
445
446     /* calculate how much space do we need to send the startup info */
447     len = 1;
448     for (i=0; i<argc; i++)
449         len += strlenW(argv[i])+1;
450
451     ssi = HeapAlloc(GetProcessHeap(),0,sizeof *ssi + (len-1)*sizeof(WCHAR));
452     ssi->cmd = WINESERV_STARTINFO;
453     ssi->size = len;
454
455     /* copy service args into a single buffer*/
456     p = &ssi->str[0];
457     for (i=0; i<argc; i++)
458     {
459         strcpyW(p, argv[i]);
460         p += strlenW(p) + 1;
461     }
462     *p=0;
463
464     r = WriteFile(pipe, ssi, sizeof *ssi + len*sizeof(WCHAR), &count, NULL);
465     if (r)
466         r = ReadFile(pipe, &result, sizeof result, &count, NULL);
467
468     HeapFree(GetProcessHeap(),0,ssi);
469
470     return r;
471 }
472
473 /******************************************************************************
474  * service_handle_get_status
475  */
476 static BOOL service_handle_get_status(HANDLE pipe, service_data *service)
477 {
478     DWORD count = 0;
479     TRACE("\n");
480     return WriteFile(pipe, &service->status, 
481                      sizeof service->status, &count, NULL);
482 }
483
484 /******************************************************************************
485  * service_get_status
486  */
487 static BOOL service_get_status(HANDLE pipe, LPSERVICE_STATUS status)
488 {
489     DWORD cmd[2], count = 0;
490     BOOL r;
491     
492     cmd[0] = WINESERV_GETSTATUS;
493     cmd[1] = 0;
494     r = WriteFile( pipe, cmd, sizeof cmd, &count, NULL );
495     if (!r || count != sizeof cmd)
496     {
497         ERR("service protocol error - failed to write pipe!\n");
498         return r;
499     }
500     r = ReadFile( pipe, status, sizeof *status, &count, NULL );
501     if (!r || count != sizeof *status)
502         ERR("service protocol error - failed to read pipe "
503             "r = %d  count = %ld/%d!\n", r, count, sizeof *status);
504     return r;
505 }
506
507 /******************************************************************************
508  * service_send_control
509  */
510 static BOOL service_send_control(HANDLE pipe, DWORD dwControl, DWORD *result)
511 {
512     DWORD cmd[2], count = 0;
513     BOOL r;
514     
515     cmd[0] = WINESERV_SENDCONTROL;
516     cmd[1] = dwControl;
517     r = WriteFile(pipe, cmd, sizeof cmd, &count, NULL);
518     if (!r || count != sizeof cmd)
519     {
520         ERR("service protocol error - failed to write pipe!\n");
521         return r;
522     }
523     r = ReadFile(pipe, result, sizeof *result, &count, NULL);
524     if (!r || count != sizeof *result)
525         ERR("service protocol error - failed to read pipe "
526             "r = %d  count = %ld/%d!\n", r, count, sizeof *result);
527     return r;
528 }
529
530 /******************************************************************************
531  * service_accepts_control
532  */
533 static BOOL service_accepts_control(service_data *service, DWORD dwControl)
534 {
535     DWORD a = service->status.dwControlsAccepted;
536
537     switch (dwControl)
538     {
539     case SERVICE_CONTROL_INTERROGATE:
540         return TRUE;
541     case SERVICE_CONTROL_STOP:
542         if (a&SERVICE_ACCEPT_STOP)
543             return TRUE;
544         break;
545     case SERVICE_CONTROL_SHUTDOWN:
546         if (a&SERVICE_ACCEPT_SHUTDOWN)
547             return TRUE;
548         break;
549     case SERVICE_CONTROL_PAUSE:
550     case SERVICE_CONTROL_CONTINUE:
551         if (a&SERVICE_ACCEPT_PAUSE_CONTINUE)
552             return TRUE;
553         break;
554     case SERVICE_CONTROL_PARAMCHANGE:
555         if (a&SERVICE_ACCEPT_PARAMCHANGE)
556             return TRUE;
557         break;
558     case SERVICE_CONTROL_NETBINDADD:
559     case SERVICE_CONTROL_NETBINDREMOVE:
560     case SERVICE_CONTROL_NETBINDENABLE:
561     case SERVICE_CONTROL_NETBINDDISABLE:
562         if (a&SERVICE_ACCEPT_NETBINDCHANGE)
563             return TRUE;
564     }
565     if (1) /* (!service->handlerex) */
566         return FALSE;
567     switch (dwControl)
568     {
569     case SERVICE_CONTROL_HARDWAREPROFILECHANGE:
570         if (a&SERVICE_ACCEPT_HARDWAREPROFILECHANGE)
571             return TRUE;
572         break;
573     case SERVICE_CONTROL_POWEREVENT:
574         if (a&SERVICE_ACCEPT_POWEREVENT)
575             return TRUE;
576         break;
577     case SERVICE_CONTROL_SESSIONCHANGE:
578         if (a&SERVICE_ACCEPT_SESSIONCHANGE)
579             return TRUE;
580         break;
581     }
582     return FALSE;
583 }
584
585 /******************************************************************************
586  * service_handle_control
587  */
588 static BOOL service_handle_control(HANDLE pipe, service_data *service,
589                                    DWORD dwControl)
590 {
591     DWORD count, ret = ERROR_INVALID_SERVICE_CONTROL;
592
593     TRACE("received control %ld\n", dwControl);
594     
595     if (service_accepts_control(service, dwControl) && service->handler)
596     {
597         service->handler(dwControl);
598         ret = ERROR_SUCCESS;
599     }
600     return WriteFile(pipe, &ret, sizeof ret, &count, NULL);
601 }
602
603 /******************************************************************************
604  * service_reap_thread
605  */
606 static DWORD service_reap_thread(service_data *service)
607 {
608     DWORD exitcode = 0;
609
610     if (!service->thread)
611         return 0;
612     GetExitCodeThread(service->thread, &exitcode);
613     if (exitcode!=STILL_ACTIVE)
614     {
615         CloseHandle(service->thread);
616         service->thread = 0;
617     }
618     return exitcode;
619 }
620
621 /******************************************************************************
622  * service_control_dispatcher
623  */
624 static DWORD WINAPI service_control_dispatcher(LPVOID arg)
625 {
626     service_data *service = arg;
627     LPWSTR name;
628     HANDLE pipe, event;
629
630     TRACE("%p %s\n", service, debugstr_w(service->name));
631
632     /* create a pipe to talk to the rest of the world with */
633     name = service_get_pipe_name(service->name);
634     pipe = CreateNamedPipeW(name, PIPE_ACCESS_DUPLEX,
635                   PIPE_TYPE_BYTE|PIPE_WAIT, 1, 256, 256, 10000, NULL );
636     SERV_free(name);
637
638     /* let the process who started us know we've tried to create a pipe */
639     event = service_get_event_handle(service->name);
640     SetEvent(event);
641     CloseHandle(event);
642
643     if (pipe==INVALID_HANDLE_VALUE)
644     {
645         ERR("failed to create pipe, error = %ld\n", GetLastError());
646         return 0;
647     }
648
649     /* dispatcher loop */
650     while (1)
651     {
652         BOOL r;
653         DWORD count, req[2] = {0,0};
654
655         r = ConnectNamedPipe(pipe, NULL);
656         if (!r && GetLastError() != ERROR_PIPE_CONNECTED)
657         {
658             ERR("pipe connect failed\n");
659             break;
660         }
661
662         r = ReadFile( pipe, &req, sizeof req, &count, NULL );
663         if (!r || count!=sizeof req)
664         {
665             ERR("pipe read failed\n");
666             break;
667         }
668
669         service_reap_thread(service);
670
671         /* handle the request */
672         switch (req[0])
673         {
674         case WINESERV_STARTINFO:
675             service_handle_start(pipe, service, req[1]);
676             break;
677         case WINESERV_GETSTATUS:
678             service_handle_get_status(pipe, service);
679             break;
680         case WINESERV_SENDCONTROL:
681             service_handle_control(pipe, service, req[1]);
682             break;
683         default:
684             ERR("received invalid command %ld length %ld\n", req[0], req[1]);
685         }
686
687         FlushFileBuffers(pipe);
688         DisconnectNamedPipe(pipe);
689     }
690
691     CloseHandle(pipe);
692     return 1;
693 }
694
695 /******************************************************************************
696  * service_run_threads
697  */
698 static BOOL service_run_threads(void)
699 {
700     service_data *service;
701     DWORD count = 0, n = 0;
702     HANDLE *handles;
703
704     EnterCriticalSection( &service_cs );
705
706     /* count how many services there are */
707     for (service = service_list; service; service = service->next)
708         count++;
709
710     TRACE("starting %ld pipe listener threads\n", count);
711
712     handles = HeapAlloc(GetProcessHeap(), 0, sizeof(HANDLE)*count);
713
714     for (n=0, service = service_list; service; service = service->next, n++)
715         handles[n] = CreateThread( NULL, 0, service_control_dispatcher,
716                                    service, 0, NULL );
717     assert(n==count);
718
719     LeaveCriticalSection( &service_cs );
720
721     /* wait for all the threads to pack up and exit */
722     WaitForMultipleObjectsEx(count, handles, TRUE, INFINITE, FALSE);
723
724     HeapFree(GetProcessHeap(), 0, handles);
725
726     return TRUE;
727 }
728
729 /******************************************************************************
730  * StartServiceCtrlDispatcherA [ADVAPI32.@]
731  *
732  *  Connects a process containing one or more services to the service control
733  * manager.
734  *
735  * PARAMS
736  *   servent [I]  A list of the service names and service procedures
737  */
738 BOOL WINAPI StartServiceCtrlDispatcherA( LPSERVICE_TABLE_ENTRYA servent )
739 {
740     service_data *info;
741     DWORD sz, len;
742     BOOL ret = TRUE;
743
744     TRACE("%p\n", servent);
745
746     EnterCriticalSection( &service_cs );
747     while (servent->lpServiceName)
748     {
749         LPSTR name = servent->lpServiceName;
750
751         len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0);
752         sz = len*sizeof(WCHAR) + sizeof *info;
753         info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
754         MultiByteToWideChar(CP_ACP, 0, name, -1, info->name, len);
755         info->proc.a = servent->lpServiceProc;
756         info->unicode = FALSE;
757         
758         /* insert into the list */
759         info->next = service_list;
760         service_list = info;
761
762         servent++;
763     }
764     LeaveCriticalSection( &service_cs );
765
766     service_run_threads();
767
768     return ret;
769 }
770
771 /******************************************************************************
772  * StartServiceCtrlDispatcherW [ADVAPI32.@]
773  *
774  *  Connects a process containing one or more services to the service control
775  * manager.
776  *
777  * PARAMS
778  *   servent [I]  A list of the service names and service procedures
779  */
780 BOOL WINAPI StartServiceCtrlDispatcherW( LPSERVICE_TABLE_ENTRYW servent )
781 {
782     service_data *info;
783     DWORD sz, len;
784     BOOL ret = TRUE;
785
786     TRACE("%p\n", servent);
787
788     EnterCriticalSection( &service_cs );
789     while (servent->lpServiceName)
790     {
791         LPWSTR name = servent->lpServiceName;
792
793         len = strlenW(name);
794         sz = len*sizeof(WCHAR) + sizeof *info;
795         info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
796         strcpyW(info->name, name);
797         info->proc.w = servent->lpServiceProc;
798         info->unicode = TRUE;
799         
800         /* insert into the list */
801         info->next = service_list;
802         service_list = info;
803
804         servent++;
805     }
806     LeaveCriticalSection( &service_cs );
807
808     service_run_threads();
809
810     return ret;
811 }
812
813 /******************************************************************************
814  * LockServiceDatabase  [ADVAPI32.@]
815  */
816 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
817 {
818     HANDLE ret;
819
820     TRACE("%p\n",hSCManager);
821
822     ret = CreateSemaphoreW( NULL, 1, 1, szSCMLock );
823     if( ret && GetLastError() == ERROR_ALREADY_EXISTS )
824     {
825         CloseHandle( ret );
826         ret = NULL;
827         SetLastError( ERROR_SERVICE_DATABASE_LOCKED );
828     }
829
830     TRACE("returning %p\n", ret);
831
832     return ret;
833 }
834
835 /******************************************************************************
836  * UnlockServiceDatabase  [ADVAPI32.@]
837  */
838 BOOL WINAPI UnlockServiceDatabase (SC_LOCK ScLock)
839 {
840     TRACE("%p\n",ScLock);
841
842     return CloseHandle( ScLock );
843 }
844
845 /******************************************************************************
846  * RegisterServiceCtrlHandlerA [ADVAPI32.@]
847  */
848 SERVICE_STATUS_HANDLE WINAPI
849 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName, LPHANDLER_FUNCTION lpfHandler )
850 {
851     LPWSTR lpServiceNameW;
852     SERVICE_STATUS_HANDLE ret;
853
854     lpServiceNameW = SERV_dup(lpServiceName);
855     ret = RegisterServiceCtrlHandlerW( lpServiceNameW, lpfHandler );
856     SERV_free(lpServiceNameW);
857     return ret;
858 }
859
860 /******************************************************************************
861  * RegisterServiceCtrlHandlerW [ADVAPI32.@]
862  *
863  * PARAMS
864  *   lpServiceName []
865  *   lpfHandler    []
866  */
867 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName,
868                              LPHANDLER_FUNCTION lpfHandler )
869 {
870     service_data *service;
871
872     EnterCriticalSection( &service_cs );
873     for(service = service_list; service; service = service->next)
874         if(!strcmpW(lpServiceName, service->name))
875             break;
876     if (service)
877         service->handler = lpfHandler;
878     LeaveCriticalSection( &service_cs );
879
880     return (SERVICE_STATUS_HANDLE)service;
881 }
882
883 /******************************************************************************
884  * SetServiceStatus [ADVAPI32.@]
885  *
886  * PARAMS
887  *   hService []
888  *   lpStatus []
889  */
890 BOOL WINAPI
891 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
892 {
893     service_data *service;
894     BOOL r = TRUE;
895
896     TRACE("%lx %lx %lx %lx %lx %lx %lx %lx\n", hService,
897           lpStatus->dwServiceType, lpStatus->dwCurrentState,
898           lpStatus->dwControlsAccepted, lpStatus->dwWin32ExitCode,
899           lpStatus->dwServiceSpecificExitCode, lpStatus->dwCheckPoint,
900           lpStatus->dwWaitHint);
901
902     EnterCriticalSection( &service_cs );
903     for (service = service_list; service; service = service->next)
904         if(service == (service_data*)hService)
905             break;
906     if (service)
907     {
908         memcpy( &service->status, lpStatus, sizeof(SERVICE_STATUS) );
909         TRACE("Set service status to %ld\n",service->status.dwCurrentState);
910     }
911     else
912         r = FALSE;
913     LeaveCriticalSection( &service_cs );
914
915     return r;
916 }
917
918
919 /******************************************************************************
920  * OpenSCManagerA [ADVAPI32.@]
921  *
922  * Establish a connection to the service control manager and open its database.
923  *
924  * PARAMS
925  *   lpMachineName   [I] Pointer to machine name string
926  *   lpDatabaseName  [I] Pointer to database name string
927  *   dwDesiredAccess [I] Type of access
928  *
929  * RETURNS
930  *   Success: A Handle to the service control manager database
931  *   Failure: NULL
932  */
933 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
934                                  DWORD dwDesiredAccess )
935 {
936     LPWSTR lpMachineNameW, lpDatabaseNameW;
937     SC_HANDLE ret;
938
939     lpMachineNameW = SERV_dup(lpMachineName);
940     lpDatabaseNameW = SERV_dup(lpDatabaseName);
941     ret = OpenSCManagerW(lpMachineNameW, lpDatabaseNameW, dwDesiredAccess);
942     SERV_free(lpDatabaseNameW);
943     SERV_free(lpMachineNameW);
944     return ret;
945 }
946
947 /******************************************************************************
948  * OpenSCManagerW [ADVAPI32.@]
949  *
950  * See OpenSCManagerA.
951  */
952 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
953                                  DWORD dwDesiredAccess )
954 {
955     struct sc_manager *manager;
956     HKEY hReg;
957     LONG r;
958
959     TRACE("(%s,%s,0x%08lx)\n", debugstr_w(lpMachineName),
960           debugstr_w(lpDatabaseName), dwDesiredAccess);
961
962     if( lpDatabaseName && lpDatabaseName[0] )
963     {
964         if( strcmpiW( lpDatabaseName, SERVICES_ACTIVE_DATABASEW ) == 0 )
965         {
966             /* noop, all right */
967         }
968         else if( strcmpiW( lpDatabaseName, SERVICES_FAILED_DATABASEW ) == 0 )
969         {
970             SetLastError( ERROR_DATABASE_DOES_NOT_EXIST );
971             return NULL;
972         }
973         else
974         {
975             SetLastError( ERROR_INVALID_NAME );
976             return NULL;
977         }
978     }
979
980     manager = sc_handle_alloc( SC_HTYPE_MANAGER, sizeof (struct sc_manager),
981                                sc_handle_destroy_manager );
982     if (!manager)
983          return NULL;
984
985     r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
986     if (r!=ERROR_SUCCESS)
987         goto error;
988
989     r = RegOpenKeyExW(hReg, szServiceManagerKey,
990                       0, KEY_ALL_ACCESS, &manager->hkey);
991     RegCloseKey( hReg );
992     if (r!=ERROR_SUCCESS)
993         goto error;
994
995     TRACE("returning %p\n", manager);
996
997     return (SC_HANDLE) &manager->hdr;
998
999 error:
1000     sc_handle_free( &manager->hdr );
1001     return NULL;
1002 }
1003
1004 /******************************************************************************
1005  * ControlService [ADVAPI32.@]
1006  *
1007  * Send a control code to a service.
1008  *
1009  * PARAMS
1010  *   hService        [I] Handle of the service control manager database
1011  *   dwControl       [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
1012  *   lpServiceStatus [O] Destination for the status of the service, if available
1013  *
1014  * RETURNS
1015  *   Success: TRUE.
1016  *   Failure: FALSE.
1017  *
1018  * BUGS
1019  *   Unlike M$' implementation, control requests are not serialized and may be
1020  *   processed asynchronously.
1021  */
1022 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
1023                             LPSERVICE_STATUS lpServiceStatus )
1024 {
1025     struct sc_service *hsvc;
1026     BOOL ret = FALSE;
1027     HANDLE handle;
1028
1029     TRACE("%p %ld %p\n", hService, dwControl, lpServiceStatus);
1030
1031     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1032     if (!hsvc)
1033     {
1034         SetLastError( ERROR_INVALID_HANDLE );
1035         return FALSE;
1036     }
1037
1038     ret = QueryServiceStatus(hService, lpServiceStatus);
1039     if (!ret)
1040     {
1041         ERR("failed to query service status\n");
1042         SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1043         return FALSE;
1044     }
1045
1046     switch (lpServiceStatus->dwCurrentState)
1047     {
1048     case SERVICE_STOPPED:
1049         SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1050         return FALSE;
1051     case SERVICE_START_PENDING:
1052         if (dwControl==SERVICE_CONTROL_STOP)
1053             break;
1054         /* fall thru */
1055     case SERVICE_STOP_PENDING:
1056         SetLastError(ERROR_SERVICE_CANNOT_ACCEPT_CTRL);
1057         return FALSE;
1058     }
1059
1060     handle = service_open_pipe(hsvc->name);
1061     if (handle!=INVALID_HANDLE_VALUE)
1062     {
1063         DWORD result = ERROR_SUCCESS;
1064         ret = service_send_control(handle, dwControl, &result);
1065         CloseHandle(handle);
1066         if (result!=ERROR_SUCCESS)
1067         {
1068             SetLastError(result);
1069             ret = FALSE;
1070         }
1071     }
1072
1073     return ret;
1074 }
1075
1076 /******************************************************************************
1077  * CloseServiceHandle [ADVAPI32.@]
1078  * 
1079  * Close a handle to a service or the service control manager database.
1080  *
1081  * PARAMS
1082  *   hSCObject [I] Handle to service or service control manager database
1083  *
1084  * RETURNS
1085  *  Success: TRUE
1086  *  Failure: FALSE
1087  */
1088 BOOL WINAPI
1089 CloseServiceHandle( SC_HANDLE hSCObject )
1090 {
1091     TRACE("%p\n", hSCObject);
1092
1093     sc_handle_free( (struct sc_handle*) hSCObject );
1094
1095     return TRUE;
1096 }
1097
1098
1099 /******************************************************************************
1100  * OpenServiceA [ADVAPI32.@]
1101  *
1102  * Open a handle to a service.
1103  *
1104  * PARAMS
1105  *   hSCManager      [I] Handle of the service control manager database
1106  *   lpServiceName   [I] Name of the service to open
1107  *   dwDesiredAccess [I] Access required to the service
1108  *
1109  * RETURNS
1110  *    Success: Handle to the service
1111  *    Failure: NULL
1112  */
1113 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1114                                DWORD dwDesiredAccess )
1115 {
1116     LPWSTR lpServiceNameW;
1117     SC_HANDLE ret;
1118
1119     TRACE("%p %s %ld\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
1120
1121     lpServiceNameW = SERV_dup(lpServiceName);
1122     ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
1123     SERV_free(lpServiceNameW);
1124     return ret;
1125 }
1126
1127
1128 /******************************************************************************
1129  * OpenServiceW [ADVAPI32.@]
1130  *
1131  * See OpenServiceA.
1132  */
1133 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1134                                DWORD dwDesiredAccess)
1135 {
1136     struct sc_manager *hscm;
1137     struct sc_service *hsvc;
1138     HKEY hKey;
1139     long r;
1140     DWORD len;
1141
1142     TRACE("%p %s %ld\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
1143
1144     if (!lpServiceName)
1145     {
1146         SetLastError(ERROR_INVALID_ADDRESS);
1147         return NULL;
1148     }
1149
1150     hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1151     if (!hscm)
1152     {
1153         SetLastError( ERROR_INVALID_HANDLE );
1154         return FALSE;
1155     }
1156
1157     r = RegOpenKeyExW( hscm->hkey, lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
1158     if (r!=ERROR_SUCCESS)
1159     {
1160         SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
1161         return NULL;
1162     }
1163     
1164     len = strlenW(lpServiceName)+1;
1165     hsvc = sc_handle_alloc( SC_HTYPE_SERVICE,
1166                             sizeof (struct sc_service) + len*sizeof(WCHAR),
1167                             sc_handle_destroy_service );
1168     if (!hsvc)
1169         return NULL;
1170     strcpyW( hsvc->name, lpServiceName );
1171     hsvc->hkey = hKey;
1172
1173     /* add reference to SCM handle */
1174     hscm->hdr.ref_count++;
1175     hsvc->scm = hscm;
1176
1177     TRACE("returning %p\n",hsvc);
1178
1179     return (SC_HANDLE) &hsvc->hdr;
1180 }
1181
1182 /******************************************************************************
1183  * CreateServiceW [ADVAPI32.@]
1184  */
1185 SC_HANDLE WINAPI
1186 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1187                   LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
1188                   DWORD dwServiceType, DWORD dwStartType,
1189                   DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1190                   LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1191                   LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
1192                   LPCWSTR lpPassword )
1193 {
1194     struct sc_manager *hscm;
1195     struct sc_service *hsvc = NULL;
1196     HKEY hKey;
1197     LONG r;
1198     DWORD dp, len;
1199     struct reg_value val[10];
1200     int n = 0;
1201
1202     TRACE("%p %s %s\n", hSCManager, 
1203           debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
1204
1205     hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1206     if (!hscm)
1207     {
1208         SetLastError( ERROR_INVALID_HANDLE );
1209         return NULL;
1210     }
1211
1212     r = RegCreateKeyExW(hscm->hkey, lpServiceName, 0, NULL,
1213                        REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
1214     if (r!=ERROR_SUCCESS)
1215         return NULL;
1216
1217     if (dp != REG_CREATED_NEW_KEY)
1218     {
1219         SetLastError(ERROR_SERVICE_EXISTS);
1220         goto error;
1221     }
1222
1223     if( lpDisplayName )
1224         service_set_string( &val[n++], szDisplayName, lpDisplayName );
1225
1226     service_set_dword( &val[n++], szType, &dwServiceType );
1227     service_set_dword( &val[n++], szStart, &dwStartType );
1228     service_set_dword( &val[n++], szError, &dwErrorControl );
1229
1230     if( lpBinaryPathName )
1231         service_set_string( &val[n++], szImagePath, lpBinaryPathName );
1232
1233     if( lpLoadOrderGroup )
1234         service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
1235
1236     if( lpDependencies )
1237         service_set_multi_string( &val[n++], szDependencies, lpDependencies );
1238
1239     if( lpPassword )
1240         FIXME("Don't know how to add a Password for a service.\n");
1241
1242     if( lpServiceStartName )
1243         service_set_string( &val[n++], szDependOnService, lpServiceStartName );
1244
1245     r = service_write_values( hKey, val, n );
1246     if( r != ERROR_SUCCESS )
1247         goto error;
1248
1249     len = strlenW(lpServiceName)+1;
1250     len = sizeof (struct sc_service) + len*sizeof(WCHAR);
1251     hsvc = sc_handle_alloc( SC_HTYPE_SERVICE, len, sc_handle_destroy_service );
1252     if( !hsvc )
1253         goto error;
1254     lstrcpyW( hsvc->name, lpServiceName );
1255     hsvc->hkey = hKey;
1256     hsvc->scm = hscm;
1257     hscm->hdr.ref_count++;
1258
1259     return (SC_HANDLE) &hsvc->hdr;
1260     
1261 error:
1262     RegCloseKey( hKey );
1263     return NULL;
1264 }
1265
1266
1267 /******************************************************************************
1268  * CreateServiceA [ADVAPI32.@]
1269  */
1270 SC_HANDLE WINAPI
1271 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1272                   LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1273                   DWORD dwServiceType, DWORD dwStartType,
1274                   DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1275                   LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1276                   LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1277                   LPCSTR lpPassword )
1278 {
1279     LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1280         lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1281     SC_HANDLE r;
1282
1283     TRACE("%p %s %s\n", hSCManager,
1284           debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1285
1286     lpServiceNameW = SERV_dup( lpServiceName );
1287     lpDisplayNameW = SERV_dup( lpDisplayName );
1288     lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1289     lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1290     lpDependenciesW = SERV_dupmulti( lpDependencies );
1291     lpServiceStartNameW = SERV_dup( lpServiceStartName );
1292     lpPasswordW = SERV_dup( lpPassword );
1293
1294     r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1295             dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1296             lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1297             lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1298
1299     SERV_free( lpServiceNameW );
1300     SERV_free( lpDisplayNameW );
1301     SERV_free( lpBinaryPathNameW );
1302     SERV_free( lpLoadOrderGroupW );
1303     SERV_free( lpDependenciesW );
1304     SERV_free( lpServiceStartNameW );
1305     SERV_free( lpPasswordW );
1306
1307     return r;
1308 }
1309
1310
1311 /******************************************************************************
1312  * DeleteService [ADVAPI32.@]
1313  *
1314  * Delete a service from the service control manager database.
1315  *
1316  * PARAMS
1317  *    hService [I] Handle of the service to delete
1318  *
1319  * RETURNS
1320  *  Success: TRUE
1321  *  Failure: FALSE
1322  */
1323 BOOL WINAPI DeleteService( SC_HANDLE hService )
1324 {
1325     struct sc_service *hsvc;
1326     HKEY hKey;
1327     WCHAR valname[MAX_PATH+1];
1328     INT index = 0;
1329     LONG rc;
1330     DWORD size;
1331
1332     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1333     if (!hsvc)
1334     {
1335         SetLastError( ERROR_INVALID_HANDLE );
1336         return FALSE;
1337     }
1338     hKey = hsvc->hkey;
1339
1340     size = MAX_PATH+1; 
1341     /* Clean out the values */
1342     rc = RegEnumValueW(hKey, index, valname,&size,0,0,0,0);
1343     while (rc == ERROR_SUCCESS)
1344     {
1345         RegDeleteValueW(hKey,valname);
1346         index++;
1347         size = MAX_PATH+1; 
1348         rc = RegEnumValueW(hKey, index, valname, &size,0,0,0,0);
1349     }
1350
1351     RegCloseKey(hKey);
1352     hsvc->hkey = NULL;
1353
1354     /* delete the key */
1355     RegDeleteKeyW(hsvc->scm->hkey, hsvc->name);
1356
1357     return TRUE;
1358 }
1359
1360
1361 /******************************************************************************
1362  * StartServiceA [ADVAPI32.@]
1363  *
1364  * Start a service
1365  *
1366  * PARAMS
1367  *   hService            [I] Handle of service
1368  *   dwNumServiceArgs    [I] Number of arguments
1369  *   lpServiceArgVectors [I] Address of array of argument strings
1370  *
1371  * NOTES
1372  *  - NT implements this function using an obscure RPC call.
1373  *  - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1374  *    to get things like "%SystemRoot%\\System32\\service.exe" to load.
1375  *  - This will only work for shared address space. How should the service
1376  *    args be transferred when address spaces are separated?
1377  *  - Can only start one service at a time.
1378  *  - Has no concept of privilege.
1379  *
1380  * RETURNS
1381  *   Success: TRUE.
1382  *   Failure: FALSE
1383  */
1384 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1385                            LPCSTR *lpServiceArgVectors )
1386 {
1387     LPWSTR *lpwstr=NULL;
1388     unsigned int i;
1389     BOOL r;
1390
1391     TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1392
1393     if (dwNumServiceArgs)
1394         lpwstr = HeapAlloc( GetProcessHeap(), 0,
1395                                    dwNumServiceArgs*sizeof(LPWSTR) );
1396
1397     for(i=0; i<dwNumServiceArgs; i++)
1398         lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1399
1400     r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1401
1402     if (dwNumServiceArgs)
1403     {
1404         for(i=0; i<dwNumServiceArgs; i++)
1405             SERV_free(lpwstr[i]);
1406         HeapFree(GetProcessHeap(), 0, lpwstr);
1407     }
1408
1409     return r;
1410 }
1411
1412 /******************************************************************************
1413  * service_start_process    [INTERNAL]
1414  */
1415 static DWORD service_start_process(struct sc_service *hsvc)
1416 {
1417     static const WCHAR _ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0};
1418     PROCESS_INFORMATION pi;
1419     STARTUPINFOW si;
1420     LPWSTR path = NULL, str;
1421     DWORD type, size, ret;
1422     HANDLE handles[2];
1423     BOOL r;
1424
1425     /* read the executable path from memory */
1426     size = 0;
1427     ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, NULL, &size);
1428     if (ret!=ERROR_SUCCESS)
1429         return FALSE;
1430     str = HeapAlloc(GetProcessHeap(),0,size);
1431     ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, (LPBYTE)str, &size);
1432     if (ret==ERROR_SUCCESS)
1433     {
1434         size = ExpandEnvironmentStringsW(str,NULL,0);
1435         path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
1436         ExpandEnvironmentStringsW(str,path,size);
1437     }
1438     HeapFree(GetProcessHeap(),0,str);
1439     if (!path)
1440         return FALSE;
1441
1442     /* wait for the process to start and set an event or terminate */
1443     handles[0] = service_get_event_handle( hsvc->name );
1444     ZeroMemory(&si, sizeof(STARTUPINFOW));
1445     si.cb = sizeof(STARTUPINFOW);
1446     r = CreateProcessW(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1447     if (r)
1448     {
1449         handles[1] = pi.hProcess;
1450         ret = WaitForMultipleObjectsEx(2, handles, FALSE, 30000, FALSE);
1451         if(ret != WAIT_OBJECT_0)
1452         {
1453             SetLastError(ERROR_IO_PENDING);
1454             r = FALSE;
1455         }
1456
1457         CloseHandle( pi.hThread );
1458         CloseHandle( pi.hProcess );
1459     }
1460     CloseHandle( handles[0] );
1461     HeapFree(GetProcessHeap(),0,path);
1462     return r;
1463 }
1464
1465 static BOOL service_wait_for_startup(SC_HANDLE hService)
1466 {
1467     DWORD i;
1468     SERVICE_STATUS status;
1469     BOOL r = FALSE;
1470
1471     TRACE("%p\n", hService);
1472
1473     for (i=0; i<30; i++)
1474     {
1475         status.dwCurrentState = 0;
1476         r = QueryServiceStatus(hService, &status);
1477         if (!r)
1478             break;
1479         if (status.dwCurrentState == SERVICE_RUNNING)
1480         {
1481             TRACE("Service started successfully\n");
1482             break;
1483         }
1484         r = FALSE;
1485         Sleep(1000);
1486     }
1487     return r;
1488 }
1489
1490 /******************************************************************************
1491  * StartServiceW [ADVAPI32.@]
1492  * 
1493  * See StartServiceA.
1494  */
1495 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1496                           LPCWSTR *lpServiceArgVectors)
1497 {
1498     struct sc_service *hsvc;
1499     BOOL r = FALSE;
1500     SC_LOCK hLock;
1501     HANDLE handle = INVALID_HANDLE_VALUE;
1502
1503     TRACE("%p %ld %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1504
1505     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1506     if (!hsvc)
1507     {
1508         SetLastError(ERROR_INVALID_HANDLE);
1509         return r;
1510     }
1511
1512     hLock = LockServiceDatabase(hsvc->scm);
1513     if (!hLock)
1514         return r;
1515
1516     handle = service_open_pipe(hsvc->name);
1517     if (handle==INVALID_HANDLE_VALUE)
1518     {
1519         /* start the service process */
1520         if (service_start_process(hsvc))
1521             handle = service_open_pipe(hsvc->name);
1522     }
1523
1524     if (handle != INVALID_HANDLE_VALUE)
1525     {
1526         service_send_start_message(handle, lpServiceArgVectors, dwNumServiceArgs);
1527         CloseHandle(handle);
1528         r = TRUE;
1529     }
1530
1531     UnlockServiceDatabase( hLock );
1532
1533     TRACE("returning %d\n", r);
1534
1535     service_wait_for_startup(hService);
1536
1537     return r;
1538 }
1539
1540 /******************************************************************************
1541  * QueryServiceStatus [ADVAPI32.@]
1542  *
1543  * PARAMS
1544  *   hService        []
1545  *   lpservicestatus []
1546  *
1547  */
1548 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1549                                LPSERVICE_STATUS lpservicestatus)
1550 {
1551     struct sc_service *hsvc;
1552     DWORD size, type, val;
1553     HANDLE pipe;
1554     LONG r;
1555
1556     TRACE("%p %p\n", hService, lpservicestatus);
1557
1558     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1559     if (!hsvc)
1560     {
1561         SetLastError( ERROR_INVALID_HANDLE );
1562         return FALSE;
1563     }
1564
1565     pipe = service_open_pipe(hsvc->name);
1566     if (pipe != INVALID_HANDLE_VALUE)
1567     {
1568         r = service_get_status(pipe, lpservicestatus);
1569         CloseHandle(pipe);
1570         if (r)
1571             return TRUE;
1572     }
1573
1574     TRACE("Failed to read service status\n");
1575
1576     /* read the service type from the registry */
1577     size = sizeof(val);
1578     r = RegQueryValueExA(hsvc->hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1579     if(r!=ERROR_SUCCESS || type!=REG_DWORD)
1580         val = 0;
1581
1582     lpservicestatus->dwServiceType = val;
1583     lpservicestatus->dwCurrentState            = SERVICE_STOPPED;  /* stopped */
1584     lpservicestatus->dwControlsAccepted        = 0;
1585     lpservicestatus->dwWin32ExitCode           = ERROR_SERVICE_NEVER_STARTED;
1586     lpservicestatus->dwServiceSpecificExitCode = 0;
1587     lpservicestatus->dwCheckPoint              = 0;
1588     lpservicestatus->dwWaitHint                = 0;
1589
1590     return TRUE;
1591 }
1592
1593 /******************************************************************************
1594  * QueryServiceStatusEx [ADVAPI32.@]
1595  *
1596  * Get information about a service.
1597  *
1598  * PARAMS
1599  *   hService       [I] Handle to service to get information about
1600  *   InfoLevel      [I] Level of information to get
1601  *   lpBuffer       [O] Destination for requested information
1602  *   cbBufSize      [I] Size of lpBuffer in bytes
1603  *   pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1604  *
1605  * RETURNS
1606  *  Success: TRUE
1607  *  FAILURE: FALSE
1608  */
1609 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1610                         LPBYTE lpBuffer, DWORD cbBufSize,
1611                         LPDWORD pcbBytesNeeded)
1612 {
1613     FIXME("stub\n");
1614     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1615     return FALSE;
1616 }
1617
1618 /******************************************************************************
1619  * QueryServiceConfigA [ADVAPI32.@]
1620  */
1621 BOOL WINAPI 
1622 QueryServiceConfigA( SC_HANDLE hService,
1623                      LPQUERY_SERVICE_CONFIGA lpServiceConfig,
1624                      DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1625 {
1626     static const CHAR szDisplayName[] = "DisplayName";
1627     static const CHAR szType[] = "Type";
1628     static const CHAR szStart[] = "Start";
1629     static const CHAR szError[] = "ErrorControl";
1630     static const CHAR szImagePath[] = "ImagePath";
1631     static const CHAR szGroup[] = "Group";
1632     static const CHAR szDependencies[] = "Dependencies";
1633     struct sc_service *hsvc;
1634     HKEY hKey;
1635     CHAR str_buffer[ MAX_PATH ];
1636     LONG r;
1637     DWORD type, val, sz, total, n;
1638     LPBYTE p;
1639
1640     TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
1641            cbBufSize, pcbBytesNeeded);
1642
1643     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1644     if (!hsvc)
1645     {
1646         SetLastError( ERROR_INVALID_HANDLE );
1647         return FALSE;
1648     }
1649     hKey = hsvc->hkey;
1650
1651     /* calculate the size required first */
1652     total = sizeof (QUERY_SERVICE_CONFIGA);
1653
1654     sz = sizeof(str_buffer);
1655     r = RegQueryValueExA( hKey, szImagePath, 0, &type, str_buffer, &sz );
1656     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1657     {
1658         sz = ExpandEnvironmentStringsA(str_buffer,NULL,0);
1659         if( 0 == sz ) return FALSE;
1660
1661         total += sz;
1662     }
1663     else
1664     {
1665         /* FIXME: set last error */
1666         return FALSE;
1667     }
1668
1669     sz = 0;
1670     r = RegQueryValueExA( hKey, szGroup, 0, &type, NULL, &sz );
1671     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1672         total += sz;
1673
1674     sz = 0;
1675     r = RegQueryValueExA( hKey, szDependencies, 0, &type, NULL, &sz );
1676     if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1677         total += sz;
1678
1679     sz = 0;
1680     r = RegQueryValueExA( hKey, szStart, 0, &type, NULL, &sz );
1681     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1682         total += sz;
1683
1684     sz = 0;
1685     r = RegQueryValueExA( hKey, szDisplayName, 0, &type, NULL, &sz );
1686     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1687         total += sz;
1688
1689     *pcbBytesNeeded = total;
1690
1691     /* if there's not enough memory, return an error */
1692     if( total > cbBufSize )
1693     {
1694         SetLastError( ERROR_INSUFFICIENT_BUFFER );
1695         return FALSE;
1696     }
1697
1698     ZeroMemory( lpServiceConfig, total );
1699
1700     sz = sizeof val;
1701     r = RegQueryValueExA( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1702     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1703         lpServiceConfig->dwServiceType = val;
1704
1705     sz = sizeof val;
1706     r = RegQueryValueExA( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1707     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1708         lpServiceConfig->dwStartType = val;
1709
1710     sz = sizeof val;
1711     r = RegQueryValueExA( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1712     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1713         lpServiceConfig->dwErrorControl = val;
1714
1715     /* now do the strings */
1716     p = (LPBYTE) &lpServiceConfig[1];
1717     n = total - sizeof (QUERY_SERVICE_CONFIGA);
1718
1719     sz = sizeof(str_buffer);
1720     r = RegQueryValueExA( hKey, szImagePath, 0, &type, str_buffer, &sz );
1721     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1722     {
1723         sz = ExpandEnvironmentStringsA(str_buffer, p, n);
1724         if( 0 == sz || sz > n ) return FALSE;
1725
1726         lpServiceConfig->lpBinaryPathName = (LPSTR) p;
1727         p += sz;
1728         n -= sz;
1729     }
1730     else
1731     {
1732         /* FIXME: set last error */
1733         return FALSE;
1734     }
1735
1736     sz = n;
1737     r = RegQueryValueExA( hKey, szGroup, 0, &type, p, &sz );
1738     if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1739     {
1740         lpServiceConfig->lpLoadOrderGroup = (LPSTR) p;
1741         p += sz;
1742         n -= sz;
1743     }
1744
1745     sz = n;
1746     r = RegQueryValueExA( hKey, szDependencies, 0, &type, p, &sz );
1747     if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1748     {
1749         lpServiceConfig->lpDependencies = (LPSTR) p;
1750         p += sz;
1751         n -= sz;
1752     }
1753
1754     if( n < 0 )
1755         ERR("Buffer overflow!\n");
1756
1757     TRACE("Image path = %s\n", lpServiceConfig->lpBinaryPathName );
1758     TRACE("Group      = %s\n", lpServiceConfig->lpLoadOrderGroup );
1759
1760     return TRUE;
1761 }
1762
1763 /******************************************************************************
1764  * QueryServiceConfigW [ADVAPI32.@]
1765  */
1766 BOOL WINAPI 
1767 QueryServiceConfigW( SC_HANDLE hService,
1768                      LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1769                      DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1770 {
1771     WCHAR str_buffer[ MAX_PATH ];
1772     LONG r;
1773     DWORD type, val, sz, total, n;
1774     LPBYTE p;
1775     HKEY hKey;
1776     struct sc_service *hsvc;
1777
1778     TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
1779            cbBufSize, pcbBytesNeeded);
1780
1781     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1782     if (!hsvc)
1783     {
1784         SetLastError( ERROR_INVALID_HANDLE );
1785         return FALSE;
1786     }
1787     hKey = hsvc->hkey;
1788
1789     /* calculate the size required first */
1790     total = sizeof (QUERY_SERVICE_CONFIGW);
1791
1792     sz = sizeof(str_buffer);
1793     r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1794     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1795     {
1796         sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1797         if( 0 == sz ) return FALSE;
1798
1799         total += sizeof(WCHAR) * sz;
1800     }
1801     else
1802     {
1803        /* FIXME: set last error */
1804        return FALSE;
1805     }
1806
1807     sz = 0;
1808     r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1809     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1810         total += sz;
1811
1812     sz = 0;
1813     r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1814     if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1815         total += sz;
1816     else
1817         total += sizeof(WCHAR);
1818
1819     sz = 0;
1820     r = RegQueryValueExW( hKey, szStart, 0, &type, NULL, &sz );
1821     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1822         total += sz;
1823
1824     sz = 0;
1825     r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1826     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1827         total += sz;
1828
1829     *pcbBytesNeeded = total;
1830
1831     /* if there's not enough memory, return an error */
1832     if( total > cbBufSize )
1833     {
1834         SetLastError( ERROR_INSUFFICIENT_BUFFER );
1835         return FALSE;
1836     }
1837
1838     ZeroMemory( lpServiceConfig, total );
1839
1840     sz = sizeof val;
1841     r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1842     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1843         lpServiceConfig->dwServiceType = val;
1844
1845     sz = sizeof val;
1846     r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1847     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1848         lpServiceConfig->dwStartType = val;
1849
1850     sz = sizeof val;
1851     r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1852     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1853         lpServiceConfig->dwErrorControl = val;
1854
1855     /* now do the strings */
1856     p = (LPBYTE) &lpServiceConfig[1];
1857     n = total - sizeof (QUERY_SERVICE_CONFIGW);
1858
1859     sz = sizeof(str_buffer);
1860     r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1861     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1862     {
1863         sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
1864         sz *= sizeof(WCHAR);
1865         if( 0 == sz || sz > n ) return FALSE;
1866
1867         lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
1868         p += sz;
1869         n -= sz;
1870     }
1871     else
1872     {
1873        /* FIXME: set last error */
1874        return FALSE;
1875     }
1876
1877     sz = n;
1878     r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
1879     if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1880     {
1881         lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
1882         p += sz;
1883         n -= sz;
1884     }
1885
1886     sz = n;
1887     r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
1888     lpServiceConfig->lpDependencies = (LPWSTR) p;
1889     if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1890     {
1891         p += sz;
1892         n -= sz;
1893     }
1894     else
1895     {
1896         *(WCHAR *) p = 0;
1897         p += sizeof(WCHAR);
1898         n -= sizeof(WCHAR);
1899     }
1900
1901     if( n < 0 )
1902         ERR("Buffer overflow!\n");
1903
1904     TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1905     TRACE("Group      = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1906
1907     return TRUE;
1908 }
1909
1910 /******************************************************************************
1911  * EnumServicesStatusA [ADVAPI32.@]
1912  */
1913 BOOL WINAPI
1914 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
1915                      DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
1916                      DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1917                      LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1918 {
1919     FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
1920           dwServiceType, dwServiceState, lpServices, cbBufSize,
1921           pcbBytesNeeded, lpServicesReturned,  lpResumeHandle);
1922     SetLastError (ERROR_ACCESS_DENIED);
1923     return FALSE;
1924 }
1925
1926 /******************************************************************************
1927  * EnumServicesStatusW [ADVAPI32.@]
1928  */
1929 BOOL WINAPI
1930 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
1931                      DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
1932                      DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1933                      LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1934 {
1935     FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
1936           dwServiceType, dwServiceState, lpServices, cbBufSize,
1937           pcbBytesNeeded, lpServicesReturned,  lpResumeHandle);
1938     SetLastError (ERROR_ACCESS_DENIED);
1939     return FALSE;
1940 }
1941
1942 /******************************************************************************
1943  * GetServiceKeyNameA [ADVAPI32.@]
1944  */
1945 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
1946                                 LPSTR lpServiceName, LPDWORD lpcchBuffer )
1947 {
1948     FIXME("%p %s %p %p\n", hSCManager, debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
1949     return FALSE;
1950 }
1951
1952 /******************************************************************************
1953  * GetServiceKeyNameW [ADVAPI32.@]
1954  */
1955 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
1956                                 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
1957 {
1958     FIXME("%p %s %p %p\n", hSCManager, debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
1959     return FALSE;
1960 }
1961
1962 /******************************************************************************
1963  * QueryServiceLockStatusA [ADVAPI32.@]
1964  */
1965 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
1966                                      LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
1967                                      DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1968 {
1969     FIXME("%p %p %08lx %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1970
1971     return FALSE;
1972 }
1973
1974 /******************************************************************************
1975  * QueryServiceLockStatusW [ADVAPI32.@]
1976  */
1977 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
1978                                      LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
1979                                      DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1980 {
1981     FIXME("%p %p %08lx %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1982
1983     return FALSE;
1984 }
1985
1986 /******************************************************************************
1987  * GetServiceDisplayNameA  [ADVAPI32.@]
1988  */
1989 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1990   LPSTR lpDisplayName, LPDWORD lpcchBuffer)
1991 {
1992     FIXME("%p %s %p %p\n", hSCManager,
1993           debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
1994     return FALSE;
1995 }
1996
1997 /******************************************************************************
1998  * GetServiceDisplayNameW  [ADVAPI32.@]
1999  */
2000 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
2001   LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
2002 {
2003     FIXME("%p %s %p %p\n", hSCManager,
2004           debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
2005     return FALSE;
2006 }
2007
2008 /******************************************************************************
2009  * ChangeServiceConfigW  [ADVAPI32.@]
2010  */
2011 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
2012   DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
2013   LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
2014   LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
2015 {
2016     struct reg_value val[10];
2017     struct sc_service *hsvc;
2018     DWORD r = ERROR_SUCCESS;
2019     HKEY hKey;
2020     int n = 0;
2021
2022     TRACE("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
2023           hService, dwServiceType, dwStartType, dwErrorControl, 
2024           debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2025           lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2026           debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2027
2028     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2029     if (!hsvc)
2030     {
2031         SetLastError( ERROR_INVALID_HANDLE );
2032         return FALSE;
2033     }
2034     hKey = hsvc->hkey;
2035
2036     if( dwServiceType != SERVICE_NO_CHANGE )
2037         service_set_dword( &val[n++], szType, &dwServiceType );
2038
2039     if( dwStartType != SERVICE_NO_CHANGE )
2040         service_set_dword( &val[n++], szStart, &dwStartType );
2041
2042     if( dwErrorControl != SERVICE_NO_CHANGE )
2043         service_set_dword( &val[n++], szError, &dwErrorControl );
2044
2045     if( lpBinaryPathName )
2046         service_set_string( &val[n++], szImagePath, lpBinaryPathName );
2047
2048     if( lpLoadOrderGroup )
2049         service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
2050
2051     if( lpDependencies )
2052         service_set_multi_string( &val[n++], szDependencies, lpDependencies );
2053
2054     if( lpPassword )
2055         FIXME("ignoring password\n");
2056
2057     if( lpServiceStartName )
2058         service_set_string( &val[n++], szDependOnService, lpServiceStartName );
2059
2060     r = service_write_values( hsvc->hkey, val, n );
2061
2062     return (r == ERROR_SUCCESS) ? TRUE : FALSE ;
2063 }
2064
2065 /******************************************************************************
2066  * ChangeServiceConfigA  [ADVAPI32.@]
2067  */
2068 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2069   DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2070   LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2071   LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2072 {
2073     LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2074     LPWSTR wServiceStartName, wPassword, wDisplayName;
2075     BOOL r;
2076
2077     TRACE("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
2078           hService, dwServiceType, dwStartType, dwErrorControl, 
2079           debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2080           lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2081           debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2082
2083     wBinaryPathName = SERV_dup( lpBinaryPathName );
2084     wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2085     wDependencies = SERV_dupmulti( lpDependencies );
2086     wServiceStartName = SERV_dup( lpServiceStartName );
2087     wPassword = SERV_dup( lpPassword );
2088     wDisplayName = SERV_dup( lpDisplayName );
2089
2090     r = ChangeServiceConfigW( hService, dwServiceType,
2091             dwStartType, dwErrorControl, wBinaryPathName,
2092             wLoadOrderGroup, lpdwTagId, wDependencies,
2093             wServiceStartName, wPassword, wDisplayName);
2094
2095     SERV_free( wBinaryPathName );
2096     SERV_free( wLoadOrderGroup );
2097     SERV_free( wDependencies );
2098     SERV_free( wServiceStartName );
2099     SERV_free( wPassword );
2100     SERV_free( wDisplayName );
2101
2102     return r;
2103 }
2104
2105 /******************************************************************************
2106  * ChangeServiceConfig2A  [ADVAPI32.@]
2107  */
2108 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel, 
2109     LPVOID lpInfo)
2110 {
2111     BOOL r = FALSE;
2112
2113     TRACE("%p %ld %p\n",hService, dwInfoLevel, lpInfo);
2114
2115     if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2116     {
2117         LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
2118         SERVICE_DESCRIPTIONW sdw;
2119
2120         sdw.lpDescription = SERV_dup( sd->lpDescription );
2121
2122         r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2123
2124         SERV_free( sdw.lpDescription );
2125     }
2126     else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2127     {
2128         LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
2129         SERVICE_FAILURE_ACTIONSW faw;
2130
2131         faw.dwResetPeriod = fa->dwResetPeriod;
2132         faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2133         faw.lpCommand = SERV_dup( fa->lpCommand );
2134         faw.cActions = fa->cActions;
2135         faw.lpsaActions = fa->lpsaActions;
2136
2137         r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2138
2139         SERV_free( faw.lpRebootMsg );
2140         SERV_free( faw.lpCommand );
2141     }
2142     else
2143         SetLastError( ERROR_INVALID_PARAMETER );
2144
2145     return r;
2146 }
2147
2148 /******************************************************************************
2149  * ChangeServiceConfig2W  [ADVAPI32.@]
2150  */
2151 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel, 
2152     LPVOID lpInfo)
2153 {
2154     HKEY hKey;
2155     struct sc_service *hsvc;
2156
2157     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2158     if (!hsvc)
2159     {
2160         SetLastError( ERROR_INVALID_HANDLE );
2161         return FALSE;
2162     }
2163     hKey = hsvc->hkey;
2164
2165     if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2166     {
2167         static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2168         LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
2169         if (sd->lpDescription)
2170         {
2171             TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
2172             if (sd->lpDescription[0] == 0)
2173                 RegDeleteValueW(hKey,szDescription);
2174             else
2175                 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2176                                         (LPVOID)sd->lpDescription,
2177                                  sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2178         }
2179     }
2180     else   
2181         FIXME("STUB: %p %ld %p\n",hService, dwInfoLevel, lpInfo);
2182     return TRUE;
2183 }
2184
2185 /******************************************************************************
2186  * QueryServiceObjectSecurity [ADVAPI32.@]
2187  */
2188 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2189        SECURITY_INFORMATION dwSecurityInformation,
2190        PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2191        DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2192 {
2193     PACL pACL = NULL;
2194
2195     FIXME("%p %ld %p %lu %p\n", hService, dwSecurityInformation,
2196           lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2197
2198     InitializeSecurityDescriptor(lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
2199
2200     pACL = HeapAlloc( GetProcessHeap(), 0, sizeof(ACL) );
2201     InitializeAcl(pACL, sizeof(ACL), ACL_REVISION);
2202     SetSecurityDescriptorDacl(lpSecurityDescriptor, TRUE, pACL, TRUE);
2203     return TRUE;
2204 }
2205
2206 /******************************************************************************
2207  * SetServiceObjectSecurity [ADVAPI32.@]
2208  */
2209 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2210        SECURITY_INFORMATION dwSecurityInformation,
2211        PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2212 {
2213     FIXME("%p %ld %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2214     return TRUE;
2215 }
2216
2217 /******************************************************************************
2218  * SetServiceBits [ADVAPI32.@]
2219  */
2220 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2221         DWORD dwServiceBits,
2222         BOOL bSetBitsOn,
2223         BOOL bUpdateImmediately)
2224 {
2225     FIXME("%08lx %08lx %x %x\n", hServiceStatus, dwServiceBits,
2226           bSetBitsOn, bUpdateImmediately);
2227     return TRUE;
2228 }