shell32/tests: Fixed potential overflow.
[wine/gsoc_dplay.git] / dlls / advapi32 / service.c
blob24b209e4aa622ab9674d066071e79c3f4e780c51
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 union {
61 LPHANDLER_FUNCTION handler;
62 LPHANDLER_FUNCTION_EX handler_ex;
63 } handler;
64 LPVOID context;
65 SERVICE_STATUS status;
66 HANDLE thread;
67 BOOL unicode : 1;
68 BOOL extended : 1; /* uses handler_ex instead of handler? */
69 union {
70 LPSERVICE_MAIN_FUNCTIONA a;
71 LPSERVICE_MAIN_FUNCTIONW w;
72 } proc;
73 LPWSTR args;
74 WCHAR name[1];
75 } service_data;
77 static CRITICAL_SECTION service_cs;
78 static CRITICAL_SECTION_DEBUG service_cs_debug =
80 0, 0, &service_cs,
81 { &service_cs_debug.ProcessLocksList,
82 &service_cs_debug.ProcessLocksList },
83 0, 0, { (DWORD_PTR)(__FILE__ ": service_cs") }
85 static CRITICAL_SECTION service_cs = { &service_cs_debug, -1, 0, 0, 0, 0 };
87 static service_data *service_list;
89 /******************************************************************************
90 * SC_HANDLEs
93 #define MAX_SERVICE_NAME 256
95 typedef enum { SC_HTYPE_MANAGER, SC_HTYPE_SERVICE } SC_HANDLE_TYPE;
97 struct sc_handle;
98 typedef VOID (*sc_handle_destructor)(struct sc_handle *);
100 struct sc_handle
102 SC_HANDLE_TYPE htype;
103 DWORD ref_count;
104 sc_handle_destructor destroy;
107 struct sc_manager /* service control manager handle */
109 struct sc_handle hdr;
110 HKEY hkey; /* handle to services database in the registry */
113 struct sc_service /* service handle */
115 struct sc_handle hdr;
116 HKEY hkey; /* handle to service entry in the registry (under hkey) */
117 struct sc_manager *scm; /* pointer to SCM handle */
118 WCHAR name[1];
121 static void *sc_handle_alloc(SC_HANDLE_TYPE htype, DWORD size,
122 sc_handle_destructor destroy)
124 struct sc_handle *hdr;
126 hdr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
127 if (hdr)
129 hdr->htype = htype;
130 hdr->ref_count = 1;
131 hdr->destroy = destroy;
133 TRACE("sc_handle type=%d -> %p\n", htype, hdr);
134 return hdr;
137 static void *sc_handle_get_handle_data(SC_HANDLE handle, DWORD htype)
139 struct sc_handle *hdr = (struct sc_handle *) handle;
141 if (!hdr)
142 return NULL;
143 if (hdr->htype != htype)
144 return NULL;
145 return hdr;
148 static void sc_handle_free(struct sc_handle* hdr)
150 if (!hdr)
151 return;
152 if (--hdr->ref_count)
153 return;
154 hdr->destroy(hdr);
155 HeapFree(GetProcessHeap(), 0, hdr);
158 static void sc_handle_destroy_manager(struct sc_handle *handle)
160 struct sc_manager *mgr = (struct sc_manager*) handle;
162 TRACE("destroying SC Manager %p\n", mgr);
163 if (mgr->hkey)
164 RegCloseKey(mgr->hkey);
167 static void sc_handle_destroy_service(struct sc_handle *handle)
169 struct sc_service *svc = (struct sc_service*) handle;
171 TRACE("destroying service %p\n", svc);
172 if (svc->hkey)
173 RegCloseKey(svc->hkey);
174 svc->hkey = NULL;
175 sc_handle_free(&svc->scm->hdr);
176 svc->scm = NULL;
179 /******************************************************************************
180 * String management functions
182 static inline LPWSTR SERV_dup( LPCSTR str )
184 UINT len;
185 LPWSTR wstr;
187 if( !str )
188 return NULL;
189 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
190 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
191 MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
192 return wstr;
195 static inline LPWSTR SERV_dupmulti(LPCSTR str)
197 UINT len = 0, n = 0;
198 LPWSTR wstr;
200 if( !str )
201 return NULL;
202 do {
203 len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
204 n += (strlen( &str[n] ) + 1);
205 } while (str[n]);
206 len++;
207 n++;
209 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
210 MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
211 return wstr;
214 static inline VOID SERV_free( LPWSTR wstr )
216 HeapFree( GetProcessHeap(), 0, wstr );
219 /******************************************************************************
220 * registry access functions and data
222 static const WCHAR szDisplayName[] = {
223 'D','i','s','p','l','a','y','N','a','m','e', 0 };
224 static const WCHAR szType[] = {'T','y','p','e',0};
225 static const WCHAR szStart[] = {'S','t','a','r','t',0};
226 static const WCHAR szError[] = {
227 'E','r','r','o','r','C','o','n','t','r','o','l', 0};
228 static const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
229 static const WCHAR szGroup[] = {'G','r','o','u','p',0};
230 static const WCHAR szDependencies[] = {
231 'D','e','p','e','n','d','e','n','c','i','e','s',0};
232 static const WCHAR szDependOnService[] = {
233 'D','e','p','e','n','d','O','n','S','e','r','v','i','c','e',0};
235 struct reg_value {
236 DWORD type;
237 DWORD size;
238 LPCWSTR name;
239 LPCVOID data;
242 static inline void service_set_value( struct reg_value *val,
243 DWORD type, LPCWSTR name, LPCVOID data, DWORD size )
245 val->name = name;
246 val->type = type;
247 val->data = data;
248 val->size = size;
251 static inline void service_set_dword( struct reg_value *val,
252 LPCWSTR name, DWORD *data )
254 service_set_value( val, REG_DWORD, name, data, sizeof (DWORD));
257 static inline void service_set_string( struct reg_value *val,
258 LPCWSTR name, LPCWSTR string )
260 DWORD len = (lstrlenW(string)+1) * sizeof (WCHAR);
261 service_set_value( val, REG_SZ, name, string, len );
264 static inline void service_set_multi_string( struct reg_value *val,
265 LPCWSTR name, LPCWSTR string )
267 DWORD len = 0;
269 /* determine the length of a double null terminated multi string */
270 do {
271 len += (lstrlenW( &string[ len ] )+1);
272 } while ( string[ len++ ] );
274 len *= sizeof (WCHAR);
275 service_set_value( val, REG_MULTI_SZ, name, string, len );
278 static inline LONG service_write_values( HKEY hKey,
279 struct reg_value *val, int n )
281 LONG r = ERROR_SUCCESS;
282 int i;
284 for( i=0; i<n; i++ )
286 r = RegSetValueExW(hKey, val[i].name, 0, val[i].type,
287 (const BYTE*)val[i].data, val[i].size );
288 if( r != ERROR_SUCCESS )
289 break;
291 return r;
294 /******************************************************************************
295 * Service IPC functions
297 static LPWSTR service_get_pipe_name(LPWSTR service)
299 static const WCHAR prefix[] = { '\\','\\','.','\\','p','i','p','e','\\',
300 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
301 LPWSTR name;
302 DWORD len;
304 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
305 name = HeapAlloc(GetProcessHeap(), 0, len);
306 strcpyW(name, prefix);
307 strcatW(name, service);
308 return name;
311 static HANDLE service_open_pipe(LPWSTR service)
313 LPWSTR szPipe = service_get_pipe_name( service );
314 HANDLE handle = INVALID_HANDLE_VALUE;
316 do {
317 handle = CreateFileW(szPipe, GENERIC_READ|GENERIC_WRITE,
318 0, NULL, OPEN_ALWAYS, 0, NULL);
319 if (handle != INVALID_HANDLE_VALUE)
320 break;
321 if (GetLastError() != ERROR_PIPE_BUSY)
322 break;
323 } while (WaitNamedPipeW(szPipe, NMPWAIT_WAIT_FOREVER));
324 SERV_free(szPipe);
326 return handle;
329 /******************************************************************************
330 * service_get_event_handle
332 static HANDLE service_get_event_handle(LPWSTR service)
334 static const WCHAR prefix[] = {
335 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
336 LPWSTR name;
337 DWORD len;
338 HANDLE handle;
340 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
341 name = HeapAlloc(GetProcessHeap(), 0, len);
342 strcpyW(name, prefix);
343 strcatW(name, service);
344 handle = CreateEventW(NULL, TRUE, FALSE, name);
345 SERV_free(name);
346 return handle;
349 /******************************************************************************
350 * service_thread
352 * Call into the main service routine provided by StartServiceCtrlDispatcher.
354 static DWORD WINAPI service_thread(LPVOID arg)
356 service_data *info = arg;
357 LPWSTR str = info->args;
358 DWORD argc = 0, len = 0;
360 TRACE("%p\n", arg);
362 while (str[len])
364 len += strlenW(&str[len]) + 1;
365 argc++;
368 if (!argc)
370 if (info->unicode)
371 info->proc.w(0, NULL);
372 else
373 info->proc.a(0, NULL);
374 return 0;
377 if (info->unicode)
379 LPWSTR *argv, p;
381 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPWSTR));
382 for (argc=0, p=str; *p; p += strlenW(p) + 1)
383 argv[argc++] = p;
384 argv[argc] = NULL;
386 info->proc.w(argc, argv);
387 HeapFree(GetProcessHeap(), 0, argv);
389 else
391 LPSTR strA, *argv, p;
392 DWORD lenA;
394 lenA = WideCharToMultiByte(CP_ACP,0, str, len, NULL, 0, NULL, NULL);
395 strA = HeapAlloc(GetProcessHeap(), 0, lenA);
396 WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL);
398 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPSTR));
399 for (argc=0, p=strA; *p; p += strlen(p) + 1)
400 argv[argc++] = p;
401 argv[argc] = NULL;
403 info->proc.a(argc, argv);
404 HeapFree(GetProcessHeap(), 0, argv);
405 HeapFree(GetProcessHeap(), 0, strA);
407 return 0;
410 /******************************************************************************
411 * service_handle_start
413 static BOOL service_handle_start(HANDLE pipe, service_data *service, DWORD count)
415 DWORD read = 0, result = 0;
416 LPWSTR args;
417 BOOL r;
419 TRACE("%p %p %d\n", pipe, service, count);
421 args = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
422 r = ReadFile(pipe, args, count*sizeof(WCHAR), &read, NULL);
423 if (!r || count!=read/sizeof(WCHAR) || args[count-1])
425 ERR("pipe read failed r = %d count = %d read = %d args[n-1]=%s\n",
426 r, count, read, debugstr_wn(args, count));
427 goto end;
430 if (service->thread)
432 ERR("service is not stopped\n");
433 goto end;
436 SERV_free(service->args);
437 service->args = args;
438 args = NULL;
439 service->thread = CreateThread( NULL, 0, service_thread,
440 service, 0, NULL );
442 end:
443 HeapFree(GetProcessHeap(), 0, args);
444 WriteFile( pipe, &result, sizeof result, &read, NULL );
446 return TRUE;
449 /******************************************************************************
450 * service_send_start_message
452 static BOOL service_send_start_message(HANDLE pipe, LPCWSTR *argv, DWORD argc)
454 DWORD i, len, count, result;
455 service_start_info *ssi;
456 LPWSTR p;
457 BOOL r;
459 TRACE("%p %p %d\n", pipe, argv, argc);
461 /* calculate how much space do we need to send the startup info */
462 len = 1;
463 for (i=0; i<argc; i++)
464 len += strlenW(argv[i])+1;
466 ssi = HeapAlloc(GetProcessHeap(),0,sizeof *ssi + (len-1)*sizeof(WCHAR));
467 ssi->cmd = WINESERV_STARTINFO;
468 ssi->size = len;
470 /* copy service args into a single buffer*/
471 p = &ssi->str[0];
472 for (i=0; i<argc; i++)
474 strcpyW(p, argv[i]);
475 p += strlenW(p) + 1;
477 *p=0;
479 r = WriteFile(pipe, ssi, sizeof *ssi + len*sizeof(WCHAR), &count, NULL);
480 if (r)
481 r = ReadFile(pipe, &result, sizeof result, &count, NULL);
483 HeapFree(GetProcessHeap(),0,ssi);
485 return r;
488 /******************************************************************************
489 * service_handle_get_status
491 static BOOL service_handle_get_status(HANDLE pipe, service_data *service)
493 DWORD count = 0;
494 TRACE("\n");
495 return WriteFile(pipe, &service->status,
496 sizeof service->status, &count, NULL);
499 /******************************************************************************
500 * service_get_status
502 static BOOL service_get_status(HANDLE pipe, LPSERVICE_STATUS status)
504 DWORD cmd[2], count = 0;
505 BOOL r;
507 cmd[0] = WINESERV_GETSTATUS;
508 cmd[1] = 0;
509 r = WriteFile( pipe, cmd, sizeof cmd, &count, NULL );
510 if (!r || count != sizeof cmd)
512 ERR("service protocol error - failed to write pipe!\n");
513 return r;
515 r = ReadFile( pipe, status, sizeof *status, &count, NULL );
516 if (!r || count != sizeof *status)
517 ERR("service protocol error - failed to read pipe "
518 "r = %d count = %d!\n", r, count);
519 return r;
522 /******************************************************************************
523 * service_send_control
525 static BOOL service_send_control(HANDLE pipe, DWORD dwControl, DWORD *result)
527 DWORD cmd[2], count = 0;
528 BOOL r;
530 cmd[0] = WINESERV_SENDCONTROL;
531 cmd[1] = dwControl;
532 r = WriteFile(pipe, cmd, sizeof cmd, &count, NULL);
533 if (!r || count != sizeof cmd)
535 ERR("service protocol error - failed to write pipe!\n");
536 return r;
538 r = ReadFile(pipe, result, sizeof *result, &count, NULL);
539 if (!r || count != sizeof *result)
540 ERR("service protocol error - failed to read pipe "
541 "r = %d count = %d!\n", r, count);
542 return r;
545 /******************************************************************************
546 * service_accepts_control
548 static BOOL service_accepts_control(service_data *service, DWORD dwControl)
550 DWORD a = service->status.dwControlsAccepted;
552 switch (dwControl)
554 case SERVICE_CONTROL_INTERROGATE:
555 return TRUE;
556 case SERVICE_CONTROL_STOP:
557 if (a&SERVICE_ACCEPT_STOP)
558 return TRUE;
559 break;
560 case SERVICE_CONTROL_SHUTDOWN:
561 if (a&SERVICE_ACCEPT_SHUTDOWN)
562 return TRUE;
563 break;
564 case SERVICE_CONTROL_PAUSE:
565 case SERVICE_CONTROL_CONTINUE:
566 if (a&SERVICE_ACCEPT_PAUSE_CONTINUE)
567 return TRUE;
568 break;
569 case SERVICE_CONTROL_PARAMCHANGE:
570 if (a&SERVICE_ACCEPT_PARAMCHANGE)
571 return TRUE;
572 break;
573 case SERVICE_CONTROL_NETBINDADD:
574 case SERVICE_CONTROL_NETBINDREMOVE:
575 case SERVICE_CONTROL_NETBINDENABLE:
576 case SERVICE_CONTROL_NETBINDDISABLE:
577 if (a&SERVICE_ACCEPT_NETBINDCHANGE)
578 return TRUE;
580 if (!service->extended)
581 return FALSE;
582 switch (dwControl)
584 case SERVICE_CONTROL_HARDWAREPROFILECHANGE:
585 if (a&SERVICE_ACCEPT_HARDWAREPROFILECHANGE)
586 return TRUE;
587 break;
588 case SERVICE_CONTROL_POWEREVENT:
589 if (a&SERVICE_ACCEPT_POWEREVENT)
590 return TRUE;
591 break;
592 case SERVICE_CONTROL_SESSIONCHANGE:
593 if (a&SERVICE_ACCEPT_SESSIONCHANGE)
594 return TRUE;
595 break;
597 return FALSE;
600 /******************************************************************************
601 * service_handle_control
603 static BOOL service_handle_control(HANDLE pipe, service_data *service,
604 DWORD dwControl)
606 DWORD count, ret = ERROR_INVALID_SERVICE_CONTROL;
608 TRACE("received control %d\n", dwControl);
610 if (service_accepts_control(service, dwControl))
612 if (service->extended && service->handler.handler_ex)
614 service->handler.handler_ex(dwControl, 0, NULL, service->context);
615 ret = ERROR_SUCCESS;
617 else if (service->handler.handler)
619 service->handler.handler(dwControl);
620 ret = ERROR_SUCCESS;
623 return WriteFile(pipe, &ret, sizeof ret, &count, NULL);
626 /******************************************************************************
627 * service_reap_thread
629 static DWORD service_reap_thread(service_data *service)
631 DWORD exitcode = 0;
633 if (!service->thread)
634 return 0;
635 GetExitCodeThread(service->thread, &exitcode);
636 if (exitcode!=STILL_ACTIVE)
638 CloseHandle(service->thread);
639 service->thread = 0;
641 return exitcode;
644 /******************************************************************************
645 * service_control_dispatcher
647 static DWORD WINAPI service_control_dispatcher(LPVOID arg)
649 service_data *service = arg;
650 LPWSTR name;
651 HANDLE pipe, event;
653 TRACE("%p %s\n", service, debugstr_w(service->name));
655 /* create a pipe to talk to the rest of the world with */
656 name = service_get_pipe_name(service->name);
657 pipe = CreateNamedPipeW(name, PIPE_ACCESS_DUPLEX,
658 PIPE_TYPE_BYTE|PIPE_WAIT, 1, 256, 256, 10000, NULL );
659 SERV_free(name);
661 /* let the process who started us know we've tried to create a pipe */
662 event = service_get_event_handle(service->name);
663 SetEvent(event);
664 CloseHandle(event);
666 if (pipe==INVALID_HANDLE_VALUE)
668 ERR("failed to create pipe for %s, error = %d\n",
669 debugstr_w(service->name), GetLastError());
670 return 0;
673 /* dispatcher loop */
674 while (1)
676 BOOL r;
677 DWORD count, req[2] = {0,0};
679 r = ConnectNamedPipe(pipe, NULL);
680 if (!r && GetLastError() != ERROR_PIPE_CONNECTED)
682 ERR("pipe connect failed\n");
683 break;
686 r = ReadFile( pipe, &req, sizeof req, &count, NULL );
687 if (!r || count!=sizeof req)
689 ERR("pipe read failed\n");
690 break;
693 service_reap_thread(service);
695 /* handle the request */
696 switch (req[0])
698 case WINESERV_STARTINFO:
699 service_handle_start(pipe, service, req[1]);
700 break;
701 case WINESERV_GETSTATUS:
702 service_handle_get_status(pipe, service);
703 break;
704 case WINESERV_SENDCONTROL:
705 service_handle_control(pipe, service, req[1]);
706 break;
707 default:
708 ERR("received invalid command %d length %d\n", req[0], req[1]);
711 FlushFileBuffers(pipe);
712 DisconnectNamedPipe(pipe);
715 CloseHandle(pipe);
716 return 1;
719 /******************************************************************************
720 * service_run_threads
722 static BOOL service_run_threads(void)
724 service_data *service;
725 DWORD count = 0, n = 0;
726 HANDLE *handles;
728 EnterCriticalSection( &service_cs );
730 /* count how many services there are */
731 for (service = service_list; service; service = service->next)
732 count++;
734 TRACE("starting %d pipe listener threads\n", count);
736 handles = HeapAlloc(GetProcessHeap(), 0, sizeof(HANDLE)*count);
738 for (n=0, service = service_list; service; service = service->next, n++)
739 handles[n] = CreateThread( NULL, 0, service_control_dispatcher,
740 service, 0, NULL );
741 assert(n==count);
743 LeaveCriticalSection( &service_cs );
745 /* wait for all the threads to pack up and exit */
746 WaitForMultipleObjectsEx(count, handles, TRUE, INFINITE, FALSE);
748 HeapFree(GetProcessHeap(), 0, handles);
750 return TRUE;
753 /******************************************************************************
754 * StartServiceCtrlDispatcherA [ADVAPI32.@]
756 * See StartServiceCtrlDispatcherW.
758 BOOL WINAPI StartServiceCtrlDispatcherA( LPSERVICE_TABLE_ENTRYA servent )
760 service_data *info;
761 DWORD sz, len;
762 BOOL ret = TRUE;
764 TRACE("%p\n", servent);
766 EnterCriticalSection( &service_cs );
767 while (servent->lpServiceName)
769 LPSTR name = servent->lpServiceName;
771 len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0);
772 sz = len*sizeof(WCHAR) + sizeof *info;
773 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
774 MultiByteToWideChar(CP_ACP, 0, name, -1, info->name, len);
775 info->proc.a = servent->lpServiceProc;
776 info->unicode = FALSE;
778 /* insert into the list */
779 info->next = service_list;
780 service_list = info;
782 servent++;
784 LeaveCriticalSection( &service_cs );
786 service_run_threads();
788 return ret;
791 /******************************************************************************
792 * StartServiceCtrlDispatcherW [ADVAPI32.@]
794 * Connects a process containing one or more services to the service control
795 * manager.
797 * PARAMS
798 * servent [I] A list of the service names and service procedures
800 * RETURNS
801 * Success: TRUE.
802 * Failure: FALSE.
804 BOOL WINAPI StartServiceCtrlDispatcherW( LPSERVICE_TABLE_ENTRYW servent )
806 service_data *info;
807 DWORD sz, len;
808 BOOL ret = TRUE;
810 TRACE("%p\n", servent);
812 EnterCriticalSection( &service_cs );
813 while (servent->lpServiceName)
815 LPWSTR name = servent->lpServiceName;
817 len = strlenW(name);
818 sz = len*sizeof(WCHAR) + sizeof *info;
819 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
820 strcpyW(info->name, name);
821 info->proc.w = servent->lpServiceProc;
822 info->unicode = TRUE;
824 /* insert into the list */
825 info->next = service_list;
826 service_list = info;
828 servent++;
830 LeaveCriticalSection( &service_cs );
832 service_run_threads();
834 return ret;
837 /******************************************************************************
838 * LockServiceDatabase [ADVAPI32.@]
840 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
842 HANDLE ret;
844 TRACE("%p\n",hSCManager);
846 ret = CreateSemaphoreW( NULL, 1, 1, szSCMLock );
847 if( ret && GetLastError() == ERROR_ALREADY_EXISTS )
849 CloseHandle( ret );
850 ret = NULL;
851 SetLastError( ERROR_SERVICE_DATABASE_LOCKED );
854 TRACE("returning %p\n", ret);
856 return ret;
859 /******************************************************************************
860 * UnlockServiceDatabase [ADVAPI32.@]
862 BOOL WINAPI UnlockServiceDatabase (SC_LOCK ScLock)
864 TRACE("%p\n",ScLock);
866 return CloseHandle( ScLock );
869 /******************************************************************************
870 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
872 SERVICE_STATUS_HANDLE WINAPI
873 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName, LPHANDLER_FUNCTION lpfHandler )
875 LPWSTR lpServiceNameW;
876 SERVICE_STATUS_HANDLE ret;
878 lpServiceNameW = SERV_dup(lpServiceName);
879 ret = RegisterServiceCtrlHandlerW( lpServiceNameW, lpfHandler );
880 SERV_free(lpServiceNameW);
881 return ret;
884 /******************************************************************************
885 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
887 * PARAMS
888 * lpServiceName []
889 * lpfHandler []
891 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName,
892 LPHANDLER_FUNCTION lpfHandler )
894 service_data *service;
896 EnterCriticalSection( &service_cs );
897 for(service = service_list; service; service = service->next)
898 if(!strcmpW(lpServiceName, service->name))
899 break;
900 if (service)
901 service->handler.handler = lpfHandler;
902 LeaveCriticalSection( &service_cs );
904 return (SERVICE_STATUS_HANDLE)service;
907 /******************************************************************************
908 * SetServiceStatus [ADVAPI32.@]
910 * PARAMS
911 * hService []
912 * lpStatus []
914 BOOL WINAPI
915 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
917 service_data *service;
918 BOOL r = TRUE;
920 TRACE("%p %x %x %x %x %x %x %x\n", hService,
921 lpStatus->dwServiceType, lpStatus->dwCurrentState,
922 lpStatus->dwControlsAccepted, lpStatus->dwWin32ExitCode,
923 lpStatus->dwServiceSpecificExitCode, lpStatus->dwCheckPoint,
924 lpStatus->dwWaitHint);
926 EnterCriticalSection( &service_cs );
927 for (service = service_list; service; service = service->next)
928 if(service == (service_data*)hService)
929 break;
930 if (service)
932 memcpy( &service->status, lpStatus, sizeof(SERVICE_STATUS) );
933 TRACE("Set service status to %d\n",service->status.dwCurrentState);
935 else
936 r = FALSE;
937 LeaveCriticalSection( &service_cs );
939 return r;
943 /******************************************************************************
944 * OpenSCManagerA [ADVAPI32.@]
946 * Establish a connection to the service control manager and open its database.
948 * PARAMS
949 * lpMachineName [I] Pointer to machine name string
950 * lpDatabaseName [I] Pointer to database name string
951 * dwDesiredAccess [I] Type of access
953 * RETURNS
954 * Success: A Handle to the service control manager database
955 * Failure: NULL
957 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
958 DWORD dwDesiredAccess )
960 LPWSTR lpMachineNameW, lpDatabaseNameW;
961 SC_HANDLE ret;
963 lpMachineNameW = SERV_dup(lpMachineName);
964 lpDatabaseNameW = SERV_dup(lpDatabaseName);
965 ret = OpenSCManagerW(lpMachineNameW, lpDatabaseNameW, dwDesiredAccess);
966 SERV_free(lpDatabaseNameW);
967 SERV_free(lpMachineNameW);
968 return ret;
971 /******************************************************************************
972 * OpenSCManagerW [ADVAPI32.@]
974 * See OpenSCManagerA.
976 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
977 DWORD dwDesiredAccess )
979 struct sc_manager *manager;
980 HKEY hReg;
981 LONG r;
983 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName),
984 debugstr_w(lpDatabaseName), dwDesiredAccess);
986 if( lpDatabaseName && lpDatabaseName[0] )
988 if( strcmpiW( lpDatabaseName, SERVICES_ACTIVE_DATABASEW ) == 0 )
990 /* noop, all right */
992 else if( strcmpiW( lpDatabaseName, SERVICES_FAILED_DATABASEW ) == 0 )
994 SetLastError( ERROR_DATABASE_DOES_NOT_EXIST );
995 return NULL;
997 else
999 SetLastError( ERROR_INVALID_NAME );
1000 return NULL;
1004 manager = sc_handle_alloc( SC_HTYPE_MANAGER, sizeof (struct sc_manager),
1005 sc_handle_destroy_manager );
1006 if (!manager)
1007 return NULL;
1009 r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
1010 if (r!=ERROR_SUCCESS)
1011 goto error;
1013 r = RegOpenKeyExW(hReg, szServiceManagerKey,
1014 0, KEY_ALL_ACCESS, &manager->hkey);
1015 RegCloseKey( hReg );
1016 if (r!=ERROR_SUCCESS)
1017 goto error;
1019 TRACE("returning %p\n", manager);
1021 return (SC_HANDLE) &manager->hdr;
1023 error:
1024 sc_handle_free( &manager->hdr );
1025 SetLastError( r);
1026 return NULL;
1029 /******************************************************************************
1030 * ControlService [ADVAPI32.@]
1032 * Send a control code to a service.
1034 * PARAMS
1035 * hService [I] Handle of the service control manager database
1036 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
1037 * lpServiceStatus [O] Destination for the status of the service, if available
1039 * RETURNS
1040 * Success: TRUE.
1041 * Failure: FALSE.
1043 * BUGS
1044 * Unlike M$' implementation, control requests are not serialized and may be
1045 * processed asynchronously.
1047 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
1048 LPSERVICE_STATUS lpServiceStatus )
1050 struct sc_service *hsvc;
1051 BOOL ret = FALSE;
1052 HANDLE handle;
1054 TRACE("%p %d %p\n", hService, dwControl, lpServiceStatus);
1056 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1057 if (!hsvc)
1059 SetLastError( ERROR_INVALID_HANDLE );
1060 return FALSE;
1063 ret = QueryServiceStatus(hService, lpServiceStatus);
1064 if (!ret)
1066 ERR("failed to query service status\n");
1067 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1068 return FALSE;
1071 switch (lpServiceStatus->dwCurrentState)
1073 case SERVICE_STOPPED:
1074 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1075 return FALSE;
1076 case SERVICE_START_PENDING:
1077 if (dwControl==SERVICE_CONTROL_STOP)
1078 break;
1079 /* fall thru */
1080 case SERVICE_STOP_PENDING:
1081 SetLastError(ERROR_SERVICE_CANNOT_ACCEPT_CTRL);
1082 return FALSE;
1085 handle = service_open_pipe(hsvc->name);
1086 if (handle!=INVALID_HANDLE_VALUE)
1088 DWORD result = ERROR_SUCCESS;
1089 ret = service_send_control(handle, dwControl, &result);
1090 CloseHandle(handle);
1091 if (result!=ERROR_SUCCESS)
1093 SetLastError(result);
1094 ret = FALSE;
1098 return ret;
1101 /******************************************************************************
1102 * CloseServiceHandle [ADVAPI32.@]
1104 * Close a handle to a service or the service control manager database.
1106 * PARAMS
1107 * hSCObject [I] Handle to service or service control manager database
1109 * RETURNS
1110 * Success: TRUE
1111 * Failure: FALSE
1113 BOOL WINAPI
1114 CloseServiceHandle( SC_HANDLE hSCObject )
1116 TRACE("%p\n", hSCObject);
1118 sc_handle_free( (struct sc_handle*) hSCObject );
1120 return TRUE;
1124 /******************************************************************************
1125 * OpenServiceA [ADVAPI32.@]
1127 * Open a handle to a service.
1129 * PARAMS
1130 * hSCManager [I] Handle of the service control manager database
1131 * lpServiceName [I] Name of the service to open
1132 * dwDesiredAccess [I] Access required to the service
1134 * RETURNS
1135 * Success: Handle to the service
1136 * Failure: NULL
1138 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1139 DWORD dwDesiredAccess )
1141 LPWSTR lpServiceNameW;
1142 SC_HANDLE ret;
1144 TRACE("%p %s %d\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
1146 lpServiceNameW = SERV_dup(lpServiceName);
1147 ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
1148 SERV_free(lpServiceNameW);
1149 return ret;
1153 /******************************************************************************
1154 * OpenServiceW [ADVAPI32.@]
1156 * See OpenServiceA.
1158 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1159 DWORD dwDesiredAccess)
1161 struct sc_manager *hscm;
1162 struct sc_service *hsvc;
1163 HKEY hKey;
1164 long r;
1165 DWORD len;
1167 TRACE("%p %s %d\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
1169 if (!lpServiceName)
1171 SetLastError(ERROR_INVALID_ADDRESS);
1172 return NULL;
1175 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1176 if (!hscm)
1178 SetLastError( ERROR_INVALID_HANDLE );
1179 return FALSE;
1182 r = RegOpenKeyExW( hscm->hkey, lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
1183 if (r!=ERROR_SUCCESS)
1185 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
1186 return NULL;
1189 len = strlenW(lpServiceName)+1;
1190 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE,
1191 sizeof (struct sc_service) + len*sizeof(WCHAR),
1192 sc_handle_destroy_service );
1193 if (!hsvc)
1194 return NULL;
1195 strcpyW( hsvc->name, lpServiceName );
1196 hsvc->hkey = hKey;
1198 /* add reference to SCM handle */
1199 hscm->hdr.ref_count++;
1200 hsvc->scm = hscm;
1202 TRACE("returning %p\n",hsvc);
1204 return (SC_HANDLE) &hsvc->hdr;
1207 /******************************************************************************
1208 * CreateServiceW [ADVAPI32.@]
1210 SC_HANDLE WINAPI
1211 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1212 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
1213 DWORD dwServiceType, DWORD dwStartType,
1214 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1215 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1216 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
1217 LPCWSTR lpPassword )
1219 struct sc_manager *hscm;
1220 struct sc_service *hsvc = NULL;
1221 HKEY hKey;
1222 LONG r;
1223 DWORD dp, len;
1224 struct reg_value val[10];
1225 int n = 0;
1227 TRACE("%p %s %s\n", hSCManager,
1228 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
1230 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1231 if (!hscm)
1233 SetLastError( ERROR_INVALID_HANDLE );
1234 return NULL;
1237 r = RegCreateKeyExW(hscm->hkey, lpServiceName, 0, NULL,
1238 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
1239 if (r!=ERROR_SUCCESS)
1240 return NULL;
1242 if (dp != REG_CREATED_NEW_KEY)
1244 SetLastError(ERROR_SERVICE_EXISTS);
1245 goto error;
1248 if( lpDisplayName )
1249 service_set_string( &val[n++], szDisplayName, lpDisplayName );
1251 service_set_dword( &val[n++], szType, &dwServiceType );
1252 service_set_dword( &val[n++], szStart, &dwStartType );
1253 service_set_dword( &val[n++], szError, &dwErrorControl );
1255 if( lpBinaryPathName )
1256 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
1258 if( lpLoadOrderGroup )
1259 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
1261 if( lpDependencies )
1262 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
1264 if( lpPassword )
1265 FIXME("Don't know how to add a Password for a service.\n");
1267 if( lpServiceStartName )
1268 service_set_string( &val[n++], szDependOnService, lpServiceStartName );
1270 r = service_write_values( hKey, val, n );
1271 if( r != ERROR_SUCCESS )
1272 goto error;
1274 len = strlenW(lpServiceName)+1;
1275 len = sizeof (struct sc_service) + len*sizeof(WCHAR);
1276 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE, len, sc_handle_destroy_service );
1277 if( !hsvc )
1278 goto error;
1279 lstrcpyW( hsvc->name, lpServiceName );
1280 hsvc->hkey = hKey;
1281 hsvc->scm = hscm;
1282 hscm->hdr.ref_count++;
1284 return (SC_HANDLE) &hsvc->hdr;
1286 error:
1287 RegCloseKey( hKey );
1288 return NULL;
1292 /******************************************************************************
1293 * CreateServiceA [ADVAPI32.@]
1295 SC_HANDLE WINAPI
1296 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1297 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1298 DWORD dwServiceType, DWORD dwStartType,
1299 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1300 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1301 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1302 LPCSTR lpPassword )
1304 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1305 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1306 SC_HANDLE r;
1308 TRACE("%p %s %s\n", hSCManager,
1309 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1311 lpServiceNameW = SERV_dup( lpServiceName );
1312 lpDisplayNameW = SERV_dup( lpDisplayName );
1313 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1314 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1315 lpDependenciesW = SERV_dupmulti( lpDependencies );
1316 lpServiceStartNameW = SERV_dup( lpServiceStartName );
1317 lpPasswordW = SERV_dup( lpPassword );
1319 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1320 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1321 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1322 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1324 SERV_free( lpServiceNameW );
1325 SERV_free( lpDisplayNameW );
1326 SERV_free( lpBinaryPathNameW );
1327 SERV_free( lpLoadOrderGroupW );
1328 SERV_free( lpDependenciesW );
1329 SERV_free( lpServiceStartNameW );
1330 SERV_free( lpPasswordW );
1332 return r;
1336 /******************************************************************************
1337 * DeleteService [ADVAPI32.@]
1339 * Delete a service from the service control manager database.
1341 * PARAMS
1342 * hService [I] Handle of the service to delete
1344 * RETURNS
1345 * Success: TRUE
1346 * Failure: FALSE
1348 BOOL WINAPI DeleteService( SC_HANDLE hService )
1350 struct sc_service *hsvc;
1351 HKEY hKey;
1352 WCHAR valname[MAX_PATH+1];
1353 INT index = 0;
1354 LONG rc;
1355 DWORD size;
1357 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1358 if (!hsvc)
1360 SetLastError( ERROR_INVALID_HANDLE );
1361 return FALSE;
1363 hKey = hsvc->hkey;
1365 size = MAX_PATH+1;
1366 /* Clean out the values */
1367 rc = RegEnumValueW(hKey, index, valname,&size,0,0,0,0);
1368 while (rc == ERROR_SUCCESS)
1370 RegDeleteValueW(hKey,valname);
1371 index++;
1372 size = MAX_PATH+1;
1373 rc = RegEnumValueW(hKey, index, valname, &size,0,0,0,0);
1376 RegCloseKey(hKey);
1377 hsvc->hkey = NULL;
1379 /* delete the key */
1380 RegDeleteKeyW(hsvc->scm->hkey, hsvc->name);
1382 return TRUE;
1386 /******************************************************************************
1387 * StartServiceA [ADVAPI32.@]
1389 * Start a service
1391 * PARAMS
1392 * hService [I] Handle of service
1393 * dwNumServiceArgs [I] Number of arguments
1394 * lpServiceArgVectors [I] Address of array of argument strings
1396 * NOTES
1397 * - NT implements this function using an obscure RPC call.
1398 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1399 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1400 * - This will only work for shared address space. How should the service
1401 * args be transferred when address spaces are separated?
1402 * - Can only start one service at a time.
1403 * - Has no concept of privilege.
1405 * RETURNS
1406 * Success: TRUE.
1407 * Failure: FALSE
1409 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1410 LPCSTR *lpServiceArgVectors )
1412 LPWSTR *lpwstr=NULL;
1413 unsigned int i;
1414 BOOL r;
1416 TRACE("(%p,%d,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1418 if (dwNumServiceArgs)
1419 lpwstr = HeapAlloc( GetProcessHeap(), 0,
1420 dwNumServiceArgs*sizeof(LPWSTR) );
1422 for(i=0; i<dwNumServiceArgs; i++)
1423 lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1425 r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1427 if (dwNumServiceArgs)
1429 for(i=0; i<dwNumServiceArgs; i++)
1430 SERV_free(lpwstr[i]);
1431 HeapFree(GetProcessHeap(), 0, lpwstr);
1434 return r;
1437 /******************************************************************************
1438 * service_start_process [INTERNAL]
1440 static DWORD service_start_process(struct sc_service *hsvc)
1442 static const WCHAR _ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0};
1443 PROCESS_INFORMATION pi;
1444 STARTUPINFOW si;
1445 LPWSTR path = NULL, str;
1446 DWORD type, size, ret;
1447 HANDLE handles[2];
1448 BOOL r;
1450 /* read the executable path from memory */
1451 size = 0;
1452 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, NULL, &size);
1453 if (ret!=ERROR_SUCCESS)
1454 return FALSE;
1455 str = HeapAlloc(GetProcessHeap(),0,size);
1456 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, (LPBYTE)str, &size);
1457 if (ret==ERROR_SUCCESS)
1459 size = ExpandEnvironmentStringsW(str,NULL,0);
1460 path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
1461 ExpandEnvironmentStringsW(str,path,size);
1463 HeapFree(GetProcessHeap(),0,str);
1464 if (!path)
1465 return FALSE;
1467 /* wait for the process to start and set an event or terminate */
1468 handles[0] = service_get_event_handle( hsvc->name );
1469 ZeroMemory(&si, sizeof(STARTUPINFOW));
1470 si.cb = sizeof(STARTUPINFOW);
1471 r = CreateProcessW(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1472 if (r)
1474 handles[1] = pi.hProcess;
1475 ret = WaitForMultipleObjectsEx(2, handles, FALSE, 30000, FALSE);
1476 if(ret != WAIT_OBJECT_0)
1478 SetLastError(ERROR_IO_PENDING);
1479 r = FALSE;
1482 CloseHandle( pi.hThread );
1483 CloseHandle( pi.hProcess );
1485 CloseHandle( handles[0] );
1486 HeapFree(GetProcessHeap(),0,path);
1487 return r;
1490 static BOOL service_wait_for_startup(SC_HANDLE hService)
1492 DWORD i;
1493 SERVICE_STATUS status;
1494 BOOL r = FALSE;
1496 TRACE("%p\n", hService);
1498 for (i=0; i<30; i++)
1500 status.dwCurrentState = 0;
1501 r = QueryServiceStatus(hService, &status);
1502 if (!r)
1503 break;
1504 if (status.dwCurrentState == SERVICE_RUNNING)
1506 TRACE("Service started successfully\n");
1507 break;
1509 r = FALSE;
1510 Sleep(1000);
1512 return r;
1515 /******************************************************************************
1516 * StartServiceW [ADVAPI32.@]
1518 * See StartServiceA.
1520 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1521 LPCWSTR *lpServiceArgVectors)
1523 struct sc_service *hsvc;
1524 BOOL r = FALSE;
1525 SC_LOCK hLock;
1526 HANDLE handle = INVALID_HANDLE_VALUE;
1528 TRACE("%p %d %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1530 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1531 if (!hsvc)
1533 SetLastError(ERROR_INVALID_HANDLE);
1534 return r;
1537 hLock = LockServiceDatabase((SC_HANDLE)hsvc->scm);
1538 if (!hLock)
1539 return r;
1541 handle = service_open_pipe(hsvc->name);
1542 if (handle==INVALID_HANDLE_VALUE)
1544 /* start the service process */
1545 if (service_start_process(hsvc))
1546 handle = service_open_pipe(hsvc->name);
1549 if (handle != INVALID_HANDLE_VALUE)
1551 service_send_start_message(handle, lpServiceArgVectors, dwNumServiceArgs);
1552 CloseHandle(handle);
1553 r = TRUE;
1556 UnlockServiceDatabase( hLock );
1558 TRACE("returning %d\n", r);
1560 if (r)
1561 service_wait_for_startup(hService);
1563 return r;
1566 /******************************************************************************
1567 * QueryServiceStatus [ADVAPI32.@]
1569 * PARAMS
1570 * hService []
1571 * lpservicestatus []
1574 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1575 LPSERVICE_STATUS lpservicestatus)
1577 struct sc_service *hsvc;
1578 DWORD size, type, val;
1579 HANDLE pipe;
1580 LONG r;
1582 TRACE("%p %p\n", hService, lpservicestatus);
1584 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1585 if (!hsvc)
1587 SetLastError( ERROR_INVALID_HANDLE );
1588 return FALSE;
1591 pipe = service_open_pipe(hsvc->name);
1592 if (pipe != INVALID_HANDLE_VALUE)
1594 r = service_get_status(pipe, lpservicestatus);
1595 CloseHandle(pipe);
1596 if (r)
1597 return TRUE;
1600 TRACE("Failed to read service status\n");
1602 /* read the service type from the registry */
1603 size = sizeof(val);
1604 r = RegQueryValueExA(hsvc->hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1605 if(r!=ERROR_SUCCESS || type!=REG_DWORD)
1606 val = 0;
1608 lpservicestatus->dwServiceType = val;
1609 lpservicestatus->dwCurrentState = SERVICE_STOPPED; /* stopped */
1610 lpservicestatus->dwControlsAccepted = 0;
1611 lpservicestatus->dwWin32ExitCode = ERROR_SERVICE_NEVER_STARTED;
1612 lpservicestatus->dwServiceSpecificExitCode = 0;
1613 lpservicestatus->dwCheckPoint = 0;
1614 lpservicestatus->dwWaitHint = 0;
1616 return TRUE;
1619 /******************************************************************************
1620 * QueryServiceStatusEx [ADVAPI32.@]
1622 * Get information about a service.
1624 * PARAMS
1625 * hService [I] Handle to service to get information about
1626 * InfoLevel [I] Level of information to get
1627 * lpBuffer [O] Destination for requested information
1628 * cbBufSize [I] Size of lpBuffer in bytes
1629 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1631 * RETURNS
1632 * Success: TRUE
1633 * FAILURE: FALSE
1635 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1636 LPBYTE lpBuffer, DWORD cbBufSize,
1637 LPDWORD pcbBytesNeeded)
1639 FIXME("stub\n");
1640 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1641 return FALSE;
1644 /******************************************************************************
1645 * QueryServiceConfigA [ADVAPI32.@]
1647 BOOL WINAPI
1648 QueryServiceConfigA( SC_HANDLE hService,
1649 LPQUERY_SERVICE_CONFIGA lpServiceConfig,
1650 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1652 static const CHAR szDisplayName[] = "DisplayName";
1653 static const CHAR szType[] = "Type";
1654 static const CHAR szStart[] = "Start";
1655 static const CHAR szError[] = "ErrorControl";
1656 static const CHAR szImagePath[] = "ImagePath";
1657 static const CHAR szGroup[] = "Group";
1658 static const CHAR szDependencies[] = "Dependencies";
1659 struct sc_service *hsvc;
1660 HKEY hKey;
1661 CHAR str_buffer[ MAX_PATH ];
1662 LONG r;
1663 DWORD type, val, sz, total, n;
1664 LPSTR p;
1666 TRACE("%p %p %d %p\n", hService, lpServiceConfig,
1667 cbBufSize, pcbBytesNeeded);
1669 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1670 if (!hsvc)
1672 SetLastError( ERROR_INVALID_HANDLE );
1673 return FALSE;
1675 hKey = hsvc->hkey;
1677 /* calculate the size required first */
1678 total = sizeof (QUERY_SERVICE_CONFIGA);
1680 sz = sizeof(str_buffer);
1681 r = RegQueryValueExA( hKey, szImagePath, 0, &type, (LPBYTE)str_buffer, &sz );
1682 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1684 sz = ExpandEnvironmentStringsA(str_buffer,NULL,0);
1685 if( 0 == sz ) return FALSE;
1687 total += sz;
1689 else
1691 /* FIXME: set last error */
1692 return FALSE;
1695 sz = 0;
1696 r = RegQueryValueExA( hKey, szGroup, 0, &type, NULL, &sz );
1697 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1698 total += sz;
1700 sz = 0;
1701 r = RegQueryValueExA( hKey, szDependencies, 0, &type, NULL, &sz );
1702 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1703 total += sz;
1705 sz = 0;
1706 r = RegQueryValueExA( hKey, szStart, 0, &type, NULL, &sz );
1707 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1708 total += sz;
1710 sz = 0;
1711 r = RegQueryValueExA( hKey, szDisplayName, 0, &type, NULL, &sz );
1712 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1713 total += sz;
1715 *pcbBytesNeeded = total;
1717 /* if there's not enough memory, return an error */
1718 if( total > cbBufSize )
1720 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1721 return FALSE;
1724 ZeroMemory( lpServiceConfig, total );
1726 sz = sizeof val;
1727 r = RegQueryValueExA( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1728 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1729 lpServiceConfig->dwServiceType = val;
1731 sz = sizeof val;
1732 r = RegQueryValueExA( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1733 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1734 lpServiceConfig->dwStartType = val;
1736 sz = sizeof val;
1737 r = RegQueryValueExA( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1738 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1739 lpServiceConfig->dwErrorControl = val;
1741 /* now do the strings */
1742 p = (LPSTR) &lpServiceConfig[1];
1743 n = total - sizeof (QUERY_SERVICE_CONFIGA);
1745 sz = sizeof(str_buffer);
1746 r = RegQueryValueExA( hKey, szImagePath, 0, &type, (LPBYTE)str_buffer, &sz );
1747 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1749 sz = ExpandEnvironmentStringsA(str_buffer, p, n);
1750 if( 0 == sz || sz > n ) return FALSE;
1752 lpServiceConfig->lpBinaryPathName = p;
1753 p += sz;
1754 n -= sz;
1756 else
1758 /* FIXME: set last error */
1759 return FALSE;
1762 sz = n;
1763 r = RegQueryValueExA( hKey, szGroup, 0, &type, (LPBYTE)p, &sz );
1764 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1766 lpServiceConfig->lpLoadOrderGroup = p;
1767 p += sz;
1768 n -= sz;
1771 sz = n;
1772 r = RegQueryValueExA( hKey, szDependencies, 0, &type, (LPBYTE)p, &sz );
1773 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1775 lpServiceConfig->lpDependencies = p;
1776 p += sz;
1777 n -= sz;
1780 if( n < 0 )
1781 ERR("Buffer overflow!\n");
1783 TRACE("Image path = %s\n", lpServiceConfig->lpBinaryPathName );
1784 TRACE("Group = %s\n", lpServiceConfig->lpLoadOrderGroup );
1786 return TRUE;
1789 /******************************************************************************
1790 * QueryServiceConfigW [ADVAPI32.@]
1792 BOOL WINAPI
1793 QueryServiceConfigW( SC_HANDLE hService,
1794 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1795 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1797 WCHAR str_buffer[ MAX_PATH ];
1798 LONG r;
1799 DWORD type, val, sz, total, n;
1800 LPBYTE p;
1801 HKEY hKey;
1802 struct sc_service *hsvc;
1804 TRACE("%p %p %d %p\n", hService, lpServiceConfig,
1805 cbBufSize, pcbBytesNeeded);
1807 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1808 if (!hsvc)
1810 SetLastError( ERROR_INVALID_HANDLE );
1811 return FALSE;
1813 hKey = hsvc->hkey;
1815 /* calculate the size required first */
1816 total = sizeof (QUERY_SERVICE_CONFIGW);
1818 sz = sizeof(str_buffer);
1819 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1820 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1822 sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1823 if( 0 == sz ) return FALSE;
1825 total += sizeof(WCHAR) * sz;
1827 else
1829 /* FIXME: set last error */
1830 return FALSE;
1833 sz = 0;
1834 r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1835 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1836 total += sz;
1838 sz = 0;
1839 r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1840 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1841 total += sz;
1842 else
1843 total += sizeof(WCHAR);
1845 sz = 0;
1846 r = RegQueryValueExW( hKey, szStart, 0, &type, NULL, &sz );
1847 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1848 total += sz;
1850 sz = 0;
1851 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1852 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1853 total += sz;
1855 *pcbBytesNeeded = total;
1857 /* if there's not enough memory, return an error */
1858 if( total > cbBufSize )
1860 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1861 return FALSE;
1864 ZeroMemory( lpServiceConfig, total );
1866 sz = sizeof val;
1867 r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1868 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1869 lpServiceConfig->dwServiceType = val;
1871 sz = sizeof val;
1872 r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1873 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1874 lpServiceConfig->dwStartType = val;
1876 sz = sizeof val;
1877 r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1878 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1879 lpServiceConfig->dwErrorControl = val;
1881 /* now do the strings */
1882 p = (LPBYTE) &lpServiceConfig[1];
1883 n = total - sizeof (QUERY_SERVICE_CONFIGW);
1885 sz = sizeof(str_buffer);
1886 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1887 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1889 sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
1890 sz *= sizeof(WCHAR);
1891 if( 0 == sz || sz > n ) return FALSE;
1893 lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
1894 p += sz;
1895 n -= sz;
1897 else
1899 /* FIXME: set last error */
1900 return FALSE;
1903 sz = n;
1904 r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
1905 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1907 lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
1908 p += sz;
1909 n -= sz;
1912 sz = n;
1913 r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
1914 lpServiceConfig->lpDependencies = (LPWSTR) p;
1915 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1917 p += sz;
1918 n -= sz;
1920 else
1922 *(WCHAR *) p = 0;
1923 p += sizeof(WCHAR);
1924 n -= sizeof(WCHAR);
1927 if( n < 0 )
1928 ERR("Buffer overflow!\n");
1930 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1931 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1933 return TRUE;
1936 /******************************************************************************
1937 * EnumServicesStatusA [ADVAPI32.@]
1939 BOOL WINAPI
1940 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
1941 DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
1942 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1943 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1945 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
1946 dwServiceType, dwServiceState, lpServices, cbBufSize,
1947 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
1948 SetLastError (ERROR_ACCESS_DENIED);
1949 return FALSE;
1952 /******************************************************************************
1953 * EnumServicesStatusW [ADVAPI32.@]
1955 BOOL WINAPI
1956 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
1957 DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
1958 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1959 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1961 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
1962 dwServiceType, dwServiceState, lpServices, cbBufSize,
1963 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
1964 SetLastError (ERROR_ACCESS_DENIED);
1965 return FALSE;
1968 /******************************************************************************
1969 * GetServiceKeyNameA [ADVAPI32.@]
1971 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
1972 LPSTR lpServiceName, LPDWORD lpcchBuffer )
1974 FIXME("%p %s %p %p\n", hSCManager, debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
1975 return FALSE;
1978 /******************************************************************************
1979 * GetServiceKeyNameW [ADVAPI32.@]
1981 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
1982 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
1984 FIXME("%p %s %p %p\n", hSCManager, debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
1985 return FALSE;
1988 /******************************************************************************
1989 * QueryServiceLockStatusA [ADVAPI32.@]
1991 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
1992 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
1993 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1995 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1997 return FALSE;
2000 /******************************************************************************
2001 * QueryServiceLockStatusW [ADVAPI32.@]
2003 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
2004 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2005 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2007 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2009 return FALSE;
2012 /******************************************************************************
2013 * GetServiceDisplayNameA [ADVAPI32.@]
2015 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
2016 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
2018 FIXME("%p %s %p %p\n", hSCManager,
2019 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
2020 return FALSE;
2023 /******************************************************************************
2024 * GetServiceDisplayNameW [ADVAPI32.@]
2026 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
2027 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
2029 FIXME("%p %s %p %p\n", hSCManager,
2030 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
2031 return FALSE;
2034 /******************************************************************************
2035 * ChangeServiceConfigW [ADVAPI32.@]
2037 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
2038 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
2039 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
2040 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
2042 struct reg_value val[10];
2043 struct sc_service *hsvc;
2044 DWORD r = ERROR_SUCCESS;
2045 HKEY hKey;
2046 int n = 0;
2048 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2049 hService, dwServiceType, dwStartType, dwErrorControl,
2050 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2051 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2052 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2054 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2055 if (!hsvc)
2057 SetLastError( ERROR_INVALID_HANDLE );
2058 return FALSE;
2060 hKey = hsvc->hkey;
2062 if( dwServiceType != SERVICE_NO_CHANGE )
2063 service_set_dword( &val[n++], szType, &dwServiceType );
2065 if( dwStartType != SERVICE_NO_CHANGE )
2066 service_set_dword( &val[n++], szStart, &dwStartType );
2068 if( dwErrorControl != SERVICE_NO_CHANGE )
2069 service_set_dword( &val[n++], szError, &dwErrorControl );
2071 if( lpBinaryPathName )
2072 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
2074 if( lpLoadOrderGroup )
2075 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
2077 if( lpDependencies )
2078 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
2080 if( lpPassword )
2081 FIXME("ignoring password\n");
2083 if( lpServiceStartName )
2084 service_set_string( &val[n++], szDependOnService, lpServiceStartName );
2086 r = service_write_values( hsvc->hkey, val, n );
2088 return (r == ERROR_SUCCESS) ? TRUE : FALSE ;
2091 /******************************************************************************
2092 * ChangeServiceConfigA [ADVAPI32.@]
2094 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2095 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2096 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2097 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2099 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2100 LPWSTR wServiceStartName, wPassword, wDisplayName;
2101 BOOL r;
2103 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2104 hService, dwServiceType, dwStartType, dwErrorControl,
2105 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2106 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2107 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2109 wBinaryPathName = SERV_dup( lpBinaryPathName );
2110 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2111 wDependencies = SERV_dupmulti( lpDependencies );
2112 wServiceStartName = SERV_dup( lpServiceStartName );
2113 wPassword = SERV_dup( lpPassword );
2114 wDisplayName = SERV_dup( lpDisplayName );
2116 r = ChangeServiceConfigW( hService, dwServiceType,
2117 dwStartType, dwErrorControl, wBinaryPathName,
2118 wLoadOrderGroup, lpdwTagId, wDependencies,
2119 wServiceStartName, wPassword, wDisplayName);
2121 SERV_free( wBinaryPathName );
2122 SERV_free( wLoadOrderGroup );
2123 SERV_free( wDependencies );
2124 SERV_free( wServiceStartName );
2125 SERV_free( wPassword );
2126 SERV_free( wDisplayName );
2128 return r;
2131 /******************************************************************************
2132 * ChangeServiceConfig2A [ADVAPI32.@]
2134 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2135 LPVOID lpInfo)
2137 BOOL r = FALSE;
2139 TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo);
2141 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2143 LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
2144 SERVICE_DESCRIPTIONW sdw;
2146 sdw.lpDescription = SERV_dup( sd->lpDescription );
2148 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2150 SERV_free( sdw.lpDescription );
2152 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2154 LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
2155 SERVICE_FAILURE_ACTIONSW faw;
2157 faw.dwResetPeriod = fa->dwResetPeriod;
2158 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2159 faw.lpCommand = SERV_dup( fa->lpCommand );
2160 faw.cActions = fa->cActions;
2161 faw.lpsaActions = fa->lpsaActions;
2163 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2165 SERV_free( faw.lpRebootMsg );
2166 SERV_free( faw.lpCommand );
2168 else
2169 SetLastError( ERROR_INVALID_PARAMETER );
2171 return r;
2174 /******************************************************************************
2175 * ChangeServiceConfig2W [ADVAPI32.@]
2177 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2178 LPVOID lpInfo)
2180 HKEY hKey;
2181 struct sc_service *hsvc;
2183 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2184 if (!hsvc)
2186 SetLastError( ERROR_INVALID_HANDLE );
2187 return FALSE;
2189 hKey = hsvc->hkey;
2191 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2193 static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2194 LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
2195 if (sd->lpDescription)
2197 TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
2198 if (sd->lpDescription[0] == 0)
2199 RegDeleteValueW(hKey,szDescription);
2200 else
2201 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2202 (LPVOID)sd->lpDescription,
2203 sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2206 else
2207 FIXME("STUB: %p %d %p\n",hService, dwInfoLevel, lpInfo);
2208 return TRUE;
2211 /******************************************************************************
2212 * QueryServiceObjectSecurity [ADVAPI32.@]
2214 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2215 SECURITY_INFORMATION dwSecurityInformation,
2216 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2217 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2219 PACL pACL = NULL;
2221 FIXME("%p %d %p %u %p\n", hService, dwSecurityInformation,
2222 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2224 InitializeSecurityDescriptor(lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
2226 pACL = HeapAlloc( GetProcessHeap(), 0, sizeof(ACL) );
2227 InitializeAcl(pACL, sizeof(ACL), ACL_REVISION);
2228 SetSecurityDescriptorDacl(lpSecurityDescriptor, TRUE, pACL, TRUE);
2229 return TRUE;
2232 /******************************************************************************
2233 * SetServiceObjectSecurity [ADVAPI32.@]
2235 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2236 SECURITY_INFORMATION dwSecurityInformation,
2237 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2239 FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2240 return TRUE;
2243 /******************************************************************************
2244 * SetServiceBits [ADVAPI32.@]
2246 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2247 DWORD dwServiceBits,
2248 BOOL bSetBitsOn,
2249 BOOL bUpdateImmediately)
2251 FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2252 bSetBitsOn, bUpdateImmediately);
2253 return TRUE;
2256 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR lpServiceName,
2257 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2259 FIXME("%s %p %p\n", debugstr_a(lpServiceName), lpHandlerProc, lpContext);
2260 return 0;
2263 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2264 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2266 service_data *service;
2268 TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2270 EnterCriticalSection( &service_cs );
2271 for(service = service_list; service; service = service->next)
2272 if(!strcmpW(lpServiceName, service->name))
2273 break;
2274 if (service)
2276 service->handler.handler_ex = lpHandlerProc;
2277 service->context = lpContext;
2278 service->extended = TRUE;
2280 LeaveCriticalSection( &service_cs );
2282 return (SERVICE_STATUS_HANDLE)service;