advapi/service: Fix possible handle leak.
[wine/testsucceed.git] / dlls / advapi32 / service.c
blob55e9716db6f783c62c154b063f1c1a0f15543789
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 static const GENERIC_MAPPING scm_generic = {
49 (STANDARD_RIGHTS_READ | SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_QUERY_LOCK_STATUS),
50 (STANDARD_RIGHTS_WRITE | SC_MANAGER_CREATE_SERVICE | SC_MANAGER_MODIFY_BOOT_CONFIG),
51 (STANDARD_RIGHTS_EXECUTE | SC_MANAGER_CONNECT | SC_MANAGER_LOCK),
52 SC_MANAGER_ALL_ACCESS
55 typedef struct service_start_info_t
57 DWORD cmd;
58 DWORD size;
59 WCHAR str[1];
60 } service_start_info;
62 #define WINESERV_STARTINFO 1
63 #define WINESERV_GETSTATUS 2
64 #define WINESERV_SENDCONTROL 3
65 #define WINESERV_SETPID 4
67 typedef struct service_data_t
69 struct list entry;
70 union {
71 LPHANDLER_FUNCTION handler;
72 LPHANDLER_FUNCTION_EX handler_ex;
73 } handler;
74 LPVOID context;
75 SERVICE_STATUS_PROCESS status;
76 HANDLE thread;
77 BOOL unicode : 1;
78 BOOL extended : 1; /* uses handler_ex instead of handler? */
79 union {
80 LPSERVICE_MAIN_FUNCTIONA a;
81 LPSERVICE_MAIN_FUNCTIONW w;
82 } proc;
83 LPWSTR args;
84 WCHAR name[1];
85 } service_data;
87 static CRITICAL_SECTION service_cs;
88 static CRITICAL_SECTION_DEBUG service_cs_debug =
90 0, 0, &service_cs,
91 { &service_cs_debug.ProcessLocksList,
92 &service_cs_debug.ProcessLocksList },
93 0, 0, { (DWORD_PTR)(__FILE__ ": service_cs") }
95 static CRITICAL_SECTION service_cs = { &service_cs_debug, -1, 0, 0, 0, 0 };
97 static struct list service_list = LIST_INIT(service_list);
99 extern HANDLE __wine_make_process_system(void);
101 /******************************************************************************
102 * SC_HANDLEs
105 #define MAX_SERVICE_NAME 256
107 typedef enum { SC_HTYPE_MANAGER, SC_HTYPE_SERVICE } SC_HANDLE_TYPE;
109 struct sc_handle;
110 typedef VOID (*sc_handle_destructor)(struct sc_handle *);
112 struct sc_handle
114 SC_HANDLE_TYPE htype;
115 DWORD ref_count;
116 sc_handle_destructor destroy;
119 struct sc_manager /* service control manager handle */
121 struct sc_handle hdr;
122 HKEY hkey; /* handle to services database in the registry */
123 DWORD dwAccess;
126 struct sc_service /* service handle */
128 struct sc_handle hdr;
129 HKEY hkey; /* handle to service entry in the registry (under hkey) */
130 DWORD dwAccess;
131 struct sc_manager *scm; /* pointer to SCM handle */
132 WCHAR name[1];
135 static void *sc_handle_alloc(SC_HANDLE_TYPE htype, DWORD size,
136 sc_handle_destructor destroy)
138 struct sc_handle *hdr;
140 hdr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
141 if (hdr)
143 hdr->htype = htype;
144 hdr->ref_count = 1;
145 hdr->destroy = destroy;
147 TRACE("sc_handle type=%d -> %p\n", htype, hdr);
148 return hdr;
151 static void *sc_handle_get_handle_data(SC_HANDLE handle, DWORD htype)
153 struct sc_handle *hdr = (struct sc_handle *) handle;
155 if (!hdr)
156 return NULL;
157 if (hdr->htype != htype)
158 return NULL;
159 return hdr;
162 static void sc_handle_free(struct sc_handle* hdr)
164 if (!hdr)
165 return;
166 if (--hdr->ref_count)
167 return;
168 hdr->destroy(hdr);
169 HeapFree(GetProcessHeap(), 0, hdr);
172 static void sc_handle_destroy_manager(struct sc_handle *handle)
174 struct sc_manager *mgr = (struct sc_manager*) handle;
176 TRACE("destroying SC Manager %p\n", mgr);
177 if (mgr->hkey)
178 RegCloseKey(mgr->hkey);
181 static void sc_handle_destroy_service(struct sc_handle *handle)
183 struct sc_service *svc = (struct sc_service*) handle;
185 TRACE("destroying service %p\n", svc);
186 if (svc->hkey)
187 RegCloseKey(svc->hkey);
188 svc->hkey = NULL;
189 sc_handle_free(&svc->scm->hdr);
190 svc->scm = NULL;
193 /******************************************************************************
194 * String management functions
196 static inline LPWSTR SERV_dup( LPCSTR str )
198 UINT len;
199 LPWSTR wstr;
201 if( !str )
202 return NULL;
203 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
204 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
205 MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
206 return wstr;
209 static inline LPWSTR SERV_dupmulti(LPCSTR str)
211 UINT len = 0, n = 0;
212 LPWSTR wstr;
214 if( !str )
215 return NULL;
216 do {
217 len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
218 n += (strlen( &str[n] ) + 1);
219 } while (str[n]);
220 len++;
221 n++;
223 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
224 MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
225 return wstr;
228 static inline VOID SERV_free( LPWSTR wstr )
230 HeapFree( GetProcessHeap(), 0, wstr );
233 /******************************************************************************
234 * registry access functions and data
236 static const WCHAR szDisplayName[] = {
237 'D','i','s','p','l','a','y','N','a','m','e', 0 };
238 static const WCHAR szType[] = {'T','y','p','e',0};
239 static const WCHAR szStart[] = {'S','t','a','r','t',0};
240 static const WCHAR szError[] = {
241 'E','r','r','o','r','C','o','n','t','r','o','l', 0};
242 static const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
243 static const WCHAR szGroup[] = {'G','r','o','u','p',0};
244 static const WCHAR szDependencies[] = {
245 'D','e','p','e','n','d','e','n','c','i','e','s',0};
246 static const WCHAR szDependOnService[] = {
247 'D','e','p','e','n','d','O','n','S','e','r','v','i','c','e',0};
248 static const WCHAR szObjectName[] = {
249 'O','b','j','e','c','t','N','a','m','e',0};
250 static const WCHAR szTag[] = {
251 'T','a','g',0};
253 struct reg_value {
254 DWORD type;
255 DWORD size;
256 LPCWSTR name;
257 LPCVOID data;
260 static inline void service_set_value( struct reg_value *val,
261 DWORD type, LPCWSTR name, LPCVOID data, DWORD size )
263 val->name = name;
264 val->type = type;
265 val->data = data;
266 val->size = size;
269 static inline void service_set_dword( struct reg_value *val,
270 LPCWSTR name, const DWORD *data )
272 service_set_value( val, REG_DWORD, name, data, sizeof (DWORD));
275 static inline void service_set_string( struct reg_value *val,
276 LPCWSTR name, LPCWSTR string )
278 DWORD len = (lstrlenW(string)+1) * sizeof (WCHAR);
279 service_set_value( val, REG_SZ, name, string, len );
282 static inline void service_set_multi_string( struct reg_value *val,
283 LPCWSTR name, LPCWSTR string )
285 DWORD len = 0;
287 /* determine the length of a double null terminated multi string */
288 do {
289 len += (lstrlenW( &string[ len ] )+1);
290 } while ( string[ len++ ] );
292 len *= sizeof (WCHAR);
293 service_set_value( val, REG_MULTI_SZ, name, string, len );
296 static inline LONG service_write_values( HKEY hKey,
297 const struct reg_value *val, int n )
299 LONG r = ERROR_SUCCESS;
300 int i;
302 for( i=0; i<n; i++ )
304 r = RegSetValueExW(hKey, val[i].name, 0, val[i].type,
305 (const BYTE*)val[i].data, val[i].size );
306 if( r != ERROR_SUCCESS )
307 break;
309 return r;
312 /******************************************************************************
313 * Service IPC functions
315 static LPWSTR service_get_pipe_name(LPCWSTR service)
317 static const WCHAR prefix[] = { '\\','\\','.','\\','p','i','p','e','\\',
318 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
319 LPWSTR name;
320 DWORD len;
322 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
323 name = HeapAlloc(GetProcessHeap(), 0, len);
324 strcpyW(name, prefix);
325 strcatW(name, service);
326 return name;
329 static HANDLE service_open_pipe(LPCWSTR service)
331 LPWSTR szPipe = service_get_pipe_name( service );
332 HANDLE handle = INVALID_HANDLE_VALUE;
334 do {
335 handle = CreateFileW(szPipe, GENERIC_READ|GENERIC_WRITE,
336 0, NULL, OPEN_ALWAYS, 0, NULL);
337 if (handle != INVALID_HANDLE_VALUE)
338 break;
339 if (GetLastError() != ERROR_PIPE_BUSY)
340 break;
341 } while (WaitNamedPipeW(szPipe, NMPWAIT_WAIT_FOREVER));
342 SERV_free(szPipe);
344 return handle;
347 /******************************************************************************
348 * service_get_event_handle
350 static HANDLE service_get_event_handle(LPCWSTR service)
352 static const WCHAR prefix[] = {
353 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
354 LPWSTR name;
355 DWORD len;
356 HANDLE handle;
358 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
359 name = HeapAlloc(GetProcessHeap(), 0, len);
360 strcpyW(name, prefix);
361 strcatW(name, service);
362 handle = CreateEventW(NULL, TRUE, FALSE, name);
363 SERV_free(name);
364 return handle;
367 /******************************************************************************
368 * service_thread
370 * Call into the main service routine provided by StartServiceCtrlDispatcher.
372 static DWORD WINAPI service_thread(LPVOID arg)
374 service_data *info = arg;
375 LPWSTR str = info->args;
376 DWORD argc = 0, len = 0;
378 TRACE("%p\n", arg);
380 while (str[len])
382 len += strlenW(&str[len]) + 1;
383 argc++;
386 if (!argc)
388 if (info->unicode)
389 info->proc.w(0, NULL);
390 else
391 info->proc.a(0, NULL);
392 return 0;
395 if (info->unicode)
397 LPWSTR *argv, p;
399 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPWSTR));
400 for (argc=0, p=str; *p; p += strlenW(p) + 1)
401 argv[argc++] = p;
402 argv[argc] = NULL;
404 info->proc.w(argc, argv);
405 HeapFree(GetProcessHeap(), 0, argv);
407 else
409 LPSTR strA, *argv, p;
410 DWORD lenA;
412 lenA = WideCharToMultiByte(CP_ACP,0, str, len, NULL, 0, NULL, NULL);
413 strA = HeapAlloc(GetProcessHeap(), 0, lenA);
414 WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL);
416 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPSTR));
417 for (argc=0, p=strA; *p; p += strlen(p) + 1)
418 argv[argc++] = p;
419 argv[argc] = NULL;
421 info->proc.a(argc, argv);
422 HeapFree(GetProcessHeap(), 0, argv);
423 HeapFree(GetProcessHeap(), 0, strA);
425 return 0;
428 /******************************************************************************
429 * service_handle_start
431 static BOOL service_handle_start(HANDLE pipe, service_data *service, DWORD count)
433 DWORD read = 0, result = 0;
434 LPWSTR args;
435 BOOL r;
437 TRACE("%p %p %d\n", pipe, service, count);
439 args = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
440 r = ReadFile(pipe, args, count*sizeof(WCHAR), &read, NULL);
441 if (!r || count!=read/sizeof(WCHAR) || args[count-1])
443 ERR("pipe read failed r = %d count = %d read = %d args[n-1]=%s\n",
444 r, count, read, debugstr_wn(args, count));
445 goto end;
448 if (service->thread)
450 ERR("service is not stopped\n");
451 goto end;
454 SERV_free(service->args);
455 service->args = args;
456 args = NULL;
457 service->thread = CreateThread( NULL, 0, service_thread,
458 service, 0, NULL );
460 end:
461 HeapFree(GetProcessHeap(), 0, args);
462 WriteFile( pipe, &result, sizeof result, &read, NULL );
464 return TRUE;
467 /******************************************************************************
468 * service_send_start_message
470 static BOOL service_send_start_message(HANDLE pipe, LPCWSTR *argv, DWORD argc)
472 DWORD i, len, count, result;
473 service_start_info *ssi;
474 LPWSTR p;
475 BOOL r;
477 TRACE("%p %p %d\n", pipe, argv, argc);
479 /* calculate how much space do we need to send the startup info */
480 len = 1;
481 for (i=0; i<argc; i++)
482 len += strlenW(argv[i])+1;
484 ssi = HeapAlloc(GetProcessHeap(),0,sizeof *ssi + (len-1)*sizeof(WCHAR));
485 ssi->cmd = WINESERV_STARTINFO;
486 ssi->size = len;
488 /* copy service args into a single buffer*/
489 p = &ssi->str[0];
490 for (i=0; i<argc; i++)
492 strcpyW(p, argv[i]);
493 p += strlenW(p) + 1;
495 *p=0;
497 r = WriteFile(pipe, ssi, sizeof *ssi + len*sizeof(WCHAR), &count, NULL);
498 if (r)
499 r = ReadFile(pipe, &result, sizeof result, &count, NULL);
501 HeapFree(GetProcessHeap(),0,ssi);
503 return r;
506 /******************************************************************************
507 * service_handle_get_status
509 static BOOL service_handle_get_status(HANDLE pipe, const service_data *service)
511 DWORD count = 0;
512 TRACE("\n");
513 return WriteFile(pipe, &service->status,
514 sizeof service->status, &count, NULL);
517 /******************************************************************************
518 * service_get_status
520 static BOOL service_get_status(HANDLE pipe, LPSERVICE_STATUS_PROCESS status)
522 DWORD cmd[2], count = 0;
523 BOOL r;
525 cmd[0] = WINESERV_GETSTATUS;
526 cmd[1] = 0;
527 r = WriteFile( pipe, cmd, sizeof cmd, &count, NULL );
528 if (!r || count != sizeof cmd)
530 ERR("service protocol error - failed to write pipe!\n");
531 return r;
533 r = ReadFile( pipe, status, sizeof *status, &count, NULL );
534 if (!r || count != sizeof *status)
535 ERR("service protocol error - failed to read pipe "
536 "r = %d count = %d!\n", r, count);
537 return r;
540 /******************************************************************************
541 * service_handle_set_processID
543 static BOOL service_handle_set_processID(HANDLE pipe, service_data *service, DWORD dwProcessId)
545 DWORD count, ret = ERROR_SUCCESS;
547 TRACE("received control %d\n", dwProcessId);
548 service->status.dwProcessId = dwProcessId;
549 return WriteFile(pipe, &ret, sizeof ret , &count, NULL);
552 /******************************************************************************
553 * service_set_processID
555 static BOOL service_set_processID(HANDLE pipe, DWORD dwprocessId, LPDWORD dwResult)
557 DWORD cmd[2], count = 0;
558 BOOL r;
560 cmd[0] = WINESERV_SETPID;
561 cmd[1] = dwprocessId;
562 r = WriteFile( pipe, cmd, sizeof cmd, &count, NULL );
563 if (!r || count != sizeof cmd)
565 ERR("service protocol error - failed to write pipe!\n");
566 return r;
568 r = ReadFile( pipe, dwResult, sizeof *dwResult, &count, NULL );
569 if (!r || count != sizeof *dwResult)
570 ERR("service protocol error - failed to read pipe "
571 "r = %d count = %d!\n", r, count);
572 return r;
575 /******************************************************************************
576 * service_send_control
578 static BOOL service_send_control(HANDLE pipe, DWORD dwControl, DWORD *result)
580 DWORD cmd[2], count = 0;
581 BOOL r;
583 cmd[0] = WINESERV_SENDCONTROL;
584 cmd[1] = dwControl;
585 r = WriteFile(pipe, cmd, sizeof cmd, &count, NULL);
586 if (!r || count != sizeof cmd)
588 ERR("service protocol error - failed to write pipe!\n");
589 return r;
591 r = ReadFile(pipe, result, sizeof *result, &count, NULL);
592 if (!r || count != sizeof *result)
593 ERR("service protocol error - failed to read pipe "
594 "r = %d count = %d!\n", r, count);
595 return r;
598 /******************************************************************************
599 * service_accepts_control
601 static BOOL service_accepts_control(const service_data *service, DWORD dwControl)
603 DWORD a = service->status.dwControlsAccepted;
605 switch (dwControl)
607 case SERVICE_CONTROL_INTERROGATE:
608 return TRUE;
609 case SERVICE_CONTROL_STOP:
610 if (a&SERVICE_ACCEPT_STOP)
611 return TRUE;
612 break;
613 case SERVICE_CONTROL_SHUTDOWN:
614 if (a&SERVICE_ACCEPT_SHUTDOWN)
615 return TRUE;
616 break;
617 case SERVICE_CONTROL_PAUSE:
618 case SERVICE_CONTROL_CONTINUE:
619 if (a&SERVICE_ACCEPT_PAUSE_CONTINUE)
620 return TRUE;
621 break;
622 case SERVICE_CONTROL_PARAMCHANGE:
623 if (a&SERVICE_ACCEPT_PARAMCHANGE)
624 return TRUE;
625 break;
626 case SERVICE_CONTROL_NETBINDADD:
627 case SERVICE_CONTROL_NETBINDREMOVE:
628 case SERVICE_CONTROL_NETBINDENABLE:
629 case SERVICE_CONTROL_NETBINDDISABLE:
630 if (a&SERVICE_ACCEPT_NETBINDCHANGE)
631 return TRUE;
633 if (!service->extended)
634 return FALSE;
635 switch (dwControl)
637 case SERVICE_CONTROL_HARDWAREPROFILECHANGE:
638 if (a&SERVICE_ACCEPT_HARDWAREPROFILECHANGE)
639 return TRUE;
640 break;
641 case SERVICE_CONTROL_POWEREVENT:
642 if (a&SERVICE_ACCEPT_POWEREVENT)
643 return TRUE;
644 break;
645 case SERVICE_CONTROL_SESSIONCHANGE:
646 if (a&SERVICE_ACCEPT_SESSIONCHANGE)
647 return TRUE;
648 break;
650 return FALSE;
653 /******************************************************************************
654 * service_handle_control
656 static BOOL service_handle_control(HANDLE pipe, service_data *service,
657 DWORD dwControl)
659 DWORD count, ret = ERROR_INVALID_SERVICE_CONTROL;
661 TRACE("received control %d\n", dwControl);
663 if (service_accepts_control(service, dwControl))
665 if (service->extended && service->handler.handler_ex)
667 service->handler.handler_ex(dwControl, 0, NULL, service->context);
668 ret = ERROR_SUCCESS;
670 else if (service->handler.handler)
672 service->handler.handler(dwControl);
673 ret = ERROR_SUCCESS;
676 return WriteFile(pipe, &ret, sizeof ret, &count, NULL);
679 /******************************************************************************
680 * service_reap_thread
682 static DWORD service_reap_thread(service_data *service)
684 DWORD exitcode = 0;
686 if (!service->thread)
687 return 0;
688 GetExitCodeThread(service->thread, &exitcode);
689 if (exitcode!=STILL_ACTIVE)
691 CloseHandle(service->thread);
692 service->thread = 0;
694 return exitcode;
697 /******************************************************************************
698 * service_control_dispatcher
700 static DWORD WINAPI service_control_dispatcher(LPVOID arg)
702 service_data *service = arg;
703 LPWSTR name;
704 HANDLE pipe, event;
706 TRACE("%p %s\n", service, debugstr_w(service->name));
708 /* create a pipe to talk to the rest of the world with */
709 name = service_get_pipe_name(service->name);
710 pipe = CreateNamedPipeW(name, PIPE_ACCESS_DUPLEX,
711 PIPE_TYPE_BYTE|PIPE_WAIT, 1, 256, 256, 10000, NULL );
712 SERV_free(name);
714 /* let the process who started us know we've tried to create a pipe */
715 event = service_get_event_handle(service->name);
716 SetEvent(event);
717 CloseHandle(event);
719 if (pipe==INVALID_HANDLE_VALUE)
721 ERR("failed to create pipe for %s, error = %d\n",
722 debugstr_w(service->name), GetLastError());
723 return 0;
726 /* dispatcher loop */
727 while (1)
729 BOOL r;
730 DWORD count, req[2] = {0,0};
732 r = ConnectNamedPipe(pipe, NULL);
733 if (!r && GetLastError() != ERROR_PIPE_CONNECTED)
735 ERR("pipe connect failed\n");
736 break;
739 r = ReadFile( pipe, &req, sizeof req, &count, NULL );
740 if (!r || count!=sizeof req)
742 ERR("pipe read failed\n");
743 break;
746 service_reap_thread(service);
748 /* handle the request */
749 switch (req[0])
751 case WINESERV_STARTINFO:
752 service_handle_start(pipe, service, req[1]);
753 break;
754 case WINESERV_GETSTATUS:
755 service_handle_get_status(pipe, service);
756 break;
757 case WINESERV_SENDCONTROL:
758 service_handle_control(pipe, service, req[1]);
759 break;
760 case WINESERV_SETPID:
761 service_handle_set_processID(pipe, service, req[1]);
762 break;
763 default:
764 ERR("received invalid command %d length %d\n", req[0], req[1]);
767 FlushFileBuffers(pipe);
768 DisconnectNamedPipe(pipe);
771 CloseHandle(pipe);
772 return 1;
775 /******************************************************************************
776 * service_run_threads
778 static BOOL service_run_threads(void)
780 service_data *service;
781 DWORD count, n = 0;
782 HANDLE *handles;
784 EnterCriticalSection( &service_cs );
786 count = list_count( &service_list );
788 TRACE("starting %d pipe listener threads\n", count);
790 handles = HeapAlloc(GetProcessHeap(), 0, sizeof(HANDLE) * (count + 1));
792 handles[n++] = __wine_make_process_system();
794 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
795 handles[n++] = CreateThread( NULL, 0, service_control_dispatcher,
796 service, 0, NULL );
797 assert(n == count + 1);
799 LeaveCriticalSection( &service_cs );
801 /* wait for all the threads to pack up and exit */
802 while (n > 1)
804 DWORD ret = WaitForMultipleObjects( min(n,MAXIMUM_WAIT_OBJECTS), handles, FALSE, INFINITE );
805 if (!ret) /* system process event */
807 TRACE( "last user process exited, shutting down\n" );
808 /* FIXME: we should maybe send a shutdown control to running services */
809 ExitProcess(0);
811 if (ret < MAXIMUM_WAIT_OBJECTS)
813 CloseHandle( handles[ret] );
814 memmove( &handles[ret], &handles[ret+1], (n - ret - 1) * sizeof(HANDLE) );
815 n--;
817 else break;
820 while (n) CloseHandle( handles[--n] );
821 HeapFree(GetProcessHeap(), 0, handles);
823 return TRUE;
826 /******************************************************************************
827 * StartServiceCtrlDispatcherA [ADVAPI32.@]
829 * See StartServiceCtrlDispatcherW.
831 BOOL WINAPI StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *servent )
833 service_data *info;
834 DWORD sz, len;
835 BOOL ret = TRUE;
837 TRACE("%p\n", servent);
839 EnterCriticalSection( &service_cs );
840 while (servent->lpServiceName)
842 LPSTR name = servent->lpServiceName;
844 len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0);
845 sz = len*sizeof(WCHAR) + sizeof *info;
846 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
847 MultiByteToWideChar(CP_ACP, 0, name, -1, info->name, len);
848 info->proc.a = servent->lpServiceProc;
849 info->unicode = FALSE;
850 list_add_head( &service_list, &info->entry );
851 servent++;
853 LeaveCriticalSection( &service_cs );
855 service_run_threads();
857 return ret;
860 /******************************************************************************
861 * StartServiceCtrlDispatcherW [ADVAPI32.@]
863 * Connects a process containing one or more services to the service control
864 * manager.
866 * PARAMS
867 * servent [I] A list of the service names and service procedures
869 * RETURNS
870 * Success: TRUE.
871 * Failure: FALSE.
873 BOOL WINAPI StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW *servent )
875 service_data *info;
876 DWORD sz, len;
877 BOOL ret = TRUE;
879 TRACE("%p\n", servent);
881 EnterCriticalSection( &service_cs );
882 while (servent->lpServiceName)
884 LPWSTR name = servent->lpServiceName;
886 len = strlenW(name);
887 sz = len*sizeof(WCHAR) + sizeof *info;
888 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
889 strcpyW(info->name, name);
890 info->proc.w = servent->lpServiceProc;
891 info->unicode = TRUE;
892 list_add_head( &service_list, &info->entry );
893 servent++;
895 LeaveCriticalSection( &service_cs );
897 service_run_threads();
899 return ret;
902 /******************************************************************************
903 * LockServiceDatabase [ADVAPI32.@]
905 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
907 HANDLE ret;
909 TRACE("%p\n",hSCManager);
911 ret = CreateSemaphoreW( NULL, 1, 1, szSCMLock );
912 if( ret && GetLastError() == ERROR_ALREADY_EXISTS )
914 CloseHandle( ret );
915 ret = NULL;
916 SetLastError( ERROR_SERVICE_DATABASE_LOCKED );
919 TRACE("returning %p\n", ret);
921 return ret;
924 /******************************************************************************
925 * UnlockServiceDatabase [ADVAPI32.@]
927 BOOL WINAPI UnlockServiceDatabase (SC_LOCK ScLock)
929 TRACE("%p\n",ScLock);
931 return CloseHandle( ScLock );
934 /******************************************************************************
935 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
937 SERVICE_STATUS_HANDLE WINAPI
938 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName, LPHANDLER_FUNCTION lpfHandler )
940 LPWSTR lpServiceNameW;
941 SERVICE_STATUS_HANDLE ret;
943 lpServiceNameW = SERV_dup(lpServiceName);
944 ret = RegisterServiceCtrlHandlerW( lpServiceNameW, lpfHandler );
945 SERV_free(lpServiceNameW);
946 return ret;
949 /******************************************************************************
950 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
952 * PARAMS
953 * lpServiceName []
954 * lpfHandler []
956 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName,
957 LPHANDLER_FUNCTION lpfHandler )
959 service_data *service;
960 SERVICE_STATUS_HANDLE handle = 0;
962 EnterCriticalSection( &service_cs );
963 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
965 if(!strcmpW(lpServiceName, service->name))
967 service->handler.handler = lpfHandler;
968 handle = (SERVICE_STATUS_HANDLE)service;
969 break;
972 LeaveCriticalSection( &service_cs );
973 return handle;
976 /******************************************************************************
977 * SetServiceStatus [ADVAPI32.@]
979 * PARAMS
980 * hService []
981 * lpStatus []
983 BOOL WINAPI
984 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
986 service_data *service;
987 BOOL r = FALSE;
989 TRACE("%p %x %x %x %x %x %x %x\n", hService,
990 lpStatus->dwServiceType, lpStatus->dwCurrentState,
991 lpStatus->dwControlsAccepted, lpStatus->dwWin32ExitCode,
992 lpStatus->dwServiceSpecificExitCode, lpStatus->dwCheckPoint,
993 lpStatus->dwWaitHint);
995 EnterCriticalSection( &service_cs );
996 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
998 if(service == (service_data*)hService)
1000 memcpy( &service->status, lpStatus, sizeof(SERVICE_STATUS) );
1001 TRACE("Set service status to %d\n",service->status.dwCurrentState);
1002 r = TRUE;
1003 break;
1006 LeaveCriticalSection( &service_cs );
1008 return r;
1012 /******************************************************************************
1013 * OpenSCManagerA [ADVAPI32.@]
1015 * Establish a connection to the service control manager and open its database.
1017 * PARAMS
1018 * lpMachineName [I] Pointer to machine name string
1019 * lpDatabaseName [I] Pointer to database name string
1020 * dwDesiredAccess [I] Type of access
1022 * RETURNS
1023 * Success: A Handle to the service control manager database
1024 * Failure: NULL
1026 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
1027 DWORD dwDesiredAccess )
1029 LPWSTR lpMachineNameW, lpDatabaseNameW;
1030 SC_HANDLE ret;
1032 lpMachineNameW = SERV_dup(lpMachineName);
1033 lpDatabaseNameW = SERV_dup(lpDatabaseName);
1034 ret = OpenSCManagerW(lpMachineNameW, lpDatabaseNameW, dwDesiredAccess);
1035 SERV_free(lpDatabaseNameW);
1036 SERV_free(lpMachineNameW);
1037 return ret;
1040 /******************************************************************************
1041 * OpenSCManagerW [ADVAPI32.@]
1043 * See OpenSCManagerA.
1045 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
1046 DWORD dwDesiredAccess )
1048 struct sc_manager *manager;
1049 HKEY hReg;
1050 LONG r;
1051 DWORD new_mask = dwDesiredAccess;
1053 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName),
1054 debugstr_w(lpDatabaseName), dwDesiredAccess);
1056 if( lpDatabaseName && lpDatabaseName[0] )
1058 if( strcmpiW( lpDatabaseName, SERVICES_ACTIVE_DATABASEW ) == 0 )
1060 /* noop, all right */
1062 else if( strcmpiW( lpDatabaseName, SERVICES_FAILED_DATABASEW ) == 0 )
1064 SetLastError( ERROR_DATABASE_DOES_NOT_EXIST );
1065 return NULL;
1067 else
1069 SetLastError( ERROR_INVALID_NAME );
1070 return NULL;
1074 manager = sc_handle_alloc( SC_HTYPE_MANAGER, sizeof (struct sc_manager),
1075 sc_handle_destroy_manager );
1076 if (!manager)
1077 return NULL;
1079 r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
1080 if (r!=ERROR_SUCCESS)
1081 goto error;
1083 r = RegCreateKeyW(hReg, szServiceManagerKey, &manager->hkey);
1084 RegCloseKey( hReg );
1085 if (r!=ERROR_SUCCESS)
1086 goto error;
1088 RtlMapGenericMask(&new_mask, &scm_generic);
1089 manager->dwAccess = new_mask;
1090 TRACE("returning %p (access : 0x%08x)\n", manager, manager->dwAccess);
1092 return (SC_HANDLE) &manager->hdr;
1094 error:
1095 sc_handle_free( &manager->hdr );
1096 SetLastError( r);
1097 return NULL;
1100 /******************************************************************************
1101 * ControlService [ADVAPI32.@]
1103 * Send a control code to a service.
1105 * PARAMS
1106 * hService [I] Handle of the service control manager database
1107 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
1108 * lpServiceStatus [O] Destination for the status of the service, if available
1110 * RETURNS
1111 * Success: TRUE.
1112 * Failure: FALSE.
1114 * BUGS
1115 * Unlike M$' implementation, control requests are not serialized and may be
1116 * processed asynchronously.
1118 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
1119 LPSERVICE_STATUS lpServiceStatus )
1121 struct sc_service *hsvc;
1122 BOOL ret = FALSE;
1123 HANDLE handle;
1125 TRACE("%p %d %p\n", hService, dwControl, lpServiceStatus);
1127 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1128 if (!hsvc)
1130 SetLastError( ERROR_INVALID_HANDLE );
1131 return FALSE;
1134 ret = QueryServiceStatus(hService, lpServiceStatus);
1135 if (!ret)
1137 ERR("failed to query service status\n");
1138 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1139 return FALSE;
1142 switch (lpServiceStatus->dwCurrentState)
1144 case SERVICE_STOPPED:
1145 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1146 return FALSE;
1147 case SERVICE_START_PENDING:
1148 if (dwControl==SERVICE_CONTROL_STOP)
1149 break;
1150 /* fall thru */
1151 case SERVICE_STOP_PENDING:
1152 SetLastError(ERROR_SERVICE_CANNOT_ACCEPT_CTRL);
1153 return FALSE;
1156 handle = service_open_pipe(hsvc->name);
1157 if (handle!=INVALID_HANDLE_VALUE)
1159 DWORD result = ERROR_SUCCESS;
1160 ret = service_send_control(handle, dwControl, &result);
1161 CloseHandle(handle);
1162 if (result!=ERROR_SUCCESS)
1164 SetLastError(result);
1165 ret = FALSE;
1169 return ret;
1172 /******************************************************************************
1173 * CloseServiceHandle [ADVAPI32.@]
1175 * Close a handle to a service or the service control manager database.
1177 * PARAMS
1178 * hSCObject [I] Handle to service or service control manager database
1180 * RETURNS
1181 * Success: TRUE
1182 * Failure: FALSE
1184 BOOL WINAPI
1185 CloseServiceHandle( SC_HANDLE hSCObject )
1187 TRACE("%p\n", hSCObject);
1189 sc_handle_free( (struct sc_handle*) hSCObject );
1191 return TRUE;
1195 /******************************************************************************
1196 * OpenServiceA [ADVAPI32.@]
1198 * Open a handle to a service.
1200 * PARAMS
1201 * hSCManager [I] Handle of the service control manager database
1202 * lpServiceName [I] Name of the service to open
1203 * dwDesiredAccess [I] Access required to the service
1205 * RETURNS
1206 * Success: Handle to the service
1207 * Failure: NULL
1209 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1210 DWORD dwDesiredAccess )
1212 LPWSTR lpServiceNameW;
1213 SC_HANDLE ret;
1215 TRACE("%p %s %d\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
1217 lpServiceNameW = SERV_dup(lpServiceName);
1218 ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
1219 SERV_free(lpServiceNameW);
1220 return ret;
1224 /******************************************************************************
1225 * OpenServiceW [ADVAPI32.@]
1227 * See OpenServiceA.
1229 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1230 DWORD dwDesiredAccess)
1232 struct sc_manager *hscm;
1233 struct sc_service *hsvc;
1234 HKEY hKey;
1235 long r;
1236 DWORD len;
1238 TRACE("%p %s %d\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
1240 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1241 if (!hscm)
1243 SetLastError( ERROR_INVALID_HANDLE );
1244 return FALSE;
1247 if (!lpServiceName)
1249 SetLastError(ERROR_INVALID_ADDRESS);
1250 return NULL;
1253 r = RegOpenKeyExW( hscm->hkey, lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
1254 if (r!=ERROR_SUCCESS)
1256 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
1257 return NULL;
1260 len = strlenW(lpServiceName)+1;
1261 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE,
1262 sizeof (struct sc_service) + len*sizeof(WCHAR),
1263 sc_handle_destroy_service );
1264 if (!hsvc)
1266 RegCloseKey(hKey);
1267 return NULL;
1269 strcpyW( hsvc->name, lpServiceName );
1270 hsvc->hkey = hKey;
1271 hsvc->dwAccess = dwDesiredAccess;
1273 /* add reference to SCM handle */
1274 hscm->hdr.ref_count++;
1275 hsvc->scm = hscm;
1277 TRACE("returning %p\n",hsvc);
1279 return (SC_HANDLE) &hsvc->hdr;
1282 /******************************************************************************
1283 * CreateServiceW [ADVAPI32.@]
1285 SC_HANDLE WINAPI
1286 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1287 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
1288 DWORD dwServiceType, DWORD dwStartType,
1289 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1290 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1291 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
1292 LPCWSTR lpPassword )
1294 struct sc_manager *hscm;
1295 struct sc_service *hsvc = NULL;
1296 HKEY hKey;
1297 LONG r;
1298 DWORD dp, len;
1299 struct reg_value val[10];
1300 int n = 0;
1302 TRACE("%p %s %s\n", hSCManager,
1303 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
1305 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1306 if (!hscm)
1308 SetLastError( ERROR_INVALID_HANDLE );
1309 return NULL;
1312 r = RegCreateKeyExW(hscm->hkey, lpServiceName, 0, NULL,
1313 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
1314 if (r!=ERROR_SUCCESS)
1315 return NULL;
1317 if (dp != REG_CREATED_NEW_KEY)
1319 SetLastError(ERROR_SERVICE_EXISTS);
1320 goto error;
1323 if( lpDisplayName )
1324 service_set_string( &val[n++], szDisplayName, lpDisplayName );
1326 service_set_dword( &val[n++], szType, &dwServiceType );
1327 service_set_dword( &val[n++], szStart, &dwStartType );
1328 service_set_dword( &val[n++], szError, &dwErrorControl );
1330 if( lpBinaryPathName )
1331 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
1333 if( lpLoadOrderGroup )
1334 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
1336 /* FIXME: lpDependencies is used to create both DependOnService and DependOnGroup
1337 * There is no such key as what szDependencies refers to */
1338 if( lpDependencies )
1339 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
1341 if( lpPassword )
1342 FIXME("Don't know how to add a Password for a service.\n");
1344 if( lpServiceStartName )
1345 service_set_string( &val[n++], szObjectName, lpServiceStartName );
1347 r = service_write_values( hKey, val, n );
1348 if( r != ERROR_SUCCESS )
1349 goto error;
1351 len = strlenW(lpServiceName)+1;
1352 len = sizeof (struct sc_service) + len*sizeof(WCHAR);
1353 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE, len, sc_handle_destroy_service );
1354 if( !hsvc )
1355 goto error;
1356 lstrcpyW( hsvc->name, lpServiceName );
1357 hsvc->hkey = hKey;
1358 hsvc->scm = hscm;
1359 hscm->hdr.ref_count++;
1361 return (SC_HANDLE) &hsvc->hdr;
1363 error:
1364 RegCloseKey( hKey );
1365 return NULL;
1369 /******************************************************************************
1370 * CreateServiceA [ADVAPI32.@]
1372 SC_HANDLE WINAPI
1373 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1374 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1375 DWORD dwServiceType, DWORD dwStartType,
1376 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1377 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1378 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1379 LPCSTR lpPassword )
1381 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1382 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1383 SC_HANDLE r;
1385 TRACE("%p %s %s\n", hSCManager,
1386 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1388 lpServiceNameW = SERV_dup( lpServiceName );
1389 lpDisplayNameW = SERV_dup( lpDisplayName );
1390 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1391 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1392 lpDependenciesW = SERV_dupmulti( lpDependencies );
1393 lpServiceStartNameW = SERV_dup( lpServiceStartName );
1394 lpPasswordW = SERV_dup( lpPassword );
1396 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1397 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1398 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1399 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1401 SERV_free( lpServiceNameW );
1402 SERV_free( lpDisplayNameW );
1403 SERV_free( lpBinaryPathNameW );
1404 SERV_free( lpLoadOrderGroupW );
1405 SERV_free( lpDependenciesW );
1406 SERV_free( lpServiceStartNameW );
1407 SERV_free( lpPasswordW );
1409 return r;
1413 /******************************************************************************
1414 * DeleteService [ADVAPI32.@]
1416 * Delete a service from the service control manager database.
1418 * PARAMS
1419 * hService [I] Handle of the service to delete
1421 * RETURNS
1422 * Success: TRUE
1423 * Failure: FALSE
1425 BOOL WINAPI DeleteService( SC_HANDLE hService )
1427 struct sc_service *hsvc;
1429 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1430 if (!hsvc)
1432 SetLastError( ERROR_INVALID_HANDLE );
1433 return FALSE;
1436 /* Close the key to the service */
1437 RegCloseKey(hsvc->hkey);
1439 /* Delete the service under the Service Control Manager key */
1440 RegDeleteTreeW(hsvc->scm->hkey, hsvc->name);
1442 hsvc->hkey = NULL;
1444 return TRUE;
1448 /******************************************************************************
1449 * StartServiceA [ADVAPI32.@]
1451 * Start a service
1453 * PARAMS
1454 * hService [I] Handle of service
1455 * dwNumServiceArgs [I] Number of arguments
1456 * lpServiceArgVectors [I] Address of array of argument strings
1458 * NOTES
1459 * - NT implements this function using an obscure RPC call.
1460 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1461 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1462 * - This will only work for shared address space. How should the service
1463 * args be transferred when address spaces are separated?
1464 * - Can only start one service at a time.
1465 * - Has no concept of privilege.
1467 * RETURNS
1468 * Success: TRUE.
1469 * Failure: FALSE
1471 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1472 LPCSTR *lpServiceArgVectors )
1474 LPWSTR *lpwstr=NULL;
1475 unsigned int i;
1476 BOOL r;
1478 TRACE("(%p,%d,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1480 if (dwNumServiceArgs)
1481 lpwstr = HeapAlloc( GetProcessHeap(), 0,
1482 dwNumServiceArgs*sizeof(LPWSTR) );
1484 for(i=0; i<dwNumServiceArgs; i++)
1485 lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1487 r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1489 if (dwNumServiceArgs)
1491 for(i=0; i<dwNumServiceArgs; i++)
1492 SERV_free(lpwstr[i]);
1493 HeapFree(GetProcessHeap(), 0, lpwstr);
1496 return r;
1499 /******************************************************************************
1500 * service_start_process [INTERNAL]
1502 static DWORD service_start_process(struct sc_service *hsvc, LPDWORD ppid)
1504 static const WCHAR _ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0};
1505 PROCESS_INFORMATION pi;
1506 STARTUPINFOW si;
1507 LPWSTR path = NULL, str;
1508 DWORD type, size, ret, svc_type;
1509 HANDLE handles[2];
1510 BOOL r;
1512 size = sizeof(svc_type);
1513 if (RegQueryValueExW(hsvc->hkey, szType, NULL, &type, (LPBYTE)&svc_type, &size) || type != REG_DWORD)
1514 svc_type = 0;
1516 if (svc_type == SERVICE_KERNEL_DRIVER)
1518 static const WCHAR winedeviceW[] = {'\\','w','i','n','e','d','e','v','i','c','e','.','e','x','e',' ',0};
1519 DWORD len = GetSystemDirectoryW( NULL, 0 ) + sizeof(winedeviceW)/sizeof(WCHAR) + strlenW(hsvc->name);
1521 if (!(path = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return FALSE;
1522 GetSystemDirectoryW( path, len );
1523 lstrcatW( path, winedeviceW );
1524 lstrcatW( path, hsvc->name );
1526 else
1528 /* read the executable path from the registry */
1529 size = 0;
1530 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, NULL, &size);
1531 if (ret!=ERROR_SUCCESS)
1532 return FALSE;
1533 str = HeapAlloc(GetProcessHeap(),0,size);
1534 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, (LPBYTE)str, &size);
1535 if (ret==ERROR_SUCCESS)
1537 size = ExpandEnvironmentStringsW(str,NULL,0);
1538 path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
1539 ExpandEnvironmentStringsW(str,path,size);
1541 HeapFree(GetProcessHeap(),0,str);
1542 if (!path)
1543 return FALSE;
1546 /* wait for the process to start and set an event or terminate */
1547 handles[0] = service_get_event_handle( hsvc->name );
1548 ZeroMemory(&si, sizeof(STARTUPINFOW));
1549 si.cb = sizeof(STARTUPINFOW);
1550 r = CreateProcessW(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1551 if (r)
1553 if (ppid) *ppid = pi.dwProcessId;
1555 handles[1] = pi.hProcess;
1556 ret = WaitForMultipleObjectsEx(2, handles, FALSE, 30000, FALSE);
1557 if(ret != WAIT_OBJECT_0)
1559 SetLastError(ERROR_IO_PENDING);
1560 r = FALSE;
1563 CloseHandle( pi.hThread );
1564 CloseHandle( pi.hProcess );
1566 CloseHandle( handles[0] );
1567 HeapFree(GetProcessHeap(),0,path);
1568 return r;
1571 static BOOL service_wait_for_startup(SC_HANDLE hService)
1573 DWORD i;
1574 SERVICE_STATUS status;
1575 BOOL r = FALSE;
1577 TRACE("%p\n", hService);
1579 for (i=0; i<30; i++)
1581 status.dwCurrentState = 0;
1582 r = QueryServiceStatus(hService, &status);
1583 if (!r)
1584 break;
1585 if (status.dwCurrentState == SERVICE_RUNNING)
1587 TRACE("Service started successfully\n");
1588 break;
1590 r = FALSE;
1591 Sleep(1000);
1593 return r;
1596 /******************************************************************************
1597 * StartServiceW [ADVAPI32.@]
1599 * See StartServiceA.
1601 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1602 LPCWSTR *lpServiceArgVectors)
1604 struct sc_service *hsvc;
1605 BOOL r = FALSE;
1606 DWORD dwResult, dwProcessId = 0;
1607 SC_LOCK hLock;
1608 HANDLE handle = INVALID_HANDLE_VALUE;
1610 TRACE("%p %d %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1612 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1613 if (!hsvc)
1615 SetLastError(ERROR_INVALID_HANDLE);
1616 return r;
1619 hLock = LockServiceDatabase((SC_HANDLE)hsvc->scm);
1620 if (!hLock)
1621 return r;
1623 handle = service_open_pipe(hsvc->name);
1624 if (handle==INVALID_HANDLE_VALUE)
1626 /* start the service process */
1627 if (service_start_process(hsvc, &dwProcessId))
1628 handle = service_open_pipe(hsvc->name);
1631 if (handle != INVALID_HANDLE_VALUE)
1633 r = service_send_start_message(handle, lpServiceArgVectors, dwNumServiceArgs);
1634 CloseHandle(handle);
1637 handle = service_open_pipe(hsvc->name);
1638 if (handle != INVALID_HANDLE_VALUE)
1640 service_set_processID(handle, dwProcessId, &dwResult);
1641 CloseHandle(handle);
1644 UnlockServiceDatabase( hLock );
1646 TRACE("returning %d\n", r);
1648 if (r)
1649 service_wait_for_startup(hService);
1651 return r;
1654 /******************************************************************************
1655 * QueryServiceStatus [ADVAPI32.@]
1657 * PARAMS
1658 * hService [I] Handle to service to get information about
1659 * lpservicestatus [O] buffer to receive the status information for the service
1662 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1663 LPSERVICE_STATUS lpservicestatus)
1665 SERVICE_STATUS_PROCESS SvcStatusData;
1666 BOOL ret;
1668 TRACE("%p %p\n", hService, lpservicestatus);
1670 ret = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&SvcStatusData,
1671 sizeof(SERVICE_STATUS_PROCESS), NULL);
1672 if (ret) memcpy(lpservicestatus, &SvcStatusData, sizeof(SERVICE_STATUS)) ;
1673 return ret;
1677 /******************************************************************************
1678 * QueryServiceStatusEx [ADVAPI32.@]
1680 * Get information about a service.
1682 * PARAMS
1683 * hService [I] Handle to service to get information about
1684 * InfoLevel [I] Level of information to get
1685 * lpBuffer [O] Destination for requested information
1686 * cbBufSize [I] Size of lpBuffer in bytes
1687 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1689 * RETURNS
1690 * Success: TRUE
1691 * FAILURE: FALSE
1693 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1694 LPBYTE lpBuffer, DWORD cbBufSize,
1695 LPDWORD pcbBytesNeeded)
1697 struct sc_service *hsvc;
1698 DWORD size, type, val;
1699 HANDLE pipe;
1700 LONG r;
1701 LPSERVICE_STATUS_PROCESS pSvcStatusData;
1703 TRACE("%p %d %p %d %p\n", hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1705 if (InfoLevel != SC_STATUS_PROCESS_INFO)
1707 SetLastError( ERROR_INVALID_LEVEL);
1708 return FALSE;
1711 pSvcStatusData = (LPSERVICE_STATUS_PROCESS) lpBuffer;
1712 if (pSvcStatusData == NULL)
1714 SetLastError( ERROR_INVALID_PARAMETER);
1715 return FALSE;
1718 if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
1720 if( pcbBytesNeeded != NULL)
1721 *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
1723 SetLastError( ERROR_INSUFFICIENT_BUFFER);
1724 return FALSE;
1727 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1728 if (!hsvc)
1730 SetLastError( ERROR_INVALID_HANDLE );
1731 return FALSE;
1734 pipe = service_open_pipe(hsvc->name);
1735 if (pipe != INVALID_HANDLE_VALUE)
1737 r = service_get_status(pipe, pSvcStatusData);
1738 CloseHandle(pipe);
1739 if (r)
1740 return TRUE;
1743 TRACE("Failed to read service status\n");
1745 /* read the service type from the registry */
1746 size = sizeof(val);
1747 r = RegQueryValueExA(hsvc->hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1748 if (r != ERROR_SUCCESS || type != REG_DWORD)
1749 val = 0;
1751 pSvcStatusData->dwServiceType = val;
1752 pSvcStatusData->dwCurrentState = SERVICE_STOPPED; /* stopped */
1753 pSvcStatusData->dwControlsAccepted = 0;
1754 pSvcStatusData->dwWin32ExitCode = ERROR_SERVICE_NEVER_STARTED;
1755 pSvcStatusData->dwServiceSpecificExitCode = 0;
1756 pSvcStatusData->dwCheckPoint = 0;
1757 pSvcStatusData->dwWaitHint = 0;
1759 return TRUE;
1762 /******************************************************************************
1763 * QueryServiceConfigA [ADVAPI32.@]
1765 BOOL WINAPI QueryServiceConfigA( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGA config,
1766 DWORD size, LPDWORD needed )
1768 DWORD n;
1769 LPSTR p, buffer;
1770 BOOL ret;
1771 QUERY_SERVICE_CONFIGW *configW;
1773 TRACE("%p %p %d %p\n", hService, config, size, needed);
1775 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, 2 * size )))
1777 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1778 return FALSE;
1780 configW = (QUERY_SERVICE_CONFIGW *)buffer;
1781 ret = QueryServiceConfigW( hService, configW, 2 * size, needed );
1782 if (!ret) goto done;
1784 config->dwServiceType = configW->dwServiceType;
1785 config->dwStartType = configW->dwStartType;
1786 config->dwErrorControl = configW->dwErrorControl;
1787 config->lpBinaryPathName = NULL;
1788 config->lpLoadOrderGroup = NULL;
1789 config->dwTagId = configW->dwTagId;
1790 config->lpDependencies = NULL;
1791 config->lpServiceStartName = NULL;
1792 config->lpDisplayName = NULL;
1794 p = (LPSTR)(config + 1);
1795 n = size - sizeof(*config);
1796 ret = FALSE;
1798 #define MAP_STR(str) \
1799 do { \
1800 if (configW->str) \
1802 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1803 if (!sz) goto done; \
1804 config->str = p; \
1805 p += sz; \
1806 n -= sz; \
1808 } while (0)
1810 MAP_STR( lpBinaryPathName );
1811 MAP_STR( lpLoadOrderGroup );
1812 MAP_STR( lpDependencies );
1813 MAP_STR( lpServiceStartName );
1814 MAP_STR( lpDisplayName );
1815 #undef MAP_STR
1817 *needed = p - (LPSTR)config;
1818 ret = TRUE;
1820 done:
1821 HeapFree( GetProcessHeap(), 0, buffer );
1822 return ret;
1825 /******************************************************************************
1826 * QueryServiceConfigW [ADVAPI32.@]
1828 BOOL WINAPI
1829 QueryServiceConfigW( SC_HANDLE hService,
1830 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1831 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1833 WCHAR str_buffer[ MAX_PATH ];
1834 LONG r;
1835 DWORD type, val, sz, total, n;
1836 LPBYTE p;
1837 HKEY hKey;
1838 struct sc_service *hsvc;
1840 TRACE("%p %p %d %p\n", hService, lpServiceConfig,
1841 cbBufSize, pcbBytesNeeded);
1843 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1844 if (!hsvc)
1846 SetLastError( ERROR_INVALID_HANDLE );
1847 return FALSE;
1849 hKey = hsvc->hkey;
1851 /* TODO: Check which members are mandatory and what the registry types
1852 * should be. This should of course also be tested when a service is
1853 * created.
1856 /* calculate the size required first */
1857 total = sizeof (QUERY_SERVICE_CONFIGW);
1859 sz = sizeof(str_buffer);
1860 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1861 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1863 sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1864 if( 0 == sz ) return FALSE;
1866 total += sizeof(WCHAR) * sz;
1868 else
1870 /* FIXME: set last error */
1871 return FALSE;
1874 sz = 0;
1875 r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1876 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1877 total += sz;
1878 else
1879 total += sizeof(WCHAR);
1881 sz = 0;
1882 r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1883 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1884 total += sz;
1885 else
1886 total += sizeof(WCHAR);
1888 sz = 0;
1889 r = RegQueryValueExW( hKey, szObjectName, 0, &type, NULL, &sz );
1890 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1891 total += sz;
1892 else
1893 total += sizeof(WCHAR);
1895 sz = 0;
1896 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1897 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1898 total += sz;
1899 else
1900 total += sizeof(WCHAR);
1902 *pcbBytesNeeded = total;
1904 /* if there's not enough memory, return an error */
1905 if( total > cbBufSize )
1907 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1908 return FALSE;
1911 ZeroMemory( lpServiceConfig, total );
1913 sz = sizeof val;
1914 r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1915 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
1916 lpServiceConfig->dwServiceType = val;
1918 sz = sizeof val;
1919 r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1920 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
1921 lpServiceConfig->dwStartType = val;
1923 sz = sizeof val;
1924 r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1925 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
1926 lpServiceConfig->dwErrorControl = val;
1928 sz = sizeof val;
1929 r = RegQueryValueExW( hKey, szTag, 0, &type, (LPBYTE)&val, &sz );
1930 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
1931 lpServiceConfig->dwTagId = val;
1933 /* now do the strings */
1934 p = (LPBYTE) &lpServiceConfig[1];
1935 n = total - sizeof (QUERY_SERVICE_CONFIGW);
1937 sz = sizeof(str_buffer);
1938 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1939 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1941 sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
1942 sz *= sizeof(WCHAR);
1943 if( 0 == sz || sz > n ) return FALSE;
1945 lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
1946 p += sz;
1947 n -= sz;
1949 else
1951 /* FIXME: set last error */
1952 return FALSE;
1955 sz = n;
1956 r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
1957 lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
1958 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1960 p += sz;
1961 n -= sz;
1963 else
1965 *(WCHAR *) p = 0;
1966 p += sizeof(WCHAR);
1967 n -= sizeof(WCHAR);
1970 sz = n;
1971 r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
1972 lpServiceConfig->lpDependencies = (LPWSTR) p;
1973 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1975 p += sz;
1976 n -= sz;
1978 else
1980 *(WCHAR *) p = 0;
1981 p += sizeof(WCHAR);
1982 n -= sizeof(WCHAR);
1985 sz = n;
1986 r = RegQueryValueExW( hKey, szObjectName, 0, &type, p, &sz );
1987 lpServiceConfig->lpServiceStartName = (LPWSTR) p;
1988 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1990 p += sz;
1991 n -= sz;
1993 else
1995 *(WCHAR *) p = 0;
1996 p += sizeof(WCHAR);
1997 n -= sizeof(WCHAR);
2000 sz = n;
2001 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, p, &sz );
2002 lpServiceConfig->lpDisplayName = (LPWSTR) p;
2003 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2005 p += sz;
2006 n -= sz;
2008 else
2010 *(WCHAR *) p = 0;
2011 p += sizeof(WCHAR);
2012 n -= sizeof(WCHAR);
2015 if( n < 0 )
2016 ERR("Buffer overflow!\n");
2018 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
2019 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
2020 TRACE("Dependencies = %s\n", debugstr_w(lpServiceConfig->lpDependencies) );
2021 TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig->lpServiceStartName) );
2022 TRACE("Display name = %s\n", debugstr_w(lpServiceConfig->lpDisplayName) );
2024 return TRUE;
2027 /******************************************************************************
2028 * EnumServicesStatusA [ADVAPI32.@]
2030 BOOL WINAPI
2031 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
2032 DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
2033 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2034 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
2036 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
2037 dwServiceType, dwServiceState, lpServices, cbBufSize,
2038 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
2039 SetLastError (ERROR_ACCESS_DENIED);
2040 return FALSE;
2043 /******************************************************************************
2044 * EnumServicesStatusW [ADVAPI32.@]
2046 BOOL WINAPI
2047 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
2048 DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
2049 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2050 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
2052 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
2053 dwServiceType, dwServiceState, lpServices, cbBufSize,
2054 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
2055 SetLastError (ERROR_ACCESS_DENIED);
2056 return FALSE;
2059 /******************************************************************************
2060 * EnumServicesStatusExA [ADVAPI32.@]
2062 BOOL WINAPI
2063 EnumServicesStatusExA(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
2064 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2065 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCSTR pszGroupName)
2067 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
2068 dwServiceType, dwServiceState, lpServices, cbBufSize,
2069 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_a(pszGroupName));
2070 SetLastError (ERROR_ACCESS_DENIED);
2071 return FALSE;
2074 /******************************************************************************
2075 * EnumServicesStatusExW [ADVAPI32.@]
2077 BOOL WINAPI
2078 EnumServicesStatusExW(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
2079 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2080 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCWSTR pszGroupName)
2082 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
2083 dwServiceType, dwServiceState, lpServices, cbBufSize,
2084 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_w(pszGroupName));
2085 SetLastError (ERROR_ACCESS_DENIED);
2086 return FALSE;
2089 /******************************************************************************
2090 * GetServiceKeyNameA [ADVAPI32.@]
2092 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
2093 LPSTR lpServiceName, LPDWORD lpcchBuffer )
2095 FIXME("%p %s %p %p\n", hSCManager, debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
2096 return FALSE;
2099 /******************************************************************************
2100 * GetServiceKeyNameW [ADVAPI32.@]
2102 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
2103 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
2105 FIXME("%p %s %p %p\n", hSCManager, debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
2106 return FALSE;
2109 /******************************************************************************
2110 * QueryServiceLockStatusA [ADVAPI32.@]
2112 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
2113 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
2114 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2116 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2118 return FALSE;
2121 /******************************************************************************
2122 * QueryServiceLockStatusW [ADVAPI32.@]
2124 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
2125 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2126 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2128 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2130 return FALSE;
2133 /******************************************************************************
2134 * GetServiceDisplayNameA [ADVAPI32.@]
2136 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
2137 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
2139 struct sc_manager *hscm;
2140 DWORD type, size;
2141 LONG ret;
2143 TRACE("%p %s %p %p\n", hSCManager,
2144 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
2146 if (!lpServiceName)
2148 SetLastError(ERROR_INVALID_PARAMETER);
2149 return FALSE;
2152 hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
2153 if (!hscm)
2155 SetLastError(ERROR_INVALID_HANDLE);
2156 return FALSE;
2159 size = *lpcchBuffer;
2160 ret = RegGetValueA(hscm->hkey, lpServiceName, "DisplayName", RRF_RT_REG_SZ, &type, lpDisplayName, &size);
2161 if (!ret && !lpDisplayName && size)
2162 ret = ERROR_MORE_DATA;
2164 if (ret)
2166 if (lpDisplayName && *lpcchBuffer) *lpDisplayName = 0;
2168 if (ret == ERROR_MORE_DATA)
2170 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2171 *lpcchBuffer = size - 1;
2173 else
2174 SetLastError(ret);
2175 return FALSE;
2177 return TRUE;
2180 /******************************************************************************
2181 * GetServiceDisplayNameW [ADVAPI32.@]
2183 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
2184 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
2186 struct sc_manager *hscm;
2187 DWORD type, size;
2188 LONG ret;
2190 TRACE("%p %s %p %p\n", hSCManager,
2191 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
2193 if (!lpServiceName)
2195 SetLastError(ERROR_INVALID_PARAMETER);
2196 return FALSE;
2199 hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
2200 if (!hscm)
2202 SetLastError(ERROR_INVALID_HANDLE);
2203 return FALSE;
2206 size = *lpcchBuffer * sizeof(WCHAR);
2207 ret = RegGetValueW(hscm->hkey, lpServiceName, szDisplayName, RRF_RT_REG_SZ, &type, lpDisplayName, &size);
2208 if (!ret && !lpDisplayName && size)
2209 ret = ERROR_MORE_DATA;
2211 if (ret)
2213 if (lpDisplayName && *lpcchBuffer) *lpDisplayName = 0;
2215 if (ret == ERROR_MORE_DATA)
2217 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2218 *lpcchBuffer = (size / sizeof(WCHAR)) - 1;
2220 else
2221 SetLastError(ret);
2222 return FALSE;
2224 return TRUE;
2227 /******************************************************************************
2228 * ChangeServiceConfigW [ADVAPI32.@]
2230 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
2231 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
2232 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
2233 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
2235 struct reg_value val[10];
2236 struct sc_service *hsvc;
2237 DWORD r = ERROR_SUCCESS;
2238 HKEY hKey;
2239 int n = 0;
2241 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2242 hService, dwServiceType, dwStartType, dwErrorControl,
2243 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2244 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2245 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2247 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2248 if (!hsvc)
2250 SetLastError( ERROR_INVALID_HANDLE );
2251 return FALSE;
2253 hKey = hsvc->hkey;
2255 if( dwServiceType != SERVICE_NO_CHANGE )
2256 service_set_dword( &val[n++], szType, &dwServiceType );
2258 if( dwStartType != SERVICE_NO_CHANGE )
2259 service_set_dword( &val[n++], szStart, &dwStartType );
2261 if( dwErrorControl != SERVICE_NO_CHANGE )
2262 service_set_dword( &val[n++], szError, &dwErrorControl );
2264 if( lpBinaryPathName )
2265 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
2267 if( lpLoadOrderGroup )
2268 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
2270 /* FIXME: lpDependencies is used to create/change both DependOnService and DependOnGroup
2271 * There is no such key as what szDependencies refers to */
2272 if( lpDependencies )
2273 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
2275 if( lpPassword )
2276 FIXME("ignoring password\n");
2278 if( lpServiceStartName )
2279 service_set_string( &val[n++], szObjectName, lpServiceStartName );
2281 r = service_write_values( hsvc->hkey, val, n );
2283 return (r == ERROR_SUCCESS) ? TRUE : FALSE ;
2286 /******************************************************************************
2287 * ChangeServiceConfigA [ADVAPI32.@]
2289 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2290 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2291 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2292 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2294 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2295 LPWSTR wServiceStartName, wPassword, wDisplayName;
2296 BOOL r;
2298 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2299 hService, dwServiceType, dwStartType, dwErrorControl,
2300 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2301 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2302 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2304 wBinaryPathName = SERV_dup( lpBinaryPathName );
2305 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2306 wDependencies = SERV_dupmulti( lpDependencies );
2307 wServiceStartName = SERV_dup( lpServiceStartName );
2308 wPassword = SERV_dup( lpPassword );
2309 wDisplayName = SERV_dup( lpDisplayName );
2311 r = ChangeServiceConfigW( hService, dwServiceType,
2312 dwStartType, dwErrorControl, wBinaryPathName,
2313 wLoadOrderGroup, lpdwTagId, wDependencies,
2314 wServiceStartName, wPassword, wDisplayName);
2316 SERV_free( wBinaryPathName );
2317 SERV_free( wLoadOrderGroup );
2318 SERV_free( wDependencies );
2319 SERV_free( wServiceStartName );
2320 SERV_free( wPassword );
2321 SERV_free( wDisplayName );
2323 return r;
2326 /******************************************************************************
2327 * ChangeServiceConfig2A [ADVAPI32.@]
2329 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2330 LPVOID lpInfo)
2332 BOOL r = FALSE;
2334 TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo);
2336 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2338 LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
2339 SERVICE_DESCRIPTIONW sdw;
2341 sdw.lpDescription = SERV_dup( sd->lpDescription );
2343 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2345 SERV_free( sdw.lpDescription );
2347 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2349 LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
2350 SERVICE_FAILURE_ACTIONSW faw;
2352 faw.dwResetPeriod = fa->dwResetPeriod;
2353 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2354 faw.lpCommand = SERV_dup( fa->lpCommand );
2355 faw.cActions = fa->cActions;
2356 faw.lpsaActions = fa->lpsaActions;
2358 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2360 SERV_free( faw.lpRebootMsg );
2361 SERV_free( faw.lpCommand );
2363 else
2364 SetLastError( ERROR_INVALID_PARAMETER );
2366 return r;
2369 /******************************************************************************
2370 * ChangeServiceConfig2W [ADVAPI32.@]
2372 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2373 LPVOID lpInfo)
2375 HKEY hKey;
2376 struct sc_service *hsvc;
2378 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2379 if (!hsvc)
2381 SetLastError( ERROR_INVALID_HANDLE );
2382 return FALSE;
2384 hKey = hsvc->hkey;
2386 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2388 static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2389 LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
2390 if (sd->lpDescription)
2392 TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
2393 if (sd->lpDescription[0] == 0)
2394 RegDeleteValueW(hKey,szDescription);
2395 else
2396 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2397 (LPVOID)sd->lpDescription,
2398 sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2401 else
2402 FIXME("STUB: %p %d %p\n",hService, dwInfoLevel, lpInfo);
2403 return TRUE;
2406 /******************************************************************************
2407 * QueryServiceObjectSecurity [ADVAPI32.@]
2409 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2410 SECURITY_INFORMATION dwSecurityInformation,
2411 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2412 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2414 PACL pACL = NULL;
2416 FIXME("%p %d %p %u %p\n", hService, dwSecurityInformation,
2417 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2419 InitializeSecurityDescriptor(lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
2421 pACL = HeapAlloc( GetProcessHeap(), 0, sizeof(ACL) );
2422 InitializeAcl(pACL, sizeof(ACL), ACL_REVISION);
2423 SetSecurityDescriptorDacl(lpSecurityDescriptor, TRUE, pACL, TRUE);
2424 return TRUE;
2427 /******************************************************************************
2428 * SetServiceObjectSecurity [ADVAPI32.@]
2430 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2431 SECURITY_INFORMATION dwSecurityInformation,
2432 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2434 FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2435 return TRUE;
2438 /******************************************************************************
2439 * SetServiceBits [ADVAPI32.@]
2441 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2442 DWORD dwServiceBits,
2443 BOOL bSetBitsOn,
2444 BOOL bUpdateImmediately)
2446 FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2447 bSetBitsOn, bUpdateImmediately);
2448 return TRUE;
2451 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR lpServiceName,
2452 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2454 FIXME("%s %p %p\n", debugstr_a(lpServiceName), lpHandlerProc, lpContext);
2455 return 0;
2458 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2459 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2461 service_data *service;
2462 SERVICE_STATUS_HANDLE handle = 0;
2464 TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2466 EnterCriticalSection( &service_cs );
2467 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
2469 if(!strcmpW(lpServiceName, service->name))
2471 service->handler.handler_ex = lpHandlerProc;
2472 service->context = lpContext;
2473 service->extended = TRUE;
2474 handle = (SERVICE_STATUS_HANDLE)service;
2475 break;
2478 LeaveCriticalSection( &service_cs );
2480 return handle;