Added YUV routines needed for v4l driver, and in the future possibly
[wine/gsoc-2012-control.git] / dlls / advapi32 / service.c
blobfa5e9dc1624fcbd169e8aebb3018249faecd0518
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"
36 WINE_DEFAULT_DEBUG_CHANNEL(advapi);
38 static const WCHAR szServiceManagerKey[] = { 'S','y','s','t','e','m','\\',
39 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
40 'S','e','r','v','i','c','e','s','\\',0 };
41 static const WCHAR szSCMLock[] = {'A','D','V','A','P','I','_','S','C','M',
42 'L','O','C','K',0};
44 typedef struct service_start_info_t
46 DWORD cmd;
47 DWORD size;
48 WCHAR str[1];
49 } service_start_info;
51 #define WINESERV_STARTINFO 1
52 #define WINESERV_GETSTATUS 2
53 #define WINESERV_SENDCONTROL 3
55 typedef struct service_data_t
57 struct service_data_t *next;
58 LPHANDLER_FUNCTION handler;
59 SERVICE_STATUS status;
60 HANDLE thread;
61 BOOL unicode;
62 union {
63 LPSERVICE_MAIN_FUNCTIONA a;
64 LPSERVICE_MAIN_FUNCTIONW w;
65 } proc;
66 LPWSTR args;
67 WCHAR name[1];
68 } service_data;
70 static CRITICAL_SECTION service_cs;
71 static CRITICAL_SECTION_DEBUG service_cs_debug =
73 0, 0, &service_cs,
74 { &service_cs_debug.ProcessLocksList,
75 &service_cs_debug.ProcessLocksList },
76 0, 0, { 0, (DWORD)(__FILE__ ": service_cs") }
78 static CRITICAL_SECTION service_cs = { &service_cs_debug, -1, 0, 0, 0, 0 };
80 service_data *service_list;
82 /******************************************************************************
83 * SC_HANDLEs
86 #define MAX_SERVICE_NAME 256
88 typedef enum { SC_HTYPE_MANAGER, SC_HTYPE_SERVICE } SC_HANDLE_TYPE;
90 struct sc_handle;
91 typedef VOID (*sc_handle_destructor)(struct sc_handle *);
93 struct sc_handle
95 SC_HANDLE_TYPE htype;
96 DWORD ref_count;
97 sc_handle_destructor destroy;
100 struct sc_manager /* service control manager handle */
102 struct sc_handle hdr;
103 HKEY hkey; /* handle to services database in the registry */
106 struct sc_service /* service handle */
108 struct sc_handle hdr;
109 HKEY hkey; /* handle to service entry in the registry (under hkey) */
110 struct sc_manager *scm; /* pointer to SCM handle */
111 WCHAR name[1];
114 static void *sc_handle_alloc(SC_HANDLE_TYPE htype, DWORD size,
115 sc_handle_destructor destroy)
117 struct sc_handle *hdr;
119 hdr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
120 if (hdr)
122 hdr->htype = htype;
123 hdr->ref_count = 1;
124 hdr->destroy = destroy;
126 TRACE("sc_handle type=%d -> %p\n", htype, hdr);
127 return hdr;
130 static void *sc_handle_get_handle_data(SC_HANDLE handle, DWORD htype)
132 struct sc_handle *hdr = (struct sc_handle *) handle;
134 if (!hdr)
135 return NULL;
136 if (hdr->htype != htype)
137 return NULL;
138 return hdr;
141 static void sc_handle_free(struct sc_handle* hdr)
143 if (!hdr)
144 return;
145 if (--hdr->ref_count)
146 return;
147 hdr->destroy(hdr);
148 HeapFree(GetProcessHeap(), 0, hdr);
151 static void sc_handle_destroy_manager(struct sc_handle *handle)
153 struct sc_manager *mgr = (struct sc_manager*) handle;
155 TRACE("destroying SC Manager %p\n", mgr);
156 if (mgr->hkey)
157 RegCloseKey(mgr->hkey);
160 static void sc_handle_destroy_service(struct sc_handle *handle)
162 struct sc_service *svc = (struct sc_service*) handle;
164 TRACE("destroying service %p\n", svc);
165 if (svc->hkey)
166 RegCloseKey(svc->hkey);
167 svc->hkey = NULL;
168 sc_handle_free(&svc->scm->hdr);
169 svc->scm = NULL;
172 /******************************************************************************
173 * String management functions
175 static inline LPWSTR SERV_dup( LPCSTR str )
177 UINT len;
178 LPWSTR wstr;
180 if( !str )
181 return NULL;
182 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
183 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
184 MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
185 return wstr;
188 static inline LPWSTR SERV_dupmulti(LPCSTR str)
190 UINT len = 0, n = 0;
191 LPWSTR wstr;
193 if( !str )
194 return NULL;
195 do {
196 len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
197 n += (strlen( &str[n] ) + 1);
198 } while (str[n]);
199 len++;
200 n++;
202 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
203 MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
204 return wstr;
207 static inline VOID SERV_free( LPWSTR wstr )
209 HeapFree( GetProcessHeap(), 0, wstr );
212 /******************************************************************************
213 * registry access functions and data
215 static const WCHAR szDisplayName[] = {
216 'D','i','s','p','l','a','y','N','a','m','e', 0 };
217 static const WCHAR szType[] = {'T','y','p','e',0};
218 static const WCHAR szStart[] = {'S','t','a','r','t',0};
219 static const WCHAR szError[] = {
220 'E','r','r','o','r','C','o','n','t','r','o','l', 0};
221 static const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
222 static const WCHAR szGroup[] = {'G','r','o','u','p',0};
223 static const WCHAR szDependencies[] = {
224 'D','e','p','e','n','d','e','n','c','i','e','s',0};
225 static const WCHAR szDependOnService[] = {
226 'D','e','p','e','n','d','O','n','S','e','r','v','i','c','e',0};
228 struct reg_value {
229 DWORD type;
230 DWORD size;
231 LPCWSTR name;
232 LPCVOID data;
235 static inline void service_set_value( struct reg_value *val,
236 DWORD type, LPCWSTR name, LPCVOID data, DWORD size )
238 val->name = name;
239 val->type = type;
240 val->data = data;
241 val->size = size;
244 static inline void service_set_dword( struct reg_value *val,
245 LPCWSTR name, DWORD *data )
247 service_set_value( val, REG_DWORD, name, data, sizeof (DWORD));
250 static inline void service_set_string( struct reg_value *val,
251 LPCWSTR name, LPCWSTR string )
253 DWORD len = (lstrlenW(string)+1) * sizeof (WCHAR);
254 service_set_value( val, REG_SZ, name, string, len );
257 static inline void service_set_multi_string( struct reg_value *val,
258 LPCWSTR name, LPCWSTR string )
260 DWORD len = 0;
262 /* determine the length of a double null terminated multi string */
263 do {
264 len += (lstrlenW( &string[ len ] )+1);
265 } while ( string[ len++ ] );
267 len *= sizeof (WCHAR);
268 service_set_value( val, REG_MULTI_SZ, name, string, len );
271 static inline LONG service_write_values( HKEY hKey,
272 struct reg_value *val, int n )
274 LONG r = ERROR_SUCCESS;
275 int i;
277 for( i=0; i<n; i++ )
279 r = RegSetValueExW(hKey, val[i].name, 0, val[i].type,
280 (const BYTE*)val[i].data, val[i].size );
281 if( r != ERROR_SUCCESS )
282 break;
284 return r;
287 /******************************************************************************
288 * Service IPC functions
290 static LPWSTR service_get_pipe_name(LPWSTR service)
292 static const WCHAR prefix[] = { '\\','\\','.','\\','p','i','p','e','\\',
293 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
294 LPWSTR name;
295 DWORD len;
297 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
298 name = HeapAlloc(GetProcessHeap(), 0, len);
299 strcpyW(name, prefix);
300 strcatW(name, service);
301 return name;
304 static HANDLE service_open_pipe(LPWSTR service)
306 LPWSTR szPipe = service_get_pipe_name( service );
307 HANDLE handle = INVALID_HANDLE_VALUE;
309 do {
310 handle = CreateFileW(szPipe, GENERIC_READ|GENERIC_WRITE,
311 0, NULL, OPEN_ALWAYS, 0, NULL);
312 if (handle != INVALID_HANDLE_VALUE)
313 break;
314 if (GetLastError() != ERROR_PIPE_BUSY)
315 break;
316 } while (WaitNamedPipeW(szPipe, NMPWAIT_WAIT_FOREVER));
317 SERV_free(szPipe);
319 return handle;
322 /******************************************************************************
323 * service_get_event_handle
325 static HANDLE service_get_event_handle(LPWSTR service)
327 static const WCHAR prefix[] = {
328 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
329 LPWSTR name;
330 DWORD len;
331 HANDLE handle;
333 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
334 name = HeapAlloc(GetProcessHeap(), 0, len);
335 strcpyW(name, prefix);
336 strcatW(name, service);
337 handle = CreateEventW(NULL, TRUE, FALSE, name);
338 SERV_free(name);
339 return handle;
342 /******************************************************************************
343 * service_thread
345 * Call into the main service routine provided by StartServiceCtrlDispatcher.
347 static DWORD WINAPI service_thread(LPVOID arg)
349 service_data *info = arg;
350 LPWSTR str = info->args;
351 DWORD argc = 0, len = 0;
353 TRACE("%p\n", arg);
355 while (str[len])
357 len += strlenW(&str[len]) + 1;
358 argc++;
361 if (info->unicode)
363 LPWSTR *argv, p;
365 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPWSTR));
366 for (argc=0, p=str; *p; p += strlenW(p) + 1)
367 argv[argc++] = p;
368 argv[argc] = NULL;
370 info->proc.w(argc, argv);
371 HeapFree(GetProcessHeap(), 0, argv);
373 else
375 LPSTR strA, *argv, p;
376 DWORD lenA;
378 lenA = WideCharToMultiByte(CP_ACP,0, str, len, NULL, 0, NULL, NULL);
379 strA = HeapAlloc(GetProcessHeap(), 0, lenA);
380 WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL);
382 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPSTR));
383 for (argc=0, p=strA; *p; p += strlen(p) + 1)
384 argv[argc++] = p;
385 argv[argc] = NULL;
387 info->proc.a(argc, argv);
388 HeapFree(GetProcessHeap(), 0, argv);
389 HeapFree(GetProcessHeap(), 0, strA);
391 return 0;
394 /******************************************************************************
395 * service_handle_start
397 static BOOL service_handle_start(HANDLE pipe, service_data *service, DWORD count)
399 DWORD read = 0, result = 0;
400 LPWSTR args;
401 BOOL r;
403 TRACE("%p %p %ld\n", pipe, service, count);
405 args = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
406 r = ReadFile(pipe, args, count*sizeof(WCHAR), &read, NULL);
407 if (!r || count!=read/sizeof(WCHAR) || args[count-1])
409 ERR("pipe read failed r = %d count = %ld/%ld args[n-1]=%s\n",
410 r, count, read/sizeof(WCHAR), debugstr_wn(args, count));
411 goto end;
414 if (service->thread)
416 ERR("service is not stopped\n");
417 goto end;
420 if (service->args)
421 SERV_free(service->args);
422 service->args = args;
423 args = NULL;
424 service->thread = CreateThread( NULL, 0, service_thread,
425 service, 0, NULL );
427 end:
428 HeapFree(GetProcessHeap(), 0, args);
429 WriteFile( pipe, &result, sizeof result, &read, NULL );
431 return TRUE;
434 /******************************************************************************
435 * service_send_start_message
437 static BOOL service_send_start_message(HANDLE pipe, LPCWSTR *argv, DWORD argc)
439 DWORD i, len, count, result;
440 service_start_info *ssi;
441 LPWSTR p;
442 BOOL r;
444 TRACE("%p %p %ld\n", pipe, argv, argc);
446 /* calculate how much space do we need to send the startup info */
447 len = 1;
448 for (i=0; i<argc; i++)
449 len += strlenW(argv[i])+1;
451 ssi = HeapAlloc(GetProcessHeap(),0,sizeof *ssi + (len-1)*sizeof(WCHAR));
452 ssi->cmd = WINESERV_STARTINFO;
453 ssi->size = len;
455 /* copy service args into a single buffer*/
456 p = &ssi->str[0];
457 for (i=0; i<argc; i++)
459 strcpyW(p, argv[i]);
460 p += strlenW(p) + 1;
462 *p=0;
464 r = WriteFile(pipe, ssi, sizeof *ssi + len*sizeof(WCHAR), &count, NULL);
465 if (r)
466 r = ReadFile(pipe, &result, sizeof result, &count, NULL);
468 HeapFree(GetProcessHeap(),0,ssi);
470 return r;
473 /******************************************************************************
474 * service_handle_get_status
476 static BOOL service_handle_get_status(HANDLE pipe, service_data *service)
478 DWORD count = 0;
479 TRACE("\n");
480 return WriteFile(pipe, &service->status,
481 sizeof service->status, &count, NULL);
484 /******************************************************************************
485 * service_get_status
487 static BOOL service_get_status(HANDLE pipe, LPSERVICE_STATUS status)
489 DWORD cmd[2], count = 0;
490 BOOL r;
492 cmd[0] = WINESERV_GETSTATUS;
493 cmd[1] = 0;
494 r = WriteFile( pipe, cmd, sizeof cmd, &count, NULL );
495 if (!r || count != sizeof cmd)
497 ERR("service protocol error - failed to write pipe!\n");
498 return r;
500 r = ReadFile( pipe, status, sizeof *status, &count, NULL );
501 if (!r || count != sizeof *status)
502 ERR("service protocol error - failed to read pipe "
503 "r = %d count = %ld/%d!\n", r, count, sizeof *status);
504 return r;
507 /******************************************************************************
508 * service_send_control
510 static BOOL service_send_control(HANDLE pipe, DWORD dwControl, DWORD *result)
512 DWORD cmd[2], count = 0;
513 BOOL r;
515 cmd[0] = WINESERV_SENDCONTROL;
516 cmd[1] = dwControl;
517 r = WriteFile(pipe, cmd, sizeof cmd, &count, NULL);
518 if (!r || count != sizeof cmd)
520 ERR("service protocol error - failed to write pipe!\n");
521 return r;
523 r = ReadFile(pipe, result, sizeof *result, &count, NULL);
524 if (!r || count != sizeof *result)
525 ERR("service protocol error - failed to read pipe "
526 "r = %d count = %ld/%d!\n", r, count, sizeof *result);
527 return r;
530 /******************************************************************************
531 * service_accepts_control
533 static BOOL service_accepts_control(service_data *service, DWORD dwControl)
535 DWORD a = service->status.dwControlsAccepted;
537 switch (dwControl)
539 case SERVICE_CONTROL_INTERROGATE:
540 return TRUE;
541 case SERVICE_CONTROL_STOP:
542 if (a&SERVICE_ACCEPT_STOP)
543 return TRUE;
544 break;
545 case SERVICE_CONTROL_SHUTDOWN:
546 if (a&SERVICE_ACCEPT_SHUTDOWN)
547 return TRUE;
548 break;
549 case SERVICE_CONTROL_PAUSE:
550 case SERVICE_CONTROL_CONTINUE:
551 if (a&SERVICE_ACCEPT_PAUSE_CONTINUE)
552 return TRUE;
553 break;
554 case SERVICE_CONTROL_PARAMCHANGE:
555 if (a&SERVICE_ACCEPT_PARAMCHANGE)
556 return TRUE;
557 break;
558 case SERVICE_CONTROL_NETBINDADD:
559 case SERVICE_CONTROL_NETBINDREMOVE:
560 case SERVICE_CONTROL_NETBINDENABLE:
561 case SERVICE_CONTROL_NETBINDDISABLE:
562 if (a&SERVICE_ACCEPT_NETBINDCHANGE)
563 return TRUE;
565 if (1) /* (!service->handlerex) */
566 return FALSE;
567 switch (dwControl)
569 case SERVICE_CONTROL_HARDWAREPROFILECHANGE:
570 if (a&SERVICE_ACCEPT_HARDWAREPROFILECHANGE)
571 return TRUE;
572 break;
573 case SERVICE_CONTROL_POWEREVENT:
574 if (a&SERVICE_ACCEPT_POWEREVENT)
575 return TRUE;
576 break;
577 case SERVICE_CONTROL_SESSIONCHANGE:
578 if (a&SERVICE_ACCEPT_SESSIONCHANGE)
579 return TRUE;
580 break;
582 return FALSE;
585 /******************************************************************************
586 * service_handle_control
588 static BOOL service_handle_control(HANDLE pipe, service_data *service,
589 DWORD dwControl)
591 DWORD count, ret = ERROR_INVALID_SERVICE_CONTROL;
593 TRACE("received control %ld\n", dwControl);
595 if (service_accepts_control(service, dwControl) && service->handler)
597 service->handler(dwControl);
598 ret = ERROR_SUCCESS;
600 return WriteFile(pipe, &ret, sizeof ret, &count, NULL);
603 /******************************************************************************
604 * service_reap_thread
606 static DWORD service_reap_thread(service_data *service)
608 DWORD exitcode = 0;
610 if (!service->thread)
611 return 0;
612 GetExitCodeThread(service->thread, &exitcode);
613 if (exitcode!=STILL_ACTIVE)
615 CloseHandle(service->thread);
616 service->thread = 0;
618 return exitcode;
621 /******************************************************************************
622 * service_control_dispatcher
624 static DWORD WINAPI service_control_dispatcher(LPVOID arg)
626 service_data *service = arg;
627 LPWSTR name;
628 HANDLE pipe, event;
630 TRACE("%p %s\n", service, debugstr_w(service->name));
632 /* create a pipe to talk to the rest of the world with */
633 name = service_get_pipe_name(service->name);
634 pipe = CreateNamedPipeW(name, PIPE_ACCESS_DUPLEX,
635 PIPE_TYPE_BYTE|PIPE_WAIT, 1, 256, 256, 10000, NULL );
636 SERV_free(name);
638 /* let the process who started us know we've tried to create a pipe */
639 event = service_get_event_handle(service->name);
640 SetEvent(event);
641 CloseHandle(event);
643 if (pipe==INVALID_HANDLE_VALUE)
645 ERR("failed to create pipe, error = %ld\n", GetLastError());
646 return 0;
649 /* dispatcher loop */
650 while (1)
652 BOOL r;
653 DWORD count, req[2] = {0,0};
655 r = ConnectNamedPipe(pipe, NULL);
656 if (!r && GetLastError() != ERROR_PIPE_CONNECTED)
658 ERR("pipe connect failed\n");
659 break;
662 r = ReadFile( pipe, &req, sizeof req, &count, NULL );
663 if (!r || count!=sizeof req)
665 ERR("pipe read failed\n");
666 break;
669 service_reap_thread(service);
671 /* handle the request */
672 switch (req[0])
674 case WINESERV_STARTINFO:
675 service_handle_start(pipe, service, req[1]);
676 break;
677 case WINESERV_GETSTATUS:
678 service_handle_get_status(pipe, service);
679 break;
680 case WINESERV_SENDCONTROL:
681 service_handle_control(pipe, service, req[1]);
682 break;
683 default:
684 ERR("received invalid command %ld length %ld\n", req[0], req[1]);
687 FlushFileBuffers(pipe);
688 DisconnectNamedPipe(pipe);
691 CloseHandle(pipe);
692 return 1;
695 /******************************************************************************
696 * service_run_threads
698 static BOOL service_run_threads(void)
700 service_data *service;
701 DWORD count = 0, n = 0;
702 HANDLE *handles;
704 EnterCriticalSection( &service_cs );
706 /* count how many services there are */
707 for (service = service_list; service; service = service->next)
708 count++;
710 TRACE("starting %ld pipe listener threads\n", count);
712 handles = HeapAlloc(GetProcessHeap(), 0, sizeof(HANDLE)*count);
714 for (n=0, service = service_list; service; service = service->next, n++)
715 handles[n] = CreateThread( NULL, 0, service_control_dispatcher,
716 service, 0, NULL );
717 assert(n==count);
719 LeaveCriticalSection( &service_cs );
721 /* wait for all the threads to pack up and exit */
722 WaitForMultipleObjectsEx(count, handles, TRUE, INFINITE, FALSE);
724 HeapFree(GetProcessHeap(), 0, handles);
726 return TRUE;
729 /******************************************************************************
730 * StartServiceCtrlDispatcherA [ADVAPI32.@]
732 * Connects a process containing one or more services to the service control
733 * manager.
735 * PARAMS
736 * servent [I] A list of the service names and service procedures
738 BOOL WINAPI StartServiceCtrlDispatcherA( LPSERVICE_TABLE_ENTRYA servent )
740 service_data *info;
741 DWORD sz, len;
742 BOOL ret = TRUE;
744 TRACE("%p\n", servent);
746 EnterCriticalSection( &service_cs );
747 while (servent->lpServiceName)
749 LPSTR name = servent->lpServiceName;
751 len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0);
752 sz = len*sizeof(WCHAR) + sizeof *info;
753 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
754 MultiByteToWideChar(CP_ACP, 0, name, -1, info->name, len);
755 info->proc.a = servent->lpServiceProc;
756 info->unicode = FALSE;
758 /* insert into the list */
759 info->next = service_list;
760 service_list = info;
762 servent++;
764 LeaveCriticalSection( &service_cs );
766 service_run_threads();
768 return ret;
771 /******************************************************************************
772 * StartServiceCtrlDispatcherW [ADVAPI32.@]
774 * Connects a process containing one or more services to the service control
775 * manager.
777 * PARAMS
778 * servent [I] A list of the service names and service procedures
780 BOOL WINAPI StartServiceCtrlDispatcherW( LPSERVICE_TABLE_ENTRYW servent )
782 service_data *info;
783 DWORD sz, len;
784 BOOL ret = TRUE;
786 TRACE("%p\n", servent);
788 EnterCriticalSection( &service_cs );
789 while (servent->lpServiceName)
791 LPWSTR name = servent->lpServiceName;
793 len = strlenW(name);
794 sz = len*sizeof(WCHAR) + sizeof *info;
795 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
796 strcpyW(info->name, name);
797 info->proc.w = servent->lpServiceProc;
798 info->unicode = TRUE;
800 /* insert into the list */
801 info->next = service_list;
802 service_list = info;
804 servent++;
806 LeaveCriticalSection( &service_cs );
808 service_run_threads();
810 return ret;
813 /******************************************************************************
814 * LockServiceDatabase [ADVAPI32.@]
816 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
818 HANDLE ret;
820 TRACE("%p\n",hSCManager);
822 ret = CreateSemaphoreW( NULL, 1, 1, szSCMLock );
823 if( ret && GetLastError() == ERROR_ALREADY_EXISTS )
825 CloseHandle( ret );
826 ret = NULL;
827 SetLastError( ERROR_SERVICE_DATABASE_LOCKED );
830 TRACE("returning %p\n", ret);
832 return ret;
835 /******************************************************************************
836 * UnlockServiceDatabase [ADVAPI32.@]
838 BOOL WINAPI UnlockServiceDatabase (SC_LOCK ScLock)
840 TRACE("%p\n",ScLock);
842 return CloseHandle( ScLock );
845 /******************************************************************************
846 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
848 SERVICE_STATUS_HANDLE WINAPI
849 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName, LPHANDLER_FUNCTION lpfHandler )
851 LPWSTR lpServiceNameW;
852 SERVICE_STATUS_HANDLE ret;
854 lpServiceNameW = SERV_dup(lpServiceName);
855 ret = RegisterServiceCtrlHandlerW( lpServiceNameW, lpfHandler );
856 SERV_free(lpServiceNameW);
857 return ret;
860 /******************************************************************************
861 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
863 * PARAMS
864 * lpServiceName []
865 * lpfHandler []
867 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName,
868 LPHANDLER_FUNCTION lpfHandler )
870 service_data *service;
872 EnterCriticalSection( &service_cs );
873 for(service = service_list; service; service = service->next)
874 if(!strcmpW(lpServiceName, service->name))
875 break;
876 if (service)
877 service->handler = lpfHandler;
878 LeaveCriticalSection( &service_cs );
880 return (SERVICE_STATUS_HANDLE)service;
883 /******************************************************************************
884 * SetServiceStatus [ADVAPI32.@]
886 * PARAMS
887 * hService []
888 * lpStatus []
890 BOOL WINAPI
891 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
893 service_data *service;
894 BOOL r = TRUE;
896 TRACE("%lx %lx %lx %lx %lx %lx %lx %lx\n", hService,
897 lpStatus->dwServiceType, lpStatus->dwCurrentState,
898 lpStatus->dwControlsAccepted, lpStatus->dwWin32ExitCode,
899 lpStatus->dwServiceSpecificExitCode, lpStatus->dwCheckPoint,
900 lpStatus->dwWaitHint);
902 EnterCriticalSection( &service_cs );
903 for (service = service_list; service; service = service->next)
904 if(service == (service_data*)hService)
905 break;
906 if (service)
908 memcpy( &service->status, lpStatus, sizeof(SERVICE_STATUS) );
909 TRACE("Set service status to %ld\n",service->status.dwCurrentState);
911 else
912 r = FALSE;
913 LeaveCriticalSection( &service_cs );
915 return r;
919 /******************************************************************************
920 * OpenSCManagerA [ADVAPI32.@]
922 * Establish a connection to the service control manager and open its database.
924 * PARAMS
925 * lpMachineName [I] Pointer to machine name string
926 * lpDatabaseName [I] Pointer to database name string
927 * dwDesiredAccess [I] Type of access
929 * RETURNS
930 * Success: A Handle to the service control manager database
931 * Failure: NULL
933 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
934 DWORD dwDesiredAccess )
936 LPWSTR lpMachineNameW, lpDatabaseNameW;
937 SC_HANDLE ret;
939 lpMachineNameW = SERV_dup(lpMachineName);
940 lpDatabaseNameW = SERV_dup(lpDatabaseName);
941 ret = OpenSCManagerW(lpMachineNameW, lpDatabaseNameW, dwDesiredAccess);
942 SERV_free(lpDatabaseNameW);
943 SERV_free(lpMachineNameW);
944 return ret;
947 /******************************************************************************
948 * OpenSCManagerW [ADVAPI32.@]
950 * See OpenSCManagerA.
952 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
953 DWORD dwDesiredAccess )
955 struct sc_manager *manager;
956 HKEY hReg;
957 LONG r;
959 TRACE("(%s,%s,0x%08lx)\n", debugstr_w(lpMachineName),
960 debugstr_w(lpDatabaseName), dwDesiredAccess);
962 if( lpDatabaseName && lpDatabaseName[0] )
964 if( strcmpiW( lpDatabaseName, SERVICES_ACTIVE_DATABASEW ) == 0 )
966 /* noop, all right */
968 else if( strcmpiW( lpDatabaseName, SERVICES_FAILED_DATABASEW ) == 0 )
970 SetLastError( ERROR_DATABASE_DOES_NOT_EXIST );
971 return NULL;
973 else
975 SetLastError( ERROR_INVALID_NAME );
976 return NULL;
980 manager = sc_handle_alloc( SC_HTYPE_MANAGER, sizeof (struct sc_manager),
981 sc_handle_destroy_manager );
982 if (!manager)
983 return NULL;
985 r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
986 if (r!=ERROR_SUCCESS)
987 goto error;
989 r = RegOpenKeyExW(hReg, szServiceManagerKey,
990 0, KEY_ALL_ACCESS, &manager->hkey);
991 RegCloseKey( hReg );
992 if (r!=ERROR_SUCCESS)
993 goto error;
995 TRACE("returning %p\n", manager);
997 return (SC_HANDLE) &manager->hdr;
999 error:
1000 sc_handle_free( &manager->hdr );
1001 return NULL;
1004 /******************************************************************************
1005 * ControlService [ADVAPI32.@]
1007 * Send a control code to a service.
1009 * PARAMS
1010 * hService [I] Handle of the service control manager database
1011 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
1012 * lpServiceStatus [O] Destination for the status of the service, if available
1014 * RETURNS
1015 * Success: TRUE.
1016 * Failure: FALSE.
1018 * BUGS
1019 * Unlike M$' implementation, control requests are not serialized and may be
1020 * processed asynchronously.
1022 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
1023 LPSERVICE_STATUS lpServiceStatus )
1025 struct sc_service *hsvc;
1026 BOOL ret = FALSE;
1027 HANDLE handle;
1029 TRACE("%p %ld %p\n", hService, dwControl, lpServiceStatus);
1031 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1032 if (!hsvc)
1034 SetLastError( ERROR_INVALID_HANDLE );
1035 return FALSE;
1038 ret = QueryServiceStatus(hService, lpServiceStatus);
1039 if (!ret)
1041 ERR("failed to query service status\n");
1042 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1043 return FALSE;
1046 switch (lpServiceStatus->dwCurrentState)
1048 case SERVICE_STOPPED:
1049 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1050 return FALSE;
1051 case SERVICE_START_PENDING:
1052 if (dwControl==SERVICE_CONTROL_STOP)
1053 break;
1054 /* fall thru */
1055 case SERVICE_STOP_PENDING:
1056 SetLastError(ERROR_SERVICE_CANNOT_ACCEPT_CTRL);
1057 return FALSE;
1060 handle = service_open_pipe(hsvc->name);
1061 if (handle!=INVALID_HANDLE_VALUE)
1063 DWORD result = ERROR_SUCCESS;
1064 ret = service_send_control(handle, dwControl, &result);
1065 CloseHandle(handle);
1066 if (result!=ERROR_SUCCESS)
1068 SetLastError(result);
1069 ret = FALSE;
1073 return ret;
1076 /******************************************************************************
1077 * CloseServiceHandle [ADVAPI32.@]
1079 * Close a handle to a service or the service control manager database.
1081 * PARAMS
1082 * hSCObject [I] Handle to service or service control manager database
1084 * RETURNS
1085 * Success: TRUE
1086 * Failure: FALSE
1088 BOOL WINAPI
1089 CloseServiceHandle( SC_HANDLE hSCObject )
1091 TRACE("%p\n", hSCObject);
1093 sc_handle_free( (struct sc_handle*) hSCObject );
1095 return TRUE;
1099 /******************************************************************************
1100 * OpenServiceA [ADVAPI32.@]
1102 * Open a handle to a service.
1104 * PARAMS
1105 * hSCManager [I] Handle of the service control manager database
1106 * lpServiceName [I] Name of the service to open
1107 * dwDesiredAccess [I] Access required to the service
1109 * RETURNS
1110 * Success: Handle to the service
1111 * Failure: NULL
1113 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1114 DWORD dwDesiredAccess )
1116 LPWSTR lpServiceNameW;
1117 SC_HANDLE ret;
1119 TRACE("%p %s %ld\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
1121 lpServiceNameW = SERV_dup(lpServiceName);
1122 ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
1123 SERV_free(lpServiceNameW);
1124 return ret;
1128 /******************************************************************************
1129 * OpenServiceW [ADVAPI32.@]
1131 * See OpenServiceA.
1133 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1134 DWORD dwDesiredAccess)
1136 struct sc_manager *hscm;
1137 struct sc_service *hsvc;
1138 HKEY hKey;
1139 long r;
1140 DWORD len;
1142 TRACE("%p %s %ld\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
1144 if (!lpServiceName)
1146 SetLastError(ERROR_INVALID_ADDRESS);
1147 return NULL;
1150 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1151 if (!hscm)
1153 SetLastError( ERROR_INVALID_HANDLE );
1154 return FALSE;
1157 r = RegOpenKeyExW( hscm->hkey, lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
1158 if (r!=ERROR_SUCCESS)
1160 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
1161 return NULL;
1164 len = strlenW(lpServiceName)+1;
1165 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE,
1166 sizeof (struct sc_service) + len*sizeof(WCHAR),
1167 sc_handle_destroy_service );
1168 if (!hsvc)
1169 return NULL;
1170 strcpyW( hsvc->name, lpServiceName );
1171 hsvc->hkey = hKey;
1173 /* add reference to SCM handle */
1174 hscm->hdr.ref_count++;
1175 hsvc->scm = hscm;
1177 TRACE("returning %p\n",hsvc);
1179 return (SC_HANDLE) &hsvc->hdr;
1182 /******************************************************************************
1183 * CreateServiceW [ADVAPI32.@]
1185 SC_HANDLE WINAPI
1186 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1187 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
1188 DWORD dwServiceType, DWORD dwStartType,
1189 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1190 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1191 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
1192 LPCWSTR lpPassword )
1194 struct sc_manager *hscm;
1195 struct sc_service *hsvc = NULL;
1196 HKEY hKey;
1197 LONG r;
1198 DWORD dp, len;
1199 struct reg_value val[10];
1200 int n = 0;
1202 TRACE("%p %s %s\n", hSCManager,
1203 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
1205 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1206 if (!hscm)
1208 SetLastError( ERROR_INVALID_HANDLE );
1209 return NULL;
1212 r = RegCreateKeyExW(hscm->hkey, lpServiceName, 0, NULL,
1213 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
1214 if (r!=ERROR_SUCCESS)
1215 return NULL;
1217 if (dp != REG_CREATED_NEW_KEY)
1219 SetLastError(ERROR_SERVICE_EXISTS);
1220 goto error;
1223 if( lpDisplayName )
1224 service_set_string( &val[n++], szDisplayName, lpDisplayName );
1226 service_set_dword( &val[n++], szType, &dwServiceType );
1227 service_set_dword( &val[n++], szStart, &dwStartType );
1228 service_set_dword( &val[n++], szError, &dwErrorControl );
1230 if( lpBinaryPathName )
1231 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
1233 if( lpLoadOrderGroup )
1234 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
1236 if( lpDependencies )
1237 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
1239 if( lpPassword )
1240 FIXME("Don't know how to add a Password for a service.\n");
1242 if( lpServiceStartName )
1243 service_set_string( &val[n++], szDependOnService, lpServiceStartName );
1245 r = service_write_values( hKey, val, n );
1246 if( r != ERROR_SUCCESS )
1247 goto error;
1249 len = strlenW(lpServiceName)+1;
1250 len = sizeof (struct sc_service) + len*sizeof(WCHAR);
1251 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE, len, sc_handle_destroy_service );
1252 if( !hsvc )
1253 goto error;
1254 lstrcpyW( hsvc->name, lpServiceName );
1255 hsvc->hkey = hKey;
1256 hsvc->scm = hscm;
1257 hscm->hdr.ref_count++;
1259 return (SC_HANDLE) &hsvc->hdr;
1261 error:
1262 RegCloseKey( hKey );
1263 return NULL;
1267 /******************************************************************************
1268 * CreateServiceA [ADVAPI32.@]
1270 SC_HANDLE WINAPI
1271 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1272 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1273 DWORD dwServiceType, DWORD dwStartType,
1274 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1275 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1276 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1277 LPCSTR lpPassword )
1279 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1280 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1281 SC_HANDLE r;
1283 TRACE("%p %s %s\n", hSCManager,
1284 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1286 lpServiceNameW = SERV_dup( lpServiceName );
1287 lpDisplayNameW = SERV_dup( lpDisplayName );
1288 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1289 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1290 lpDependenciesW = SERV_dupmulti( lpDependencies );
1291 lpServiceStartNameW = SERV_dup( lpServiceStartName );
1292 lpPasswordW = SERV_dup( lpPassword );
1294 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1295 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1296 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1297 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1299 SERV_free( lpServiceNameW );
1300 SERV_free( lpDisplayNameW );
1301 SERV_free( lpBinaryPathNameW );
1302 SERV_free( lpLoadOrderGroupW );
1303 SERV_free( lpDependenciesW );
1304 SERV_free( lpServiceStartNameW );
1305 SERV_free( lpPasswordW );
1307 return r;
1311 /******************************************************************************
1312 * DeleteService [ADVAPI32.@]
1314 * Delete a service from the service control manager database.
1316 * PARAMS
1317 * hService [I] Handle of the service to delete
1319 * RETURNS
1320 * Success: TRUE
1321 * Failure: FALSE
1323 BOOL WINAPI DeleteService( SC_HANDLE hService )
1325 struct sc_service *hsvc;
1326 HKEY hKey;
1327 WCHAR valname[MAX_PATH+1];
1328 INT index = 0;
1329 LONG rc;
1330 DWORD size;
1332 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1333 if (!hsvc)
1335 SetLastError( ERROR_INVALID_HANDLE );
1336 return FALSE;
1338 hKey = hsvc->hkey;
1340 size = MAX_PATH+1;
1341 /* Clean out the values */
1342 rc = RegEnumValueW(hKey, index, valname,&size,0,0,0,0);
1343 while (rc == ERROR_SUCCESS)
1345 RegDeleteValueW(hKey,valname);
1346 index++;
1347 size = MAX_PATH+1;
1348 rc = RegEnumValueW(hKey, index, valname, &size,0,0,0,0);
1351 RegCloseKey(hKey);
1352 hsvc->hkey = NULL;
1354 /* delete the key */
1355 RegDeleteKeyW(hsvc->scm->hkey, hsvc->name);
1357 return TRUE;
1361 /******************************************************************************
1362 * StartServiceA [ADVAPI32.@]
1364 * Start a service
1366 * PARAMS
1367 * hService [I] Handle of service
1368 * dwNumServiceArgs [I] Number of arguments
1369 * lpServiceArgVectors [I] Address of array of argument strings
1371 * NOTES
1372 * - NT implements this function using an obscure RPC call.
1373 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1374 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1375 * - This will only work for shared address space. How should the service
1376 * args be transferred when address spaces are separated?
1377 * - Can only start one service at a time.
1378 * - Has no concept of privilege.
1380 * RETURNS
1381 * Success: TRUE.
1382 * Failure: FALSE
1384 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1385 LPCSTR *lpServiceArgVectors )
1387 LPWSTR *lpwstr=NULL;
1388 unsigned int i;
1389 BOOL r;
1391 TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1393 if (dwNumServiceArgs)
1394 lpwstr = HeapAlloc( GetProcessHeap(), 0,
1395 dwNumServiceArgs*sizeof(LPWSTR) );
1397 for(i=0; i<dwNumServiceArgs; i++)
1398 lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1400 r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1402 if (dwNumServiceArgs)
1404 for(i=0; i<dwNumServiceArgs; i++)
1405 SERV_free(lpwstr[i]);
1406 HeapFree(GetProcessHeap(), 0, lpwstr);
1409 return r;
1412 /******************************************************************************
1413 * service_start_process [INTERNAL]
1415 static DWORD service_start_process(struct sc_service *hsvc)
1417 static const WCHAR _ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0};
1418 PROCESS_INFORMATION pi;
1419 STARTUPINFOW si;
1420 LPWSTR path = NULL, str;
1421 DWORD type, size, ret;
1422 HANDLE handles[2];
1423 BOOL r;
1425 /* read the executable path from memory */
1426 size = 0;
1427 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, NULL, &size);
1428 if (ret!=ERROR_SUCCESS)
1429 return FALSE;
1430 str = HeapAlloc(GetProcessHeap(),0,size);
1431 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, (LPBYTE)str, &size);
1432 if (ret==ERROR_SUCCESS)
1434 size = ExpandEnvironmentStringsW(str,NULL,0);
1435 path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
1436 ExpandEnvironmentStringsW(str,path,size);
1438 HeapFree(GetProcessHeap(),0,str);
1439 if (!path)
1440 return FALSE;
1442 /* wait for the process to start and set an event or terminate */
1443 handles[0] = service_get_event_handle( hsvc->name );
1444 ZeroMemory(&si, sizeof(STARTUPINFOW));
1445 si.cb = sizeof(STARTUPINFOW);
1446 r = CreateProcessW(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1447 if (r)
1449 handles[1] = pi.hProcess;
1450 ret = WaitForMultipleObjectsEx(2, handles, FALSE, 30000, FALSE);
1451 if(ret != WAIT_OBJECT_0)
1453 SetLastError(ERROR_IO_PENDING);
1454 r = FALSE;
1457 CloseHandle( pi.hThread );
1458 CloseHandle( pi.hProcess );
1460 CloseHandle( handles[0] );
1461 HeapFree(GetProcessHeap(),0,path);
1462 return r;
1465 static BOOL service_wait_for_startup(SC_HANDLE hService)
1467 DWORD i;
1468 SERVICE_STATUS status;
1469 BOOL r = FALSE;
1471 TRACE("%p\n", hService);
1473 for (i=0; i<30; i++)
1475 status.dwCurrentState = 0;
1476 r = QueryServiceStatus(hService, &status);
1477 if (!r)
1478 break;
1479 if (status.dwCurrentState == SERVICE_RUNNING)
1481 TRACE("Service started successfully\n");
1482 break;
1484 r = FALSE;
1485 Sleep(1000);
1487 return r;
1490 /******************************************************************************
1491 * StartServiceW [ADVAPI32.@]
1493 * See StartServiceA.
1495 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1496 LPCWSTR *lpServiceArgVectors)
1498 struct sc_service *hsvc;
1499 BOOL r = FALSE;
1500 SC_LOCK hLock;
1501 HANDLE handle = INVALID_HANDLE_VALUE;
1503 TRACE("%p %ld %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1505 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1506 if (!hsvc)
1508 SetLastError(ERROR_INVALID_HANDLE);
1509 return r;
1512 hLock = LockServiceDatabase(hsvc->scm);
1513 if (!hLock)
1514 return r;
1516 handle = service_open_pipe(hsvc->name);
1517 if (handle==INVALID_HANDLE_VALUE)
1519 /* start the service process */
1520 if (service_start_process(hsvc))
1521 handle = service_open_pipe(hsvc->name);
1524 if (handle != INVALID_HANDLE_VALUE)
1526 service_send_start_message(handle, lpServiceArgVectors, dwNumServiceArgs);
1527 CloseHandle(handle);
1528 r = TRUE;
1531 UnlockServiceDatabase( hLock );
1533 TRACE("returning %d\n", r);
1535 service_wait_for_startup(hService);
1537 return r;
1540 /******************************************************************************
1541 * QueryServiceStatus [ADVAPI32.@]
1543 * PARAMS
1544 * hService []
1545 * lpservicestatus []
1548 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1549 LPSERVICE_STATUS lpservicestatus)
1551 struct sc_service *hsvc;
1552 DWORD size, type, val;
1553 HANDLE pipe;
1554 LONG r;
1556 TRACE("%p %p\n", hService, lpservicestatus);
1558 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1559 if (!hsvc)
1561 SetLastError( ERROR_INVALID_HANDLE );
1562 return FALSE;
1565 pipe = service_open_pipe(hsvc->name);
1566 if (pipe != INVALID_HANDLE_VALUE)
1568 r = service_get_status(pipe, lpservicestatus);
1569 CloseHandle(pipe);
1570 if (r)
1571 return TRUE;
1574 TRACE("Failed to read service status\n");
1576 /* read the service type from the registry */
1577 size = sizeof(val);
1578 r = RegQueryValueExA(hsvc->hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1579 if(r!=ERROR_SUCCESS || type!=REG_DWORD)
1580 val = 0;
1582 lpservicestatus->dwServiceType = val;
1583 lpservicestatus->dwCurrentState = SERVICE_STOPPED; /* stopped */
1584 lpservicestatus->dwControlsAccepted = 0;
1585 lpservicestatus->dwWin32ExitCode = ERROR_SERVICE_NEVER_STARTED;
1586 lpservicestatus->dwServiceSpecificExitCode = 0;
1587 lpservicestatus->dwCheckPoint = 0;
1588 lpservicestatus->dwWaitHint = 0;
1590 return TRUE;
1593 /******************************************************************************
1594 * QueryServiceStatusEx [ADVAPI32.@]
1596 * Get information about a service.
1598 * PARAMS
1599 * hService [I] Handle to service to get information about
1600 * InfoLevel [I] Level of information to get
1601 * lpBuffer [O] Destination for requested information
1602 * cbBufSize [I] Size of lpBuffer in bytes
1603 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1605 * RETURNS
1606 * Success: TRUE
1607 * FAILURE: FALSE
1609 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1610 LPBYTE lpBuffer, DWORD cbBufSize,
1611 LPDWORD pcbBytesNeeded)
1613 FIXME("stub\n");
1614 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1615 return FALSE;
1618 /******************************************************************************
1619 * QueryServiceConfigA [ADVAPI32.@]
1621 BOOL WINAPI
1622 QueryServiceConfigA( SC_HANDLE hService,
1623 LPQUERY_SERVICE_CONFIGA lpServiceConfig,
1624 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1626 static const CHAR szDisplayName[] = "DisplayName";
1627 static const CHAR szType[] = "Type";
1628 static const CHAR szStart[] = "Start";
1629 static const CHAR szError[] = "ErrorControl";
1630 static const CHAR szImagePath[] = "ImagePath";
1631 static const CHAR szGroup[] = "Group";
1632 static const CHAR szDependencies[] = "Dependencies";
1633 struct sc_service *hsvc;
1634 HKEY hKey;
1635 CHAR str_buffer[ MAX_PATH ];
1636 LONG r;
1637 DWORD type, val, sz, total, n;
1638 LPBYTE p;
1640 TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
1641 cbBufSize, pcbBytesNeeded);
1643 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1644 if (!hsvc)
1646 SetLastError( ERROR_INVALID_HANDLE );
1647 return FALSE;
1649 hKey = hsvc->hkey;
1651 /* calculate the size required first */
1652 total = sizeof (QUERY_SERVICE_CONFIGA);
1654 sz = sizeof(str_buffer);
1655 r = RegQueryValueExA( hKey, szImagePath, 0, &type, str_buffer, &sz );
1656 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1658 sz = ExpandEnvironmentStringsA(str_buffer,NULL,0);
1659 if( 0 == sz ) return FALSE;
1661 total += sz;
1663 else
1665 /* FIXME: set last error */
1666 return FALSE;
1669 sz = 0;
1670 r = RegQueryValueExA( hKey, szGroup, 0, &type, NULL, &sz );
1671 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1672 total += sz;
1674 sz = 0;
1675 r = RegQueryValueExA( hKey, szDependencies, 0, &type, NULL, &sz );
1676 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1677 total += sz;
1679 sz = 0;
1680 r = RegQueryValueExA( hKey, szStart, 0, &type, NULL, &sz );
1681 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1682 total += sz;
1684 sz = 0;
1685 r = RegQueryValueExA( hKey, szDisplayName, 0, &type, NULL, &sz );
1686 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1687 total += sz;
1689 *pcbBytesNeeded = total;
1691 /* if there's not enough memory, return an error */
1692 if( total > cbBufSize )
1694 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1695 return FALSE;
1698 ZeroMemory( lpServiceConfig, total );
1700 sz = sizeof val;
1701 r = RegQueryValueExA( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1702 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1703 lpServiceConfig->dwServiceType = val;
1705 sz = sizeof val;
1706 r = RegQueryValueExA( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1707 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1708 lpServiceConfig->dwStartType = val;
1710 sz = sizeof val;
1711 r = RegQueryValueExA( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1712 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1713 lpServiceConfig->dwErrorControl = val;
1715 /* now do the strings */
1716 p = (LPBYTE) &lpServiceConfig[1];
1717 n = total - sizeof (QUERY_SERVICE_CONFIGA);
1719 sz = sizeof(str_buffer);
1720 r = RegQueryValueExA( hKey, szImagePath, 0, &type, str_buffer, &sz );
1721 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1723 sz = ExpandEnvironmentStringsA(str_buffer, p, n);
1724 if( 0 == sz || sz > n ) return FALSE;
1726 lpServiceConfig->lpBinaryPathName = (LPSTR) p;
1727 p += sz;
1728 n -= sz;
1730 else
1732 /* FIXME: set last error */
1733 return FALSE;
1736 sz = n;
1737 r = RegQueryValueExA( hKey, szGroup, 0, &type, p, &sz );
1738 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1740 lpServiceConfig->lpLoadOrderGroup = (LPSTR) p;
1741 p += sz;
1742 n -= sz;
1745 sz = n;
1746 r = RegQueryValueExA( hKey, szDependencies, 0, &type, p, &sz );
1747 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1749 lpServiceConfig->lpDependencies = (LPSTR) p;
1750 p += sz;
1751 n -= sz;
1754 if( n < 0 )
1755 ERR("Buffer overflow!\n");
1757 TRACE("Image path = %s\n", lpServiceConfig->lpBinaryPathName );
1758 TRACE("Group = %s\n", lpServiceConfig->lpLoadOrderGroup );
1760 return TRUE;
1763 /******************************************************************************
1764 * QueryServiceConfigW [ADVAPI32.@]
1766 BOOL WINAPI
1767 QueryServiceConfigW( SC_HANDLE hService,
1768 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1769 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1771 WCHAR str_buffer[ MAX_PATH ];
1772 LONG r;
1773 DWORD type, val, sz, total, n;
1774 LPBYTE p;
1775 HKEY hKey;
1776 struct sc_service *hsvc;
1778 TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
1779 cbBufSize, pcbBytesNeeded);
1781 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1782 if (!hsvc)
1784 SetLastError( ERROR_INVALID_HANDLE );
1785 return FALSE;
1787 hKey = hsvc->hkey;
1789 /* calculate the size required first */
1790 total = sizeof (QUERY_SERVICE_CONFIGW);
1792 sz = sizeof(str_buffer);
1793 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1794 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1796 sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1797 if( 0 == sz ) return FALSE;
1799 total += sizeof(WCHAR) * sz;
1801 else
1803 /* FIXME: set last error */
1804 return FALSE;
1807 sz = 0;
1808 r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1809 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1810 total += sz;
1812 sz = 0;
1813 r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1814 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1815 total += sz;
1816 else
1817 total += sizeof(WCHAR);
1819 sz = 0;
1820 r = RegQueryValueExW( hKey, szStart, 0, &type, NULL, &sz );
1821 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1822 total += sz;
1824 sz = 0;
1825 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1826 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1827 total += sz;
1829 *pcbBytesNeeded = total;
1831 /* if there's not enough memory, return an error */
1832 if( total > cbBufSize )
1834 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1835 return FALSE;
1838 ZeroMemory( lpServiceConfig, total );
1840 sz = sizeof val;
1841 r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1842 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1843 lpServiceConfig->dwServiceType = val;
1845 sz = sizeof val;
1846 r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1847 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1848 lpServiceConfig->dwStartType = val;
1850 sz = sizeof val;
1851 r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1852 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1853 lpServiceConfig->dwErrorControl = val;
1855 /* now do the strings */
1856 p = (LPBYTE) &lpServiceConfig[1];
1857 n = total - sizeof (QUERY_SERVICE_CONFIGW);
1859 sz = sizeof(str_buffer);
1860 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1861 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1863 sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
1864 sz *= sizeof(WCHAR);
1865 if( 0 == sz || sz > n ) return FALSE;
1867 lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
1868 p += sz;
1869 n -= sz;
1871 else
1873 /* FIXME: set last error */
1874 return FALSE;
1877 sz = n;
1878 r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
1879 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1881 lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
1882 p += sz;
1883 n -= sz;
1886 sz = n;
1887 r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
1888 lpServiceConfig->lpDependencies = (LPWSTR) p;
1889 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1891 p += sz;
1892 n -= sz;
1894 else
1896 *(WCHAR *) p = 0;
1897 p += sizeof(WCHAR);
1898 n -= sizeof(WCHAR);
1901 if( n < 0 )
1902 ERR("Buffer overflow!\n");
1904 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1905 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1907 return TRUE;
1910 /******************************************************************************
1911 * EnumServicesStatusA [ADVAPI32.@]
1913 BOOL WINAPI
1914 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
1915 DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
1916 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1917 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1919 FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
1920 dwServiceType, dwServiceState, lpServices, cbBufSize,
1921 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
1922 SetLastError (ERROR_ACCESS_DENIED);
1923 return FALSE;
1926 /******************************************************************************
1927 * EnumServicesStatusW [ADVAPI32.@]
1929 BOOL WINAPI
1930 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
1931 DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
1932 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1933 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1935 FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
1936 dwServiceType, dwServiceState, lpServices, cbBufSize,
1937 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
1938 SetLastError (ERROR_ACCESS_DENIED);
1939 return FALSE;
1942 /******************************************************************************
1943 * GetServiceKeyNameA [ADVAPI32.@]
1945 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
1946 LPSTR lpServiceName, LPDWORD lpcchBuffer )
1948 FIXME("%p %s %p %p\n", hSCManager, debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
1949 return FALSE;
1952 /******************************************************************************
1953 * GetServiceKeyNameW [ADVAPI32.@]
1955 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
1956 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
1958 FIXME("%p %s %p %p\n", hSCManager, debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
1959 return FALSE;
1962 /******************************************************************************
1963 * QueryServiceLockStatusA [ADVAPI32.@]
1965 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
1966 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
1967 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1969 FIXME("%p %p %08lx %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1971 return FALSE;
1974 /******************************************************************************
1975 * QueryServiceLockStatusW [ADVAPI32.@]
1977 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
1978 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
1979 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1981 FIXME("%p %p %08lx %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1983 return FALSE;
1986 /******************************************************************************
1987 * GetServiceDisplayNameA [ADVAPI32.@]
1989 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1990 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
1992 FIXME("%p %s %p %p\n", hSCManager,
1993 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
1994 return FALSE;
1997 /******************************************************************************
1998 * GetServiceDisplayNameW [ADVAPI32.@]
2000 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
2001 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
2003 FIXME("%p %s %p %p\n", hSCManager,
2004 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
2005 return FALSE;
2008 /******************************************************************************
2009 * ChangeServiceConfigW [ADVAPI32.@]
2011 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
2012 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
2013 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
2014 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
2016 struct reg_value val[10];
2017 struct sc_service *hsvc;
2018 DWORD r = ERROR_SUCCESS;
2019 HKEY hKey;
2020 int n = 0;
2022 TRACE("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
2023 hService, dwServiceType, dwStartType, dwErrorControl,
2024 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2025 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2026 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2028 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2029 if (!hsvc)
2031 SetLastError( ERROR_INVALID_HANDLE );
2032 return FALSE;
2034 hKey = hsvc->hkey;
2036 if( dwServiceType != SERVICE_NO_CHANGE )
2037 service_set_dword( &val[n++], szType, &dwServiceType );
2039 if( dwStartType != SERVICE_NO_CHANGE )
2040 service_set_dword( &val[n++], szStart, &dwStartType );
2042 if( dwErrorControl != SERVICE_NO_CHANGE )
2043 service_set_dword( &val[n++], szError, &dwErrorControl );
2045 if( lpBinaryPathName )
2046 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
2048 if( lpLoadOrderGroup )
2049 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
2051 if( lpDependencies )
2052 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
2054 if( lpPassword )
2055 FIXME("ignoring password\n");
2057 if( lpServiceStartName )
2058 service_set_string( &val[n++], szDependOnService, lpServiceStartName );
2060 r = service_write_values( hsvc->hkey, val, n );
2062 return (r == ERROR_SUCCESS) ? TRUE : FALSE ;
2065 /******************************************************************************
2066 * ChangeServiceConfigA [ADVAPI32.@]
2068 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2069 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2070 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2071 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2073 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2074 LPWSTR wServiceStartName, wPassword, wDisplayName;
2075 BOOL r;
2077 TRACE("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
2078 hService, dwServiceType, dwStartType, dwErrorControl,
2079 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2080 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2081 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2083 wBinaryPathName = SERV_dup( lpBinaryPathName );
2084 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2085 wDependencies = SERV_dupmulti( lpDependencies );
2086 wServiceStartName = SERV_dup( lpServiceStartName );
2087 wPassword = SERV_dup( lpPassword );
2088 wDisplayName = SERV_dup( lpDisplayName );
2090 r = ChangeServiceConfigW( hService, dwServiceType,
2091 dwStartType, dwErrorControl, wBinaryPathName,
2092 wLoadOrderGroup, lpdwTagId, wDependencies,
2093 wServiceStartName, wPassword, wDisplayName);
2095 SERV_free( wBinaryPathName );
2096 SERV_free( wLoadOrderGroup );
2097 SERV_free( wDependencies );
2098 SERV_free( wServiceStartName );
2099 SERV_free( wPassword );
2100 SERV_free( wDisplayName );
2102 return r;
2105 /******************************************************************************
2106 * ChangeServiceConfig2A [ADVAPI32.@]
2108 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2109 LPVOID lpInfo)
2111 BOOL r = FALSE;
2113 TRACE("%p %ld %p\n",hService, dwInfoLevel, lpInfo);
2115 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2117 LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
2118 SERVICE_DESCRIPTIONW sdw;
2120 sdw.lpDescription = SERV_dup( sd->lpDescription );
2122 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2124 SERV_free( sdw.lpDescription );
2126 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2128 LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
2129 SERVICE_FAILURE_ACTIONSW faw;
2131 faw.dwResetPeriod = fa->dwResetPeriod;
2132 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2133 faw.lpCommand = SERV_dup( fa->lpCommand );
2134 faw.cActions = fa->cActions;
2135 faw.lpsaActions = fa->lpsaActions;
2137 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2139 SERV_free( faw.lpRebootMsg );
2140 SERV_free( faw.lpCommand );
2142 else
2143 SetLastError( ERROR_INVALID_PARAMETER );
2145 return r;
2148 /******************************************************************************
2149 * ChangeServiceConfig2W [ADVAPI32.@]
2151 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2152 LPVOID lpInfo)
2154 HKEY hKey;
2155 struct sc_service *hsvc;
2157 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2158 if (!hsvc)
2160 SetLastError( ERROR_INVALID_HANDLE );
2161 return FALSE;
2163 hKey = hsvc->hkey;
2165 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2167 static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2168 LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
2169 if (sd->lpDescription)
2171 TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
2172 if (sd->lpDescription[0] == 0)
2173 RegDeleteValueW(hKey,szDescription);
2174 else
2175 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2176 (LPVOID)sd->lpDescription,
2177 sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2180 else
2181 FIXME("STUB: %p %ld %p\n",hService, dwInfoLevel, lpInfo);
2182 return TRUE;
2185 /******************************************************************************
2186 * QueryServiceObjectSecurity [ADVAPI32.@]
2188 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2189 SECURITY_INFORMATION dwSecurityInformation,
2190 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2191 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2193 PACL pACL = NULL;
2195 FIXME("%p %ld %p %lu %p\n", hService, dwSecurityInformation,
2196 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2198 InitializeSecurityDescriptor(lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
2200 pACL = HeapAlloc( GetProcessHeap(), 0, sizeof(ACL) );
2201 InitializeAcl(pACL, sizeof(ACL), ACL_REVISION);
2202 SetSecurityDescriptorDacl(lpSecurityDescriptor, TRUE, pACL, TRUE);
2203 return TRUE;
2206 /******************************************************************************
2207 * SetServiceObjectSecurity [ADVAPI32.@]
2209 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2210 SECURITY_INFORMATION dwSecurityInformation,
2211 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2213 FIXME("%p %ld %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2214 return TRUE;
2217 /******************************************************************************
2218 * SetServiceBits [ADVAPI32.@]
2220 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2221 DWORD dwServiceBits,
2222 BOOL bSetBitsOn,
2223 BOOL bUpdateImmediately)
2225 FIXME("%08lx %08lx %x %x\n", hServiceStatus, dwServiceBits,
2226 bSetBitsOn, bUpdateImmediately);
2227 return TRUE;