advapi32: Fix set process request, a pipe instance can only handle one request.
[wine.git] / dlls / advapi32 / service.c
blob587b9aea09f0ef75d44d17d7510112961aeb8642
1 /*
2 * Win32 advapi functions
4 * Copyright 1995 Sven Verdoolaege
5 * Copyright 2005 Mike McCormack
6 * Copyright 2007 Rolf Kalbermatter
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include <stdarg.h>
24 #include <string.h>
25 #include <time.h>
26 #include <assert.h>
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winsvc.h"
31 #include "winerror.h"
32 #include "winreg.h"
33 #include "wine/unicode.h"
34 #include "wine/debug.h"
35 #include "winternl.h"
36 #include "lmcons.h"
37 #include "lmserver.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(advapi);
41 static const WCHAR szServiceManagerKey[] = { 'S','y','s','t','e','m','\\',
42 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
43 'S','e','r','v','i','c','e','s',0 };
44 static const WCHAR szSCMLock[] = {'A','D','V','A','P','I','_','S','C','M',
45 'L','O','C','K',0};
47 typedef struct service_start_info_t
49 DWORD cmd;
50 DWORD size;
51 WCHAR str[1];
52 } service_start_info;
54 #define WINESERV_STARTINFO 1
55 #define WINESERV_GETSTATUS 2
56 #define WINESERV_SENDCONTROL 3
57 #define WINESERV_SETPID 4
59 typedef struct service_data_t
61 struct service_data_t *next;
62 union {
63 LPHANDLER_FUNCTION handler;
64 LPHANDLER_FUNCTION_EX handler_ex;
65 } handler;
66 LPVOID context;
67 SERVICE_STATUS_PROCESS status;
68 HANDLE thread;
69 BOOL unicode : 1;
70 BOOL extended : 1; /* uses handler_ex instead of handler? */
71 union {
72 LPSERVICE_MAIN_FUNCTIONA a;
73 LPSERVICE_MAIN_FUNCTIONW w;
74 } proc;
75 LPWSTR args;
76 WCHAR name[1];
77 } service_data;
79 static CRITICAL_SECTION service_cs;
80 static CRITICAL_SECTION_DEBUG service_cs_debug =
82 0, 0, &service_cs,
83 { &service_cs_debug.ProcessLocksList,
84 &service_cs_debug.ProcessLocksList },
85 0, 0, { (DWORD_PTR)(__FILE__ ": service_cs") }
87 static CRITICAL_SECTION service_cs = { &service_cs_debug, -1, 0, 0, 0, 0 };
89 static service_data *service_list;
91 /******************************************************************************
92 * SC_HANDLEs
95 #define MAX_SERVICE_NAME 256
97 typedef enum { SC_HTYPE_MANAGER, SC_HTYPE_SERVICE } SC_HANDLE_TYPE;
99 struct sc_handle;
100 typedef VOID (*sc_handle_destructor)(struct sc_handle *);
102 struct sc_handle
104 SC_HANDLE_TYPE htype;
105 DWORD ref_count;
106 sc_handle_destructor destroy;
109 struct sc_manager /* service control manager handle */
111 struct sc_handle hdr;
112 HKEY hkey; /* handle to services database in the registry */
115 struct sc_service /* service handle */
117 struct sc_handle hdr;
118 HKEY hkey; /* handle to service entry in the registry (under hkey) */
119 struct sc_manager *scm; /* pointer to SCM handle */
120 WCHAR name[1];
123 static void *sc_handle_alloc(SC_HANDLE_TYPE htype, DWORD size,
124 sc_handle_destructor destroy)
126 struct sc_handle *hdr;
128 hdr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
129 if (hdr)
131 hdr->htype = htype;
132 hdr->ref_count = 1;
133 hdr->destroy = destroy;
135 TRACE("sc_handle type=%d -> %p\n", htype, hdr);
136 return hdr;
139 static void *sc_handle_get_handle_data(SC_HANDLE handle, DWORD htype)
141 struct sc_handle *hdr = (struct sc_handle *) handle;
143 if (!hdr)
144 return NULL;
145 if (hdr->htype != htype)
146 return NULL;
147 return hdr;
150 static void sc_handle_free(struct sc_handle* hdr)
152 if (!hdr)
153 return;
154 if (--hdr->ref_count)
155 return;
156 hdr->destroy(hdr);
157 HeapFree(GetProcessHeap(), 0, hdr);
160 static void sc_handle_destroy_manager(struct sc_handle *handle)
162 struct sc_manager *mgr = (struct sc_manager*) handle;
164 TRACE("destroying SC Manager %p\n", mgr);
165 if (mgr->hkey)
166 RegCloseKey(mgr->hkey);
169 static void sc_handle_destroy_service(struct sc_handle *handle)
171 struct sc_service *svc = (struct sc_service*) handle;
173 TRACE("destroying service %p\n", svc);
174 if (svc->hkey)
175 RegCloseKey(svc->hkey);
176 svc->hkey = NULL;
177 sc_handle_free(&svc->scm->hdr);
178 svc->scm = NULL;
181 /******************************************************************************
182 * String management functions
184 static inline LPWSTR SERV_dup( LPCSTR str )
186 UINT len;
187 LPWSTR wstr;
189 if( !str )
190 return NULL;
191 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
192 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
193 MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
194 return wstr;
197 static inline LPWSTR SERV_dupmulti(LPCSTR str)
199 UINT len = 0, n = 0;
200 LPWSTR wstr;
202 if( !str )
203 return NULL;
204 do {
205 len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
206 n += (strlen( &str[n] ) + 1);
207 } while (str[n]);
208 len++;
209 n++;
211 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
212 MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
213 return wstr;
216 static inline VOID SERV_free( LPWSTR wstr )
218 HeapFree( GetProcessHeap(), 0, wstr );
221 /******************************************************************************
222 * registry access functions and data
224 static const WCHAR szDisplayName[] = {
225 'D','i','s','p','l','a','y','N','a','m','e', 0 };
226 static const WCHAR szType[] = {'T','y','p','e',0};
227 static const WCHAR szStart[] = {'S','t','a','r','t',0};
228 static const WCHAR szError[] = {
229 'E','r','r','o','r','C','o','n','t','r','o','l', 0};
230 static const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
231 static const WCHAR szGroup[] = {'G','r','o','u','p',0};
232 static const WCHAR szDependencies[] = {
233 'D','e','p','e','n','d','e','n','c','i','e','s',0};
234 static const WCHAR szDependOnService[] = {
235 'D','e','p','e','n','d','O','n','S','e','r','v','i','c','e',0};
237 struct reg_value {
238 DWORD type;
239 DWORD size;
240 LPCWSTR name;
241 LPCVOID data;
244 static inline void service_set_value( struct reg_value *val,
245 DWORD type, LPCWSTR name, LPCVOID data, DWORD size )
247 val->name = name;
248 val->type = type;
249 val->data = data;
250 val->size = size;
253 static inline void service_set_dword( struct reg_value *val,
254 LPCWSTR name, const DWORD *data )
256 service_set_value( val, REG_DWORD, name, data, sizeof (DWORD));
259 static inline void service_set_string( struct reg_value *val,
260 LPCWSTR name, LPCWSTR string )
262 DWORD len = (lstrlenW(string)+1) * sizeof (WCHAR);
263 service_set_value( val, REG_SZ, name, string, len );
266 static inline void service_set_multi_string( struct reg_value *val,
267 LPCWSTR name, LPCWSTR string )
269 DWORD len = 0;
271 /* determine the length of a double null terminated multi string */
272 do {
273 len += (lstrlenW( &string[ len ] )+1);
274 } while ( string[ len++ ] );
276 len *= sizeof (WCHAR);
277 service_set_value( val, REG_MULTI_SZ, name, string, len );
280 static inline LONG service_write_values( HKEY hKey,
281 const struct reg_value *val, int n )
283 LONG r = ERROR_SUCCESS;
284 int i;
286 for( i=0; i<n; i++ )
288 r = RegSetValueExW(hKey, val[i].name, 0, val[i].type,
289 (const BYTE*)val[i].data, val[i].size );
290 if( r != ERROR_SUCCESS )
291 break;
293 return r;
296 /******************************************************************************
297 * Service IPC functions
299 static LPWSTR service_get_pipe_name(LPCWSTR service)
301 static const WCHAR prefix[] = { '\\','\\','.','\\','p','i','p','e','\\',
302 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
303 LPWSTR name;
304 DWORD len;
306 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
307 name = HeapAlloc(GetProcessHeap(), 0, len);
308 strcpyW(name, prefix);
309 strcatW(name, service);
310 return name;
313 static HANDLE service_open_pipe(LPCWSTR service)
315 LPWSTR szPipe = service_get_pipe_name( service );
316 HANDLE handle = INVALID_HANDLE_VALUE;
318 do {
319 handle = CreateFileW(szPipe, GENERIC_READ|GENERIC_WRITE,
320 0, NULL, OPEN_ALWAYS, 0, NULL);
321 if (handle != INVALID_HANDLE_VALUE)
322 break;
323 if (GetLastError() != ERROR_PIPE_BUSY)
324 break;
325 } while (WaitNamedPipeW(szPipe, NMPWAIT_WAIT_FOREVER));
326 SERV_free(szPipe);
328 return handle;
331 /******************************************************************************
332 * service_get_event_handle
334 static HANDLE service_get_event_handle(LPCWSTR service)
336 static const WCHAR prefix[] = {
337 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
338 LPWSTR name;
339 DWORD len;
340 HANDLE handle;
342 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
343 name = HeapAlloc(GetProcessHeap(), 0, len);
344 strcpyW(name, prefix);
345 strcatW(name, service);
346 handle = CreateEventW(NULL, TRUE, FALSE, name);
347 SERV_free(name);
348 return handle;
351 /******************************************************************************
352 * service_thread
354 * Call into the main service routine provided by StartServiceCtrlDispatcher.
356 static DWORD WINAPI service_thread(LPVOID arg)
358 service_data *info = arg;
359 LPWSTR str = info->args;
360 DWORD argc = 0, len = 0;
362 TRACE("%p\n", arg);
364 while (str[len])
366 len += strlenW(&str[len]) + 1;
367 argc++;
370 if (!argc)
372 if (info->unicode)
373 info->proc.w(0, NULL);
374 else
375 info->proc.a(0, NULL);
376 return 0;
379 if (info->unicode)
381 LPWSTR *argv, p;
383 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPWSTR));
384 for (argc=0, p=str; *p; p += strlenW(p) + 1)
385 argv[argc++] = p;
386 argv[argc] = NULL;
388 info->proc.w(argc, argv);
389 HeapFree(GetProcessHeap(), 0, argv);
391 else
393 LPSTR strA, *argv, p;
394 DWORD lenA;
396 lenA = WideCharToMultiByte(CP_ACP,0, str, len, NULL, 0, NULL, NULL);
397 strA = HeapAlloc(GetProcessHeap(), 0, lenA);
398 WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL);
400 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPSTR));
401 for (argc=0, p=strA; *p; p += strlen(p) + 1)
402 argv[argc++] = p;
403 argv[argc] = NULL;
405 info->proc.a(argc, argv);
406 HeapFree(GetProcessHeap(), 0, argv);
407 HeapFree(GetProcessHeap(), 0, strA);
409 return 0;
412 /******************************************************************************
413 * service_handle_start
415 static BOOL service_handle_start(HANDLE pipe, service_data *service, DWORD count)
417 DWORD read = 0, result = 0;
418 LPWSTR args;
419 BOOL r;
421 TRACE("%p %p %d\n", pipe, service, count);
423 args = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
424 r = ReadFile(pipe, args, count*sizeof(WCHAR), &read, NULL);
425 if (!r || count!=read/sizeof(WCHAR) || args[count-1])
427 ERR("pipe read failed r = %d count = %d read = %d args[n-1]=%s\n",
428 r, count, read, debugstr_wn(args, count));
429 goto end;
432 if (service->thread)
434 ERR("service is not stopped\n");
435 goto end;
438 SERV_free(service->args);
439 service->args = args;
440 args = NULL;
441 service->thread = CreateThread( NULL, 0, service_thread,
442 service, 0, NULL );
444 end:
445 HeapFree(GetProcessHeap(), 0, args);
446 WriteFile( pipe, &result, sizeof result, &read, NULL );
448 return TRUE;
451 /******************************************************************************
452 * service_send_start_message
454 static BOOL service_send_start_message(HANDLE pipe, LPCWSTR *argv, DWORD argc)
456 DWORD i, len, count, result;
457 service_start_info *ssi;
458 LPWSTR p;
459 BOOL r;
461 TRACE("%p %p %d\n", pipe, argv, argc);
463 /* calculate how much space do we need to send the startup info */
464 len = 1;
465 for (i=0; i<argc; i++)
466 len += strlenW(argv[i])+1;
468 ssi = HeapAlloc(GetProcessHeap(),0,sizeof *ssi + (len-1)*sizeof(WCHAR));
469 ssi->cmd = WINESERV_STARTINFO;
470 ssi->size = len;
472 /* copy service args into a single buffer*/
473 p = &ssi->str[0];
474 for (i=0; i<argc; i++)
476 strcpyW(p, argv[i]);
477 p += strlenW(p) + 1;
479 *p=0;
481 r = WriteFile(pipe, ssi, sizeof *ssi + len*sizeof(WCHAR), &count, NULL);
482 if (r)
483 r = ReadFile(pipe, &result, sizeof result, &count, NULL);
485 HeapFree(GetProcessHeap(),0,ssi);
487 return r;
490 /******************************************************************************
491 * service_handle_get_status
493 static BOOL service_handle_get_status(HANDLE pipe, const service_data *service)
495 DWORD count = 0;
496 TRACE("\n");
497 return WriteFile(pipe, &service->status,
498 sizeof service->status, &count, NULL);
501 /******************************************************************************
502 * service_get_status
504 static BOOL service_get_status(HANDLE pipe, LPSERVICE_STATUS_PROCESS status)
506 DWORD cmd[2], count = 0;
507 BOOL r;
509 cmd[0] = WINESERV_GETSTATUS;
510 cmd[1] = 0;
511 r = WriteFile( pipe, cmd, sizeof cmd, &count, NULL );
512 if (!r || count != sizeof cmd)
514 ERR("service protocol error - failed to write pipe!\n");
515 return r;
517 r = ReadFile( pipe, status, sizeof *status, &count, NULL );
518 if (!r || count != sizeof *status)
519 ERR("service protocol error - failed to read pipe "
520 "r = %d count = %d!\n", r, count);
521 return r;
524 /******************************************************************************
525 * service_handle_set_processID
527 static BOOL service_handle_set_processID(HANDLE pipe, service_data *service, DWORD dwProcessId)
529 DWORD count, ret = ERROR_SUCCESS;
531 TRACE("received control %d\n", dwProcessId);
532 service->status.dwProcessId = dwProcessId;
533 return WriteFile(pipe, &ret, sizeof ret , &count, NULL);
536 /******************************************************************************
537 * service_set_processID
539 static BOOL service_set_processID(HANDLE pipe, DWORD dwprocessId, LPDWORD dwResult)
541 DWORD cmd[2], count = 0;
542 BOOL r;
544 cmd[0] = WINESERV_SETPID;
545 cmd[1] = dwprocessId;
546 r = WriteFile( pipe, cmd, sizeof cmd, &count, NULL );
547 if (!r || count != sizeof cmd)
549 ERR("service protocol error - failed to write pipe!\n");
550 return r;
552 r = ReadFile( pipe, dwResult, sizeof *dwResult, &count, NULL );
553 if (!r || count != sizeof *dwResult)
554 ERR("service protocol error - failed to read pipe "
555 "r = %d count = %d!\n", r, count);
556 return r;
559 /******************************************************************************
560 * service_send_control
562 static BOOL service_send_control(HANDLE pipe, DWORD dwControl, DWORD *result)
564 DWORD cmd[2], count = 0;
565 BOOL r;
567 cmd[0] = WINESERV_SENDCONTROL;
568 cmd[1] = dwControl;
569 r = WriteFile(pipe, cmd, sizeof cmd, &count, NULL);
570 if (!r || count != sizeof cmd)
572 ERR("service protocol error - failed to write pipe!\n");
573 return r;
575 r = ReadFile(pipe, result, sizeof *result, &count, NULL);
576 if (!r || count != sizeof *result)
577 ERR("service protocol error - failed to read pipe "
578 "r = %d count = %d!\n", r, count);
579 return r;
582 /******************************************************************************
583 * service_accepts_control
585 static BOOL service_accepts_control(const service_data *service, DWORD dwControl)
587 DWORD a = service->status.dwControlsAccepted;
589 switch (dwControl)
591 case SERVICE_CONTROL_INTERROGATE:
592 return TRUE;
593 case SERVICE_CONTROL_STOP:
594 if (a&SERVICE_ACCEPT_STOP)
595 return TRUE;
596 break;
597 case SERVICE_CONTROL_SHUTDOWN:
598 if (a&SERVICE_ACCEPT_SHUTDOWN)
599 return TRUE;
600 break;
601 case SERVICE_CONTROL_PAUSE:
602 case SERVICE_CONTROL_CONTINUE:
603 if (a&SERVICE_ACCEPT_PAUSE_CONTINUE)
604 return TRUE;
605 break;
606 case SERVICE_CONTROL_PARAMCHANGE:
607 if (a&SERVICE_ACCEPT_PARAMCHANGE)
608 return TRUE;
609 break;
610 case SERVICE_CONTROL_NETBINDADD:
611 case SERVICE_CONTROL_NETBINDREMOVE:
612 case SERVICE_CONTROL_NETBINDENABLE:
613 case SERVICE_CONTROL_NETBINDDISABLE:
614 if (a&SERVICE_ACCEPT_NETBINDCHANGE)
615 return TRUE;
617 if (!service->extended)
618 return FALSE;
619 switch (dwControl)
621 case SERVICE_CONTROL_HARDWAREPROFILECHANGE:
622 if (a&SERVICE_ACCEPT_HARDWAREPROFILECHANGE)
623 return TRUE;
624 break;
625 case SERVICE_CONTROL_POWEREVENT:
626 if (a&SERVICE_ACCEPT_POWEREVENT)
627 return TRUE;
628 break;
629 case SERVICE_CONTROL_SESSIONCHANGE:
630 if (a&SERVICE_ACCEPT_SESSIONCHANGE)
631 return TRUE;
632 break;
634 return FALSE;
637 /******************************************************************************
638 * service_handle_control
640 static BOOL service_handle_control(HANDLE pipe, service_data *service,
641 DWORD dwControl)
643 DWORD count, ret = ERROR_INVALID_SERVICE_CONTROL;
645 TRACE("received control %d\n", dwControl);
647 if (service_accepts_control(service, dwControl))
649 if (service->extended && service->handler.handler_ex)
651 service->handler.handler_ex(dwControl, 0, NULL, service->context);
652 ret = ERROR_SUCCESS;
654 else if (service->handler.handler)
656 service->handler.handler(dwControl);
657 ret = ERROR_SUCCESS;
660 return WriteFile(pipe, &ret, sizeof ret, &count, NULL);
663 /******************************************************************************
664 * service_reap_thread
666 static DWORD service_reap_thread(service_data *service)
668 DWORD exitcode = 0;
670 if (!service->thread)
671 return 0;
672 GetExitCodeThread(service->thread, &exitcode);
673 if (exitcode!=STILL_ACTIVE)
675 CloseHandle(service->thread);
676 service->thread = 0;
678 return exitcode;
681 /******************************************************************************
682 * service_control_dispatcher
684 static DWORD WINAPI service_control_dispatcher(LPVOID arg)
686 service_data *service = arg;
687 LPWSTR name;
688 HANDLE pipe, event;
690 TRACE("%p %s\n", service, debugstr_w(service->name));
692 /* create a pipe to talk to the rest of the world with */
693 name = service_get_pipe_name(service->name);
694 pipe = CreateNamedPipeW(name, PIPE_ACCESS_DUPLEX,
695 PIPE_TYPE_BYTE|PIPE_WAIT, 1, 256, 256, 10000, NULL );
696 SERV_free(name);
698 /* let the process who started us know we've tried to create a pipe */
699 event = service_get_event_handle(service->name);
700 SetEvent(event);
701 CloseHandle(event);
703 if (pipe==INVALID_HANDLE_VALUE)
705 ERR("failed to create pipe for %s, error = %d\n",
706 debugstr_w(service->name), GetLastError());
707 return 0;
710 /* dispatcher loop */
711 while (1)
713 BOOL r;
714 DWORD count, req[2] = {0,0};
716 r = ConnectNamedPipe(pipe, NULL);
717 if (!r && GetLastError() != ERROR_PIPE_CONNECTED)
719 ERR("pipe connect failed\n");
720 break;
723 r = ReadFile( pipe, &req, sizeof req, &count, NULL );
724 if (!r || count!=sizeof req)
726 ERR("pipe read failed\n");
727 break;
730 service_reap_thread(service);
732 /* handle the request */
733 switch (req[0])
735 case WINESERV_STARTINFO:
736 service_handle_start(pipe, service, req[1]);
737 break;
738 case WINESERV_GETSTATUS:
739 service_handle_get_status(pipe, service);
740 break;
741 case WINESERV_SENDCONTROL:
742 service_handle_control(pipe, service, req[1]);
743 break;
744 case WINESERV_SETPID:
745 service_handle_set_processID(pipe, service, req[1]);
746 break;
747 default:
748 ERR("received invalid command %d length %d\n", req[0], req[1]);
751 FlushFileBuffers(pipe);
752 DisconnectNamedPipe(pipe);
755 CloseHandle(pipe);
756 return 1;
759 /******************************************************************************
760 * service_run_threads
762 static BOOL service_run_threads(void)
764 service_data *service;
765 DWORD count = 0, n = 0;
766 HANDLE *handles;
768 EnterCriticalSection( &service_cs );
770 /* count how many services there are */
771 for (service = service_list; service; service = service->next)
772 count++;
774 TRACE("starting %d pipe listener threads\n", count);
776 handles = HeapAlloc(GetProcessHeap(), 0, sizeof(HANDLE)*count);
778 for (n=0, service = service_list; service; service = service->next, n++)
779 handles[n] = CreateThread( NULL, 0, service_control_dispatcher,
780 service, 0, NULL );
781 assert(n==count);
783 LeaveCriticalSection( &service_cs );
785 /* wait for all the threads to pack up and exit */
786 WaitForMultipleObjectsEx(count, handles, TRUE, INFINITE, FALSE);
788 HeapFree(GetProcessHeap(), 0, handles);
790 return TRUE;
793 /******************************************************************************
794 * StartServiceCtrlDispatcherA [ADVAPI32.@]
796 * See StartServiceCtrlDispatcherW.
798 BOOL WINAPI StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *servent )
800 service_data *info;
801 DWORD sz, len;
802 BOOL ret = TRUE;
804 TRACE("%p\n", servent);
806 EnterCriticalSection( &service_cs );
807 while (servent->lpServiceName)
809 LPSTR name = servent->lpServiceName;
811 len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0);
812 sz = len*sizeof(WCHAR) + sizeof *info;
813 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
814 MultiByteToWideChar(CP_ACP, 0, name, -1, info->name, len);
815 info->proc.a = servent->lpServiceProc;
816 info->unicode = FALSE;
818 /* insert into the list */
819 info->next = service_list;
820 service_list = info;
822 servent++;
824 LeaveCriticalSection( &service_cs );
826 service_run_threads();
828 return ret;
831 /******************************************************************************
832 * StartServiceCtrlDispatcherW [ADVAPI32.@]
834 * Connects a process containing one or more services to the service control
835 * manager.
837 * PARAMS
838 * servent [I] A list of the service names and service procedures
840 * RETURNS
841 * Success: TRUE.
842 * Failure: FALSE.
844 BOOL WINAPI StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW *servent )
846 service_data *info;
847 DWORD sz, len;
848 BOOL ret = TRUE;
850 TRACE("%p\n", servent);
852 EnterCriticalSection( &service_cs );
853 while (servent->lpServiceName)
855 LPWSTR name = servent->lpServiceName;
857 len = strlenW(name);
858 sz = len*sizeof(WCHAR) + sizeof *info;
859 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
860 strcpyW(info->name, name);
861 info->proc.w = servent->lpServiceProc;
862 info->unicode = TRUE;
864 /* insert into the list */
865 info->next = service_list;
866 service_list = info;
868 servent++;
870 LeaveCriticalSection( &service_cs );
872 service_run_threads();
874 return ret;
877 /******************************************************************************
878 * LockServiceDatabase [ADVAPI32.@]
880 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
882 HANDLE ret;
884 TRACE("%p\n",hSCManager);
886 ret = CreateSemaphoreW( NULL, 1, 1, szSCMLock );
887 if( ret && GetLastError() == ERROR_ALREADY_EXISTS )
889 CloseHandle( ret );
890 ret = NULL;
891 SetLastError( ERROR_SERVICE_DATABASE_LOCKED );
894 TRACE("returning %p\n", ret);
896 return ret;
899 /******************************************************************************
900 * UnlockServiceDatabase [ADVAPI32.@]
902 BOOL WINAPI UnlockServiceDatabase (SC_LOCK ScLock)
904 TRACE("%p\n",ScLock);
906 return CloseHandle( ScLock );
909 /******************************************************************************
910 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
912 SERVICE_STATUS_HANDLE WINAPI
913 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName, LPHANDLER_FUNCTION lpfHandler )
915 LPWSTR lpServiceNameW;
916 SERVICE_STATUS_HANDLE ret;
918 lpServiceNameW = SERV_dup(lpServiceName);
919 ret = RegisterServiceCtrlHandlerW( lpServiceNameW, lpfHandler );
920 SERV_free(lpServiceNameW);
921 return ret;
924 /******************************************************************************
925 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
927 * PARAMS
928 * lpServiceName []
929 * lpfHandler []
931 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName,
932 LPHANDLER_FUNCTION lpfHandler )
934 service_data *service;
936 EnterCriticalSection( &service_cs );
937 for(service = service_list; service; service = service->next)
938 if(!strcmpW(lpServiceName, service->name))
939 break;
940 if (service)
941 service->handler.handler = lpfHandler;
942 LeaveCriticalSection( &service_cs );
944 return (SERVICE_STATUS_HANDLE)service;
947 /******************************************************************************
948 * SetServiceStatus [ADVAPI32.@]
950 * PARAMS
951 * hService []
952 * lpStatus []
954 BOOL WINAPI
955 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
957 service_data *service;
958 BOOL r = TRUE;
960 TRACE("%p %x %x %x %x %x %x %x\n", hService,
961 lpStatus->dwServiceType, lpStatus->dwCurrentState,
962 lpStatus->dwControlsAccepted, lpStatus->dwWin32ExitCode,
963 lpStatus->dwServiceSpecificExitCode, lpStatus->dwCheckPoint,
964 lpStatus->dwWaitHint);
966 EnterCriticalSection( &service_cs );
967 for (service = service_list; service; service = service->next)
968 if(service == (service_data*)hService)
969 break;
970 if (service)
972 memcpy( &service->status, lpStatus, sizeof(SERVICE_STATUS) );
973 TRACE("Set service status to %d\n",service->status.dwCurrentState);
975 else
976 r = FALSE;
977 LeaveCriticalSection( &service_cs );
979 return r;
983 /******************************************************************************
984 * OpenSCManagerA [ADVAPI32.@]
986 * Establish a connection to the service control manager and open its database.
988 * PARAMS
989 * lpMachineName [I] Pointer to machine name string
990 * lpDatabaseName [I] Pointer to database name string
991 * dwDesiredAccess [I] Type of access
993 * RETURNS
994 * Success: A Handle to the service control manager database
995 * Failure: NULL
997 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
998 DWORD dwDesiredAccess )
1000 LPWSTR lpMachineNameW, lpDatabaseNameW;
1001 SC_HANDLE ret;
1003 lpMachineNameW = SERV_dup(lpMachineName);
1004 lpDatabaseNameW = SERV_dup(lpDatabaseName);
1005 ret = OpenSCManagerW(lpMachineNameW, lpDatabaseNameW, dwDesiredAccess);
1006 SERV_free(lpDatabaseNameW);
1007 SERV_free(lpMachineNameW);
1008 return ret;
1011 /******************************************************************************
1012 * OpenSCManagerW [ADVAPI32.@]
1014 * See OpenSCManagerA.
1016 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
1017 DWORD dwDesiredAccess )
1019 struct sc_manager *manager;
1020 HKEY hReg;
1021 LONG r;
1023 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName),
1024 debugstr_w(lpDatabaseName), dwDesiredAccess);
1026 if( lpDatabaseName && lpDatabaseName[0] )
1028 if( strcmpiW( lpDatabaseName, SERVICES_ACTIVE_DATABASEW ) == 0 )
1030 /* noop, all right */
1032 else if( strcmpiW( lpDatabaseName, SERVICES_FAILED_DATABASEW ) == 0 )
1034 SetLastError( ERROR_DATABASE_DOES_NOT_EXIST );
1035 return NULL;
1037 else
1039 SetLastError( ERROR_INVALID_NAME );
1040 return NULL;
1044 manager = sc_handle_alloc( SC_HTYPE_MANAGER, sizeof (struct sc_manager),
1045 sc_handle_destroy_manager );
1046 if (!manager)
1047 return NULL;
1049 r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
1050 if (r!=ERROR_SUCCESS)
1051 goto error;
1053 r = RegCreateKeyW(hReg, szServiceManagerKey, &manager->hkey);
1054 RegCloseKey( hReg );
1055 if (r!=ERROR_SUCCESS)
1056 goto error;
1058 TRACE("returning %p\n", manager);
1060 return (SC_HANDLE) &manager->hdr;
1062 error:
1063 sc_handle_free( &manager->hdr );
1064 SetLastError( r);
1065 return NULL;
1068 /******************************************************************************
1069 * ControlService [ADVAPI32.@]
1071 * Send a control code to a service.
1073 * PARAMS
1074 * hService [I] Handle of the service control manager database
1075 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
1076 * lpServiceStatus [O] Destination for the status of the service, if available
1078 * RETURNS
1079 * Success: TRUE.
1080 * Failure: FALSE.
1082 * BUGS
1083 * Unlike M$' implementation, control requests are not serialized and may be
1084 * processed asynchronously.
1086 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
1087 LPSERVICE_STATUS lpServiceStatus )
1089 struct sc_service *hsvc;
1090 BOOL ret = FALSE;
1091 HANDLE handle;
1093 TRACE("%p %d %p\n", hService, dwControl, lpServiceStatus);
1095 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1096 if (!hsvc)
1098 SetLastError( ERROR_INVALID_HANDLE );
1099 return FALSE;
1102 ret = QueryServiceStatus(hService, lpServiceStatus);
1103 if (!ret)
1105 ERR("failed to query service status\n");
1106 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1107 return FALSE;
1110 switch (lpServiceStatus->dwCurrentState)
1112 case SERVICE_STOPPED:
1113 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1114 return FALSE;
1115 case SERVICE_START_PENDING:
1116 if (dwControl==SERVICE_CONTROL_STOP)
1117 break;
1118 /* fall thru */
1119 case SERVICE_STOP_PENDING:
1120 SetLastError(ERROR_SERVICE_CANNOT_ACCEPT_CTRL);
1121 return FALSE;
1124 handle = service_open_pipe(hsvc->name);
1125 if (handle!=INVALID_HANDLE_VALUE)
1127 DWORD result = ERROR_SUCCESS;
1128 ret = service_send_control(handle, dwControl, &result);
1129 CloseHandle(handle);
1130 if (result!=ERROR_SUCCESS)
1132 SetLastError(result);
1133 ret = FALSE;
1137 return ret;
1140 /******************************************************************************
1141 * CloseServiceHandle [ADVAPI32.@]
1143 * Close a handle to a service or the service control manager database.
1145 * PARAMS
1146 * hSCObject [I] Handle to service or service control manager database
1148 * RETURNS
1149 * Success: TRUE
1150 * Failure: FALSE
1152 BOOL WINAPI
1153 CloseServiceHandle( SC_HANDLE hSCObject )
1155 TRACE("%p\n", hSCObject);
1157 sc_handle_free( (struct sc_handle*) hSCObject );
1159 return TRUE;
1163 /******************************************************************************
1164 * OpenServiceA [ADVAPI32.@]
1166 * Open a handle to a service.
1168 * PARAMS
1169 * hSCManager [I] Handle of the service control manager database
1170 * lpServiceName [I] Name of the service to open
1171 * dwDesiredAccess [I] Access required to the service
1173 * RETURNS
1174 * Success: Handle to the service
1175 * Failure: NULL
1177 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1178 DWORD dwDesiredAccess )
1180 LPWSTR lpServiceNameW;
1181 SC_HANDLE ret;
1183 TRACE("%p %s %d\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
1185 lpServiceNameW = SERV_dup(lpServiceName);
1186 ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
1187 SERV_free(lpServiceNameW);
1188 return ret;
1192 /******************************************************************************
1193 * OpenServiceW [ADVAPI32.@]
1195 * See OpenServiceA.
1197 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1198 DWORD dwDesiredAccess)
1200 struct sc_manager *hscm;
1201 struct sc_service *hsvc;
1202 HKEY hKey;
1203 long r;
1204 DWORD len;
1206 TRACE("%p %s %d\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
1208 if (!lpServiceName)
1210 SetLastError(ERROR_INVALID_ADDRESS);
1211 return NULL;
1214 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1215 if (!hscm)
1217 SetLastError( ERROR_INVALID_HANDLE );
1218 return FALSE;
1221 r = RegOpenKeyExW( hscm->hkey, lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
1222 if (r!=ERROR_SUCCESS)
1224 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
1225 return NULL;
1228 len = strlenW(lpServiceName)+1;
1229 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE,
1230 sizeof (struct sc_service) + len*sizeof(WCHAR),
1231 sc_handle_destroy_service );
1232 if (!hsvc)
1233 return NULL;
1234 strcpyW( hsvc->name, lpServiceName );
1235 hsvc->hkey = hKey;
1237 /* add reference to SCM handle */
1238 hscm->hdr.ref_count++;
1239 hsvc->scm = hscm;
1241 TRACE("returning %p\n",hsvc);
1243 return (SC_HANDLE) &hsvc->hdr;
1246 /******************************************************************************
1247 * CreateServiceW [ADVAPI32.@]
1249 SC_HANDLE WINAPI
1250 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1251 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
1252 DWORD dwServiceType, DWORD dwStartType,
1253 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1254 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1255 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
1256 LPCWSTR lpPassword )
1258 struct sc_manager *hscm;
1259 struct sc_service *hsvc = NULL;
1260 HKEY hKey;
1261 LONG r;
1262 DWORD dp, len;
1263 struct reg_value val[10];
1264 int n = 0;
1266 TRACE("%p %s %s\n", hSCManager,
1267 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
1269 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1270 if (!hscm)
1272 SetLastError( ERROR_INVALID_HANDLE );
1273 return NULL;
1276 r = RegCreateKeyExW(hscm->hkey, lpServiceName, 0, NULL,
1277 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
1278 if (r!=ERROR_SUCCESS)
1279 return NULL;
1281 if (dp != REG_CREATED_NEW_KEY)
1283 SetLastError(ERROR_SERVICE_EXISTS);
1284 goto error;
1287 if( lpDisplayName )
1288 service_set_string( &val[n++], szDisplayName, lpDisplayName );
1290 service_set_dword( &val[n++], szType, &dwServiceType );
1291 service_set_dword( &val[n++], szStart, &dwStartType );
1292 service_set_dword( &val[n++], szError, &dwErrorControl );
1294 if( lpBinaryPathName )
1295 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
1297 if( lpLoadOrderGroup )
1298 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
1300 if( lpDependencies )
1301 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
1303 if( lpPassword )
1304 FIXME("Don't know how to add a Password for a service.\n");
1306 if( lpServiceStartName )
1307 service_set_string( &val[n++], szDependOnService, lpServiceStartName );
1309 r = service_write_values( hKey, val, n );
1310 if( r != ERROR_SUCCESS )
1311 goto error;
1313 len = strlenW(lpServiceName)+1;
1314 len = sizeof (struct sc_service) + len*sizeof(WCHAR);
1315 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE, len, sc_handle_destroy_service );
1316 if( !hsvc )
1317 goto error;
1318 lstrcpyW( hsvc->name, lpServiceName );
1319 hsvc->hkey = hKey;
1320 hsvc->scm = hscm;
1321 hscm->hdr.ref_count++;
1323 return (SC_HANDLE) &hsvc->hdr;
1325 error:
1326 RegCloseKey( hKey );
1327 return NULL;
1331 /******************************************************************************
1332 * CreateServiceA [ADVAPI32.@]
1334 SC_HANDLE WINAPI
1335 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1336 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1337 DWORD dwServiceType, DWORD dwStartType,
1338 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1339 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1340 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1341 LPCSTR lpPassword )
1343 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1344 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1345 SC_HANDLE r;
1347 TRACE("%p %s %s\n", hSCManager,
1348 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1350 lpServiceNameW = SERV_dup( lpServiceName );
1351 lpDisplayNameW = SERV_dup( lpDisplayName );
1352 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1353 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1354 lpDependenciesW = SERV_dupmulti( lpDependencies );
1355 lpServiceStartNameW = SERV_dup( lpServiceStartName );
1356 lpPasswordW = SERV_dup( lpPassword );
1358 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1359 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1360 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1361 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1363 SERV_free( lpServiceNameW );
1364 SERV_free( lpDisplayNameW );
1365 SERV_free( lpBinaryPathNameW );
1366 SERV_free( lpLoadOrderGroupW );
1367 SERV_free( lpDependenciesW );
1368 SERV_free( lpServiceStartNameW );
1369 SERV_free( lpPasswordW );
1371 return r;
1375 /******************************************************************************
1376 * DeleteService [ADVAPI32.@]
1378 * Delete a service from the service control manager database.
1380 * PARAMS
1381 * hService [I] Handle of the service to delete
1383 * RETURNS
1384 * Success: TRUE
1385 * Failure: FALSE
1387 BOOL WINAPI DeleteService( SC_HANDLE hService )
1389 struct sc_service *hsvc;
1390 HKEY hKey;
1391 WCHAR valname[MAX_PATH+1];
1392 INT index = 0;
1393 LONG rc;
1394 DWORD size;
1396 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1397 if (!hsvc)
1399 SetLastError( ERROR_INVALID_HANDLE );
1400 return FALSE;
1402 hKey = hsvc->hkey;
1404 size = MAX_PATH+1;
1405 /* Clean out the values */
1406 rc = RegEnumValueW(hKey, index, valname,&size,0,0,0,0);
1407 while (rc == ERROR_SUCCESS)
1409 RegDeleteValueW(hKey,valname);
1410 index++;
1411 size = MAX_PATH+1;
1412 rc = RegEnumValueW(hKey, index, valname, &size,0,0,0,0);
1415 RegCloseKey(hKey);
1416 hsvc->hkey = NULL;
1418 /* delete the key */
1419 RegDeleteKeyW(hsvc->scm->hkey, hsvc->name);
1421 return TRUE;
1425 /******************************************************************************
1426 * StartServiceA [ADVAPI32.@]
1428 * Start a service
1430 * PARAMS
1431 * hService [I] Handle of service
1432 * dwNumServiceArgs [I] Number of arguments
1433 * lpServiceArgVectors [I] Address of array of argument strings
1435 * NOTES
1436 * - NT implements this function using an obscure RPC call.
1437 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1438 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1439 * - This will only work for shared address space. How should the service
1440 * args be transferred when address spaces are separated?
1441 * - Can only start one service at a time.
1442 * - Has no concept of privilege.
1444 * RETURNS
1445 * Success: TRUE.
1446 * Failure: FALSE
1448 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1449 LPCSTR *lpServiceArgVectors )
1451 LPWSTR *lpwstr=NULL;
1452 unsigned int i;
1453 BOOL r;
1455 TRACE("(%p,%d,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1457 if (dwNumServiceArgs)
1458 lpwstr = HeapAlloc( GetProcessHeap(), 0,
1459 dwNumServiceArgs*sizeof(LPWSTR) );
1461 for(i=0; i<dwNumServiceArgs; i++)
1462 lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1464 r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1466 if (dwNumServiceArgs)
1468 for(i=0; i<dwNumServiceArgs; i++)
1469 SERV_free(lpwstr[i]);
1470 HeapFree(GetProcessHeap(), 0, lpwstr);
1473 return r;
1476 /******************************************************************************
1477 * service_start_process [INTERNAL]
1479 static DWORD service_start_process(struct sc_service *hsvc, LPDWORD ppid)
1481 static const WCHAR _ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0};
1482 PROCESS_INFORMATION pi;
1483 STARTUPINFOW si;
1484 LPWSTR path = NULL, str;
1485 DWORD type, size, ret;
1486 HANDLE handles[2];
1487 BOOL r;
1489 /* read the executable path from memory */
1490 size = 0;
1491 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, NULL, &size);
1492 if (ret!=ERROR_SUCCESS)
1493 return FALSE;
1494 str = HeapAlloc(GetProcessHeap(),0,size);
1495 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, (LPBYTE)str, &size);
1496 if (ret==ERROR_SUCCESS)
1498 size = ExpandEnvironmentStringsW(str,NULL,0);
1499 path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
1500 ExpandEnvironmentStringsW(str,path,size);
1502 HeapFree(GetProcessHeap(),0,str);
1503 if (!path)
1504 return FALSE;
1506 /* wait for the process to start and set an event or terminate */
1507 handles[0] = service_get_event_handle( hsvc->name );
1508 ZeroMemory(&si, sizeof(STARTUPINFOW));
1509 si.cb = sizeof(STARTUPINFOW);
1510 r = CreateProcessW(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1511 if (r)
1513 if (ppid) *ppid = pi.dwProcessId;
1515 handles[1] = pi.hProcess;
1516 ret = WaitForMultipleObjectsEx(2, handles, FALSE, 30000, FALSE);
1517 if(ret != WAIT_OBJECT_0)
1519 SetLastError(ERROR_IO_PENDING);
1520 r = FALSE;
1523 CloseHandle( pi.hThread );
1524 CloseHandle( pi.hProcess );
1526 CloseHandle( handles[0] );
1527 HeapFree(GetProcessHeap(),0,path);
1528 return r;
1531 static BOOL service_wait_for_startup(SC_HANDLE hService)
1533 DWORD i;
1534 SERVICE_STATUS status;
1535 BOOL r = FALSE;
1537 TRACE("%p\n", hService);
1539 for (i=0; i<30; i++)
1541 status.dwCurrentState = 0;
1542 r = QueryServiceStatus(hService, &status);
1543 if (!r)
1544 break;
1545 if (status.dwCurrentState == SERVICE_RUNNING)
1547 TRACE("Service started successfully\n");
1548 break;
1550 r = FALSE;
1551 Sleep(1000);
1553 return r;
1556 /******************************************************************************
1557 * StartServiceW [ADVAPI32.@]
1559 * See StartServiceA.
1561 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1562 LPCWSTR *lpServiceArgVectors)
1564 struct sc_service *hsvc;
1565 BOOL r = FALSE;
1566 DWORD dwResult, dwProcessId = 0;
1567 SC_LOCK hLock;
1568 HANDLE handle = INVALID_HANDLE_VALUE;
1570 TRACE("%p %d %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1572 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1573 if (!hsvc)
1575 SetLastError(ERROR_INVALID_HANDLE);
1576 return r;
1579 hLock = LockServiceDatabase((SC_HANDLE)hsvc->scm);
1580 if (!hLock)
1581 return r;
1583 handle = service_open_pipe(hsvc->name);
1584 if (handle==INVALID_HANDLE_VALUE)
1586 /* start the service process */
1587 if (service_start_process(hsvc, &dwProcessId))
1588 handle = service_open_pipe(hsvc->name);
1591 if (handle != INVALID_HANDLE_VALUE)
1593 r = service_send_start_message(handle, lpServiceArgVectors, dwNumServiceArgs);
1594 CloseHandle(handle);
1597 handle = service_open_pipe(hsvc->name);
1598 if (handle != INVALID_HANDLE_VALUE)
1600 service_set_processID(handle, dwProcessId, &dwResult);
1601 CloseHandle(handle);
1604 UnlockServiceDatabase( hLock );
1606 TRACE("returning %d\n", r);
1608 if (r)
1609 service_wait_for_startup(hService);
1611 return r;
1614 /******************************************************************************
1615 * QueryServiceStatus [ADVAPI32.@]
1617 * PARAMS
1618 * hService [I] Handle to service to get information about
1619 * lpservicestatus [O] buffer to receive the status information for the service
1622 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1623 LPSERVICE_STATUS lpservicestatus)
1625 SERVICE_STATUS_PROCESS SvcStatusData;
1626 BOOL ret;
1628 TRACE("%p %p\n", hService, lpservicestatus);
1630 ret = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&SvcStatusData,
1631 sizeof(SERVICE_STATUS_PROCESS), NULL);
1632 if (ret) memcpy(lpservicestatus, &SvcStatusData, sizeof(SERVICE_STATUS)) ;
1633 return ret;
1637 /******************************************************************************
1638 * QueryServiceStatusEx [ADVAPI32.@]
1640 * Get information about a service.
1642 * PARAMS
1643 * hService [I] Handle to service to get information about
1644 * InfoLevel [I] Level of information to get
1645 * lpBuffer [O] Destination for requested information
1646 * cbBufSize [I] Size of lpBuffer in bytes
1647 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1649 * RETURNS
1650 * Success: TRUE
1651 * FAILURE: FALSE
1653 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1654 LPBYTE lpBuffer, DWORD cbBufSize,
1655 LPDWORD pcbBytesNeeded)
1657 struct sc_service *hsvc;
1658 DWORD size, type, val;
1659 HANDLE pipe;
1660 LONG r;
1661 LPSERVICE_STATUS_PROCESS pSvcStatusData;
1663 TRACE("%p %d %p %d %p\n", hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1665 if (InfoLevel != SC_STATUS_PROCESS_INFO)
1667 SetLastError( ERROR_INVALID_LEVEL);
1668 return FALSE;
1671 pSvcStatusData = (LPSERVICE_STATUS_PROCESS) lpBuffer;
1672 if (pSvcStatusData == NULL)
1674 SetLastError( ERROR_INVALID_PARAMETER);
1675 return FALSE;
1678 if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
1680 if( pcbBytesNeeded != NULL)
1681 *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
1683 SetLastError( ERROR_INSUFFICIENT_BUFFER);
1684 return FALSE;
1687 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1688 if (!hsvc)
1690 SetLastError( ERROR_INVALID_HANDLE );
1691 return FALSE;
1694 pipe = service_open_pipe(hsvc->name);
1695 if (pipe != INVALID_HANDLE_VALUE)
1697 r = service_get_status(pipe, pSvcStatusData);
1698 CloseHandle(pipe);
1699 if (r)
1700 return TRUE;
1703 TRACE("Failed to read service status\n");
1705 /* read the service type from the registry */
1706 size = sizeof(val);
1707 r = RegQueryValueExA(hsvc->hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1708 if (r != ERROR_SUCCESS || type != REG_DWORD)
1709 val = 0;
1711 pSvcStatusData->dwServiceType = val;
1712 pSvcStatusData->dwCurrentState = SERVICE_STOPPED; /* stopped */
1713 pSvcStatusData->dwControlsAccepted = 0;
1714 pSvcStatusData->dwWin32ExitCode = ERROR_SERVICE_NEVER_STARTED;
1715 pSvcStatusData->dwServiceSpecificExitCode = 0;
1716 pSvcStatusData->dwCheckPoint = 0;
1717 pSvcStatusData->dwWaitHint = 0;
1719 return TRUE;
1722 /******************************************************************************
1723 * QueryServiceConfigA [ADVAPI32.@]
1725 BOOL WINAPI QueryServiceConfigA( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGA config,
1726 DWORD size, LPDWORD needed )
1728 DWORD n;
1729 LPSTR p, buffer;
1730 BOOL ret;
1731 QUERY_SERVICE_CONFIGW *configW;
1733 TRACE("%p %p %d %p\n", hService, config, size, needed);
1735 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, 2 * size )))
1737 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1738 return FALSE;
1740 configW = (QUERY_SERVICE_CONFIGW *)buffer;
1741 ret = QueryServiceConfigW( hService, configW, 2 * size, needed );
1742 if (!ret) goto done;
1744 config->dwServiceType = configW->dwServiceType;
1745 config->dwStartType = configW->dwStartType;
1746 config->dwErrorControl = configW->dwErrorControl;
1747 config->lpBinaryPathName = NULL;
1748 config->lpLoadOrderGroup = NULL;
1749 config->dwTagId = configW->dwTagId;
1750 config->lpDependencies = NULL;
1751 config->lpServiceStartName = NULL;
1752 config->lpDisplayName = NULL;
1754 p = (LPSTR)(config + 1);
1755 n = size - sizeof(*config);
1756 ret = FALSE;
1758 #define MAP_STR(str) \
1759 do { \
1760 if (configW->str) \
1762 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1763 if (!sz) goto done; \
1764 config->str = p; \
1765 p += sz; \
1766 n -= sz; \
1768 } while (0)
1770 MAP_STR( lpBinaryPathName );
1771 MAP_STR( lpLoadOrderGroup );
1772 MAP_STR( lpDependencies );
1773 MAP_STR( lpServiceStartName );
1774 MAP_STR( lpDisplayName );
1775 #undef MAP_STR
1777 *needed = p - buffer;
1778 ret = TRUE;
1780 done:
1781 HeapFree( GetProcessHeap(), 0, buffer );
1782 return ret;
1785 /******************************************************************************
1786 * QueryServiceConfigW [ADVAPI32.@]
1788 BOOL WINAPI
1789 QueryServiceConfigW( SC_HANDLE hService,
1790 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1791 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1793 WCHAR str_buffer[ MAX_PATH ];
1794 LONG r;
1795 DWORD type, val, sz, total, n;
1796 LPBYTE p;
1797 HKEY hKey;
1798 struct sc_service *hsvc;
1800 TRACE("%p %p %d %p\n", hService, lpServiceConfig,
1801 cbBufSize, pcbBytesNeeded);
1803 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1804 if (!hsvc)
1806 SetLastError( ERROR_INVALID_HANDLE );
1807 return FALSE;
1809 hKey = hsvc->hkey;
1811 /* calculate the size required first */
1812 total = sizeof (QUERY_SERVICE_CONFIGW);
1814 sz = sizeof(str_buffer);
1815 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1816 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1818 sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1819 if( 0 == sz ) return FALSE;
1821 total += sizeof(WCHAR) * sz;
1823 else
1825 /* FIXME: set last error */
1826 return FALSE;
1829 sz = 0;
1830 r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1831 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1832 total += sz;
1834 sz = 0;
1835 r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1836 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1837 total += sz;
1838 else
1839 total += sizeof(WCHAR);
1841 sz = 0;
1842 r = RegQueryValueExW( hKey, szStart, 0, &type, NULL, &sz );
1843 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1844 total += sz;
1846 sz = 0;
1847 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1848 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1849 total += sz;
1851 *pcbBytesNeeded = total;
1853 /* if there's not enough memory, return an error */
1854 if( total > cbBufSize )
1856 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1857 return FALSE;
1860 ZeroMemory( lpServiceConfig, total );
1862 sz = sizeof val;
1863 r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1864 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1865 lpServiceConfig->dwServiceType = val;
1867 sz = sizeof val;
1868 r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1869 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1870 lpServiceConfig->dwStartType = val;
1872 sz = sizeof val;
1873 r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1874 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1875 lpServiceConfig->dwErrorControl = val;
1877 /* now do the strings */
1878 p = (LPBYTE) &lpServiceConfig[1];
1879 n = total - sizeof (QUERY_SERVICE_CONFIGW);
1881 sz = sizeof(str_buffer);
1882 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1883 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1885 sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
1886 sz *= sizeof(WCHAR);
1887 if( 0 == sz || sz > n ) return FALSE;
1889 lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
1890 p += sz;
1891 n -= sz;
1893 else
1895 /* FIXME: set last error */
1896 return FALSE;
1899 sz = n;
1900 r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
1901 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1903 lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
1904 p += sz;
1905 n -= sz;
1908 sz = n;
1909 r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
1910 lpServiceConfig->lpDependencies = (LPWSTR) p;
1911 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1913 p += sz;
1914 n -= sz;
1916 else
1918 *(WCHAR *) p = 0;
1919 p += sizeof(WCHAR);
1920 n -= sizeof(WCHAR);
1923 if( n < 0 )
1924 ERR("Buffer overflow!\n");
1926 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1927 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1929 return TRUE;
1932 /******************************************************************************
1933 * EnumServicesStatusA [ADVAPI32.@]
1935 BOOL WINAPI
1936 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
1937 DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
1938 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1939 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1941 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
1942 dwServiceType, dwServiceState, lpServices, cbBufSize,
1943 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
1944 SetLastError (ERROR_ACCESS_DENIED);
1945 return FALSE;
1948 /******************************************************************************
1949 * EnumServicesStatusW [ADVAPI32.@]
1951 BOOL WINAPI
1952 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
1953 DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
1954 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1955 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1957 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
1958 dwServiceType, dwServiceState, lpServices, cbBufSize,
1959 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
1960 SetLastError (ERROR_ACCESS_DENIED);
1961 return FALSE;
1964 /******************************************************************************
1965 * EnumServicesStatusExA [ADVAPI32.@]
1967 BOOL WINAPI
1968 EnumServicesStatusExA(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
1969 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1970 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCSTR pszGroupName)
1972 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
1973 dwServiceType, dwServiceState, lpServices, cbBufSize,
1974 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_a(pszGroupName));
1975 SetLastError (ERROR_ACCESS_DENIED);
1976 return FALSE;
1979 /******************************************************************************
1980 * EnumServicesStatusExW [ADVAPI32.@]
1982 BOOL WINAPI
1983 EnumServicesStatusExW(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
1984 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1985 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCWSTR pszGroupName)
1987 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
1988 dwServiceType, dwServiceState, lpServices, cbBufSize,
1989 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_w(pszGroupName));
1990 SetLastError (ERROR_ACCESS_DENIED);
1991 return FALSE;
1994 /******************************************************************************
1995 * GetServiceKeyNameA [ADVAPI32.@]
1997 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
1998 LPSTR lpServiceName, LPDWORD lpcchBuffer )
2000 FIXME("%p %s %p %p\n", hSCManager, debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
2001 return FALSE;
2004 /******************************************************************************
2005 * GetServiceKeyNameW [ADVAPI32.@]
2007 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
2008 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
2010 FIXME("%p %s %p %p\n", hSCManager, debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
2011 return FALSE;
2014 /******************************************************************************
2015 * QueryServiceLockStatusA [ADVAPI32.@]
2017 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
2018 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
2019 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2021 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2023 return FALSE;
2026 /******************************************************************************
2027 * QueryServiceLockStatusW [ADVAPI32.@]
2029 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
2030 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2031 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2033 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2035 return FALSE;
2038 /******************************************************************************
2039 * GetServiceDisplayNameA [ADVAPI32.@]
2041 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
2042 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
2044 struct sc_manager *hscm;
2045 DWORD type, size;
2046 LONG ret;
2048 TRACE("%p %s %p %p\n", hSCManager,
2049 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
2051 hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
2052 if (!hscm)
2054 SetLastError(ERROR_INVALID_HANDLE);
2055 return FALSE;
2058 size = *lpcchBuffer;
2059 ret = RegGetValueA(hscm->hkey, lpServiceName, "DisplayName", RRF_RT_REG_SZ, &type, lpDisplayName, &size);
2060 if (ret)
2062 if (lpDisplayName && *lpcchBuffer) *lpDisplayName = 0;
2064 if (ret == ERROR_MORE_DATA)
2066 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2067 *lpcchBuffer = size - 1;
2069 else
2070 SetLastError(ret);
2071 return FALSE;
2073 return TRUE;
2076 /******************************************************************************
2077 * GetServiceDisplayNameW [ADVAPI32.@]
2079 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
2080 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
2082 struct sc_manager *hscm;
2083 DWORD type, size;
2084 LONG ret;
2086 TRACE("%p %s %p %p\n", hSCManager,
2087 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
2089 hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
2090 if (!hscm)
2092 SetLastError(ERROR_INVALID_HANDLE);
2093 return FALSE;
2096 size = *lpcchBuffer * sizeof(WCHAR);
2097 ret = RegGetValueW(hscm->hkey, lpServiceName, szDisplayName, RRF_RT_REG_SZ, &type, lpDisplayName, &size);
2098 if (ret)
2100 if (lpDisplayName && *lpcchBuffer) *lpDisplayName = 0;
2102 if (ret == ERROR_MORE_DATA)
2104 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2105 *lpcchBuffer = (size / sizeof(WCHAR)) - 1;
2107 else
2108 SetLastError(ret);
2109 return FALSE;
2111 return TRUE;
2114 /******************************************************************************
2115 * ChangeServiceConfigW [ADVAPI32.@]
2117 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
2118 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
2119 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
2120 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
2122 struct reg_value val[10];
2123 struct sc_service *hsvc;
2124 DWORD r = ERROR_SUCCESS;
2125 HKEY hKey;
2126 int n = 0;
2128 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2129 hService, dwServiceType, dwStartType, dwErrorControl,
2130 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2131 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2132 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2134 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2135 if (!hsvc)
2137 SetLastError( ERROR_INVALID_HANDLE );
2138 return FALSE;
2140 hKey = hsvc->hkey;
2142 if( dwServiceType != SERVICE_NO_CHANGE )
2143 service_set_dword( &val[n++], szType, &dwServiceType );
2145 if( dwStartType != SERVICE_NO_CHANGE )
2146 service_set_dword( &val[n++], szStart, &dwStartType );
2148 if( dwErrorControl != SERVICE_NO_CHANGE )
2149 service_set_dword( &val[n++], szError, &dwErrorControl );
2151 if( lpBinaryPathName )
2152 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
2154 if( lpLoadOrderGroup )
2155 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
2157 if( lpDependencies )
2158 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
2160 if( lpPassword )
2161 FIXME("ignoring password\n");
2163 if( lpServiceStartName )
2164 service_set_string( &val[n++], szDependOnService, lpServiceStartName );
2166 r = service_write_values( hsvc->hkey, val, n );
2168 return (r == ERROR_SUCCESS) ? TRUE : FALSE ;
2171 /******************************************************************************
2172 * ChangeServiceConfigA [ADVAPI32.@]
2174 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2175 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2176 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2177 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2179 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2180 LPWSTR wServiceStartName, wPassword, wDisplayName;
2181 BOOL r;
2183 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2184 hService, dwServiceType, dwStartType, dwErrorControl,
2185 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2186 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2187 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2189 wBinaryPathName = SERV_dup( lpBinaryPathName );
2190 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2191 wDependencies = SERV_dupmulti( lpDependencies );
2192 wServiceStartName = SERV_dup( lpServiceStartName );
2193 wPassword = SERV_dup( lpPassword );
2194 wDisplayName = SERV_dup( lpDisplayName );
2196 r = ChangeServiceConfigW( hService, dwServiceType,
2197 dwStartType, dwErrorControl, wBinaryPathName,
2198 wLoadOrderGroup, lpdwTagId, wDependencies,
2199 wServiceStartName, wPassword, wDisplayName);
2201 SERV_free( wBinaryPathName );
2202 SERV_free( wLoadOrderGroup );
2203 SERV_free( wDependencies );
2204 SERV_free( wServiceStartName );
2205 SERV_free( wPassword );
2206 SERV_free( wDisplayName );
2208 return r;
2211 /******************************************************************************
2212 * ChangeServiceConfig2A [ADVAPI32.@]
2214 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2215 LPVOID lpInfo)
2217 BOOL r = FALSE;
2219 TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo);
2221 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2223 LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
2224 SERVICE_DESCRIPTIONW sdw;
2226 sdw.lpDescription = SERV_dup( sd->lpDescription );
2228 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2230 SERV_free( sdw.lpDescription );
2232 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2234 LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
2235 SERVICE_FAILURE_ACTIONSW faw;
2237 faw.dwResetPeriod = fa->dwResetPeriod;
2238 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2239 faw.lpCommand = SERV_dup( fa->lpCommand );
2240 faw.cActions = fa->cActions;
2241 faw.lpsaActions = fa->lpsaActions;
2243 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2245 SERV_free( faw.lpRebootMsg );
2246 SERV_free( faw.lpCommand );
2248 else
2249 SetLastError( ERROR_INVALID_PARAMETER );
2251 return r;
2254 /******************************************************************************
2255 * ChangeServiceConfig2W [ADVAPI32.@]
2257 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2258 LPVOID lpInfo)
2260 HKEY hKey;
2261 struct sc_service *hsvc;
2263 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2264 if (!hsvc)
2266 SetLastError( ERROR_INVALID_HANDLE );
2267 return FALSE;
2269 hKey = hsvc->hkey;
2271 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2273 static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2274 LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
2275 if (sd->lpDescription)
2277 TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
2278 if (sd->lpDescription[0] == 0)
2279 RegDeleteValueW(hKey,szDescription);
2280 else
2281 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2282 (LPVOID)sd->lpDescription,
2283 sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2286 else
2287 FIXME("STUB: %p %d %p\n",hService, dwInfoLevel, lpInfo);
2288 return TRUE;
2291 /******************************************************************************
2292 * QueryServiceObjectSecurity [ADVAPI32.@]
2294 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2295 SECURITY_INFORMATION dwSecurityInformation,
2296 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2297 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2299 PACL pACL = NULL;
2301 FIXME("%p %d %p %u %p\n", hService, dwSecurityInformation,
2302 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2304 InitializeSecurityDescriptor(lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
2306 pACL = HeapAlloc( GetProcessHeap(), 0, sizeof(ACL) );
2307 InitializeAcl(pACL, sizeof(ACL), ACL_REVISION);
2308 SetSecurityDescriptorDacl(lpSecurityDescriptor, TRUE, pACL, TRUE);
2309 return TRUE;
2312 /******************************************************************************
2313 * SetServiceObjectSecurity [ADVAPI32.@]
2315 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2316 SECURITY_INFORMATION dwSecurityInformation,
2317 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2319 FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2320 return TRUE;
2323 /******************************************************************************
2324 * SetServiceBits [ADVAPI32.@]
2326 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2327 DWORD dwServiceBits,
2328 BOOL bSetBitsOn,
2329 BOOL bUpdateImmediately)
2331 FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2332 bSetBitsOn, bUpdateImmediately);
2333 return TRUE;
2336 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR lpServiceName,
2337 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2339 FIXME("%s %p %p\n", debugstr_a(lpServiceName), lpHandlerProc, lpContext);
2340 return 0;
2343 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2344 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2346 service_data *service;
2348 TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2350 EnterCriticalSection( &service_cs );
2351 for(service = service_list; service; service = service->next)
2352 if(!strcmpW(lpServiceName, service->name))
2353 break;
2354 if (service)
2356 service->handler.handler_ex = lpHandlerProc;
2357 service->context = lpContext;
2358 service->extended = TRUE;
2360 LeaveCriticalSection( &service_cs );
2362 return (SERVICE_STATUS_HANDLE)service;