Silence some -Wmissing-declarations warnings.
[wine.git] / dlls / advapi32 / service.c
blobe81b9875cd05906f7bf953b4fafc98c587c04df4
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, { 0, (DWORD)(__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("%lx %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 return NULL;
1006 /******************************************************************************
1007 * ControlService [ADVAPI32.@]
1009 * Send a control code to a service.
1011 * PARAMS
1012 * hService [I] Handle of the service control manager database
1013 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
1014 * lpServiceStatus [O] Destination for the status of the service, if available
1016 * RETURNS
1017 * Success: TRUE.
1018 * Failure: FALSE.
1020 * BUGS
1021 * Unlike M$' implementation, control requests are not serialized and may be
1022 * processed asynchronously.
1024 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
1025 LPSERVICE_STATUS lpServiceStatus )
1027 struct sc_service *hsvc;
1028 BOOL ret = FALSE;
1029 HANDLE handle;
1031 TRACE("%p %ld %p\n", hService, dwControl, lpServiceStatus);
1033 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1034 if (!hsvc)
1036 SetLastError( ERROR_INVALID_HANDLE );
1037 return FALSE;
1040 ret = QueryServiceStatus(hService, lpServiceStatus);
1041 if (!ret)
1043 ERR("failed to query service status\n");
1044 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1045 return FALSE;
1048 switch (lpServiceStatus->dwCurrentState)
1050 case SERVICE_STOPPED:
1051 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1052 return FALSE;
1053 case SERVICE_START_PENDING:
1054 if (dwControl==SERVICE_CONTROL_STOP)
1055 break;
1056 /* fall thru */
1057 case SERVICE_STOP_PENDING:
1058 SetLastError(ERROR_SERVICE_CANNOT_ACCEPT_CTRL);
1059 return FALSE;
1062 handle = service_open_pipe(hsvc->name);
1063 if (handle!=INVALID_HANDLE_VALUE)
1065 DWORD result = ERROR_SUCCESS;
1066 ret = service_send_control(handle, dwControl, &result);
1067 CloseHandle(handle);
1068 if (result!=ERROR_SUCCESS)
1070 SetLastError(result);
1071 ret = FALSE;
1075 return ret;
1078 /******************************************************************************
1079 * CloseServiceHandle [ADVAPI32.@]
1081 * Close a handle to a service or the service control manager database.
1083 * PARAMS
1084 * hSCObject [I] Handle to service or service control manager database
1086 * RETURNS
1087 * Success: TRUE
1088 * Failure: FALSE
1090 BOOL WINAPI
1091 CloseServiceHandle( SC_HANDLE hSCObject )
1093 TRACE("%p\n", hSCObject);
1095 sc_handle_free( (struct sc_handle*) hSCObject );
1097 return TRUE;
1101 /******************************************************************************
1102 * OpenServiceA [ADVAPI32.@]
1104 * Open a handle to a service.
1106 * PARAMS
1107 * hSCManager [I] Handle of the service control manager database
1108 * lpServiceName [I] Name of the service to open
1109 * dwDesiredAccess [I] Access required to the service
1111 * RETURNS
1112 * Success: Handle to the service
1113 * Failure: NULL
1115 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1116 DWORD dwDesiredAccess )
1118 LPWSTR lpServiceNameW;
1119 SC_HANDLE ret;
1121 TRACE("%p %s %ld\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
1123 lpServiceNameW = SERV_dup(lpServiceName);
1124 ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
1125 SERV_free(lpServiceNameW);
1126 return ret;
1130 /******************************************************************************
1131 * OpenServiceW [ADVAPI32.@]
1133 * See OpenServiceA.
1135 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1136 DWORD dwDesiredAccess)
1138 struct sc_manager *hscm;
1139 struct sc_service *hsvc;
1140 HKEY hKey;
1141 long r;
1142 DWORD len;
1144 TRACE("%p %s %ld\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
1146 if (!lpServiceName)
1148 SetLastError(ERROR_INVALID_ADDRESS);
1149 return NULL;
1152 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1153 if (!hscm)
1155 SetLastError( ERROR_INVALID_HANDLE );
1156 return FALSE;
1159 r = RegOpenKeyExW( hscm->hkey, lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
1160 if (r!=ERROR_SUCCESS)
1162 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
1163 return NULL;
1166 len = strlenW(lpServiceName)+1;
1167 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE,
1168 sizeof (struct sc_service) + len*sizeof(WCHAR),
1169 sc_handle_destroy_service );
1170 if (!hsvc)
1171 return NULL;
1172 strcpyW( hsvc->name, lpServiceName );
1173 hsvc->hkey = hKey;
1175 /* add reference to SCM handle */
1176 hscm->hdr.ref_count++;
1177 hsvc->scm = hscm;
1179 TRACE("returning %p\n",hsvc);
1181 return (SC_HANDLE) &hsvc->hdr;
1184 /******************************************************************************
1185 * CreateServiceW [ADVAPI32.@]
1187 SC_HANDLE WINAPI
1188 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1189 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
1190 DWORD dwServiceType, DWORD dwStartType,
1191 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1192 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1193 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
1194 LPCWSTR lpPassword )
1196 struct sc_manager *hscm;
1197 struct sc_service *hsvc = NULL;
1198 HKEY hKey;
1199 LONG r;
1200 DWORD dp, len;
1201 struct reg_value val[10];
1202 int n = 0;
1204 TRACE("%p %s %s\n", hSCManager,
1205 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
1207 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1208 if (!hscm)
1210 SetLastError( ERROR_INVALID_HANDLE );
1211 return NULL;
1214 r = RegCreateKeyExW(hscm->hkey, lpServiceName, 0, NULL,
1215 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
1216 if (r!=ERROR_SUCCESS)
1217 return NULL;
1219 if (dp != REG_CREATED_NEW_KEY)
1221 SetLastError(ERROR_SERVICE_EXISTS);
1222 goto error;
1225 if( lpDisplayName )
1226 service_set_string( &val[n++], szDisplayName, lpDisplayName );
1228 service_set_dword( &val[n++], szType, &dwServiceType );
1229 service_set_dword( &val[n++], szStart, &dwStartType );
1230 service_set_dword( &val[n++], szError, &dwErrorControl );
1232 if( lpBinaryPathName )
1233 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
1235 if( lpLoadOrderGroup )
1236 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
1238 if( lpDependencies )
1239 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
1241 if( lpPassword )
1242 FIXME("Don't know how to add a Password for a service.\n");
1244 if( lpServiceStartName )
1245 service_set_string( &val[n++], szDependOnService, lpServiceStartName );
1247 r = service_write_values( hKey, val, n );
1248 if( r != ERROR_SUCCESS )
1249 goto error;
1251 len = strlenW(lpServiceName)+1;
1252 len = sizeof (struct sc_service) + len*sizeof(WCHAR);
1253 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE, len, sc_handle_destroy_service );
1254 if( !hsvc )
1255 goto error;
1256 lstrcpyW( hsvc->name, lpServiceName );
1257 hsvc->hkey = hKey;
1258 hsvc->scm = hscm;
1259 hscm->hdr.ref_count++;
1261 return (SC_HANDLE) &hsvc->hdr;
1263 error:
1264 RegCloseKey( hKey );
1265 return NULL;
1269 /******************************************************************************
1270 * CreateServiceA [ADVAPI32.@]
1272 SC_HANDLE WINAPI
1273 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1274 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1275 DWORD dwServiceType, DWORD dwStartType,
1276 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1277 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1278 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1279 LPCSTR lpPassword )
1281 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1282 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1283 SC_HANDLE r;
1285 TRACE("%p %s %s\n", hSCManager,
1286 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1288 lpServiceNameW = SERV_dup( lpServiceName );
1289 lpDisplayNameW = SERV_dup( lpDisplayName );
1290 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1291 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1292 lpDependenciesW = SERV_dupmulti( lpDependencies );
1293 lpServiceStartNameW = SERV_dup( lpServiceStartName );
1294 lpPasswordW = SERV_dup( lpPassword );
1296 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1297 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1298 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1299 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1301 SERV_free( lpServiceNameW );
1302 SERV_free( lpDisplayNameW );
1303 SERV_free( lpBinaryPathNameW );
1304 SERV_free( lpLoadOrderGroupW );
1305 SERV_free( lpDependenciesW );
1306 SERV_free( lpServiceStartNameW );
1307 SERV_free( lpPasswordW );
1309 return r;
1313 /******************************************************************************
1314 * DeleteService [ADVAPI32.@]
1316 * Delete a service from the service control manager database.
1318 * PARAMS
1319 * hService [I] Handle of the service to delete
1321 * RETURNS
1322 * Success: TRUE
1323 * Failure: FALSE
1325 BOOL WINAPI DeleteService( SC_HANDLE hService )
1327 struct sc_service *hsvc;
1328 HKEY hKey;
1329 WCHAR valname[MAX_PATH+1];
1330 INT index = 0;
1331 LONG rc;
1332 DWORD size;
1334 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1335 if (!hsvc)
1337 SetLastError( ERROR_INVALID_HANDLE );
1338 return FALSE;
1340 hKey = hsvc->hkey;
1342 size = MAX_PATH+1;
1343 /* Clean out the values */
1344 rc = RegEnumValueW(hKey, index, valname,&size,0,0,0,0);
1345 while (rc == ERROR_SUCCESS)
1347 RegDeleteValueW(hKey,valname);
1348 index++;
1349 size = MAX_PATH+1;
1350 rc = RegEnumValueW(hKey, index, valname, &size,0,0,0,0);
1353 RegCloseKey(hKey);
1354 hsvc->hkey = NULL;
1356 /* delete the key */
1357 RegDeleteKeyW(hsvc->scm->hkey, hsvc->name);
1359 return TRUE;
1363 /******************************************************************************
1364 * StartServiceA [ADVAPI32.@]
1366 * Start a service
1368 * PARAMS
1369 * hService [I] Handle of service
1370 * dwNumServiceArgs [I] Number of arguments
1371 * lpServiceArgVectors [I] Address of array of argument strings
1373 * NOTES
1374 * - NT implements this function using an obscure RPC call.
1375 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1376 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1377 * - This will only work for shared address space. How should the service
1378 * args be transferred when address spaces are separated?
1379 * - Can only start one service at a time.
1380 * - Has no concept of privilege.
1382 * RETURNS
1383 * Success: TRUE.
1384 * Failure: FALSE
1386 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1387 LPCSTR *lpServiceArgVectors )
1389 LPWSTR *lpwstr=NULL;
1390 unsigned int i;
1391 BOOL r;
1393 TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1395 if (dwNumServiceArgs)
1396 lpwstr = HeapAlloc( GetProcessHeap(), 0,
1397 dwNumServiceArgs*sizeof(LPWSTR) );
1399 for(i=0; i<dwNumServiceArgs; i++)
1400 lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1402 r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1404 if (dwNumServiceArgs)
1406 for(i=0; i<dwNumServiceArgs; i++)
1407 SERV_free(lpwstr[i]);
1408 HeapFree(GetProcessHeap(), 0, lpwstr);
1411 return r;
1414 /******************************************************************************
1415 * service_start_process [INTERNAL]
1417 static DWORD service_start_process(struct sc_service *hsvc)
1419 static const WCHAR _ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0};
1420 PROCESS_INFORMATION pi;
1421 STARTUPINFOW si;
1422 LPWSTR path = NULL, str;
1423 DWORD type, size, ret;
1424 HANDLE handles[2];
1425 BOOL r;
1427 /* read the executable path from memory */
1428 size = 0;
1429 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, NULL, &size);
1430 if (ret!=ERROR_SUCCESS)
1431 return FALSE;
1432 str = HeapAlloc(GetProcessHeap(),0,size);
1433 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, (LPBYTE)str, &size);
1434 if (ret==ERROR_SUCCESS)
1436 size = ExpandEnvironmentStringsW(str,NULL,0);
1437 path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
1438 ExpandEnvironmentStringsW(str,path,size);
1440 HeapFree(GetProcessHeap(),0,str);
1441 if (!path)
1442 return FALSE;
1444 /* wait for the process to start and set an event or terminate */
1445 handles[0] = service_get_event_handle( hsvc->name );
1446 ZeroMemory(&si, sizeof(STARTUPINFOW));
1447 si.cb = sizeof(STARTUPINFOW);
1448 r = CreateProcessW(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1449 if (r)
1451 handles[1] = pi.hProcess;
1452 ret = WaitForMultipleObjectsEx(2, handles, FALSE, 30000, FALSE);
1453 if(ret != WAIT_OBJECT_0)
1455 SetLastError(ERROR_IO_PENDING);
1456 r = FALSE;
1459 CloseHandle( pi.hThread );
1460 CloseHandle( pi.hProcess );
1462 CloseHandle( handles[0] );
1463 HeapFree(GetProcessHeap(),0,path);
1464 return r;
1467 static BOOL service_wait_for_startup(SC_HANDLE hService)
1469 DWORD i;
1470 SERVICE_STATUS status;
1471 BOOL r = FALSE;
1473 TRACE("%p\n", hService);
1475 for (i=0; i<30; i++)
1477 status.dwCurrentState = 0;
1478 r = QueryServiceStatus(hService, &status);
1479 if (!r)
1480 break;
1481 if (status.dwCurrentState == SERVICE_RUNNING)
1483 TRACE("Service started successfully\n");
1484 break;
1486 r = FALSE;
1487 Sleep(1000);
1489 return r;
1492 /******************************************************************************
1493 * StartServiceW [ADVAPI32.@]
1495 * See StartServiceA.
1497 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1498 LPCWSTR *lpServiceArgVectors)
1500 struct sc_service *hsvc;
1501 BOOL r = FALSE;
1502 SC_LOCK hLock;
1503 HANDLE handle = INVALID_HANDLE_VALUE;
1505 TRACE("%p %ld %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1507 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1508 if (!hsvc)
1510 SetLastError(ERROR_INVALID_HANDLE);
1511 return r;
1514 hLock = LockServiceDatabase(hsvc->scm);
1515 if (!hLock)
1516 return r;
1518 handle = service_open_pipe(hsvc->name);
1519 if (handle==INVALID_HANDLE_VALUE)
1521 /* start the service process */
1522 if (service_start_process(hsvc))
1523 handle = service_open_pipe(hsvc->name);
1526 if (handle != INVALID_HANDLE_VALUE)
1528 service_send_start_message(handle, lpServiceArgVectors, dwNumServiceArgs);
1529 CloseHandle(handle);
1530 r = TRUE;
1533 UnlockServiceDatabase( hLock );
1535 TRACE("returning %d\n", r);
1537 service_wait_for_startup(hService);
1539 return r;
1542 /******************************************************************************
1543 * QueryServiceStatus [ADVAPI32.@]
1545 * PARAMS
1546 * hService []
1547 * lpservicestatus []
1550 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1551 LPSERVICE_STATUS lpservicestatus)
1553 struct sc_service *hsvc;
1554 DWORD size, type, val;
1555 HANDLE pipe;
1556 LONG r;
1558 TRACE("%p %p\n", hService, lpservicestatus);
1560 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1561 if (!hsvc)
1563 SetLastError( ERROR_INVALID_HANDLE );
1564 return FALSE;
1567 pipe = service_open_pipe(hsvc->name);
1568 if (pipe != INVALID_HANDLE_VALUE)
1570 r = service_get_status(pipe, lpservicestatus);
1571 CloseHandle(pipe);
1572 if (r)
1573 return TRUE;
1576 TRACE("Failed to read service status\n");
1578 /* read the service type from the registry */
1579 size = sizeof(val);
1580 r = RegQueryValueExA(hsvc->hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1581 if(r!=ERROR_SUCCESS || type!=REG_DWORD)
1582 val = 0;
1584 lpservicestatus->dwServiceType = val;
1585 lpservicestatus->dwCurrentState = SERVICE_STOPPED; /* stopped */
1586 lpservicestatus->dwControlsAccepted = 0;
1587 lpservicestatus->dwWin32ExitCode = ERROR_SERVICE_NEVER_STARTED;
1588 lpservicestatus->dwServiceSpecificExitCode = 0;
1589 lpservicestatus->dwCheckPoint = 0;
1590 lpservicestatus->dwWaitHint = 0;
1592 return TRUE;
1595 /******************************************************************************
1596 * QueryServiceStatusEx [ADVAPI32.@]
1598 * Get information about a service.
1600 * PARAMS
1601 * hService [I] Handle to service to get information about
1602 * InfoLevel [I] Level of information to get
1603 * lpBuffer [O] Destination for requested information
1604 * cbBufSize [I] Size of lpBuffer in bytes
1605 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1607 * RETURNS
1608 * Success: TRUE
1609 * FAILURE: FALSE
1611 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1612 LPBYTE lpBuffer, DWORD cbBufSize,
1613 LPDWORD pcbBytesNeeded)
1615 FIXME("stub\n");
1616 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1617 return FALSE;
1620 /******************************************************************************
1621 * QueryServiceConfigA [ADVAPI32.@]
1623 BOOL WINAPI
1624 QueryServiceConfigA( SC_HANDLE hService,
1625 LPQUERY_SERVICE_CONFIGA lpServiceConfig,
1626 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1628 static const CHAR szDisplayName[] = "DisplayName";
1629 static const CHAR szType[] = "Type";
1630 static const CHAR szStart[] = "Start";
1631 static const CHAR szError[] = "ErrorControl";
1632 static const CHAR szImagePath[] = "ImagePath";
1633 static const CHAR szGroup[] = "Group";
1634 static const CHAR szDependencies[] = "Dependencies";
1635 struct sc_service *hsvc;
1636 HKEY hKey;
1637 CHAR str_buffer[ MAX_PATH ];
1638 LONG r;
1639 DWORD type, val, sz, total, n;
1640 LPBYTE p;
1642 TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
1643 cbBufSize, pcbBytesNeeded);
1645 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1646 if (!hsvc)
1648 SetLastError( ERROR_INVALID_HANDLE );
1649 return FALSE;
1651 hKey = hsvc->hkey;
1653 /* calculate the size required first */
1654 total = sizeof (QUERY_SERVICE_CONFIGA);
1656 sz = sizeof(str_buffer);
1657 r = RegQueryValueExA( hKey, szImagePath, 0, &type, str_buffer, &sz );
1658 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1660 sz = ExpandEnvironmentStringsA(str_buffer,NULL,0);
1661 if( 0 == sz ) return FALSE;
1663 total += sz;
1665 else
1667 /* FIXME: set last error */
1668 return FALSE;
1671 sz = 0;
1672 r = RegQueryValueExA( hKey, szGroup, 0, &type, NULL, &sz );
1673 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1674 total += sz;
1676 sz = 0;
1677 r = RegQueryValueExA( hKey, szDependencies, 0, &type, NULL, &sz );
1678 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1679 total += sz;
1681 sz = 0;
1682 r = RegQueryValueExA( hKey, szStart, 0, &type, NULL, &sz );
1683 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1684 total += sz;
1686 sz = 0;
1687 r = RegQueryValueExA( hKey, szDisplayName, 0, &type, NULL, &sz );
1688 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1689 total += sz;
1691 *pcbBytesNeeded = total;
1693 /* if there's not enough memory, return an error */
1694 if( total > cbBufSize )
1696 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1697 return FALSE;
1700 ZeroMemory( lpServiceConfig, total );
1702 sz = sizeof val;
1703 r = RegQueryValueExA( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1704 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1705 lpServiceConfig->dwServiceType = val;
1707 sz = sizeof val;
1708 r = RegQueryValueExA( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1709 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1710 lpServiceConfig->dwStartType = val;
1712 sz = sizeof val;
1713 r = RegQueryValueExA( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1714 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1715 lpServiceConfig->dwErrorControl = val;
1717 /* now do the strings */
1718 p = (LPBYTE) &lpServiceConfig[1];
1719 n = total - sizeof (QUERY_SERVICE_CONFIGA);
1721 sz = sizeof(str_buffer);
1722 r = RegQueryValueExA( hKey, szImagePath, 0, &type, str_buffer, &sz );
1723 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1725 sz = ExpandEnvironmentStringsA(str_buffer, p, n);
1726 if( 0 == sz || sz > n ) return FALSE;
1728 lpServiceConfig->lpBinaryPathName = (LPSTR) p;
1729 p += sz;
1730 n -= sz;
1732 else
1734 /* FIXME: set last error */
1735 return FALSE;
1738 sz = n;
1739 r = RegQueryValueExA( hKey, szGroup, 0, &type, p, &sz );
1740 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1742 lpServiceConfig->lpLoadOrderGroup = (LPSTR) p;
1743 p += sz;
1744 n -= sz;
1747 sz = n;
1748 r = RegQueryValueExA( hKey, szDependencies, 0, &type, p, &sz );
1749 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1751 lpServiceConfig->lpDependencies = (LPSTR) p;
1752 p += sz;
1753 n -= sz;
1756 if( n < 0 )
1757 ERR("Buffer overflow!\n");
1759 TRACE("Image path = %s\n", lpServiceConfig->lpBinaryPathName );
1760 TRACE("Group = %s\n", lpServiceConfig->lpLoadOrderGroup );
1762 return TRUE;
1765 /******************************************************************************
1766 * QueryServiceConfigW [ADVAPI32.@]
1768 BOOL WINAPI
1769 QueryServiceConfigW( SC_HANDLE hService,
1770 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1771 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1773 WCHAR str_buffer[ MAX_PATH ];
1774 LONG r;
1775 DWORD type, val, sz, total, n;
1776 LPBYTE p;
1777 HKEY hKey;
1778 struct sc_service *hsvc;
1780 TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
1781 cbBufSize, pcbBytesNeeded);
1783 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1784 if (!hsvc)
1786 SetLastError( ERROR_INVALID_HANDLE );
1787 return FALSE;
1789 hKey = hsvc->hkey;
1791 /* calculate the size required first */
1792 total = sizeof (QUERY_SERVICE_CONFIGW);
1794 sz = sizeof(str_buffer);
1795 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1796 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1798 sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1799 if( 0 == sz ) return FALSE;
1801 total += sizeof(WCHAR) * sz;
1803 else
1805 /* FIXME: set last error */
1806 return FALSE;
1809 sz = 0;
1810 r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1811 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1812 total += sz;
1814 sz = 0;
1815 r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1816 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1817 total += sz;
1818 else
1819 total += sizeof(WCHAR);
1821 sz = 0;
1822 r = RegQueryValueExW( hKey, szStart, 0, &type, NULL, &sz );
1823 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1824 total += sz;
1826 sz = 0;
1827 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1828 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1829 total += sz;
1831 *pcbBytesNeeded = total;
1833 /* if there's not enough memory, return an error */
1834 if( total > cbBufSize )
1836 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1837 return FALSE;
1840 ZeroMemory( lpServiceConfig, total );
1842 sz = sizeof val;
1843 r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1844 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1845 lpServiceConfig->dwServiceType = val;
1847 sz = sizeof val;
1848 r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1849 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1850 lpServiceConfig->dwStartType = val;
1852 sz = sizeof val;
1853 r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1854 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1855 lpServiceConfig->dwErrorControl = val;
1857 /* now do the strings */
1858 p = (LPBYTE) &lpServiceConfig[1];
1859 n = total - sizeof (QUERY_SERVICE_CONFIGW);
1861 sz = sizeof(str_buffer);
1862 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1863 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1865 sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
1866 sz *= sizeof(WCHAR);
1867 if( 0 == sz || sz > n ) return FALSE;
1869 lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
1870 p += sz;
1871 n -= sz;
1873 else
1875 /* FIXME: set last error */
1876 return FALSE;
1879 sz = n;
1880 r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
1881 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1883 lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
1884 p += sz;
1885 n -= sz;
1888 sz = n;
1889 r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
1890 lpServiceConfig->lpDependencies = (LPWSTR) p;
1891 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1893 p += sz;
1894 n -= sz;
1896 else
1898 *(WCHAR *) p = 0;
1899 p += sizeof(WCHAR);
1900 n -= sizeof(WCHAR);
1903 if( n < 0 )
1904 ERR("Buffer overflow!\n");
1906 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1907 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1909 return TRUE;
1912 /******************************************************************************
1913 * EnumServicesStatusA [ADVAPI32.@]
1915 BOOL WINAPI
1916 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
1917 DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
1918 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1919 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1921 FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
1922 dwServiceType, dwServiceState, lpServices, cbBufSize,
1923 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
1924 SetLastError (ERROR_ACCESS_DENIED);
1925 return FALSE;
1928 /******************************************************************************
1929 * EnumServicesStatusW [ADVAPI32.@]
1931 BOOL WINAPI
1932 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
1933 DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
1934 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1935 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1937 FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
1938 dwServiceType, dwServiceState, lpServices, cbBufSize,
1939 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
1940 SetLastError (ERROR_ACCESS_DENIED);
1941 return FALSE;
1944 /******************************************************************************
1945 * GetServiceKeyNameA [ADVAPI32.@]
1947 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
1948 LPSTR lpServiceName, LPDWORD lpcchBuffer )
1950 FIXME("%p %s %p %p\n", hSCManager, debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
1951 return FALSE;
1954 /******************************************************************************
1955 * GetServiceKeyNameW [ADVAPI32.@]
1957 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
1958 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
1960 FIXME("%p %s %p %p\n", hSCManager, debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
1961 return FALSE;
1964 /******************************************************************************
1965 * QueryServiceLockStatusA [ADVAPI32.@]
1967 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
1968 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
1969 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1971 FIXME("%p %p %08lx %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1973 return FALSE;
1976 /******************************************************************************
1977 * QueryServiceLockStatusW [ADVAPI32.@]
1979 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
1980 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
1981 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1983 FIXME("%p %p %08lx %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1985 return FALSE;
1988 /******************************************************************************
1989 * GetServiceDisplayNameA [ADVAPI32.@]
1991 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1992 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
1994 FIXME("%p %s %p %p\n", hSCManager,
1995 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
1996 return FALSE;
1999 /******************************************************************************
2000 * GetServiceDisplayNameW [ADVAPI32.@]
2002 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
2003 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
2005 FIXME("%p %s %p %p\n", hSCManager,
2006 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
2007 return FALSE;
2010 /******************************************************************************
2011 * ChangeServiceConfigW [ADVAPI32.@]
2013 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
2014 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
2015 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
2016 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
2018 struct reg_value val[10];
2019 struct sc_service *hsvc;
2020 DWORD r = ERROR_SUCCESS;
2021 HKEY hKey;
2022 int n = 0;
2024 TRACE("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
2025 hService, dwServiceType, dwStartType, dwErrorControl,
2026 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2027 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2028 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2030 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2031 if (!hsvc)
2033 SetLastError( ERROR_INVALID_HANDLE );
2034 return FALSE;
2036 hKey = hsvc->hkey;
2038 if( dwServiceType != SERVICE_NO_CHANGE )
2039 service_set_dword( &val[n++], szType, &dwServiceType );
2041 if( dwStartType != SERVICE_NO_CHANGE )
2042 service_set_dword( &val[n++], szStart, &dwStartType );
2044 if( dwErrorControl != SERVICE_NO_CHANGE )
2045 service_set_dword( &val[n++], szError, &dwErrorControl );
2047 if( lpBinaryPathName )
2048 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
2050 if( lpLoadOrderGroup )
2051 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
2053 if( lpDependencies )
2054 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
2056 if( lpPassword )
2057 FIXME("ignoring password\n");
2059 if( lpServiceStartName )
2060 service_set_string( &val[n++], szDependOnService, lpServiceStartName );
2062 r = service_write_values( hsvc->hkey, val, n );
2064 return (r == ERROR_SUCCESS) ? TRUE : FALSE ;
2067 /******************************************************************************
2068 * ChangeServiceConfigA [ADVAPI32.@]
2070 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2071 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2072 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2073 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2075 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2076 LPWSTR wServiceStartName, wPassword, wDisplayName;
2077 BOOL r;
2079 TRACE("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
2080 hService, dwServiceType, dwStartType, dwErrorControl,
2081 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2082 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2083 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2085 wBinaryPathName = SERV_dup( lpBinaryPathName );
2086 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2087 wDependencies = SERV_dupmulti( lpDependencies );
2088 wServiceStartName = SERV_dup( lpServiceStartName );
2089 wPassword = SERV_dup( lpPassword );
2090 wDisplayName = SERV_dup( lpDisplayName );
2092 r = ChangeServiceConfigW( hService, dwServiceType,
2093 dwStartType, dwErrorControl, wBinaryPathName,
2094 wLoadOrderGroup, lpdwTagId, wDependencies,
2095 wServiceStartName, wPassword, wDisplayName);
2097 SERV_free( wBinaryPathName );
2098 SERV_free( wLoadOrderGroup );
2099 SERV_free( wDependencies );
2100 SERV_free( wServiceStartName );
2101 SERV_free( wPassword );
2102 SERV_free( wDisplayName );
2104 return r;
2107 /******************************************************************************
2108 * ChangeServiceConfig2A [ADVAPI32.@]
2110 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2111 LPVOID lpInfo)
2113 BOOL r = FALSE;
2115 TRACE("%p %ld %p\n",hService, dwInfoLevel, lpInfo);
2117 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2119 LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
2120 SERVICE_DESCRIPTIONW sdw;
2122 sdw.lpDescription = SERV_dup( sd->lpDescription );
2124 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2126 SERV_free( sdw.lpDescription );
2128 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2130 LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
2131 SERVICE_FAILURE_ACTIONSW faw;
2133 faw.dwResetPeriod = fa->dwResetPeriod;
2134 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2135 faw.lpCommand = SERV_dup( fa->lpCommand );
2136 faw.cActions = fa->cActions;
2137 faw.lpsaActions = fa->lpsaActions;
2139 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2141 SERV_free( faw.lpRebootMsg );
2142 SERV_free( faw.lpCommand );
2144 else
2145 SetLastError( ERROR_INVALID_PARAMETER );
2147 return r;
2150 /******************************************************************************
2151 * ChangeServiceConfig2W [ADVAPI32.@]
2153 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2154 LPVOID lpInfo)
2156 HKEY hKey;
2157 struct sc_service *hsvc;
2159 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2160 if (!hsvc)
2162 SetLastError( ERROR_INVALID_HANDLE );
2163 return FALSE;
2165 hKey = hsvc->hkey;
2167 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2169 static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2170 LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
2171 if (sd->lpDescription)
2173 TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
2174 if (sd->lpDescription[0] == 0)
2175 RegDeleteValueW(hKey,szDescription);
2176 else
2177 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2178 (LPVOID)sd->lpDescription,
2179 sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2182 else
2183 FIXME("STUB: %p %ld %p\n",hService, dwInfoLevel, lpInfo);
2184 return TRUE;
2187 /******************************************************************************
2188 * QueryServiceObjectSecurity [ADVAPI32.@]
2190 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2191 SECURITY_INFORMATION dwSecurityInformation,
2192 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2193 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2195 PACL pACL = NULL;
2197 FIXME("%p %ld %p %lu %p\n", hService, dwSecurityInformation,
2198 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2200 InitializeSecurityDescriptor(lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
2202 pACL = HeapAlloc( GetProcessHeap(), 0, sizeof(ACL) );
2203 InitializeAcl(pACL, sizeof(ACL), ACL_REVISION);
2204 SetSecurityDescriptorDacl(lpSecurityDescriptor, TRUE, pACL, TRUE);
2205 return TRUE;
2208 /******************************************************************************
2209 * SetServiceObjectSecurity [ADVAPI32.@]
2211 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2212 SECURITY_INFORMATION dwSecurityInformation,
2213 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2215 FIXME("%p %ld %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2216 return TRUE;
2219 /******************************************************************************
2220 * SetServiceBits [ADVAPI32.@]
2222 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2223 DWORD dwServiceBits,
2224 BOOL bSetBitsOn,
2225 BOOL bUpdateImmediately)
2227 FIXME("%08lx %08lx %x %x\n", hServiceStatus, dwServiceBits,
2228 bSetBitsOn, bUpdateImmediately);
2229 return TRUE;