advapi32: If we can't connect to a service's pipe, name the service in
[wine/multimedia.git] / dlls / advapi32 / service.c
blob1db25d7cb2572b5adb95f08966013ab45f4aecd6
1 /*
2 * Win32 advapi functions
4 * Copyright 1995 Sven Verdoolaege
5 * Copyright 2005 Mike McCormack
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.
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.
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
22 #include <stdarg.h>
23 #include <string.h>
24 #include <time.h>
25 #include <assert.h>
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 #include "lmcons.h"
36 #include "lmserver.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(advapi);
40 static const WCHAR szServiceManagerKey[] = { 'S','y','s','t','e','m','\\',
41 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
42 'S','e','r','v','i','c','e','s','\\',0 };
43 static const WCHAR szSCMLock[] = {'A','D','V','A','P','I','_','S','C','M',
44 'L','O','C','K',0};
46 typedef struct service_start_info_t
48 DWORD cmd;
49 DWORD size;
50 WCHAR str[1];
51 } service_start_info;
53 #define WINESERV_STARTINFO 1
54 #define WINESERV_GETSTATUS 2
55 #define WINESERV_SENDCONTROL 3
57 typedef struct service_data_t
59 struct service_data_t *next;
60 LPHANDLER_FUNCTION handler;
61 SERVICE_STATUS status;
62 HANDLE thread;
63 BOOL unicode;
64 union {
65 LPSERVICE_MAIN_FUNCTIONA a;
66 LPSERVICE_MAIN_FUNCTIONW w;
67 } proc;
68 LPWSTR args;
69 WCHAR name[1];
70 } service_data;
72 static CRITICAL_SECTION service_cs;
73 static CRITICAL_SECTION_DEBUG service_cs_debug =
75 0, 0, &service_cs,
76 { &service_cs_debug.ProcessLocksList,
77 &service_cs_debug.ProcessLocksList },
78 0, 0, { (DWORD_PTR)(__FILE__ ": service_cs") }
80 static CRITICAL_SECTION service_cs = { &service_cs_debug, -1, 0, 0, 0, 0 };
82 service_data *service_list;
84 /******************************************************************************
85 * SC_HANDLEs
88 #define MAX_SERVICE_NAME 256
90 typedef enum { SC_HTYPE_MANAGER, SC_HTYPE_SERVICE } SC_HANDLE_TYPE;
92 struct sc_handle;
93 typedef VOID (*sc_handle_destructor)(struct sc_handle *);
95 struct sc_handle
97 SC_HANDLE_TYPE htype;
98 DWORD ref_count;
99 sc_handle_destructor destroy;
102 struct sc_manager /* service control manager handle */
104 struct sc_handle hdr;
105 HKEY hkey; /* handle to services database in the registry */
108 struct sc_service /* service handle */
110 struct sc_handle hdr;
111 HKEY hkey; /* handle to service entry in the registry (under hkey) */
112 struct sc_manager *scm; /* pointer to SCM handle */
113 WCHAR name[1];
116 static void *sc_handle_alloc(SC_HANDLE_TYPE htype, DWORD size,
117 sc_handle_destructor destroy)
119 struct sc_handle *hdr;
121 hdr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
122 if (hdr)
124 hdr->htype = htype;
125 hdr->ref_count = 1;
126 hdr->destroy = destroy;
128 TRACE("sc_handle type=%d -> %p\n", htype, hdr);
129 return hdr;
132 static void *sc_handle_get_handle_data(SC_HANDLE handle, DWORD htype)
134 struct sc_handle *hdr = (struct sc_handle *) handle;
136 if (!hdr)
137 return NULL;
138 if (hdr->htype != htype)
139 return NULL;
140 return hdr;
143 static void sc_handle_free(struct sc_handle* hdr)
145 if (!hdr)
146 return;
147 if (--hdr->ref_count)
148 return;
149 hdr->destroy(hdr);
150 HeapFree(GetProcessHeap(), 0, hdr);
153 static void sc_handle_destroy_manager(struct sc_handle *handle)
155 struct sc_manager *mgr = (struct sc_manager*) handle;
157 TRACE("destroying SC Manager %p\n", mgr);
158 if (mgr->hkey)
159 RegCloseKey(mgr->hkey);
162 static void sc_handle_destroy_service(struct sc_handle *handle)
164 struct sc_service *svc = (struct sc_service*) handle;
166 TRACE("destroying service %p\n", svc);
167 if (svc->hkey)
168 RegCloseKey(svc->hkey);
169 svc->hkey = NULL;
170 sc_handle_free(&svc->scm->hdr);
171 svc->scm = NULL;
174 /******************************************************************************
175 * String management functions
177 static inline LPWSTR SERV_dup( LPCSTR str )
179 UINT len;
180 LPWSTR wstr;
182 if( !str )
183 return NULL;
184 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
185 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
186 MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
187 return wstr;
190 static inline LPWSTR SERV_dupmulti(LPCSTR str)
192 UINT len = 0, n = 0;
193 LPWSTR wstr;
195 if( !str )
196 return NULL;
197 do {
198 len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
199 n += (strlen( &str[n] ) + 1);
200 } while (str[n]);
201 len++;
202 n++;
204 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
205 MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
206 return wstr;
209 static inline VOID SERV_free( LPWSTR wstr )
211 HeapFree( GetProcessHeap(), 0, wstr );
214 /******************************************************************************
215 * registry access functions and data
217 static const WCHAR szDisplayName[] = {
218 'D','i','s','p','l','a','y','N','a','m','e', 0 };
219 static const WCHAR szType[] = {'T','y','p','e',0};
220 static const WCHAR szStart[] = {'S','t','a','r','t',0};
221 static const WCHAR szError[] = {
222 'E','r','r','o','r','C','o','n','t','r','o','l', 0};
223 static const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
224 static const WCHAR szGroup[] = {'G','r','o','u','p',0};
225 static const WCHAR szDependencies[] = {
226 'D','e','p','e','n','d','e','n','c','i','e','s',0};
227 static const WCHAR szDependOnService[] = {
228 'D','e','p','e','n','d','O','n','S','e','r','v','i','c','e',0};
230 struct reg_value {
231 DWORD type;
232 DWORD size;
233 LPCWSTR name;
234 LPCVOID data;
237 static inline void service_set_value( struct reg_value *val,
238 DWORD type, LPCWSTR name, LPCVOID data, DWORD size )
240 val->name = name;
241 val->type = type;
242 val->data = data;
243 val->size = size;
246 static inline void service_set_dword( struct reg_value *val,
247 LPCWSTR name, DWORD *data )
249 service_set_value( val, REG_DWORD, name, data, sizeof (DWORD));
252 static inline void service_set_string( struct reg_value *val,
253 LPCWSTR name, LPCWSTR string )
255 DWORD len = (lstrlenW(string)+1) * sizeof (WCHAR);
256 service_set_value( val, REG_SZ, name, string, len );
259 static inline void service_set_multi_string( struct reg_value *val,
260 LPCWSTR name, LPCWSTR string )
262 DWORD len = 0;
264 /* determine the length of a double null terminated multi string */
265 do {
266 len += (lstrlenW( &string[ len ] )+1);
267 } while ( string[ len++ ] );
269 len *= sizeof (WCHAR);
270 service_set_value( val, REG_MULTI_SZ, name, string, len );
273 static inline LONG service_write_values( HKEY hKey,
274 struct reg_value *val, int n )
276 LONG r = ERROR_SUCCESS;
277 int i;
279 for( i=0; i<n; i++ )
281 r = RegSetValueExW(hKey, val[i].name, 0, val[i].type,
282 (const BYTE*)val[i].data, val[i].size );
283 if( r != ERROR_SUCCESS )
284 break;
286 return r;
289 /******************************************************************************
290 * Service IPC functions
292 static LPWSTR service_get_pipe_name(LPWSTR service)
294 static const WCHAR prefix[] = { '\\','\\','.','\\','p','i','p','e','\\',
295 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
296 LPWSTR name;
297 DWORD len;
299 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
300 name = HeapAlloc(GetProcessHeap(), 0, len);
301 strcpyW(name, prefix);
302 strcatW(name, service);
303 return name;
306 static HANDLE service_open_pipe(LPWSTR service)
308 LPWSTR szPipe = service_get_pipe_name( service );
309 HANDLE handle = INVALID_HANDLE_VALUE;
311 do {
312 handle = CreateFileW(szPipe, GENERIC_READ|GENERIC_WRITE,
313 0, NULL, OPEN_ALWAYS, 0, NULL);
314 if (handle != INVALID_HANDLE_VALUE)
315 break;
316 if (GetLastError() != ERROR_PIPE_BUSY)
317 break;
318 } while (WaitNamedPipeW(szPipe, NMPWAIT_WAIT_FOREVER));
319 SERV_free(szPipe);
321 return handle;
324 /******************************************************************************
325 * service_get_event_handle
327 static HANDLE service_get_event_handle(LPWSTR service)
329 static const WCHAR prefix[] = {
330 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
331 LPWSTR name;
332 DWORD len;
333 HANDLE handle;
335 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
336 name = HeapAlloc(GetProcessHeap(), 0, len);
337 strcpyW(name, prefix);
338 strcatW(name, service);
339 handle = CreateEventW(NULL, TRUE, FALSE, name);
340 SERV_free(name);
341 return handle;
344 /******************************************************************************
345 * service_thread
347 * Call into the main service routine provided by StartServiceCtrlDispatcher.
349 static DWORD WINAPI service_thread(LPVOID arg)
351 service_data *info = arg;
352 LPWSTR str = info->args;
353 DWORD argc = 0, len = 0;
355 TRACE("%p\n", arg);
357 while (str[len])
359 len += strlenW(&str[len]) + 1;
360 argc++;
363 if (!argc)
365 if (info->unicode)
366 info->proc.w(0, NULL);
367 else
368 info->proc.a(0, NULL);
369 return 0;
372 if (info->unicode)
374 LPWSTR *argv, p;
376 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPWSTR));
377 for (argc=0, p=str; *p; p += strlenW(p) + 1)
378 argv[argc++] = p;
379 argv[argc] = NULL;
381 info->proc.w(argc, argv);
382 HeapFree(GetProcessHeap(), 0, argv);
384 else
386 LPSTR strA, *argv, p;
387 DWORD lenA;
389 lenA = WideCharToMultiByte(CP_ACP,0, str, len, NULL, 0, NULL, NULL);
390 strA = HeapAlloc(GetProcessHeap(), 0, lenA);
391 WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL);
393 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPSTR));
394 for (argc=0, p=strA; *p; p += strlen(p) + 1)
395 argv[argc++] = p;
396 argv[argc] = NULL;
398 info->proc.a(argc, argv);
399 HeapFree(GetProcessHeap(), 0, argv);
400 HeapFree(GetProcessHeap(), 0, strA);
402 return 0;
405 /******************************************************************************
406 * service_handle_start
408 static BOOL service_handle_start(HANDLE pipe, service_data *service, DWORD count)
410 DWORD read = 0, result = 0;
411 LPWSTR args;
412 BOOL r;
414 TRACE("%p %p %ld\n", pipe, service, count);
416 args = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
417 r = ReadFile(pipe, args, count*sizeof(WCHAR), &read, NULL);
418 if (!r || count!=read/sizeof(WCHAR) || args[count-1])
420 ERR("pipe read failed r = %d count = %ld/%ld args[n-1]=%s\n",
421 r, count, read/sizeof(WCHAR), debugstr_wn(args, count));
422 goto end;
425 if (service->thread)
427 ERR("service is not stopped\n");
428 goto end;
431 if (service->args)
432 SERV_free(service->args);
433 service->args = args;
434 args = NULL;
435 service->thread = CreateThread( NULL, 0, service_thread,
436 service, 0, NULL );
438 end:
439 HeapFree(GetProcessHeap(), 0, args);
440 WriteFile( pipe, &result, sizeof result, &read, NULL );
442 return TRUE;
445 /******************************************************************************
446 * service_send_start_message
448 static BOOL service_send_start_message(HANDLE pipe, LPCWSTR *argv, DWORD argc)
450 DWORD i, len, count, result;
451 service_start_info *ssi;
452 LPWSTR p;
453 BOOL r;
455 TRACE("%p %p %ld\n", pipe, argv, argc);
457 /* calculate how much space do we need to send the startup info */
458 len = 1;
459 for (i=0; i<argc; i++)
460 len += strlenW(argv[i])+1;
462 ssi = HeapAlloc(GetProcessHeap(),0,sizeof *ssi + (len-1)*sizeof(WCHAR));
463 ssi->cmd = WINESERV_STARTINFO;
464 ssi->size = len;
466 /* copy service args into a single buffer*/
467 p = &ssi->str[0];
468 for (i=0; i<argc; i++)
470 strcpyW(p, argv[i]);
471 p += strlenW(p) + 1;
473 *p=0;
475 r = WriteFile(pipe, ssi, sizeof *ssi + len*sizeof(WCHAR), &count, NULL);
476 if (r)
477 r = ReadFile(pipe, &result, sizeof result, &count, NULL);
479 HeapFree(GetProcessHeap(),0,ssi);
481 return r;
484 /******************************************************************************
485 * service_handle_get_status
487 static BOOL service_handle_get_status(HANDLE pipe, service_data *service)
489 DWORD count = 0;
490 TRACE("\n");
491 return WriteFile(pipe, &service->status,
492 sizeof service->status, &count, NULL);
495 /******************************************************************************
496 * service_get_status
498 static BOOL service_get_status(HANDLE pipe, LPSERVICE_STATUS status)
500 DWORD cmd[2], count = 0;
501 BOOL r;
503 cmd[0] = WINESERV_GETSTATUS;
504 cmd[1] = 0;
505 r = WriteFile( pipe, cmd, sizeof cmd, &count, NULL );
506 if (!r || count != sizeof cmd)
508 ERR("service protocol error - failed to write pipe!\n");
509 return r;
511 r = ReadFile( pipe, status, sizeof *status, &count, NULL );
512 if (!r || count != sizeof *status)
513 ERR("service protocol error - failed to read pipe "
514 "r = %d count = %ld/%d!\n", r, count, sizeof *status);
515 return r;
518 /******************************************************************************
519 * service_send_control
521 static BOOL service_send_control(HANDLE pipe, DWORD dwControl, DWORD *result)
523 DWORD cmd[2], count = 0;
524 BOOL r;
526 cmd[0] = WINESERV_SENDCONTROL;
527 cmd[1] = dwControl;
528 r = WriteFile(pipe, cmd, sizeof cmd, &count, NULL);
529 if (!r || count != sizeof cmd)
531 ERR("service protocol error - failed to write pipe!\n");
532 return r;
534 r = ReadFile(pipe, result, sizeof *result, &count, NULL);
535 if (!r || count != sizeof *result)
536 ERR("service protocol error - failed to read pipe "
537 "r = %d count = %ld/%d!\n", r, count, sizeof *result);
538 return r;
541 /******************************************************************************
542 * service_accepts_control
544 static BOOL service_accepts_control(service_data *service, DWORD dwControl)
546 DWORD a = service->status.dwControlsAccepted;
548 switch (dwControl)
550 case SERVICE_CONTROL_INTERROGATE:
551 return TRUE;
552 case SERVICE_CONTROL_STOP:
553 if (a&SERVICE_ACCEPT_STOP)
554 return TRUE;
555 break;
556 case SERVICE_CONTROL_SHUTDOWN:
557 if (a&SERVICE_ACCEPT_SHUTDOWN)
558 return TRUE;
559 break;
560 case SERVICE_CONTROL_PAUSE:
561 case SERVICE_CONTROL_CONTINUE:
562 if (a&SERVICE_ACCEPT_PAUSE_CONTINUE)
563 return TRUE;
564 break;
565 case SERVICE_CONTROL_PARAMCHANGE:
566 if (a&SERVICE_ACCEPT_PARAMCHANGE)
567 return TRUE;
568 break;
569 case SERVICE_CONTROL_NETBINDADD:
570 case SERVICE_CONTROL_NETBINDREMOVE:
571 case SERVICE_CONTROL_NETBINDENABLE:
572 case SERVICE_CONTROL_NETBINDDISABLE:
573 if (a&SERVICE_ACCEPT_NETBINDCHANGE)
574 return TRUE;
576 if (1) /* (!service->handlerex) */
577 return FALSE;
578 switch (dwControl)
580 case SERVICE_CONTROL_HARDWAREPROFILECHANGE:
581 if (a&SERVICE_ACCEPT_HARDWAREPROFILECHANGE)
582 return TRUE;
583 break;
584 case SERVICE_CONTROL_POWEREVENT:
585 if (a&SERVICE_ACCEPT_POWEREVENT)
586 return TRUE;
587 break;
588 case SERVICE_CONTROL_SESSIONCHANGE:
589 if (a&SERVICE_ACCEPT_SESSIONCHANGE)
590 return TRUE;
591 break;
593 return FALSE;
596 /******************************************************************************
597 * service_handle_control
599 static BOOL service_handle_control(HANDLE pipe, service_data *service,
600 DWORD dwControl)
602 DWORD count, ret = ERROR_INVALID_SERVICE_CONTROL;
604 TRACE("received control %ld\n", dwControl);
606 if (service_accepts_control(service, dwControl) && service->handler)
608 service->handler(dwControl);
609 ret = ERROR_SUCCESS;
611 return WriteFile(pipe, &ret, sizeof ret, &count, NULL);
614 /******************************************************************************
615 * service_reap_thread
617 static DWORD service_reap_thread(service_data *service)
619 DWORD exitcode = 0;
621 if (!service->thread)
622 return 0;
623 GetExitCodeThread(service->thread, &exitcode);
624 if (exitcode!=STILL_ACTIVE)
626 CloseHandle(service->thread);
627 service->thread = 0;
629 return exitcode;
632 /******************************************************************************
633 * service_control_dispatcher
635 static DWORD WINAPI service_control_dispatcher(LPVOID arg)
637 service_data *service = arg;
638 LPWSTR name;
639 HANDLE pipe, event;
641 TRACE("%p %s\n", service, debugstr_w(service->name));
643 /* create a pipe to talk to the rest of the world with */
644 name = service_get_pipe_name(service->name);
645 pipe = CreateNamedPipeW(name, PIPE_ACCESS_DUPLEX,
646 PIPE_TYPE_BYTE|PIPE_WAIT, 1, 256, 256, 10000, NULL );
647 SERV_free(name);
649 /* let the process who started us know we've tried to create a pipe */
650 event = service_get_event_handle(service->name);
651 SetEvent(event);
652 CloseHandle(event);
654 if (pipe==INVALID_HANDLE_VALUE)
656 ERR("failed to create pipe for %s, error = %ld\n",
657 debugstr_w(service->name), GetLastError());
658 return 0;
661 /* dispatcher loop */
662 while (1)
664 BOOL r;
665 DWORD count, req[2] = {0,0};
667 r = ConnectNamedPipe(pipe, NULL);
668 if (!r && GetLastError() != ERROR_PIPE_CONNECTED)
670 ERR("pipe connect failed\n");
671 break;
674 r = ReadFile( pipe, &req, sizeof req, &count, NULL );
675 if (!r || count!=sizeof req)
677 ERR("pipe read failed\n");
678 break;
681 service_reap_thread(service);
683 /* handle the request */
684 switch (req[0])
686 case WINESERV_STARTINFO:
687 service_handle_start(pipe, service, req[1]);
688 break;
689 case WINESERV_GETSTATUS:
690 service_handle_get_status(pipe, service);
691 break;
692 case WINESERV_SENDCONTROL:
693 service_handle_control(pipe, service, req[1]);
694 break;
695 default:
696 ERR("received invalid command %ld length %ld\n", req[0], req[1]);
699 FlushFileBuffers(pipe);
700 DisconnectNamedPipe(pipe);
703 CloseHandle(pipe);
704 return 1;
707 /******************************************************************************
708 * service_run_threads
710 static BOOL service_run_threads(void)
712 service_data *service;
713 DWORD count = 0, n = 0;
714 HANDLE *handles;
716 EnterCriticalSection( &service_cs );
718 /* count how many services there are */
719 for (service = service_list; service; service = service->next)
720 count++;
722 TRACE("starting %ld pipe listener threads\n", count);
724 handles = HeapAlloc(GetProcessHeap(), 0, sizeof(HANDLE)*count);
726 for (n=0, service = service_list; service; service = service->next, n++)
727 handles[n] = CreateThread( NULL, 0, service_control_dispatcher,
728 service, 0, NULL );
729 assert(n==count);
731 LeaveCriticalSection( &service_cs );
733 /* wait for all the threads to pack up and exit */
734 WaitForMultipleObjectsEx(count, handles, TRUE, INFINITE, FALSE);
736 HeapFree(GetProcessHeap(), 0, handles);
738 return TRUE;
741 /******************************************************************************
742 * StartServiceCtrlDispatcherA [ADVAPI32.@]
744 * See StartServiceCtrlDispatcherW.
746 BOOL WINAPI StartServiceCtrlDispatcherA( LPSERVICE_TABLE_ENTRYA servent )
748 service_data *info;
749 DWORD sz, len;
750 BOOL ret = TRUE;
752 TRACE("%p\n", servent);
754 EnterCriticalSection( &service_cs );
755 while (servent->lpServiceName)
757 LPSTR name = servent->lpServiceName;
759 len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0);
760 sz = len*sizeof(WCHAR) + sizeof *info;
761 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
762 MultiByteToWideChar(CP_ACP, 0, name, -1, info->name, len);
763 info->proc.a = servent->lpServiceProc;
764 info->unicode = FALSE;
766 /* insert into the list */
767 info->next = service_list;
768 service_list = info;
770 servent++;
772 LeaveCriticalSection( &service_cs );
774 service_run_threads();
776 return ret;
779 /******************************************************************************
780 * StartServiceCtrlDispatcherW [ADVAPI32.@]
782 * Connects a process containing one or more services to the service control
783 * manager.
785 * PARAMS
786 * servent [I] A list of the service names and service procedures
788 * RETURNS
789 * Success: TRUE.
790 * Failure: FALSE.
792 BOOL WINAPI StartServiceCtrlDispatcherW( LPSERVICE_TABLE_ENTRYW servent )
794 service_data *info;
795 DWORD sz, len;
796 BOOL ret = TRUE;
798 TRACE("%p\n", servent);
800 EnterCriticalSection( &service_cs );
801 while (servent->lpServiceName)
803 LPWSTR name = servent->lpServiceName;
805 len = strlenW(name);
806 sz = len*sizeof(WCHAR) + sizeof *info;
807 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
808 strcpyW(info->name, name);
809 info->proc.w = servent->lpServiceProc;
810 info->unicode = TRUE;
812 /* insert into the list */
813 info->next = service_list;
814 service_list = info;
816 servent++;
818 LeaveCriticalSection( &service_cs );
820 service_run_threads();
822 return ret;
825 /******************************************************************************
826 * LockServiceDatabase [ADVAPI32.@]
828 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
830 HANDLE ret;
832 TRACE("%p\n",hSCManager);
834 ret = CreateSemaphoreW( NULL, 1, 1, szSCMLock );
835 if( ret && GetLastError() == ERROR_ALREADY_EXISTS )
837 CloseHandle( ret );
838 ret = NULL;
839 SetLastError( ERROR_SERVICE_DATABASE_LOCKED );
842 TRACE("returning %p\n", ret);
844 return ret;
847 /******************************************************************************
848 * UnlockServiceDatabase [ADVAPI32.@]
850 BOOL WINAPI UnlockServiceDatabase (SC_LOCK ScLock)
852 TRACE("%p\n",ScLock);
854 return CloseHandle( ScLock );
857 /******************************************************************************
858 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
860 SERVICE_STATUS_HANDLE WINAPI
861 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName, LPHANDLER_FUNCTION lpfHandler )
863 LPWSTR lpServiceNameW;
864 SERVICE_STATUS_HANDLE ret;
866 lpServiceNameW = SERV_dup(lpServiceName);
867 ret = RegisterServiceCtrlHandlerW( lpServiceNameW, lpfHandler );
868 SERV_free(lpServiceNameW);
869 return ret;
872 /******************************************************************************
873 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
875 * PARAMS
876 * lpServiceName []
877 * lpfHandler []
879 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName,
880 LPHANDLER_FUNCTION lpfHandler )
882 service_data *service;
884 EnterCriticalSection( &service_cs );
885 for(service = service_list; service; service = service->next)
886 if(!strcmpW(lpServiceName, service->name))
887 break;
888 if (service)
889 service->handler = lpfHandler;
890 LeaveCriticalSection( &service_cs );
892 return (SERVICE_STATUS_HANDLE)service;
895 /******************************************************************************
896 * SetServiceStatus [ADVAPI32.@]
898 * PARAMS
899 * hService []
900 * lpStatus []
902 BOOL WINAPI
903 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
905 service_data *service;
906 BOOL r = TRUE;
908 TRACE("%p %lx %lx %lx %lx %lx %lx %lx\n", hService,
909 lpStatus->dwServiceType, lpStatus->dwCurrentState,
910 lpStatus->dwControlsAccepted, lpStatus->dwWin32ExitCode,
911 lpStatus->dwServiceSpecificExitCode, lpStatus->dwCheckPoint,
912 lpStatus->dwWaitHint);
914 EnterCriticalSection( &service_cs );
915 for (service = service_list; service; service = service->next)
916 if(service == (service_data*)hService)
917 break;
918 if (service)
920 memcpy( &service->status, lpStatus, sizeof(SERVICE_STATUS) );
921 TRACE("Set service status to %ld\n",service->status.dwCurrentState);
923 else
924 r = FALSE;
925 LeaveCriticalSection( &service_cs );
927 return r;
931 /******************************************************************************
932 * OpenSCManagerA [ADVAPI32.@]
934 * Establish a connection to the service control manager and open its database.
936 * PARAMS
937 * lpMachineName [I] Pointer to machine name string
938 * lpDatabaseName [I] Pointer to database name string
939 * dwDesiredAccess [I] Type of access
941 * RETURNS
942 * Success: A Handle to the service control manager database
943 * Failure: NULL
945 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
946 DWORD dwDesiredAccess )
948 LPWSTR lpMachineNameW, lpDatabaseNameW;
949 SC_HANDLE ret;
951 lpMachineNameW = SERV_dup(lpMachineName);
952 lpDatabaseNameW = SERV_dup(lpDatabaseName);
953 ret = OpenSCManagerW(lpMachineNameW, lpDatabaseNameW, dwDesiredAccess);
954 SERV_free(lpDatabaseNameW);
955 SERV_free(lpMachineNameW);
956 return ret;
959 /******************************************************************************
960 * OpenSCManagerW [ADVAPI32.@]
962 * See OpenSCManagerA.
964 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
965 DWORD dwDesiredAccess )
967 struct sc_manager *manager;
968 HKEY hReg;
969 LONG r;
971 TRACE("(%s,%s,0x%08lx)\n", debugstr_w(lpMachineName),
972 debugstr_w(lpDatabaseName), dwDesiredAccess);
974 if( lpDatabaseName && lpDatabaseName[0] )
976 if( strcmpiW( lpDatabaseName, SERVICES_ACTIVE_DATABASEW ) == 0 )
978 /* noop, all right */
980 else if( strcmpiW( lpDatabaseName, SERVICES_FAILED_DATABASEW ) == 0 )
982 SetLastError( ERROR_DATABASE_DOES_NOT_EXIST );
983 return NULL;
985 else
987 SetLastError( ERROR_INVALID_NAME );
988 return NULL;
992 manager = sc_handle_alloc( SC_HTYPE_MANAGER, sizeof (struct sc_manager),
993 sc_handle_destroy_manager );
994 if (!manager)
995 return NULL;
997 r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
998 if (r!=ERROR_SUCCESS)
999 goto error;
1001 r = RegOpenKeyExW(hReg, szServiceManagerKey,
1002 0, KEY_ALL_ACCESS, &manager->hkey);
1003 RegCloseKey( hReg );
1004 if (r!=ERROR_SUCCESS)
1005 goto error;
1007 TRACE("returning %p\n", manager);
1009 return (SC_HANDLE) &manager->hdr;
1011 error:
1012 sc_handle_free( &manager->hdr );
1013 SetLastError( r);
1014 return NULL;
1017 /******************************************************************************
1018 * ControlService [ADVAPI32.@]
1020 * Send a control code to a service.
1022 * PARAMS
1023 * hService [I] Handle of the service control manager database
1024 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
1025 * lpServiceStatus [O] Destination for the status of the service, if available
1027 * RETURNS
1028 * Success: TRUE.
1029 * Failure: FALSE.
1031 * BUGS
1032 * Unlike M$' implementation, control requests are not serialized and may be
1033 * processed asynchronously.
1035 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
1036 LPSERVICE_STATUS lpServiceStatus )
1038 struct sc_service *hsvc;
1039 BOOL ret = FALSE;
1040 HANDLE handle;
1042 TRACE("%p %ld %p\n", hService, dwControl, lpServiceStatus);
1044 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1045 if (!hsvc)
1047 SetLastError( ERROR_INVALID_HANDLE );
1048 return FALSE;
1051 ret = QueryServiceStatus(hService, lpServiceStatus);
1052 if (!ret)
1054 ERR("failed to query service status\n");
1055 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1056 return FALSE;
1059 switch (lpServiceStatus->dwCurrentState)
1061 case SERVICE_STOPPED:
1062 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1063 return FALSE;
1064 case SERVICE_START_PENDING:
1065 if (dwControl==SERVICE_CONTROL_STOP)
1066 break;
1067 /* fall thru */
1068 case SERVICE_STOP_PENDING:
1069 SetLastError(ERROR_SERVICE_CANNOT_ACCEPT_CTRL);
1070 return FALSE;
1073 handle = service_open_pipe(hsvc->name);
1074 if (handle!=INVALID_HANDLE_VALUE)
1076 DWORD result = ERROR_SUCCESS;
1077 ret = service_send_control(handle, dwControl, &result);
1078 CloseHandle(handle);
1079 if (result!=ERROR_SUCCESS)
1081 SetLastError(result);
1082 ret = FALSE;
1086 return ret;
1089 /******************************************************************************
1090 * CloseServiceHandle [ADVAPI32.@]
1092 * Close a handle to a service or the service control manager database.
1094 * PARAMS
1095 * hSCObject [I] Handle to service or service control manager database
1097 * RETURNS
1098 * Success: TRUE
1099 * Failure: FALSE
1101 BOOL WINAPI
1102 CloseServiceHandle( SC_HANDLE hSCObject )
1104 TRACE("%p\n", hSCObject);
1106 sc_handle_free( (struct sc_handle*) hSCObject );
1108 return TRUE;
1112 /******************************************************************************
1113 * OpenServiceA [ADVAPI32.@]
1115 * Open a handle to a service.
1117 * PARAMS
1118 * hSCManager [I] Handle of the service control manager database
1119 * lpServiceName [I] Name of the service to open
1120 * dwDesiredAccess [I] Access required to the service
1122 * RETURNS
1123 * Success: Handle to the service
1124 * Failure: NULL
1126 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1127 DWORD dwDesiredAccess )
1129 LPWSTR lpServiceNameW;
1130 SC_HANDLE ret;
1132 TRACE("%p %s %ld\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
1134 lpServiceNameW = SERV_dup(lpServiceName);
1135 ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
1136 SERV_free(lpServiceNameW);
1137 return ret;
1141 /******************************************************************************
1142 * OpenServiceW [ADVAPI32.@]
1144 * See OpenServiceA.
1146 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1147 DWORD dwDesiredAccess)
1149 struct sc_manager *hscm;
1150 struct sc_service *hsvc;
1151 HKEY hKey;
1152 long r;
1153 DWORD len;
1155 TRACE("%p %s %ld\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
1157 if (!lpServiceName)
1159 SetLastError(ERROR_INVALID_ADDRESS);
1160 return NULL;
1163 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1164 if (!hscm)
1166 SetLastError( ERROR_INVALID_HANDLE );
1167 return FALSE;
1170 r = RegOpenKeyExW( hscm->hkey, lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
1171 if (r!=ERROR_SUCCESS)
1173 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
1174 return NULL;
1177 len = strlenW(lpServiceName)+1;
1178 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE,
1179 sizeof (struct sc_service) + len*sizeof(WCHAR),
1180 sc_handle_destroy_service );
1181 if (!hsvc)
1182 return NULL;
1183 strcpyW( hsvc->name, lpServiceName );
1184 hsvc->hkey = hKey;
1186 /* add reference to SCM handle */
1187 hscm->hdr.ref_count++;
1188 hsvc->scm = hscm;
1190 TRACE("returning %p\n",hsvc);
1192 return (SC_HANDLE) &hsvc->hdr;
1195 /******************************************************************************
1196 * CreateServiceW [ADVAPI32.@]
1198 SC_HANDLE WINAPI
1199 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1200 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
1201 DWORD dwServiceType, DWORD dwStartType,
1202 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1203 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1204 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
1205 LPCWSTR lpPassword )
1207 struct sc_manager *hscm;
1208 struct sc_service *hsvc = NULL;
1209 HKEY hKey;
1210 LONG r;
1211 DWORD dp, len;
1212 struct reg_value val[10];
1213 int n = 0;
1215 TRACE("%p %s %s\n", hSCManager,
1216 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
1218 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1219 if (!hscm)
1221 SetLastError( ERROR_INVALID_HANDLE );
1222 return NULL;
1225 r = RegCreateKeyExW(hscm->hkey, lpServiceName, 0, NULL,
1226 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
1227 if (r!=ERROR_SUCCESS)
1228 return NULL;
1230 if (dp != REG_CREATED_NEW_KEY)
1232 SetLastError(ERROR_SERVICE_EXISTS);
1233 goto error;
1236 if( lpDisplayName )
1237 service_set_string( &val[n++], szDisplayName, lpDisplayName );
1239 service_set_dword( &val[n++], szType, &dwServiceType );
1240 service_set_dword( &val[n++], szStart, &dwStartType );
1241 service_set_dword( &val[n++], szError, &dwErrorControl );
1243 if( lpBinaryPathName )
1244 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
1246 if( lpLoadOrderGroup )
1247 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
1249 if( lpDependencies )
1250 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
1252 if( lpPassword )
1253 FIXME("Don't know how to add a Password for a service.\n");
1255 if( lpServiceStartName )
1256 service_set_string( &val[n++], szDependOnService, lpServiceStartName );
1258 r = service_write_values( hKey, val, n );
1259 if( r != ERROR_SUCCESS )
1260 goto error;
1262 len = strlenW(lpServiceName)+1;
1263 len = sizeof (struct sc_service) + len*sizeof(WCHAR);
1264 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE, len, sc_handle_destroy_service );
1265 if( !hsvc )
1266 goto error;
1267 lstrcpyW( hsvc->name, lpServiceName );
1268 hsvc->hkey = hKey;
1269 hsvc->scm = hscm;
1270 hscm->hdr.ref_count++;
1272 return (SC_HANDLE) &hsvc->hdr;
1274 error:
1275 RegCloseKey( hKey );
1276 return NULL;
1280 /******************************************************************************
1281 * CreateServiceA [ADVAPI32.@]
1283 SC_HANDLE WINAPI
1284 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1285 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1286 DWORD dwServiceType, DWORD dwStartType,
1287 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1288 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1289 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1290 LPCSTR lpPassword )
1292 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1293 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1294 SC_HANDLE r;
1296 TRACE("%p %s %s\n", hSCManager,
1297 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1299 lpServiceNameW = SERV_dup( lpServiceName );
1300 lpDisplayNameW = SERV_dup( lpDisplayName );
1301 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1302 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1303 lpDependenciesW = SERV_dupmulti( lpDependencies );
1304 lpServiceStartNameW = SERV_dup( lpServiceStartName );
1305 lpPasswordW = SERV_dup( lpPassword );
1307 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1308 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1309 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1310 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1312 SERV_free( lpServiceNameW );
1313 SERV_free( lpDisplayNameW );
1314 SERV_free( lpBinaryPathNameW );
1315 SERV_free( lpLoadOrderGroupW );
1316 SERV_free( lpDependenciesW );
1317 SERV_free( lpServiceStartNameW );
1318 SERV_free( lpPasswordW );
1320 return r;
1324 /******************************************************************************
1325 * DeleteService [ADVAPI32.@]
1327 * Delete a service from the service control manager database.
1329 * PARAMS
1330 * hService [I] Handle of the service to delete
1332 * RETURNS
1333 * Success: TRUE
1334 * Failure: FALSE
1336 BOOL WINAPI DeleteService( SC_HANDLE hService )
1338 struct sc_service *hsvc;
1339 HKEY hKey;
1340 WCHAR valname[MAX_PATH+1];
1341 INT index = 0;
1342 LONG rc;
1343 DWORD size;
1345 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1346 if (!hsvc)
1348 SetLastError( ERROR_INVALID_HANDLE );
1349 return FALSE;
1351 hKey = hsvc->hkey;
1353 size = MAX_PATH+1;
1354 /* Clean out the values */
1355 rc = RegEnumValueW(hKey, index, valname,&size,0,0,0,0);
1356 while (rc == ERROR_SUCCESS)
1358 RegDeleteValueW(hKey,valname);
1359 index++;
1360 size = MAX_PATH+1;
1361 rc = RegEnumValueW(hKey, index, valname, &size,0,0,0,0);
1364 RegCloseKey(hKey);
1365 hsvc->hkey = NULL;
1367 /* delete the key */
1368 RegDeleteKeyW(hsvc->scm->hkey, hsvc->name);
1370 return TRUE;
1374 /******************************************************************************
1375 * StartServiceA [ADVAPI32.@]
1377 * Start a service
1379 * PARAMS
1380 * hService [I] Handle of service
1381 * dwNumServiceArgs [I] Number of arguments
1382 * lpServiceArgVectors [I] Address of array of argument strings
1384 * NOTES
1385 * - NT implements this function using an obscure RPC call.
1386 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1387 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1388 * - This will only work for shared address space. How should the service
1389 * args be transferred when address spaces are separated?
1390 * - Can only start one service at a time.
1391 * - Has no concept of privilege.
1393 * RETURNS
1394 * Success: TRUE.
1395 * Failure: FALSE
1397 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1398 LPCSTR *lpServiceArgVectors )
1400 LPWSTR *lpwstr=NULL;
1401 unsigned int i;
1402 BOOL r;
1404 TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1406 if (dwNumServiceArgs)
1407 lpwstr = HeapAlloc( GetProcessHeap(), 0,
1408 dwNumServiceArgs*sizeof(LPWSTR) );
1410 for(i=0; i<dwNumServiceArgs; i++)
1411 lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1413 r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1415 if (dwNumServiceArgs)
1417 for(i=0; i<dwNumServiceArgs; i++)
1418 SERV_free(lpwstr[i]);
1419 HeapFree(GetProcessHeap(), 0, lpwstr);
1422 return r;
1425 /******************************************************************************
1426 * service_start_process [INTERNAL]
1428 static DWORD service_start_process(struct sc_service *hsvc)
1430 static const WCHAR _ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0};
1431 PROCESS_INFORMATION pi;
1432 STARTUPINFOW si;
1433 LPWSTR path = NULL, str;
1434 DWORD type, size, ret;
1435 HANDLE handles[2];
1436 BOOL r;
1438 /* read the executable path from memory */
1439 size = 0;
1440 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, NULL, &size);
1441 if (ret!=ERROR_SUCCESS)
1442 return FALSE;
1443 str = HeapAlloc(GetProcessHeap(),0,size);
1444 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, (LPBYTE)str, &size);
1445 if (ret==ERROR_SUCCESS)
1447 size = ExpandEnvironmentStringsW(str,NULL,0);
1448 path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
1449 ExpandEnvironmentStringsW(str,path,size);
1451 HeapFree(GetProcessHeap(),0,str);
1452 if (!path)
1453 return FALSE;
1455 /* wait for the process to start and set an event or terminate */
1456 handles[0] = service_get_event_handle( hsvc->name );
1457 ZeroMemory(&si, sizeof(STARTUPINFOW));
1458 si.cb = sizeof(STARTUPINFOW);
1459 r = CreateProcessW(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1460 if (r)
1462 handles[1] = pi.hProcess;
1463 ret = WaitForMultipleObjectsEx(2, handles, FALSE, 30000, FALSE);
1464 if(ret != WAIT_OBJECT_0)
1466 SetLastError(ERROR_IO_PENDING);
1467 r = FALSE;
1470 CloseHandle( pi.hThread );
1471 CloseHandle( pi.hProcess );
1473 CloseHandle( handles[0] );
1474 HeapFree(GetProcessHeap(),0,path);
1475 return r;
1478 static BOOL service_wait_for_startup(SC_HANDLE hService)
1480 DWORD i;
1481 SERVICE_STATUS status;
1482 BOOL r = FALSE;
1484 TRACE("%p\n", hService);
1486 for (i=0; i<30; i++)
1488 status.dwCurrentState = 0;
1489 r = QueryServiceStatus(hService, &status);
1490 if (!r)
1491 break;
1492 if (status.dwCurrentState == SERVICE_RUNNING)
1494 TRACE("Service started successfully\n");
1495 break;
1497 r = FALSE;
1498 Sleep(1000);
1500 return r;
1503 /******************************************************************************
1504 * StartServiceW [ADVAPI32.@]
1506 * See StartServiceA.
1508 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1509 LPCWSTR *lpServiceArgVectors)
1511 struct sc_service *hsvc;
1512 BOOL r = FALSE;
1513 SC_LOCK hLock;
1514 HANDLE handle = INVALID_HANDLE_VALUE;
1516 TRACE("%p %ld %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1518 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1519 if (!hsvc)
1521 SetLastError(ERROR_INVALID_HANDLE);
1522 return r;
1525 hLock = LockServiceDatabase((SC_HANDLE)hsvc->scm);
1526 if (!hLock)
1527 return r;
1529 handle = service_open_pipe(hsvc->name);
1530 if (handle==INVALID_HANDLE_VALUE)
1532 /* start the service process */
1533 if (service_start_process(hsvc))
1534 handle = service_open_pipe(hsvc->name);
1537 if (handle != INVALID_HANDLE_VALUE)
1539 service_send_start_message(handle, lpServiceArgVectors, dwNumServiceArgs);
1540 CloseHandle(handle);
1541 r = TRUE;
1544 UnlockServiceDatabase( hLock );
1546 TRACE("returning %d\n", r);
1548 if (r)
1549 service_wait_for_startup(hService);
1551 return r;
1554 /******************************************************************************
1555 * QueryServiceStatus [ADVAPI32.@]
1557 * PARAMS
1558 * hService []
1559 * lpservicestatus []
1562 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1563 LPSERVICE_STATUS lpservicestatus)
1565 struct sc_service *hsvc;
1566 DWORD size, type, val;
1567 HANDLE pipe;
1568 LONG r;
1570 TRACE("%p %p\n", hService, lpservicestatus);
1572 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1573 if (!hsvc)
1575 SetLastError( ERROR_INVALID_HANDLE );
1576 return FALSE;
1579 pipe = service_open_pipe(hsvc->name);
1580 if (pipe != INVALID_HANDLE_VALUE)
1582 r = service_get_status(pipe, lpservicestatus);
1583 CloseHandle(pipe);
1584 if (r)
1585 return TRUE;
1588 TRACE("Failed to read service status\n");
1590 /* read the service type from the registry */
1591 size = sizeof(val);
1592 r = RegQueryValueExA(hsvc->hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1593 if(r!=ERROR_SUCCESS || type!=REG_DWORD)
1594 val = 0;
1596 lpservicestatus->dwServiceType = val;
1597 lpservicestatus->dwCurrentState = SERVICE_STOPPED; /* stopped */
1598 lpservicestatus->dwControlsAccepted = 0;
1599 lpservicestatus->dwWin32ExitCode = ERROR_SERVICE_NEVER_STARTED;
1600 lpservicestatus->dwServiceSpecificExitCode = 0;
1601 lpservicestatus->dwCheckPoint = 0;
1602 lpservicestatus->dwWaitHint = 0;
1604 return TRUE;
1607 /******************************************************************************
1608 * QueryServiceStatusEx [ADVAPI32.@]
1610 * Get information about a service.
1612 * PARAMS
1613 * hService [I] Handle to service to get information about
1614 * InfoLevel [I] Level of information to get
1615 * lpBuffer [O] Destination for requested information
1616 * cbBufSize [I] Size of lpBuffer in bytes
1617 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1619 * RETURNS
1620 * Success: TRUE
1621 * FAILURE: FALSE
1623 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1624 LPBYTE lpBuffer, DWORD cbBufSize,
1625 LPDWORD pcbBytesNeeded)
1627 FIXME("stub\n");
1628 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1629 return FALSE;
1632 /******************************************************************************
1633 * QueryServiceConfigA [ADVAPI32.@]
1635 BOOL WINAPI
1636 QueryServiceConfigA( SC_HANDLE hService,
1637 LPQUERY_SERVICE_CONFIGA lpServiceConfig,
1638 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1640 static const CHAR szDisplayName[] = "DisplayName";
1641 static const CHAR szType[] = "Type";
1642 static const CHAR szStart[] = "Start";
1643 static const CHAR szError[] = "ErrorControl";
1644 static const CHAR szImagePath[] = "ImagePath";
1645 static const CHAR szGroup[] = "Group";
1646 static const CHAR szDependencies[] = "Dependencies";
1647 struct sc_service *hsvc;
1648 HKEY hKey;
1649 CHAR str_buffer[ MAX_PATH ];
1650 LONG r;
1651 DWORD type, val, sz, total, n;
1652 LPSTR p;
1654 TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
1655 cbBufSize, pcbBytesNeeded);
1657 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1658 if (!hsvc)
1660 SetLastError( ERROR_INVALID_HANDLE );
1661 return FALSE;
1663 hKey = hsvc->hkey;
1665 /* calculate the size required first */
1666 total = sizeof (QUERY_SERVICE_CONFIGA);
1668 sz = sizeof(str_buffer);
1669 r = RegQueryValueExA( hKey, szImagePath, 0, &type, (LPBYTE)str_buffer, &sz );
1670 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1672 sz = ExpandEnvironmentStringsA(str_buffer,NULL,0);
1673 if( 0 == sz ) return FALSE;
1675 total += sz;
1677 else
1679 /* FIXME: set last error */
1680 return FALSE;
1683 sz = 0;
1684 r = RegQueryValueExA( hKey, szGroup, 0, &type, NULL, &sz );
1685 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1686 total += sz;
1688 sz = 0;
1689 r = RegQueryValueExA( hKey, szDependencies, 0, &type, NULL, &sz );
1690 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1691 total += sz;
1693 sz = 0;
1694 r = RegQueryValueExA( hKey, szStart, 0, &type, NULL, &sz );
1695 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1696 total += sz;
1698 sz = 0;
1699 r = RegQueryValueExA( hKey, szDisplayName, 0, &type, NULL, &sz );
1700 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1701 total += sz;
1703 *pcbBytesNeeded = total;
1705 /* if there's not enough memory, return an error */
1706 if( total > cbBufSize )
1708 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1709 return FALSE;
1712 ZeroMemory( lpServiceConfig, total );
1714 sz = sizeof val;
1715 r = RegQueryValueExA( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1716 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1717 lpServiceConfig->dwServiceType = val;
1719 sz = sizeof val;
1720 r = RegQueryValueExA( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1721 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1722 lpServiceConfig->dwStartType = val;
1724 sz = sizeof val;
1725 r = RegQueryValueExA( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1726 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1727 lpServiceConfig->dwErrorControl = val;
1729 /* now do the strings */
1730 p = (LPSTR) &lpServiceConfig[1];
1731 n = total - sizeof (QUERY_SERVICE_CONFIGA);
1733 sz = sizeof(str_buffer);
1734 r = RegQueryValueExA( hKey, szImagePath, 0, &type, (LPBYTE)str_buffer, &sz );
1735 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1737 sz = ExpandEnvironmentStringsA(str_buffer, p, n);
1738 if( 0 == sz || sz > n ) return FALSE;
1740 lpServiceConfig->lpBinaryPathName = p;
1741 p += sz;
1742 n -= sz;
1744 else
1746 /* FIXME: set last error */
1747 return FALSE;
1750 sz = n;
1751 r = RegQueryValueExA( hKey, szGroup, 0, &type, (LPBYTE)p, &sz );
1752 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1754 lpServiceConfig->lpLoadOrderGroup = p;
1755 p += sz;
1756 n -= sz;
1759 sz = n;
1760 r = RegQueryValueExA( hKey, szDependencies, 0, &type, (LPBYTE)p, &sz );
1761 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1763 lpServiceConfig->lpDependencies = p;
1764 p += sz;
1765 n -= sz;
1768 if( n < 0 )
1769 ERR("Buffer overflow!\n");
1771 TRACE("Image path = %s\n", lpServiceConfig->lpBinaryPathName );
1772 TRACE("Group = %s\n", lpServiceConfig->lpLoadOrderGroup );
1774 return TRUE;
1777 /******************************************************************************
1778 * QueryServiceConfigW [ADVAPI32.@]
1780 BOOL WINAPI
1781 QueryServiceConfigW( SC_HANDLE hService,
1782 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1783 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1785 WCHAR str_buffer[ MAX_PATH ];
1786 LONG r;
1787 DWORD type, val, sz, total, n;
1788 LPBYTE p;
1789 HKEY hKey;
1790 struct sc_service *hsvc;
1792 TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
1793 cbBufSize, pcbBytesNeeded);
1795 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1796 if (!hsvc)
1798 SetLastError( ERROR_INVALID_HANDLE );
1799 return FALSE;
1801 hKey = hsvc->hkey;
1803 /* calculate the size required first */
1804 total = sizeof (QUERY_SERVICE_CONFIGW);
1806 sz = sizeof(str_buffer);
1807 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1808 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1810 sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1811 if( 0 == sz ) return FALSE;
1813 total += sizeof(WCHAR) * sz;
1815 else
1817 /* FIXME: set last error */
1818 return FALSE;
1821 sz = 0;
1822 r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1823 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1824 total += sz;
1826 sz = 0;
1827 r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1828 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1829 total += sz;
1830 else
1831 total += sizeof(WCHAR);
1833 sz = 0;
1834 r = RegQueryValueExW( hKey, szStart, 0, &type, NULL, &sz );
1835 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1836 total += sz;
1838 sz = 0;
1839 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1840 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1841 total += sz;
1843 *pcbBytesNeeded = total;
1845 /* if there's not enough memory, return an error */
1846 if( total > cbBufSize )
1848 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1849 return FALSE;
1852 ZeroMemory( lpServiceConfig, total );
1854 sz = sizeof val;
1855 r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1856 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1857 lpServiceConfig->dwServiceType = val;
1859 sz = sizeof val;
1860 r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1861 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1862 lpServiceConfig->dwStartType = val;
1864 sz = sizeof val;
1865 r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1866 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1867 lpServiceConfig->dwErrorControl = val;
1869 /* now do the strings */
1870 p = (LPBYTE) &lpServiceConfig[1];
1871 n = total - sizeof (QUERY_SERVICE_CONFIGW);
1873 sz = sizeof(str_buffer);
1874 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1875 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1877 sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
1878 sz *= sizeof(WCHAR);
1879 if( 0 == sz || sz > n ) return FALSE;
1881 lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
1882 p += sz;
1883 n -= sz;
1885 else
1887 /* FIXME: set last error */
1888 return FALSE;
1891 sz = n;
1892 r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
1893 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1895 lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
1896 p += sz;
1897 n -= sz;
1900 sz = n;
1901 r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
1902 lpServiceConfig->lpDependencies = (LPWSTR) p;
1903 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1905 p += sz;
1906 n -= sz;
1908 else
1910 *(WCHAR *) p = 0;
1911 p += sizeof(WCHAR);
1912 n -= sizeof(WCHAR);
1915 if( n < 0 )
1916 ERR("Buffer overflow!\n");
1918 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1919 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1921 return TRUE;
1924 /******************************************************************************
1925 * EnumServicesStatusA [ADVAPI32.@]
1927 BOOL WINAPI
1928 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
1929 DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
1930 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1931 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1933 FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
1934 dwServiceType, dwServiceState, lpServices, cbBufSize,
1935 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
1936 SetLastError (ERROR_ACCESS_DENIED);
1937 return FALSE;
1940 /******************************************************************************
1941 * EnumServicesStatusW [ADVAPI32.@]
1943 BOOL WINAPI
1944 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
1945 DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
1946 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1947 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1949 FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
1950 dwServiceType, dwServiceState, lpServices, cbBufSize,
1951 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
1952 SetLastError (ERROR_ACCESS_DENIED);
1953 return FALSE;
1956 /******************************************************************************
1957 * GetServiceKeyNameA [ADVAPI32.@]
1959 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
1960 LPSTR lpServiceName, LPDWORD lpcchBuffer )
1962 FIXME("%p %s %p %p\n", hSCManager, debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
1963 return FALSE;
1966 /******************************************************************************
1967 * GetServiceKeyNameW [ADVAPI32.@]
1969 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
1970 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
1972 FIXME("%p %s %p %p\n", hSCManager, debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
1973 return FALSE;
1976 /******************************************************************************
1977 * QueryServiceLockStatusA [ADVAPI32.@]
1979 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
1980 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
1981 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1983 FIXME("%p %p %08lx %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1985 return FALSE;
1988 /******************************************************************************
1989 * QueryServiceLockStatusW [ADVAPI32.@]
1991 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
1992 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
1993 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1995 FIXME("%p %p %08lx %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1997 return FALSE;
2000 /******************************************************************************
2001 * GetServiceDisplayNameA [ADVAPI32.@]
2003 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
2004 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
2006 FIXME("%p %s %p %p\n", hSCManager,
2007 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
2008 return FALSE;
2011 /******************************************************************************
2012 * GetServiceDisplayNameW [ADVAPI32.@]
2014 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
2015 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
2017 FIXME("%p %s %p %p\n", hSCManager,
2018 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
2019 return FALSE;
2022 /******************************************************************************
2023 * ChangeServiceConfigW [ADVAPI32.@]
2025 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
2026 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
2027 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
2028 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
2030 struct reg_value val[10];
2031 struct sc_service *hsvc;
2032 DWORD r = ERROR_SUCCESS;
2033 HKEY hKey;
2034 int n = 0;
2036 TRACE("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
2037 hService, dwServiceType, dwStartType, dwErrorControl,
2038 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2039 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2040 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2042 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2043 if (!hsvc)
2045 SetLastError( ERROR_INVALID_HANDLE );
2046 return FALSE;
2048 hKey = hsvc->hkey;
2050 if( dwServiceType != SERVICE_NO_CHANGE )
2051 service_set_dword( &val[n++], szType, &dwServiceType );
2053 if( dwStartType != SERVICE_NO_CHANGE )
2054 service_set_dword( &val[n++], szStart, &dwStartType );
2056 if( dwErrorControl != SERVICE_NO_CHANGE )
2057 service_set_dword( &val[n++], szError, &dwErrorControl );
2059 if( lpBinaryPathName )
2060 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
2062 if( lpLoadOrderGroup )
2063 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
2065 if( lpDependencies )
2066 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
2068 if( lpPassword )
2069 FIXME("ignoring password\n");
2071 if( lpServiceStartName )
2072 service_set_string( &val[n++], szDependOnService, lpServiceStartName );
2074 r = service_write_values( hsvc->hkey, val, n );
2076 return (r == ERROR_SUCCESS) ? TRUE : FALSE ;
2079 /******************************************************************************
2080 * ChangeServiceConfigA [ADVAPI32.@]
2082 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2083 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2084 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2085 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2087 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2088 LPWSTR wServiceStartName, wPassword, wDisplayName;
2089 BOOL r;
2091 TRACE("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
2092 hService, dwServiceType, dwStartType, dwErrorControl,
2093 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2094 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2095 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2097 wBinaryPathName = SERV_dup( lpBinaryPathName );
2098 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2099 wDependencies = SERV_dupmulti( lpDependencies );
2100 wServiceStartName = SERV_dup( lpServiceStartName );
2101 wPassword = SERV_dup( lpPassword );
2102 wDisplayName = SERV_dup( lpDisplayName );
2104 r = ChangeServiceConfigW( hService, dwServiceType,
2105 dwStartType, dwErrorControl, wBinaryPathName,
2106 wLoadOrderGroup, lpdwTagId, wDependencies,
2107 wServiceStartName, wPassword, wDisplayName);
2109 SERV_free( wBinaryPathName );
2110 SERV_free( wLoadOrderGroup );
2111 SERV_free( wDependencies );
2112 SERV_free( wServiceStartName );
2113 SERV_free( wPassword );
2114 SERV_free( wDisplayName );
2116 return r;
2119 /******************************************************************************
2120 * ChangeServiceConfig2A [ADVAPI32.@]
2122 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2123 LPVOID lpInfo)
2125 BOOL r = FALSE;
2127 TRACE("%p %ld %p\n",hService, dwInfoLevel, lpInfo);
2129 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2131 LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
2132 SERVICE_DESCRIPTIONW sdw;
2134 sdw.lpDescription = SERV_dup( sd->lpDescription );
2136 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2138 SERV_free( sdw.lpDescription );
2140 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2142 LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
2143 SERVICE_FAILURE_ACTIONSW faw;
2145 faw.dwResetPeriod = fa->dwResetPeriod;
2146 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2147 faw.lpCommand = SERV_dup( fa->lpCommand );
2148 faw.cActions = fa->cActions;
2149 faw.lpsaActions = fa->lpsaActions;
2151 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2153 SERV_free( faw.lpRebootMsg );
2154 SERV_free( faw.lpCommand );
2156 else
2157 SetLastError( ERROR_INVALID_PARAMETER );
2159 return r;
2162 /******************************************************************************
2163 * ChangeServiceConfig2W [ADVAPI32.@]
2165 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2166 LPVOID lpInfo)
2168 HKEY hKey;
2169 struct sc_service *hsvc;
2171 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2172 if (!hsvc)
2174 SetLastError( ERROR_INVALID_HANDLE );
2175 return FALSE;
2177 hKey = hsvc->hkey;
2179 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2181 static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2182 LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
2183 if (sd->lpDescription)
2185 TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
2186 if (sd->lpDescription[0] == 0)
2187 RegDeleteValueW(hKey,szDescription);
2188 else
2189 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2190 (LPVOID)sd->lpDescription,
2191 sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2194 else
2195 FIXME("STUB: %p %ld %p\n",hService, dwInfoLevel, lpInfo);
2196 return TRUE;
2199 /******************************************************************************
2200 * QueryServiceObjectSecurity [ADVAPI32.@]
2202 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2203 SECURITY_INFORMATION dwSecurityInformation,
2204 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2205 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2207 PACL pACL = NULL;
2209 FIXME("%p %ld %p %lu %p\n", hService, dwSecurityInformation,
2210 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2212 InitializeSecurityDescriptor(lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
2214 pACL = HeapAlloc( GetProcessHeap(), 0, sizeof(ACL) );
2215 InitializeAcl(pACL, sizeof(ACL), ACL_REVISION);
2216 SetSecurityDescriptorDacl(lpSecurityDescriptor, TRUE, pACL, TRUE);
2217 return TRUE;
2220 /******************************************************************************
2221 * SetServiceObjectSecurity [ADVAPI32.@]
2223 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2224 SECURITY_INFORMATION dwSecurityInformation,
2225 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2227 FIXME("%p %ld %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2228 return TRUE;
2231 /******************************************************************************
2232 * SetServiceBits [ADVAPI32.@]
2234 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2235 DWORD dwServiceBits,
2236 BOOL bSetBitsOn,
2237 BOOL bUpdateImmediately)
2239 FIXME("%p %08lx %x %x\n", hServiceStatus, dwServiceBits,
2240 bSetBitsOn, bUpdateImmediately);
2241 return TRUE;
2244 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR lpServiceName,
2245 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2247 FIXME("%s %p %p\n", debugstr_a(lpServiceName), lpHandlerProc, lpContext);
2248 return 0;
2251 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2252 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2254 FIXME("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2255 return 0;