advapi32: Simplify RegisterServiceCtrlHandlerExW.
[wine.git] / dlls / advapi32 / service.c
blobccca721a49f271770e8ed97efa8602a56cf5116c
1 /*
2 * Win32 advapi functions
4 * Copyright 1995 Sven Verdoolaege
5 * Copyright 2005 Mike McCormack
6 * Copyright 2007 Rolf Kalbermatter
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include "config.h"
24 #include "wine/port.h"
26 #include <stdarg.h>
27 #include <string.h>
28 #include <time.h>
29 #include <assert.h>
31 #define NONAMELESSUNION
33 #include "ntstatus.h"
34 #define WIN32_NO_STATUS
35 #include "windef.h"
36 #include "winbase.h"
37 #include "winsvc.h"
38 #include "winerror.h"
39 #include "winreg.h"
40 #include "wine/unicode.h"
41 #include "wine/debug.h"
42 #include "winternl.h"
43 #include "lmcons.h"
44 #include "lmserver.h"
46 #include "svcctl.h"
48 #include "advapi32_misc.h"
50 #include "wine/exception.h"
52 WINE_DEFAULT_DEBUG_CHANNEL(service);
54 void __RPC_FAR * __RPC_USER MIDL_user_allocate(SIZE_T len)
56 return heap_alloc(len);
59 void __RPC_USER MIDL_user_free(void __RPC_FAR * ptr)
61 heap_free(ptr);
64 typedef struct service_data_t
66 LPHANDLER_FUNCTION_EX handler;
67 LPVOID context;
68 HANDLE thread;
69 SC_HANDLE handle;
70 SC_HANDLE full_access_handle;
71 BOOL unicode : 1;
72 union {
73 LPSERVICE_MAIN_FUNCTIONA a;
74 LPSERVICE_MAIN_FUNCTIONW w;
75 } proc;
76 LPWSTR args;
77 WCHAR name[1];
78 } service_data;
80 typedef struct dispatcher_data_t
82 SC_HANDLE manager;
83 HANDLE pipe;
84 } dispatcher_data;
86 static CRITICAL_SECTION service_cs;
87 static CRITICAL_SECTION_DEBUG service_cs_debug =
89 0, 0, &service_cs,
90 { &service_cs_debug.ProcessLocksList,
91 &service_cs_debug.ProcessLocksList },
92 0, 0, { (DWORD_PTR)(__FILE__ ": service_cs") }
94 static CRITICAL_SECTION service_cs = { &service_cs_debug, -1, 0, 0, 0, 0 };
96 static service_data **services;
97 static unsigned int nb_services;
98 static HANDLE service_event;
99 static HANDLE stop_event;
101 extern HANDLE CDECL __wine_make_process_system(void);
103 /******************************************************************************
104 * String management functions (same behaviour as strdup)
105 * NOTE: the caller of those functions is responsible for calling HeapFree
106 * in order to release the memory allocated by those functions.
108 LPWSTR SERV_dup( LPCSTR str )
110 UINT len;
111 LPWSTR wstr;
113 if( !str )
114 return NULL;
115 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
116 wstr = heap_alloc( len*sizeof (WCHAR) );
117 MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
118 return wstr;
121 static inline LPWSTR SERV_dupmulti(LPCSTR str)
123 UINT len = 0, n = 0;
124 LPWSTR wstr;
126 if( !str )
127 return NULL;
128 do {
129 len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
130 n += (strlen( &str[n] ) + 1);
131 } while (str[n]);
132 len++;
133 n++;
135 wstr = heap_alloc( len*sizeof (WCHAR) );
136 MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
137 return wstr;
140 static inline DWORD multisz_cb(LPCWSTR wmultisz)
142 const WCHAR *wptr = wmultisz;
144 if (wmultisz == NULL)
145 return 0;
147 while (*wptr)
148 wptr += lstrlenW(wptr)+1;
149 return (wptr - wmultisz + 1)*sizeof(WCHAR);
152 /******************************************************************************
153 * RPC connection with services.exe
155 static handle_t rpc_wstr_bind(RPC_WSTR str)
157 WCHAR transport[] = SVCCTL_TRANSPORT;
158 WCHAR endpoint[] = SVCCTL_ENDPOINT;
159 RPC_WSTR binding_str;
160 RPC_STATUS status;
161 handle_t rpc_handle;
163 status = RpcStringBindingComposeW(NULL, transport, str, endpoint, NULL, &binding_str);
164 if (status != RPC_S_OK)
166 ERR("RpcStringBindingComposeW failed (%d)\n", (DWORD)status);
167 return NULL;
170 status = RpcBindingFromStringBindingW(binding_str, &rpc_handle);
171 RpcStringFreeW(&binding_str);
173 if (status != RPC_S_OK)
175 ERR("Couldn't connect to services.exe: error code %u\n", (DWORD)status);
176 return NULL;
179 return rpc_handle;
182 static handle_t rpc_cstr_bind(RPC_CSTR str)
184 RPC_CSTR transport = (RPC_CSTR)SVCCTL_TRANSPORTA;
185 RPC_CSTR endpoint = (RPC_CSTR)SVCCTL_ENDPOINTA;
186 RPC_CSTR binding_str;
187 RPC_STATUS status;
188 handle_t rpc_handle;
190 status = RpcStringBindingComposeA(NULL, transport, str, endpoint, NULL, &binding_str);
191 if (status != RPC_S_OK)
193 ERR("RpcStringBindingComposeW failed (%d)\n", (DWORD)status);
194 return NULL;
197 status = RpcBindingFromStringBindingA(binding_str, &rpc_handle);
198 RpcStringFreeA(&binding_str);
200 if (status != RPC_S_OK)
202 ERR("Couldn't connect to services.exe: error code %u\n", (DWORD)status);
203 return NULL;
206 return rpc_handle;
209 DECLSPEC_HIDDEN handle_t __RPC_USER MACHINE_HANDLEA_bind(MACHINE_HANDLEA MachineName)
211 return rpc_cstr_bind((RPC_CSTR)MachineName);
214 DECLSPEC_HIDDEN void __RPC_USER MACHINE_HANDLEA_unbind(MACHINE_HANDLEA MachineName, handle_t h)
216 RpcBindingFree(&h);
219 DECLSPEC_HIDDEN handle_t __RPC_USER MACHINE_HANDLEW_bind(MACHINE_HANDLEW MachineName)
221 return rpc_wstr_bind((RPC_WSTR)MachineName);
224 DECLSPEC_HIDDEN void __RPC_USER MACHINE_HANDLEW_unbind(MACHINE_HANDLEW MachineName, handle_t h)
226 RpcBindingFree(&h);
229 DECLSPEC_HIDDEN handle_t __RPC_USER SVCCTL_HANDLEW_bind(SVCCTL_HANDLEW MachineName)
231 return rpc_wstr_bind((RPC_WSTR)MachineName);
234 DECLSPEC_HIDDEN void __RPC_USER SVCCTL_HANDLEW_unbind(SVCCTL_HANDLEW MachineName, handle_t h)
236 RpcBindingFree(&h);
239 static LONG WINAPI rpc_filter(EXCEPTION_POINTERS *eptr)
241 return I_RpcExceptionFilter(eptr->ExceptionRecord->ExceptionCode);
244 static DWORD map_exception_code(DWORD exception_code)
246 switch (exception_code)
248 case RPC_X_NULL_REF_POINTER:
249 return ERROR_INVALID_ADDRESS;
250 case RPC_X_ENUM_VALUE_OUT_OF_RANGE:
251 case RPC_X_BYTE_COUNT_TOO_SMALL:
252 return ERROR_INVALID_PARAMETER;
253 case RPC_S_INVALID_BINDING:
254 case RPC_X_SS_IN_NULL_CONTEXT:
255 return ERROR_INVALID_HANDLE;
256 default:
257 return exception_code;
261 /******************************************************************************
262 * Service IPC functions
264 static LPWSTR service_get_pipe_name(void)
266 static const WCHAR format[] = { '\\','\\','.','\\','p','i','p','e','\\',
267 'n','e','t','\\','N','t','C','o','n','t','r','o','l','P','i','p','e','%','u',0};
268 static const WCHAR service_current_key_str[] = { 'S','Y','S','T','E','M','\\',
269 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
270 'C','o','n','t','r','o','l','\\',
271 'S','e','r','v','i','c','e','C','u','r','r','e','n','t',0};
272 LPWSTR name;
273 DWORD len;
274 HKEY service_current_key;
275 DWORD service_current;
276 LONG ret;
277 DWORD type;
279 ret = RegOpenKeyExW(HKEY_LOCAL_MACHINE, service_current_key_str, 0,
280 KEY_QUERY_VALUE, &service_current_key);
281 if (ret != ERROR_SUCCESS)
282 return NULL;
283 len = sizeof(service_current);
284 ret = RegQueryValueExW(service_current_key, NULL, NULL, &type,
285 (BYTE *)&service_current, &len);
286 RegCloseKey(service_current_key);
287 if (ret != ERROR_SUCCESS || type != REG_DWORD)
288 return NULL;
289 len = sizeof(format)/sizeof(WCHAR) + 10 /* strlenW("4294967295") */;
290 name = heap_alloc(len * sizeof(WCHAR));
291 if (!name)
292 return NULL;
293 snprintfW(name, len, format, service_current);
294 return name;
297 static HANDLE service_open_pipe(void)
299 LPWSTR szPipe = service_get_pipe_name();
300 HANDLE handle = INVALID_HANDLE_VALUE;
302 do {
303 handle = CreateFileW(szPipe, GENERIC_READ|GENERIC_WRITE,
304 0, NULL, OPEN_ALWAYS, 0, NULL);
305 if (handle != INVALID_HANDLE_VALUE)
306 break;
307 if (GetLastError() != ERROR_PIPE_BUSY)
308 break;
309 } while (WaitNamedPipeW(szPipe, NMPWAIT_USE_DEFAULT_WAIT));
310 heap_free(szPipe);
312 return handle;
315 static service_data *find_service_by_name( const WCHAR *name )
317 unsigned int i;
319 if (nb_services == 1) /* only one service (FIXME: should depend on OWN_PROCESS etc.) */
320 return services[0];
321 for (i = 0; i < nb_services; i++)
322 if (!strcmpiW( name, services[i]->name )) return services[i];
323 return NULL;
326 /******************************************************************************
327 * service_thread
329 * Call into the main service routine provided by StartServiceCtrlDispatcher.
331 static DWORD WINAPI service_thread(LPVOID arg)
333 service_data *info = arg;
334 LPWSTR str = info->args;
335 DWORD argc = 0, len = 0;
337 TRACE("%p\n", arg);
339 while (str[len])
341 len += strlenW(&str[len]) + 1;
342 argc++;
344 len++;
346 if (info->unicode)
348 LPWSTR *argv, p;
350 argv = heap_alloc((argc+1)*sizeof(LPWSTR));
351 for (argc=0, p=str; *p; p += strlenW(p) + 1)
352 argv[argc++] = p;
353 argv[argc] = NULL;
355 info->proc.w(argc, argv);
356 heap_free(argv);
358 else
360 LPSTR strA, *argv, p;
361 DWORD lenA;
363 lenA = WideCharToMultiByte(CP_ACP,0, str, len, NULL, 0, NULL, NULL);
364 strA = heap_alloc(lenA);
365 WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL);
367 argv = heap_alloc((argc+1)*sizeof(LPSTR));
368 for (argc=0, p=strA; *p; p += strlen(p) + 1)
369 argv[argc++] = p;
370 argv[argc] = NULL;
372 info->proc.a(argc, argv);
373 heap_free(argv);
374 heap_free(strA);
376 return 0;
379 /******************************************************************************
380 * service_handle_start
382 static DWORD service_handle_start(service_data *service, const WCHAR *data, DWORD count)
384 TRACE("%s argsize %u\n", debugstr_w(service->name), count);
386 if (service->thread)
388 WARN("service is not stopped\n");
389 return ERROR_SERVICE_ALREADY_RUNNING;
392 heap_free(service->args);
393 service->args = heap_alloc(count * sizeof(WCHAR));
394 memcpy( service->args, data, count * sizeof(WCHAR) );
395 service->thread = CreateThread( NULL, 0, service_thread,
396 service, 0, NULL );
397 SetEvent( service_event ); /* notify the main loop */
398 return 0;
401 /******************************************************************************
402 * service_handle_control
404 static DWORD service_handle_control(const service_data *service, DWORD control, void *data)
406 DWORD ret = ERROR_INVALID_SERVICE_CONTROL;
408 TRACE("%s control %u data %p\n", debugstr_w(service->name), control, data);
410 if (service->handler)
411 ret = service->handler(control, 0, data, service->context);
412 return ret;
415 /******************************************************************************
416 * service_control_dispatcher
418 static DWORD WINAPI service_control_dispatcher(LPVOID arg)
420 dispatcher_data *disp = arg;
422 /* dispatcher loop */
423 while (1)
425 service_data *service;
426 service_start_info info;
427 BYTE *data = NULL;
428 WCHAR *name;
429 BOOL r;
430 DWORD data_size = 0, count, result;
432 r = ReadFile( disp->pipe, &info, FIELD_OFFSET(service_start_info,data), &count, NULL );
433 if (!r)
435 if (GetLastError() != ERROR_BROKEN_PIPE)
436 ERR( "pipe read failed error %u\n", GetLastError() );
437 break;
439 if (count != FIELD_OFFSET(service_start_info,data))
441 ERR( "partial pipe read %u\n", count );
442 break;
444 if (count < info.total_size)
446 data_size = info.total_size - FIELD_OFFSET(service_start_info,data);
447 data = heap_alloc( data_size );
448 r = ReadFile( disp->pipe, data, data_size, &count, NULL );
449 if (!r)
451 if (GetLastError() != ERROR_BROKEN_PIPE)
452 ERR( "pipe read failed error %u\n", GetLastError() );
453 heap_free( data );
454 break;
456 if (count != data_size)
458 ERR( "partial pipe read %u/%u\n", count, data_size );
459 heap_free( data );
460 break;
464 /* validate service name */
465 name = (WCHAR *)data;
466 if (!info.name_size || data_size < info.name_size * sizeof(WCHAR) || name[info.name_size - 1])
468 ERR( "got request without valid service name\n" );
469 result = ERROR_INVALID_PARAMETER;
470 goto done;
473 /* find the service */
474 if (!(service = find_service_by_name( name )))
476 FIXME( "got request %u for unknown service %s\n", info.cmd, debugstr_w(name));
477 result = ERROR_INVALID_PARAMETER;
478 goto done;
481 TRACE( "got request %u for service %s\n", info.cmd, debugstr_w(name) );
483 /* handle the request */
484 switch (info.cmd)
486 case WINESERV_STARTINFO:
487 if (!service->handle)
489 if (!(service->handle = OpenServiceW( disp->manager, name, SERVICE_SET_STATUS )) ||
490 !(service->full_access_handle = OpenServiceW( disp->manager, name,
491 GENERIC_READ|GENERIC_WRITE )))
492 FIXME( "failed to open service %s\n", debugstr_w(name) );
494 result = service_handle_start(service, (WCHAR *)data, data_size / sizeof(WCHAR));
495 break;
496 case WINESERV_SENDCONTROL:
497 result = service_handle_control(service, info.control, (data_size > info.name_size * sizeof(WCHAR)) ?
498 &data[info.name_size * sizeof(WCHAR)] : NULL);
499 break;
500 default:
501 ERR("received invalid command %u\n", info.cmd);
502 result = ERROR_INVALID_PARAMETER;
503 break;
506 done:
507 WriteFile( disp->pipe, &result, sizeof(result), &count, NULL );
508 heap_free( data );
511 CloseHandle( disp->pipe );
512 CloseServiceHandle( disp->manager );
513 heap_free( disp );
514 return 1;
517 /******************************************************************************
518 * service_run_main_thread
520 static BOOL service_run_main_thread(void)
522 DWORD i, n, ret;
523 HANDLE wait_handles[MAXIMUM_WAIT_OBJECTS];
524 UINT wait_services[MAXIMUM_WAIT_OBJECTS];
525 dispatcher_data *disp = heap_alloc( sizeof(*disp) );
527 disp->manager = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
528 if (!disp->manager)
530 ERR("failed to open service manager error %u\n", GetLastError());
531 heap_free( disp );
532 return FALSE;
535 disp->pipe = service_open_pipe();
536 if (disp->pipe == INVALID_HANDLE_VALUE)
538 WARN("failed to create control pipe error %u\n", GetLastError());
539 CloseServiceHandle( disp->manager );
540 heap_free( disp );
541 SetLastError( ERROR_FAILED_SERVICE_CONTROLLER_CONNECT );
542 return FALSE;
545 service_event = CreateEventW( NULL, FALSE, FALSE, NULL );
546 stop_event = CreateEventW( NULL, FALSE, FALSE, NULL );
548 /* FIXME: service_control_dispatcher should be merged into the main thread */
549 wait_handles[0] = __wine_make_process_system();
550 wait_handles[1] = CreateThread( NULL, 0, service_control_dispatcher, disp, 0, NULL );
551 wait_handles[2] = service_event;
552 wait_handles[3] = stop_event;
554 TRACE("Starting %d services running as process %d\n",
555 nb_services, GetCurrentProcessId());
557 /* wait for all the threads to pack up and exit */
558 for (;;)
560 EnterCriticalSection( &service_cs );
561 for (i = 0, n = 4; i < nb_services && n < MAXIMUM_WAIT_OBJECTS; i++)
563 if (!services[i]->thread) continue;
564 wait_services[n] = i;
565 wait_handles[n++] = services[i]->thread;
567 LeaveCriticalSection( &service_cs );
569 ret = WaitForMultipleObjects( n, wait_handles, FALSE, INFINITE );
570 if (!ret) /* system process event */
572 SERVICE_STATUS st;
573 SERVICE_PRESHUTDOWN_INFO spi;
574 DWORD timeout = 5000;
575 BOOL res;
577 EnterCriticalSection( &service_cs );
578 n = 0;
579 for (i = 0; i < nb_services && n < MAXIMUM_WAIT_OBJECTS; i++)
581 if (!services[i]->thread) continue;
583 res = QueryServiceStatus(services[i]->full_access_handle, &st);
584 ret = ERROR_SUCCESS;
585 if (res && (st.dwControlsAccepted & SERVICE_ACCEPT_PRESHUTDOWN))
587 res = QueryServiceConfig2W( services[i]->full_access_handle, SERVICE_CONFIG_PRESHUTDOWN_INFO,
588 (LPBYTE)&spi, sizeof(spi), &i );
589 if (res)
591 FIXME("service should be able to delay shutdown\n");
592 timeout += spi.dwPreshutdownTimeout;
593 ret = service_handle_control( services[i], SERVICE_CONTROL_PRESHUTDOWN, NULL );
594 wait_handles[n++] = services[i]->thread;
597 else if (res && (st.dwControlsAccepted & SERVICE_ACCEPT_SHUTDOWN))
599 ret = service_handle_control( services[i], SERVICE_CONTROL_SHUTDOWN, NULL );
600 wait_handles[n++] = services[i]->thread;
603 LeaveCriticalSection( &service_cs );
605 TRACE("last user process exited, shutting down (timeout: %d)\n", timeout);
606 WaitForMultipleObjects( n, wait_handles, TRUE, timeout );
607 ExitProcess(0);
609 else if (ret == 1)
611 TRACE( "control dispatcher exited, shutting down\n" );
612 /* FIXME: we should maybe send a shutdown control to running services */
613 ExitProcess(0);
615 else if (ret == 2)
617 continue; /* rebuild the list */
619 else if (ret == 3)
621 return TRUE;
623 else if (ret < n)
625 services[wait_services[ret]]->thread = 0;
626 CloseHandle( wait_handles[ret] );
628 else return FALSE;
632 /******************************************************************************
633 * StartServiceCtrlDispatcherA [ADVAPI32.@]
635 * See StartServiceCtrlDispatcherW.
637 BOOL WINAPI StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *servent )
639 service_data *info;
640 unsigned int i;
642 TRACE("%p\n", servent);
644 if (nb_services)
646 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
647 return FALSE;
649 while (servent[nb_services].lpServiceName) nb_services++;
650 if (!nb_services)
652 SetLastError( ERROR_INVALID_PARAMETER );
653 return FALSE;
656 services = heap_alloc( nb_services * sizeof(*services) );
658 for (i = 0; i < nb_services; i++)
660 DWORD len = MultiByteToWideChar(CP_ACP, 0, servent[i].lpServiceName, -1, NULL, 0);
661 DWORD sz = FIELD_OFFSET( service_data, name[len] );
662 info = heap_alloc_zero( sz );
663 MultiByteToWideChar(CP_ACP, 0, servent[i].lpServiceName, -1, info->name, len);
664 info->proc.a = servent[i].lpServiceProc;
665 info->unicode = FALSE;
666 services[i] = info;
669 return service_run_main_thread();
672 /******************************************************************************
673 * StartServiceCtrlDispatcherW [ADVAPI32.@]
675 * Connects a process containing one or more services to the service control
676 * manager.
678 * PARAMS
679 * servent [I] A list of the service names and service procedures
681 * RETURNS
682 * Success: TRUE.
683 * Failure: FALSE.
685 BOOL WINAPI StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW *servent )
687 service_data *info;
688 unsigned int i;
690 TRACE("%p\n", servent);
692 if (nb_services)
694 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
695 return FALSE;
697 while (servent[nb_services].lpServiceName) nb_services++;
698 if (!nb_services)
700 SetLastError( ERROR_INVALID_PARAMETER );
701 return FALSE;
704 services = heap_alloc( nb_services * sizeof(*services) );
706 for (i = 0; i < nb_services; i++)
708 DWORD len = strlenW(servent[i].lpServiceName) + 1;
709 DWORD sz = FIELD_OFFSET( service_data, name[len] );
710 info = heap_alloc_zero( sz );
711 strcpyW(info->name, servent[i].lpServiceName);
712 info->proc.w = servent[i].lpServiceProc;
713 info->unicode = TRUE;
714 services[i] = info;
717 return service_run_main_thread();
720 /******************************************************************************
721 * LockServiceDatabase [ADVAPI32.@]
723 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
725 SC_RPC_LOCK hLock = NULL;
726 DWORD err;
728 TRACE("%p\n",hSCManager);
730 __TRY
732 err = svcctl_LockServiceDatabase(hSCManager, &hLock);
734 __EXCEPT(rpc_filter)
736 err = map_exception_code(GetExceptionCode());
738 __ENDTRY
739 if (err != ERROR_SUCCESS)
741 SetLastError(err);
742 return NULL;
744 return hLock;
747 /******************************************************************************
748 * UnlockServiceDatabase [ADVAPI32.@]
750 BOOL WINAPI UnlockServiceDatabase (SC_LOCK ScLock)
752 DWORD err;
753 SC_RPC_LOCK hRpcLock = ScLock;
755 TRACE("%p\n",ScLock);
757 __TRY
759 err = svcctl_UnlockServiceDatabase(&hRpcLock);
761 __EXCEPT(rpc_filter)
763 err = map_exception_code(GetExceptionCode());
765 __ENDTRY
766 if (err != ERROR_SUCCESS)
768 SetLastError(err);
769 return FALSE;
771 return TRUE;
774 /******************************************************************************
775 * SetServiceStatus [ADVAPI32.@]
777 * PARAMS
778 * hService []
779 * lpStatus []
781 BOOL WINAPI
782 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
784 DWORD err;
786 TRACE("%p %x %x %x %x %x %x %x\n", hService,
787 lpStatus->dwServiceType, lpStatus->dwCurrentState,
788 lpStatus->dwControlsAccepted, lpStatus->dwWin32ExitCode,
789 lpStatus->dwServiceSpecificExitCode, lpStatus->dwCheckPoint,
790 lpStatus->dwWaitHint);
792 __TRY
794 err = svcctl_SetServiceStatus( hService, lpStatus );
796 __EXCEPT(rpc_filter)
798 err = map_exception_code(GetExceptionCode());
800 __ENDTRY
801 if (err != ERROR_SUCCESS)
803 SetLastError(err);
804 return FALSE;
807 if (lpStatus->dwCurrentState == SERVICE_STOPPED) {
808 SetEvent(stop_event);
809 CloseServiceHandle((SC_HANDLE)hService);
812 return TRUE;
816 /******************************************************************************
817 * OpenSCManagerA [ADVAPI32.@]
819 * Establish a connection to the service control manager and open its database.
821 * PARAMS
822 * lpMachineName [I] Pointer to machine name string
823 * lpDatabaseName [I] Pointer to database name string
824 * dwDesiredAccess [I] Type of access
826 * RETURNS
827 * Success: A Handle to the service control manager database
828 * Failure: NULL
830 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
831 DWORD dwDesiredAccess )
833 LPWSTR machineW, databaseW;
834 SC_HANDLE ret;
836 machineW = SERV_dup(lpMachineName);
837 databaseW = SERV_dup(lpDatabaseName);
838 ret = OpenSCManagerW(machineW, databaseW, dwDesiredAccess);
839 heap_free(databaseW);
840 heap_free(machineW);
841 return ret;
844 /******************************************************************************
845 * OpenSCManagerW [ADVAPI32.@]
847 * See OpenSCManagerA.
849 DWORD SERV_OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
850 DWORD dwDesiredAccess, SC_HANDLE *handle )
852 DWORD r;
854 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName),
855 debugstr_w(lpDatabaseName), dwDesiredAccess);
857 __TRY
859 r = svcctl_OpenSCManagerW(lpMachineName, lpDatabaseName, dwDesiredAccess, (SC_RPC_HANDLE *)handle);
861 __EXCEPT(rpc_filter)
863 r = map_exception_code(GetExceptionCode());
865 __ENDTRY
867 if (r!=ERROR_SUCCESS)
868 *handle = 0;
870 TRACE("returning %p\n", *handle);
871 return r;
874 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
875 DWORD dwDesiredAccess )
877 SC_HANDLE handle = 0;
878 DWORD r;
880 r = SERV_OpenSCManagerW(lpMachineName, lpDatabaseName, dwDesiredAccess, &handle);
881 if (r!=ERROR_SUCCESS)
882 SetLastError(r);
883 return handle;
886 /******************************************************************************
887 * ControlService [ADVAPI32.@]
889 * Send a control code to a service.
891 * PARAMS
892 * hService [I] Handle of the service control manager database
893 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
894 * lpServiceStatus [O] Destination for the status of the service, if available
896 * RETURNS
897 * Success: TRUE.
898 * Failure: FALSE.
900 * BUGS
901 * Unlike M$' implementation, control requests are not serialized and may be
902 * processed asynchronously.
904 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
905 LPSERVICE_STATUS lpServiceStatus )
907 DWORD err;
909 TRACE("%p %d %p\n", hService, dwControl, lpServiceStatus);
911 __TRY
913 err = svcctl_ControlService(hService, dwControl, lpServiceStatus);
915 __EXCEPT(rpc_filter)
917 err = map_exception_code(GetExceptionCode());
919 __ENDTRY
920 if (err != ERROR_SUCCESS)
922 SetLastError(err);
923 return FALSE;
926 return TRUE;
929 /******************************************************************************
930 * CloseServiceHandle [ADVAPI32.@]
932 * Close a handle to a service or the service control manager database.
934 * PARAMS
935 * hSCObject [I] Handle to service or service control manager database
937 * RETURNS
938 * Success: TRUE
939 * Failure: FALSE
941 BOOL WINAPI
942 CloseServiceHandle( SC_HANDLE hSCObject )
944 DWORD err;
946 TRACE("%p\n", hSCObject);
948 __TRY
950 err = svcctl_CloseServiceHandle((SC_RPC_HANDLE *)&hSCObject);
952 __EXCEPT(rpc_filter)
954 err = map_exception_code(GetExceptionCode());
956 __ENDTRY
958 if (err != ERROR_SUCCESS)
960 SetLastError(err);
961 return FALSE;
963 return TRUE;
967 /******************************************************************************
968 * OpenServiceA [ADVAPI32.@]
970 * Open a handle to a service.
972 * PARAMS
973 * hSCManager [I] Handle of the service control manager database
974 * lpServiceName [I] Name of the service to open
975 * dwDesiredAccess [I] Access required to the service
977 * RETURNS
978 * Success: Handle to the service
979 * Failure: NULL
981 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
982 DWORD dwDesiredAccess )
984 LPWSTR lpServiceNameW;
985 SC_HANDLE ret;
987 TRACE("%p %s 0x%08x\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
989 lpServiceNameW = SERV_dup(lpServiceName);
990 ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
991 heap_free(lpServiceNameW);
992 return ret;
996 /******************************************************************************
997 * OpenServiceW [ADVAPI32.@]
999 * See OpenServiceA.
1001 DWORD SERV_OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1002 DWORD dwDesiredAccess, SC_HANDLE *handle )
1004 DWORD err;
1006 TRACE("%p %s 0x%08x\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
1008 if (!hSCManager)
1009 return ERROR_INVALID_HANDLE;
1011 __TRY
1013 err = svcctl_OpenServiceW(hSCManager, lpServiceName, dwDesiredAccess, (SC_RPC_HANDLE *)handle);
1015 __EXCEPT(rpc_filter)
1017 err = map_exception_code(GetExceptionCode());
1019 __ENDTRY
1021 if (err != ERROR_SUCCESS)
1022 *handle = 0;
1024 TRACE("returning %p\n", *handle);
1025 return err;
1028 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1029 DWORD dwDesiredAccess)
1031 SC_HANDLE handle = 0;
1032 DWORD err;
1034 err = SERV_OpenServiceW(hSCManager, lpServiceName, dwDesiredAccess, &handle);
1035 if (err != ERROR_SUCCESS)
1036 SetLastError(err);
1037 return handle;
1040 /******************************************************************************
1041 * CreateServiceW [ADVAPI32.@]
1043 SC_HANDLE WINAPI
1044 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1045 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
1046 DWORD dwServiceType, DWORD dwStartType,
1047 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1048 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1049 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
1050 LPCWSTR lpPassword )
1052 SC_HANDLE handle = 0;
1053 DWORD err;
1054 SIZE_T passwdlen;
1056 TRACE("%p %s %s\n", hSCManager,
1057 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
1059 if (!hSCManager)
1061 SetLastError( ERROR_INVALID_HANDLE );
1062 return 0;
1065 if (lpPassword)
1066 passwdlen = (strlenW(lpPassword) + 1) * sizeof(WCHAR);
1067 else
1068 passwdlen = 0;
1070 __TRY
1072 BOOL is_wow64;
1074 IsWow64Process(GetCurrentProcess(), &is_wow64);
1076 if (is_wow64)
1077 err = svcctl_CreateServiceWOW64W(hSCManager, lpServiceName,
1078 lpDisplayName, dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1079 lpBinaryPathName, lpLoadOrderGroup, lpdwTagId, (const BYTE*)lpDependencies,
1080 multisz_cb(lpDependencies), lpServiceStartName, (const BYTE*)lpPassword, passwdlen,
1081 (SC_RPC_HANDLE *)&handle);
1082 else
1083 err = svcctl_CreateServiceW(hSCManager, lpServiceName,
1084 lpDisplayName, dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1085 lpBinaryPathName, lpLoadOrderGroup, lpdwTagId, (const BYTE*)lpDependencies,
1086 multisz_cb(lpDependencies), lpServiceStartName, (const BYTE*)lpPassword, passwdlen,
1087 (SC_RPC_HANDLE *)&handle);
1089 __EXCEPT(rpc_filter)
1091 err = map_exception_code(GetExceptionCode());
1093 __ENDTRY
1095 if (err != ERROR_SUCCESS)
1097 SetLastError(err);
1098 handle = 0;
1100 return handle;
1104 /******************************************************************************
1105 * CreateServiceA [ADVAPI32.@]
1107 SC_HANDLE WINAPI
1108 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1109 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1110 DWORD dwServiceType, DWORD dwStartType,
1111 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1112 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1113 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1114 LPCSTR lpPassword )
1116 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1117 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1118 SC_HANDLE r;
1120 TRACE("%p %s %s\n", hSCManager,
1121 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1123 lpServiceNameW = SERV_dup( lpServiceName );
1124 lpDisplayNameW = SERV_dup( lpDisplayName );
1125 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1126 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1127 lpDependenciesW = SERV_dupmulti( lpDependencies );
1128 lpServiceStartNameW = SERV_dup( lpServiceStartName );
1129 lpPasswordW = SERV_dup( lpPassword );
1131 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1132 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1133 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1134 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1136 heap_free( lpServiceNameW );
1137 heap_free( lpDisplayNameW );
1138 heap_free( lpBinaryPathNameW );
1139 heap_free( lpLoadOrderGroupW );
1140 heap_free( lpDependenciesW );
1141 heap_free( lpServiceStartNameW );
1142 heap_free( lpPasswordW );
1144 return r;
1148 /******************************************************************************
1149 * DeleteService [ADVAPI32.@]
1151 * Delete a service from the service control manager database.
1153 * PARAMS
1154 * hService [I] Handle of the service to delete
1156 * RETURNS
1157 * Success: TRUE
1158 * Failure: FALSE
1160 BOOL WINAPI DeleteService( SC_HANDLE hService )
1162 DWORD err;
1164 TRACE("%p\n", hService);
1166 __TRY
1168 err = svcctl_DeleteService(hService);
1170 __EXCEPT(rpc_filter)
1172 err = map_exception_code(GetExceptionCode());
1174 __ENDTRY
1175 if (err != 0)
1177 SetLastError(err);
1178 return FALSE;
1181 return TRUE;
1185 /******************************************************************************
1186 * StartServiceA [ADVAPI32.@]
1188 * Start a service
1190 * PARAMS
1191 * hService [I] Handle of service
1192 * dwNumServiceArgs [I] Number of arguments
1193 * lpServiceArgVectors [I] Address of array of argument strings
1195 * NOTES
1196 * - NT implements this function using an obscure RPC call.
1197 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1198 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1199 * - This will only work for shared address space. How should the service
1200 * args be transferred when address spaces are separated?
1201 * - Can only start one service at a time.
1202 * - Has no concept of privilege.
1204 * RETURNS
1205 * Success: TRUE.
1206 * Failure: FALSE
1208 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1209 LPCSTR *lpServiceArgVectors )
1211 LPWSTR *lpwstr=NULL;
1212 unsigned int i;
1213 BOOL r;
1215 TRACE("(%p,%d,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1217 if (dwNumServiceArgs)
1218 lpwstr = heap_alloc( dwNumServiceArgs*sizeof(LPWSTR) );
1220 for(i=0; i<dwNumServiceArgs; i++)
1221 lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1223 r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1225 if (dwNumServiceArgs)
1227 for(i=0; i<dwNumServiceArgs; i++)
1228 heap_free(lpwstr[i]);
1229 heap_free(lpwstr);
1232 return r;
1236 /******************************************************************************
1237 * StartServiceW [ADVAPI32.@]
1239 * See StartServiceA.
1241 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1242 LPCWSTR *lpServiceArgVectors)
1244 DWORD err;
1246 TRACE("%p %d %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1248 __TRY
1250 err = svcctl_StartServiceW(hService, dwNumServiceArgs, lpServiceArgVectors);
1252 __EXCEPT(rpc_filter)
1254 err = map_exception_code(GetExceptionCode());
1256 __ENDTRY
1257 if (err != ERROR_SUCCESS)
1259 SetLastError(err);
1260 return FALSE;
1263 return TRUE;
1266 /******************************************************************************
1267 * QueryServiceStatus [ADVAPI32.@]
1269 * PARAMS
1270 * hService [I] Handle to service to get information about
1271 * lpservicestatus [O] buffer to receive the status information for the service
1274 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1275 LPSERVICE_STATUS lpservicestatus)
1277 SERVICE_STATUS_PROCESS SvcStatusData;
1278 BOOL ret;
1279 DWORD dummy;
1281 TRACE("%p %p\n", hService, lpservicestatus);
1283 if (!hService)
1285 SetLastError(ERROR_INVALID_HANDLE);
1286 return FALSE;
1288 if (!lpservicestatus)
1290 SetLastError(ERROR_INVALID_ADDRESS);
1291 return FALSE;
1294 ret = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&SvcStatusData,
1295 sizeof(SERVICE_STATUS_PROCESS), &dummy);
1296 if (ret) memcpy(lpservicestatus, &SvcStatusData, sizeof(SERVICE_STATUS)) ;
1297 return ret;
1301 /******************************************************************************
1302 * QueryServiceStatusEx [ADVAPI32.@]
1304 * Get information about a service.
1306 * PARAMS
1307 * hService [I] Handle to service to get information about
1308 * InfoLevel [I] Level of information to get
1309 * lpBuffer [O] Destination for requested information
1310 * cbBufSize [I] Size of lpBuffer in bytes
1311 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1313 * RETURNS
1314 * Success: TRUE
1315 * FAILURE: FALSE
1317 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1318 LPBYTE lpBuffer, DWORD cbBufSize,
1319 LPDWORD pcbBytesNeeded)
1321 DWORD err;
1323 TRACE("%p %d %p %d %p\n", hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1325 if (InfoLevel != SC_STATUS_PROCESS_INFO)
1327 err = ERROR_INVALID_LEVEL;
1329 else if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
1331 *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
1332 err = ERROR_INSUFFICIENT_BUFFER;
1334 else
1336 __TRY
1338 err = svcctl_QueryServiceStatusEx(hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1340 __EXCEPT(rpc_filter)
1342 err = map_exception_code(GetExceptionCode());
1344 __ENDTRY
1346 if (err != ERROR_SUCCESS)
1348 SetLastError(err);
1349 return FALSE;
1351 return TRUE;
1354 /******************************************************************************
1355 * QueryServiceConfigA [ADVAPI32.@]
1357 BOOL WINAPI QueryServiceConfigA( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGA config,
1358 DWORD size, LPDWORD needed )
1360 DWORD n;
1361 LPSTR p, buffer;
1362 BOOL ret;
1363 QUERY_SERVICE_CONFIGW *configW;
1365 TRACE("%p %p %d %p\n", hService, config, size, needed);
1367 if (!(buffer = heap_alloc( 2 * size )))
1369 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1370 return FALSE;
1372 configW = (QUERY_SERVICE_CONFIGW *)buffer;
1373 ret = QueryServiceConfigW( hService, configW, 2 * size, needed );
1374 if (!ret) goto done;
1376 config->dwServiceType = configW->dwServiceType;
1377 config->dwStartType = configW->dwStartType;
1378 config->dwErrorControl = configW->dwErrorControl;
1379 config->lpBinaryPathName = NULL;
1380 config->lpLoadOrderGroup = NULL;
1381 config->dwTagId = configW->dwTagId;
1382 config->lpDependencies = NULL;
1383 config->lpServiceStartName = NULL;
1384 config->lpDisplayName = NULL;
1386 p = (LPSTR)(config + 1);
1387 n = size - sizeof(*config);
1388 ret = FALSE;
1390 #define MAP_STR(str) \
1391 do { \
1392 if (configW->str) \
1394 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1395 if (!sz) goto done; \
1396 config->str = p; \
1397 p += sz; \
1398 n -= sz; \
1400 } while (0)
1402 MAP_STR( lpBinaryPathName );
1403 MAP_STR( lpLoadOrderGroup );
1404 MAP_STR( lpDependencies );
1405 MAP_STR( lpServiceStartName );
1406 MAP_STR( lpDisplayName );
1407 #undef MAP_STR
1409 *needed = p - (LPSTR)config;
1410 ret = TRUE;
1412 done:
1413 heap_free( buffer );
1414 return ret;
1417 static DWORD move_string_to_buffer(BYTE **buf, LPWSTR *string_ptr)
1419 DWORD cb;
1421 if (!*string_ptr)
1423 cb = sizeof(WCHAR);
1424 memset(*buf, 0, cb);
1426 else
1428 cb = (strlenW(*string_ptr) + 1)*sizeof(WCHAR);
1429 memcpy(*buf, *string_ptr, cb);
1430 MIDL_user_free(*string_ptr);
1433 *string_ptr = (LPWSTR)*buf;
1434 *buf += cb;
1436 return cb;
1439 static DWORD size_string(LPCWSTR string)
1441 return (string ? (strlenW(string) + 1)*sizeof(WCHAR) : sizeof(WCHAR));
1444 /******************************************************************************
1445 * QueryServiceConfigW [ADVAPI32.@]
1447 BOOL WINAPI
1448 QueryServiceConfigW( SC_HANDLE hService,
1449 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1450 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1452 QUERY_SERVICE_CONFIGW config;
1453 DWORD total;
1454 DWORD err;
1455 BYTE *bufpos;
1457 TRACE("%p %p %d %p\n", hService, lpServiceConfig,
1458 cbBufSize, pcbBytesNeeded);
1460 memset(&config, 0, sizeof(config));
1462 __TRY
1464 err = svcctl_QueryServiceConfigW(hService, &config, cbBufSize, pcbBytesNeeded);
1466 __EXCEPT(rpc_filter)
1468 err = map_exception_code(GetExceptionCode());
1470 __ENDTRY
1472 if (err != ERROR_SUCCESS)
1474 TRACE("services.exe: error %u\n", err);
1475 SetLastError(err);
1476 return FALSE;
1479 /* calculate the size required first */
1480 total = sizeof (QUERY_SERVICE_CONFIGW);
1481 total += size_string(config.lpBinaryPathName);
1482 total += size_string(config.lpLoadOrderGroup);
1483 total += size_string(config.lpDependencies);
1484 total += size_string(config.lpServiceStartName);
1485 total += size_string(config.lpDisplayName);
1487 *pcbBytesNeeded = total;
1489 /* if there's not enough memory, return an error */
1490 if( total > cbBufSize )
1492 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1493 MIDL_user_free(config.lpBinaryPathName);
1494 MIDL_user_free(config.lpLoadOrderGroup);
1495 MIDL_user_free(config.lpDependencies);
1496 MIDL_user_free(config.lpServiceStartName);
1497 MIDL_user_free(config.lpDisplayName);
1498 return FALSE;
1501 *lpServiceConfig = config;
1502 bufpos = ((BYTE *)lpServiceConfig) + sizeof(QUERY_SERVICE_CONFIGW);
1503 move_string_to_buffer(&bufpos, &lpServiceConfig->lpBinaryPathName);
1504 move_string_to_buffer(&bufpos, &lpServiceConfig->lpLoadOrderGroup);
1505 move_string_to_buffer(&bufpos, &lpServiceConfig->lpDependencies);
1506 move_string_to_buffer(&bufpos, &lpServiceConfig->lpServiceStartName);
1507 move_string_to_buffer(&bufpos, &lpServiceConfig->lpDisplayName);
1509 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1510 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1511 TRACE("Dependencies = %s\n", debugstr_w(lpServiceConfig->lpDependencies) );
1512 TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig->lpServiceStartName) );
1513 TRACE("Display name = %s\n", debugstr_w(lpServiceConfig->lpDisplayName) );
1515 return TRUE;
1518 /******************************************************************************
1519 * QueryServiceConfig2A [ADVAPI32.@]
1521 * Note
1522 * observed under win2k:
1523 * The functions QueryServiceConfig2A and QueryServiceConfig2W return the same
1524 * required buffer size (in byte) at least for dwLevel SERVICE_CONFIG_DESCRIPTION
1526 BOOL WINAPI QueryServiceConfig2A(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffer,
1527 DWORD size, LPDWORD needed)
1529 BOOL ret;
1530 LPBYTE bufferW = NULL;
1532 if(buffer && size)
1533 bufferW = heap_alloc(size);
1535 ret = QueryServiceConfig2W(hService, dwLevel, bufferW, size, needed);
1536 if(!ret) goto cleanup;
1538 switch(dwLevel) {
1539 case SERVICE_CONFIG_DESCRIPTION:
1540 if (buffer && bufferW) {
1541 LPSERVICE_DESCRIPTIONA configA = (LPSERVICE_DESCRIPTIONA) buffer;
1542 LPSERVICE_DESCRIPTIONW configW = (LPSERVICE_DESCRIPTIONW) bufferW;
1543 if (configW->lpDescription && (size > sizeof(SERVICE_DESCRIPTIONA))) {
1544 DWORD sz;
1545 configA->lpDescription = (LPSTR)(configA + 1);
1546 sz = WideCharToMultiByte( CP_ACP, 0, configW->lpDescription, -1,
1547 configA->lpDescription, size - sizeof(SERVICE_DESCRIPTIONA), NULL, NULL );
1548 if (!sz) {
1549 FIXME("WideCharToMultiByte failed for configW->lpDescription\n");
1550 ret = FALSE;
1551 configA->lpDescription = NULL;
1554 else configA->lpDescription = NULL;
1556 break;
1557 case SERVICE_CONFIG_PRESHUTDOWN_INFO:
1558 if (buffer && bufferW && *needed<=size)
1559 memcpy(buffer, bufferW, *needed);
1560 break;
1561 default:
1562 FIXME("conversation W->A not implemented for level %d\n", dwLevel);
1563 ret = FALSE;
1564 break;
1567 cleanup:
1568 heap_free( bufferW);
1569 return ret;
1572 /******************************************************************************
1573 * QueryServiceConfig2W [ADVAPI32.@]
1575 * See QueryServiceConfig2A.
1577 BOOL WINAPI QueryServiceConfig2W(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffer,
1578 DWORD size, LPDWORD needed)
1580 DWORD err;
1582 if(dwLevel!=SERVICE_CONFIG_DESCRIPTION && dwLevel!=SERVICE_CONFIG_PRESHUTDOWN_INFO) {
1583 FIXME("Level %d not implemented\n", dwLevel);
1584 SetLastError(ERROR_INVALID_LEVEL);
1585 return FALSE;
1588 if(!buffer && size) {
1589 SetLastError(ERROR_INVALID_ADDRESS);
1590 return FALSE;
1593 TRACE("%p 0x%d %p 0x%d %p\n", hService, dwLevel, buffer, size, needed);
1595 __TRY
1597 err = svcctl_QueryServiceConfig2W(hService, dwLevel, buffer, size, needed);
1599 __EXCEPT(rpc_filter)
1601 err = map_exception_code(GetExceptionCode());
1603 __ENDTRY
1605 if (err != ERROR_SUCCESS)
1607 SetLastError( err );
1608 return FALSE;
1611 switch (dwLevel)
1613 case SERVICE_CONFIG_DESCRIPTION:
1614 if (buffer)
1616 SERVICE_DESCRIPTIONW *descr = (SERVICE_DESCRIPTIONW *)buffer;
1617 if (descr->lpDescription) /* make it an absolute pointer */
1618 descr->lpDescription = (WCHAR *)(buffer + (ULONG_PTR)descr->lpDescription);
1619 break;
1623 return TRUE;
1626 /******************************************************************************
1627 * EnumServicesStatusA [ADVAPI32.@]
1629 BOOL WINAPI
1630 EnumServicesStatusA( SC_HANDLE hmngr, DWORD type, DWORD state, LPENUM_SERVICE_STATUSA
1631 services, DWORD size, LPDWORD needed, LPDWORD returned,
1632 LPDWORD resume_handle )
1634 BOOL ret;
1635 unsigned int i;
1636 ENUM_SERVICE_STATUSW *servicesW = NULL;
1637 DWORD sz, n;
1638 char *p;
1640 TRACE("%p 0x%x 0x%x %p %u %p %p %p\n", hmngr, type, state, services, size, needed,
1641 returned, resume_handle);
1643 sz = max( 2 * size, sizeof(*servicesW) );
1644 if (!(servicesW = heap_alloc( sz )))
1646 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1647 return FALSE;
1650 ret = EnumServicesStatusW( hmngr, type, state, servicesW, sz, needed, returned, resume_handle );
1651 if (!ret) goto done;
1653 p = (char *)services + *returned * sizeof(ENUM_SERVICE_STATUSA);
1654 n = size - (p - (char *)services);
1655 ret = FALSE;
1656 for (i = 0; i < *returned; i++)
1658 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpServiceName, -1, p, n, NULL, NULL );
1659 if (!sz) goto done;
1660 services[i].lpServiceName = p;
1661 p += sz;
1662 n -= sz;
1663 if (servicesW[i].lpDisplayName)
1665 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpDisplayName, -1, p, n, NULL, NULL );
1666 if (!sz) goto done;
1667 services[i].lpDisplayName = p;
1668 p += sz;
1669 n -= sz;
1671 else services[i].lpDisplayName = NULL;
1672 services[i].ServiceStatus = servicesW[i].ServiceStatus;
1675 ret = TRUE;
1677 done:
1678 heap_free( servicesW );
1679 return ret;
1682 /******************************************************************************
1683 * EnumServicesStatusW [ADVAPI32.@]
1685 BOOL WINAPI
1686 EnumServicesStatusW( SC_HANDLE hmngr, DWORD type, DWORD state, LPENUM_SERVICE_STATUSW
1687 services, DWORD size, LPDWORD needed, LPDWORD returned,
1688 LPDWORD resume_handle )
1690 DWORD err, i;
1691 ENUM_SERVICE_STATUSW dummy_status;
1693 TRACE("%p 0x%x 0x%x %p %u %p %p %p\n", hmngr, type, state, services, size, needed,
1694 returned, resume_handle);
1696 if (!hmngr)
1698 SetLastError( ERROR_INVALID_HANDLE );
1699 return FALSE;
1702 /* make sure we pass a valid pointer */
1703 if (!services || size < sizeof(*services))
1705 services = &dummy_status;
1706 size = sizeof(dummy_status);
1709 __TRY
1711 err = svcctl_EnumServicesStatusW( hmngr, type, state, (BYTE *)services, size, needed, returned, resume_handle );
1713 __EXCEPT(rpc_filter)
1715 err = map_exception_code( GetExceptionCode() );
1717 __ENDTRY
1719 if (err != ERROR_SUCCESS)
1721 SetLastError( err );
1722 return FALSE;
1725 for (i = 0; i < *returned; i++)
1727 /* convert buffer offsets into pointers */
1728 services[i].lpServiceName = (WCHAR *)((char *)services + (DWORD_PTR)services[i].lpServiceName);
1729 if (services[i].lpDisplayName)
1730 services[i].lpDisplayName = (WCHAR *)((char *)services + (DWORD_PTR)services[i].lpDisplayName);
1733 return TRUE;
1736 /******************************************************************************
1737 * EnumServicesStatusExA [ADVAPI32.@]
1739 BOOL WINAPI
1740 EnumServicesStatusExA( SC_HANDLE hmngr, SC_ENUM_TYPE level, DWORD type, DWORD state,
1741 LPBYTE buffer, DWORD size, LPDWORD needed, LPDWORD returned,
1742 LPDWORD resume_handle, LPCSTR group )
1744 BOOL ret;
1745 unsigned int i;
1746 ENUM_SERVICE_STATUS_PROCESSA *services = (ENUM_SERVICE_STATUS_PROCESSA *)buffer;
1747 ENUM_SERVICE_STATUS_PROCESSW *servicesW = NULL;
1748 WCHAR *groupW = NULL;
1749 DWORD sz, n;
1750 char *p;
1752 TRACE("%p %u 0x%x 0x%x %p %u %p %p %p %s\n", hmngr, level, type, state, buffer,
1753 size, needed, returned, resume_handle, debugstr_a(group));
1755 sz = max( 2 * size, sizeof(*servicesW) );
1756 if (!(servicesW = heap_alloc( sz )))
1758 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1759 return FALSE;
1761 if (group)
1763 int len = MultiByteToWideChar( CP_ACP, 0, group, -1, NULL, 0 );
1764 if (!(groupW = heap_alloc( len * sizeof(WCHAR) )))
1766 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1767 heap_free( servicesW );
1768 return FALSE;
1770 MultiByteToWideChar( CP_ACP, 0, group, -1, groupW, len * sizeof(WCHAR) );
1773 ret = EnumServicesStatusExW( hmngr, level, type, state, (BYTE *)servicesW, sz,
1774 needed, returned, resume_handle, groupW );
1775 if (!ret) goto done;
1777 p = (char *)services + *returned * sizeof(ENUM_SERVICE_STATUS_PROCESSA);
1778 n = size - (p - (char *)services);
1779 ret = FALSE;
1780 for (i = 0; i < *returned; i++)
1782 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpServiceName, -1, p, n, NULL, NULL );
1783 if (!sz) goto done;
1784 services[i].lpServiceName = p;
1785 p += sz;
1786 n -= sz;
1787 if (servicesW[i].lpDisplayName)
1789 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpDisplayName, -1, p, n, NULL, NULL );
1790 if (!sz) goto done;
1791 services[i].lpDisplayName = p;
1792 p += sz;
1793 n -= sz;
1795 else services[i].lpDisplayName = NULL;
1796 services[i].ServiceStatusProcess = servicesW[i].ServiceStatusProcess;
1799 ret = TRUE;
1801 done:
1802 heap_free( servicesW );
1803 heap_free( groupW );
1804 return ret;
1807 /******************************************************************************
1808 * EnumServicesStatusExW [ADVAPI32.@]
1810 BOOL WINAPI
1811 EnumServicesStatusExW( SC_HANDLE hmngr, SC_ENUM_TYPE level, DWORD type, DWORD state,
1812 LPBYTE buffer, DWORD size, LPDWORD needed, LPDWORD returned,
1813 LPDWORD resume_handle, LPCWSTR group )
1815 DWORD err, i;
1816 ENUM_SERVICE_STATUS_PROCESSW dummy_status;
1817 ENUM_SERVICE_STATUS_PROCESSW *services = (ENUM_SERVICE_STATUS_PROCESSW *)buffer;
1819 TRACE("%p %u 0x%x 0x%x %p %u %p %p %p %s\n", hmngr, level, type, state, buffer,
1820 size, needed, returned, resume_handle, debugstr_w(group));
1822 if (level != SC_ENUM_PROCESS_INFO)
1824 SetLastError( ERROR_INVALID_LEVEL );
1825 return FALSE;
1827 if (!hmngr)
1829 SetLastError( ERROR_INVALID_HANDLE );
1830 return FALSE;
1833 /* make sure we pass a valid buffer pointer */
1834 if (!services || size < sizeof(*services))
1836 buffer = (BYTE *)&dummy_status;
1837 size = sizeof(dummy_status);
1840 __TRY
1842 err = svcctl_EnumServicesStatusExW( hmngr, SC_ENUM_PROCESS_INFO, type, state, buffer, size, needed,
1843 returned, resume_handle, group );
1845 __EXCEPT(rpc_filter)
1847 err = map_exception_code( GetExceptionCode() );
1849 __ENDTRY
1851 if (err != ERROR_SUCCESS)
1853 SetLastError( err );
1854 return FALSE;
1857 for (i = 0; i < *returned; i++)
1859 /* convert buffer offsets into pointers */
1860 services[i].lpServiceName = (WCHAR *)((char *)services + (DWORD_PTR)services[i].lpServiceName);
1861 if (services[i].lpDisplayName)
1862 services[i].lpDisplayName = (WCHAR *)((char *)services + (DWORD_PTR)services[i].lpDisplayName);
1865 return TRUE;
1868 /******************************************************************************
1869 * GetServiceKeyNameA [ADVAPI32.@]
1871 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
1872 LPSTR lpServiceName, LPDWORD lpcchBuffer )
1874 LPWSTR lpDisplayNameW, lpServiceNameW;
1875 DWORD sizeW;
1876 BOOL ret = FALSE;
1878 TRACE("%p %s %p %p\n", hSCManager,
1879 debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
1881 lpDisplayNameW = SERV_dup(lpDisplayName);
1882 if (lpServiceName)
1883 lpServiceNameW = heap_alloc(*lpcchBuffer * sizeof(WCHAR));
1884 else
1885 lpServiceNameW = NULL;
1887 sizeW = *lpcchBuffer;
1888 if (!GetServiceKeyNameW(hSCManager, lpDisplayNameW, lpServiceNameW, &sizeW))
1890 if (lpServiceName && *lpcchBuffer)
1891 lpServiceName[0] = 0;
1892 *lpcchBuffer = sizeW*2; /* we can only provide an upper estimation of string length */
1893 goto cleanup;
1896 if (!WideCharToMultiByte(CP_ACP, 0, lpServiceNameW, (sizeW + 1), lpServiceName,
1897 *lpcchBuffer, NULL, NULL ))
1899 if (*lpcchBuffer && lpServiceName)
1900 lpServiceName[0] = 0;
1901 *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpServiceNameW, -1, NULL, 0, NULL, NULL);
1902 goto cleanup;
1905 /* lpcchBuffer not updated - same as in GetServiceDisplayNameA */
1906 ret = TRUE;
1908 cleanup:
1909 heap_free(lpServiceNameW);
1910 heap_free(lpDisplayNameW);
1911 return ret;
1914 /******************************************************************************
1915 * GetServiceKeyNameW [ADVAPI32.@]
1917 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
1918 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
1920 DWORD err;
1921 WCHAR buffer[2];
1922 DWORD size;
1924 TRACE("%p %s %p %p\n", hSCManager,
1925 debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
1927 if (!hSCManager)
1929 SetLastError( ERROR_INVALID_HANDLE );
1930 return FALSE;
1933 /* provide a buffer if the caller didn't */
1934 if (!lpServiceName || *lpcchBuffer < 2)
1936 lpServiceName = buffer;
1937 /* A size of 1 would be enough, but tests show that Windows returns 2,
1938 * probably because of a WCHAR/bytes mismatch in their code.
1940 *lpcchBuffer = 2;
1943 /* RPC call takes size excluding nul-terminator, whereas *lpcchBuffer
1944 * includes the nul-terminator on input. */
1945 size = *lpcchBuffer - 1;
1947 __TRY
1949 err = svcctl_GetServiceKeyNameW(hSCManager, lpDisplayName, lpServiceName,
1950 &size);
1952 __EXCEPT(rpc_filter)
1954 err = map_exception_code(GetExceptionCode());
1956 __ENDTRY
1958 /* The value of *lpcchBuffer excludes nul-terminator on output. */
1959 if (err == ERROR_SUCCESS || err == ERROR_INSUFFICIENT_BUFFER)
1960 *lpcchBuffer = size;
1962 if (err)
1963 SetLastError(err);
1964 return err == ERROR_SUCCESS;
1967 /******************************************************************************
1968 * QueryServiceLockStatusA [ADVAPI32.@]
1970 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
1971 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
1972 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1974 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1976 return FALSE;
1979 /******************************************************************************
1980 * QueryServiceLockStatusW [ADVAPI32.@]
1982 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
1983 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
1984 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1986 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1988 return FALSE;
1991 /******************************************************************************
1992 * GetServiceDisplayNameA [ADVAPI32.@]
1994 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1995 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
1997 LPWSTR lpServiceNameW, lpDisplayNameW;
1998 DWORD sizeW;
1999 BOOL ret = FALSE;
2001 TRACE("%p %s %p %p\n", hSCManager,
2002 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
2004 lpServiceNameW = SERV_dup(lpServiceName);
2005 if (lpDisplayName)
2006 lpDisplayNameW = heap_alloc(*lpcchBuffer * sizeof(WCHAR));
2007 else
2008 lpDisplayNameW = NULL;
2010 sizeW = *lpcchBuffer;
2011 if (!GetServiceDisplayNameW(hSCManager, lpServiceNameW, lpDisplayNameW, &sizeW))
2013 if (lpDisplayName && *lpcchBuffer)
2014 lpDisplayName[0] = 0;
2015 *lpcchBuffer = sizeW*2; /* we can only provide an upper estimation of string length */
2016 goto cleanup;
2019 if (!WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, (sizeW + 1), lpDisplayName,
2020 *lpcchBuffer, NULL, NULL ))
2022 if (*lpcchBuffer && lpDisplayName)
2023 lpDisplayName[0] = 0;
2024 *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, -1, NULL, 0, NULL, NULL);
2025 goto cleanup;
2028 /* probably due to a bug GetServiceDisplayNameA doesn't modify lpcchBuffer on success.
2029 * (but if the function succeeded it means that is a good upper estimation of the size) */
2030 ret = TRUE;
2032 cleanup:
2033 heap_free(lpDisplayNameW);
2034 heap_free(lpServiceNameW);
2035 return ret;
2038 /******************************************************************************
2039 * GetServiceDisplayNameW [ADVAPI32.@]
2041 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
2042 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
2044 DWORD err;
2045 DWORD size;
2046 WCHAR buffer[2];
2048 TRACE("%p %s %p %p\n", hSCManager,
2049 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
2051 if (!hSCManager)
2053 SetLastError( ERROR_INVALID_HANDLE );
2054 return FALSE;
2057 /* provide a buffer if the caller didn't */
2058 if (!lpDisplayName || *lpcchBuffer < 2)
2060 lpDisplayName = buffer;
2061 /* A size of 1 would be enough, but tests show that Windows returns 2,
2062 * probably because of a WCHAR/bytes mismatch in their code.
2064 *lpcchBuffer = 2;
2067 /* RPC call takes size excluding nul-terminator, whereas *lpcchBuffer
2068 * includes the nul-terminator on input. */
2069 size = *lpcchBuffer - 1;
2071 __TRY
2073 err = svcctl_GetServiceDisplayNameW(hSCManager, lpServiceName, lpDisplayName,
2074 &size);
2076 __EXCEPT(rpc_filter)
2078 err = map_exception_code(GetExceptionCode());
2080 __ENDTRY
2082 /* The value of *lpcchBuffer excludes nul-terminator on output. */
2083 if (err == ERROR_SUCCESS || err == ERROR_INSUFFICIENT_BUFFER)
2084 *lpcchBuffer = size;
2086 if (err)
2087 SetLastError(err);
2088 return err == ERROR_SUCCESS;
2091 /******************************************************************************
2092 * ChangeServiceConfigW [ADVAPI32.@]
2094 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
2095 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
2096 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
2097 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
2099 DWORD cb_pwd;
2100 DWORD err;
2102 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2103 hService, dwServiceType, dwStartType, dwErrorControl,
2104 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2105 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2106 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2108 cb_pwd = lpPassword ? (strlenW(lpPassword) + 1)*sizeof(WCHAR) : 0;
2110 __TRY
2112 err = svcctl_ChangeServiceConfigW(hService, dwServiceType,
2113 dwStartType, dwErrorControl, lpBinaryPathName, lpLoadOrderGroup, lpdwTagId,
2114 (const BYTE *)lpDependencies, multisz_cb(lpDependencies), lpServiceStartName,
2115 (const BYTE *)lpPassword, cb_pwd, lpDisplayName);
2117 __EXCEPT(rpc_filter)
2119 err = map_exception_code(GetExceptionCode());
2121 __ENDTRY
2123 if (err != ERROR_SUCCESS)
2124 SetLastError(err);
2126 return err == ERROR_SUCCESS;
2129 /******************************************************************************
2130 * ChangeServiceConfigA [ADVAPI32.@]
2132 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2133 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2134 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2135 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2137 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2138 LPWSTR wServiceStartName, wPassword, wDisplayName;
2139 BOOL r;
2141 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2142 hService, dwServiceType, dwStartType, dwErrorControl,
2143 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2144 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2145 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2147 wBinaryPathName = SERV_dup( lpBinaryPathName );
2148 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2149 wDependencies = SERV_dupmulti( lpDependencies );
2150 wServiceStartName = SERV_dup( lpServiceStartName );
2151 wPassword = SERV_dup( lpPassword );
2152 wDisplayName = SERV_dup( lpDisplayName );
2154 r = ChangeServiceConfigW( hService, dwServiceType,
2155 dwStartType, dwErrorControl, wBinaryPathName,
2156 wLoadOrderGroup, lpdwTagId, wDependencies,
2157 wServiceStartName, wPassword, wDisplayName);
2159 heap_free( wBinaryPathName );
2160 heap_free( wLoadOrderGroup );
2161 heap_free( wDependencies );
2162 heap_free( wServiceStartName );
2163 heap_free( wPassword );
2164 heap_free( wDisplayName );
2166 return r;
2169 /******************************************************************************
2170 * ChangeServiceConfig2A [ADVAPI32.@]
2172 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2173 LPVOID lpInfo)
2175 BOOL r = FALSE;
2177 TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo);
2179 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2181 LPSERVICE_DESCRIPTIONA sd = lpInfo;
2182 SERVICE_DESCRIPTIONW sdw;
2184 sdw.lpDescription = SERV_dup( sd->lpDescription );
2186 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2188 heap_free( sdw.lpDescription );
2190 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2192 LPSERVICE_FAILURE_ACTIONSA fa = lpInfo;
2193 SERVICE_FAILURE_ACTIONSW faw;
2195 faw.dwResetPeriod = fa->dwResetPeriod;
2196 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2197 faw.lpCommand = SERV_dup( fa->lpCommand );
2198 faw.cActions = fa->cActions;
2199 faw.lpsaActions = fa->lpsaActions;
2201 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2203 heap_free( faw.lpRebootMsg );
2204 heap_free( faw.lpCommand );
2206 else if (dwInfoLevel == SERVICE_CONFIG_PRESHUTDOWN_INFO)
2208 r = ChangeServiceConfig2W( hService, dwInfoLevel, lpInfo);
2210 else
2211 SetLastError( ERROR_INVALID_PARAMETER );
2213 return r;
2216 /******************************************************************************
2217 * ChangeServiceConfig2W [ADVAPI32.@]
2219 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2220 LPVOID lpInfo)
2222 DWORD err;
2224 __TRY
2226 SC_RPC_CONFIG_INFOW info;
2228 info.dwInfoLevel = dwInfoLevel;
2229 info.u.descr = lpInfo;
2230 err = svcctl_ChangeServiceConfig2W( hService, info );
2232 __EXCEPT(rpc_filter)
2234 err = map_exception_code(GetExceptionCode());
2236 __ENDTRY
2238 if (err != ERROR_SUCCESS)
2239 SetLastError(err);
2241 return err == ERROR_SUCCESS;
2244 NTSTATUS SERV_QueryServiceObjectSecurity(SC_HANDLE hService,
2245 SECURITY_INFORMATION dwSecurityInformation,
2246 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2247 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2249 SECURITY_DESCRIPTOR descriptor;
2250 NTSTATUS status;
2251 DWORD size;
2252 ACL acl;
2254 FIXME("%p %d %p %u %p - semi-stub\n", hService, dwSecurityInformation,
2255 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2257 if (dwSecurityInformation != DACL_SECURITY_INFORMATION)
2258 FIXME("information %d not supported\n", dwSecurityInformation);
2260 InitializeSecurityDescriptor(&descriptor, SECURITY_DESCRIPTOR_REVISION);
2262 InitializeAcl(&acl, sizeof(ACL), ACL_REVISION);
2263 SetSecurityDescriptorDacl(&descriptor, TRUE, &acl, TRUE);
2265 size = cbBufSize;
2266 status = RtlMakeSelfRelativeSD(&descriptor, lpSecurityDescriptor, &size);
2267 *pcbBytesNeeded = size;
2268 return status;
2271 /******************************************************************************
2272 * QueryServiceObjectSecurity [ADVAPI32.@]
2274 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2275 SECURITY_INFORMATION dwSecurityInformation,
2276 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2277 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2279 NTSTATUS status = SERV_QueryServiceObjectSecurity(hService, dwSecurityInformation, lpSecurityDescriptor,
2280 cbBufSize, pcbBytesNeeded);
2281 if (status != STATUS_SUCCESS)
2283 SetLastError(RtlNtStatusToDosError(status));
2284 return FALSE;
2286 return TRUE;
2289 /******************************************************************************
2290 * SetServiceObjectSecurity [ADVAPI32.@]
2292 * NOTES
2293 * - SetSecurityInfo should be updated to call this function once it's implemented.
2295 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2296 SECURITY_INFORMATION dwSecurityInformation,
2297 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2299 FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2300 return TRUE;
2303 /******************************************************************************
2304 * SetServiceBits [ADVAPI32.@]
2306 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2307 DWORD dwServiceBits,
2308 BOOL bSetBitsOn,
2309 BOOL bUpdateImmediately)
2311 FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2312 bSetBitsOn, bUpdateImmediately);
2313 return TRUE;
2316 /* thunk for calling the RegisterServiceCtrlHandler handler function */
2317 static DWORD WINAPI ctrl_handler_thunk( DWORD control, DWORD type, void *data, void *context )
2319 LPHANDLER_FUNCTION func = context;
2321 func( control );
2322 return ERROR_SUCCESS;
2325 /******************************************************************************
2326 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
2328 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerA( LPCSTR name, LPHANDLER_FUNCTION handler )
2330 return RegisterServiceCtrlHandlerExA( name, ctrl_handler_thunk, handler );
2333 /******************************************************************************
2334 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
2336 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR name, LPHANDLER_FUNCTION handler )
2338 return RegisterServiceCtrlHandlerExW( name, ctrl_handler_thunk, handler );
2341 /******************************************************************************
2342 * RegisterServiceCtrlHandlerExA [ADVAPI32.@]
2344 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR name, LPHANDLER_FUNCTION_EX handler, LPVOID context )
2346 LPWSTR nameW;
2347 SERVICE_STATUS_HANDLE ret;
2349 nameW = SERV_dup(name);
2350 ret = RegisterServiceCtrlHandlerExW( nameW, handler, context );
2351 heap_free( nameW );
2352 return ret;
2355 /******************************************************************************
2356 * RegisterServiceCtrlHandlerExW [ADVAPI32.@]
2358 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2359 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2361 service_data *service;
2362 SC_HANDLE hService = 0;
2364 TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2366 EnterCriticalSection( &service_cs );
2367 if ((service = find_service_by_name( lpServiceName )))
2369 service->handler = lpHandlerProc;
2370 service->context = lpContext;
2371 hService = service->handle;
2373 LeaveCriticalSection( &service_cs );
2375 if (!hService) SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
2376 return (SERVICE_STATUS_HANDLE)hService;
2379 /******************************************************************************
2380 * EnumDependentServicesA [ADVAPI32.@]
2382 BOOL WINAPI EnumDependentServicesA( SC_HANDLE hService, DWORD dwServiceState,
2383 LPENUM_SERVICE_STATUSA lpServices, DWORD cbBufSize,
2384 LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
2386 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
2387 lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
2389 *lpServicesReturned = 0;
2390 return TRUE;
2393 /******************************************************************************
2394 * EnumDependentServicesW [ADVAPI32.@]
2396 BOOL WINAPI EnumDependentServicesW( SC_HANDLE hService, DWORD dwServiceState,
2397 LPENUM_SERVICE_STATUSW lpServices, DWORD cbBufSize,
2398 LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
2400 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
2401 lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
2403 *lpServicesReturned = 0;
2404 return TRUE;
2407 /******************************************************************************
2408 * NotifyServiceStatusChangeW [ADVAPI32.@]
2410 DWORD WINAPI NotifyServiceStatusChangeW(SC_HANDLE hService, DWORD dwNotifyMask,
2411 SERVICE_NOTIFYW *pNotifyBuffer)
2413 DWORD dummy;
2414 BOOL ret;
2415 SERVICE_STATUS_PROCESS st;
2417 FIXME("%p 0x%x %p - semi-stub\n", hService, dwNotifyMask, pNotifyBuffer);
2419 ret = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (void*)&st, sizeof(st), &dummy);
2420 if (ret)
2422 /* dwNotifyMask is a set of bitflags in same order as SERVICE_ statuses */
2423 if (dwNotifyMask & (1 << (st.dwCurrentState - SERVICE_STOPPED)))
2425 pNotifyBuffer->dwNotificationStatus = ERROR_SUCCESS;
2426 memcpy(&pNotifyBuffer->ServiceStatus, &st, sizeof(pNotifyBuffer->ServiceStatus));
2427 pNotifyBuffer->dwNotificationTriggered = 1 << (st.dwCurrentState - SERVICE_STOPPED);
2428 pNotifyBuffer->pszServiceNames = NULL;
2429 TRACE("Queueing notification: 0x%x\n", pNotifyBuffer->dwNotificationTriggered);
2430 QueueUserAPC((PAPCFUNC)pNotifyBuffer->pfnNotifyCallback,
2431 GetCurrentThread(), (ULONG_PTR)pNotifyBuffer);
2435 /* TODO: If the service is not currently in a matching state, we should
2436 * tell `services` to monitor it. */
2438 return ERROR_SUCCESS;