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