Release 0.9.39.
[wine/gsoc-2012-control.git] / dlls / advapi32 / service.c
blob4808db15f18b2da0fa520bcfa979ac9531e1c652
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"
38 #include "wine/list.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(advapi);
42 static const WCHAR szServiceManagerKey[] = { 'S','y','s','t','e','m','\\',
43 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
44 'S','e','r','v','i','c','e','s',0 };
45 static const WCHAR szSCMLock[] = {'A','D','V','A','P','I','_','S','C','M',
46 'L','O','C','K',0};
48 typedef struct service_start_info_t
50 DWORD cmd;
51 DWORD size;
52 WCHAR str[1];
53 } service_start_info;
55 #define WINESERV_STARTINFO 1
56 #define WINESERV_GETSTATUS 2
57 #define WINESERV_SENDCONTROL 3
58 #define WINESERV_SETPID 4
60 typedef struct service_data_t
62 struct list entry;
63 union {
64 LPHANDLER_FUNCTION handler;
65 LPHANDLER_FUNCTION_EX handler_ex;
66 } handler;
67 LPVOID context;
68 SERVICE_STATUS_PROCESS status;
69 HANDLE thread;
70 BOOL unicode : 1;
71 BOOL extended : 1; /* uses handler_ex instead of handler? */
72 union {
73 LPSERVICE_MAIN_FUNCTIONA a;
74 LPSERVICE_MAIN_FUNCTIONW w;
75 } proc;
76 LPWSTR args;
77 WCHAR name[1];
78 } service_data;
80 static CRITICAL_SECTION service_cs;
81 static CRITICAL_SECTION_DEBUG service_cs_debug =
83 0, 0, &service_cs,
84 { &service_cs_debug.ProcessLocksList,
85 &service_cs_debug.ProcessLocksList },
86 0, 0, { (DWORD_PTR)(__FILE__ ": service_cs") }
88 static CRITICAL_SECTION service_cs = { &service_cs_debug, -1, 0, 0, 0, 0 };
90 static struct list service_list = LIST_INIT(service_list);
92 extern HANDLE __wine_make_process_system(void);
94 /******************************************************************************
95 * SC_HANDLEs
98 #define MAX_SERVICE_NAME 256
100 typedef enum { SC_HTYPE_MANAGER, SC_HTYPE_SERVICE } SC_HANDLE_TYPE;
102 struct sc_handle;
103 typedef VOID (*sc_handle_destructor)(struct sc_handle *);
105 struct sc_handle
107 SC_HANDLE_TYPE htype;
108 DWORD ref_count;
109 sc_handle_destructor destroy;
112 struct sc_manager /* service control manager handle */
114 struct sc_handle hdr;
115 HKEY hkey; /* handle to services database in the registry */
116 DWORD dwAccess;
119 struct sc_service /* service handle */
121 struct sc_handle hdr;
122 HKEY hkey; /* handle to service entry in the registry (under hkey) */
123 DWORD dwAccess;
124 struct sc_manager *scm; /* pointer to SCM handle */
125 WCHAR name[1];
128 static void *sc_handle_alloc(SC_HANDLE_TYPE htype, DWORD size,
129 sc_handle_destructor destroy)
131 struct sc_handle *hdr;
133 hdr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
134 if (hdr)
136 hdr->htype = htype;
137 hdr->ref_count = 1;
138 hdr->destroy = destroy;
140 TRACE("sc_handle type=%d -> %p\n", htype, hdr);
141 return hdr;
144 static void *sc_handle_get_handle_data(SC_HANDLE handle, DWORD htype)
146 struct sc_handle *hdr = (struct sc_handle *) handle;
148 if (!hdr)
149 return NULL;
150 if (hdr->htype != htype)
151 return NULL;
152 return hdr;
155 static void sc_handle_free(struct sc_handle* hdr)
157 if (!hdr)
158 return;
159 if (--hdr->ref_count)
160 return;
161 hdr->destroy(hdr);
162 HeapFree(GetProcessHeap(), 0, hdr);
165 static void sc_handle_destroy_manager(struct sc_handle *handle)
167 struct sc_manager *mgr = (struct sc_manager*) handle;
169 TRACE("destroying SC Manager %p\n", mgr);
170 if (mgr->hkey)
171 RegCloseKey(mgr->hkey);
174 static void sc_handle_destroy_service(struct sc_handle *handle)
176 struct sc_service *svc = (struct sc_service*) handle;
178 TRACE("destroying service %p\n", svc);
179 if (svc->hkey)
180 RegCloseKey(svc->hkey);
181 svc->hkey = NULL;
182 sc_handle_free(&svc->scm->hdr);
183 svc->scm = NULL;
186 /******************************************************************************
187 * String management functions
189 static inline LPWSTR SERV_dup( LPCSTR str )
191 UINT len;
192 LPWSTR wstr;
194 if( !str )
195 return NULL;
196 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
197 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
198 MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
199 return wstr;
202 static inline LPWSTR SERV_dupmulti(LPCSTR str)
204 UINT len = 0, n = 0;
205 LPWSTR wstr;
207 if( !str )
208 return NULL;
209 do {
210 len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
211 n += (strlen( &str[n] ) + 1);
212 } while (str[n]);
213 len++;
214 n++;
216 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
217 MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
218 return wstr;
221 static inline VOID SERV_free( LPWSTR wstr )
223 HeapFree( GetProcessHeap(), 0, wstr );
226 /******************************************************************************
227 * registry access functions and data
229 static const WCHAR szDisplayName[] = {
230 'D','i','s','p','l','a','y','N','a','m','e', 0 };
231 static const WCHAR szType[] = {'T','y','p','e',0};
232 static const WCHAR szStart[] = {'S','t','a','r','t',0};
233 static const WCHAR szError[] = {
234 'E','r','r','o','r','C','o','n','t','r','o','l', 0};
235 static const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
236 static const WCHAR szGroup[] = {'G','r','o','u','p',0};
237 static const WCHAR szDependencies[] = {
238 'D','e','p','e','n','d','e','n','c','i','e','s',0};
239 static const WCHAR szDependOnService[] = {
240 'D','e','p','e','n','d','O','n','S','e','r','v','i','c','e',0};
242 struct reg_value {
243 DWORD type;
244 DWORD size;
245 LPCWSTR name;
246 LPCVOID data;
249 static inline void service_set_value( struct reg_value *val,
250 DWORD type, LPCWSTR name, LPCVOID data, DWORD size )
252 val->name = name;
253 val->type = type;
254 val->data = data;
255 val->size = size;
258 static inline void service_set_dword( struct reg_value *val,
259 LPCWSTR name, const DWORD *data )
261 service_set_value( val, REG_DWORD, name, data, sizeof (DWORD));
264 static inline void service_set_string( struct reg_value *val,
265 LPCWSTR name, LPCWSTR string )
267 DWORD len = (lstrlenW(string)+1) * sizeof (WCHAR);
268 service_set_value( val, REG_SZ, name, string, len );
271 static inline void service_set_multi_string( struct reg_value *val,
272 LPCWSTR name, LPCWSTR string )
274 DWORD len = 0;
276 /* determine the length of a double null terminated multi string */
277 do {
278 len += (lstrlenW( &string[ len ] )+1);
279 } while ( string[ len++ ] );
281 len *= sizeof (WCHAR);
282 service_set_value( val, REG_MULTI_SZ, name, string, len );
285 static inline LONG service_write_values( HKEY hKey,
286 const struct reg_value *val, int n )
288 LONG r = ERROR_SUCCESS;
289 int i;
291 for( i=0; i<n; i++ )
293 r = RegSetValueExW(hKey, val[i].name, 0, val[i].type,
294 (const BYTE*)val[i].data, val[i].size );
295 if( r != ERROR_SUCCESS )
296 break;
298 return r;
301 /******************************************************************************
302 * Service IPC functions
304 static LPWSTR service_get_pipe_name(LPCWSTR service)
306 static const WCHAR prefix[] = { '\\','\\','.','\\','p','i','p','e','\\',
307 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
308 LPWSTR name;
309 DWORD len;
311 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
312 name = HeapAlloc(GetProcessHeap(), 0, len);
313 strcpyW(name, prefix);
314 strcatW(name, service);
315 return name;
318 static HANDLE service_open_pipe(LPCWSTR service)
320 LPWSTR szPipe = service_get_pipe_name( service );
321 HANDLE handle = INVALID_HANDLE_VALUE;
323 do {
324 handle = CreateFileW(szPipe, GENERIC_READ|GENERIC_WRITE,
325 0, NULL, OPEN_ALWAYS, 0, NULL);
326 if (handle != INVALID_HANDLE_VALUE)
327 break;
328 if (GetLastError() != ERROR_PIPE_BUSY)
329 break;
330 } while (WaitNamedPipeW(szPipe, NMPWAIT_WAIT_FOREVER));
331 SERV_free(szPipe);
333 return handle;
336 /******************************************************************************
337 * service_get_event_handle
339 static HANDLE service_get_event_handle(LPCWSTR service)
341 static const WCHAR prefix[] = {
342 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
343 LPWSTR name;
344 DWORD len;
345 HANDLE handle;
347 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
348 name = HeapAlloc(GetProcessHeap(), 0, len);
349 strcpyW(name, prefix);
350 strcatW(name, service);
351 handle = CreateEventW(NULL, TRUE, FALSE, name);
352 SERV_free(name);
353 return handle;
356 /******************************************************************************
357 * service_thread
359 * Call into the main service routine provided by StartServiceCtrlDispatcher.
361 static DWORD WINAPI service_thread(LPVOID arg)
363 service_data *info = arg;
364 LPWSTR str = info->args;
365 DWORD argc = 0, len = 0;
367 TRACE("%p\n", arg);
369 while (str[len])
371 len += strlenW(&str[len]) + 1;
372 argc++;
375 if (!argc)
377 if (info->unicode)
378 info->proc.w(0, NULL);
379 else
380 info->proc.a(0, NULL);
381 return 0;
384 if (info->unicode)
386 LPWSTR *argv, p;
388 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPWSTR));
389 for (argc=0, p=str; *p; p += strlenW(p) + 1)
390 argv[argc++] = p;
391 argv[argc] = NULL;
393 info->proc.w(argc, argv);
394 HeapFree(GetProcessHeap(), 0, argv);
396 else
398 LPSTR strA, *argv, p;
399 DWORD lenA;
401 lenA = WideCharToMultiByte(CP_ACP,0, str, len, NULL, 0, NULL, NULL);
402 strA = HeapAlloc(GetProcessHeap(), 0, lenA);
403 WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL);
405 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPSTR));
406 for (argc=0, p=strA; *p; p += strlen(p) + 1)
407 argv[argc++] = p;
408 argv[argc] = NULL;
410 info->proc.a(argc, argv);
411 HeapFree(GetProcessHeap(), 0, argv);
412 HeapFree(GetProcessHeap(), 0, strA);
414 return 0;
417 /******************************************************************************
418 * service_handle_start
420 static BOOL service_handle_start(HANDLE pipe, service_data *service, DWORD count)
422 DWORD read = 0, result = 0;
423 LPWSTR args;
424 BOOL r;
426 TRACE("%p %p %d\n", pipe, service, count);
428 args = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
429 r = ReadFile(pipe, args, count*sizeof(WCHAR), &read, NULL);
430 if (!r || count!=read/sizeof(WCHAR) || args[count-1])
432 ERR("pipe read failed r = %d count = %d read = %d args[n-1]=%s\n",
433 r, count, read, debugstr_wn(args, count));
434 goto end;
437 if (service->thread)
439 ERR("service is not stopped\n");
440 goto end;
443 SERV_free(service->args);
444 service->args = args;
445 args = NULL;
446 service->thread = CreateThread( NULL, 0, service_thread,
447 service, 0, NULL );
449 end:
450 HeapFree(GetProcessHeap(), 0, args);
451 WriteFile( pipe, &result, sizeof result, &read, NULL );
453 return TRUE;
456 /******************************************************************************
457 * service_send_start_message
459 static BOOL service_send_start_message(HANDLE pipe, LPCWSTR *argv, DWORD argc)
461 DWORD i, len, count, result;
462 service_start_info *ssi;
463 LPWSTR p;
464 BOOL r;
466 TRACE("%p %p %d\n", pipe, argv, argc);
468 /* calculate how much space do we need to send the startup info */
469 len = 1;
470 for (i=0; i<argc; i++)
471 len += strlenW(argv[i])+1;
473 ssi = HeapAlloc(GetProcessHeap(),0,sizeof *ssi + (len-1)*sizeof(WCHAR));
474 ssi->cmd = WINESERV_STARTINFO;
475 ssi->size = len;
477 /* copy service args into a single buffer*/
478 p = &ssi->str[0];
479 for (i=0; i<argc; i++)
481 strcpyW(p, argv[i]);
482 p += strlenW(p) + 1;
484 *p=0;
486 r = WriteFile(pipe, ssi, sizeof *ssi + len*sizeof(WCHAR), &count, NULL);
487 if (r)
488 r = ReadFile(pipe, &result, sizeof result, &count, NULL);
490 HeapFree(GetProcessHeap(),0,ssi);
492 return r;
495 /******************************************************************************
496 * service_handle_get_status
498 static BOOL service_handle_get_status(HANDLE pipe, const service_data *service)
500 DWORD count = 0;
501 TRACE("\n");
502 return WriteFile(pipe, &service->status,
503 sizeof service->status, &count, NULL);
506 /******************************************************************************
507 * service_get_status
509 static BOOL service_get_status(HANDLE pipe, LPSERVICE_STATUS_PROCESS status)
511 DWORD cmd[2], count = 0;
512 BOOL r;
514 cmd[0] = WINESERV_GETSTATUS;
515 cmd[1] = 0;
516 r = WriteFile( pipe, cmd, sizeof cmd, &count, NULL );
517 if (!r || count != sizeof cmd)
519 ERR("service protocol error - failed to write pipe!\n");
520 return r;
522 r = ReadFile( pipe, status, sizeof *status, &count, NULL );
523 if (!r || count != sizeof *status)
524 ERR("service protocol error - failed to read pipe "
525 "r = %d count = %d!\n", r, count);
526 return r;
529 /******************************************************************************
530 * service_handle_set_processID
532 static BOOL service_handle_set_processID(HANDLE pipe, service_data *service, DWORD dwProcessId)
534 DWORD count, ret = ERROR_SUCCESS;
536 TRACE("received control %d\n", dwProcessId);
537 service->status.dwProcessId = dwProcessId;
538 return WriteFile(pipe, &ret, sizeof ret , &count, NULL);
541 /******************************************************************************
542 * service_set_processID
544 static BOOL service_set_processID(HANDLE pipe, DWORD dwprocessId, LPDWORD dwResult)
546 DWORD cmd[2], count = 0;
547 BOOL r;
549 cmd[0] = WINESERV_SETPID;
550 cmd[1] = dwprocessId;
551 r = WriteFile( pipe, cmd, sizeof cmd, &count, NULL );
552 if (!r || count != sizeof cmd)
554 ERR("service protocol error - failed to write pipe!\n");
555 return r;
557 r = ReadFile( pipe, dwResult, sizeof *dwResult, &count, NULL );
558 if (!r || count != sizeof *dwResult)
559 ERR("service protocol error - failed to read pipe "
560 "r = %d count = %d!\n", r, count);
561 return r;
564 /******************************************************************************
565 * service_send_control
567 static BOOL service_send_control(HANDLE pipe, DWORD dwControl, DWORD *result)
569 DWORD cmd[2], count = 0;
570 BOOL r;
572 cmd[0] = WINESERV_SENDCONTROL;
573 cmd[1] = dwControl;
574 r = WriteFile(pipe, cmd, sizeof cmd, &count, NULL);
575 if (!r || count != sizeof cmd)
577 ERR("service protocol error - failed to write pipe!\n");
578 return r;
580 r = ReadFile(pipe, result, sizeof *result, &count, NULL);
581 if (!r || count != sizeof *result)
582 ERR("service protocol error - failed to read pipe "
583 "r = %d count = %d!\n", r, count);
584 return r;
587 /******************************************************************************
588 * service_accepts_control
590 static BOOL service_accepts_control(const service_data *service, DWORD dwControl)
592 DWORD a = service->status.dwControlsAccepted;
594 switch (dwControl)
596 case SERVICE_CONTROL_INTERROGATE:
597 return TRUE;
598 case SERVICE_CONTROL_STOP:
599 if (a&SERVICE_ACCEPT_STOP)
600 return TRUE;
601 break;
602 case SERVICE_CONTROL_SHUTDOWN:
603 if (a&SERVICE_ACCEPT_SHUTDOWN)
604 return TRUE;
605 break;
606 case SERVICE_CONTROL_PAUSE:
607 case SERVICE_CONTROL_CONTINUE:
608 if (a&SERVICE_ACCEPT_PAUSE_CONTINUE)
609 return TRUE;
610 break;
611 case SERVICE_CONTROL_PARAMCHANGE:
612 if (a&SERVICE_ACCEPT_PARAMCHANGE)
613 return TRUE;
614 break;
615 case SERVICE_CONTROL_NETBINDADD:
616 case SERVICE_CONTROL_NETBINDREMOVE:
617 case SERVICE_CONTROL_NETBINDENABLE:
618 case SERVICE_CONTROL_NETBINDDISABLE:
619 if (a&SERVICE_ACCEPT_NETBINDCHANGE)
620 return TRUE;
622 if (!service->extended)
623 return FALSE;
624 switch (dwControl)
626 case SERVICE_CONTROL_HARDWAREPROFILECHANGE:
627 if (a&SERVICE_ACCEPT_HARDWAREPROFILECHANGE)
628 return TRUE;
629 break;
630 case SERVICE_CONTROL_POWEREVENT:
631 if (a&SERVICE_ACCEPT_POWEREVENT)
632 return TRUE;
633 break;
634 case SERVICE_CONTROL_SESSIONCHANGE:
635 if (a&SERVICE_ACCEPT_SESSIONCHANGE)
636 return TRUE;
637 break;
639 return FALSE;
642 /******************************************************************************
643 * service_handle_control
645 static BOOL service_handle_control(HANDLE pipe, service_data *service,
646 DWORD dwControl)
648 DWORD count, ret = ERROR_INVALID_SERVICE_CONTROL;
650 TRACE("received control %d\n", dwControl);
652 if (service_accepts_control(service, dwControl))
654 if (service->extended && service->handler.handler_ex)
656 service->handler.handler_ex(dwControl, 0, NULL, service->context);
657 ret = ERROR_SUCCESS;
659 else if (service->handler.handler)
661 service->handler.handler(dwControl);
662 ret = ERROR_SUCCESS;
665 return WriteFile(pipe, &ret, sizeof ret, &count, NULL);
668 /******************************************************************************
669 * service_reap_thread
671 static DWORD service_reap_thread(service_data *service)
673 DWORD exitcode = 0;
675 if (!service->thread)
676 return 0;
677 GetExitCodeThread(service->thread, &exitcode);
678 if (exitcode!=STILL_ACTIVE)
680 CloseHandle(service->thread);
681 service->thread = 0;
683 return exitcode;
686 /******************************************************************************
687 * service_control_dispatcher
689 static DWORD WINAPI service_control_dispatcher(LPVOID arg)
691 service_data *service = arg;
692 LPWSTR name;
693 HANDLE pipe, event;
695 TRACE("%p %s\n", service, debugstr_w(service->name));
697 /* create a pipe to talk to the rest of the world with */
698 name = service_get_pipe_name(service->name);
699 pipe = CreateNamedPipeW(name, PIPE_ACCESS_DUPLEX,
700 PIPE_TYPE_BYTE|PIPE_WAIT, 1, 256, 256, 10000, NULL );
701 SERV_free(name);
703 /* let the process who started us know we've tried to create a pipe */
704 event = service_get_event_handle(service->name);
705 SetEvent(event);
706 CloseHandle(event);
708 if (pipe==INVALID_HANDLE_VALUE)
710 ERR("failed to create pipe for %s, error = %d\n",
711 debugstr_w(service->name), GetLastError());
712 return 0;
715 /* dispatcher loop */
716 while (1)
718 BOOL r;
719 DWORD count, req[2] = {0,0};
721 r = ConnectNamedPipe(pipe, NULL);
722 if (!r && GetLastError() != ERROR_PIPE_CONNECTED)
724 ERR("pipe connect failed\n");
725 break;
728 r = ReadFile( pipe, &req, sizeof req, &count, NULL );
729 if (!r || count!=sizeof req)
731 ERR("pipe read failed\n");
732 break;
735 service_reap_thread(service);
737 /* handle the request */
738 switch (req[0])
740 case WINESERV_STARTINFO:
741 service_handle_start(pipe, service, req[1]);
742 break;
743 case WINESERV_GETSTATUS:
744 service_handle_get_status(pipe, service);
745 break;
746 case WINESERV_SENDCONTROL:
747 service_handle_control(pipe, service, req[1]);
748 break;
749 case WINESERV_SETPID:
750 service_handle_set_processID(pipe, service, req[1]);
751 break;
752 default:
753 ERR("received invalid command %d length %d\n", req[0], req[1]);
756 FlushFileBuffers(pipe);
757 DisconnectNamedPipe(pipe);
760 CloseHandle(pipe);
761 return 1;
764 /******************************************************************************
765 * service_run_threads
767 static BOOL service_run_threads(void)
769 service_data *service;
770 DWORD count, n = 0;
771 HANDLE *handles;
773 EnterCriticalSection( &service_cs );
775 count = list_count( &service_list );
777 TRACE("starting %d pipe listener threads\n", count);
779 handles = HeapAlloc(GetProcessHeap(), 0, sizeof(HANDLE) * (count + 1));
781 handles[n++] = __wine_make_process_system();
783 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
784 handles[n++] = CreateThread( NULL, 0, service_control_dispatcher,
785 service, 0, NULL );
786 assert(n == count + 1);
788 LeaveCriticalSection( &service_cs );
790 /* wait for all the threads to pack up and exit */
791 while (n > 1)
793 DWORD ret = WaitForMultipleObjects( min(n,MAXIMUM_WAIT_OBJECTS), handles, FALSE, INFINITE );
794 if (!ret) /* system process event */
796 TRACE( "last user process exited, shutting down\n" );
797 /* FIXME: we should maybe send a shutdown control to running services */
798 ExitProcess(0);
800 if (ret < MAXIMUM_WAIT_OBJECTS)
802 CloseHandle( handles[ret] );
803 memmove( &handles[ret], &handles[ret+1], (n - ret - 1) * sizeof(HANDLE) );
804 n--;
806 else break;
809 while (n) CloseHandle( handles[--n] );
810 HeapFree(GetProcessHeap(), 0, handles);
812 return TRUE;
815 /******************************************************************************
816 * StartServiceCtrlDispatcherA [ADVAPI32.@]
818 * See StartServiceCtrlDispatcherW.
820 BOOL WINAPI StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *servent )
822 service_data *info;
823 DWORD sz, len;
824 BOOL ret = TRUE;
826 TRACE("%p\n", servent);
828 EnterCriticalSection( &service_cs );
829 while (servent->lpServiceName)
831 LPSTR name = servent->lpServiceName;
833 len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0);
834 sz = len*sizeof(WCHAR) + sizeof *info;
835 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
836 MultiByteToWideChar(CP_ACP, 0, name, -1, info->name, len);
837 info->proc.a = servent->lpServiceProc;
838 info->unicode = FALSE;
839 list_add_head( &service_list, &info->entry );
840 servent++;
842 LeaveCriticalSection( &service_cs );
844 service_run_threads();
846 return ret;
849 /******************************************************************************
850 * StartServiceCtrlDispatcherW [ADVAPI32.@]
852 * Connects a process containing one or more services to the service control
853 * manager.
855 * PARAMS
856 * servent [I] A list of the service names and service procedures
858 * RETURNS
859 * Success: TRUE.
860 * Failure: FALSE.
862 BOOL WINAPI StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW *servent )
864 service_data *info;
865 DWORD sz, len;
866 BOOL ret = TRUE;
868 TRACE("%p\n", servent);
870 EnterCriticalSection( &service_cs );
871 while (servent->lpServiceName)
873 LPWSTR name = servent->lpServiceName;
875 len = strlenW(name);
876 sz = len*sizeof(WCHAR) + sizeof *info;
877 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
878 strcpyW(info->name, name);
879 info->proc.w = servent->lpServiceProc;
880 info->unicode = TRUE;
881 list_add_head( &service_list, &info->entry );
882 servent++;
884 LeaveCriticalSection( &service_cs );
886 service_run_threads();
888 return ret;
891 /******************************************************************************
892 * LockServiceDatabase [ADVAPI32.@]
894 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
896 HANDLE ret;
898 TRACE("%p\n",hSCManager);
900 ret = CreateSemaphoreW( NULL, 1, 1, szSCMLock );
901 if( ret && GetLastError() == ERROR_ALREADY_EXISTS )
903 CloseHandle( ret );
904 ret = NULL;
905 SetLastError( ERROR_SERVICE_DATABASE_LOCKED );
908 TRACE("returning %p\n", ret);
910 return ret;
913 /******************************************************************************
914 * UnlockServiceDatabase [ADVAPI32.@]
916 BOOL WINAPI UnlockServiceDatabase (SC_LOCK ScLock)
918 TRACE("%p\n",ScLock);
920 return CloseHandle( ScLock );
923 /******************************************************************************
924 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
926 SERVICE_STATUS_HANDLE WINAPI
927 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName, LPHANDLER_FUNCTION lpfHandler )
929 LPWSTR lpServiceNameW;
930 SERVICE_STATUS_HANDLE ret;
932 lpServiceNameW = SERV_dup(lpServiceName);
933 ret = RegisterServiceCtrlHandlerW( lpServiceNameW, lpfHandler );
934 SERV_free(lpServiceNameW);
935 return ret;
938 /******************************************************************************
939 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
941 * PARAMS
942 * lpServiceName []
943 * lpfHandler []
945 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName,
946 LPHANDLER_FUNCTION lpfHandler )
948 service_data *service;
949 SERVICE_STATUS_HANDLE handle = 0;
951 EnterCriticalSection( &service_cs );
952 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
954 if(!strcmpW(lpServiceName, service->name))
956 service->handler.handler = lpfHandler;
957 handle = (SERVICE_STATUS_HANDLE)service;
958 break;
961 LeaveCriticalSection( &service_cs );
962 return handle;
965 /******************************************************************************
966 * SetServiceStatus [ADVAPI32.@]
968 * PARAMS
969 * hService []
970 * lpStatus []
972 BOOL WINAPI
973 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
975 service_data *service;
976 BOOL r = FALSE;
978 TRACE("%p %x %x %x %x %x %x %x\n", hService,
979 lpStatus->dwServiceType, lpStatus->dwCurrentState,
980 lpStatus->dwControlsAccepted, lpStatus->dwWin32ExitCode,
981 lpStatus->dwServiceSpecificExitCode, lpStatus->dwCheckPoint,
982 lpStatus->dwWaitHint);
984 EnterCriticalSection( &service_cs );
985 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
987 if(service == (service_data*)hService)
989 memcpy( &service->status, lpStatus, sizeof(SERVICE_STATUS) );
990 TRACE("Set service status to %d\n",service->status.dwCurrentState);
991 r = TRUE;
992 break;
995 LeaveCriticalSection( &service_cs );
997 return r;
1001 /******************************************************************************
1002 * OpenSCManagerA [ADVAPI32.@]
1004 * Establish a connection to the service control manager and open its database.
1006 * PARAMS
1007 * lpMachineName [I] Pointer to machine name string
1008 * lpDatabaseName [I] Pointer to database name string
1009 * dwDesiredAccess [I] Type of access
1011 * RETURNS
1012 * Success: A Handle to the service control manager database
1013 * Failure: NULL
1015 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
1016 DWORD dwDesiredAccess )
1018 LPWSTR lpMachineNameW, lpDatabaseNameW;
1019 SC_HANDLE ret;
1021 lpMachineNameW = SERV_dup(lpMachineName);
1022 lpDatabaseNameW = SERV_dup(lpDatabaseName);
1023 ret = OpenSCManagerW(lpMachineNameW, lpDatabaseNameW, dwDesiredAccess);
1024 SERV_free(lpDatabaseNameW);
1025 SERV_free(lpMachineNameW);
1026 return ret;
1029 /******************************************************************************
1030 * OpenSCManagerW [ADVAPI32.@]
1032 * See OpenSCManagerA.
1034 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
1035 DWORD dwDesiredAccess )
1037 struct sc_manager *manager;
1038 HKEY hReg;
1039 LONG r;
1041 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName),
1042 debugstr_w(lpDatabaseName), dwDesiredAccess);
1044 if( lpDatabaseName && lpDatabaseName[0] )
1046 if( strcmpiW( lpDatabaseName, SERVICES_ACTIVE_DATABASEW ) == 0 )
1048 /* noop, all right */
1050 else if( strcmpiW( lpDatabaseName, SERVICES_FAILED_DATABASEW ) == 0 )
1052 SetLastError( ERROR_DATABASE_DOES_NOT_EXIST );
1053 return NULL;
1055 else
1057 SetLastError( ERROR_INVALID_NAME );
1058 return NULL;
1062 manager = sc_handle_alloc( SC_HTYPE_MANAGER, sizeof (struct sc_manager),
1063 sc_handle_destroy_manager );
1064 if (!manager)
1065 return NULL;
1067 r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
1068 if (r!=ERROR_SUCCESS)
1069 goto error;
1071 r = RegCreateKeyW(hReg, szServiceManagerKey, &manager->hkey);
1072 RegCloseKey( hReg );
1073 if (r!=ERROR_SUCCESS)
1074 goto error;
1076 manager->dwAccess = dwDesiredAccess;
1077 TRACE("returning %p\n", manager);
1079 return (SC_HANDLE) &manager->hdr;
1081 error:
1082 sc_handle_free( &manager->hdr );
1083 SetLastError( r);
1084 return NULL;
1087 /******************************************************************************
1088 * ControlService [ADVAPI32.@]
1090 * Send a control code to a service.
1092 * PARAMS
1093 * hService [I] Handle of the service control manager database
1094 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
1095 * lpServiceStatus [O] Destination for the status of the service, if available
1097 * RETURNS
1098 * Success: TRUE.
1099 * Failure: FALSE.
1101 * BUGS
1102 * Unlike M$' implementation, control requests are not serialized and may be
1103 * processed asynchronously.
1105 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
1106 LPSERVICE_STATUS lpServiceStatus )
1108 struct sc_service *hsvc;
1109 BOOL ret = FALSE;
1110 HANDLE handle;
1112 TRACE("%p %d %p\n", hService, dwControl, lpServiceStatus);
1114 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1115 if (!hsvc)
1117 SetLastError( ERROR_INVALID_HANDLE );
1118 return FALSE;
1121 ret = QueryServiceStatus(hService, lpServiceStatus);
1122 if (!ret)
1124 ERR("failed to query service status\n");
1125 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1126 return FALSE;
1129 switch (lpServiceStatus->dwCurrentState)
1131 case SERVICE_STOPPED:
1132 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1133 return FALSE;
1134 case SERVICE_START_PENDING:
1135 if (dwControl==SERVICE_CONTROL_STOP)
1136 break;
1137 /* fall thru */
1138 case SERVICE_STOP_PENDING:
1139 SetLastError(ERROR_SERVICE_CANNOT_ACCEPT_CTRL);
1140 return FALSE;
1143 handle = service_open_pipe(hsvc->name);
1144 if (handle!=INVALID_HANDLE_VALUE)
1146 DWORD result = ERROR_SUCCESS;
1147 ret = service_send_control(handle, dwControl, &result);
1148 CloseHandle(handle);
1149 if (result!=ERROR_SUCCESS)
1151 SetLastError(result);
1152 ret = FALSE;
1156 return ret;
1159 /******************************************************************************
1160 * CloseServiceHandle [ADVAPI32.@]
1162 * Close a handle to a service or the service control manager database.
1164 * PARAMS
1165 * hSCObject [I] Handle to service or service control manager database
1167 * RETURNS
1168 * Success: TRUE
1169 * Failure: FALSE
1171 BOOL WINAPI
1172 CloseServiceHandle( SC_HANDLE hSCObject )
1174 TRACE("%p\n", hSCObject);
1176 sc_handle_free( (struct sc_handle*) hSCObject );
1178 return TRUE;
1182 /******************************************************************************
1183 * OpenServiceA [ADVAPI32.@]
1185 * Open a handle to a service.
1187 * PARAMS
1188 * hSCManager [I] Handle of the service control manager database
1189 * lpServiceName [I] Name of the service to open
1190 * dwDesiredAccess [I] Access required to the service
1192 * RETURNS
1193 * Success: Handle to the service
1194 * Failure: NULL
1196 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1197 DWORD dwDesiredAccess )
1199 LPWSTR lpServiceNameW;
1200 SC_HANDLE ret;
1202 TRACE("%p %s %d\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
1204 lpServiceNameW = SERV_dup(lpServiceName);
1205 ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
1206 SERV_free(lpServiceNameW);
1207 return ret;
1211 /******************************************************************************
1212 * OpenServiceW [ADVAPI32.@]
1214 * See OpenServiceA.
1216 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1217 DWORD dwDesiredAccess)
1219 struct sc_manager *hscm;
1220 struct sc_service *hsvc;
1221 HKEY hKey;
1222 long r;
1223 DWORD len;
1225 TRACE("%p %s %d\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
1227 if (!lpServiceName)
1229 SetLastError(ERROR_INVALID_ADDRESS);
1230 return NULL;
1233 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1234 if (!hscm)
1236 SetLastError( ERROR_INVALID_HANDLE );
1237 return FALSE;
1240 r = RegOpenKeyExW( hscm->hkey, lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
1241 if (r!=ERROR_SUCCESS)
1243 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
1244 return NULL;
1247 len = strlenW(lpServiceName)+1;
1248 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE,
1249 sizeof (struct sc_service) + len*sizeof(WCHAR),
1250 sc_handle_destroy_service );
1251 if (!hsvc)
1252 return NULL;
1253 strcpyW( hsvc->name, lpServiceName );
1254 hsvc->hkey = hKey;
1255 hsvc->dwAccess = dwDesiredAccess;
1257 /* add reference to SCM handle */
1258 hscm->hdr.ref_count++;
1259 hsvc->scm = hscm;
1261 TRACE("returning %p\n",hsvc);
1263 return (SC_HANDLE) &hsvc->hdr;
1266 /******************************************************************************
1267 * CreateServiceW [ADVAPI32.@]
1269 SC_HANDLE WINAPI
1270 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1271 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
1272 DWORD dwServiceType, DWORD dwStartType,
1273 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1274 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1275 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
1276 LPCWSTR lpPassword )
1278 struct sc_manager *hscm;
1279 struct sc_service *hsvc = NULL;
1280 HKEY hKey;
1281 LONG r;
1282 DWORD dp, len;
1283 struct reg_value val[10];
1284 int n = 0;
1286 TRACE("%p %s %s\n", hSCManager,
1287 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
1289 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1290 if (!hscm)
1292 SetLastError( ERROR_INVALID_HANDLE );
1293 return NULL;
1296 r = RegCreateKeyExW(hscm->hkey, lpServiceName, 0, NULL,
1297 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
1298 if (r!=ERROR_SUCCESS)
1299 return NULL;
1301 if (dp != REG_CREATED_NEW_KEY)
1303 SetLastError(ERROR_SERVICE_EXISTS);
1304 goto error;
1307 if( lpDisplayName )
1308 service_set_string( &val[n++], szDisplayName, lpDisplayName );
1310 service_set_dword( &val[n++], szType, &dwServiceType );
1311 service_set_dword( &val[n++], szStart, &dwStartType );
1312 service_set_dword( &val[n++], szError, &dwErrorControl );
1314 if( lpBinaryPathName )
1315 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
1317 if( lpLoadOrderGroup )
1318 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
1320 if( lpDependencies )
1321 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
1323 if( lpPassword )
1324 FIXME("Don't know how to add a Password for a service.\n");
1326 if( lpServiceStartName )
1327 service_set_string( &val[n++], szDependOnService, lpServiceStartName );
1329 r = service_write_values( hKey, val, n );
1330 if( r != ERROR_SUCCESS )
1331 goto error;
1333 len = strlenW(lpServiceName)+1;
1334 len = sizeof (struct sc_service) + len*sizeof(WCHAR);
1335 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE, len, sc_handle_destroy_service );
1336 if( !hsvc )
1337 goto error;
1338 lstrcpyW( hsvc->name, lpServiceName );
1339 hsvc->hkey = hKey;
1340 hsvc->scm = hscm;
1341 hscm->hdr.ref_count++;
1343 return (SC_HANDLE) &hsvc->hdr;
1345 error:
1346 RegCloseKey( hKey );
1347 return NULL;
1351 /******************************************************************************
1352 * CreateServiceA [ADVAPI32.@]
1354 SC_HANDLE WINAPI
1355 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1356 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1357 DWORD dwServiceType, DWORD dwStartType,
1358 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1359 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1360 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1361 LPCSTR lpPassword )
1363 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1364 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1365 SC_HANDLE r;
1367 TRACE("%p %s %s\n", hSCManager,
1368 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1370 lpServiceNameW = SERV_dup( lpServiceName );
1371 lpDisplayNameW = SERV_dup( lpDisplayName );
1372 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1373 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1374 lpDependenciesW = SERV_dupmulti( lpDependencies );
1375 lpServiceStartNameW = SERV_dup( lpServiceStartName );
1376 lpPasswordW = SERV_dup( lpPassword );
1378 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1379 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1380 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1381 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1383 SERV_free( lpServiceNameW );
1384 SERV_free( lpDisplayNameW );
1385 SERV_free( lpBinaryPathNameW );
1386 SERV_free( lpLoadOrderGroupW );
1387 SERV_free( lpDependenciesW );
1388 SERV_free( lpServiceStartNameW );
1389 SERV_free( lpPasswordW );
1391 return r;
1395 /******************************************************************************
1396 * DeleteService [ADVAPI32.@]
1398 * Delete a service from the service control manager database.
1400 * PARAMS
1401 * hService [I] Handle of the service to delete
1403 * RETURNS
1404 * Success: TRUE
1405 * Failure: FALSE
1407 BOOL WINAPI DeleteService( SC_HANDLE hService )
1409 struct sc_service *hsvc;
1410 HKEY hKey;
1411 WCHAR valname[MAX_PATH+1];
1412 INT index = 0;
1413 LONG rc;
1414 DWORD size;
1416 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1417 if (!hsvc)
1419 SetLastError( ERROR_INVALID_HANDLE );
1420 return FALSE;
1422 hKey = hsvc->hkey;
1424 size = MAX_PATH+1;
1425 /* Clean out the values */
1426 rc = RegEnumValueW(hKey, index, valname,&size,0,0,0,0);
1427 while (rc == ERROR_SUCCESS)
1429 RegDeleteValueW(hKey,valname);
1430 index++;
1431 size = MAX_PATH+1;
1432 rc = RegEnumValueW(hKey, index, valname, &size,0,0,0,0);
1435 RegCloseKey(hKey);
1436 hsvc->hkey = NULL;
1438 /* delete the key */
1439 RegDeleteKeyW(hsvc->scm->hkey, hsvc->name);
1441 return TRUE;
1445 /******************************************************************************
1446 * StartServiceA [ADVAPI32.@]
1448 * Start a service
1450 * PARAMS
1451 * hService [I] Handle of service
1452 * dwNumServiceArgs [I] Number of arguments
1453 * lpServiceArgVectors [I] Address of array of argument strings
1455 * NOTES
1456 * - NT implements this function using an obscure RPC call.
1457 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1458 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1459 * - This will only work for shared address space. How should the service
1460 * args be transferred when address spaces are separated?
1461 * - Can only start one service at a time.
1462 * - Has no concept of privilege.
1464 * RETURNS
1465 * Success: TRUE.
1466 * Failure: FALSE
1468 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1469 LPCSTR *lpServiceArgVectors )
1471 LPWSTR *lpwstr=NULL;
1472 unsigned int i;
1473 BOOL r;
1475 TRACE("(%p,%d,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1477 if (dwNumServiceArgs)
1478 lpwstr = HeapAlloc( GetProcessHeap(), 0,
1479 dwNumServiceArgs*sizeof(LPWSTR) );
1481 for(i=0; i<dwNumServiceArgs; i++)
1482 lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1484 r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1486 if (dwNumServiceArgs)
1488 for(i=0; i<dwNumServiceArgs; i++)
1489 SERV_free(lpwstr[i]);
1490 HeapFree(GetProcessHeap(), 0, lpwstr);
1493 return r;
1496 /******************************************************************************
1497 * service_start_process [INTERNAL]
1499 static DWORD service_start_process(struct sc_service *hsvc, LPDWORD ppid)
1501 static const WCHAR _ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0};
1502 PROCESS_INFORMATION pi;
1503 STARTUPINFOW si;
1504 LPWSTR path = NULL, str;
1505 DWORD type, size, ret, svc_type;
1506 HANDLE handles[2];
1507 BOOL r;
1509 size = sizeof(svc_type);
1510 if (RegQueryValueExW(hsvc->hkey, szType, NULL, &type, (LPBYTE)&svc_type, &size) || type != REG_DWORD)
1511 svc_type = 0;
1513 if (svc_type == SERVICE_KERNEL_DRIVER)
1515 static const WCHAR winedeviceW[] = {'\\','w','i','n','e','d','e','v','i','c','e','.','e','x','e',' ',0};
1516 DWORD len = GetSystemDirectoryW( NULL, 0 ) + sizeof(winedeviceW)/sizeof(WCHAR) + strlenW(hsvc->name);
1518 if (!(path = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return FALSE;
1519 GetSystemDirectoryW( path, len );
1520 lstrcatW( path, winedeviceW );
1521 lstrcatW( path, hsvc->name );
1523 else
1525 /* read the executable path from the registry */
1526 size = 0;
1527 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, NULL, &size);
1528 if (ret!=ERROR_SUCCESS)
1529 return FALSE;
1530 str = HeapAlloc(GetProcessHeap(),0,size);
1531 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, (LPBYTE)str, &size);
1532 if (ret==ERROR_SUCCESS)
1534 size = ExpandEnvironmentStringsW(str,NULL,0);
1535 path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
1536 ExpandEnvironmentStringsW(str,path,size);
1538 HeapFree(GetProcessHeap(),0,str);
1539 if (!path)
1540 return FALSE;
1543 /* wait for the process to start and set an event or terminate */
1544 handles[0] = service_get_event_handle( hsvc->name );
1545 ZeroMemory(&si, sizeof(STARTUPINFOW));
1546 si.cb = sizeof(STARTUPINFOW);
1547 r = CreateProcessW(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1548 if (r)
1550 if (ppid) *ppid = pi.dwProcessId;
1552 handles[1] = pi.hProcess;
1553 ret = WaitForMultipleObjectsEx(2, handles, FALSE, 30000, FALSE);
1554 if(ret != WAIT_OBJECT_0)
1556 SetLastError(ERROR_IO_PENDING);
1557 r = FALSE;
1560 CloseHandle( pi.hThread );
1561 CloseHandle( pi.hProcess );
1563 CloseHandle( handles[0] );
1564 HeapFree(GetProcessHeap(),0,path);
1565 return r;
1568 static BOOL service_wait_for_startup(SC_HANDLE hService)
1570 DWORD i;
1571 SERVICE_STATUS status;
1572 BOOL r = FALSE;
1574 TRACE("%p\n", hService);
1576 for (i=0; i<30; i++)
1578 status.dwCurrentState = 0;
1579 r = QueryServiceStatus(hService, &status);
1580 if (!r)
1581 break;
1582 if (status.dwCurrentState == SERVICE_RUNNING)
1584 TRACE("Service started successfully\n");
1585 break;
1587 r = FALSE;
1588 Sleep(1000);
1590 return r;
1593 /******************************************************************************
1594 * StartServiceW [ADVAPI32.@]
1596 * See StartServiceA.
1598 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1599 LPCWSTR *lpServiceArgVectors)
1601 struct sc_service *hsvc;
1602 BOOL r = FALSE;
1603 DWORD dwResult, dwProcessId = 0;
1604 SC_LOCK hLock;
1605 HANDLE handle = INVALID_HANDLE_VALUE;
1607 TRACE("%p %d %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1609 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1610 if (!hsvc)
1612 SetLastError(ERROR_INVALID_HANDLE);
1613 return r;
1616 hLock = LockServiceDatabase((SC_HANDLE)hsvc->scm);
1617 if (!hLock)
1618 return r;
1620 handle = service_open_pipe(hsvc->name);
1621 if (handle==INVALID_HANDLE_VALUE)
1623 /* start the service process */
1624 if (service_start_process(hsvc, &dwProcessId))
1625 handle = service_open_pipe(hsvc->name);
1628 if (handle != INVALID_HANDLE_VALUE)
1630 r = service_send_start_message(handle, lpServiceArgVectors, dwNumServiceArgs);
1631 CloseHandle(handle);
1634 handle = service_open_pipe(hsvc->name);
1635 if (handle != INVALID_HANDLE_VALUE)
1637 service_set_processID(handle, dwProcessId, &dwResult);
1638 CloseHandle(handle);
1641 UnlockServiceDatabase( hLock );
1643 TRACE("returning %d\n", r);
1645 if (r)
1646 service_wait_for_startup(hService);
1648 return r;
1651 /******************************************************************************
1652 * QueryServiceStatus [ADVAPI32.@]
1654 * PARAMS
1655 * hService [I] Handle to service to get information about
1656 * lpservicestatus [O] buffer to receive the status information for the service
1659 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1660 LPSERVICE_STATUS lpservicestatus)
1662 SERVICE_STATUS_PROCESS SvcStatusData;
1663 BOOL ret;
1665 TRACE("%p %p\n", hService, lpservicestatus);
1667 ret = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&SvcStatusData,
1668 sizeof(SERVICE_STATUS_PROCESS), NULL);
1669 if (ret) memcpy(lpservicestatus, &SvcStatusData, sizeof(SERVICE_STATUS)) ;
1670 return ret;
1674 /******************************************************************************
1675 * QueryServiceStatusEx [ADVAPI32.@]
1677 * Get information about a service.
1679 * PARAMS
1680 * hService [I] Handle to service to get information about
1681 * InfoLevel [I] Level of information to get
1682 * lpBuffer [O] Destination for requested information
1683 * cbBufSize [I] Size of lpBuffer in bytes
1684 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1686 * RETURNS
1687 * Success: TRUE
1688 * FAILURE: FALSE
1690 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1691 LPBYTE lpBuffer, DWORD cbBufSize,
1692 LPDWORD pcbBytesNeeded)
1694 struct sc_service *hsvc;
1695 DWORD size, type, val;
1696 HANDLE pipe;
1697 LONG r;
1698 LPSERVICE_STATUS_PROCESS pSvcStatusData;
1700 TRACE("%p %d %p %d %p\n", hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1702 if (InfoLevel != SC_STATUS_PROCESS_INFO)
1704 SetLastError( ERROR_INVALID_LEVEL);
1705 return FALSE;
1708 pSvcStatusData = (LPSERVICE_STATUS_PROCESS) lpBuffer;
1709 if (pSvcStatusData == NULL)
1711 SetLastError( ERROR_INVALID_PARAMETER);
1712 return FALSE;
1715 if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
1717 if( pcbBytesNeeded != NULL)
1718 *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
1720 SetLastError( ERROR_INSUFFICIENT_BUFFER);
1721 return FALSE;
1724 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1725 if (!hsvc)
1727 SetLastError( ERROR_INVALID_HANDLE );
1728 return FALSE;
1731 pipe = service_open_pipe(hsvc->name);
1732 if (pipe != INVALID_HANDLE_VALUE)
1734 r = service_get_status(pipe, pSvcStatusData);
1735 CloseHandle(pipe);
1736 if (r)
1737 return TRUE;
1740 TRACE("Failed to read service status\n");
1742 /* read the service type from the registry */
1743 size = sizeof(val);
1744 r = RegQueryValueExA(hsvc->hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1745 if (r != ERROR_SUCCESS || type != REG_DWORD)
1746 val = 0;
1748 pSvcStatusData->dwServiceType = val;
1749 pSvcStatusData->dwCurrentState = SERVICE_STOPPED; /* stopped */
1750 pSvcStatusData->dwControlsAccepted = 0;
1751 pSvcStatusData->dwWin32ExitCode = ERROR_SERVICE_NEVER_STARTED;
1752 pSvcStatusData->dwServiceSpecificExitCode = 0;
1753 pSvcStatusData->dwCheckPoint = 0;
1754 pSvcStatusData->dwWaitHint = 0;
1756 return TRUE;
1759 /******************************************************************************
1760 * QueryServiceConfigA [ADVAPI32.@]
1762 BOOL WINAPI QueryServiceConfigA( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGA config,
1763 DWORD size, LPDWORD needed )
1765 DWORD n;
1766 LPSTR p, buffer;
1767 BOOL ret;
1768 QUERY_SERVICE_CONFIGW *configW;
1770 TRACE("%p %p %d %p\n", hService, config, size, needed);
1772 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, 2 * size )))
1774 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1775 return FALSE;
1777 configW = (QUERY_SERVICE_CONFIGW *)buffer;
1778 ret = QueryServiceConfigW( hService, configW, 2 * size, needed );
1779 if (!ret) goto done;
1781 config->dwServiceType = configW->dwServiceType;
1782 config->dwStartType = configW->dwStartType;
1783 config->dwErrorControl = configW->dwErrorControl;
1784 config->lpBinaryPathName = NULL;
1785 config->lpLoadOrderGroup = NULL;
1786 config->dwTagId = configW->dwTagId;
1787 config->lpDependencies = NULL;
1788 config->lpServiceStartName = NULL;
1789 config->lpDisplayName = NULL;
1791 p = (LPSTR)(config + 1);
1792 n = size - sizeof(*config);
1793 ret = FALSE;
1795 #define MAP_STR(str) \
1796 do { \
1797 if (configW->str) \
1799 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1800 if (!sz) goto done; \
1801 config->str = p; \
1802 p += sz; \
1803 n -= sz; \
1805 } while (0)
1807 MAP_STR( lpBinaryPathName );
1808 MAP_STR( lpLoadOrderGroup );
1809 MAP_STR( lpDependencies );
1810 MAP_STR( lpServiceStartName );
1811 MAP_STR( lpDisplayName );
1812 #undef MAP_STR
1814 *needed = p - buffer;
1815 ret = TRUE;
1817 done:
1818 HeapFree( GetProcessHeap(), 0, buffer );
1819 return ret;
1822 /******************************************************************************
1823 * QueryServiceConfigW [ADVAPI32.@]
1825 BOOL WINAPI
1826 QueryServiceConfigW( SC_HANDLE hService,
1827 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1828 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1830 WCHAR str_buffer[ MAX_PATH ];
1831 LONG r;
1832 DWORD type, val, sz, total, n;
1833 LPBYTE p;
1834 HKEY hKey;
1835 struct sc_service *hsvc;
1837 TRACE("%p %p %d %p\n", hService, lpServiceConfig,
1838 cbBufSize, pcbBytesNeeded);
1840 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1841 if (!hsvc)
1843 SetLastError( ERROR_INVALID_HANDLE );
1844 return FALSE;
1846 hKey = hsvc->hkey;
1848 /* calculate the size required first */
1849 total = sizeof (QUERY_SERVICE_CONFIGW);
1851 sz = sizeof(str_buffer);
1852 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1853 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1855 sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1856 if( 0 == sz ) return FALSE;
1858 total += sizeof(WCHAR) * sz;
1860 else
1862 /* FIXME: set last error */
1863 return FALSE;
1866 sz = 0;
1867 r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1868 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1869 total += sz;
1871 sz = 0;
1872 r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1873 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1874 total += sz;
1875 else
1876 total += sizeof(WCHAR);
1878 sz = 0;
1879 r = RegQueryValueExW( hKey, szStart, 0, &type, NULL, &sz );
1880 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1881 total += sz;
1883 sz = 0;
1884 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1885 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1886 total += sz;
1888 *pcbBytesNeeded = total;
1890 /* if there's not enough memory, return an error */
1891 if( total > cbBufSize )
1893 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1894 return FALSE;
1897 ZeroMemory( lpServiceConfig, total );
1899 sz = sizeof val;
1900 r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1901 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1902 lpServiceConfig->dwServiceType = val;
1904 sz = sizeof val;
1905 r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1906 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1907 lpServiceConfig->dwStartType = val;
1909 sz = sizeof val;
1910 r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1911 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1912 lpServiceConfig->dwErrorControl = val;
1914 /* now do the strings */
1915 p = (LPBYTE) &lpServiceConfig[1];
1916 n = total - sizeof (QUERY_SERVICE_CONFIGW);
1918 sz = sizeof(str_buffer);
1919 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1920 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1922 sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
1923 sz *= sizeof(WCHAR);
1924 if( 0 == sz || sz > n ) return FALSE;
1926 lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
1927 p += sz;
1928 n -= sz;
1930 else
1932 /* FIXME: set last error */
1933 return FALSE;
1936 sz = n;
1937 r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
1938 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1940 lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
1941 p += sz;
1942 n -= sz;
1945 sz = n;
1946 r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
1947 lpServiceConfig->lpDependencies = (LPWSTR) p;
1948 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1950 p += sz;
1951 n -= sz;
1953 else
1955 *(WCHAR *) p = 0;
1956 p += sizeof(WCHAR);
1957 n -= sizeof(WCHAR);
1960 if( n < 0 )
1961 ERR("Buffer overflow!\n");
1963 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1964 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1966 return TRUE;
1969 /******************************************************************************
1970 * EnumServicesStatusA [ADVAPI32.@]
1972 BOOL WINAPI
1973 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
1974 DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
1975 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1976 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1978 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
1979 dwServiceType, dwServiceState, lpServices, cbBufSize,
1980 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
1981 SetLastError (ERROR_ACCESS_DENIED);
1982 return FALSE;
1985 /******************************************************************************
1986 * EnumServicesStatusW [ADVAPI32.@]
1988 BOOL WINAPI
1989 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
1990 DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
1991 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1992 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1994 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
1995 dwServiceType, dwServiceState, lpServices, cbBufSize,
1996 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
1997 SetLastError (ERROR_ACCESS_DENIED);
1998 return FALSE;
2001 /******************************************************************************
2002 * EnumServicesStatusExA [ADVAPI32.@]
2004 BOOL WINAPI
2005 EnumServicesStatusExA(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
2006 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2007 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCSTR pszGroupName)
2009 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
2010 dwServiceType, dwServiceState, lpServices, cbBufSize,
2011 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_a(pszGroupName));
2012 SetLastError (ERROR_ACCESS_DENIED);
2013 return FALSE;
2016 /******************************************************************************
2017 * EnumServicesStatusExW [ADVAPI32.@]
2019 BOOL WINAPI
2020 EnumServicesStatusExW(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
2021 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2022 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCWSTR pszGroupName)
2024 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
2025 dwServiceType, dwServiceState, lpServices, cbBufSize,
2026 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_w(pszGroupName));
2027 SetLastError (ERROR_ACCESS_DENIED);
2028 return FALSE;
2031 /******************************************************************************
2032 * GetServiceKeyNameA [ADVAPI32.@]
2034 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
2035 LPSTR lpServiceName, LPDWORD lpcchBuffer )
2037 FIXME("%p %s %p %p\n", hSCManager, debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
2038 return FALSE;
2041 /******************************************************************************
2042 * GetServiceKeyNameW [ADVAPI32.@]
2044 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
2045 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
2047 FIXME("%p %s %p %p\n", hSCManager, debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
2048 return FALSE;
2051 /******************************************************************************
2052 * QueryServiceLockStatusA [ADVAPI32.@]
2054 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
2055 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
2056 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2058 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2060 return FALSE;
2063 /******************************************************************************
2064 * QueryServiceLockStatusW [ADVAPI32.@]
2066 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
2067 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2068 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2070 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2072 return FALSE;
2075 /******************************************************************************
2076 * GetServiceDisplayNameA [ADVAPI32.@]
2078 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
2079 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
2081 struct sc_manager *hscm;
2082 DWORD type, size;
2083 LONG ret;
2085 TRACE("%p %s %p %p\n", hSCManager,
2086 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
2088 if (!lpServiceName)
2090 SetLastError(ERROR_INVALID_PARAMETER);
2091 return FALSE;
2094 hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
2095 if (!hscm)
2097 SetLastError(ERROR_INVALID_HANDLE);
2098 return FALSE;
2101 size = *lpcchBuffer;
2102 ret = RegGetValueA(hscm->hkey, lpServiceName, "DisplayName", RRF_RT_REG_SZ, &type, lpDisplayName, &size);
2103 if (!ret && !lpDisplayName && size)
2104 ret = ERROR_MORE_DATA;
2106 if (ret)
2108 if (lpDisplayName && *lpcchBuffer) *lpDisplayName = 0;
2110 if (ret == ERROR_MORE_DATA)
2112 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2113 *lpcchBuffer = size - 1;
2115 else
2116 SetLastError(ret);
2117 return FALSE;
2119 return TRUE;
2122 /******************************************************************************
2123 * GetServiceDisplayNameW [ADVAPI32.@]
2125 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
2126 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
2128 struct sc_manager *hscm;
2129 DWORD type, size;
2130 LONG ret;
2132 TRACE("%p %s %p %p\n", hSCManager,
2133 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
2135 if (!lpServiceName)
2137 SetLastError(ERROR_INVALID_PARAMETER);
2138 return FALSE;
2141 hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
2142 if (!hscm)
2144 SetLastError(ERROR_INVALID_HANDLE);
2145 return FALSE;
2148 size = *lpcchBuffer * sizeof(WCHAR);
2149 ret = RegGetValueW(hscm->hkey, lpServiceName, szDisplayName, RRF_RT_REG_SZ, &type, lpDisplayName, &size);
2150 if (!ret && !lpDisplayName && size)
2151 ret = ERROR_MORE_DATA;
2153 if (ret)
2155 if (lpDisplayName && *lpcchBuffer) *lpDisplayName = 0;
2157 if (ret == ERROR_MORE_DATA)
2159 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2160 *lpcchBuffer = (size / sizeof(WCHAR)) - 1;
2162 else
2163 SetLastError(ret);
2164 return FALSE;
2166 return TRUE;
2169 /******************************************************************************
2170 * ChangeServiceConfigW [ADVAPI32.@]
2172 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
2173 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
2174 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
2175 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
2177 struct reg_value val[10];
2178 struct sc_service *hsvc;
2179 DWORD r = ERROR_SUCCESS;
2180 HKEY hKey;
2181 int n = 0;
2183 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2184 hService, dwServiceType, dwStartType, dwErrorControl,
2185 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2186 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2187 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2189 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2190 if (!hsvc)
2192 SetLastError( ERROR_INVALID_HANDLE );
2193 return FALSE;
2195 hKey = hsvc->hkey;
2197 if( dwServiceType != SERVICE_NO_CHANGE )
2198 service_set_dword( &val[n++], szType, &dwServiceType );
2200 if( dwStartType != SERVICE_NO_CHANGE )
2201 service_set_dword( &val[n++], szStart, &dwStartType );
2203 if( dwErrorControl != SERVICE_NO_CHANGE )
2204 service_set_dword( &val[n++], szError, &dwErrorControl );
2206 if( lpBinaryPathName )
2207 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
2209 if( lpLoadOrderGroup )
2210 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
2212 if( lpDependencies )
2213 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
2215 if( lpPassword )
2216 FIXME("ignoring password\n");
2218 if( lpServiceStartName )
2219 service_set_string( &val[n++], szDependOnService, lpServiceStartName );
2221 r = service_write_values( hsvc->hkey, val, n );
2223 return (r == ERROR_SUCCESS) ? TRUE : FALSE ;
2226 /******************************************************************************
2227 * ChangeServiceConfigA [ADVAPI32.@]
2229 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2230 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2231 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2232 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2234 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2235 LPWSTR wServiceStartName, wPassword, wDisplayName;
2236 BOOL r;
2238 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2239 hService, dwServiceType, dwStartType, dwErrorControl,
2240 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2241 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2242 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2244 wBinaryPathName = SERV_dup( lpBinaryPathName );
2245 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2246 wDependencies = SERV_dupmulti( lpDependencies );
2247 wServiceStartName = SERV_dup( lpServiceStartName );
2248 wPassword = SERV_dup( lpPassword );
2249 wDisplayName = SERV_dup( lpDisplayName );
2251 r = ChangeServiceConfigW( hService, dwServiceType,
2252 dwStartType, dwErrorControl, wBinaryPathName,
2253 wLoadOrderGroup, lpdwTagId, wDependencies,
2254 wServiceStartName, wPassword, wDisplayName);
2256 SERV_free( wBinaryPathName );
2257 SERV_free( wLoadOrderGroup );
2258 SERV_free( wDependencies );
2259 SERV_free( wServiceStartName );
2260 SERV_free( wPassword );
2261 SERV_free( wDisplayName );
2263 return r;
2266 /******************************************************************************
2267 * ChangeServiceConfig2A [ADVAPI32.@]
2269 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2270 LPVOID lpInfo)
2272 BOOL r = FALSE;
2274 TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo);
2276 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2278 LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
2279 SERVICE_DESCRIPTIONW sdw;
2281 sdw.lpDescription = SERV_dup( sd->lpDescription );
2283 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2285 SERV_free( sdw.lpDescription );
2287 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2289 LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
2290 SERVICE_FAILURE_ACTIONSW faw;
2292 faw.dwResetPeriod = fa->dwResetPeriod;
2293 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2294 faw.lpCommand = SERV_dup( fa->lpCommand );
2295 faw.cActions = fa->cActions;
2296 faw.lpsaActions = fa->lpsaActions;
2298 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2300 SERV_free( faw.lpRebootMsg );
2301 SERV_free( faw.lpCommand );
2303 else
2304 SetLastError( ERROR_INVALID_PARAMETER );
2306 return r;
2309 /******************************************************************************
2310 * ChangeServiceConfig2W [ADVAPI32.@]
2312 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2313 LPVOID lpInfo)
2315 HKEY hKey;
2316 struct sc_service *hsvc;
2318 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2319 if (!hsvc)
2321 SetLastError( ERROR_INVALID_HANDLE );
2322 return FALSE;
2324 hKey = hsvc->hkey;
2326 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2328 static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2329 LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
2330 if (sd->lpDescription)
2332 TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
2333 if (sd->lpDescription[0] == 0)
2334 RegDeleteValueW(hKey,szDescription);
2335 else
2336 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2337 (LPVOID)sd->lpDescription,
2338 sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2341 else
2342 FIXME("STUB: %p %d %p\n",hService, dwInfoLevel, lpInfo);
2343 return TRUE;
2346 /******************************************************************************
2347 * QueryServiceObjectSecurity [ADVAPI32.@]
2349 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2350 SECURITY_INFORMATION dwSecurityInformation,
2351 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2352 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2354 PACL pACL = NULL;
2356 FIXME("%p %d %p %u %p\n", hService, dwSecurityInformation,
2357 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2359 InitializeSecurityDescriptor(lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
2361 pACL = HeapAlloc( GetProcessHeap(), 0, sizeof(ACL) );
2362 InitializeAcl(pACL, sizeof(ACL), ACL_REVISION);
2363 SetSecurityDescriptorDacl(lpSecurityDescriptor, TRUE, pACL, TRUE);
2364 return TRUE;
2367 /******************************************************************************
2368 * SetServiceObjectSecurity [ADVAPI32.@]
2370 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2371 SECURITY_INFORMATION dwSecurityInformation,
2372 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2374 FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2375 return TRUE;
2378 /******************************************************************************
2379 * SetServiceBits [ADVAPI32.@]
2381 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2382 DWORD dwServiceBits,
2383 BOOL bSetBitsOn,
2384 BOOL bUpdateImmediately)
2386 FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2387 bSetBitsOn, bUpdateImmediately);
2388 return TRUE;
2391 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR lpServiceName,
2392 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2394 FIXME("%s %p %p\n", debugstr_a(lpServiceName), lpHandlerProc, lpContext);
2395 return 0;
2398 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2399 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2401 service_data *service;
2402 SERVICE_STATUS_HANDLE handle = 0;
2404 TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2406 EnterCriticalSection( &service_cs );
2407 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
2409 if(!strcmpW(lpServiceName, service->name))
2411 service->handler.handler_ex = lpHandlerProc;
2412 service->context = lpContext;
2413 service->extended = TRUE;
2414 handle = (SERVICE_STATUS_HANDLE)service;
2415 break;
2418 LeaveCriticalSection( &service_cs );
2420 return handle;