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