Added stub for RegisterServiceCtrlHandlerEx{A,W}.
[wine/multimedia.git] / dlls / advapi32 / service.c
blob94aad59bb8b14d91b76c03356e062f4d39f871cd
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 (info->unicode)
365 LPWSTR *argv, p;
367 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPWSTR));
368 for (argc=0, p=str; *p; p += strlenW(p) + 1)
369 argv[argc++] = p;
370 argv[argc] = NULL;
372 info->proc.w(argc, argv);
373 HeapFree(GetProcessHeap(), 0, argv);
375 else
377 LPSTR strA, *argv, p;
378 DWORD lenA;
380 lenA = WideCharToMultiByte(CP_ACP,0, str, len, NULL, 0, NULL, NULL);
381 strA = HeapAlloc(GetProcessHeap(), 0, lenA);
382 WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL);
384 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPSTR));
385 for (argc=0, p=strA; *p; p += strlen(p) + 1)
386 argv[argc++] = p;
387 argv[argc] = NULL;
389 info->proc.a(argc, argv);
390 HeapFree(GetProcessHeap(), 0, argv);
391 HeapFree(GetProcessHeap(), 0, strA);
393 return 0;
396 /******************************************************************************
397 * service_handle_start
399 static BOOL service_handle_start(HANDLE pipe, service_data *service, DWORD count)
401 DWORD read = 0, result = 0;
402 LPWSTR args;
403 BOOL r;
405 TRACE("%p %p %ld\n", pipe, service, count);
407 args = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
408 r = ReadFile(pipe, args, count*sizeof(WCHAR), &read, NULL);
409 if (!r || count!=read/sizeof(WCHAR) || args[count-1])
411 ERR("pipe read failed r = %d count = %ld/%ld args[n-1]=%s\n",
412 r, count, read/sizeof(WCHAR), debugstr_wn(args, count));
413 goto end;
416 if (service->thread)
418 ERR("service is not stopped\n");
419 goto end;
422 if (service->args)
423 SERV_free(service->args);
424 service->args = args;
425 args = NULL;
426 service->thread = CreateThread( NULL, 0, service_thread,
427 service, 0, NULL );
429 end:
430 HeapFree(GetProcessHeap(), 0, args);
431 WriteFile( pipe, &result, sizeof result, &read, NULL );
433 return TRUE;
436 /******************************************************************************
437 * service_send_start_message
439 static BOOL service_send_start_message(HANDLE pipe, LPCWSTR *argv, DWORD argc)
441 DWORD i, len, count, result;
442 service_start_info *ssi;
443 LPWSTR p;
444 BOOL r;
446 TRACE("%p %p %ld\n", pipe, argv, argc);
448 /* calculate how much space do we need to send the startup info */
449 len = 1;
450 for (i=0; i<argc; i++)
451 len += strlenW(argv[i])+1;
453 ssi = HeapAlloc(GetProcessHeap(),0,sizeof *ssi + (len-1)*sizeof(WCHAR));
454 ssi->cmd = WINESERV_STARTINFO;
455 ssi->size = len;
457 /* copy service args into a single buffer*/
458 p = &ssi->str[0];
459 for (i=0; i<argc; i++)
461 strcpyW(p, argv[i]);
462 p += strlenW(p) + 1;
464 *p=0;
466 r = WriteFile(pipe, ssi, sizeof *ssi + len*sizeof(WCHAR), &count, NULL);
467 if (r)
468 r = ReadFile(pipe, &result, sizeof result, &count, NULL);
470 HeapFree(GetProcessHeap(),0,ssi);
472 return r;
475 /******************************************************************************
476 * service_handle_get_status
478 static BOOL service_handle_get_status(HANDLE pipe, service_data *service)
480 DWORD count = 0;
481 TRACE("\n");
482 return WriteFile(pipe, &service->status,
483 sizeof service->status, &count, NULL);
486 /******************************************************************************
487 * service_get_status
489 static BOOL service_get_status(HANDLE pipe, LPSERVICE_STATUS status)
491 DWORD cmd[2], count = 0;
492 BOOL r;
494 cmd[0] = WINESERV_GETSTATUS;
495 cmd[1] = 0;
496 r = WriteFile( pipe, cmd, sizeof cmd, &count, NULL );
497 if (!r || count != sizeof cmd)
499 ERR("service protocol error - failed to write pipe!\n");
500 return r;
502 r = ReadFile( pipe, status, sizeof *status, &count, NULL );
503 if (!r || count != sizeof *status)
504 ERR("service protocol error - failed to read pipe "
505 "r = %d count = %ld/%d!\n", r, count, sizeof *status);
506 return r;
509 /******************************************************************************
510 * service_send_control
512 static BOOL service_send_control(HANDLE pipe, DWORD dwControl, DWORD *result)
514 DWORD cmd[2], count = 0;
515 BOOL r;
517 cmd[0] = WINESERV_SENDCONTROL;
518 cmd[1] = dwControl;
519 r = WriteFile(pipe, cmd, sizeof cmd, &count, NULL);
520 if (!r || count != sizeof cmd)
522 ERR("service protocol error - failed to write pipe!\n");
523 return r;
525 r = ReadFile(pipe, result, sizeof *result, &count, NULL);
526 if (!r || count != sizeof *result)
527 ERR("service protocol error - failed to read pipe "
528 "r = %d count = %ld/%d!\n", r, count, sizeof *result);
529 return r;
532 /******************************************************************************
533 * service_accepts_control
535 static BOOL service_accepts_control(service_data *service, DWORD dwControl)
537 DWORD a = service->status.dwControlsAccepted;
539 switch (dwControl)
541 case SERVICE_CONTROL_INTERROGATE:
542 return TRUE;
543 case SERVICE_CONTROL_STOP:
544 if (a&SERVICE_ACCEPT_STOP)
545 return TRUE;
546 break;
547 case SERVICE_CONTROL_SHUTDOWN:
548 if (a&SERVICE_ACCEPT_SHUTDOWN)
549 return TRUE;
550 break;
551 case SERVICE_CONTROL_PAUSE:
552 case SERVICE_CONTROL_CONTINUE:
553 if (a&SERVICE_ACCEPT_PAUSE_CONTINUE)
554 return TRUE;
555 break;
556 case SERVICE_CONTROL_PARAMCHANGE:
557 if (a&SERVICE_ACCEPT_PARAMCHANGE)
558 return TRUE;
559 break;
560 case SERVICE_CONTROL_NETBINDADD:
561 case SERVICE_CONTROL_NETBINDREMOVE:
562 case SERVICE_CONTROL_NETBINDENABLE:
563 case SERVICE_CONTROL_NETBINDDISABLE:
564 if (a&SERVICE_ACCEPT_NETBINDCHANGE)
565 return TRUE;
567 if (1) /* (!service->handlerex) */
568 return FALSE;
569 switch (dwControl)
571 case SERVICE_CONTROL_HARDWAREPROFILECHANGE:
572 if (a&SERVICE_ACCEPT_HARDWAREPROFILECHANGE)
573 return TRUE;
574 break;
575 case SERVICE_CONTROL_POWEREVENT:
576 if (a&SERVICE_ACCEPT_POWEREVENT)
577 return TRUE;
578 break;
579 case SERVICE_CONTROL_SESSIONCHANGE:
580 if (a&SERVICE_ACCEPT_SESSIONCHANGE)
581 return TRUE;
582 break;
584 return FALSE;
587 /******************************************************************************
588 * service_handle_control
590 static BOOL service_handle_control(HANDLE pipe, service_data *service,
591 DWORD dwControl)
593 DWORD count, ret = ERROR_INVALID_SERVICE_CONTROL;
595 TRACE("received control %ld\n", dwControl);
597 if (service_accepts_control(service, dwControl) && service->handler)
599 service->handler(dwControl);
600 ret = ERROR_SUCCESS;
602 return WriteFile(pipe, &ret, sizeof ret, &count, NULL);
605 /******************************************************************************
606 * service_reap_thread
608 static DWORD service_reap_thread(service_data *service)
610 DWORD exitcode = 0;
612 if (!service->thread)
613 return 0;
614 GetExitCodeThread(service->thread, &exitcode);
615 if (exitcode!=STILL_ACTIVE)
617 CloseHandle(service->thread);
618 service->thread = 0;
620 return exitcode;
623 /******************************************************************************
624 * service_control_dispatcher
626 static DWORD WINAPI service_control_dispatcher(LPVOID arg)
628 service_data *service = arg;
629 LPWSTR name;
630 HANDLE pipe, event;
632 TRACE("%p %s\n", service, debugstr_w(service->name));
634 /* create a pipe to talk to the rest of the world with */
635 name = service_get_pipe_name(service->name);
636 pipe = CreateNamedPipeW(name, PIPE_ACCESS_DUPLEX,
637 PIPE_TYPE_BYTE|PIPE_WAIT, 1, 256, 256, 10000, NULL );
638 SERV_free(name);
640 /* let the process who started us know we've tried to create a pipe */
641 event = service_get_event_handle(service->name);
642 SetEvent(event);
643 CloseHandle(event);
645 if (pipe==INVALID_HANDLE_VALUE)
647 ERR("failed to create pipe, error = %ld\n", GetLastError());
648 return 0;
651 /* dispatcher loop */
652 while (1)
654 BOOL r;
655 DWORD count, req[2] = {0,0};
657 r = ConnectNamedPipe(pipe, NULL);
658 if (!r && GetLastError() != ERROR_PIPE_CONNECTED)
660 ERR("pipe connect failed\n");
661 break;
664 r = ReadFile( pipe, &req, sizeof req, &count, NULL );
665 if (!r || count!=sizeof req)
667 ERR("pipe read failed\n");
668 break;
671 service_reap_thread(service);
673 /* handle the request */
674 switch (req[0])
676 case WINESERV_STARTINFO:
677 service_handle_start(pipe, service, req[1]);
678 break;
679 case WINESERV_GETSTATUS:
680 service_handle_get_status(pipe, service);
681 break;
682 case WINESERV_SENDCONTROL:
683 service_handle_control(pipe, service, req[1]);
684 break;
685 default:
686 ERR("received invalid command %ld length %ld\n", req[0], req[1]);
689 FlushFileBuffers(pipe);
690 DisconnectNamedPipe(pipe);
693 CloseHandle(pipe);
694 return 1;
697 /******************************************************************************
698 * service_run_threads
700 static BOOL service_run_threads(void)
702 service_data *service;
703 DWORD count = 0, n = 0;
704 HANDLE *handles;
706 EnterCriticalSection( &service_cs );
708 /* count how many services there are */
709 for (service = service_list; service; service = service->next)
710 count++;
712 TRACE("starting %ld pipe listener threads\n", count);
714 handles = HeapAlloc(GetProcessHeap(), 0, sizeof(HANDLE)*count);
716 for (n=0, service = service_list; service; service = service->next, n++)
717 handles[n] = CreateThread( NULL, 0, service_control_dispatcher,
718 service, 0, NULL );
719 assert(n==count);
721 LeaveCriticalSection( &service_cs );
723 /* wait for all the threads to pack up and exit */
724 WaitForMultipleObjectsEx(count, handles, TRUE, INFINITE, FALSE);
726 HeapFree(GetProcessHeap(), 0, handles);
728 return TRUE;
731 /******************************************************************************
732 * StartServiceCtrlDispatcherA [ADVAPI32.@]
734 * Connects a process containing one or more services to the service control
735 * manager.
737 * PARAMS
738 * servent [I] A list of the service names and service procedures
740 BOOL WINAPI StartServiceCtrlDispatcherA( LPSERVICE_TABLE_ENTRYA servent )
742 service_data *info;
743 DWORD sz, len;
744 BOOL ret = TRUE;
746 TRACE("%p\n", servent);
748 EnterCriticalSection( &service_cs );
749 while (servent->lpServiceName)
751 LPSTR name = servent->lpServiceName;
753 len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0);
754 sz = len*sizeof(WCHAR) + sizeof *info;
755 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
756 MultiByteToWideChar(CP_ACP, 0, name, -1, info->name, len);
757 info->proc.a = servent->lpServiceProc;
758 info->unicode = FALSE;
760 /* insert into the list */
761 info->next = service_list;
762 service_list = info;
764 servent++;
766 LeaveCriticalSection( &service_cs );
768 service_run_threads();
770 return ret;
773 /******************************************************************************
774 * StartServiceCtrlDispatcherW [ADVAPI32.@]
776 * Connects a process containing one or more services to the service control
777 * manager.
779 * PARAMS
780 * servent [I] A list of the service names and service procedures
782 BOOL WINAPI StartServiceCtrlDispatcherW( LPSERVICE_TABLE_ENTRYW servent )
784 service_data *info;
785 DWORD sz, len;
786 BOOL ret = TRUE;
788 TRACE("%p\n", servent);
790 EnterCriticalSection( &service_cs );
791 while (servent->lpServiceName)
793 LPWSTR name = servent->lpServiceName;
795 len = strlenW(name);
796 sz = len*sizeof(WCHAR) + sizeof *info;
797 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
798 strcpyW(info->name, name);
799 info->proc.w = servent->lpServiceProc;
800 info->unicode = TRUE;
802 /* insert into the list */
803 info->next = service_list;
804 service_list = info;
806 servent++;
808 LeaveCriticalSection( &service_cs );
810 service_run_threads();
812 return ret;
815 /******************************************************************************
816 * LockServiceDatabase [ADVAPI32.@]
818 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
820 HANDLE ret;
822 TRACE("%p\n",hSCManager);
824 ret = CreateSemaphoreW( NULL, 1, 1, szSCMLock );
825 if( ret && GetLastError() == ERROR_ALREADY_EXISTS )
827 CloseHandle( ret );
828 ret = NULL;
829 SetLastError( ERROR_SERVICE_DATABASE_LOCKED );
832 TRACE("returning %p\n", ret);
834 return ret;
837 /******************************************************************************
838 * UnlockServiceDatabase [ADVAPI32.@]
840 BOOL WINAPI UnlockServiceDatabase (SC_LOCK ScLock)
842 TRACE("%p\n",ScLock);
844 return CloseHandle( ScLock );
847 /******************************************************************************
848 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
850 SERVICE_STATUS_HANDLE WINAPI
851 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName, LPHANDLER_FUNCTION lpfHandler )
853 LPWSTR lpServiceNameW;
854 SERVICE_STATUS_HANDLE ret;
856 lpServiceNameW = SERV_dup(lpServiceName);
857 ret = RegisterServiceCtrlHandlerW( lpServiceNameW, lpfHandler );
858 SERV_free(lpServiceNameW);
859 return ret;
862 /******************************************************************************
863 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
865 * PARAMS
866 * lpServiceName []
867 * lpfHandler []
869 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName,
870 LPHANDLER_FUNCTION lpfHandler )
872 service_data *service;
874 EnterCriticalSection( &service_cs );
875 for(service = service_list; service; service = service->next)
876 if(!strcmpW(lpServiceName, service->name))
877 break;
878 if (service)
879 service->handler = lpfHandler;
880 LeaveCriticalSection( &service_cs );
882 return (SERVICE_STATUS_HANDLE)service;
885 /******************************************************************************
886 * SetServiceStatus [ADVAPI32.@]
888 * PARAMS
889 * hService []
890 * lpStatus []
892 BOOL WINAPI
893 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
895 service_data *service;
896 BOOL r = TRUE;
898 TRACE("%p %lx %lx %lx %lx %lx %lx %lx\n", hService,
899 lpStatus->dwServiceType, lpStatus->dwCurrentState,
900 lpStatus->dwControlsAccepted, lpStatus->dwWin32ExitCode,
901 lpStatus->dwServiceSpecificExitCode, lpStatus->dwCheckPoint,
902 lpStatus->dwWaitHint);
904 EnterCriticalSection( &service_cs );
905 for (service = service_list; service; service = service->next)
906 if(service == (service_data*)hService)
907 break;
908 if (service)
910 memcpy( &service->status, lpStatus, sizeof(SERVICE_STATUS) );
911 TRACE("Set service status to %ld\n",service->status.dwCurrentState);
913 else
914 r = FALSE;
915 LeaveCriticalSection( &service_cs );
917 return r;
921 /******************************************************************************
922 * OpenSCManagerA [ADVAPI32.@]
924 * Establish a connection to the service control manager and open its database.
926 * PARAMS
927 * lpMachineName [I] Pointer to machine name string
928 * lpDatabaseName [I] Pointer to database name string
929 * dwDesiredAccess [I] Type of access
931 * RETURNS
932 * Success: A Handle to the service control manager database
933 * Failure: NULL
935 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
936 DWORD dwDesiredAccess )
938 LPWSTR lpMachineNameW, lpDatabaseNameW;
939 SC_HANDLE ret;
941 lpMachineNameW = SERV_dup(lpMachineName);
942 lpDatabaseNameW = SERV_dup(lpDatabaseName);
943 ret = OpenSCManagerW(lpMachineNameW, lpDatabaseNameW, dwDesiredAccess);
944 SERV_free(lpDatabaseNameW);
945 SERV_free(lpMachineNameW);
946 return ret;
949 /******************************************************************************
950 * OpenSCManagerW [ADVAPI32.@]
952 * See OpenSCManagerA.
954 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
955 DWORD dwDesiredAccess )
957 struct sc_manager *manager;
958 HKEY hReg;
959 LONG r;
961 TRACE("(%s,%s,0x%08lx)\n", debugstr_w(lpMachineName),
962 debugstr_w(lpDatabaseName), dwDesiredAccess);
964 if( lpDatabaseName && lpDatabaseName[0] )
966 if( strcmpiW( lpDatabaseName, SERVICES_ACTIVE_DATABASEW ) == 0 )
968 /* noop, all right */
970 else if( strcmpiW( lpDatabaseName, SERVICES_FAILED_DATABASEW ) == 0 )
972 SetLastError( ERROR_DATABASE_DOES_NOT_EXIST );
973 return NULL;
975 else
977 SetLastError( ERROR_INVALID_NAME );
978 return NULL;
982 manager = sc_handle_alloc( SC_HTYPE_MANAGER, sizeof (struct sc_manager),
983 sc_handle_destroy_manager );
984 if (!manager)
985 return NULL;
987 r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
988 if (r!=ERROR_SUCCESS)
989 goto error;
991 r = RegOpenKeyExW(hReg, szServiceManagerKey,
992 0, KEY_ALL_ACCESS, &manager->hkey);
993 RegCloseKey( hReg );
994 if (r!=ERROR_SUCCESS)
995 goto error;
997 TRACE("returning %p\n", manager);
999 return (SC_HANDLE) &manager->hdr;
1001 error:
1002 sc_handle_free( &manager->hdr );
1003 SetLastError( r);
1004 return NULL;
1007 /******************************************************************************
1008 * ControlService [ADVAPI32.@]
1010 * Send a control code to a service.
1012 * PARAMS
1013 * hService [I] Handle of the service control manager database
1014 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
1015 * lpServiceStatus [O] Destination for the status of the service, if available
1017 * RETURNS
1018 * Success: TRUE.
1019 * Failure: FALSE.
1021 * BUGS
1022 * Unlike M$' implementation, control requests are not serialized and may be
1023 * processed asynchronously.
1025 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
1026 LPSERVICE_STATUS lpServiceStatus )
1028 struct sc_service *hsvc;
1029 BOOL ret = FALSE;
1030 HANDLE handle;
1032 TRACE("%p %ld %p\n", hService, dwControl, lpServiceStatus);
1034 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1035 if (!hsvc)
1037 SetLastError( ERROR_INVALID_HANDLE );
1038 return FALSE;
1041 ret = QueryServiceStatus(hService, lpServiceStatus);
1042 if (!ret)
1044 ERR("failed to query service status\n");
1045 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1046 return FALSE;
1049 switch (lpServiceStatus->dwCurrentState)
1051 case SERVICE_STOPPED:
1052 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1053 return FALSE;
1054 case SERVICE_START_PENDING:
1055 if (dwControl==SERVICE_CONTROL_STOP)
1056 break;
1057 /* fall thru */
1058 case SERVICE_STOP_PENDING:
1059 SetLastError(ERROR_SERVICE_CANNOT_ACCEPT_CTRL);
1060 return FALSE;
1063 handle = service_open_pipe(hsvc->name);
1064 if (handle!=INVALID_HANDLE_VALUE)
1066 DWORD result = ERROR_SUCCESS;
1067 ret = service_send_control(handle, dwControl, &result);
1068 CloseHandle(handle);
1069 if (result!=ERROR_SUCCESS)
1071 SetLastError(result);
1072 ret = FALSE;
1076 return ret;
1079 /******************************************************************************
1080 * CloseServiceHandle [ADVAPI32.@]
1082 * Close a handle to a service or the service control manager database.
1084 * PARAMS
1085 * hSCObject [I] Handle to service or service control manager database
1087 * RETURNS
1088 * Success: TRUE
1089 * Failure: FALSE
1091 BOOL WINAPI
1092 CloseServiceHandle( SC_HANDLE hSCObject )
1094 TRACE("%p\n", hSCObject);
1096 sc_handle_free( (struct sc_handle*) hSCObject );
1098 return TRUE;
1102 /******************************************************************************
1103 * OpenServiceA [ADVAPI32.@]
1105 * Open a handle to a service.
1107 * PARAMS
1108 * hSCManager [I] Handle of the service control manager database
1109 * lpServiceName [I] Name of the service to open
1110 * dwDesiredAccess [I] Access required to the service
1112 * RETURNS
1113 * Success: Handle to the service
1114 * Failure: NULL
1116 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1117 DWORD dwDesiredAccess )
1119 LPWSTR lpServiceNameW;
1120 SC_HANDLE ret;
1122 TRACE("%p %s %ld\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
1124 lpServiceNameW = SERV_dup(lpServiceName);
1125 ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
1126 SERV_free(lpServiceNameW);
1127 return ret;
1131 /******************************************************************************
1132 * OpenServiceW [ADVAPI32.@]
1134 * See OpenServiceA.
1136 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1137 DWORD dwDesiredAccess)
1139 struct sc_manager *hscm;
1140 struct sc_service *hsvc;
1141 HKEY hKey;
1142 long r;
1143 DWORD len;
1145 TRACE("%p %s %ld\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
1147 if (!lpServiceName)
1149 SetLastError(ERROR_INVALID_ADDRESS);
1150 return NULL;
1153 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1154 if (!hscm)
1156 SetLastError( ERROR_INVALID_HANDLE );
1157 return FALSE;
1160 r = RegOpenKeyExW( hscm->hkey, lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
1161 if (r!=ERROR_SUCCESS)
1163 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
1164 return NULL;
1167 len = strlenW(lpServiceName)+1;
1168 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE,
1169 sizeof (struct sc_service) + len*sizeof(WCHAR),
1170 sc_handle_destroy_service );
1171 if (!hsvc)
1172 return NULL;
1173 strcpyW( hsvc->name, lpServiceName );
1174 hsvc->hkey = hKey;
1176 /* add reference to SCM handle */
1177 hscm->hdr.ref_count++;
1178 hsvc->scm = hscm;
1180 TRACE("returning %p\n",hsvc);
1182 return (SC_HANDLE) &hsvc->hdr;
1185 /******************************************************************************
1186 * CreateServiceW [ADVAPI32.@]
1188 SC_HANDLE WINAPI
1189 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1190 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
1191 DWORD dwServiceType, DWORD dwStartType,
1192 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1193 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1194 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
1195 LPCWSTR lpPassword )
1197 struct sc_manager *hscm;
1198 struct sc_service *hsvc = NULL;
1199 HKEY hKey;
1200 LONG r;
1201 DWORD dp, len;
1202 struct reg_value val[10];
1203 int n = 0;
1205 TRACE("%p %s %s\n", hSCManager,
1206 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
1208 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1209 if (!hscm)
1211 SetLastError( ERROR_INVALID_HANDLE );
1212 return NULL;
1215 r = RegCreateKeyExW(hscm->hkey, lpServiceName, 0, NULL,
1216 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
1217 if (r!=ERROR_SUCCESS)
1218 return NULL;
1220 if (dp != REG_CREATED_NEW_KEY)
1222 SetLastError(ERROR_SERVICE_EXISTS);
1223 goto error;
1226 if( lpDisplayName )
1227 service_set_string( &val[n++], szDisplayName, lpDisplayName );
1229 service_set_dword( &val[n++], szType, &dwServiceType );
1230 service_set_dword( &val[n++], szStart, &dwStartType );
1231 service_set_dword( &val[n++], szError, &dwErrorControl );
1233 if( lpBinaryPathName )
1234 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
1236 if( lpLoadOrderGroup )
1237 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
1239 if( lpDependencies )
1240 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
1242 if( lpPassword )
1243 FIXME("Don't know how to add a Password for a service.\n");
1245 if( lpServiceStartName )
1246 service_set_string( &val[n++], szDependOnService, lpServiceStartName );
1248 r = service_write_values( hKey, val, n );
1249 if( r != ERROR_SUCCESS )
1250 goto error;
1252 len = strlenW(lpServiceName)+1;
1253 len = sizeof (struct sc_service) + len*sizeof(WCHAR);
1254 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE, len, sc_handle_destroy_service );
1255 if( !hsvc )
1256 goto error;
1257 lstrcpyW( hsvc->name, lpServiceName );
1258 hsvc->hkey = hKey;
1259 hsvc->scm = hscm;
1260 hscm->hdr.ref_count++;
1262 return (SC_HANDLE) &hsvc->hdr;
1264 error:
1265 RegCloseKey( hKey );
1266 return NULL;
1270 /******************************************************************************
1271 * CreateServiceA [ADVAPI32.@]
1273 SC_HANDLE WINAPI
1274 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1275 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1276 DWORD dwServiceType, DWORD dwStartType,
1277 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1278 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1279 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1280 LPCSTR lpPassword )
1282 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1283 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1284 SC_HANDLE r;
1286 TRACE("%p %s %s\n", hSCManager,
1287 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1289 lpServiceNameW = SERV_dup( lpServiceName );
1290 lpDisplayNameW = SERV_dup( lpDisplayName );
1291 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1292 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1293 lpDependenciesW = SERV_dupmulti( lpDependencies );
1294 lpServiceStartNameW = SERV_dup( lpServiceStartName );
1295 lpPasswordW = SERV_dup( lpPassword );
1297 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1298 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1299 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1300 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1302 SERV_free( lpServiceNameW );
1303 SERV_free( lpDisplayNameW );
1304 SERV_free( lpBinaryPathNameW );
1305 SERV_free( lpLoadOrderGroupW );
1306 SERV_free( lpDependenciesW );
1307 SERV_free( lpServiceStartNameW );
1308 SERV_free( lpPasswordW );
1310 return r;
1314 /******************************************************************************
1315 * DeleteService [ADVAPI32.@]
1317 * Delete a service from the service control manager database.
1319 * PARAMS
1320 * hService [I] Handle of the service to delete
1322 * RETURNS
1323 * Success: TRUE
1324 * Failure: FALSE
1326 BOOL WINAPI DeleteService( SC_HANDLE hService )
1328 struct sc_service *hsvc;
1329 HKEY hKey;
1330 WCHAR valname[MAX_PATH+1];
1331 INT index = 0;
1332 LONG rc;
1333 DWORD size;
1335 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1336 if (!hsvc)
1338 SetLastError( ERROR_INVALID_HANDLE );
1339 return FALSE;
1341 hKey = hsvc->hkey;
1343 size = MAX_PATH+1;
1344 /* Clean out the values */
1345 rc = RegEnumValueW(hKey, index, valname,&size,0,0,0,0);
1346 while (rc == ERROR_SUCCESS)
1348 RegDeleteValueW(hKey,valname);
1349 index++;
1350 size = MAX_PATH+1;
1351 rc = RegEnumValueW(hKey, index, valname, &size,0,0,0,0);
1354 RegCloseKey(hKey);
1355 hsvc->hkey = NULL;
1357 /* delete the key */
1358 RegDeleteKeyW(hsvc->scm->hkey, hsvc->name);
1360 return TRUE;
1364 /******************************************************************************
1365 * StartServiceA [ADVAPI32.@]
1367 * Start a service
1369 * PARAMS
1370 * hService [I] Handle of service
1371 * dwNumServiceArgs [I] Number of arguments
1372 * lpServiceArgVectors [I] Address of array of argument strings
1374 * NOTES
1375 * - NT implements this function using an obscure RPC call.
1376 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1377 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1378 * - This will only work for shared address space. How should the service
1379 * args be transferred when address spaces are separated?
1380 * - Can only start one service at a time.
1381 * - Has no concept of privilege.
1383 * RETURNS
1384 * Success: TRUE.
1385 * Failure: FALSE
1387 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1388 LPCSTR *lpServiceArgVectors )
1390 LPWSTR *lpwstr=NULL;
1391 unsigned int i;
1392 BOOL r;
1394 TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1396 if (dwNumServiceArgs)
1397 lpwstr = HeapAlloc( GetProcessHeap(), 0,
1398 dwNumServiceArgs*sizeof(LPWSTR) );
1400 for(i=0; i<dwNumServiceArgs; i++)
1401 lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1403 r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1405 if (dwNumServiceArgs)
1407 for(i=0; i<dwNumServiceArgs; i++)
1408 SERV_free(lpwstr[i]);
1409 HeapFree(GetProcessHeap(), 0, lpwstr);
1412 return r;
1415 /******************************************************************************
1416 * service_start_process [INTERNAL]
1418 static DWORD service_start_process(struct sc_service *hsvc)
1420 static const WCHAR _ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0};
1421 PROCESS_INFORMATION pi;
1422 STARTUPINFOW si;
1423 LPWSTR path = NULL, str;
1424 DWORD type, size, ret;
1425 HANDLE handles[2];
1426 BOOL r;
1428 /* read the executable path from memory */
1429 size = 0;
1430 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, NULL, &size);
1431 if (ret!=ERROR_SUCCESS)
1432 return FALSE;
1433 str = HeapAlloc(GetProcessHeap(),0,size);
1434 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, (LPBYTE)str, &size);
1435 if (ret==ERROR_SUCCESS)
1437 size = ExpandEnvironmentStringsW(str,NULL,0);
1438 path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
1439 ExpandEnvironmentStringsW(str,path,size);
1441 HeapFree(GetProcessHeap(),0,str);
1442 if (!path)
1443 return FALSE;
1445 /* wait for the process to start and set an event or terminate */
1446 handles[0] = service_get_event_handle( hsvc->name );
1447 ZeroMemory(&si, sizeof(STARTUPINFOW));
1448 si.cb = sizeof(STARTUPINFOW);
1449 r = CreateProcessW(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1450 if (r)
1452 handles[1] = pi.hProcess;
1453 ret = WaitForMultipleObjectsEx(2, handles, FALSE, 30000, FALSE);
1454 if(ret != WAIT_OBJECT_0)
1456 SetLastError(ERROR_IO_PENDING);
1457 r = FALSE;
1460 CloseHandle( pi.hThread );
1461 CloseHandle( pi.hProcess );
1463 CloseHandle( handles[0] );
1464 HeapFree(GetProcessHeap(),0,path);
1465 return r;
1468 static BOOL service_wait_for_startup(SC_HANDLE hService)
1470 DWORD i;
1471 SERVICE_STATUS status;
1472 BOOL r = FALSE;
1474 TRACE("%p\n", hService);
1476 for (i=0; i<30; i++)
1478 status.dwCurrentState = 0;
1479 r = QueryServiceStatus(hService, &status);
1480 if (!r)
1481 break;
1482 if (status.dwCurrentState == SERVICE_RUNNING)
1484 TRACE("Service started successfully\n");
1485 break;
1487 r = FALSE;
1488 Sleep(1000);
1490 return r;
1493 /******************************************************************************
1494 * StartServiceW [ADVAPI32.@]
1496 * See StartServiceA.
1498 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1499 LPCWSTR *lpServiceArgVectors)
1501 struct sc_service *hsvc;
1502 BOOL r = FALSE;
1503 SC_LOCK hLock;
1504 HANDLE handle = INVALID_HANDLE_VALUE;
1506 TRACE("%p %ld %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1508 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1509 if (!hsvc)
1511 SetLastError(ERROR_INVALID_HANDLE);
1512 return r;
1515 hLock = LockServiceDatabase((SC_HANDLE)hsvc->scm);
1516 if (!hLock)
1517 return r;
1519 handle = service_open_pipe(hsvc->name);
1520 if (handle==INVALID_HANDLE_VALUE)
1522 /* start the service process */
1523 if (service_start_process(hsvc))
1524 handle = service_open_pipe(hsvc->name);
1527 if (handle != INVALID_HANDLE_VALUE)
1529 service_send_start_message(handle, lpServiceArgVectors, dwNumServiceArgs);
1530 CloseHandle(handle);
1531 r = TRUE;
1534 UnlockServiceDatabase( hLock );
1536 TRACE("returning %d\n", r);
1538 service_wait_for_startup(hService);
1540 return r;
1543 /******************************************************************************
1544 * QueryServiceStatus [ADVAPI32.@]
1546 * PARAMS
1547 * hService []
1548 * lpservicestatus []
1551 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1552 LPSERVICE_STATUS lpservicestatus)
1554 struct sc_service *hsvc;
1555 DWORD size, type, val;
1556 HANDLE pipe;
1557 LONG r;
1559 TRACE("%p %p\n", hService, lpservicestatus);
1561 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1562 if (!hsvc)
1564 SetLastError( ERROR_INVALID_HANDLE );
1565 return FALSE;
1568 pipe = service_open_pipe(hsvc->name);
1569 if (pipe != INVALID_HANDLE_VALUE)
1571 r = service_get_status(pipe, lpservicestatus);
1572 CloseHandle(pipe);
1573 if (r)
1574 return TRUE;
1577 TRACE("Failed to read service status\n");
1579 /* read the service type from the registry */
1580 size = sizeof(val);
1581 r = RegQueryValueExA(hsvc->hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1582 if(r!=ERROR_SUCCESS || type!=REG_DWORD)
1583 val = 0;
1585 lpservicestatus->dwServiceType = val;
1586 lpservicestatus->dwCurrentState = SERVICE_STOPPED; /* stopped */
1587 lpservicestatus->dwControlsAccepted = 0;
1588 lpservicestatus->dwWin32ExitCode = ERROR_SERVICE_NEVER_STARTED;
1589 lpservicestatus->dwServiceSpecificExitCode = 0;
1590 lpservicestatus->dwCheckPoint = 0;
1591 lpservicestatus->dwWaitHint = 0;
1593 return TRUE;
1596 /******************************************************************************
1597 * QueryServiceStatusEx [ADVAPI32.@]
1599 * Get information about a service.
1601 * PARAMS
1602 * hService [I] Handle to service to get information about
1603 * InfoLevel [I] Level of information to get
1604 * lpBuffer [O] Destination for requested information
1605 * cbBufSize [I] Size of lpBuffer in bytes
1606 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1608 * RETURNS
1609 * Success: TRUE
1610 * FAILURE: FALSE
1612 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1613 LPBYTE lpBuffer, DWORD cbBufSize,
1614 LPDWORD pcbBytesNeeded)
1616 FIXME("stub\n");
1617 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1618 return FALSE;
1621 /******************************************************************************
1622 * QueryServiceConfigA [ADVAPI32.@]
1624 BOOL WINAPI
1625 QueryServiceConfigA( SC_HANDLE hService,
1626 LPQUERY_SERVICE_CONFIGA lpServiceConfig,
1627 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1629 static const CHAR szDisplayName[] = "DisplayName";
1630 static const CHAR szType[] = "Type";
1631 static const CHAR szStart[] = "Start";
1632 static const CHAR szError[] = "ErrorControl";
1633 static const CHAR szImagePath[] = "ImagePath";
1634 static const CHAR szGroup[] = "Group";
1635 static const CHAR szDependencies[] = "Dependencies";
1636 struct sc_service *hsvc;
1637 HKEY hKey;
1638 CHAR str_buffer[ MAX_PATH ];
1639 LONG r;
1640 DWORD type, val, sz, total, n;
1641 LPSTR p;
1643 TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
1644 cbBufSize, pcbBytesNeeded);
1646 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1647 if (!hsvc)
1649 SetLastError( ERROR_INVALID_HANDLE );
1650 return FALSE;
1652 hKey = hsvc->hkey;
1654 /* calculate the size required first */
1655 total = sizeof (QUERY_SERVICE_CONFIGA);
1657 sz = sizeof(str_buffer);
1658 r = RegQueryValueExA( hKey, szImagePath, 0, &type, (LPBYTE)str_buffer, &sz );
1659 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1661 sz = ExpandEnvironmentStringsA(str_buffer,NULL,0);
1662 if( 0 == sz ) return FALSE;
1664 total += sz;
1666 else
1668 /* FIXME: set last error */
1669 return FALSE;
1672 sz = 0;
1673 r = RegQueryValueExA( hKey, szGroup, 0, &type, NULL, &sz );
1674 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1675 total += sz;
1677 sz = 0;
1678 r = RegQueryValueExA( hKey, szDependencies, 0, &type, NULL, &sz );
1679 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1680 total += sz;
1682 sz = 0;
1683 r = RegQueryValueExA( hKey, szStart, 0, &type, NULL, &sz );
1684 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1685 total += sz;
1687 sz = 0;
1688 r = RegQueryValueExA( hKey, szDisplayName, 0, &type, NULL, &sz );
1689 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1690 total += sz;
1692 *pcbBytesNeeded = total;
1694 /* if there's not enough memory, return an error */
1695 if( total > cbBufSize )
1697 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1698 return FALSE;
1701 ZeroMemory( lpServiceConfig, total );
1703 sz = sizeof val;
1704 r = RegQueryValueExA( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1705 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1706 lpServiceConfig->dwServiceType = val;
1708 sz = sizeof val;
1709 r = RegQueryValueExA( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1710 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1711 lpServiceConfig->dwStartType = val;
1713 sz = sizeof val;
1714 r = RegQueryValueExA( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1715 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1716 lpServiceConfig->dwErrorControl = val;
1718 /* now do the strings */
1719 p = (LPSTR) &lpServiceConfig[1];
1720 n = total - sizeof (QUERY_SERVICE_CONFIGA);
1722 sz = sizeof(str_buffer);
1723 r = RegQueryValueExA( hKey, szImagePath, 0, &type, (LPBYTE)str_buffer, &sz );
1724 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1726 sz = ExpandEnvironmentStringsA(str_buffer, p, n);
1727 if( 0 == sz || sz > n ) return FALSE;
1729 lpServiceConfig->lpBinaryPathName = p;
1730 p += sz;
1731 n -= sz;
1733 else
1735 /* FIXME: set last error */
1736 return FALSE;
1739 sz = n;
1740 r = RegQueryValueExA( hKey, szGroup, 0, &type, (LPBYTE)p, &sz );
1741 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1743 lpServiceConfig->lpLoadOrderGroup = p;
1744 p += sz;
1745 n -= sz;
1748 sz = n;
1749 r = RegQueryValueExA( hKey, szDependencies, 0, &type, (LPBYTE)p, &sz );
1750 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1752 lpServiceConfig->lpDependencies = p;
1753 p += sz;
1754 n -= sz;
1757 if( n < 0 )
1758 ERR("Buffer overflow!\n");
1760 TRACE("Image path = %s\n", lpServiceConfig->lpBinaryPathName );
1761 TRACE("Group = %s\n", lpServiceConfig->lpLoadOrderGroup );
1763 return TRUE;
1766 /******************************************************************************
1767 * QueryServiceConfigW [ADVAPI32.@]
1769 BOOL WINAPI
1770 QueryServiceConfigW( SC_HANDLE hService,
1771 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1772 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1774 WCHAR str_buffer[ MAX_PATH ];
1775 LONG r;
1776 DWORD type, val, sz, total, n;
1777 LPBYTE p;
1778 HKEY hKey;
1779 struct sc_service *hsvc;
1781 TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
1782 cbBufSize, pcbBytesNeeded);
1784 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1785 if (!hsvc)
1787 SetLastError( ERROR_INVALID_HANDLE );
1788 return FALSE;
1790 hKey = hsvc->hkey;
1792 /* calculate the size required first */
1793 total = sizeof (QUERY_SERVICE_CONFIGW);
1795 sz = sizeof(str_buffer);
1796 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1797 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1799 sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1800 if( 0 == sz ) return FALSE;
1802 total += sizeof(WCHAR) * sz;
1804 else
1806 /* FIXME: set last error */
1807 return FALSE;
1810 sz = 0;
1811 r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1812 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1813 total += sz;
1815 sz = 0;
1816 r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1817 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1818 total += sz;
1819 else
1820 total += sizeof(WCHAR);
1822 sz = 0;
1823 r = RegQueryValueExW( hKey, szStart, 0, &type, NULL, &sz );
1824 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1825 total += sz;
1827 sz = 0;
1828 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1829 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1830 total += sz;
1832 *pcbBytesNeeded = total;
1834 /* if there's not enough memory, return an error */
1835 if( total > cbBufSize )
1837 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1838 return FALSE;
1841 ZeroMemory( lpServiceConfig, total );
1843 sz = sizeof val;
1844 r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1845 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1846 lpServiceConfig->dwServiceType = val;
1848 sz = sizeof val;
1849 r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1850 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1851 lpServiceConfig->dwStartType = val;
1853 sz = sizeof val;
1854 r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1855 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1856 lpServiceConfig->dwErrorControl = val;
1858 /* now do the strings */
1859 p = (LPBYTE) &lpServiceConfig[1];
1860 n = total - sizeof (QUERY_SERVICE_CONFIGW);
1862 sz = sizeof(str_buffer);
1863 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1864 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1866 sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
1867 sz *= sizeof(WCHAR);
1868 if( 0 == sz || sz > n ) return FALSE;
1870 lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
1871 p += sz;
1872 n -= sz;
1874 else
1876 /* FIXME: set last error */
1877 return FALSE;
1880 sz = n;
1881 r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
1882 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1884 lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
1885 p += sz;
1886 n -= sz;
1889 sz = n;
1890 r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
1891 lpServiceConfig->lpDependencies = (LPWSTR) p;
1892 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1894 p += sz;
1895 n -= sz;
1897 else
1899 *(WCHAR *) p = 0;
1900 p += sizeof(WCHAR);
1901 n -= sizeof(WCHAR);
1904 if( n < 0 )
1905 ERR("Buffer overflow!\n");
1907 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1908 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1910 return TRUE;
1913 /******************************************************************************
1914 * EnumServicesStatusA [ADVAPI32.@]
1916 BOOL WINAPI
1917 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
1918 DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
1919 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1920 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1922 FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
1923 dwServiceType, dwServiceState, lpServices, cbBufSize,
1924 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
1925 SetLastError (ERROR_ACCESS_DENIED);
1926 return FALSE;
1929 /******************************************************************************
1930 * EnumServicesStatusW [ADVAPI32.@]
1932 BOOL WINAPI
1933 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
1934 DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
1935 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1936 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1938 FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
1939 dwServiceType, dwServiceState, lpServices, cbBufSize,
1940 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
1941 SetLastError (ERROR_ACCESS_DENIED);
1942 return FALSE;
1945 /******************************************************************************
1946 * GetServiceKeyNameA [ADVAPI32.@]
1948 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
1949 LPSTR lpServiceName, LPDWORD lpcchBuffer )
1951 FIXME("%p %s %p %p\n", hSCManager, debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
1952 return FALSE;
1955 /******************************************************************************
1956 * GetServiceKeyNameW [ADVAPI32.@]
1958 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
1959 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
1961 FIXME("%p %s %p %p\n", hSCManager, debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
1962 return FALSE;
1965 /******************************************************************************
1966 * QueryServiceLockStatusA [ADVAPI32.@]
1968 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
1969 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
1970 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1972 FIXME("%p %p %08lx %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1974 return FALSE;
1977 /******************************************************************************
1978 * QueryServiceLockStatusW [ADVAPI32.@]
1980 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
1981 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
1982 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1984 FIXME("%p %p %08lx %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1986 return FALSE;
1989 /******************************************************************************
1990 * GetServiceDisplayNameA [ADVAPI32.@]
1992 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1993 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
1995 FIXME("%p %s %p %p\n", hSCManager,
1996 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
1997 return FALSE;
2000 /******************************************************************************
2001 * GetServiceDisplayNameW [ADVAPI32.@]
2003 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
2004 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
2006 FIXME("%p %s %p %p\n", hSCManager,
2007 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
2008 return FALSE;
2011 /******************************************************************************
2012 * ChangeServiceConfigW [ADVAPI32.@]
2014 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
2015 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
2016 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
2017 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
2019 struct reg_value val[10];
2020 struct sc_service *hsvc;
2021 DWORD r = ERROR_SUCCESS;
2022 HKEY hKey;
2023 int n = 0;
2025 TRACE("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
2026 hService, dwServiceType, dwStartType, dwErrorControl,
2027 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2028 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2029 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2031 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2032 if (!hsvc)
2034 SetLastError( ERROR_INVALID_HANDLE );
2035 return FALSE;
2037 hKey = hsvc->hkey;
2039 if( dwServiceType != SERVICE_NO_CHANGE )
2040 service_set_dword( &val[n++], szType, &dwServiceType );
2042 if( dwStartType != SERVICE_NO_CHANGE )
2043 service_set_dword( &val[n++], szStart, &dwStartType );
2045 if( dwErrorControl != SERVICE_NO_CHANGE )
2046 service_set_dword( &val[n++], szError, &dwErrorControl );
2048 if( lpBinaryPathName )
2049 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
2051 if( lpLoadOrderGroup )
2052 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
2054 if( lpDependencies )
2055 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
2057 if( lpPassword )
2058 FIXME("ignoring password\n");
2060 if( lpServiceStartName )
2061 service_set_string( &val[n++], szDependOnService, lpServiceStartName );
2063 r = service_write_values( hsvc->hkey, val, n );
2065 return (r == ERROR_SUCCESS) ? TRUE : FALSE ;
2068 /******************************************************************************
2069 * ChangeServiceConfigA [ADVAPI32.@]
2071 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2072 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2073 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2074 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2076 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2077 LPWSTR wServiceStartName, wPassword, wDisplayName;
2078 BOOL r;
2080 TRACE("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
2081 hService, dwServiceType, dwStartType, dwErrorControl,
2082 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2083 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2084 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2086 wBinaryPathName = SERV_dup( lpBinaryPathName );
2087 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2088 wDependencies = SERV_dupmulti( lpDependencies );
2089 wServiceStartName = SERV_dup( lpServiceStartName );
2090 wPassword = SERV_dup( lpPassword );
2091 wDisplayName = SERV_dup( lpDisplayName );
2093 r = ChangeServiceConfigW( hService, dwServiceType,
2094 dwStartType, dwErrorControl, wBinaryPathName,
2095 wLoadOrderGroup, lpdwTagId, wDependencies,
2096 wServiceStartName, wPassword, wDisplayName);
2098 SERV_free( wBinaryPathName );
2099 SERV_free( wLoadOrderGroup );
2100 SERV_free( wDependencies );
2101 SERV_free( wServiceStartName );
2102 SERV_free( wPassword );
2103 SERV_free( wDisplayName );
2105 return r;
2108 /******************************************************************************
2109 * ChangeServiceConfig2A [ADVAPI32.@]
2111 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2112 LPVOID lpInfo)
2114 BOOL r = FALSE;
2116 TRACE("%p %ld %p\n",hService, dwInfoLevel, lpInfo);
2118 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2120 LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
2121 SERVICE_DESCRIPTIONW sdw;
2123 sdw.lpDescription = SERV_dup( sd->lpDescription );
2125 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2127 SERV_free( sdw.lpDescription );
2129 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2131 LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
2132 SERVICE_FAILURE_ACTIONSW faw;
2134 faw.dwResetPeriod = fa->dwResetPeriod;
2135 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2136 faw.lpCommand = SERV_dup( fa->lpCommand );
2137 faw.cActions = fa->cActions;
2138 faw.lpsaActions = fa->lpsaActions;
2140 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2142 SERV_free( faw.lpRebootMsg );
2143 SERV_free( faw.lpCommand );
2145 else
2146 SetLastError( ERROR_INVALID_PARAMETER );
2148 return r;
2151 /******************************************************************************
2152 * ChangeServiceConfig2W [ADVAPI32.@]
2154 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2155 LPVOID lpInfo)
2157 HKEY hKey;
2158 struct sc_service *hsvc;
2160 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2161 if (!hsvc)
2163 SetLastError( ERROR_INVALID_HANDLE );
2164 return FALSE;
2166 hKey = hsvc->hkey;
2168 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2170 static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2171 LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
2172 if (sd->lpDescription)
2174 TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
2175 if (sd->lpDescription[0] == 0)
2176 RegDeleteValueW(hKey,szDescription);
2177 else
2178 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2179 (LPVOID)sd->lpDescription,
2180 sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2183 else
2184 FIXME("STUB: %p %ld %p\n",hService, dwInfoLevel, lpInfo);
2185 return TRUE;
2188 /******************************************************************************
2189 * QueryServiceObjectSecurity [ADVAPI32.@]
2191 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2192 SECURITY_INFORMATION dwSecurityInformation,
2193 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2194 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2196 PACL pACL = NULL;
2198 FIXME("%p %ld %p %lu %p\n", hService, dwSecurityInformation,
2199 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2201 InitializeSecurityDescriptor(lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
2203 pACL = HeapAlloc( GetProcessHeap(), 0, sizeof(ACL) );
2204 InitializeAcl(pACL, sizeof(ACL), ACL_REVISION);
2205 SetSecurityDescriptorDacl(lpSecurityDescriptor, TRUE, pACL, TRUE);
2206 return TRUE;
2209 /******************************************************************************
2210 * SetServiceObjectSecurity [ADVAPI32.@]
2212 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2213 SECURITY_INFORMATION dwSecurityInformation,
2214 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2216 FIXME("%p %ld %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2217 return TRUE;
2220 /******************************************************************************
2221 * SetServiceBits [ADVAPI32.@]
2223 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2224 DWORD dwServiceBits,
2225 BOOL bSetBitsOn,
2226 BOOL bUpdateImmediately)
2228 FIXME("%p %08lx %x %x\n", hServiceStatus, dwServiceBits,
2229 bSetBitsOn, bUpdateImmediately);
2230 return TRUE;
2233 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR lpServiceName,
2234 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2236 FIXME("%s %p %p\n", debugstr_a(lpServiceName), lpHandlerProc, lpContext);
2237 return 0;
2240 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2241 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2243 FIXME("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2244 return 0;