shell32: Added some test to document native ITEMIDLIST format.
[wine.git] / dlls / advapi32 / service.c
blobcc6a36c28d5840d0d3a0f2ee95f4c10e57d6e61f
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 * See StartServiceCtrlDispatcherW.
736 BOOL WINAPI StartServiceCtrlDispatcherA( LPSERVICE_TABLE_ENTRYA servent )
738 service_data *info;
739 DWORD sz, len;
740 BOOL ret = TRUE;
742 TRACE("%p\n", servent);
744 EnterCriticalSection( &service_cs );
745 while (servent->lpServiceName)
747 LPSTR name = servent->lpServiceName;
749 len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0);
750 sz = len*sizeof(WCHAR) + sizeof *info;
751 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
752 MultiByteToWideChar(CP_ACP, 0, name, -1, info->name, len);
753 info->proc.a = servent->lpServiceProc;
754 info->unicode = FALSE;
756 /* insert into the list */
757 info->next = service_list;
758 service_list = info;
760 servent++;
762 LeaveCriticalSection( &service_cs );
764 service_run_threads();
766 return ret;
769 /******************************************************************************
770 * StartServiceCtrlDispatcherW [ADVAPI32.@]
772 * Connects a process containing one or more services to the service control
773 * manager.
775 * PARAMS
776 * servent [I] A list of the service names and service procedures
778 * RETURNS
779 * Success: TRUE.
780 * Failure: FALSE.
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 if (r)
1539 service_wait_for_startup(hService);
1541 return r;
1544 /******************************************************************************
1545 * QueryServiceStatus [ADVAPI32.@]
1547 * PARAMS
1548 * hService []
1549 * lpservicestatus []
1552 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1553 LPSERVICE_STATUS lpservicestatus)
1555 struct sc_service *hsvc;
1556 DWORD size, type, val;
1557 HANDLE pipe;
1558 LONG r;
1560 TRACE("%p %p\n", hService, lpservicestatus);
1562 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1563 if (!hsvc)
1565 SetLastError( ERROR_INVALID_HANDLE );
1566 return FALSE;
1569 pipe = service_open_pipe(hsvc->name);
1570 if (pipe != INVALID_HANDLE_VALUE)
1572 r = service_get_status(pipe, lpservicestatus);
1573 CloseHandle(pipe);
1574 if (r)
1575 return TRUE;
1578 TRACE("Failed to read service status\n");
1580 /* read the service type from the registry */
1581 size = sizeof(val);
1582 r = RegQueryValueExA(hsvc->hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1583 if(r!=ERROR_SUCCESS || type!=REG_DWORD)
1584 val = 0;
1586 lpservicestatus->dwServiceType = val;
1587 lpservicestatus->dwCurrentState = SERVICE_STOPPED; /* stopped */
1588 lpservicestatus->dwControlsAccepted = 0;
1589 lpservicestatus->dwWin32ExitCode = ERROR_SERVICE_NEVER_STARTED;
1590 lpservicestatus->dwServiceSpecificExitCode = 0;
1591 lpservicestatus->dwCheckPoint = 0;
1592 lpservicestatus->dwWaitHint = 0;
1594 return TRUE;
1597 /******************************************************************************
1598 * QueryServiceStatusEx [ADVAPI32.@]
1600 * Get information about a service.
1602 * PARAMS
1603 * hService [I] Handle to service to get information about
1604 * InfoLevel [I] Level of information to get
1605 * lpBuffer [O] Destination for requested information
1606 * cbBufSize [I] Size of lpBuffer in bytes
1607 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1609 * RETURNS
1610 * Success: TRUE
1611 * FAILURE: FALSE
1613 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1614 LPBYTE lpBuffer, DWORD cbBufSize,
1615 LPDWORD pcbBytesNeeded)
1617 FIXME("stub\n");
1618 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1619 return FALSE;
1622 /******************************************************************************
1623 * QueryServiceConfigA [ADVAPI32.@]
1625 BOOL WINAPI
1626 QueryServiceConfigA( SC_HANDLE hService,
1627 LPQUERY_SERVICE_CONFIGA lpServiceConfig,
1628 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1630 static const CHAR szDisplayName[] = "DisplayName";
1631 static const CHAR szType[] = "Type";
1632 static const CHAR szStart[] = "Start";
1633 static const CHAR szError[] = "ErrorControl";
1634 static const CHAR szImagePath[] = "ImagePath";
1635 static const CHAR szGroup[] = "Group";
1636 static const CHAR szDependencies[] = "Dependencies";
1637 struct sc_service *hsvc;
1638 HKEY hKey;
1639 CHAR str_buffer[ MAX_PATH ];
1640 LONG r;
1641 DWORD type, val, sz, total, n;
1642 LPSTR p;
1644 TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
1645 cbBufSize, pcbBytesNeeded);
1647 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1648 if (!hsvc)
1650 SetLastError( ERROR_INVALID_HANDLE );
1651 return FALSE;
1653 hKey = hsvc->hkey;
1655 /* calculate the size required first */
1656 total = sizeof (QUERY_SERVICE_CONFIGA);
1658 sz = sizeof(str_buffer);
1659 r = RegQueryValueExA( hKey, szImagePath, 0, &type, (LPBYTE)str_buffer, &sz );
1660 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1662 sz = ExpandEnvironmentStringsA(str_buffer,NULL,0);
1663 if( 0 == sz ) return FALSE;
1665 total += sz;
1667 else
1669 /* FIXME: set last error */
1670 return FALSE;
1673 sz = 0;
1674 r = RegQueryValueExA( hKey, szGroup, 0, &type, NULL, &sz );
1675 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1676 total += sz;
1678 sz = 0;
1679 r = RegQueryValueExA( hKey, szDependencies, 0, &type, NULL, &sz );
1680 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1681 total += sz;
1683 sz = 0;
1684 r = RegQueryValueExA( hKey, szStart, 0, &type, NULL, &sz );
1685 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1686 total += sz;
1688 sz = 0;
1689 r = RegQueryValueExA( hKey, szDisplayName, 0, &type, NULL, &sz );
1690 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1691 total += sz;
1693 *pcbBytesNeeded = total;
1695 /* if there's not enough memory, return an error */
1696 if( total > cbBufSize )
1698 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1699 return FALSE;
1702 ZeroMemory( lpServiceConfig, total );
1704 sz = sizeof val;
1705 r = RegQueryValueExA( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1706 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1707 lpServiceConfig->dwServiceType = val;
1709 sz = sizeof val;
1710 r = RegQueryValueExA( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1711 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1712 lpServiceConfig->dwStartType = val;
1714 sz = sizeof val;
1715 r = RegQueryValueExA( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1716 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1717 lpServiceConfig->dwErrorControl = val;
1719 /* now do the strings */
1720 p = (LPSTR) &lpServiceConfig[1];
1721 n = total - sizeof (QUERY_SERVICE_CONFIGA);
1723 sz = sizeof(str_buffer);
1724 r = RegQueryValueExA( hKey, szImagePath, 0, &type, (LPBYTE)str_buffer, &sz );
1725 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1727 sz = ExpandEnvironmentStringsA(str_buffer, p, n);
1728 if( 0 == sz || sz > n ) return FALSE;
1730 lpServiceConfig->lpBinaryPathName = p;
1731 p += sz;
1732 n -= sz;
1734 else
1736 /* FIXME: set last error */
1737 return FALSE;
1740 sz = n;
1741 r = RegQueryValueExA( hKey, szGroup, 0, &type, (LPBYTE)p, &sz );
1742 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1744 lpServiceConfig->lpLoadOrderGroup = p;
1745 p += sz;
1746 n -= sz;
1749 sz = n;
1750 r = RegQueryValueExA( hKey, szDependencies, 0, &type, (LPBYTE)p, &sz );
1751 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1753 lpServiceConfig->lpDependencies = p;
1754 p += sz;
1755 n -= sz;
1758 if( n < 0 )
1759 ERR("Buffer overflow!\n");
1761 TRACE("Image path = %s\n", lpServiceConfig->lpBinaryPathName );
1762 TRACE("Group = %s\n", lpServiceConfig->lpLoadOrderGroup );
1764 return TRUE;
1767 /******************************************************************************
1768 * QueryServiceConfigW [ADVAPI32.@]
1770 BOOL WINAPI
1771 QueryServiceConfigW( SC_HANDLE hService,
1772 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1773 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1775 WCHAR str_buffer[ MAX_PATH ];
1776 LONG r;
1777 DWORD type, val, sz, total, n;
1778 LPBYTE p;
1779 HKEY hKey;
1780 struct sc_service *hsvc;
1782 TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
1783 cbBufSize, pcbBytesNeeded);
1785 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1786 if (!hsvc)
1788 SetLastError( ERROR_INVALID_HANDLE );
1789 return FALSE;
1791 hKey = hsvc->hkey;
1793 /* calculate the size required first */
1794 total = sizeof (QUERY_SERVICE_CONFIGW);
1796 sz = sizeof(str_buffer);
1797 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1798 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1800 sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1801 if( 0 == sz ) return FALSE;
1803 total += sizeof(WCHAR) * sz;
1805 else
1807 /* FIXME: set last error */
1808 return FALSE;
1811 sz = 0;
1812 r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1813 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1814 total += sz;
1816 sz = 0;
1817 r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1818 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1819 total += sz;
1820 else
1821 total += sizeof(WCHAR);
1823 sz = 0;
1824 r = RegQueryValueExW( hKey, szStart, 0, &type, NULL, &sz );
1825 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1826 total += sz;
1828 sz = 0;
1829 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1830 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1831 total += sz;
1833 *pcbBytesNeeded = total;
1835 /* if there's not enough memory, return an error */
1836 if( total > cbBufSize )
1838 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1839 return FALSE;
1842 ZeroMemory( lpServiceConfig, total );
1844 sz = sizeof val;
1845 r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1846 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1847 lpServiceConfig->dwServiceType = val;
1849 sz = sizeof val;
1850 r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1851 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1852 lpServiceConfig->dwStartType = val;
1854 sz = sizeof val;
1855 r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1856 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1857 lpServiceConfig->dwErrorControl = val;
1859 /* now do the strings */
1860 p = (LPBYTE) &lpServiceConfig[1];
1861 n = total - sizeof (QUERY_SERVICE_CONFIGW);
1863 sz = sizeof(str_buffer);
1864 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1865 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1867 sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
1868 sz *= sizeof(WCHAR);
1869 if( 0 == sz || sz > n ) return FALSE;
1871 lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
1872 p += sz;
1873 n -= sz;
1875 else
1877 /* FIXME: set last error */
1878 return FALSE;
1881 sz = n;
1882 r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
1883 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1885 lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
1886 p += sz;
1887 n -= sz;
1890 sz = n;
1891 r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
1892 lpServiceConfig->lpDependencies = (LPWSTR) p;
1893 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1895 p += sz;
1896 n -= sz;
1898 else
1900 *(WCHAR *) p = 0;
1901 p += sizeof(WCHAR);
1902 n -= sizeof(WCHAR);
1905 if( n < 0 )
1906 ERR("Buffer overflow!\n");
1908 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1909 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1911 return TRUE;
1914 /******************************************************************************
1915 * EnumServicesStatusA [ADVAPI32.@]
1917 BOOL WINAPI
1918 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
1919 DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
1920 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1921 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1923 FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
1924 dwServiceType, dwServiceState, lpServices, cbBufSize,
1925 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
1926 SetLastError (ERROR_ACCESS_DENIED);
1927 return FALSE;
1930 /******************************************************************************
1931 * EnumServicesStatusW [ADVAPI32.@]
1933 BOOL WINAPI
1934 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
1935 DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
1936 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1937 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1939 FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
1940 dwServiceType, dwServiceState, lpServices, cbBufSize,
1941 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
1942 SetLastError (ERROR_ACCESS_DENIED);
1943 return FALSE;
1946 /******************************************************************************
1947 * GetServiceKeyNameA [ADVAPI32.@]
1949 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
1950 LPSTR lpServiceName, LPDWORD lpcchBuffer )
1952 FIXME("%p %s %p %p\n", hSCManager, debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
1953 return FALSE;
1956 /******************************************************************************
1957 * GetServiceKeyNameW [ADVAPI32.@]
1959 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
1960 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
1962 FIXME("%p %s %p %p\n", hSCManager, debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
1963 return FALSE;
1966 /******************************************************************************
1967 * QueryServiceLockStatusA [ADVAPI32.@]
1969 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
1970 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
1971 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1973 FIXME("%p %p %08lx %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1975 return FALSE;
1978 /******************************************************************************
1979 * QueryServiceLockStatusW [ADVAPI32.@]
1981 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
1982 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
1983 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1985 FIXME("%p %p %08lx %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1987 return FALSE;
1990 /******************************************************************************
1991 * GetServiceDisplayNameA [ADVAPI32.@]
1993 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1994 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
1996 FIXME("%p %s %p %p\n", hSCManager,
1997 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
1998 return FALSE;
2001 /******************************************************************************
2002 * GetServiceDisplayNameW [ADVAPI32.@]
2004 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
2005 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
2007 FIXME("%p %s %p %p\n", hSCManager,
2008 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
2009 return FALSE;
2012 /******************************************************************************
2013 * ChangeServiceConfigW [ADVAPI32.@]
2015 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
2016 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
2017 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
2018 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
2020 struct reg_value val[10];
2021 struct sc_service *hsvc;
2022 DWORD r = ERROR_SUCCESS;
2023 HKEY hKey;
2024 int n = 0;
2026 TRACE("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
2027 hService, dwServiceType, dwStartType, dwErrorControl,
2028 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2029 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2030 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2032 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2033 if (!hsvc)
2035 SetLastError( ERROR_INVALID_HANDLE );
2036 return FALSE;
2038 hKey = hsvc->hkey;
2040 if( dwServiceType != SERVICE_NO_CHANGE )
2041 service_set_dword( &val[n++], szType, &dwServiceType );
2043 if( dwStartType != SERVICE_NO_CHANGE )
2044 service_set_dword( &val[n++], szStart, &dwStartType );
2046 if( dwErrorControl != SERVICE_NO_CHANGE )
2047 service_set_dword( &val[n++], szError, &dwErrorControl );
2049 if( lpBinaryPathName )
2050 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
2052 if( lpLoadOrderGroup )
2053 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
2055 if( lpDependencies )
2056 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
2058 if( lpPassword )
2059 FIXME("ignoring password\n");
2061 if( lpServiceStartName )
2062 service_set_string( &val[n++], szDependOnService, lpServiceStartName );
2064 r = service_write_values( hsvc->hkey, val, n );
2066 return (r == ERROR_SUCCESS) ? TRUE : FALSE ;
2069 /******************************************************************************
2070 * ChangeServiceConfigA [ADVAPI32.@]
2072 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2073 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2074 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2075 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2077 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2078 LPWSTR wServiceStartName, wPassword, wDisplayName;
2079 BOOL r;
2081 TRACE("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
2082 hService, dwServiceType, dwStartType, dwErrorControl,
2083 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2084 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2085 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2087 wBinaryPathName = SERV_dup( lpBinaryPathName );
2088 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2089 wDependencies = SERV_dupmulti( lpDependencies );
2090 wServiceStartName = SERV_dup( lpServiceStartName );
2091 wPassword = SERV_dup( lpPassword );
2092 wDisplayName = SERV_dup( lpDisplayName );
2094 r = ChangeServiceConfigW( hService, dwServiceType,
2095 dwStartType, dwErrorControl, wBinaryPathName,
2096 wLoadOrderGroup, lpdwTagId, wDependencies,
2097 wServiceStartName, wPassword, wDisplayName);
2099 SERV_free( wBinaryPathName );
2100 SERV_free( wLoadOrderGroup );
2101 SERV_free( wDependencies );
2102 SERV_free( wServiceStartName );
2103 SERV_free( wPassword );
2104 SERV_free( wDisplayName );
2106 return r;
2109 /******************************************************************************
2110 * ChangeServiceConfig2A [ADVAPI32.@]
2112 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2113 LPVOID lpInfo)
2115 BOOL r = FALSE;
2117 TRACE("%p %ld %p\n",hService, dwInfoLevel, lpInfo);
2119 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2121 LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
2122 SERVICE_DESCRIPTIONW sdw;
2124 sdw.lpDescription = SERV_dup( sd->lpDescription );
2126 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2128 SERV_free( sdw.lpDescription );
2130 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2132 LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
2133 SERVICE_FAILURE_ACTIONSW faw;
2135 faw.dwResetPeriod = fa->dwResetPeriod;
2136 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2137 faw.lpCommand = SERV_dup( fa->lpCommand );
2138 faw.cActions = fa->cActions;
2139 faw.lpsaActions = fa->lpsaActions;
2141 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2143 SERV_free( faw.lpRebootMsg );
2144 SERV_free( faw.lpCommand );
2146 else
2147 SetLastError( ERROR_INVALID_PARAMETER );
2149 return r;
2152 /******************************************************************************
2153 * ChangeServiceConfig2W [ADVAPI32.@]
2155 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2156 LPVOID lpInfo)
2158 HKEY hKey;
2159 struct sc_service *hsvc;
2161 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2162 if (!hsvc)
2164 SetLastError( ERROR_INVALID_HANDLE );
2165 return FALSE;
2167 hKey = hsvc->hkey;
2169 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2171 static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2172 LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
2173 if (sd->lpDescription)
2175 TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
2176 if (sd->lpDescription[0] == 0)
2177 RegDeleteValueW(hKey,szDescription);
2178 else
2179 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2180 (LPVOID)sd->lpDescription,
2181 sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2184 else
2185 FIXME("STUB: %p %ld %p\n",hService, dwInfoLevel, lpInfo);
2186 return TRUE;
2189 /******************************************************************************
2190 * QueryServiceObjectSecurity [ADVAPI32.@]
2192 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2193 SECURITY_INFORMATION dwSecurityInformation,
2194 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2195 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2197 PACL pACL = NULL;
2199 FIXME("%p %ld %p %lu %p\n", hService, dwSecurityInformation,
2200 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2202 InitializeSecurityDescriptor(lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
2204 pACL = HeapAlloc( GetProcessHeap(), 0, sizeof(ACL) );
2205 InitializeAcl(pACL, sizeof(ACL), ACL_REVISION);
2206 SetSecurityDescriptorDacl(lpSecurityDescriptor, TRUE, pACL, TRUE);
2207 return TRUE;
2210 /******************************************************************************
2211 * SetServiceObjectSecurity [ADVAPI32.@]
2213 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2214 SECURITY_INFORMATION dwSecurityInformation,
2215 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2217 FIXME("%p %ld %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2218 return TRUE;
2221 /******************************************************************************
2222 * SetServiceBits [ADVAPI32.@]
2224 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2225 DWORD dwServiceBits,
2226 BOOL bSetBitsOn,
2227 BOOL bUpdateImmediately)
2229 FIXME("%p %08lx %x %x\n", hServiceStatus, dwServiceBits,
2230 bSetBitsOn, bUpdateImmediately);
2231 return TRUE;
2234 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR lpServiceName,
2235 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2237 FIXME("%s %p %p\n", debugstr_a(lpServiceName), lpHandlerProc, lpContext);
2238 return 0;
2241 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2242 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2244 FIXME("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2245 return 0;