1 /*
2 * Win32 advapi functions
3 *
4 * Copyright 1995 Sven Verdoolaege
5 * Copyright 2005 Mike McCormack
6 * Copyright 2007 Rolf Kalbermatter
7 *
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.
12 *
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.
17 *
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
21 */
22
23 #include "config.h"
24 #include "wine/port.h"
25
26 #include <stdarg.h>
27 #include <string.h>
28 #include <time.h>
29 #include <assert.h>
30
31 #include "windef.h"
32 #include "winbase.h"
33 #include "winsvc.h"
34 #include "winerror.h"
35 #include "winreg.h"
36 #include "wine/unicode.h"
37 #include "wine/debug.h"
38 #include "winternl.h"
39 #include "lmcons.h"
40 #include "lmserver.h"
41
42 #include "svcctl.h"
43
44 #include "wine/exception.h"
45
46 WINE_DEFAULT_DEBUG_CHANNEL(service);
47
48 static const WCHAR szServiceManagerKey[] = { 'S','y','s','t','e','m','\\',
49 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
50 'S','e','r','v','i','c','e','s',0 };
51
52 void __RPC_FAR * __RPC_USER MIDL_user_allocate(size_t len)
53 {
54 return HeapAlloc(GetProcessHeap(), 0, len);
55 }
56
57 void __RPC_USER MIDL_user_free(void __RPC_FAR * ptr)
58 {
59 HeapFree(GetProcessHeap(), 0, ptr);
60 }
61
62 static const GENERIC_MAPPING scm_generic = {
63 (STANDARD_RIGHTS_READ | SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_QUERY_LOCK_STATUS),
64 (STANDARD_RIGHTS_WRITE | SC_MANAGER_CREATE_SERVICE | SC_MANAGER_MODIFY_BOOT_CONFIG),
65 (STANDARD_RIGHTS_EXECUTE | SC_MANAGER_CONNECT | SC_MANAGER_LOCK),
66 SC_MANAGER_ALL_ACCESS
67 };
68
69 static const GENERIC_MAPPING svc_generic = {
70 (STANDARD_RIGHTS_READ | SERVICE_QUERY_CONFIG | SERVICE_QUERY_STATUS | SERVICE_INTERROGATE | SERVICE_ENUMERATE_DEPENDENTS),
71 (STANDARD_RIGHTS_WRITE | SERVICE_CHANGE_CONFIG),
72 (STANDARD_RIGHTS_EXECUTE | SERVICE_START | SERVICE_STOP | SERVICE_PAUSE_CONTINUE | SERVICE_USER_DEFINED_CONTROL),
73 SERVICE_ALL_ACCESS
74 };
75
76 typedef struct service_data_t
77 {
78 LPHANDLER_FUNCTION_EX handler;
79 LPVOID context;
80 HANDLE thread;
81 SC_HANDLE handle;
82 BOOL unicode : 1;
83 union {
84 LPSERVICE_MAIN_FUNCTIONA a;
85 LPSERVICE_MAIN_FUNCTIONW w;
86 } proc;
87 LPWSTR args;
88 WCHAR name[1];
89 } service_data;
90
91 static CRITICAL_SECTION service_cs;
92 static CRITICAL_SECTION_DEBUG service_cs_debug =
93 {
94 0, 0, &service_cs,
95 { &service_cs_debug.ProcessLocksList,
96 &service_cs_debug.ProcessLocksList },
97 0, 0, { (DWORD_PTR)(__FILE__ ": service_cs") }
98 };
99 static CRITICAL_SECTION service_cs = { &service_cs_debug, -1, 0, 0, 0, 0 };
100
101 static service_data **services;
102 static unsigned int nb_services;
103 static HANDLE service_event;
104
105 extern HANDLE __wine_make_process_system(void);
106
107 /******************************************************************************
108 * SC_HANDLEs
109 */
110
111 #define MAX_SERVICE_NAME 256
112
113 typedef enum { SC_HTYPE_MANAGER, SC_HTYPE_SERVICE } SC_HANDLE_TYPE;
114
115 struct sc_handle;
116 typedef VOID (*sc_handle_destructor)(struct sc_handle *);
117
118 struct sc_handle
119 {
120 SC_HANDLE_TYPE htype;
121 DWORD ref_count;
122 sc_handle_destructor destroy;
123 SC_RPC_HANDLE server_handle; /* server-side handle */
124 };
125
126 struct sc_manager /* service control manager handle */
127 {
128 struct sc_handle hdr;
129 HKEY hkey; /* handle to services database in the registry */
130 DWORD dwAccess;
131 };
132
133 struct sc_service /* service handle */
134 {
135 struct sc_handle hdr;
136 HKEY hkey; /* handle to service entry in the registry (under hkey) */
137 DWORD dwAccess;
138 struct sc_manager *scm; /* pointer to SCM handle */
139 WCHAR name[1];
140 };
141
142 static void *sc_handle_alloc(SC_HANDLE_TYPE htype, DWORD size,
143 sc_handle_destructor destroy)
144 {
145 struct sc_handle *hdr;
146
147 hdr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
148 if (hdr)
149 {
150 hdr->htype = htype;
151 hdr->ref_count = 1;
152 hdr->destroy = destroy;
153 }
154 TRACE("sc_handle type=%d -> %p\n", htype, hdr);
155 return hdr;
156 }
157
158 static void *sc_handle_get_handle_data(SC_HANDLE handle, DWORD htype)
159 {
160 struct sc_handle *hdr = (struct sc_handle *) handle;
161
162 if (!hdr)
163 return NULL;
164 if (hdr->htype != htype)
165 return NULL;
166 return hdr;
167 }
168
169 static void sc_handle_free(struct sc_handle* hdr)
170 {
171 if (!hdr)
172 return;
173 if (--hdr->ref_count)
174 return;
175 hdr->destroy(hdr);
176 HeapFree(GetProcessHeap(), 0, hdr);
177 }
178
179 static void sc_handle_destroy_manager(struct sc_handle *handle)
180 {
181 struct sc_manager *mgr = (struct sc_manager*) handle;
182
183 TRACE("destroying SC Manager %p\n", mgr);
184 if (mgr->hkey)
185 RegCloseKey(mgr->hkey);
186 }
187
188 static void sc_handle_destroy_service(struct sc_handle *handle)
189 {
190 struct sc_service *svc = (struct sc_service*) handle;
191
192 TRACE("destroying service %p\n", svc);
193 if (svc->hkey)
194 RegCloseKey(svc->hkey);
195 svc->hkey = NULL;
196 sc_handle_free(&svc->scm->hdr);
197 svc->scm = NULL;
198 }
199
200 /******************************************************************************
201 * String management functions (same behaviour as strdup)
202 * NOTE: the caller of those functions is responsible for calling HeapFree
203 * in order to release the memory allocated by those functions.
204 */
205 static inline LPWSTR SERV_dup( LPCSTR str )
206 {
207 UINT len;
208 LPWSTR wstr;
209
210 if( !str )
211 return NULL;
212 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
213 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
214 MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
215 return wstr;
216 }
217
218 static inline LPWSTR SERV_dupmulti(LPCSTR str)
219 {
220 UINT len = 0, n = 0;
221 LPWSTR wstr;
222
223 if( !str )
224 return NULL;
225 do {
226 len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
227 n += (strlen( &str[n] ) + 1);
228 } while (str[n]);
229 len++;
230 n++;
231
232 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
233 MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
234 return wstr;
235 }
236
237 static inline DWORD multisz_cb(LPCWSTR wmultisz)
238 {
239 const WCHAR *wptr = wmultisz;
240
241 if (wmultisz == NULL)
242 return 0;
243
244 while (*wptr)
245 wptr += lstrlenW(wptr)+1;
246 return (wptr - wmultisz + 1)*sizeof(WCHAR);
247 }
248
249 /******************************************************************************
250 * RPC connection with services.exe
251 */
252
253 handle_t __RPC_USER MACHINE_HANDLEW_bind(MACHINE_HANDLEW MachineName)
254 {
255 WCHAR transport[] = SVCCTL_TRANSPORT;
256 WCHAR endpoint[] = SVCCTL_ENDPOINT;
257 RPC_WSTR binding_str;
258 RPC_STATUS status;
259 handle_t rpc_handle;
260
261 status = RpcStringBindingComposeW(NULL, transport, (RPC_WSTR)MachineName, endpoint, NULL, &binding_str);
262 if (status != RPC_S_OK)
263 {
264 ERR("RpcStringBindingComposeW failed (%d)\n", (DWORD)status);
265 return NULL;
266 }
267
268 status = RpcBindingFromStringBindingW(binding_str, &rpc_handle);
269 RpcStringFreeW(&binding_str);
270
271 if (status != RPC_S_OK)
272 {
273 ERR("Couldn't connect to services.exe: error code %u\n", (DWORD)status);
274 return NULL;
275 }
276
277 return rpc_handle;
278 }
279
280 void __RPC_USER MACHINE_HANDLEW_unbind(MACHINE_HANDLEW MachineName, handle_t h)
281 {
282 RpcBindingFree(&h);
283 }
284
285 static LONG WINAPI rpc_filter(EXCEPTION_POINTERS *eptr)
286 {
287 return I_RpcExceptionFilter(eptr->ExceptionRecord->ExceptionCode);
288 }
289
290 static DWORD map_exception_code(DWORD exception_code)
291 {
292 switch (exception_code)
293 {
294 case RPC_X_NULL_REF_POINTER:
295 case RPC_X_ENUM_VALUE_OUT_OF_RANGE:
296 case RPC_X_BYTE_COUNT_TOO_SMALL:
297 return ERROR_INVALID_PARAMETER;
298 default:
299 return exception_code;
300 }
301 }
302
303 /******************************************************************************
304 * Service IPC functions
305 */
306 static LPWSTR service_get_pipe_name(void)
307 {
308 static const WCHAR format[] = { '\\','\\','.','\\','p','i','p','e','\\',
309 'n','e','t','\\','N','t','C','o','n','t','r','o','l','P','i','p','e','%','u',0};
310 static const WCHAR service_current_key_str[] = { 'S','Y','S','T','E','M','\\',
311 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
312 'C','o','n','t','r','o','l','\\',
313 'S','e','r','v','i','c','e','C','u','r','r','e','n','t',0};
314 LPWSTR name;
315 DWORD len;
316 HKEY service_current_key;
317 DWORD service_current;
318 LONG ret;
319 DWORD type;
320
321 ret = RegOpenKeyExW(HKEY_LOCAL_MACHINE, service_current_key_str, 0,
322 KEY_QUERY_VALUE, &service_current_key);
323 if (ret != ERROR_SUCCESS)
324 return NULL;
325 len = sizeof(service_current);
326 ret = RegQueryValueExW(service_current_key, NULL, NULL, &type,
327 (BYTE *)&service_current, &len);
328 RegCloseKey(service_current_key);
329 if (ret != ERROR_SUCCESS || type != REG_DWORD)
330 return NULL;
331 len = sizeof(format)/sizeof(WCHAR) + 10 /* strlenW("4294967295") */;
332 name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
333 if (!name)
334 return NULL;
335 snprintfW(name, len, format, service_current);
336 return name;
337 }
338
339 static HANDLE service_open_pipe(void)
340 {
341 LPWSTR szPipe = service_get_pipe_name();
342 HANDLE handle = INVALID_HANDLE_VALUE;
343
344 do {
345 handle = CreateFileW(szPipe, GENERIC_READ|GENERIC_WRITE,
346 0, NULL, OPEN_ALWAYS, 0, NULL);
347 if (handle != INVALID_HANDLE_VALUE)
348 break;
349 if (GetLastError() != ERROR_PIPE_BUSY)
350 break;
351 } while (WaitNamedPipeW(szPipe, NMPWAIT_WAIT_FOREVER));
352 HeapFree(GetProcessHeap(), 0, szPipe);
353
354 return handle;
355 }
356
357 static service_data *find_service_by_name( const WCHAR *name )
358 {
359 unsigned int i;
360
361 if (nb_services == 1) /* only one service (FIXME: should depend on OWN_PROCESS etc.) */
362 return services[0];
363 for (i = 0; i < nb_services; i++)
364 if (!strcmpiW( name, services[i]->name )) return services[i];
365 return NULL;
366 }
367
368 /******************************************************************************
369 * service_thread
370 *
371 * Call into the main service routine provided by StartServiceCtrlDispatcher.
372 */
373 static DWORD WINAPI service_thread(LPVOID arg)
374 {
375 service_data *info = arg;
376 LPWSTR str = info->args;
377 DWORD argc = 0, len = 0;
378
379 TRACE("%p\n", arg);
380
381 while (str[len])
382 {
383 len += strlenW(&str[len]) + 1;
384 argc++;
385 }
386
387 if (!argc)
388 {
389 if (info->unicode)
390 info->proc.w(0, NULL);
391 else
392 info->proc.a(0, NULL);
393 return 0;
394 }
395
396 if (info->unicode)
397 {
398 LPWSTR *argv, p;
399
400 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPWSTR));
401 for (argc=0, p=str; *p; p += strlenW(p) + 1)
402 argv[argc++] = p;
403 argv[argc] = NULL;
404
405 info->proc.w(argc, argv);
406 HeapFree(GetProcessHeap(), 0, argv);
407 }
408 else
409 {
410 LPSTR strA, *argv, p;
411 DWORD lenA;
412
413 lenA = WideCharToMultiByte(CP_ACP,0, str, len, NULL, 0, NULL, NULL);
414 strA = HeapAlloc(GetProcessHeap(), 0, lenA);
415 WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL);
416
417 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPSTR));
418 for (argc=0, p=strA; *p; p += strlen(p) + 1)
419 argv[argc++] = p;
420 argv[argc] = NULL;
421
422 info->proc.a(argc, argv);
423 HeapFree(GetProcessHeap(), 0, argv);
424 HeapFree(GetProcessHeap(), 0, strA);
425 }
426 return 0;
427 }
428
429 /******************************************************************************
430 * service_handle_start
431 */
432 static DWORD service_handle_start(service_data *service, const WCHAR *data, DWORD count)
433 {
434 TRACE("%s argsize %u\n", debugstr_w(service->name), count);
435
436 if (service->thread)
437 {
438 WARN("service is not stopped\n");
439 return ERROR_SERVICE_ALREADY_RUNNING;
440 }
441
442 HeapFree(GetProcessHeap(), 0, service->args);
443 service->args = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WCHAR));
444 memcpy( service->args, data, count * sizeof(WCHAR) );
445 service->thread = CreateThread( NULL, 0, service_thread,
446 service, 0, NULL );
447 SetEvent( service_event ); /* notify the main loop */
448 return 0;
449 }
450
451 /******************************************************************************
452 * service_handle_control
453 */
454 static DWORD service_handle_control(service_data *service, DWORD dwControl)
455 {
456 DWORD ret = ERROR_INVALID_SERVICE_CONTROL;
457
458 TRACE("%s control %u\n", debugstr_w(service->name), dwControl);
459
460 if (service->handler)
461 ret = service->handler(dwControl, 0, NULL, service->context);
462 return ret;
463 }
464
465 /******************************************************************************
466 * service_control_dispatcher
467 */
468 static DWORD WINAPI service_control_dispatcher(LPVOID arg)
469 {
470 SC_HANDLE manager;
471 HANDLE pipe;
472
473 if (!(manager = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT )))
474 {
475 ERR("failed to open service manager error %u\n", GetLastError());
476 return 0;
477 }
478
479 pipe = service_open_pipe();
480
481 if (pipe==INVALID_HANDLE_VALUE)
482 {
483 ERR("failed to create control pipe error = %d\n", GetLastError());
484 return 0;
485 }
486
487 /* dispatcher loop */
488 while (1)
489 {
490 service_data *service;
491 service_start_info info;
492 WCHAR *data = NULL;
493 BOOL r;
494 DWORD data_size = 0, count, result;
495
496 r = ReadFile( pipe, &info, FIELD_OFFSET(service_start_info,data), &count, NULL );
497 if (!r)
498 {
499 if (GetLastError() != ERROR_BROKEN_PIPE)
500 ERR( "pipe read failed error %u\n", GetLastError() );
501 break;
502 }
503 if (count != FIELD_OFFSET(service_start_info,data))
504 {
505 ERR( "partial pipe read %u\n", count );
506 break;
507 }
508 if (count < info.total_size)
509 {
510 data_size = info.total_size - FIELD_OFFSET(service_start_info,data);
511 data = HeapAlloc( GetProcessHeap(), 0, data_size );
512 r = ReadFile( pipe, data, data_size, &count, NULL );
513 if (!r)
514 {
515 if (GetLastError() != ERROR_BROKEN_PIPE)
516 ERR( "pipe read failed error %u\n", GetLastError() );
517 break;
518 }
519 if (count != data_size)
520 {
521 ERR( "partial pipe read %u/%u\n", count, data_size );
522 break;
523 }
524 }
525
526 /* find the service */
527
528 if (!(service = find_service_by_name( data )))
529 {
530 FIXME( "got request %u for unknown service %s\n", info.cmd, debugstr_w(data));
531 result = ERROR_INVALID_PARAMETER;
532 goto done;
533 }
534
535 TRACE( "got request %u for service %s\n", info.cmd, debugstr_w(data) );
536
537 /* handle the request */
538 switch (info.cmd)
539 {
540 case WINESERV_STARTINFO:
541 if (!service->handle)
542 {
543 if (!(service->handle = OpenServiceW( manager, data, SERVICE_SET_STATUS )))
544 FIXME( "failed to open service %s\n", debugstr_w(data) );
545 }
546 result = service_handle_start(service, data + info.name_size,
547 data_size / sizeof(WCHAR) - info.name_size );
548 break;
549 case WINESERV_SENDCONTROL:
550 result = service_handle_control(service, info.control);
551 break;
552 default:
553 ERR("received invalid command %u\n", info.cmd);
554 result = ERROR_INVALID_PARAMETER;
555 break;
556 }
557
558 done:
559 WriteFile(pipe, &result, sizeof(result), &count, NULL);
560 HeapFree( GetProcessHeap(), 0, data );
561 }
562
563 CloseHandle(pipe);
564 CloseServiceHandle( manager );
565 return 1;
566 }
567
568 /******************************************************************************
569 * service_run_main_thread
570 */
571 static BOOL service_run_main_thread(void)
572 {
573 DWORD i, n, ret;
574 HANDLE wait_handles[MAXIMUM_WAIT_OBJECTS];
575 UINT wait_services[MAXIMUM_WAIT_OBJECTS];
576
577 service_event = CreateEventW( NULL, FALSE, FALSE, NULL );
578
579 /* FIXME: service_control_dispatcher should be merged into the main thread */
580 wait_handles[0] = __wine_make_process_system();
581 wait_handles[1] = CreateThread( NULL, 0, service_control_dispatcher, NULL, 0, NULL );
582 wait_handles[2] = service_event;
583
584 TRACE("Starting %d services running as process %d\n",
585 nb_services, GetCurrentProcessId());
586
587 /* wait for all the threads to pack up and exit */
588 for (;;)
589 {
590 EnterCriticalSection( &service_cs );
591 for (i = 0, n = 3; i < nb_services && n < MAXIMUM_WAIT_OBJECTS; i++)
592 {
593 if (!services[i]->thread) continue;
594 wait_services[n] = i;
595 wait_handles[n++] = services[i]->thread;
596 }
597 LeaveCriticalSection( &service_cs );
598
599 ret = WaitForMultipleObjects( n, wait_handles, FALSE, INFINITE );
600 if (!ret) /* system process event */
601 {
602 TRACE( "last user process exited, shutting down\n" );
603 /* FIXME: we should maybe send a shutdown control to running services */
604 ExitProcess(0);
605 }
606 else if (ret == 1)
607 {
608 TRACE( "control dispatcher exited, shutting down\n" );
609 /* FIXME: we should maybe send a shutdown control to running services */
610 ExitProcess(0);
611 }
612 else if (ret == 2)
613 {
614 continue; /* rebuild the list */
615 }
616 else if (ret < n)
617 {
618 services[wait_services[ret]]->thread = 0;
619 CloseHandle( wait_handles[ret] );
620 if (n == 4) return TRUE; /* it was the last running thread */
621 }
622 else return FALSE;
623 }
624 }
625
626 /******************************************************************************
627 * StartServiceCtrlDispatcherA [ADVAPI32.@]
628 *
629 * See StartServiceCtrlDispatcherW.
630 */
631 BOOL WINAPI StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *servent )
632 {
633 service_data *info;
634 unsigned int i;
635 BOOL ret = TRUE;
636
637 TRACE("%p\n", servent);
638
639 if (nb_services)
640 {
641 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
642 return FALSE;
643 }
644 while (servent[nb_services].lpServiceName) nb_services++;
645 services = HeapAlloc( GetProcessHeap(), 0, nb_services * sizeof(*services) );
646
647 for (i = 0; i < nb_services; i++)
648 {
649 DWORD len = MultiByteToWideChar(CP_ACP, 0, servent[i].lpServiceName, -1, NULL, 0);
650 DWORD sz = FIELD_OFFSET( service_data, name[len] );
651 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
652 MultiByteToWideChar(CP_ACP, 0, servent[i].lpServiceName, -1, info->name, len);
653 info->proc.a = servent[i].lpServiceProc;
654 info->unicode = FALSE;
655 services[i] = info;
656 }
657
658 service_run_main_thread();
659
660 return ret;
661 }
662
663 /******************************************************************************
664 * StartServiceCtrlDispatcherW [ADVAPI32.@]
665 *
666 * Connects a process containing one or more services to the service control
667 * manager.
668 *
669 * PARAMS
670 * servent [I] A list of the service names and service procedures
671 *
672 * RETURNS
673 * Success: TRUE.
674 * Failure: FALSE.
675 */
676 BOOL WINAPI StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW *servent )
677 {
678 service_data *info;
679 unsigned int i;
680 BOOL ret = TRUE;
681
682 TRACE("%p\n", servent);
683
684 if (nb_services)
685 {
686 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
687 return FALSE;
688 }
689 while (servent[nb_services].lpServiceName) nb_services++;
690 services = HeapAlloc( GetProcessHeap(), 0, nb_services * sizeof(*services) );
691
692 for (i = 0; i < nb_services; i++)
693 {
694 DWORD len = strlenW(servent[i].lpServiceName) + 1;
695 DWORD sz = FIELD_OFFSET( service_data, name[len] );
696 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
697 strcpyW(info->name, servent[i].lpServiceName);
698 info->proc.w = servent[i].lpServiceProc;
699 info->unicode = TRUE;
700 services[i] = info;
701 }
702
703 service_run_main_thread();
704
705 return ret;
706 }
707
708 /******************************************************************************
709 * LockServiceDatabase [ADVAPI32.@]
710 */
711 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
712 {
713 struct sc_manager *hscm;
714 SC_RPC_LOCK hLock = NULL;
715 DWORD err;
716
717 TRACE("%p\n",hSCManager);
718
719 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
720 if (!hscm)
721 {
722 SetLastError( ERROR_INVALID_HANDLE );
723 return NULL;
724 }
725
726 __TRY
727 {
728 err = svcctl_LockServiceDatabase(hscm->hdr.server_handle, &hLock);
729 }
730 __EXCEPT(rpc_filter)
731 {
732 err = map_exception_code(GetExceptionCode());
733 }
734 __ENDTRY
735 if (err != ERROR_SUCCESS)
736 {
737 SetLastError(err);
738 return NULL;
739 }
740 return hLock;
741 }
742
743 /******************************************************************************
744 * UnlockServiceDatabase [ADVAPI32.@]
745 */
746 BOOL WINAPI UnlockServiceDatabase (SC_LOCK ScLock)
747 {
748 DWORD err;
749 SC_RPC_LOCK hRpcLock = ScLock;
750
751 TRACE("%p\n",ScLock);
752
753 __TRY
754 {
755 err = svcctl_UnlockServiceDatabase(&hRpcLock);
756 }
757 __EXCEPT(rpc_filter)
758 {
759 err = map_exception_code(GetExceptionCode());
760 }
761 __ENDTRY
762 if (err != ERROR_SUCCESS)
763 {
764 SetLastError(err);
765 return FALSE;
766 }
767 return TRUE;
768 }
769
770 /******************************************************************************
771 * SetServiceStatus [ADVAPI32.@]
772 *
773 * PARAMS
774 * hService []
775 * lpStatus []
776 */
777 BOOL WINAPI
778 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
779 {
780 struct sc_service *hsvc;
781 DWORD err;
782
783 TRACE("%p %x %x %x %x %x %x %x\n", hService,
784 lpStatus->dwServiceType, lpStatus->dwCurrentState,
785 lpStatus->dwControlsAccepted, lpStatus->dwWin32ExitCode,
786 lpStatus->dwServiceSpecificExitCode, lpStatus->dwCheckPoint,
787 lpStatus->dwWaitHint);
788
789 hsvc = sc_handle_get_handle_data((SC_HANDLE)hService, SC_HTYPE_SERVICE);
790 if (!hsvc)
791 {
792 SetLastError( ERROR_INVALID_HANDLE );
793 return FALSE;
794 }
795
796 __TRY
797 {
798 err = svcctl_SetServiceStatus( hsvc->hdr.server_handle, lpStatus );
799 }
800 __EXCEPT(rpc_filter)
801 {
802 err = map_exception_code(GetExceptionCode());
803 }
804 __ENDTRY
805 if (err != ERROR_SUCCESS)
806 {
807 SetLastError(err);
808 return FALSE;
809 }
810
811 if (lpStatus->dwCurrentState == SERVICE_STOPPED)
812 CloseServiceHandle((SC_HANDLE)hService);
813
814 return TRUE;
815 }
816
817
818 /******************************************************************************
819 * OpenSCManagerA [ADVAPI32.@]
820 *
821 * Establish a connection to the service control manager and open its database.
822 *
823 * PARAMS
824 * lpMachineName [I] Pointer to machine name string
825 * lpDatabaseName [I] Pointer to database name string
826 * dwDesiredAccess [I] Type of access
827 *
828 * RETURNS
829 * Success: A Handle to the service control manager database
830 * Failure: NULL
831 */
832 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
833 DWORD dwDesiredAccess )
834 {
835 LPWSTR lpMachineNameW, lpDatabaseNameW;
836 SC_HANDLE ret;
837
838 lpMachineNameW = SERV_dup(lpMachineName);
839 lpDatabaseNameW = SERV_dup(lpDatabaseName);
840 ret = OpenSCManagerW(lpMachineNameW, lpDatabaseNameW, dwDesiredAccess);
841 HeapFree(GetProcessHeap(), 0, lpDatabaseNameW);
842 HeapFree(GetProcessHeap(), 0, lpMachineNameW);
843 return ret;
844 }
845
846 /******************************************************************************
847 * OpenSCManagerW [ADVAPI32.@]
848 *
849 * See OpenSCManagerA.
850 */
851 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
852 DWORD dwDesiredAccess )
853 {
854 struct sc_manager *manager;
855 HKEY hReg;
856 LONG r;
857 DWORD new_mask = dwDesiredAccess;
858
859 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName),
860 debugstr_w(lpDatabaseName), dwDesiredAccess);
861
862 manager = sc_handle_alloc( SC_HTYPE_MANAGER, sizeof (struct sc_manager),
863 sc_handle_destroy_manager );
864 if (!manager)
865 return NULL;
866
867 __TRY
868 {
869 r = svcctl_OpenSCManagerW(lpMachineName, lpDatabaseName, dwDesiredAccess, &manager->hdr.server_handle);
870 }
871 __EXCEPT(rpc_filter)
872 {
873 r = map_exception_code(GetExceptionCode());
874 }
875 __ENDTRY
876 if (r!=ERROR_SUCCESS)
877 goto error;
878
879 r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
880 if (r!=ERROR_SUCCESS)
881 goto error;
882
883 r = RegCreateKeyW(hReg, szServiceManagerKey, &manager->hkey);
884 RegCloseKey( hReg );
885 if (r!=ERROR_SUCCESS)
886 goto error;
887
888 RtlMapGenericMask(&new_mask, &scm_generic);
889 manager->dwAccess = new_mask;
890 TRACE("returning %p (access : 0x%08x)\n", manager, manager->dwAccess);
891
892 return (SC_HANDLE) &manager->hdr;
893
894 error:
895 sc_handle_free( &manager->hdr );
896 SetLastError( r);
897 return NULL;
898 }
899
900 /******************************************************************************
901 * ControlService [ADVAPI32.@]
902 *
903 * Send a control code to a service.
904 *
905 * PARAMS
906 * hService [I] Handle of the service control manager database
907 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
908 * lpServiceStatus [O] Destination for the status of the service, if available
909 *
910 * RETURNS
911 * Success: TRUE.
912 * Failure: FALSE.
913 *
914 * BUGS
915 * Unlike M$' implementation, control requests are not serialized and may be
916 * processed asynchronously.
917 */
918 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
919 LPSERVICE_STATUS lpServiceStatus )
920 {
921 struct sc_service *hsvc;
922 DWORD err;
923
924 TRACE("%p %d %p\n", hService, dwControl, lpServiceStatus);
925
926 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
927 if (!hsvc)
928 {
929 SetLastError( ERROR_INVALID_HANDLE );
930 return FALSE;
931 }
932
933 __TRY
934 {
935 err = svcctl_ControlService(hsvc->hdr.server_handle, dwControl, lpServiceStatus);
936 }
937 __EXCEPT(rpc_filter)
938 {
939 err = map_exception_code(GetExceptionCode());
940 }
941 __ENDTRY
942 if (err != ERROR_SUCCESS)
943 {
944 SetLastError(err);
945 return FALSE;
946 }
947
948 return TRUE;
949 }
950
951 /******************************************************************************
952 * CloseServiceHandle [ADVAPI32.@]
953 *
954 * Close a handle to a service or the service control manager database.
955 *
956 * PARAMS
957 * hSCObject [I] Handle to service or service control manager database
958 *
959 * RETURNS
960 * Success: TRUE
961 * Failure: FALSE
962 */
963 BOOL WINAPI
964 CloseServiceHandle( SC_HANDLE hSCObject )
965 {
966 struct sc_handle *obj;
967 DWORD err;
968
969 TRACE("%p\n", hSCObject);
970 if (hSCObject == NULL)
971 {
972 SetLastError(ERROR_INVALID_HANDLE);
973 return FALSE;
974 }
975
976 obj = (struct sc_handle *)hSCObject;
977 __TRY
978 {
979 err = svcctl_CloseServiceHandle(&obj->server_handle);
980 }
981 __EXCEPT(rpc_filter)
982 {
983 err = map_exception_code(GetExceptionCode());
984 }
985 __ENDTRY
986 sc_handle_free( obj );
987
988 if (err != ERROR_SUCCESS)
989 {
990 SetLastError(err);
991 return FALSE;
992 }
993 return TRUE;
994 }
995
996
997 /******************************************************************************
998 * OpenServiceA [ADVAPI32.@]
999 *
1000 * Open a handle to a service.
1001 *
1002 * PARAMS
1003 * hSCManager [I] Handle of the service control manager database
1004 * lpServiceName [I] Name of the service to open
1005 * dwDesiredAccess [I] Access required to the service
1006 *
1007 * RETURNS
1008 * Success: Handle to the service
1009 * Failure: NULL
1010 */
1011 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1012 DWORD dwDesiredAccess )
1013 {
1014 LPWSTR lpServiceNameW;
1015 SC_HANDLE ret;
1016
1017 TRACE("%p %s %d\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
1018
1019 lpServiceNameW = SERV_dup(lpServiceName);
1020 ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
1021 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
1022 return ret;
1023 }
1024
1025
1026 /******************************************************************************
1027 * OpenServiceW [ADVAPI32.@]
1028 *
1029 * See OpenServiceA.
1030 */
1031 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1032 DWORD dwDesiredAccess)
1033 {
1034 struct sc_manager *hscm;
1035 struct sc_service *hsvc;
1036 DWORD err;
1037 DWORD len;
1038 DWORD new_mask = dwDesiredAccess;
1039
1040 TRACE("%p %s %d\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
1041
1042 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1043 if (!hscm)
1044 {
1045 SetLastError( ERROR_INVALID_HANDLE );
1046 return FALSE;
1047 }
1048
1049 if (!lpServiceName)
1050 {
1051 SetLastError(ERROR_INVALID_ADDRESS);
1052 return NULL;
1053 }
1054
1055 len = strlenW(lpServiceName)+1;
1056 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE,
1057 sizeof (struct sc_service) + len*sizeof(WCHAR),
1058 sc_handle_destroy_service );
1059 if (!hsvc)
1060 {
1061 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1062 return NULL;
1063 }
1064 strcpyW( hsvc->name, lpServiceName );
1065
1066 /* add reference to SCM handle */
1067 hscm->hdr.ref_count++;
1068 hsvc->scm = hscm;
1069
1070 __TRY
1071 {
1072 err = svcctl_OpenServiceW(hscm->hdr.server_handle, lpServiceName, dwDesiredAccess, &hsvc->hdr.server_handle);
1073 }
1074 __EXCEPT(rpc_filter)
1075 {
1076 err = map_exception_code(GetExceptionCode());
1077 }
1078 __ENDTRY
1079
1080 if (err != ERROR_SUCCESS)
1081 {
1082 sc_handle_free(&hsvc->hdr);
1083 SetLastError(err);
1084 return NULL;
1085 }
1086
1087 /* for parts of advapi32 not using services.exe yet */
1088 RtlMapGenericMask(&new_mask, &svc_generic);
1089 hsvc->dwAccess = new_mask;
1090
1091 err = RegOpenKeyExW( hscm->hkey, lpServiceName, 0, KEY_ALL_ACCESS, &hsvc->hkey );
1092 if (err != ERROR_SUCCESS)
1093 ERR("Shouldn't hapen - service key for service validated by services.exe doesn't exist\n");
1094
1095 TRACE("returning %p\n",hsvc);
1096
1097 return (SC_HANDLE) &hsvc->hdr;
1098 }
1099
1100 /******************************************************************************
1101 * CreateServiceW [ADVAPI32.@]
1102 */
1103 SC_HANDLE WINAPI
1104 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1105 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
1106 DWORD dwServiceType, DWORD dwStartType,
1107 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1108 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1109 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
1110 LPCWSTR lpPassword )
1111 {
1112 struct sc_manager *hscm;
1113 struct sc_service *hsvc = NULL;
1114 DWORD new_mask = dwDesiredAccess;
1115 DWORD len, err;
1116 SIZE_T passwdlen;
1117
1118 TRACE("%p %s %s\n", hSCManager,
1119 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
1120
1121 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1122 if (!hscm)
1123 {
1124 SetLastError( ERROR_INVALID_HANDLE );
1125 return NULL;
1126 }
1127
1128 if (!lpServiceName || !lpBinaryPathName)
1129 {
1130 SetLastError(ERROR_INVALID_ADDRESS);
1131 return NULL;
1132 }
1133
1134 if (lpPassword)
1135 passwdlen = (strlenW(lpPassword) + 1) * sizeof(WCHAR);
1136 else
1137 passwdlen = 0;
1138
1139 len = strlenW(lpServiceName)+1;
1140 len = sizeof (struct sc_service) + len*sizeof(WCHAR);
1141 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE, len, sc_handle_destroy_service );
1142 if( !hsvc )
1143 {
1144 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1145 return NULL;
1146 }
1147 lstrcpyW( hsvc->name, lpServiceName );
1148
1149 hsvc->scm = hscm;
1150 hscm->hdr.ref_count++;
1151
1152 __TRY
1153 {
1154 err = svcctl_CreateServiceW(hscm->hdr.server_handle, lpServiceName,
1155 lpDisplayName, dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1156 lpBinaryPathName, lpLoadOrderGroup, lpdwTagId, (LPBYTE)lpDependencies,
1157 multisz_cb(lpDependencies), lpServiceStartName, (LPBYTE)lpPassword, passwdlen,
1158 &hsvc->hdr.server_handle);
1159 }
1160 __EXCEPT(rpc_filter)
1161 {
1162 err = map_exception_code(GetExceptionCode());
1163 }
1164 __ENDTRY
1165
1166 if (err != ERROR_SUCCESS)
1167 {
1168 SetLastError(err);
1169 sc_handle_free(&hsvc->hdr);
1170 return NULL;
1171 }
1172
1173 /* for parts of advapi32 not using services.exe yet */
1174 err = RegOpenKeyW(hscm->hkey, lpServiceName, &hsvc->hkey);
1175 if (err != ERROR_SUCCESS)
1176 WINE_ERR("Couldn't open key that should have been created by services.exe\n");
1177
1178 RtlMapGenericMask(&new_mask, &svc_generic);
1179 hsvc->dwAccess = new_mask;
1180
1181 return (SC_HANDLE) &hsvc->hdr;
1182 }
1183
1184
1185 /******************************************************************************
1186 * CreateServiceA [ADVAPI32.@]
1187 */
1188 SC_HANDLE WINAPI
1189 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1190 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1191 DWORD dwServiceType, DWORD dwStartType,
1192 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1193 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1194 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1195 LPCSTR lpPassword )
1196 {
1197 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1198 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1199 SC_HANDLE r;
1200
1201 TRACE("%p %s %s\n", hSCManager,
1202 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1203
1204 lpServiceNameW = SERV_dup( lpServiceName );
1205 lpDisplayNameW = SERV_dup( lpDisplayName );
1206 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1207 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1208 lpDependenciesW = SERV_dupmulti( lpDependencies );
1209 lpServiceStartNameW = SERV_dup( lpServiceStartName );
1210 lpPasswordW = SERV_dup( lpPassword );
1211
1212 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1213 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1214 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1215 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1216
1217 HeapFree( GetProcessHeap(), 0, lpServiceNameW );
1218 HeapFree( GetProcessHeap(), 0, lpDisplayNameW );
1219 HeapFree( GetProcessHeap(), 0, lpBinaryPathNameW );
1220 HeapFree( GetProcessHeap(), 0, lpLoadOrderGroupW );
1221 HeapFree( GetProcessHeap(), 0, lpDependenciesW );
1222 HeapFree( GetProcessHeap(), 0, lpServiceStartNameW );
1223 HeapFree( GetProcessHeap(), 0, lpPasswordW );
1224
1225 return r;
1226 }
1227
1228
1229 /******************************************************************************
1230 * DeleteService [ADVAPI32.@]
1231 *
1232 * Delete a service from the service control manager database.
1233 *
1234 * PARAMS
1235 * hService [I] Handle of the service to delete
1236 *
1237 * RETURNS
1238 * Success: TRUE
1239 * Failure: FALSE
1240 */
1241 BOOL WINAPI DeleteService( SC_HANDLE hService )
1242 {
1243 struct sc_service *hsvc;
1244 DWORD err;
1245
1246 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1247 if (!hsvc)
1248 {
1249 SetLastError( ERROR_INVALID_HANDLE );
1250 return FALSE;
1251 }
1252
1253 __TRY
1254 {
1255 err = svcctl_DeleteService(hsvc->hdr.server_handle);
1256 }
1257 __EXCEPT(rpc_filter)
1258 {
1259 err = map_exception_code(GetExceptionCode());
1260 }
1261 __ENDTRY
1262 if (err != 0)
1263 {
1264 SetLastError(err);
1265 return FALSE;
1266 }
1267
1268 /* Close the key to the service */
1269 RegCloseKey(hsvc->hkey);
1270 hsvc->hkey = NULL;
1271 return TRUE;
1272 }
1273
1274
1275 /******************************************************************************
1276 * StartServiceA [ADVAPI32.@]
1277 *
1278 * Start a service
1279 *
1280 * PARAMS
1281 * hService [I] Handle of service
1282 * dwNumServiceArgs [I] Number of arguments
1283 * lpServiceArgVectors [I] Address of array of argument strings
1284 *
1285 * NOTES
1286 * - NT implements this function using an obscure RPC call.
1287 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1288 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1289 * - This will only work for shared address space. How should the service
1290 * args be transferred when address spaces are separated?
1291 * - Can only start one service at a time.
1292 * - Has no concept of privilege.
1293 *
1294 * RETURNS
1295 * Success: TRUE.
1296 * Failure: FALSE
1297 */
1298 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1299 LPCSTR *lpServiceArgVectors )
1300 {
1301 LPWSTR *lpwstr=NULL;
1302 unsigned int i;
1303 BOOL r;
1304
1305 TRACE("(%p,%d,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1306
1307 if (dwNumServiceArgs)
1308 lpwstr = HeapAlloc( GetProcessHeap(), 0,
1309 dwNumServiceArgs*sizeof(LPWSTR) );
1310
1311 for(i=0; i<dwNumServiceArgs; i++)
1312 lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1313
1314 r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1315
1316 if (dwNumServiceArgs)
1317 {
1318 for(i=0; i<dwNumServiceArgs; i++)
1319 HeapFree(GetProcessHeap(), 0, lpwstr[i]);
1320 HeapFree(GetProcessHeap(), 0, lpwstr);
1321 }
1322
1323 return r;
1324 }
1325
1326
1327 /******************************************************************************
1328 * StartServiceW [ADVAPI32.@]
1329 *
1330 * See StartServiceA.
1331 */
1332 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1333 LPCWSTR *lpServiceArgVectors)
1334 {
1335 struct sc_service *hsvc;
1336 DWORD err;
1337
1338 TRACE("%p %d %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1339
1340 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1341 if (!hsvc)
1342 {
1343 SetLastError(ERROR_INVALID_HANDLE);
1344 return FALSE;
1345 }
1346
1347 __TRY
1348 {
1349 err = svcctl_StartServiceW(hsvc->hdr.server_handle, dwNumServiceArgs, lpServiceArgVectors);
1350 }
1351 __EXCEPT(rpc_filter)
1352 {
1353 err = map_exception_code(GetExceptionCode());
1354 }
1355 __ENDTRY
1356 if (err != ERROR_SUCCESS)
1357 {
1358 SetLastError(err);
1359 return FALSE;
1360 }
1361
1362 return TRUE;
1363 }
1364
1365 /******************************************************************************
1366 * QueryServiceStatus [ADVAPI32.@]
1367 *
1368 * PARAMS
1369 * hService [I] Handle to service to get information about
1370 * lpservicestatus [O] buffer to receive the status information for the service
1371 *
1372 */
1373 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1374 LPSERVICE_STATUS lpservicestatus)
1375 {
1376 SERVICE_STATUS_PROCESS SvcStatusData;
1377 BOOL ret;
1378 DWORD dummy;
1379
1380 TRACE("%p %p\n", hService, lpservicestatus);
1381
1382 ret = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&SvcStatusData,
1383 sizeof(SERVICE_STATUS_PROCESS), &dummy);
1384 if (ret) memcpy(lpservicestatus, &SvcStatusData, sizeof(SERVICE_STATUS)) ;
1385 return ret;
1386 }
1387
1388
1389 /******************************************************************************
1390 * QueryServiceStatusEx [ADVAPI32.@]
1391 *
1392 * Get information about a service.
1393 *
1394 * PARAMS
1395 * hService [I] Handle to service to get information about
1396 * InfoLevel [I] Level of information to get
1397 * lpBuffer [O] Destination for requested information
1398 * cbBufSize [I] Size of lpBuffer in bytes
1399 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1400 *
1401 * RETURNS
1402 * Success: TRUE
1403 * FAILURE: FALSE
1404 */
1405 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1406 LPBYTE lpBuffer, DWORD cbBufSize,
1407 LPDWORD pcbBytesNeeded)
1408 {
1409 struct sc_service *hsvc;
1410 DWORD err;
1411
1412 TRACE("%p %d %p %d %p\n", hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1413
1414 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1415 if (!hsvc)
1416 {
1417 SetLastError( ERROR_INVALID_HANDLE );
1418 return FALSE;
1419 }
1420
1421 __TRY
1422 {
1423 err = svcctl_QueryServiceStatusEx(hsvc->hdr.server_handle, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1424 }
1425 __EXCEPT(rpc_filter)
1426 {
1427 err = map_exception_code(GetExceptionCode());
1428 }
1429 __ENDTRY
1430 if (err != ERROR_SUCCESS)
1431 {
1432 SetLastError(err);
1433 return FALSE;
1434 }
1435
1436 return TRUE;
1437 }
1438
1439 /******************************************************************************
1440 * QueryServiceConfigA [ADVAPI32.@]
1441 */
1442 BOOL WINAPI QueryServiceConfigA( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGA config,
1443 DWORD size, LPDWORD needed )
1444 {
1445 DWORD n;
1446 LPSTR p, buffer;
1447 BOOL ret;
1448 QUERY_SERVICE_CONFIGW *configW;
1449
1450 TRACE("%p %p %d %p\n", hService, config, size, needed);
1451
1452 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, 2 * size )))
1453 {
1454 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1455 return FALSE;
1456 }
1457 configW = (QUERY_SERVICE_CONFIGW *)buffer;
1458 ret = QueryServiceConfigW( hService, configW, 2 * size, needed );
1459 if (!ret) goto done;
1460
1461 config->dwServiceType = configW->dwServiceType;
1462 config->dwStartType = configW->dwStartType;
1463 config->dwErrorControl = configW->dwErrorControl;
1464 config->lpBinaryPathName = NULL;
1465 config->lpLoadOrderGroup = NULL;
1466 config->dwTagId = configW->dwTagId;
1467 config->lpDependencies = NULL;
1468 config->lpServiceStartName = NULL;
1469 config->lpDisplayName = NULL;
1470
1471 p = (LPSTR)(config + 1);
1472 n = size - sizeof(*config);
1473 ret = FALSE;
1474
1475 #define MAP_STR(str) \
1476 do { \
1477 if (configW->str) \
1478 { \
1479 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1480 if (!sz) goto done; \
1481 config->str = p; \
1482 p += sz; \
1483 n -= sz; \
1484 } \
1485 } while (0)
1486
1487 MAP_STR( lpBinaryPathName );
1488 MAP_STR( lpLoadOrderGroup );
1489 MAP_STR( lpDependencies );
1490 MAP_STR( lpServiceStartName );
1491 MAP_STR( lpDisplayName );
1492 #undef MAP_STR
1493
1494 *needed = p - (LPSTR)config;
1495 ret = TRUE;
1496
1497 done:
1498 HeapFree( GetProcessHeap(), 0, buffer );
1499 return ret;
1500 }
1501
1502 static DWORD move_string_to_buffer(BYTE **buf, LPWSTR *string_ptr)
1503 {
1504 DWORD cb;
1505
1506 if (!*string_ptr)
1507 {
1508 cb = sizeof(WCHAR);
1509 memset(*buf, 0, cb);
1510 }
1511 else
1512 {
1513 cb = (strlenW(*string_ptr) + 1)*sizeof(WCHAR);
1514 memcpy(*buf, *string_ptr, cb);
1515 MIDL_user_free(*string_ptr);
1516 }
1517
1518 *string_ptr = (LPWSTR)*buf;
1519 *buf += cb;
1520
1521 return cb;
1522 }
1523
1524 static DWORD size_string(LPWSTR string)
1525 {
1526 return (string ? (strlenW(string) + 1)*sizeof(WCHAR) : sizeof(WCHAR));
1527 }
1528
1529 /******************************************************************************
1530 * QueryServiceConfigW [ADVAPI32.@]
1531 */
1532 BOOL WINAPI
1533 QueryServiceConfigW( SC_HANDLE hService,
1534 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1535 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1536 {
1537 QUERY_SERVICE_CONFIGW config;
1538 struct sc_service *hsvc;
1539 DWORD total;
1540 DWORD err;
1541 BYTE *bufpos;
1542
1543 TRACE("%p %p %d %p\n", hService, lpServiceConfig,
1544 cbBufSize, pcbBytesNeeded);
1545
1546 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1547 if (!hsvc)
1548 {
1549 SetLastError( ERROR_INVALID_HANDLE );
1550 return FALSE;
1551 }
1552
1553 memset(&config, 0, sizeof(config));
1554
1555 __TRY
1556 {
1557 err = svcctl_QueryServiceConfigW(hsvc->hdr.server_handle, &config);
1558 }
1559 __EXCEPT(rpc_filter)
1560 {
1561 err = map_exception_code(GetExceptionCode());
1562 }
1563 __ENDTRY
1564
1565 if (err != ERROR_SUCCESS)
1566 {
1567 TRACE("services.exe: error %u\n", err);
1568 SetLastError(err);
1569 return FALSE;
1570 }
1571
1572 /* calculate the size required first */
1573 total = sizeof (QUERY_SERVICE_CONFIGW);
1574 total += size_string(config.lpBinaryPathName);
1575 total += size_string(config.lpLoadOrderGroup);
1576 total += size_string(config.lpDependencies);
1577 total += size_string(config.lpServiceStartName);
1578 total += size_string(config.lpDisplayName);
1579
1580 *pcbBytesNeeded = total;
1581
1582 /* if there's not enough memory, return an error */
1583 if( total > cbBufSize )
1584 {
1585 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1586 MIDL_user_free(config.lpBinaryPathName);
1587 MIDL_user_free(config.lpLoadOrderGroup);
1588 MIDL_user_free(config.lpDependencies);
1589 MIDL_user_free(config.lpServiceStartName);
1590 MIDL_user_free(config.lpDisplayName);
1591 return FALSE;
1592 }
1593
1594 *lpServiceConfig = config;
1595 bufpos = ((BYTE *)lpServiceConfig) + sizeof(QUERY_SERVICE_CONFIGW);
1596 move_string_to_buffer(&bufpos, &lpServiceConfig->lpBinaryPathName);
1597 move_string_to_buffer(&bufpos, &lpServiceConfig->lpLoadOrderGroup);
1598 move_string_to_buffer(&bufpos, &lpServiceConfig->lpDependencies);
1599 move_string_to_buffer(&bufpos, &lpServiceConfig->lpServiceStartName);
1600 move_string_to_buffer(&bufpos, &lpServiceConfig->lpDisplayName);
1601
1602 if (bufpos - (LPBYTE)lpServiceConfig > cbBufSize)
1603 ERR("Buffer overflow!\n");
1604
1605 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1606 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1607 TRACE("Dependencies = %s\n", debugstr_w(lpServiceConfig->lpDependencies) );
1608 TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig->lpServiceStartName) );
1609 TRACE("Display name = %s\n", debugstr_w(lpServiceConfig->lpDisplayName) );
1610
1611 return TRUE;
1612 }
1613
1614 /******************************************************************************
1615 * QueryServiceConfig2A [ADVAPI32.@]
1616 *
1617 * Note
1618 * observed under win2k:
1619 * The functions QueryServiceConfig2A and QueryServiceConfig2W return the same
1620 * required buffer size (in byte) at least for dwLevel SERVICE_CONFIG_DESCRIPTION
1621 */
1622 BOOL WINAPI QueryServiceConfig2A(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffer,
1623 DWORD size, LPDWORD needed)
1624 {
1625 BOOL ret;
1626 LPBYTE bufferW = NULL;
1627
1628 if(buffer && size)
1629 bufferW = HeapAlloc( GetProcessHeap(), 0, size);
1630
1631 ret = QueryServiceConfig2W(hService, dwLevel, bufferW, size, needed);
1632 if(!ret) goto cleanup;
1633
1634 switch(dwLevel) {
1635 case SERVICE_CONFIG_DESCRIPTION:
1636 { LPSERVICE_DESCRIPTIONA configA = (LPSERVICE_DESCRIPTIONA) buffer;
1637 LPSERVICE_DESCRIPTIONW configW = (LPSERVICE_DESCRIPTIONW) bufferW;
1638 if (configW->lpDescription) {
1639 DWORD sz;
1640 configA->lpDescription = (LPSTR)(configA + 1);
1641 sz = WideCharToMultiByte( CP_ACP, 0, configW->lpDescription, -1,
1642 configA->lpDescription, size - sizeof(SERVICE_DESCRIPTIONA), NULL, NULL );
1643 if (!sz) {
1644 FIXME("WideCharToMultiByte failed for configW->lpDescription\n");
1645 ret = FALSE;
1646 configA->lpDescription = NULL;
1647 }
1648 }
1649 else configA->lpDescription = NULL;
1650 }
1651 break;
1652 default:
1653 FIXME("conversation W->A not implemented for level %d\n", dwLevel);
1654 ret = FALSE;
1655 }
1656
1657 cleanup:
1658 HeapFree( GetProcessHeap(), 0, bufferW);
1659 return ret;
1660 }
1661
1662 /******************************************************************************
1663 * QueryServiceConfig2W [ADVAPI32.@]
1664 */
1665 BOOL WINAPI QueryServiceConfig2W(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffer,
1666 DWORD size, LPDWORD needed)
1667 {
1668 DWORD sz, type;
1669 HKEY hKey;
1670 LONG r;
1671 struct sc_service *hsvc;
1672
1673 if(dwLevel != SERVICE_CONFIG_DESCRIPTION) {
1674 if((dwLevel == SERVICE_CONFIG_DELAYED_AUTO_START_INFO) ||
1675 (dwLevel == SERVICE_CONFIG_FAILURE_ACTIONS) ||
1676 (dwLevel == SERVICE_CONFIG_FAILURE_ACTIONS_FLAG) ||
1677 (dwLevel == SERVICE_CONFIG_PRESHUTDOWN_INFO) ||
1678 (dwLevel == SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO) ||
1679 (dwLevel == SERVICE_CONFIG_SERVICE_SID_INFO))
1680 FIXME("Level %d not implemented\n", dwLevel);
1681 SetLastError(ERROR_INVALID_LEVEL);
1682 return FALSE;
1683 }
1684 if(!needed || (!buffer && size)) {
1685 SetLastError(ERROR_INVALID_ADDRESS);
1686 return FALSE;
1687 }
1688
1689 TRACE("%p 0x%d %p 0x%d %p\n", hService, dwLevel, buffer, size, needed);
1690
1691 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1692 if (!hsvc)
1693 {
1694 SetLastError(ERROR_INVALID_HANDLE);
1695 return FALSE;
1696 }
1697 hKey = hsvc->hkey;
1698
1699 switch(dwLevel) {
1700 case SERVICE_CONFIG_DESCRIPTION: {
1701 static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
1702 LPSERVICE_DESCRIPTIONW config = (LPSERVICE_DESCRIPTIONW) buffer;
1703 LPBYTE strbuf = NULL;
1704 *needed = sizeof (SERVICE_DESCRIPTIONW);
1705 sz = size - *needed;
1706 if(config && (*needed <= size))
1707 strbuf = (LPBYTE) (config + 1);
1708 r = RegQueryValueExW( hKey, szDescription, 0, &type, strbuf, &sz );
1709 if((r == ERROR_SUCCESS) && ( type != REG_SZ)) {
1710 FIXME("SERVICE_CONFIG_DESCRIPTION: don't know how to handle type %d\n", type);
1711 return FALSE;
1712 }
1713 *needed += sz;
1714 if(config) {
1715 if(r == ERROR_SUCCESS)
1716 config->lpDescription = (LPWSTR) (config + 1);
1717 else
1718 config->lpDescription = NULL;
1719 }
1720 }
1721 break;
1722 }
1723 if(*needed > size)
1724 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1725
1726 return (*needed <= size);
1727 }
1728
1729 /******************************************************************************
1730 * EnumServicesStatusA [ADVAPI32.@]
1731 */
1732 BOOL WINAPI
1733 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
1734 DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
1735 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1736 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1737 {
1738 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
1739 dwServiceType, dwServiceState, lpServices, cbBufSize,
1740 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
1741 SetLastError (ERROR_ACCESS_DENIED);
1742 return FALSE;
1743 }
1744
1745 /******************************************************************************
1746 * EnumServicesStatusW [ADVAPI32.@]
1747 */
1748 BOOL WINAPI
1749 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
1750 DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
1751 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1752 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1753 {
1754 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
1755 dwServiceType, dwServiceState, lpServices, cbBufSize,
1756 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
1757 SetLastError (ERROR_ACCESS_DENIED);
1758 return FALSE;
1759 }
1760
1761 /******************************************************************************
1762 * EnumServicesStatusExA [ADVAPI32.@]
1763 */
1764 BOOL WINAPI
1765 EnumServicesStatusExA(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
1766 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1767 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCSTR pszGroupName)
1768 {
1769 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
1770 dwServiceType, dwServiceState, lpServices, cbBufSize,
1771 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_a(pszGroupName));
1772 *lpServicesReturned = 0;
1773 SetLastError (ERROR_ACCESS_DENIED);
1774 return FALSE;
1775 }
1776
1777 /******************************************************************************
1778 * EnumServicesStatusExW [ADVAPI32.@]
1779 */
1780 BOOL WINAPI
1781 EnumServicesStatusExW(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
1782 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1783 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCWSTR pszGroupName)
1784 {
1785 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
1786 dwServiceType, dwServiceState, lpServices, cbBufSize,
1787 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_w(pszGroupName));
1788 SetLastError (ERROR_ACCESS_DENIED);
1789 return FALSE;
1790 }
1791
1792 /******************************************************************************
1793 * GetServiceKeyNameA [ADVAPI32.@]
1794 */
1795 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
1796 LPSTR lpServiceName, LPDWORD lpcchBuffer )
1797 {
1798 LPWSTR lpDisplayNameW, lpServiceNameW;
1799 DWORD sizeW;
1800 BOOL ret = FALSE;
1801
1802 TRACE("%p %s %p %p\n", hSCManager,
1803 debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
1804
1805 lpDisplayNameW = SERV_dup(lpDisplayName);
1806 if (lpServiceName)
1807 lpServiceNameW = HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer * sizeof(WCHAR));
1808 else
1809 lpServiceNameW = NULL;
1810
1811 sizeW = *lpcchBuffer;
1812 if (!GetServiceKeyNameW(hSCManager, lpDisplayNameW, lpServiceNameW, &sizeW))
1813 {
1814 if (lpServiceName && *lpcchBuffer)
1815 lpServiceName[0] = 0;
1816 *lpcchBuffer = sizeW*2; /* we can only provide an upper estimation of string length */
1817 goto cleanup;
1818 }
1819
1820 if (!WideCharToMultiByte(CP_ACP, 0, lpServiceNameW, (sizeW + 1), lpServiceName,
1821 *lpcchBuffer, NULL, NULL ))
1822 {
1823 if (*lpcchBuffer && lpServiceName)
1824 lpServiceName[0] = 0;
1825 *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpServiceNameW, -1, NULL, 0, NULL, NULL);
1826 goto cleanup;
1827 }
1828
1829 /* lpcchBuffer not updated - same as in GetServiceDisplayNameA */
1830 ret = TRUE;
1831
1832 cleanup:
1833 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
1834 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
1835 return ret;
1836 }
1837
1838 /******************************************************************************
1839 * GetServiceKeyNameW [ADVAPI32.@]
1840 */
1841 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
1842 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
1843 {
1844 struct sc_manager *hscm;
1845 DWORD err;
1846
1847 TRACE("%p %s %p %p\n", hSCManager,
1848 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
1849
1850 hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
1851 if (!hscm)
1852 {
1853 SetLastError(ERROR_INVALID_HANDLE);
1854 return FALSE;
1855 }
1856
1857 if (!lpDisplayName)
1858 {
1859 SetLastError(ERROR_INVALID_ADDRESS);
1860 return FALSE;
1861 }
1862
1863 __TRY
1864 {
1865 err = svcctl_GetServiceKeyNameW(hscm->hdr.server_handle,
1866 lpDisplayName, lpServiceName, lpServiceName ? *lpcchBuffer : 0, lpcchBuffer);
1867 }
1868 __EXCEPT(rpc_filter)
1869 {
1870 err = map_exception_code(GetExceptionCode());
1871 }
1872 __ENDTRY
1873
1874 if (err)
1875 SetLastError(err);
1876 return err == ERROR_SUCCESS;
1877 }
1878
1879 /******************************************************************************
1880 * QueryServiceLockStatusA [ADVAPI32.@]
1881 */
1882 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
1883 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
1884 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1885 {
1886 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1887
1888 return FALSE;
1889 }
1890
1891 /******************************************************************************
1892 * QueryServiceLockStatusW [ADVAPI32.@]
1893 */
1894 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
1895 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
1896 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1897 {
1898 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1899
1900 return FALSE;
1901 }
1902
1903 /******************************************************************************
1904 * GetServiceDisplayNameA [ADVAPI32.@]
1905 */
1906 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1907 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
1908 {
1909 LPWSTR lpServiceNameW, lpDisplayNameW;
1910 DWORD sizeW;
1911 BOOL ret = FALSE;
1912
1913 TRACE("%p %s %p %p\n", hSCManager,
1914 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
1915
1916 lpServiceNameW = SERV_dup(lpServiceName);
1917 if (lpDisplayName)
1918 lpDisplayNameW = HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer * sizeof(WCHAR));
1919 else
1920 lpDisplayNameW = NULL;
1921
1922 sizeW = *lpcchBuffer;
1923 if (!GetServiceDisplayNameW(hSCManager, lpServiceNameW, lpDisplayNameW, &sizeW))
1924 {
1925 if (lpDisplayName && *lpcchBuffer)
1926 lpDisplayName[0] = 0;
1927 *lpcchBuffer = sizeW*2; /* we can only provide an upper estimation of string length */
1928 goto cleanup;
1929 }
1930
1931 if (!WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, (sizeW + 1), lpDisplayName,
1932 *lpcchBuffer, NULL, NULL ))
1933 {
1934 if (*lpcchBuffer && lpDisplayName)
1935 lpDisplayName[0] = 0;
1936 *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, -1, NULL, 0, NULL, NULL);
1937 goto cleanup;
1938 }
1939
1940 /* probably due to a bug GetServiceDisplayNameA doesn't modify lpcchBuffer on success.
1941 * (but if the function succeeded it means that is a good upper estimation of the size) */
1942 ret = TRUE;
1943
1944 cleanup:
1945 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
1946 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
1947 return ret;
1948 }
1949
1950 /******************************************************************************
1951 * GetServiceDisplayNameW [ADVAPI32.@]
1952 */
1953 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1954 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
1955 {
1956 struct sc_manager *hscm;
1957 DWORD err;
1958
1959 TRACE("%p %s %p %p\n", hSCManager,
1960 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
1961
1962 hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
1963 if (!hscm)
1964 {
1965 SetLastError(ERROR_INVALID_HANDLE);
1966 return FALSE;
1967 }
1968
1969 if (!lpServiceName)
1970 {
1971 SetLastError(ERROR_INVALID_ADDRESS);
1972 return FALSE;
1973 }
1974
1975 __TRY
1976 {
1977 err = svcctl_GetServiceDisplayNameW(hscm->hdr.server_handle,
1978 lpServiceName, lpDisplayName, lpDisplayName ? *lpcchBuffer : 0, lpcchBuffer);
1979 }
1980 __EXCEPT(rpc_filter)
1981 {
1982 err = map_exception_code(GetExceptionCode());
1983 }
1984 __ENDTRY
1985
1986 if (err)
1987 SetLastError(err);
1988 return err == ERROR_SUCCESS;
1989 }
1990
1991 /******************************************************************************
1992 * ChangeServiceConfigW [ADVAPI32.@]
1993 */
1994 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
1995 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1996 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
1997 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
1998 {
1999 struct sc_service *hsvc;
2000 DWORD cb_pwd;
2001 DWORD err;
2002
2003 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2004 hService, dwServiceType, dwStartType, dwErrorControl,
2005 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2006 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2007 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2008
2009 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2010 if (!hsvc)
2011 {
2012 SetLastError( ERROR_INVALID_HANDLE );
2013 return FALSE;
2014 }
2015
2016 cb_pwd = lpPassword ? (strlenW(lpPassword) + 1)*sizeof(WCHAR) : 0;
2017
2018 __TRY
2019 {
2020 err = svcctl_ChangeServiceConfigW(hsvc->hdr.server_handle, dwServiceType,
2021 dwStartType, dwErrorControl, lpBinaryPathName, lpLoadOrderGroup, lpdwTagId,
2022 (const BYTE *)lpDependencies, multisz_cb(lpDependencies), lpServiceStartName,
2023 (const BYTE *)lpPassword, cb_pwd, lpDisplayName);
2024 }
2025 __EXCEPT(rpc_filter)
2026 {
2027 err = map_exception_code(GetExceptionCode());
2028 }
2029 __ENDTRY
2030
2031 if (err != ERROR_SUCCESS)
2032 SetLastError(err);
2033
2034 return err == ERROR_SUCCESS;
2035 }
2036
2037 /******************************************************************************
2038 * ChangeServiceConfigA [ADVAPI32.@]
2039 */
2040 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2041 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2042 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2043 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2044 {
2045 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2046 LPWSTR wServiceStartName, wPassword, wDisplayName;
2047 BOOL r;
2048
2049 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2050 hService, dwServiceType, dwStartType, dwErrorControl,
2051 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2052 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2053 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2054
2055 wBinaryPathName = SERV_dup( lpBinaryPathName );
2056 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2057 wDependencies = SERV_dupmulti( lpDependencies );
2058 wServiceStartName = SERV_dup( lpServiceStartName );
2059 wPassword = SERV_dup( lpPassword );
2060 wDisplayName = SERV_dup( lpDisplayName );
2061
2062 r = ChangeServiceConfigW( hService, dwServiceType,
2063 dwStartType, dwErrorControl, wBinaryPathName,
2064 wLoadOrderGroup, lpdwTagId, wDependencies,
2065 wServiceStartName, wPassword, wDisplayName);
2066
2067 HeapFree( GetProcessHeap(), 0, wBinaryPathName );
2068 HeapFree( GetProcessHeap(), 0, wLoadOrderGroup );
2069 HeapFree( GetProcessHeap(), 0, wDependencies );
2070 HeapFree( GetProcessHeap(), 0, wServiceStartName );
2071 HeapFree( GetProcessHeap(), 0, wPassword );
2072 HeapFree( GetProcessHeap(), 0, wDisplayName );
2073
2074 return r;
2075 }
2076
2077 /******************************************************************************
2078 * ChangeServiceConfig2A [ADVAPI32.@]
2079 */
2080 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2081 LPVOID lpInfo)
2082 {
2083 BOOL r = FALSE;
2084
2085 TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo);
2086
2087 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2088 {
2089 LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
2090 SERVICE_DESCRIPTIONW sdw;
2091
2092 sdw.lpDescription = SERV_dup( sd->lpDescription );
2093
2094 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2095
2096 HeapFree( GetProcessHeap(), 0, sdw.lpDescription );
2097 }
2098 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2099 {
2100 LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
2101 SERVICE_FAILURE_ACTIONSW faw;
2102
2103 faw.dwResetPeriod = fa->dwResetPeriod;
2104 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2105 faw.lpCommand = SERV_dup( fa->lpCommand );
2106 faw.cActions = fa->cActions;
2107 faw.lpsaActions = fa->lpsaActions;
2108
2109 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2110
2111 HeapFree( GetProcessHeap(), 0, faw.lpRebootMsg );
2112 HeapFree( GetProcessHeap(), 0, faw.lpCommand );
2113 }
2114 else
2115 SetLastError( ERROR_INVALID_PARAMETER );
2116
2117 return r;
2118 }
2119
2120 /******************************************************************************
2121 * ChangeServiceConfig2W [ADVAPI32.@]
2122 */
2123 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2124 LPVOID lpInfo)
2125 {
2126 HKEY hKey;
2127 struct sc_service *hsvc;
2128
2129 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2130 if (!hsvc)
2131 {
2132 SetLastError( ERROR_INVALID_HANDLE );
2133 return FALSE;
2134 }
2135 hKey = hsvc->hkey;
2136
2137 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2138 {
2139 static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2140 LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
2141 if (sd->lpDescription)
2142 {
2143 TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
2144 if (sd->lpDescription[0] == 0)
2145 RegDeleteValueW(hKey,szDescription);
2146 else
2147 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2148 (LPVOID)sd->lpDescription,
2149 sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2150 }
2151 }
2152 else
2153 FIXME("STUB: %p %d %p\n",hService, dwInfoLevel, lpInfo);
2154 return TRUE;
2155 }
2156
2157 /******************************************************************************
2158 * QueryServiceObjectSecurity [ADVAPI32.@]
2159 */
2160 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2161 SECURITY_INFORMATION dwSecurityInformation,
2162 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2163 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2164 {
2165 SECURITY_DESCRIPTOR descriptor;
2166 DWORD size;
2167 BOOL succ;
2168 ACL acl;
2169
2170 FIXME("%p %d %p %u %p - semi-stub\n", hService, dwSecurityInformation,
2171 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2172
2173 if (dwSecurityInformation != DACL_SECURITY_INFORMATION)
2174 FIXME("information %d not supported\n", dwSecurityInformation);
2175
2176 InitializeSecurityDescriptor(&descriptor, SECURITY_DESCRIPTOR_REVISION);
2177
2178 InitializeAcl(&acl, sizeof(ACL), ACL_REVISION);
2179 SetSecurityDescriptorDacl(&descriptor, TRUE, &acl, TRUE);
2180
2181 size = cbBufSize;
2182 succ = MakeSelfRelativeSD(&descriptor, lpSecurityDescriptor, &size);
2183 *pcbBytesNeeded = size;
2184 return succ;
2185 }
2186
2187 /******************************************************************************
2188 * SetServiceObjectSecurity [ADVAPI32.@]
2189 */
2190 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2191 SECURITY_INFORMATION dwSecurityInformation,
2192 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2193 {
2194 FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2195 return TRUE;
2196 }
2197
2198 /******************************************************************************
2199 * SetServiceBits [ADVAPI32.@]
2200 */
2201 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2202 DWORD dwServiceBits,
2203 BOOL bSetBitsOn,
2204 BOOL bUpdateImmediately)
2205 {
2206 FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2207 bSetBitsOn, bUpdateImmediately);
2208 return TRUE;
2209 }
2210
2211 /* thunk for calling the RegisterServiceCtrlHandler handler function */
2212 static DWORD WINAPI ctrl_handler_thunk( DWORD control, DWORD type, void *data, void *context )
2213 {
2214 LPHANDLER_FUNCTION func = context;
2215
2216 func( control );
2217 return ERROR_SUCCESS;
2218 }
2219
2220 /******************************************************************************
2221 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
2222 */
2223 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerA( LPCSTR name, LPHANDLER_FUNCTION handler )
2224 {
2225 return RegisterServiceCtrlHandlerExA( name, ctrl_handler_thunk, handler );
2226 }
2227
2228 /******************************************************************************
2229 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
2230 */
2231 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR name, LPHANDLER_FUNCTION handler )
2232 {
2233 return RegisterServiceCtrlHandlerExW( name, ctrl_handler_thunk, handler );
2234 }
2235
2236 /******************************************************************************
2237 * RegisterServiceCtrlHandlerExA [ADVAPI32.@]
2238 */
2239 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR name, LPHANDLER_FUNCTION_EX handler, LPVOID context )
2240 {
2241 LPWSTR nameW;
2242 SERVICE_STATUS_HANDLE ret;
2243
2244 nameW = SERV_dup(name);
2245 ret = RegisterServiceCtrlHandlerExW( nameW, handler, context );
2246 HeapFree( GetProcessHeap(), 0, nameW );
2247 return ret;
2248 }
2249
2250 /******************************************************************************
2251 * RegisterServiceCtrlHandlerExW [ADVAPI32.@]
2252 */
2253 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2254 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2255 {
2256 service_data *service;
2257 SC_HANDLE hService = 0;
2258 BOOL found = FALSE;
2259
2260 TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2261
2262 EnterCriticalSection( &service_cs );
2263 if ((service = find_service_by_name( lpServiceName )))
2264 {
2265 service->handler = lpHandlerProc;
2266 service->context = lpContext;
2267 hService = service->handle;
2268 found = TRUE;
2269 }
2270 LeaveCriticalSection( &service_cs );
2271
2272 if (!found) SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
2273
2274 return (SERVICE_STATUS_HANDLE)hService;
2275 }
2276
2277 /******************************************************************************
2278 * EnumDependentServicesA [ADVAPI32.@]
2279 */
2280 BOOL WINAPI EnumDependentServicesA( SC_HANDLE hService, DWORD dwServiceState,
2281 LPENUM_SERVICE_STATUSA lpServices, DWORD cbBufSize,
2282 LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
2283 {
2284 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
2285 lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
2286
2287 *lpServicesReturned = 0;
2288 return TRUE;
2289 }
2290
2291 /******************************************************************************
2292 * EnumDependentServicesW [ADVAPI32.@]
2293 */
2294 BOOL WINAPI EnumDependentServicesW( SC_HANDLE hService, DWORD dwServiceState,
2295 LPENUM_SERVICE_STATUSW lpServices, DWORD cbBufSize,
2296 LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
2297 {
2298 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
2299 lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
2300
2301 *lpServicesReturned = 0;
2302 return TRUE;
2303 }
2304
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.