push cc6891608c0bafd7b7a9ec5535ff0d2e018364e3
[wine/hacks.git] / dlls / advapi32 / service.c
blob731d668b8aa21805f58e67c40ddc240a8b0232ad
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};
241 static const WCHAR szObjectName[] = {
242 'O','b','j','e','c','t','N','a','m','e',0};
243 static const WCHAR szTag[] = {
244 'T','a','g',0};
246 struct reg_value {
247 DWORD type;
248 DWORD size;
249 LPCWSTR name;
250 LPCVOID data;
253 static inline void service_set_value( struct reg_value *val,
254 DWORD type, LPCWSTR name, LPCVOID data, DWORD size )
256 val->name = name;
257 val->type = type;
258 val->data = data;
259 val->size = size;
262 static inline void service_set_dword( struct reg_value *val,
263 LPCWSTR name, const DWORD *data )
265 service_set_value( val, REG_DWORD, name, data, sizeof (DWORD));
268 static inline void service_set_string( struct reg_value *val,
269 LPCWSTR name, LPCWSTR string )
271 DWORD len = (lstrlenW(string)+1) * sizeof (WCHAR);
272 service_set_value( val, REG_SZ, name, string, len );
275 static inline void service_set_multi_string( struct reg_value *val,
276 LPCWSTR name, LPCWSTR string )
278 DWORD len = 0;
280 /* determine the length of a double null terminated multi string */
281 do {
282 len += (lstrlenW( &string[ len ] )+1);
283 } while ( string[ len++ ] );
285 len *= sizeof (WCHAR);
286 service_set_value( val, REG_MULTI_SZ, name, string, len );
289 static inline LONG service_write_values( HKEY hKey,
290 const struct reg_value *val, int n )
292 LONG r = ERROR_SUCCESS;
293 int i;
295 for( i=0; i<n; i++ )
297 r = RegSetValueExW(hKey, val[i].name, 0, val[i].type,
298 (const BYTE*)val[i].data, val[i].size );
299 if( r != ERROR_SUCCESS )
300 break;
302 return r;
305 /******************************************************************************
306 * Service IPC functions
308 static LPWSTR service_get_pipe_name(LPCWSTR service)
310 static const WCHAR prefix[] = { '\\','\\','.','\\','p','i','p','e','\\',
311 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
312 LPWSTR name;
313 DWORD len;
315 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
316 name = HeapAlloc(GetProcessHeap(), 0, len);
317 strcpyW(name, prefix);
318 strcatW(name, service);
319 return name;
322 static HANDLE service_open_pipe(LPCWSTR service)
324 LPWSTR szPipe = service_get_pipe_name( service );
325 HANDLE handle = INVALID_HANDLE_VALUE;
327 do {
328 handle = CreateFileW(szPipe, GENERIC_READ|GENERIC_WRITE,
329 0, NULL, OPEN_ALWAYS, 0, NULL);
330 if (handle != INVALID_HANDLE_VALUE)
331 break;
332 if (GetLastError() != ERROR_PIPE_BUSY)
333 break;
334 } while (WaitNamedPipeW(szPipe, NMPWAIT_WAIT_FOREVER));
335 SERV_free(szPipe);
337 return handle;
340 /******************************************************************************
341 * service_get_event_handle
343 static HANDLE service_get_event_handle(LPCWSTR service)
345 static const WCHAR prefix[] = {
346 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
347 LPWSTR name;
348 DWORD len;
349 HANDLE handle;
351 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
352 name = HeapAlloc(GetProcessHeap(), 0, len);
353 strcpyW(name, prefix);
354 strcatW(name, service);
355 handle = CreateEventW(NULL, TRUE, FALSE, name);
356 SERV_free(name);
357 return handle;
360 /******************************************************************************
361 * service_thread
363 * Call into the main service routine provided by StartServiceCtrlDispatcher.
365 static DWORD WINAPI service_thread(LPVOID arg)
367 service_data *info = arg;
368 LPWSTR str = info->args;
369 DWORD argc = 0, len = 0;
371 TRACE("%p\n", arg);
373 while (str[len])
375 len += strlenW(&str[len]) + 1;
376 argc++;
379 if (!argc)
381 if (info->unicode)
382 info->proc.w(0, NULL);
383 else
384 info->proc.a(0, NULL);
385 return 0;
388 if (info->unicode)
390 LPWSTR *argv, p;
392 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPWSTR));
393 for (argc=0, p=str; *p; p += strlenW(p) + 1)
394 argv[argc++] = p;
395 argv[argc] = NULL;
397 info->proc.w(argc, argv);
398 HeapFree(GetProcessHeap(), 0, argv);
400 else
402 LPSTR strA, *argv, p;
403 DWORD lenA;
405 lenA = WideCharToMultiByte(CP_ACP,0, str, len, NULL, 0, NULL, NULL);
406 strA = HeapAlloc(GetProcessHeap(), 0, lenA);
407 WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL);
409 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPSTR));
410 for (argc=0, p=strA; *p; p += strlen(p) + 1)
411 argv[argc++] = p;
412 argv[argc] = NULL;
414 info->proc.a(argc, argv);
415 HeapFree(GetProcessHeap(), 0, argv);
416 HeapFree(GetProcessHeap(), 0, strA);
418 return 0;
421 /******************************************************************************
422 * service_handle_start
424 static BOOL service_handle_start(HANDLE pipe, service_data *service, DWORD count)
426 DWORD read = 0, result = 0;
427 LPWSTR args;
428 BOOL r;
430 TRACE("%p %p %d\n", pipe, service, count);
432 args = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
433 r = ReadFile(pipe, args, count*sizeof(WCHAR), &read, NULL);
434 if (!r || count!=read/sizeof(WCHAR) || args[count-1])
436 ERR("pipe read failed r = %d count = %d read = %d args[n-1]=%s\n",
437 r, count, read, debugstr_wn(args, count));
438 goto end;
441 if (service->thread)
443 ERR("service is not stopped\n");
444 goto end;
447 SERV_free(service->args);
448 service->args = args;
449 args = NULL;
450 service->thread = CreateThread( NULL, 0, service_thread,
451 service, 0, NULL );
453 end:
454 HeapFree(GetProcessHeap(), 0, args);
455 WriteFile( pipe, &result, sizeof result, &read, NULL );
457 return TRUE;
460 /******************************************************************************
461 * service_send_start_message
463 static BOOL service_send_start_message(HANDLE pipe, LPCWSTR *argv, DWORD argc)
465 DWORD i, len, count, result;
466 service_start_info *ssi;
467 LPWSTR p;
468 BOOL r;
470 TRACE("%p %p %d\n", pipe, argv, argc);
472 /* calculate how much space do we need to send the startup info */
473 len = 1;
474 for (i=0; i<argc; i++)
475 len += strlenW(argv[i])+1;
477 ssi = HeapAlloc(GetProcessHeap(),0,sizeof *ssi + (len-1)*sizeof(WCHAR));
478 ssi->cmd = WINESERV_STARTINFO;
479 ssi->size = len;
481 /* copy service args into a single buffer*/
482 p = &ssi->str[0];
483 for (i=0; i<argc; i++)
485 strcpyW(p, argv[i]);
486 p += strlenW(p) + 1;
488 *p=0;
490 r = WriteFile(pipe, ssi, sizeof *ssi + len*sizeof(WCHAR), &count, NULL);
491 if (r)
492 r = ReadFile(pipe, &result, sizeof result, &count, NULL);
494 HeapFree(GetProcessHeap(),0,ssi);
496 return r;
499 /******************************************************************************
500 * service_handle_get_status
502 static BOOL service_handle_get_status(HANDLE pipe, const service_data *service)
504 DWORD count = 0;
505 TRACE("\n");
506 return WriteFile(pipe, &service->status,
507 sizeof service->status, &count, NULL);
510 /******************************************************************************
511 * service_get_status
513 static BOOL service_get_status(HANDLE pipe, LPSERVICE_STATUS_PROCESS status)
515 DWORD cmd[2], count = 0;
516 BOOL r;
518 cmd[0] = WINESERV_GETSTATUS;
519 cmd[1] = 0;
520 r = WriteFile( pipe, cmd, sizeof cmd, &count, NULL );
521 if (!r || count != sizeof cmd)
523 ERR("service protocol error - failed to write pipe!\n");
524 return r;
526 r = ReadFile( pipe, status, sizeof *status, &count, NULL );
527 if (!r || count != sizeof *status)
528 ERR("service protocol error - failed to read pipe "
529 "r = %d count = %d!\n", r, count);
530 return r;
533 /******************************************************************************
534 * service_handle_set_processID
536 static BOOL service_handle_set_processID(HANDLE pipe, service_data *service, DWORD dwProcessId)
538 DWORD count, ret = ERROR_SUCCESS;
540 TRACE("received control %d\n", dwProcessId);
541 service->status.dwProcessId = dwProcessId;
542 return WriteFile(pipe, &ret, sizeof ret , &count, NULL);
545 /******************************************************************************
546 * service_set_processID
548 static BOOL service_set_processID(HANDLE pipe, DWORD dwprocessId, LPDWORD dwResult)
550 DWORD cmd[2], count = 0;
551 BOOL r;
553 cmd[0] = WINESERV_SETPID;
554 cmd[1] = dwprocessId;
555 r = WriteFile( pipe, cmd, sizeof cmd, &count, NULL );
556 if (!r || count != sizeof cmd)
558 ERR("service protocol error - failed to write pipe!\n");
559 return r;
561 r = ReadFile( pipe, dwResult, sizeof *dwResult, &count, NULL );
562 if (!r || count != sizeof *dwResult)
563 ERR("service protocol error - failed to read pipe "
564 "r = %d count = %d!\n", r, count);
565 return r;
568 /******************************************************************************
569 * service_send_control
571 static BOOL service_send_control(HANDLE pipe, DWORD dwControl, DWORD *result)
573 DWORD cmd[2], count = 0;
574 BOOL r;
576 cmd[0] = WINESERV_SENDCONTROL;
577 cmd[1] = dwControl;
578 r = WriteFile(pipe, cmd, sizeof cmd, &count, NULL);
579 if (!r || count != sizeof cmd)
581 ERR("service protocol error - failed to write pipe!\n");
582 return r;
584 r = ReadFile(pipe, result, sizeof *result, &count, NULL);
585 if (!r || count != sizeof *result)
586 ERR("service protocol error - failed to read pipe "
587 "r = %d count = %d!\n", r, count);
588 return r;
591 /******************************************************************************
592 * service_accepts_control
594 static BOOL service_accepts_control(const service_data *service, DWORD dwControl)
596 DWORD a = service->status.dwControlsAccepted;
598 switch (dwControl)
600 case SERVICE_CONTROL_INTERROGATE:
601 return TRUE;
602 case SERVICE_CONTROL_STOP:
603 if (a&SERVICE_ACCEPT_STOP)
604 return TRUE;
605 break;
606 case SERVICE_CONTROL_SHUTDOWN:
607 if (a&SERVICE_ACCEPT_SHUTDOWN)
608 return TRUE;
609 break;
610 case SERVICE_CONTROL_PAUSE:
611 case SERVICE_CONTROL_CONTINUE:
612 if (a&SERVICE_ACCEPT_PAUSE_CONTINUE)
613 return TRUE;
614 break;
615 case SERVICE_CONTROL_PARAMCHANGE:
616 if (a&SERVICE_ACCEPT_PARAMCHANGE)
617 return TRUE;
618 break;
619 case SERVICE_CONTROL_NETBINDADD:
620 case SERVICE_CONTROL_NETBINDREMOVE:
621 case SERVICE_CONTROL_NETBINDENABLE:
622 case SERVICE_CONTROL_NETBINDDISABLE:
623 if (a&SERVICE_ACCEPT_NETBINDCHANGE)
624 return TRUE;
626 if (!service->extended)
627 return FALSE;
628 switch (dwControl)
630 case SERVICE_CONTROL_HARDWAREPROFILECHANGE:
631 if (a&SERVICE_ACCEPT_HARDWAREPROFILECHANGE)
632 return TRUE;
633 break;
634 case SERVICE_CONTROL_POWEREVENT:
635 if (a&SERVICE_ACCEPT_POWEREVENT)
636 return TRUE;
637 break;
638 case SERVICE_CONTROL_SESSIONCHANGE:
639 if (a&SERVICE_ACCEPT_SESSIONCHANGE)
640 return TRUE;
641 break;
643 return FALSE;
646 /******************************************************************************
647 * service_handle_control
649 static BOOL service_handle_control(HANDLE pipe, service_data *service,
650 DWORD dwControl)
652 DWORD count, ret = ERROR_INVALID_SERVICE_CONTROL;
654 TRACE("received control %d\n", dwControl);
656 if (service_accepts_control(service, dwControl))
658 if (service->extended && service->handler.handler_ex)
660 service->handler.handler_ex(dwControl, 0, NULL, service->context);
661 ret = ERROR_SUCCESS;
663 else if (service->handler.handler)
665 service->handler.handler(dwControl);
666 ret = ERROR_SUCCESS;
669 return WriteFile(pipe, &ret, sizeof ret, &count, NULL);
672 /******************************************************************************
673 * service_reap_thread
675 static DWORD service_reap_thread(service_data *service)
677 DWORD exitcode = 0;
679 if (!service->thread)
680 return 0;
681 GetExitCodeThread(service->thread, &exitcode);
682 if (exitcode!=STILL_ACTIVE)
684 CloseHandle(service->thread);
685 service->thread = 0;
687 return exitcode;
690 /******************************************************************************
691 * service_control_dispatcher
693 static DWORD WINAPI service_control_dispatcher(LPVOID arg)
695 service_data *service = arg;
696 LPWSTR name;
697 HANDLE pipe, event;
699 TRACE("%p %s\n", service, debugstr_w(service->name));
701 /* create a pipe to talk to the rest of the world with */
702 name = service_get_pipe_name(service->name);
703 pipe = CreateNamedPipeW(name, PIPE_ACCESS_DUPLEX,
704 PIPE_TYPE_BYTE|PIPE_WAIT, 1, 256, 256, 10000, NULL );
705 SERV_free(name);
707 /* let the process who started us know we've tried to create a pipe */
708 event = service_get_event_handle(service->name);
709 SetEvent(event);
710 CloseHandle(event);
712 if (pipe==INVALID_HANDLE_VALUE)
714 ERR("failed to create pipe for %s, error = %d\n",
715 debugstr_w(service->name), GetLastError());
716 return 0;
719 /* dispatcher loop */
720 while (1)
722 BOOL r;
723 DWORD count, req[2] = {0,0};
725 r = ConnectNamedPipe(pipe, NULL);
726 if (!r && GetLastError() != ERROR_PIPE_CONNECTED)
728 ERR("pipe connect failed\n");
729 break;
732 r = ReadFile( pipe, &req, sizeof req, &count, NULL );
733 if (!r || count!=sizeof req)
735 ERR("pipe read failed\n");
736 break;
739 service_reap_thread(service);
741 /* handle the request */
742 switch (req[0])
744 case WINESERV_STARTINFO:
745 service_handle_start(pipe, service, req[1]);
746 break;
747 case WINESERV_GETSTATUS:
748 service_handle_get_status(pipe, service);
749 break;
750 case WINESERV_SENDCONTROL:
751 service_handle_control(pipe, service, req[1]);
752 break;
753 case WINESERV_SETPID:
754 service_handle_set_processID(pipe, service, req[1]);
755 break;
756 default:
757 ERR("received invalid command %d length %d\n", req[0], req[1]);
760 FlushFileBuffers(pipe);
761 DisconnectNamedPipe(pipe);
764 CloseHandle(pipe);
765 return 1;
768 /******************************************************************************
769 * service_run_threads
771 static BOOL service_run_threads(void)
773 service_data *service;
774 DWORD count, n = 0;
775 HANDLE *handles;
777 EnterCriticalSection( &service_cs );
779 count = list_count( &service_list );
781 TRACE("starting %d pipe listener threads\n", count);
783 handles = HeapAlloc(GetProcessHeap(), 0, sizeof(HANDLE) * (count + 1));
785 handles[n++] = __wine_make_process_system();
787 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
788 handles[n++] = CreateThread( NULL, 0, service_control_dispatcher,
789 service, 0, NULL );
790 assert(n == count + 1);
792 LeaveCriticalSection( &service_cs );
794 /* wait for all the threads to pack up and exit */
795 while (n > 1)
797 DWORD ret = WaitForMultipleObjects( min(n,MAXIMUM_WAIT_OBJECTS), handles, FALSE, INFINITE );
798 if (!ret) /* system process event */
800 TRACE( "last user process exited, shutting down\n" );
801 /* FIXME: we should maybe send a shutdown control to running services */
802 ExitProcess(0);
804 if (ret < MAXIMUM_WAIT_OBJECTS)
806 CloseHandle( handles[ret] );
807 memmove( &handles[ret], &handles[ret+1], (n - ret - 1) * sizeof(HANDLE) );
808 n--;
810 else break;
813 while (n) CloseHandle( handles[--n] );
814 HeapFree(GetProcessHeap(), 0, handles);
816 return TRUE;
819 /******************************************************************************
820 * StartServiceCtrlDispatcherA [ADVAPI32.@]
822 * See StartServiceCtrlDispatcherW.
824 BOOL WINAPI StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *servent )
826 service_data *info;
827 DWORD sz, len;
828 BOOL ret = TRUE;
830 TRACE("%p\n", servent);
832 EnterCriticalSection( &service_cs );
833 while (servent->lpServiceName)
835 LPSTR name = servent->lpServiceName;
837 len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0);
838 sz = len*sizeof(WCHAR) + sizeof *info;
839 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
840 MultiByteToWideChar(CP_ACP, 0, name, -1, info->name, len);
841 info->proc.a = servent->lpServiceProc;
842 info->unicode = FALSE;
843 list_add_head( &service_list, &info->entry );
844 servent++;
846 LeaveCriticalSection( &service_cs );
848 service_run_threads();
850 return ret;
853 /******************************************************************************
854 * StartServiceCtrlDispatcherW [ADVAPI32.@]
856 * Connects a process containing one or more services to the service control
857 * manager.
859 * PARAMS
860 * servent [I] A list of the service names and service procedures
862 * RETURNS
863 * Success: TRUE.
864 * Failure: FALSE.
866 BOOL WINAPI StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW *servent )
868 service_data *info;
869 DWORD sz, len;
870 BOOL ret = TRUE;
872 TRACE("%p\n", servent);
874 EnterCriticalSection( &service_cs );
875 while (servent->lpServiceName)
877 LPWSTR name = servent->lpServiceName;
879 len = strlenW(name);
880 sz = len*sizeof(WCHAR) + sizeof *info;
881 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
882 strcpyW(info->name, name);
883 info->proc.w = servent->lpServiceProc;
884 info->unicode = TRUE;
885 list_add_head( &service_list, &info->entry );
886 servent++;
888 LeaveCriticalSection( &service_cs );
890 service_run_threads();
892 return ret;
895 /******************************************************************************
896 * LockServiceDatabase [ADVAPI32.@]
898 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
900 HANDLE ret;
902 TRACE("%p\n",hSCManager);
904 ret = CreateSemaphoreW( NULL, 1, 1, szSCMLock );
905 if( ret && GetLastError() == ERROR_ALREADY_EXISTS )
907 CloseHandle( ret );
908 ret = NULL;
909 SetLastError( ERROR_SERVICE_DATABASE_LOCKED );
912 TRACE("returning %p\n", ret);
914 return ret;
917 /******************************************************************************
918 * UnlockServiceDatabase [ADVAPI32.@]
920 BOOL WINAPI UnlockServiceDatabase (SC_LOCK ScLock)
922 TRACE("%p\n",ScLock);
924 return CloseHandle( ScLock );
927 /******************************************************************************
928 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
930 SERVICE_STATUS_HANDLE WINAPI
931 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName, LPHANDLER_FUNCTION lpfHandler )
933 LPWSTR lpServiceNameW;
934 SERVICE_STATUS_HANDLE ret;
936 lpServiceNameW = SERV_dup(lpServiceName);
937 ret = RegisterServiceCtrlHandlerW( lpServiceNameW, lpfHandler );
938 SERV_free(lpServiceNameW);
939 return ret;
942 /******************************************************************************
943 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
945 * PARAMS
946 * lpServiceName []
947 * lpfHandler []
949 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName,
950 LPHANDLER_FUNCTION lpfHandler )
952 service_data *service;
953 SERVICE_STATUS_HANDLE handle = 0;
955 EnterCriticalSection( &service_cs );
956 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
958 if(!strcmpW(lpServiceName, service->name))
960 service->handler.handler = lpfHandler;
961 handle = (SERVICE_STATUS_HANDLE)service;
962 break;
965 LeaveCriticalSection( &service_cs );
966 return handle;
969 /******************************************************************************
970 * SetServiceStatus [ADVAPI32.@]
972 * PARAMS
973 * hService []
974 * lpStatus []
976 BOOL WINAPI
977 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
979 service_data *service;
980 BOOL r = FALSE;
982 TRACE("%p %x %x %x %x %x %x %x\n", hService,
983 lpStatus->dwServiceType, lpStatus->dwCurrentState,
984 lpStatus->dwControlsAccepted, lpStatus->dwWin32ExitCode,
985 lpStatus->dwServiceSpecificExitCode, lpStatus->dwCheckPoint,
986 lpStatus->dwWaitHint);
988 EnterCriticalSection( &service_cs );
989 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
991 if(service == (service_data*)hService)
993 memcpy( &service->status, lpStatus, sizeof(SERVICE_STATUS) );
994 TRACE("Set service status to %d\n",service->status.dwCurrentState);
995 r = TRUE;
996 break;
999 LeaveCriticalSection( &service_cs );
1001 return r;
1005 /******************************************************************************
1006 * OpenSCManagerA [ADVAPI32.@]
1008 * Establish a connection to the service control manager and open its database.
1010 * PARAMS
1011 * lpMachineName [I] Pointer to machine name string
1012 * lpDatabaseName [I] Pointer to database name string
1013 * dwDesiredAccess [I] Type of access
1015 * RETURNS
1016 * Success: A Handle to the service control manager database
1017 * Failure: NULL
1019 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
1020 DWORD dwDesiredAccess )
1022 LPWSTR lpMachineNameW, lpDatabaseNameW;
1023 SC_HANDLE ret;
1025 lpMachineNameW = SERV_dup(lpMachineName);
1026 lpDatabaseNameW = SERV_dup(lpDatabaseName);
1027 ret = OpenSCManagerW(lpMachineNameW, lpDatabaseNameW, dwDesiredAccess);
1028 SERV_free(lpDatabaseNameW);
1029 SERV_free(lpMachineNameW);
1030 return ret;
1033 /******************************************************************************
1034 * OpenSCManagerW [ADVAPI32.@]
1036 * See OpenSCManagerA.
1038 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
1039 DWORD dwDesiredAccess )
1041 struct sc_manager *manager;
1042 HKEY hReg;
1043 LONG r;
1045 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName),
1046 debugstr_w(lpDatabaseName), dwDesiredAccess);
1048 if( lpDatabaseName && lpDatabaseName[0] )
1050 if( strcmpiW( lpDatabaseName, SERVICES_ACTIVE_DATABASEW ) == 0 )
1052 /* noop, all right */
1054 else if( strcmpiW( lpDatabaseName, SERVICES_FAILED_DATABASEW ) == 0 )
1056 SetLastError( ERROR_DATABASE_DOES_NOT_EXIST );
1057 return NULL;
1059 else
1061 SetLastError( ERROR_INVALID_NAME );
1062 return NULL;
1066 manager = sc_handle_alloc( SC_HTYPE_MANAGER, sizeof (struct sc_manager),
1067 sc_handle_destroy_manager );
1068 if (!manager)
1069 return NULL;
1071 r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
1072 if (r!=ERROR_SUCCESS)
1073 goto error;
1075 r = RegCreateKeyW(hReg, szServiceManagerKey, &manager->hkey);
1076 RegCloseKey( hReg );
1077 if (r!=ERROR_SUCCESS)
1078 goto error;
1080 manager->dwAccess = dwDesiredAccess;
1081 TRACE("returning %p\n", manager);
1083 return (SC_HANDLE) &manager->hdr;
1085 error:
1086 sc_handle_free( &manager->hdr );
1087 SetLastError( r);
1088 return NULL;
1091 /******************************************************************************
1092 * ControlService [ADVAPI32.@]
1094 * Send a control code to a service.
1096 * PARAMS
1097 * hService [I] Handle of the service control manager database
1098 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
1099 * lpServiceStatus [O] Destination for the status of the service, if available
1101 * RETURNS
1102 * Success: TRUE.
1103 * Failure: FALSE.
1105 * BUGS
1106 * Unlike M$' implementation, control requests are not serialized and may be
1107 * processed asynchronously.
1109 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
1110 LPSERVICE_STATUS lpServiceStatus )
1112 struct sc_service *hsvc;
1113 BOOL ret = FALSE;
1114 HANDLE handle;
1116 TRACE("%p %d %p\n", hService, dwControl, lpServiceStatus);
1118 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1119 if (!hsvc)
1121 SetLastError( ERROR_INVALID_HANDLE );
1122 return FALSE;
1125 ret = QueryServiceStatus(hService, lpServiceStatus);
1126 if (!ret)
1128 ERR("failed to query service status\n");
1129 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1130 return FALSE;
1133 switch (lpServiceStatus->dwCurrentState)
1135 case SERVICE_STOPPED:
1136 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1137 return FALSE;
1138 case SERVICE_START_PENDING:
1139 if (dwControl==SERVICE_CONTROL_STOP)
1140 break;
1141 /* fall thru */
1142 case SERVICE_STOP_PENDING:
1143 SetLastError(ERROR_SERVICE_CANNOT_ACCEPT_CTRL);
1144 return FALSE;
1147 handle = service_open_pipe(hsvc->name);
1148 if (handle!=INVALID_HANDLE_VALUE)
1150 DWORD result = ERROR_SUCCESS;
1151 ret = service_send_control(handle, dwControl, &result);
1152 CloseHandle(handle);
1153 if (result!=ERROR_SUCCESS)
1155 SetLastError(result);
1156 ret = FALSE;
1160 return ret;
1163 /******************************************************************************
1164 * CloseServiceHandle [ADVAPI32.@]
1166 * Close a handle to a service or the service control manager database.
1168 * PARAMS
1169 * hSCObject [I] Handle to service or service control manager database
1171 * RETURNS
1172 * Success: TRUE
1173 * Failure: FALSE
1175 BOOL WINAPI
1176 CloseServiceHandle( SC_HANDLE hSCObject )
1178 TRACE("%p\n", hSCObject);
1180 sc_handle_free( (struct sc_handle*) hSCObject );
1182 return TRUE;
1186 /******************************************************************************
1187 * OpenServiceA [ADVAPI32.@]
1189 * Open a handle to a service.
1191 * PARAMS
1192 * hSCManager [I] Handle of the service control manager database
1193 * lpServiceName [I] Name of the service to open
1194 * dwDesiredAccess [I] Access required to the service
1196 * RETURNS
1197 * Success: Handle to the service
1198 * Failure: NULL
1200 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1201 DWORD dwDesiredAccess )
1203 LPWSTR lpServiceNameW;
1204 SC_HANDLE ret;
1206 TRACE("%p %s %d\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
1208 lpServiceNameW = SERV_dup(lpServiceName);
1209 ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
1210 SERV_free(lpServiceNameW);
1211 return ret;
1215 /******************************************************************************
1216 * OpenServiceW [ADVAPI32.@]
1218 * See OpenServiceA.
1220 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1221 DWORD dwDesiredAccess)
1223 struct sc_manager *hscm;
1224 struct sc_service *hsvc;
1225 HKEY hKey;
1226 long r;
1227 DWORD len;
1229 TRACE("%p %s %d\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
1231 if (!lpServiceName)
1233 SetLastError(ERROR_INVALID_ADDRESS);
1234 return NULL;
1237 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1238 if (!hscm)
1240 SetLastError( ERROR_INVALID_HANDLE );
1241 return FALSE;
1244 r = RegOpenKeyExW( hscm->hkey, lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
1245 if (r!=ERROR_SUCCESS)
1247 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
1248 return NULL;
1251 len = strlenW(lpServiceName)+1;
1252 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE,
1253 sizeof (struct sc_service) + len*sizeof(WCHAR),
1254 sc_handle_destroy_service );
1255 if (!hsvc)
1256 return NULL;
1257 strcpyW( hsvc->name, lpServiceName );
1258 hsvc->hkey = hKey;
1259 hsvc->dwAccess = dwDesiredAccess;
1261 /* add reference to SCM handle */
1262 hscm->hdr.ref_count++;
1263 hsvc->scm = hscm;
1265 TRACE("returning %p\n",hsvc);
1267 return (SC_HANDLE) &hsvc->hdr;
1270 /******************************************************************************
1271 * CreateServiceW [ADVAPI32.@]
1273 SC_HANDLE WINAPI
1274 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1275 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
1276 DWORD dwServiceType, DWORD dwStartType,
1277 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1278 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1279 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
1280 LPCWSTR lpPassword )
1282 struct sc_manager *hscm;
1283 struct sc_service *hsvc = NULL;
1284 HKEY hKey;
1285 LONG r;
1286 DWORD dp, len;
1287 struct reg_value val[10];
1288 int n = 0;
1290 TRACE("%p %s %s\n", hSCManager,
1291 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
1293 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1294 if (!hscm)
1296 SetLastError( ERROR_INVALID_HANDLE );
1297 return NULL;
1300 r = RegCreateKeyExW(hscm->hkey, lpServiceName, 0, NULL,
1301 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
1302 if (r!=ERROR_SUCCESS)
1303 return NULL;
1305 if (dp != REG_CREATED_NEW_KEY)
1307 SetLastError(ERROR_SERVICE_EXISTS);
1308 goto error;
1311 if( lpDisplayName )
1312 service_set_string( &val[n++], szDisplayName, lpDisplayName );
1314 service_set_dword( &val[n++], szType, &dwServiceType );
1315 service_set_dword( &val[n++], szStart, &dwStartType );
1316 service_set_dword( &val[n++], szError, &dwErrorControl );
1318 if( lpBinaryPathName )
1319 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
1321 if( lpLoadOrderGroup )
1322 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
1324 /* FIXME: lpDependencies is used to create both DependOnService and DependOnGroup
1325 * There is no such key as what szDependencies refers to */
1326 if( lpDependencies )
1327 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
1329 if( lpPassword )
1330 FIXME("Don't know how to add a Password for a service.\n");
1332 if( lpServiceStartName )
1333 service_set_string( &val[n++], szObjectName, lpServiceStartName );
1335 r = service_write_values( hKey, val, n );
1336 if( r != ERROR_SUCCESS )
1337 goto error;
1339 len = strlenW(lpServiceName)+1;
1340 len = sizeof (struct sc_service) + len*sizeof(WCHAR);
1341 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE, len, sc_handle_destroy_service );
1342 if( !hsvc )
1343 goto error;
1344 lstrcpyW( hsvc->name, lpServiceName );
1345 hsvc->hkey = hKey;
1346 hsvc->scm = hscm;
1347 hscm->hdr.ref_count++;
1349 return (SC_HANDLE) &hsvc->hdr;
1351 error:
1352 RegCloseKey( hKey );
1353 return NULL;
1357 /******************************************************************************
1358 * CreateServiceA [ADVAPI32.@]
1360 SC_HANDLE WINAPI
1361 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1362 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1363 DWORD dwServiceType, DWORD dwStartType,
1364 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1365 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1366 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1367 LPCSTR lpPassword )
1369 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1370 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1371 SC_HANDLE r;
1373 TRACE("%p %s %s\n", hSCManager,
1374 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1376 lpServiceNameW = SERV_dup( lpServiceName );
1377 lpDisplayNameW = SERV_dup( lpDisplayName );
1378 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1379 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1380 lpDependenciesW = SERV_dupmulti( lpDependencies );
1381 lpServiceStartNameW = SERV_dup( lpServiceStartName );
1382 lpPasswordW = SERV_dup( lpPassword );
1384 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1385 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1386 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1387 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1389 SERV_free( lpServiceNameW );
1390 SERV_free( lpDisplayNameW );
1391 SERV_free( lpBinaryPathNameW );
1392 SERV_free( lpLoadOrderGroupW );
1393 SERV_free( lpDependenciesW );
1394 SERV_free( lpServiceStartNameW );
1395 SERV_free( lpPasswordW );
1397 return r;
1401 /******************************************************************************
1402 * DeleteService [ADVAPI32.@]
1404 * Delete a service from the service control manager database.
1406 * PARAMS
1407 * hService [I] Handle of the service to delete
1409 * RETURNS
1410 * Success: TRUE
1411 * Failure: FALSE
1413 BOOL WINAPI DeleteService( SC_HANDLE hService )
1415 struct sc_service *hsvc;
1416 HKEY hKey;
1417 WCHAR valname[MAX_PATH+1];
1418 INT index = 0;
1419 LONG rc;
1420 DWORD size;
1422 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1423 if (!hsvc)
1425 SetLastError( ERROR_INVALID_HANDLE );
1426 return FALSE;
1428 hKey = hsvc->hkey;
1430 size = MAX_PATH+1;
1431 /* Clean out the values */
1432 rc = RegEnumValueW(hKey, index, valname,&size,0,0,0,0);
1433 while (rc == ERROR_SUCCESS)
1435 RegDeleteValueW(hKey,valname);
1436 index++;
1437 size = MAX_PATH+1;
1438 rc = RegEnumValueW(hKey, index, valname, &size,0,0,0,0);
1441 RegCloseKey(hKey);
1442 hsvc->hkey = NULL;
1444 /* delete the key */
1445 RegDeleteKeyW(hsvc->scm->hkey, hsvc->name);
1447 return TRUE;
1451 /******************************************************************************
1452 * StartServiceA [ADVAPI32.@]
1454 * Start a service
1456 * PARAMS
1457 * hService [I] Handle of service
1458 * dwNumServiceArgs [I] Number of arguments
1459 * lpServiceArgVectors [I] Address of array of argument strings
1461 * NOTES
1462 * - NT implements this function using an obscure RPC call.
1463 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1464 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1465 * - This will only work for shared address space. How should the service
1466 * args be transferred when address spaces are separated?
1467 * - Can only start one service at a time.
1468 * - Has no concept of privilege.
1470 * RETURNS
1471 * Success: TRUE.
1472 * Failure: FALSE
1474 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1475 LPCSTR *lpServiceArgVectors )
1477 LPWSTR *lpwstr=NULL;
1478 unsigned int i;
1479 BOOL r;
1481 TRACE("(%p,%d,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1483 if (dwNumServiceArgs)
1484 lpwstr = HeapAlloc( GetProcessHeap(), 0,
1485 dwNumServiceArgs*sizeof(LPWSTR) );
1487 for(i=0; i<dwNumServiceArgs; i++)
1488 lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1490 r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1492 if (dwNumServiceArgs)
1494 for(i=0; i<dwNumServiceArgs; i++)
1495 SERV_free(lpwstr[i]);
1496 HeapFree(GetProcessHeap(), 0, lpwstr);
1499 return r;
1502 /******************************************************************************
1503 * service_start_process [INTERNAL]
1505 static DWORD service_start_process(struct sc_service *hsvc, LPDWORD ppid)
1507 static const WCHAR _ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0};
1508 PROCESS_INFORMATION pi;
1509 STARTUPINFOW si;
1510 LPWSTR path = NULL, str;
1511 DWORD type, size, ret, svc_type;
1512 HANDLE handles[2];
1513 BOOL r;
1515 size = sizeof(svc_type);
1516 if (RegQueryValueExW(hsvc->hkey, szType, NULL, &type, (LPBYTE)&svc_type, &size) || type != REG_DWORD)
1517 svc_type = 0;
1519 if (svc_type == SERVICE_KERNEL_DRIVER)
1521 static const WCHAR winedeviceW[] = {'\\','w','i','n','e','d','e','v','i','c','e','.','e','x','e',' ',0};
1522 DWORD len = GetSystemDirectoryW( NULL, 0 ) + sizeof(winedeviceW)/sizeof(WCHAR) + strlenW(hsvc->name);
1524 if (!(path = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return FALSE;
1525 GetSystemDirectoryW( path, len );
1526 lstrcatW( path, winedeviceW );
1527 lstrcatW( path, hsvc->name );
1529 else
1531 /* read the executable path from the registry */
1532 size = 0;
1533 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, NULL, &size);
1534 if (ret!=ERROR_SUCCESS)
1535 return FALSE;
1536 str = HeapAlloc(GetProcessHeap(),0,size);
1537 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, (LPBYTE)str, &size);
1538 if (ret==ERROR_SUCCESS)
1540 size = ExpandEnvironmentStringsW(str,NULL,0);
1541 path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
1542 ExpandEnvironmentStringsW(str,path,size);
1544 HeapFree(GetProcessHeap(),0,str);
1545 if (!path)
1546 return FALSE;
1549 /* wait for the process to start and set an event or terminate */
1550 handles[0] = service_get_event_handle( hsvc->name );
1551 ZeroMemory(&si, sizeof(STARTUPINFOW));
1552 si.cb = sizeof(STARTUPINFOW);
1553 r = CreateProcessW(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1554 if (r)
1556 if (ppid) *ppid = pi.dwProcessId;
1558 handles[1] = pi.hProcess;
1559 ret = WaitForMultipleObjectsEx(2, handles, FALSE, 30000, FALSE);
1560 if(ret != WAIT_OBJECT_0)
1562 SetLastError(ERROR_IO_PENDING);
1563 r = FALSE;
1566 CloseHandle( pi.hThread );
1567 CloseHandle( pi.hProcess );
1569 CloseHandle( handles[0] );
1570 HeapFree(GetProcessHeap(),0,path);
1571 return r;
1574 static BOOL service_wait_for_startup(SC_HANDLE hService)
1576 DWORD i;
1577 SERVICE_STATUS status;
1578 BOOL r = FALSE;
1580 TRACE("%p\n", hService);
1582 for (i=0; i<30; i++)
1584 status.dwCurrentState = 0;
1585 r = QueryServiceStatus(hService, &status);
1586 if (!r)
1587 break;
1588 if (status.dwCurrentState == SERVICE_RUNNING)
1590 TRACE("Service started successfully\n");
1591 break;
1593 r = FALSE;
1594 Sleep(1000);
1596 return r;
1599 /******************************************************************************
1600 * StartServiceW [ADVAPI32.@]
1602 * See StartServiceA.
1604 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1605 LPCWSTR *lpServiceArgVectors)
1607 struct sc_service *hsvc;
1608 BOOL r = FALSE;
1609 DWORD dwResult, dwProcessId = 0;
1610 SC_LOCK hLock;
1611 HANDLE handle = INVALID_HANDLE_VALUE;
1613 TRACE("%p %d %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1615 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1616 if (!hsvc)
1618 SetLastError(ERROR_INVALID_HANDLE);
1619 return r;
1622 hLock = LockServiceDatabase((SC_HANDLE)hsvc->scm);
1623 if (!hLock)
1624 return r;
1626 handle = service_open_pipe(hsvc->name);
1627 if (handle==INVALID_HANDLE_VALUE)
1629 /* start the service process */
1630 if (service_start_process(hsvc, &dwProcessId))
1631 handle = service_open_pipe(hsvc->name);
1634 if (handle != INVALID_HANDLE_VALUE)
1636 r = service_send_start_message(handle, lpServiceArgVectors, dwNumServiceArgs);
1637 CloseHandle(handle);
1640 handle = service_open_pipe(hsvc->name);
1641 if (handle != INVALID_HANDLE_VALUE)
1643 service_set_processID(handle, dwProcessId, &dwResult);
1644 CloseHandle(handle);
1647 UnlockServiceDatabase( hLock );
1649 TRACE("returning %d\n", r);
1651 if (r)
1652 service_wait_for_startup(hService);
1654 return r;
1657 /******************************************************************************
1658 * QueryServiceStatus [ADVAPI32.@]
1660 * PARAMS
1661 * hService [I] Handle to service to get information about
1662 * lpservicestatus [O] buffer to receive the status information for the service
1665 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1666 LPSERVICE_STATUS lpservicestatus)
1668 SERVICE_STATUS_PROCESS SvcStatusData;
1669 BOOL ret;
1671 TRACE("%p %p\n", hService, lpservicestatus);
1673 ret = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&SvcStatusData,
1674 sizeof(SERVICE_STATUS_PROCESS), NULL);
1675 if (ret) memcpy(lpservicestatus, &SvcStatusData, sizeof(SERVICE_STATUS)) ;
1676 return ret;
1680 /******************************************************************************
1681 * QueryServiceStatusEx [ADVAPI32.@]
1683 * Get information about a service.
1685 * PARAMS
1686 * hService [I] Handle to service to get information about
1687 * InfoLevel [I] Level of information to get
1688 * lpBuffer [O] Destination for requested information
1689 * cbBufSize [I] Size of lpBuffer in bytes
1690 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1692 * RETURNS
1693 * Success: TRUE
1694 * FAILURE: FALSE
1696 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1697 LPBYTE lpBuffer, DWORD cbBufSize,
1698 LPDWORD pcbBytesNeeded)
1700 struct sc_service *hsvc;
1701 DWORD size, type, val;
1702 HANDLE pipe;
1703 LONG r;
1704 LPSERVICE_STATUS_PROCESS pSvcStatusData;
1706 TRACE("%p %d %p %d %p\n", hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1708 if (InfoLevel != SC_STATUS_PROCESS_INFO)
1710 SetLastError( ERROR_INVALID_LEVEL);
1711 return FALSE;
1714 pSvcStatusData = (LPSERVICE_STATUS_PROCESS) lpBuffer;
1715 if (pSvcStatusData == NULL)
1717 SetLastError( ERROR_INVALID_PARAMETER);
1718 return FALSE;
1721 if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
1723 if( pcbBytesNeeded != NULL)
1724 *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
1726 SetLastError( ERROR_INSUFFICIENT_BUFFER);
1727 return FALSE;
1730 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1731 if (!hsvc)
1733 SetLastError( ERROR_INVALID_HANDLE );
1734 return FALSE;
1737 pipe = service_open_pipe(hsvc->name);
1738 if (pipe != INVALID_HANDLE_VALUE)
1740 r = service_get_status(pipe, pSvcStatusData);
1741 CloseHandle(pipe);
1742 if (r)
1743 return TRUE;
1746 TRACE("Failed to read service status\n");
1748 /* read the service type from the registry */
1749 size = sizeof(val);
1750 r = RegQueryValueExA(hsvc->hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1751 if (r != ERROR_SUCCESS || type != REG_DWORD)
1752 val = 0;
1754 pSvcStatusData->dwServiceType = val;
1755 pSvcStatusData->dwCurrentState = SERVICE_STOPPED; /* stopped */
1756 pSvcStatusData->dwControlsAccepted = 0;
1757 pSvcStatusData->dwWin32ExitCode = ERROR_SERVICE_NEVER_STARTED;
1758 pSvcStatusData->dwServiceSpecificExitCode = 0;
1759 pSvcStatusData->dwCheckPoint = 0;
1760 pSvcStatusData->dwWaitHint = 0;
1762 return TRUE;
1765 /******************************************************************************
1766 * QueryServiceConfigA [ADVAPI32.@]
1768 BOOL WINAPI QueryServiceConfigA( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGA config,
1769 DWORD size, LPDWORD needed )
1771 DWORD n;
1772 LPSTR p, buffer;
1773 BOOL ret;
1774 QUERY_SERVICE_CONFIGW *configW;
1776 TRACE("%p %p %d %p\n", hService, config, size, needed);
1778 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, 2 * size )))
1780 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1781 return FALSE;
1783 configW = (QUERY_SERVICE_CONFIGW *)buffer;
1784 ret = QueryServiceConfigW( hService, configW, 2 * size, needed );
1785 if (!ret) goto done;
1787 config->dwServiceType = configW->dwServiceType;
1788 config->dwStartType = configW->dwStartType;
1789 config->dwErrorControl = configW->dwErrorControl;
1790 config->lpBinaryPathName = NULL;
1791 config->lpLoadOrderGroup = NULL;
1792 config->dwTagId = configW->dwTagId;
1793 config->lpDependencies = NULL;
1794 config->lpServiceStartName = NULL;
1795 config->lpDisplayName = NULL;
1797 p = (LPSTR)(config + 1);
1798 n = size - sizeof(*config);
1799 ret = FALSE;
1801 #define MAP_STR(str) \
1802 do { \
1803 if (configW->str) \
1805 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1806 if (!sz) goto done; \
1807 config->str = p; \
1808 p += sz; \
1809 n -= sz; \
1811 } while (0)
1813 MAP_STR( lpBinaryPathName );
1814 MAP_STR( lpLoadOrderGroup );
1815 MAP_STR( lpDependencies );
1816 MAP_STR( lpServiceStartName );
1817 MAP_STR( lpDisplayName );
1818 #undef MAP_STR
1820 *needed = p - (LPSTR)config;
1821 ret = TRUE;
1823 done:
1824 HeapFree( GetProcessHeap(), 0, buffer );
1825 return ret;
1828 /******************************************************************************
1829 * QueryServiceConfigW [ADVAPI32.@]
1831 BOOL WINAPI
1832 QueryServiceConfigW( SC_HANDLE hService,
1833 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1834 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1836 WCHAR str_buffer[ MAX_PATH ];
1837 LONG r;
1838 DWORD type, val, sz, total, n;
1839 LPBYTE p;
1840 HKEY hKey;
1841 struct sc_service *hsvc;
1843 TRACE("%p %p %d %p\n", hService, lpServiceConfig,
1844 cbBufSize, pcbBytesNeeded);
1846 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1847 if (!hsvc)
1849 SetLastError( ERROR_INVALID_HANDLE );
1850 return FALSE;
1852 hKey = hsvc->hkey;
1854 /* TODO: Check which members are mandatory and what the registry types
1855 * should be. This should of course also be tested when a service is
1856 * created.
1859 /* calculate the size required first */
1860 total = sizeof (QUERY_SERVICE_CONFIGW);
1862 sz = sizeof(str_buffer);
1863 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1864 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1866 sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1867 if( 0 == sz ) return FALSE;
1869 total += sizeof(WCHAR) * sz;
1871 else
1873 /* FIXME: set last error */
1874 return FALSE;
1877 sz = 0;
1878 r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1879 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1880 total += sz;
1881 else
1882 total += sizeof(WCHAR);
1884 sz = 0;
1885 r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1886 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1887 total += sz;
1888 else
1889 total += sizeof(WCHAR);
1891 sz = 0;
1892 r = RegQueryValueExW( hKey, szObjectName, 0, &type, NULL, &sz );
1893 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1894 total += sz;
1895 else
1896 total += sizeof(WCHAR);
1898 sz = 0;
1899 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1900 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1901 total += sz;
1902 else
1903 total += sizeof(WCHAR);
1905 *pcbBytesNeeded = total;
1907 /* if there's not enough memory, return an error */
1908 if( total > cbBufSize )
1910 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1911 return FALSE;
1914 ZeroMemory( lpServiceConfig, total );
1916 sz = sizeof val;
1917 r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1918 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
1919 lpServiceConfig->dwServiceType = val;
1921 sz = sizeof val;
1922 r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1923 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
1924 lpServiceConfig->dwStartType = val;
1926 sz = sizeof val;
1927 r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1928 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
1929 lpServiceConfig->dwErrorControl = val;
1931 sz = sizeof val;
1932 r = RegQueryValueExW( hKey, szTag, 0, &type, (LPBYTE)&val, &sz );
1933 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
1934 lpServiceConfig->dwTagId = val;
1936 /* now do the strings */
1937 p = (LPBYTE) &lpServiceConfig[1];
1938 n = total - sizeof (QUERY_SERVICE_CONFIGW);
1940 sz = sizeof(str_buffer);
1941 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1942 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1944 sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
1945 sz *= sizeof(WCHAR);
1946 if( 0 == sz || sz > n ) return FALSE;
1948 lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
1949 p += sz;
1950 n -= sz;
1952 else
1954 /* FIXME: set last error */
1955 return FALSE;
1958 sz = n;
1959 r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
1960 lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
1961 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1963 p += sz;
1964 n -= sz;
1966 else
1968 *(WCHAR *) p = 0;
1969 p += sizeof(WCHAR);
1970 n -= sizeof(WCHAR);
1973 sz = n;
1974 r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
1975 lpServiceConfig->lpDependencies = (LPWSTR) p;
1976 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1978 p += sz;
1979 n -= sz;
1981 else
1983 *(WCHAR *) p = 0;
1984 p += sizeof(WCHAR);
1985 n -= sizeof(WCHAR);
1988 sz = n;
1989 r = RegQueryValueExW( hKey, szObjectName, 0, &type, p, &sz );
1990 lpServiceConfig->lpServiceStartName = (LPWSTR) p;
1991 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1993 p += sz;
1994 n -= sz;
1996 else
1998 *(WCHAR *) p = 0;
1999 p += sizeof(WCHAR);
2000 n -= sizeof(WCHAR);
2003 sz = n;
2004 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, p, &sz );
2005 lpServiceConfig->lpDisplayName = (LPWSTR) p;
2006 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2008 p += sz;
2009 n -= sz;
2011 else
2013 *(WCHAR *) p = 0;
2014 p += sizeof(WCHAR);
2015 n -= sizeof(WCHAR);
2018 if( n < 0 )
2019 ERR("Buffer overflow!\n");
2021 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
2022 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
2023 TRACE("Dependencies = %s\n", debugstr_w(lpServiceConfig->lpDependencies) );
2024 TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig->lpServiceStartName) );
2025 TRACE("Display name = %s\n", debugstr_w(lpServiceConfig->lpDisplayName) );
2027 return TRUE;
2030 /******************************************************************************
2031 * EnumServicesStatusA [ADVAPI32.@]
2033 BOOL WINAPI
2034 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
2035 DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
2036 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2037 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
2039 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
2040 dwServiceType, dwServiceState, lpServices, cbBufSize,
2041 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
2042 SetLastError (ERROR_ACCESS_DENIED);
2043 return FALSE;
2046 /******************************************************************************
2047 * EnumServicesStatusW [ADVAPI32.@]
2049 BOOL WINAPI
2050 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
2051 DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
2052 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2053 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
2055 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
2056 dwServiceType, dwServiceState, lpServices, cbBufSize,
2057 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
2058 SetLastError (ERROR_ACCESS_DENIED);
2059 return FALSE;
2062 /******************************************************************************
2063 * EnumServicesStatusExA [ADVAPI32.@]
2065 BOOL WINAPI
2066 EnumServicesStatusExA(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
2067 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2068 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCSTR pszGroupName)
2070 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
2071 dwServiceType, dwServiceState, lpServices, cbBufSize,
2072 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_a(pszGroupName));
2073 SetLastError (ERROR_ACCESS_DENIED);
2074 return FALSE;
2077 /******************************************************************************
2078 * EnumServicesStatusExW [ADVAPI32.@]
2080 BOOL WINAPI
2081 EnumServicesStatusExW(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
2082 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2083 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCWSTR pszGroupName)
2085 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
2086 dwServiceType, dwServiceState, lpServices, cbBufSize,
2087 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_w(pszGroupName));
2088 SetLastError (ERROR_ACCESS_DENIED);
2089 return FALSE;
2092 /******************************************************************************
2093 * GetServiceKeyNameA [ADVAPI32.@]
2095 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
2096 LPSTR lpServiceName, LPDWORD lpcchBuffer )
2098 FIXME("%p %s %p %p\n", hSCManager, debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
2099 return FALSE;
2102 /******************************************************************************
2103 * GetServiceKeyNameW [ADVAPI32.@]
2105 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
2106 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
2108 FIXME("%p %s %p %p\n", hSCManager, debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
2109 return FALSE;
2112 /******************************************************************************
2113 * QueryServiceLockStatusA [ADVAPI32.@]
2115 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
2116 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
2117 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2119 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2121 return FALSE;
2124 /******************************************************************************
2125 * QueryServiceLockStatusW [ADVAPI32.@]
2127 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
2128 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2129 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2131 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2133 return FALSE;
2136 /******************************************************************************
2137 * GetServiceDisplayNameA [ADVAPI32.@]
2139 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
2140 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
2142 struct sc_manager *hscm;
2143 DWORD type, size;
2144 LONG ret;
2146 TRACE("%p %s %p %p\n", hSCManager,
2147 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
2149 if (!lpServiceName)
2151 SetLastError(ERROR_INVALID_PARAMETER);
2152 return FALSE;
2155 hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
2156 if (!hscm)
2158 SetLastError(ERROR_INVALID_HANDLE);
2159 return FALSE;
2162 size = *lpcchBuffer;
2163 ret = RegGetValueA(hscm->hkey, lpServiceName, "DisplayName", RRF_RT_REG_SZ, &type, lpDisplayName, &size);
2164 if (!ret && !lpDisplayName && size)
2165 ret = ERROR_MORE_DATA;
2167 if (ret)
2169 if (lpDisplayName && *lpcchBuffer) *lpDisplayName = 0;
2171 if (ret == ERROR_MORE_DATA)
2173 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2174 *lpcchBuffer = size - 1;
2176 else
2177 SetLastError(ret);
2178 return FALSE;
2180 return TRUE;
2183 /******************************************************************************
2184 * GetServiceDisplayNameW [ADVAPI32.@]
2186 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
2187 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
2189 struct sc_manager *hscm;
2190 DWORD type, size;
2191 LONG ret;
2193 TRACE("%p %s %p %p\n", hSCManager,
2194 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
2196 if (!lpServiceName)
2198 SetLastError(ERROR_INVALID_PARAMETER);
2199 return FALSE;
2202 hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
2203 if (!hscm)
2205 SetLastError(ERROR_INVALID_HANDLE);
2206 return FALSE;
2209 size = *lpcchBuffer * sizeof(WCHAR);
2210 ret = RegGetValueW(hscm->hkey, lpServiceName, szDisplayName, RRF_RT_REG_SZ, &type, lpDisplayName, &size);
2211 if (!ret && !lpDisplayName && size)
2212 ret = ERROR_MORE_DATA;
2214 if (ret)
2216 if (lpDisplayName && *lpcchBuffer) *lpDisplayName = 0;
2218 if (ret == ERROR_MORE_DATA)
2220 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2221 *lpcchBuffer = (size / sizeof(WCHAR)) - 1;
2223 else
2224 SetLastError(ret);
2225 return FALSE;
2227 return TRUE;
2230 /******************************************************************************
2231 * ChangeServiceConfigW [ADVAPI32.@]
2233 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
2234 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
2235 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
2236 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
2238 struct reg_value val[10];
2239 struct sc_service *hsvc;
2240 DWORD r = ERROR_SUCCESS;
2241 HKEY hKey;
2242 int n = 0;
2244 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2245 hService, dwServiceType, dwStartType, dwErrorControl,
2246 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2247 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2248 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2250 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2251 if (!hsvc)
2253 SetLastError( ERROR_INVALID_HANDLE );
2254 return FALSE;
2256 hKey = hsvc->hkey;
2258 if( dwServiceType != SERVICE_NO_CHANGE )
2259 service_set_dword( &val[n++], szType, &dwServiceType );
2261 if( dwStartType != SERVICE_NO_CHANGE )
2262 service_set_dword( &val[n++], szStart, &dwStartType );
2264 if( dwErrorControl != SERVICE_NO_CHANGE )
2265 service_set_dword( &val[n++], szError, &dwErrorControl );
2267 if( lpBinaryPathName )
2268 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
2270 if( lpLoadOrderGroup )
2271 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
2273 /* FIXME: lpDependencies is used to create/change both DependOnService and DependOnGroup
2274 * There is no such key as what szDependencies refers to */
2275 if( lpDependencies )
2276 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
2278 if( lpPassword )
2279 FIXME("ignoring password\n");
2281 if( lpServiceStartName )
2282 service_set_string( &val[n++], szObjectName, lpServiceStartName );
2284 r = service_write_values( hsvc->hkey, val, n );
2286 return (r == ERROR_SUCCESS) ? TRUE : FALSE ;
2289 /******************************************************************************
2290 * ChangeServiceConfigA [ADVAPI32.@]
2292 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2293 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2294 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2295 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2297 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2298 LPWSTR wServiceStartName, wPassword, wDisplayName;
2299 BOOL r;
2301 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2302 hService, dwServiceType, dwStartType, dwErrorControl,
2303 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2304 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2305 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2307 wBinaryPathName = SERV_dup( lpBinaryPathName );
2308 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2309 wDependencies = SERV_dupmulti( lpDependencies );
2310 wServiceStartName = SERV_dup( lpServiceStartName );
2311 wPassword = SERV_dup( lpPassword );
2312 wDisplayName = SERV_dup( lpDisplayName );
2314 r = ChangeServiceConfigW( hService, dwServiceType,
2315 dwStartType, dwErrorControl, wBinaryPathName,
2316 wLoadOrderGroup, lpdwTagId, wDependencies,
2317 wServiceStartName, wPassword, wDisplayName);
2319 SERV_free( wBinaryPathName );
2320 SERV_free( wLoadOrderGroup );
2321 SERV_free( wDependencies );
2322 SERV_free( wServiceStartName );
2323 SERV_free( wPassword );
2324 SERV_free( wDisplayName );
2326 return r;
2329 /******************************************************************************
2330 * ChangeServiceConfig2A [ADVAPI32.@]
2332 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2333 LPVOID lpInfo)
2335 BOOL r = FALSE;
2337 TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo);
2339 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2341 LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
2342 SERVICE_DESCRIPTIONW sdw;
2344 sdw.lpDescription = SERV_dup( sd->lpDescription );
2346 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2348 SERV_free( sdw.lpDescription );
2350 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2352 LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
2353 SERVICE_FAILURE_ACTIONSW faw;
2355 faw.dwResetPeriod = fa->dwResetPeriod;
2356 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2357 faw.lpCommand = SERV_dup( fa->lpCommand );
2358 faw.cActions = fa->cActions;
2359 faw.lpsaActions = fa->lpsaActions;
2361 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2363 SERV_free( faw.lpRebootMsg );
2364 SERV_free( faw.lpCommand );
2366 else
2367 SetLastError( ERROR_INVALID_PARAMETER );
2369 return r;
2372 /******************************************************************************
2373 * ChangeServiceConfig2W [ADVAPI32.@]
2375 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2376 LPVOID lpInfo)
2378 HKEY hKey;
2379 struct sc_service *hsvc;
2381 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2382 if (!hsvc)
2384 SetLastError( ERROR_INVALID_HANDLE );
2385 return FALSE;
2387 hKey = hsvc->hkey;
2389 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2391 static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2392 LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
2393 if (sd->lpDescription)
2395 TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
2396 if (sd->lpDescription[0] == 0)
2397 RegDeleteValueW(hKey,szDescription);
2398 else
2399 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2400 (LPVOID)sd->lpDescription,
2401 sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2404 else
2405 FIXME("STUB: %p %d %p\n",hService, dwInfoLevel, lpInfo);
2406 return TRUE;
2409 /******************************************************************************
2410 * QueryServiceObjectSecurity [ADVAPI32.@]
2412 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2413 SECURITY_INFORMATION dwSecurityInformation,
2414 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2415 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2417 PACL pACL = NULL;
2419 FIXME("%p %d %p %u %p\n", hService, dwSecurityInformation,
2420 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2422 InitializeSecurityDescriptor(lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
2424 pACL = HeapAlloc( GetProcessHeap(), 0, sizeof(ACL) );
2425 InitializeAcl(pACL, sizeof(ACL), ACL_REVISION);
2426 SetSecurityDescriptorDacl(lpSecurityDescriptor, TRUE, pACL, TRUE);
2427 return TRUE;
2430 /******************************************************************************
2431 * SetServiceObjectSecurity [ADVAPI32.@]
2433 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2434 SECURITY_INFORMATION dwSecurityInformation,
2435 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2437 FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2438 return TRUE;
2441 /******************************************************************************
2442 * SetServiceBits [ADVAPI32.@]
2444 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2445 DWORD dwServiceBits,
2446 BOOL bSetBitsOn,
2447 BOOL bUpdateImmediately)
2449 FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2450 bSetBitsOn, bUpdateImmediately);
2451 return TRUE;
2454 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR lpServiceName,
2455 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2457 FIXME("%s %p %p\n", debugstr_a(lpServiceName), lpHandlerProc, lpContext);
2458 return 0;
2461 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2462 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2464 service_data *service;
2465 SERVICE_STATUS_HANDLE handle = 0;
2467 TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2469 EnterCriticalSection( &service_cs );
2470 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
2472 if(!strcmpW(lpServiceName, service->name))
2474 service->handler.handler_ex = lpHandlerProc;
2475 service->context = lpContext;
2476 service->extended = TRUE;
2477 handle = (SERVICE_STATUS_HANDLE)service;
2478 break;
2481 LeaveCriticalSection( &service_cs );
2483 return handle;