rpcrt4: Store all active connections in RpcServerProtseq.
[wine.git] / dlls / advapi32 / service.c
blob1150805441204321c15e6c499fabadd78e5ecb68
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 BOOL stop_service;
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 void *data, DWORD data_size)
384 DWORD count = data_size / sizeof(WCHAR);
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 + 2) * sizeof(WCHAR));
394 if (count) memcpy( service->args, data, count * sizeof(WCHAR) );
395 service->args[count++] = 0;
396 service->args[count++] = 0;
398 service->thread = CreateThread( NULL, 0, service_thread,
399 service, 0, NULL );
400 SetEvent( service_event ); /* notify the main loop */
401 return 0;
404 /******************************************************************************
405 * service_handle_control
407 static DWORD service_handle_control(service_data *service, DWORD control, const void *data, DWORD data_size)
409 DWORD ret = ERROR_INVALID_SERVICE_CONTROL;
411 TRACE("%s control %u data %p data_size %u\n", debugstr_w(service->name), control, data, data_size);
413 if (control == SERVICE_CONTROL_START)
414 ret = service_handle_start(service, data, data_size);
415 else if (service->handler)
416 ret = service->handler(control, 0, (void *)data, service->context);
417 return ret;
420 /******************************************************************************
421 * service_control_dispatcher
423 static DWORD WINAPI service_control_dispatcher(LPVOID arg)
425 dispatcher_data *disp = arg;
427 /* dispatcher loop */
428 while (1)
430 service_data *service;
431 service_start_info info;
432 BYTE *data = NULL;
433 WCHAR *name;
434 BOOL r;
435 DWORD data_size = 0, count, result;
437 r = ReadFile( disp->pipe, &info, FIELD_OFFSET(service_start_info,data), &count, NULL );
438 if (!r)
440 if (GetLastError() != ERROR_BROKEN_PIPE)
441 ERR( "pipe read failed error %u\n", GetLastError() );
442 break;
444 if (count != FIELD_OFFSET(service_start_info,data))
446 ERR( "partial pipe read %u\n", count );
447 break;
449 if (count < info.total_size)
451 data_size = info.total_size - FIELD_OFFSET(service_start_info,data);
452 data = heap_alloc( data_size );
453 r = ReadFile( disp->pipe, data, data_size, &count, NULL );
454 if (!r)
456 if (GetLastError() != ERROR_BROKEN_PIPE)
457 ERR( "pipe read failed error %u\n", GetLastError() );
458 heap_free( data );
459 break;
461 if (count != data_size)
463 ERR( "partial pipe read %u/%u\n", count, data_size );
464 heap_free( data );
465 break;
469 EnterCriticalSection( &service_cs );
471 /* validate service name */
472 name = (WCHAR *)data;
473 if (!info.name_size || data_size < info.name_size * sizeof(WCHAR) || name[info.name_size - 1])
475 ERR( "got request without valid service name\n" );
476 result = ERROR_INVALID_PARAMETER;
477 goto done;
480 if (info.magic != SERVICE_PROTOCOL_MAGIC)
482 ERR( "received invalid request for service %s\n", debugstr_w(name) );
483 result = ERROR_INVALID_PARAMETER;
484 goto done;
487 /* find the service */
488 if (!(service = find_service_by_name( name )))
490 FIXME( "got request for unknown service %s\n", debugstr_w(name) );
491 result = ERROR_INVALID_PARAMETER;
492 goto done;
495 if (!service->handle)
497 if (!(service->handle = OpenServiceW( disp->manager, name, SERVICE_SET_STATUS )) ||
498 !(service->full_access_handle = OpenServiceW( disp->manager, name,
499 GENERIC_READ|GENERIC_WRITE )))
500 FIXME( "failed to open service %s\n", debugstr_w(name) );
503 data_size -= info.name_size * sizeof(WCHAR);
504 result = service_handle_control(service, info.control, data_size ?
505 &data[info.name_size * sizeof(WCHAR)] : NULL, data_size);
507 done:
508 LeaveCriticalSection( &service_cs );
509 WriteFile( disp->pipe, &result, sizeof(result), &count, NULL );
510 heap_free( data );
513 CloseHandle( disp->pipe );
514 CloseServiceHandle( disp->manager );
515 heap_free( disp );
516 return 1;
519 /******************************************************************************
520 * service_run_main_thread
522 static BOOL service_run_main_thread(void)
524 DWORD i, n, ret;
525 HANDLE wait_handles[MAXIMUM_WAIT_OBJECTS];
526 UINT wait_services[MAXIMUM_WAIT_OBJECTS];
527 dispatcher_data *disp = heap_alloc( sizeof(*disp) );
529 disp->manager = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
530 if (!disp->manager)
532 ERR("failed to open service manager error %u\n", GetLastError());
533 heap_free( disp );
534 return FALSE;
537 disp->pipe = service_open_pipe();
538 if (disp->pipe == INVALID_HANDLE_VALUE)
540 WARN("failed to create control pipe error %u\n", GetLastError());
541 CloseServiceHandle( disp->manager );
542 heap_free( disp );
543 SetLastError( ERROR_FAILED_SERVICE_CONTROLLER_CONNECT );
544 return FALSE;
547 service_event = CreateEventW( NULL, FALSE, FALSE, NULL );
548 stop_service = FALSE;
550 /* FIXME: service_control_dispatcher should be merged into the main thread */
551 wait_handles[0] = __wine_make_process_system();
552 wait_handles[1] = CreateThread( NULL, 0, service_control_dispatcher, disp, 0, NULL );
553 wait_handles[2] = service_event;
555 TRACE("Starting %d services running as process %d\n",
556 nb_services, GetCurrentProcessId());
558 /* wait for all the threads to pack up and exit */
559 while (!stop_service)
561 EnterCriticalSection( &service_cs );
562 for (i = 0, n = 3; i < nb_services && n < MAXIMUM_WAIT_OBJECTS; i++)
564 if (!services[i]->thread) continue;
565 wait_services[n] = i;
566 wait_handles[n++] = services[i]->thread;
568 LeaveCriticalSection( &service_cs );
570 ret = WaitForMultipleObjects( n, wait_handles, FALSE, INFINITE );
571 if (!ret) /* system process event */
573 SERVICE_STATUS st;
574 SERVICE_PRESHUTDOWN_INFO spi;
575 DWORD timeout = 5000;
576 BOOL res;
578 EnterCriticalSection( &service_cs );
579 n = 0;
580 for (i = 0; i < nb_services && n < MAXIMUM_WAIT_OBJECTS; i++)
582 if (!services[i]->thread) continue;
584 res = QueryServiceStatus(services[i]->full_access_handle, &st);
585 ret = ERROR_SUCCESS;
586 if (res && (st.dwControlsAccepted & SERVICE_ACCEPT_PRESHUTDOWN))
588 res = QueryServiceConfig2W( services[i]->full_access_handle, SERVICE_CONFIG_PRESHUTDOWN_INFO,
589 (LPBYTE)&spi, sizeof(spi), &i );
590 if (res)
592 FIXME("service should be able to delay shutdown\n");
593 timeout += spi.dwPreshutdownTimeout;
594 ret = service_handle_control( services[i], SERVICE_CONTROL_PRESHUTDOWN, NULL, 0 );
595 wait_handles[n++] = services[i]->thread;
598 else if (res && (st.dwControlsAccepted & SERVICE_ACCEPT_SHUTDOWN))
600 ret = service_handle_control( services[i], SERVICE_CONTROL_SHUTDOWN, NULL, 0 );
601 wait_handles[n++] = services[i]->thread;
604 LeaveCriticalSection( &service_cs );
606 TRACE("last user process exited, shutting down (timeout: %d)\n", timeout);
607 WaitForMultipleObjects( n, wait_handles, TRUE, timeout );
608 ExitProcess(0);
610 else if (ret == 1)
612 TRACE( "control dispatcher exited, shutting down\n" );
613 /* FIXME: we should maybe send a shutdown control to running services */
614 ExitProcess(0);
616 else if (ret == 2)
618 continue; /* rebuild the list */
620 else if (ret < n)
622 i = wait_services[ret];
623 EnterCriticalSection( &service_cs );
624 CloseHandle( services[i]->thread );
625 services[i]->thread = NULL;
626 LeaveCriticalSection( &service_cs );
628 else return FALSE;
631 return TRUE;
634 /******************************************************************************
635 * StartServiceCtrlDispatcherA [ADVAPI32.@]
637 * See StartServiceCtrlDispatcherW.
639 BOOL WINAPI StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *servent )
641 service_data *info;
642 unsigned int i;
644 TRACE("%p\n", servent);
646 if (nb_services)
648 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
649 return FALSE;
651 while (servent[nb_services].lpServiceName) nb_services++;
652 if (!nb_services)
654 SetLastError( ERROR_INVALID_PARAMETER );
655 return FALSE;
658 services = heap_alloc( nb_services * sizeof(*services) );
660 for (i = 0; i < nb_services; i++)
662 DWORD len = MultiByteToWideChar(CP_ACP, 0, servent[i].lpServiceName, -1, NULL, 0);
663 DWORD sz = FIELD_OFFSET( service_data, name[len] );
664 info = heap_alloc_zero( sz );
665 MultiByteToWideChar(CP_ACP, 0, servent[i].lpServiceName, -1, info->name, len);
666 info->proc.a = servent[i].lpServiceProc;
667 info->unicode = FALSE;
668 services[i] = info;
671 return service_run_main_thread();
674 /******************************************************************************
675 * StartServiceCtrlDispatcherW [ADVAPI32.@]
677 * Connects a process containing one or more services to the service control
678 * manager.
680 * PARAMS
681 * servent [I] A list of the service names and service procedures
683 * RETURNS
684 * Success: TRUE.
685 * Failure: FALSE.
687 BOOL WINAPI StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW *servent )
689 service_data *info;
690 unsigned int i;
692 TRACE("%p\n", servent);
694 if (nb_services)
696 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
697 return FALSE;
699 while (servent[nb_services].lpServiceName) nb_services++;
700 if (!nb_services)
702 SetLastError( ERROR_INVALID_PARAMETER );
703 return FALSE;
706 services = heap_alloc( nb_services * sizeof(*services) );
708 for (i = 0; i < nb_services; i++)
710 DWORD len = strlenW(servent[i].lpServiceName) + 1;
711 DWORD sz = FIELD_OFFSET( service_data, name[len] );
712 info = heap_alloc_zero( sz );
713 strcpyW(info->name, servent[i].lpServiceName);
714 info->proc.w = servent[i].lpServiceProc;
715 info->unicode = TRUE;
716 services[i] = info;
719 return service_run_main_thread();
722 /******************************************************************************
723 * LockServiceDatabase [ADVAPI32.@]
725 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
727 SC_RPC_LOCK hLock = NULL;
728 DWORD err;
730 TRACE("%p\n",hSCManager);
732 __TRY
734 err = svcctl_LockServiceDatabase(hSCManager, &hLock);
736 __EXCEPT(rpc_filter)
738 err = map_exception_code(GetExceptionCode());
740 __ENDTRY
741 if (err != ERROR_SUCCESS)
743 SetLastError(err);
744 return NULL;
746 return hLock;
749 /******************************************************************************
750 * UnlockServiceDatabase [ADVAPI32.@]
752 BOOL WINAPI UnlockServiceDatabase (SC_LOCK ScLock)
754 DWORD err;
755 SC_RPC_LOCK hRpcLock = ScLock;
757 TRACE("%p\n",ScLock);
759 __TRY
761 err = svcctl_UnlockServiceDatabase(&hRpcLock);
763 __EXCEPT(rpc_filter)
765 err = map_exception_code(GetExceptionCode());
767 __ENDTRY
768 if (err != ERROR_SUCCESS)
770 SetLastError(err);
771 return FALSE;
773 return TRUE;
776 /******************************************************************************
777 * SetServiceStatus [ADVAPI32.@]
779 * PARAMS
780 * hService []
781 * lpStatus []
783 BOOL WINAPI
784 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
786 DWORD err;
788 TRACE("%p %x %x %x %x %x %x %x\n", hService,
789 lpStatus->dwServiceType, lpStatus->dwCurrentState,
790 lpStatus->dwControlsAccepted, lpStatus->dwWin32ExitCode,
791 lpStatus->dwServiceSpecificExitCode, lpStatus->dwCheckPoint,
792 lpStatus->dwWaitHint);
794 __TRY
796 err = svcctl_SetServiceStatus( hService, lpStatus );
798 __EXCEPT(rpc_filter)
800 err = map_exception_code(GetExceptionCode());
802 __ENDTRY
803 if (err != ERROR_SUCCESS)
805 SetLastError(err);
806 return FALSE;
809 if (lpStatus->dwCurrentState == SERVICE_STOPPED)
811 unsigned int i, count = 0;
812 EnterCriticalSection( &service_cs );
813 for (i = 0; i < nb_services; i++)
815 if (services[i]->handle == (SC_HANDLE)hService) continue;
816 if (services[i]->thread) count++;
818 if (!count)
820 stop_service = TRUE;
821 SetEvent( service_event ); /* notify the main loop */
823 LeaveCriticalSection( &service_cs );
826 return TRUE;
830 /******************************************************************************
831 * OpenSCManagerA [ADVAPI32.@]
833 * Establish a connection to the service control manager and open its database.
835 * PARAMS
836 * lpMachineName [I] Pointer to machine name string
837 * lpDatabaseName [I] Pointer to database name string
838 * dwDesiredAccess [I] Type of access
840 * RETURNS
841 * Success: A Handle to the service control manager database
842 * Failure: NULL
844 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
845 DWORD dwDesiredAccess )
847 LPWSTR machineW, databaseW;
848 SC_HANDLE ret;
850 machineW = SERV_dup(lpMachineName);
851 databaseW = SERV_dup(lpDatabaseName);
852 ret = OpenSCManagerW(machineW, databaseW, dwDesiredAccess);
853 heap_free(databaseW);
854 heap_free(machineW);
855 return ret;
858 /******************************************************************************
859 * OpenSCManagerW [ADVAPI32.@]
861 * See OpenSCManagerA.
863 DWORD SERV_OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
864 DWORD dwDesiredAccess, SC_HANDLE *handle )
866 DWORD r;
868 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName),
869 debugstr_w(lpDatabaseName), dwDesiredAccess);
871 __TRY
873 r = svcctl_OpenSCManagerW(lpMachineName, lpDatabaseName, dwDesiredAccess, (SC_RPC_HANDLE *)handle);
875 __EXCEPT(rpc_filter)
877 r = map_exception_code(GetExceptionCode());
879 __ENDTRY
881 if (r!=ERROR_SUCCESS)
882 *handle = 0;
884 TRACE("returning %p\n", *handle);
885 return r;
888 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
889 DWORD dwDesiredAccess )
891 SC_HANDLE handle = 0;
892 DWORD r;
894 r = SERV_OpenSCManagerW(lpMachineName, lpDatabaseName, dwDesiredAccess, &handle);
895 if (r!=ERROR_SUCCESS)
896 SetLastError(r);
897 return handle;
900 /******************************************************************************
901 * ControlService [ADVAPI32.@]
903 * Send a control code to a service.
905 * PARAMS
906 * hService [I] Handle of the service control manager database
907 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
908 * lpServiceStatus [O] Destination for the status of the service, if available
910 * RETURNS
911 * Success: TRUE.
912 * Failure: FALSE.
914 * BUGS
915 * Unlike M$' implementation, control requests are not serialized and may be
916 * processed asynchronously.
918 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
919 LPSERVICE_STATUS lpServiceStatus )
921 DWORD err;
923 TRACE("%p %d %p\n", hService, dwControl, lpServiceStatus);
925 __TRY
927 err = svcctl_ControlService(hService, dwControl, lpServiceStatus);
929 __EXCEPT(rpc_filter)
931 err = map_exception_code(GetExceptionCode());
933 __ENDTRY
934 if (err != ERROR_SUCCESS)
936 SetLastError(err);
937 return FALSE;
940 return TRUE;
943 /******************************************************************************
944 * CloseServiceHandle [ADVAPI32.@]
946 * Close a handle to a service or the service control manager database.
948 * PARAMS
949 * hSCObject [I] Handle to service or service control manager database
951 * RETURNS
952 * Success: TRUE
953 * Failure: FALSE
955 BOOL WINAPI
956 CloseServiceHandle( SC_HANDLE hSCObject )
958 DWORD err;
960 TRACE("%p\n", hSCObject);
962 __TRY
964 err = svcctl_CloseServiceHandle((SC_RPC_HANDLE *)&hSCObject);
966 __EXCEPT(rpc_filter)
968 err = map_exception_code(GetExceptionCode());
970 __ENDTRY
972 if (err != ERROR_SUCCESS)
974 SetLastError(err);
975 return FALSE;
977 return TRUE;
981 /******************************************************************************
982 * OpenServiceA [ADVAPI32.@]
984 * Open a handle to a service.
986 * PARAMS
987 * hSCManager [I] Handle of the service control manager database
988 * lpServiceName [I] Name of the service to open
989 * dwDesiredAccess [I] Access required to the service
991 * RETURNS
992 * Success: Handle to the service
993 * Failure: NULL
995 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
996 DWORD dwDesiredAccess )
998 LPWSTR lpServiceNameW;
999 SC_HANDLE ret;
1001 TRACE("%p %s 0x%08x\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
1003 lpServiceNameW = SERV_dup(lpServiceName);
1004 ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
1005 heap_free(lpServiceNameW);
1006 return ret;
1010 /******************************************************************************
1011 * OpenServiceW [ADVAPI32.@]
1013 * See OpenServiceA.
1015 DWORD SERV_OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1016 DWORD dwDesiredAccess, SC_HANDLE *handle )
1018 DWORD err;
1020 TRACE("%p %s 0x%08x\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
1022 if (!hSCManager)
1023 return ERROR_INVALID_HANDLE;
1025 __TRY
1027 err = svcctl_OpenServiceW(hSCManager, lpServiceName, dwDesiredAccess, (SC_RPC_HANDLE *)handle);
1029 __EXCEPT(rpc_filter)
1031 err = map_exception_code(GetExceptionCode());
1033 __ENDTRY
1035 if (err != ERROR_SUCCESS)
1036 *handle = 0;
1038 TRACE("returning %p\n", *handle);
1039 return err;
1042 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1043 DWORD dwDesiredAccess)
1045 SC_HANDLE handle = 0;
1046 DWORD err;
1048 err = SERV_OpenServiceW(hSCManager, lpServiceName, dwDesiredAccess, &handle);
1049 if (err != ERROR_SUCCESS)
1050 SetLastError(err);
1051 return handle;
1054 /******************************************************************************
1055 * CreateServiceW [ADVAPI32.@]
1057 SC_HANDLE WINAPI
1058 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1059 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
1060 DWORD dwServiceType, DWORD dwStartType,
1061 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1062 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1063 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
1064 LPCWSTR lpPassword )
1066 SC_HANDLE handle = 0;
1067 DWORD err;
1068 SIZE_T passwdlen;
1070 TRACE("%p %s %s\n", hSCManager,
1071 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
1073 if (!hSCManager)
1075 SetLastError( ERROR_INVALID_HANDLE );
1076 return 0;
1079 if (lpPassword)
1080 passwdlen = (strlenW(lpPassword) + 1) * sizeof(WCHAR);
1081 else
1082 passwdlen = 0;
1084 __TRY
1086 BOOL is_wow64;
1088 IsWow64Process(GetCurrentProcess(), &is_wow64);
1090 if (is_wow64)
1091 err = svcctl_CreateServiceWOW64W(hSCManager, lpServiceName,
1092 lpDisplayName, dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1093 lpBinaryPathName, lpLoadOrderGroup, lpdwTagId, (const BYTE*)lpDependencies,
1094 multisz_cb(lpDependencies), lpServiceStartName, (const BYTE*)lpPassword, passwdlen,
1095 (SC_RPC_HANDLE *)&handle);
1096 else
1097 err = svcctl_CreateServiceW(hSCManager, lpServiceName,
1098 lpDisplayName, dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1099 lpBinaryPathName, lpLoadOrderGroup, lpdwTagId, (const BYTE*)lpDependencies,
1100 multisz_cb(lpDependencies), lpServiceStartName, (const BYTE*)lpPassword, passwdlen,
1101 (SC_RPC_HANDLE *)&handle);
1103 __EXCEPT(rpc_filter)
1105 err = map_exception_code(GetExceptionCode());
1107 __ENDTRY
1109 if (err != ERROR_SUCCESS)
1111 SetLastError(err);
1112 handle = 0;
1114 return handle;
1118 /******************************************************************************
1119 * CreateServiceA [ADVAPI32.@]
1121 SC_HANDLE WINAPI
1122 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1123 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1124 DWORD dwServiceType, DWORD dwStartType,
1125 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1126 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1127 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1128 LPCSTR lpPassword )
1130 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1131 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1132 SC_HANDLE r;
1134 TRACE("%p %s %s\n", hSCManager,
1135 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1137 lpServiceNameW = SERV_dup( lpServiceName );
1138 lpDisplayNameW = SERV_dup( lpDisplayName );
1139 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1140 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1141 lpDependenciesW = SERV_dupmulti( lpDependencies );
1142 lpServiceStartNameW = SERV_dup( lpServiceStartName );
1143 lpPasswordW = SERV_dup( lpPassword );
1145 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1146 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1147 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1148 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1150 heap_free( lpServiceNameW );
1151 heap_free( lpDisplayNameW );
1152 heap_free( lpBinaryPathNameW );
1153 heap_free( lpLoadOrderGroupW );
1154 heap_free( lpDependenciesW );
1155 heap_free( lpServiceStartNameW );
1156 heap_free( lpPasswordW );
1158 return r;
1162 /******************************************************************************
1163 * DeleteService [ADVAPI32.@]
1165 * Delete a service from the service control manager database.
1167 * PARAMS
1168 * hService [I] Handle of the service to delete
1170 * RETURNS
1171 * Success: TRUE
1172 * Failure: FALSE
1174 BOOL WINAPI DeleteService( SC_HANDLE hService )
1176 DWORD err;
1178 TRACE("%p\n", hService);
1180 __TRY
1182 err = svcctl_DeleteService(hService);
1184 __EXCEPT(rpc_filter)
1186 err = map_exception_code(GetExceptionCode());
1188 __ENDTRY
1189 if (err != 0)
1191 SetLastError(err);
1192 return FALSE;
1195 return TRUE;
1199 /******************************************************************************
1200 * StartServiceA [ADVAPI32.@]
1202 * Start a service
1204 * PARAMS
1205 * hService [I] Handle of service
1206 * dwNumServiceArgs [I] Number of arguments
1207 * lpServiceArgVectors [I] Address of array of argument strings
1209 * NOTES
1210 * - NT implements this function using an obscure RPC call.
1211 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1212 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1213 * - This will only work for shared address space. How should the service
1214 * args be transferred when address spaces are separated?
1215 * - Can only start one service at a time.
1216 * - Has no concept of privilege.
1218 * RETURNS
1219 * Success: TRUE.
1220 * Failure: FALSE
1222 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1223 LPCSTR *lpServiceArgVectors )
1225 LPWSTR *lpwstr=NULL;
1226 unsigned int i;
1227 BOOL r;
1229 TRACE("(%p,%d,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1231 if (dwNumServiceArgs)
1232 lpwstr = heap_alloc( dwNumServiceArgs*sizeof(LPWSTR) );
1234 for(i=0; i<dwNumServiceArgs; i++)
1235 lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1237 r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1239 if (dwNumServiceArgs)
1241 for(i=0; i<dwNumServiceArgs; i++)
1242 heap_free(lpwstr[i]);
1243 heap_free(lpwstr);
1246 return r;
1250 /******************************************************************************
1251 * StartServiceW [ADVAPI32.@]
1253 * See StartServiceA.
1255 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1256 LPCWSTR *lpServiceArgVectors)
1258 DWORD err;
1260 TRACE("%p %d %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1262 __TRY
1264 err = svcctl_StartServiceW(hService, dwNumServiceArgs, lpServiceArgVectors);
1266 __EXCEPT(rpc_filter)
1268 err = map_exception_code(GetExceptionCode());
1270 __ENDTRY
1271 if (err != ERROR_SUCCESS)
1273 SetLastError(err);
1274 return FALSE;
1277 return TRUE;
1280 /******************************************************************************
1281 * QueryServiceStatus [ADVAPI32.@]
1283 * PARAMS
1284 * hService [I] Handle to service to get information about
1285 * lpservicestatus [O] buffer to receive the status information for the service
1288 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1289 LPSERVICE_STATUS lpservicestatus)
1291 SERVICE_STATUS_PROCESS SvcStatusData;
1292 BOOL ret;
1293 DWORD dummy;
1295 TRACE("%p %p\n", hService, lpservicestatus);
1297 if (!hService)
1299 SetLastError(ERROR_INVALID_HANDLE);
1300 return FALSE;
1302 if (!lpservicestatus)
1304 SetLastError(ERROR_INVALID_ADDRESS);
1305 return FALSE;
1308 ret = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&SvcStatusData,
1309 sizeof(SERVICE_STATUS_PROCESS), &dummy);
1310 if (ret) memcpy(lpservicestatus, &SvcStatusData, sizeof(SERVICE_STATUS)) ;
1311 return ret;
1315 /******************************************************************************
1316 * QueryServiceStatusEx [ADVAPI32.@]
1318 * Get information about a service.
1320 * PARAMS
1321 * hService [I] Handle to service to get information about
1322 * InfoLevel [I] Level of information to get
1323 * lpBuffer [O] Destination for requested information
1324 * cbBufSize [I] Size of lpBuffer in bytes
1325 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1327 * RETURNS
1328 * Success: TRUE
1329 * FAILURE: FALSE
1331 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1332 LPBYTE lpBuffer, DWORD cbBufSize,
1333 LPDWORD pcbBytesNeeded)
1335 DWORD err;
1337 TRACE("%p %d %p %d %p\n", hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1339 if (InfoLevel != SC_STATUS_PROCESS_INFO)
1341 err = ERROR_INVALID_LEVEL;
1343 else if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
1345 *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
1346 err = ERROR_INSUFFICIENT_BUFFER;
1348 else
1350 __TRY
1352 err = svcctl_QueryServiceStatusEx(hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1354 __EXCEPT(rpc_filter)
1356 err = map_exception_code(GetExceptionCode());
1358 __ENDTRY
1360 if (err != ERROR_SUCCESS)
1362 SetLastError(err);
1363 return FALSE;
1365 return TRUE;
1368 /******************************************************************************
1369 * QueryServiceConfigA [ADVAPI32.@]
1371 BOOL WINAPI QueryServiceConfigA( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGA config,
1372 DWORD size, LPDWORD needed )
1374 DWORD n;
1375 LPSTR p, buffer;
1376 BOOL ret;
1377 QUERY_SERVICE_CONFIGW *configW;
1379 TRACE("%p %p %d %p\n", hService, config, size, needed);
1381 if (!(buffer = heap_alloc( 2 * size )))
1383 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1384 return FALSE;
1386 configW = (QUERY_SERVICE_CONFIGW *)buffer;
1387 ret = QueryServiceConfigW( hService, configW, 2 * size, needed );
1388 if (!ret) goto done;
1390 config->dwServiceType = configW->dwServiceType;
1391 config->dwStartType = configW->dwStartType;
1392 config->dwErrorControl = configW->dwErrorControl;
1393 config->lpBinaryPathName = NULL;
1394 config->lpLoadOrderGroup = NULL;
1395 config->dwTagId = configW->dwTagId;
1396 config->lpDependencies = NULL;
1397 config->lpServiceStartName = NULL;
1398 config->lpDisplayName = NULL;
1400 p = (LPSTR)(config + 1);
1401 n = size - sizeof(*config);
1402 ret = FALSE;
1404 #define MAP_STR(str) \
1405 do { \
1406 if (configW->str) \
1408 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1409 if (!sz) goto done; \
1410 config->str = p; \
1411 p += sz; \
1412 n -= sz; \
1414 } while (0)
1416 MAP_STR( lpBinaryPathName );
1417 MAP_STR( lpLoadOrderGroup );
1418 MAP_STR( lpDependencies );
1419 MAP_STR( lpServiceStartName );
1420 MAP_STR( lpDisplayName );
1421 #undef MAP_STR
1423 *needed = p - (LPSTR)config;
1424 ret = TRUE;
1426 done:
1427 heap_free( buffer );
1428 return ret;
1431 static DWORD move_string_to_buffer(BYTE **buf, LPWSTR *string_ptr)
1433 DWORD cb;
1435 if (!*string_ptr)
1437 cb = sizeof(WCHAR);
1438 memset(*buf, 0, cb);
1440 else
1442 cb = (strlenW(*string_ptr) + 1)*sizeof(WCHAR);
1443 memcpy(*buf, *string_ptr, cb);
1444 MIDL_user_free(*string_ptr);
1447 *string_ptr = (LPWSTR)*buf;
1448 *buf += cb;
1450 return cb;
1453 static DWORD size_string(LPCWSTR string)
1455 return (string ? (strlenW(string) + 1)*sizeof(WCHAR) : sizeof(WCHAR));
1458 /******************************************************************************
1459 * QueryServiceConfigW [ADVAPI32.@]
1461 BOOL WINAPI
1462 QueryServiceConfigW( SC_HANDLE hService,
1463 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1464 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1466 QUERY_SERVICE_CONFIGW config;
1467 DWORD total;
1468 DWORD err;
1469 BYTE *bufpos;
1471 TRACE("%p %p %d %p\n", hService, lpServiceConfig,
1472 cbBufSize, pcbBytesNeeded);
1474 memset(&config, 0, sizeof(config));
1476 __TRY
1478 err = svcctl_QueryServiceConfigW(hService, &config, cbBufSize, pcbBytesNeeded);
1480 __EXCEPT(rpc_filter)
1482 err = map_exception_code(GetExceptionCode());
1484 __ENDTRY
1486 if (err != ERROR_SUCCESS)
1488 TRACE("services.exe: error %u\n", err);
1489 SetLastError(err);
1490 return FALSE;
1493 /* calculate the size required first */
1494 total = sizeof (QUERY_SERVICE_CONFIGW);
1495 total += size_string(config.lpBinaryPathName);
1496 total += size_string(config.lpLoadOrderGroup);
1497 total += size_string(config.lpDependencies);
1498 total += size_string(config.lpServiceStartName);
1499 total += size_string(config.lpDisplayName);
1501 *pcbBytesNeeded = total;
1503 /* if there's not enough memory, return an error */
1504 if( total > cbBufSize )
1506 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1507 MIDL_user_free(config.lpBinaryPathName);
1508 MIDL_user_free(config.lpLoadOrderGroup);
1509 MIDL_user_free(config.lpDependencies);
1510 MIDL_user_free(config.lpServiceStartName);
1511 MIDL_user_free(config.lpDisplayName);
1512 return FALSE;
1515 *lpServiceConfig = config;
1516 bufpos = ((BYTE *)lpServiceConfig) + sizeof(QUERY_SERVICE_CONFIGW);
1517 move_string_to_buffer(&bufpos, &lpServiceConfig->lpBinaryPathName);
1518 move_string_to_buffer(&bufpos, &lpServiceConfig->lpLoadOrderGroup);
1519 move_string_to_buffer(&bufpos, &lpServiceConfig->lpDependencies);
1520 move_string_to_buffer(&bufpos, &lpServiceConfig->lpServiceStartName);
1521 move_string_to_buffer(&bufpos, &lpServiceConfig->lpDisplayName);
1523 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1524 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1525 TRACE("Dependencies = %s\n", debugstr_w(lpServiceConfig->lpDependencies) );
1526 TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig->lpServiceStartName) );
1527 TRACE("Display name = %s\n", debugstr_w(lpServiceConfig->lpDisplayName) );
1529 return TRUE;
1532 /******************************************************************************
1533 * QueryServiceConfig2A [ADVAPI32.@]
1535 * Note
1536 * observed under win2k:
1537 * The functions QueryServiceConfig2A and QueryServiceConfig2W return the same
1538 * required buffer size (in byte) at least for dwLevel SERVICE_CONFIG_DESCRIPTION
1540 BOOL WINAPI QueryServiceConfig2A(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffer,
1541 DWORD size, LPDWORD needed)
1543 BOOL ret;
1544 LPBYTE bufferW = NULL;
1546 if(buffer && size)
1547 bufferW = heap_alloc(size);
1549 ret = QueryServiceConfig2W(hService, dwLevel, bufferW, size, needed);
1550 if(!ret) goto cleanup;
1552 switch(dwLevel) {
1553 case SERVICE_CONFIG_DESCRIPTION:
1554 if (buffer && bufferW) {
1555 LPSERVICE_DESCRIPTIONA configA = (LPSERVICE_DESCRIPTIONA) buffer;
1556 LPSERVICE_DESCRIPTIONW configW = (LPSERVICE_DESCRIPTIONW) bufferW;
1557 if (configW->lpDescription && (size > sizeof(SERVICE_DESCRIPTIONA))) {
1558 DWORD sz;
1559 configA->lpDescription = (LPSTR)(configA + 1);
1560 sz = WideCharToMultiByte( CP_ACP, 0, configW->lpDescription, -1,
1561 configA->lpDescription, size - sizeof(SERVICE_DESCRIPTIONA), NULL, NULL );
1562 if (!sz) {
1563 FIXME("WideCharToMultiByte failed for configW->lpDescription\n");
1564 ret = FALSE;
1565 configA->lpDescription = NULL;
1568 else configA->lpDescription = NULL;
1570 break;
1571 case SERVICE_CONFIG_PRESHUTDOWN_INFO:
1572 if (buffer && bufferW && *needed<=size)
1573 memcpy(buffer, bufferW, *needed);
1574 break;
1575 default:
1576 FIXME("conversation W->A not implemented for level %d\n", dwLevel);
1577 ret = FALSE;
1578 break;
1581 cleanup:
1582 heap_free( bufferW);
1583 return ret;
1586 /******************************************************************************
1587 * QueryServiceConfig2W [ADVAPI32.@]
1589 * See QueryServiceConfig2A.
1591 BOOL WINAPI QueryServiceConfig2W(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffer,
1592 DWORD size, LPDWORD needed)
1594 DWORD err;
1596 if(dwLevel!=SERVICE_CONFIG_DESCRIPTION && dwLevel!=SERVICE_CONFIG_PRESHUTDOWN_INFO) {
1597 FIXME("Level %d not implemented\n", dwLevel);
1598 SetLastError(ERROR_INVALID_LEVEL);
1599 return FALSE;
1602 if(!buffer && size) {
1603 SetLastError(ERROR_INVALID_ADDRESS);
1604 return FALSE;
1607 TRACE("%p 0x%d %p 0x%d %p\n", hService, dwLevel, buffer, size, needed);
1609 __TRY
1611 err = svcctl_QueryServiceConfig2W(hService, dwLevel, buffer, size, needed);
1613 __EXCEPT(rpc_filter)
1615 err = map_exception_code(GetExceptionCode());
1617 __ENDTRY
1619 if (err != ERROR_SUCCESS)
1621 SetLastError( err );
1622 return FALSE;
1625 switch (dwLevel)
1627 case SERVICE_CONFIG_DESCRIPTION:
1628 if (buffer)
1630 SERVICE_DESCRIPTIONW *descr = (SERVICE_DESCRIPTIONW *)buffer;
1631 if (descr->lpDescription) /* make it an absolute pointer */
1632 descr->lpDescription = (WCHAR *)(buffer + (ULONG_PTR)descr->lpDescription);
1633 break;
1637 return TRUE;
1640 /******************************************************************************
1641 * EnumServicesStatusA [ADVAPI32.@]
1643 BOOL WINAPI
1644 EnumServicesStatusA( SC_HANDLE hmngr, DWORD type, DWORD state, LPENUM_SERVICE_STATUSA
1645 services, DWORD size, LPDWORD needed, LPDWORD returned,
1646 LPDWORD resume_handle )
1648 BOOL ret;
1649 unsigned int i;
1650 ENUM_SERVICE_STATUSW *servicesW = NULL;
1651 DWORD sz, n;
1652 char *p;
1654 TRACE("%p 0x%x 0x%x %p %u %p %p %p\n", hmngr, type, state, services, size, needed,
1655 returned, resume_handle);
1657 sz = max( 2 * size, sizeof(*servicesW) );
1658 if (!(servicesW = heap_alloc( sz )))
1660 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1661 return FALSE;
1664 ret = EnumServicesStatusW( hmngr, type, state, servicesW, sz, needed, returned, resume_handle );
1665 if (!ret) goto done;
1667 p = (char *)services + *returned * sizeof(ENUM_SERVICE_STATUSA);
1668 n = size - (p - (char *)services);
1669 ret = FALSE;
1670 for (i = 0; i < *returned; i++)
1672 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpServiceName, -1, p, n, NULL, NULL );
1673 if (!sz) goto done;
1674 services[i].lpServiceName = p;
1675 p += sz;
1676 n -= sz;
1677 if (servicesW[i].lpDisplayName)
1679 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpDisplayName, -1, p, n, NULL, NULL );
1680 if (!sz) goto done;
1681 services[i].lpDisplayName = p;
1682 p += sz;
1683 n -= sz;
1685 else services[i].lpDisplayName = NULL;
1686 services[i].ServiceStatus = servicesW[i].ServiceStatus;
1689 ret = TRUE;
1691 done:
1692 heap_free( servicesW );
1693 return ret;
1696 /******************************************************************************
1697 * EnumServicesStatusW [ADVAPI32.@]
1699 BOOL WINAPI
1700 EnumServicesStatusW( SC_HANDLE hmngr, DWORD type, DWORD state, LPENUM_SERVICE_STATUSW
1701 services, DWORD size, LPDWORD needed, LPDWORD returned,
1702 LPDWORD resume_handle )
1704 DWORD err, i;
1705 ENUM_SERVICE_STATUSW dummy_status;
1707 TRACE("%p 0x%x 0x%x %p %u %p %p %p\n", hmngr, type, state, services, size, needed,
1708 returned, resume_handle);
1710 if (!hmngr)
1712 SetLastError( ERROR_INVALID_HANDLE );
1713 return FALSE;
1716 /* make sure we pass a valid pointer */
1717 if (!services || size < sizeof(*services))
1719 services = &dummy_status;
1720 size = sizeof(dummy_status);
1723 __TRY
1725 err = svcctl_EnumServicesStatusW( hmngr, type, state, (BYTE *)services, size, needed, returned, resume_handle );
1727 __EXCEPT(rpc_filter)
1729 err = map_exception_code( GetExceptionCode() );
1731 __ENDTRY
1733 if (err != ERROR_SUCCESS)
1735 SetLastError( err );
1736 return FALSE;
1739 for (i = 0; i < *returned; i++)
1741 /* convert buffer offsets into pointers */
1742 services[i].lpServiceName = (WCHAR *)((char *)services + (DWORD_PTR)services[i].lpServiceName);
1743 if (services[i].lpDisplayName)
1744 services[i].lpDisplayName = (WCHAR *)((char *)services + (DWORD_PTR)services[i].lpDisplayName);
1747 return TRUE;
1750 /******************************************************************************
1751 * EnumServicesStatusExA [ADVAPI32.@]
1753 BOOL WINAPI
1754 EnumServicesStatusExA( SC_HANDLE hmngr, SC_ENUM_TYPE level, DWORD type, DWORD state,
1755 LPBYTE buffer, DWORD size, LPDWORD needed, LPDWORD returned,
1756 LPDWORD resume_handle, LPCSTR group )
1758 BOOL ret;
1759 unsigned int i;
1760 ENUM_SERVICE_STATUS_PROCESSA *services = (ENUM_SERVICE_STATUS_PROCESSA *)buffer;
1761 ENUM_SERVICE_STATUS_PROCESSW *servicesW = NULL;
1762 WCHAR *groupW = NULL;
1763 DWORD sz, n;
1764 char *p;
1766 TRACE("%p %u 0x%x 0x%x %p %u %p %p %p %s\n", hmngr, level, type, state, buffer,
1767 size, needed, returned, resume_handle, debugstr_a(group));
1769 sz = max( 2 * size, sizeof(*servicesW) );
1770 if (!(servicesW = heap_alloc( sz )))
1772 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1773 return FALSE;
1775 if (group)
1777 int len = MultiByteToWideChar( CP_ACP, 0, group, -1, NULL, 0 );
1778 if (!(groupW = heap_alloc( len * sizeof(WCHAR) )))
1780 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1781 heap_free( servicesW );
1782 return FALSE;
1784 MultiByteToWideChar( CP_ACP, 0, group, -1, groupW, len * sizeof(WCHAR) );
1787 ret = EnumServicesStatusExW( hmngr, level, type, state, (BYTE *)servicesW, sz,
1788 needed, returned, resume_handle, groupW );
1789 if (!ret) goto done;
1791 p = (char *)services + *returned * sizeof(ENUM_SERVICE_STATUS_PROCESSA);
1792 n = size - (p - (char *)services);
1793 ret = FALSE;
1794 for (i = 0; i < *returned; i++)
1796 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpServiceName, -1, p, n, NULL, NULL );
1797 if (!sz) goto done;
1798 services[i].lpServiceName = p;
1799 p += sz;
1800 n -= sz;
1801 if (servicesW[i].lpDisplayName)
1803 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpDisplayName, -1, p, n, NULL, NULL );
1804 if (!sz) goto done;
1805 services[i].lpDisplayName = p;
1806 p += sz;
1807 n -= sz;
1809 else services[i].lpDisplayName = NULL;
1810 services[i].ServiceStatusProcess = servicesW[i].ServiceStatusProcess;
1813 ret = TRUE;
1815 done:
1816 heap_free( servicesW );
1817 heap_free( groupW );
1818 return ret;
1821 /******************************************************************************
1822 * EnumServicesStatusExW [ADVAPI32.@]
1824 BOOL WINAPI
1825 EnumServicesStatusExW( SC_HANDLE hmngr, SC_ENUM_TYPE level, DWORD type, DWORD state,
1826 LPBYTE buffer, DWORD size, LPDWORD needed, LPDWORD returned,
1827 LPDWORD resume_handle, LPCWSTR group )
1829 DWORD err, i;
1830 ENUM_SERVICE_STATUS_PROCESSW dummy_status;
1831 ENUM_SERVICE_STATUS_PROCESSW *services = (ENUM_SERVICE_STATUS_PROCESSW *)buffer;
1833 TRACE("%p %u 0x%x 0x%x %p %u %p %p %p %s\n", hmngr, level, type, state, buffer,
1834 size, needed, returned, resume_handle, debugstr_w(group));
1836 if (level != SC_ENUM_PROCESS_INFO)
1838 SetLastError( ERROR_INVALID_LEVEL );
1839 return FALSE;
1841 if (!hmngr)
1843 SetLastError( ERROR_INVALID_HANDLE );
1844 return FALSE;
1847 /* make sure we pass a valid buffer pointer */
1848 if (!services || size < sizeof(*services))
1850 buffer = (BYTE *)&dummy_status;
1851 size = sizeof(dummy_status);
1854 __TRY
1856 err = svcctl_EnumServicesStatusExW( hmngr, SC_ENUM_PROCESS_INFO, type, state, buffer, size, needed,
1857 returned, resume_handle, group );
1859 __EXCEPT(rpc_filter)
1861 err = map_exception_code( GetExceptionCode() );
1863 __ENDTRY
1865 if (err != ERROR_SUCCESS)
1867 SetLastError( err );
1868 return FALSE;
1871 for (i = 0; i < *returned; i++)
1873 /* convert buffer offsets into pointers */
1874 services[i].lpServiceName = (WCHAR *)((char *)services + (DWORD_PTR)services[i].lpServiceName);
1875 if (services[i].lpDisplayName)
1876 services[i].lpDisplayName = (WCHAR *)((char *)services + (DWORD_PTR)services[i].lpDisplayName);
1879 return TRUE;
1882 /******************************************************************************
1883 * GetServiceKeyNameA [ADVAPI32.@]
1885 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
1886 LPSTR lpServiceName, LPDWORD lpcchBuffer )
1888 LPWSTR lpDisplayNameW, lpServiceNameW;
1889 DWORD sizeW;
1890 BOOL ret = FALSE;
1892 TRACE("%p %s %p %p\n", hSCManager,
1893 debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
1895 lpDisplayNameW = SERV_dup(lpDisplayName);
1896 if (lpServiceName)
1897 lpServiceNameW = heap_alloc(*lpcchBuffer * sizeof(WCHAR));
1898 else
1899 lpServiceNameW = NULL;
1901 sizeW = *lpcchBuffer;
1902 if (!GetServiceKeyNameW(hSCManager, lpDisplayNameW, lpServiceNameW, &sizeW))
1904 if (lpServiceName && *lpcchBuffer)
1905 lpServiceName[0] = 0;
1906 *lpcchBuffer = sizeW*2; /* we can only provide an upper estimation of string length */
1907 goto cleanup;
1910 if (!WideCharToMultiByte(CP_ACP, 0, lpServiceNameW, (sizeW + 1), lpServiceName,
1911 *lpcchBuffer, NULL, NULL ))
1913 if (*lpcchBuffer && lpServiceName)
1914 lpServiceName[0] = 0;
1915 *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpServiceNameW, -1, NULL, 0, NULL, NULL);
1916 goto cleanup;
1919 /* lpcchBuffer not updated - same as in GetServiceDisplayNameA */
1920 ret = TRUE;
1922 cleanup:
1923 heap_free(lpServiceNameW);
1924 heap_free(lpDisplayNameW);
1925 return ret;
1928 /******************************************************************************
1929 * GetServiceKeyNameW [ADVAPI32.@]
1931 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
1932 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
1934 DWORD err;
1935 WCHAR buffer[2];
1936 DWORD size;
1938 TRACE("%p %s %p %p\n", hSCManager,
1939 debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
1941 if (!hSCManager)
1943 SetLastError( ERROR_INVALID_HANDLE );
1944 return FALSE;
1947 /* provide a buffer if the caller didn't */
1948 if (!lpServiceName || *lpcchBuffer < 2)
1950 lpServiceName = buffer;
1951 /* A size of 1 would be enough, but tests show that Windows returns 2,
1952 * probably because of a WCHAR/bytes mismatch in their code.
1954 *lpcchBuffer = 2;
1957 /* RPC call takes size excluding nul-terminator, whereas *lpcchBuffer
1958 * includes the nul-terminator on input. */
1959 size = *lpcchBuffer - 1;
1961 __TRY
1963 err = svcctl_GetServiceKeyNameW(hSCManager, lpDisplayName, lpServiceName,
1964 &size);
1966 __EXCEPT(rpc_filter)
1968 err = map_exception_code(GetExceptionCode());
1970 __ENDTRY
1972 /* The value of *lpcchBuffer excludes nul-terminator on output. */
1973 if (err == ERROR_SUCCESS || err == ERROR_INSUFFICIENT_BUFFER)
1974 *lpcchBuffer = size;
1976 if (err)
1977 SetLastError(err);
1978 return err == ERROR_SUCCESS;
1981 /******************************************************************************
1982 * QueryServiceLockStatusA [ADVAPI32.@]
1984 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
1985 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
1986 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1988 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1990 return FALSE;
1993 /******************************************************************************
1994 * QueryServiceLockStatusW [ADVAPI32.@]
1996 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
1997 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
1998 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2000 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2002 return FALSE;
2005 /******************************************************************************
2006 * GetServiceDisplayNameA [ADVAPI32.@]
2008 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
2009 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
2011 LPWSTR lpServiceNameW, lpDisplayNameW;
2012 DWORD sizeW;
2013 BOOL ret = FALSE;
2015 TRACE("%p %s %p %p\n", hSCManager,
2016 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
2018 lpServiceNameW = SERV_dup(lpServiceName);
2019 if (lpDisplayName)
2020 lpDisplayNameW = heap_alloc(*lpcchBuffer * sizeof(WCHAR));
2021 else
2022 lpDisplayNameW = NULL;
2024 sizeW = *lpcchBuffer;
2025 if (!GetServiceDisplayNameW(hSCManager, lpServiceNameW, lpDisplayNameW, &sizeW))
2027 if (lpDisplayName && *lpcchBuffer)
2028 lpDisplayName[0] = 0;
2029 *lpcchBuffer = sizeW*2; /* we can only provide an upper estimation of string length */
2030 goto cleanup;
2033 if (!WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, (sizeW + 1), lpDisplayName,
2034 *lpcchBuffer, NULL, NULL ))
2036 if (*lpcchBuffer && lpDisplayName)
2037 lpDisplayName[0] = 0;
2038 *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, -1, NULL, 0, NULL, NULL);
2039 goto cleanup;
2042 /* probably due to a bug GetServiceDisplayNameA doesn't modify lpcchBuffer on success.
2043 * (but if the function succeeded it means that is a good upper estimation of the size) */
2044 ret = TRUE;
2046 cleanup:
2047 heap_free(lpDisplayNameW);
2048 heap_free(lpServiceNameW);
2049 return ret;
2052 /******************************************************************************
2053 * GetServiceDisplayNameW [ADVAPI32.@]
2055 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
2056 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
2058 DWORD err;
2059 DWORD size;
2060 WCHAR buffer[2];
2062 TRACE("%p %s %p %p\n", hSCManager,
2063 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
2065 if (!hSCManager)
2067 SetLastError( ERROR_INVALID_HANDLE );
2068 return FALSE;
2071 /* provide a buffer if the caller didn't */
2072 if (!lpDisplayName || *lpcchBuffer < 2)
2074 lpDisplayName = buffer;
2075 /* A size of 1 would be enough, but tests show that Windows returns 2,
2076 * probably because of a WCHAR/bytes mismatch in their code.
2078 *lpcchBuffer = 2;
2081 /* RPC call takes size excluding nul-terminator, whereas *lpcchBuffer
2082 * includes the nul-terminator on input. */
2083 size = *lpcchBuffer - 1;
2085 __TRY
2087 err = svcctl_GetServiceDisplayNameW(hSCManager, lpServiceName, lpDisplayName,
2088 &size);
2090 __EXCEPT(rpc_filter)
2092 err = map_exception_code(GetExceptionCode());
2094 __ENDTRY
2096 /* The value of *lpcchBuffer excludes nul-terminator on output. */
2097 if (err == ERROR_SUCCESS || err == ERROR_INSUFFICIENT_BUFFER)
2098 *lpcchBuffer = size;
2100 if (err)
2101 SetLastError(err);
2102 return err == ERROR_SUCCESS;
2105 /******************************************************************************
2106 * ChangeServiceConfigW [ADVAPI32.@]
2108 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
2109 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
2110 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
2111 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
2113 DWORD cb_pwd;
2114 DWORD err;
2116 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2117 hService, dwServiceType, dwStartType, dwErrorControl,
2118 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2119 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2120 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2122 cb_pwd = lpPassword ? (strlenW(lpPassword) + 1)*sizeof(WCHAR) : 0;
2124 __TRY
2126 err = svcctl_ChangeServiceConfigW(hService, dwServiceType,
2127 dwStartType, dwErrorControl, lpBinaryPathName, lpLoadOrderGroup, lpdwTagId,
2128 (const BYTE *)lpDependencies, multisz_cb(lpDependencies), lpServiceStartName,
2129 (const BYTE *)lpPassword, cb_pwd, lpDisplayName);
2131 __EXCEPT(rpc_filter)
2133 err = map_exception_code(GetExceptionCode());
2135 __ENDTRY
2137 if (err != ERROR_SUCCESS)
2138 SetLastError(err);
2140 return err == ERROR_SUCCESS;
2143 /******************************************************************************
2144 * ChangeServiceConfigA [ADVAPI32.@]
2146 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2147 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2148 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2149 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2151 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2152 LPWSTR wServiceStartName, wPassword, wDisplayName;
2153 BOOL r;
2155 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2156 hService, dwServiceType, dwStartType, dwErrorControl,
2157 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2158 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2159 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2161 wBinaryPathName = SERV_dup( lpBinaryPathName );
2162 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2163 wDependencies = SERV_dupmulti( lpDependencies );
2164 wServiceStartName = SERV_dup( lpServiceStartName );
2165 wPassword = SERV_dup( lpPassword );
2166 wDisplayName = SERV_dup( lpDisplayName );
2168 r = ChangeServiceConfigW( hService, dwServiceType,
2169 dwStartType, dwErrorControl, wBinaryPathName,
2170 wLoadOrderGroup, lpdwTagId, wDependencies,
2171 wServiceStartName, wPassword, wDisplayName);
2173 heap_free( wBinaryPathName );
2174 heap_free( wLoadOrderGroup );
2175 heap_free( wDependencies );
2176 heap_free( wServiceStartName );
2177 heap_free( wPassword );
2178 heap_free( wDisplayName );
2180 return r;
2183 /******************************************************************************
2184 * ChangeServiceConfig2A [ADVAPI32.@]
2186 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2187 LPVOID lpInfo)
2189 BOOL r = FALSE;
2191 TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo);
2193 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2195 LPSERVICE_DESCRIPTIONA sd = lpInfo;
2196 SERVICE_DESCRIPTIONW sdw;
2198 sdw.lpDescription = SERV_dup( sd->lpDescription );
2200 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2202 heap_free( sdw.lpDescription );
2204 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2206 LPSERVICE_FAILURE_ACTIONSA fa = lpInfo;
2207 SERVICE_FAILURE_ACTIONSW faw;
2209 faw.dwResetPeriod = fa->dwResetPeriod;
2210 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2211 faw.lpCommand = SERV_dup( fa->lpCommand );
2212 faw.cActions = fa->cActions;
2213 faw.lpsaActions = fa->lpsaActions;
2215 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2217 heap_free( faw.lpRebootMsg );
2218 heap_free( faw.lpCommand );
2220 else if (dwInfoLevel == SERVICE_CONFIG_PRESHUTDOWN_INFO)
2222 r = ChangeServiceConfig2W( hService, dwInfoLevel, lpInfo);
2224 else
2225 SetLastError( ERROR_INVALID_PARAMETER );
2227 return r;
2230 /******************************************************************************
2231 * ChangeServiceConfig2W [ADVAPI32.@]
2233 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2234 LPVOID lpInfo)
2236 DWORD err;
2238 __TRY
2240 SC_RPC_CONFIG_INFOW info;
2242 info.dwInfoLevel = dwInfoLevel;
2243 info.u.descr = lpInfo;
2244 err = svcctl_ChangeServiceConfig2W( hService, info );
2246 __EXCEPT(rpc_filter)
2248 err = map_exception_code(GetExceptionCode());
2250 __ENDTRY
2252 if (err != ERROR_SUCCESS)
2253 SetLastError(err);
2255 return err == ERROR_SUCCESS;
2258 NTSTATUS SERV_QueryServiceObjectSecurity(SC_HANDLE hService,
2259 SECURITY_INFORMATION dwSecurityInformation,
2260 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2261 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2263 SECURITY_DESCRIPTOR descriptor;
2264 NTSTATUS status;
2265 DWORD size;
2266 ACL acl;
2268 FIXME("%p %d %p %u %p - semi-stub\n", hService, dwSecurityInformation,
2269 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2271 if (dwSecurityInformation != DACL_SECURITY_INFORMATION)
2272 FIXME("information %d not supported\n", dwSecurityInformation);
2274 InitializeSecurityDescriptor(&descriptor, SECURITY_DESCRIPTOR_REVISION);
2276 InitializeAcl(&acl, sizeof(ACL), ACL_REVISION);
2277 SetSecurityDescriptorDacl(&descriptor, TRUE, &acl, TRUE);
2279 size = cbBufSize;
2280 status = RtlMakeSelfRelativeSD(&descriptor, lpSecurityDescriptor, &size);
2281 *pcbBytesNeeded = size;
2282 return status;
2285 /******************************************************************************
2286 * QueryServiceObjectSecurity [ADVAPI32.@]
2288 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2289 SECURITY_INFORMATION dwSecurityInformation,
2290 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2291 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2293 NTSTATUS status = SERV_QueryServiceObjectSecurity(hService, dwSecurityInformation, lpSecurityDescriptor,
2294 cbBufSize, pcbBytesNeeded);
2295 if (status != STATUS_SUCCESS)
2297 SetLastError(RtlNtStatusToDosError(status));
2298 return FALSE;
2300 return TRUE;
2303 /******************************************************************************
2304 * SetServiceObjectSecurity [ADVAPI32.@]
2306 * NOTES
2307 * - SetSecurityInfo should be updated to call this function once it's implemented.
2309 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2310 SECURITY_INFORMATION dwSecurityInformation,
2311 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2313 FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2314 return TRUE;
2317 /******************************************************************************
2318 * SetServiceBits [ADVAPI32.@]
2320 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2321 DWORD dwServiceBits,
2322 BOOL bSetBitsOn,
2323 BOOL bUpdateImmediately)
2325 FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2326 bSetBitsOn, bUpdateImmediately);
2327 return TRUE;
2330 /* thunk for calling the RegisterServiceCtrlHandler handler function */
2331 static DWORD WINAPI ctrl_handler_thunk( DWORD control, DWORD type, void *data, void *context )
2333 LPHANDLER_FUNCTION func = context;
2335 func( control );
2336 return ERROR_SUCCESS;
2339 /******************************************************************************
2340 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
2342 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerA( LPCSTR name, LPHANDLER_FUNCTION handler )
2344 return RegisterServiceCtrlHandlerExA( name, ctrl_handler_thunk, handler );
2347 /******************************************************************************
2348 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
2350 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR name, LPHANDLER_FUNCTION handler )
2352 return RegisterServiceCtrlHandlerExW( name, ctrl_handler_thunk, handler );
2355 /******************************************************************************
2356 * RegisterServiceCtrlHandlerExA [ADVAPI32.@]
2358 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR name, LPHANDLER_FUNCTION_EX handler, LPVOID context )
2360 LPWSTR nameW;
2361 SERVICE_STATUS_HANDLE ret;
2363 nameW = SERV_dup(name);
2364 ret = RegisterServiceCtrlHandlerExW( nameW, handler, context );
2365 heap_free( nameW );
2366 return ret;
2369 /******************************************************************************
2370 * RegisterServiceCtrlHandlerExW [ADVAPI32.@]
2372 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2373 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2375 service_data *service;
2376 SC_HANDLE hService = 0;
2378 TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2380 EnterCriticalSection( &service_cs );
2381 if ((service = find_service_by_name( lpServiceName )))
2383 service->handler = lpHandlerProc;
2384 service->context = lpContext;
2385 hService = service->handle;
2387 LeaveCriticalSection( &service_cs );
2389 if (!hService) SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
2390 return (SERVICE_STATUS_HANDLE)hService;
2393 /******************************************************************************
2394 * EnumDependentServicesA [ADVAPI32.@]
2396 BOOL WINAPI EnumDependentServicesA( SC_HANDLE hService, DWORD dwServiceState,
2397 LPENUM_SERVICE_STATUSA 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 * EnumDependentServicesW [ADVAPI32.@]
2410 BOOL WINAPI EnumDependentServicesW( SC_HANDLE hService, DWORD dwServiceState,
2411 LPENUM_SERVICE_STATUSW lpServices, DWORD cbBufSize,
2412 LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
2414 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
2415 lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
2417 *lpServicesReturned = 0;
2418 return TRUE;
2421 /******************************************************************************
2422 * NotifyServiceStatusChangeW [ADVAPI32.@]
2424 DWORD WINAPI NotifyServiceStatusChangeW(SC_HANDLE hService, DWORD dwNotifyMask,
2425 SERVICE_NOTIFYW *pNotifyBuffer)
2427 DWORD dummy;
2428 BOOL ret;
2429 SERVICE_STATUS_PROCESS st;
2431 FIXME("%p 0x%x %p - semi-stub\n", hService, dwNotifyMask, pNotifyBuffer);
2433 ret = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (void*)&st, sizeof(st), &dummy);
2434 if (ret)
2436 /* dwNotifyMask is a set of bitflags in same order as SERVICE_ statuses */
2437 if (dwNotifyMask & (1 << (st.dwCurrentState - SERVICE_STOPPED)))
2439 pNotifyBuffer->dwNotificationStatus = ERROR_SUCCESS;
2440 memcpy(&pNotifyBuffer->ServiceStatus, &st, sizeof(pNotifyBuffer->ServiceStatus));
2441 pNotifyBuffer->dwNotificationTriggered = 1 << (st.dwCurrentState - SERVICE_STOPPED);
2442 pNotifyBuffer->pszServiceNames = NULL;
2443 TRACE("Queueing notification: 0x%x\n", pNotifyBuffer->dwNotificationTriggered);
2444 QueueUserAPC((PAPCFUNC)pNotifyBuffer->pfnNotifyCallback,
2445 GetCurrentThread(), (ULONG_PTR)pNotifyBuffer);
2449 /* TODO: If the service is not currently in a matching state, we should
2450 * tell `services` to monitor it. */
2452 return ERROR_SUCCESS;