makefiles: Don't use standard libs for programs that specify -nodefaultlibs.
[wine/zf.git] / dlls / advapi32 / service.c
blob231f0267e984c184ae92cd8c72cc792d4b99e56e
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"
51 #include "wine/list.h"
53 WINE_DEFAULT_DEBUG_CHANNEL(service);
55 void __RPC_FAR * __RPC_USER MIDL_user_allocate(SIZE_T len)
57 return heap_alloc(len);
60 void __RPC_USER MIDL_user_free(void __RPC_FAR * ptr)
62 heap_free(ptr);
65 typedef struct service_data_t
67 LPHANDLER_FUNCTION_EX handler;
68 LPVOID context;
69 HANDLE thread;
70 SC_HANDLE handle;
71 SC_HANDLE full_access_handle;
72 BOOL unicode : 1;
73 union {
74 LPSERVICE_MAIN_FUNCTIONA a;
75 LPSERVICE_MAIN_FUNCTIONW w;
76 } proc;
77 LPWSTR args;
78 WCHAR name[1];
79 } service_data;
81 typedef struct dispatcher_data_t
83 SC_HANDLE manager;
84 HANDLE pipe;
85 } dispatcher_data;
87 typedef struct notify_data_t {
88 SC_HANDLE service;
89 SC_RPC_NOTIFY_PARAMS params;
90 SERVICE_NOTIFY_STATUS_CHANGE_PARAMS_2 cparams;
91 SC_NOTIFY_RPC_HANDLE notify_handle;
92 SERVICE_NOTIFYW *notify_buffer;
93 HANDLE calling_thread, ready_evt;
94 struct list entry;
95 } notify_data;
97 static struct list notify_list = LIST_INIT(notify_list);
99 static CRITICAL_SECTION service_cs;
100 static CRITICAL_SECTION_DEBUG service_cs_debug =
102 0, 0, &service_cs,
103 { &service_cs_debug.ProcessLocksList,
104 &service_cs_debug.ProcessLocksList },
105 0, 0, { (DWORD_PTR)(__FILE__ ": service_cs") }
107 static CRITICAL_SECTION service_cs = { &service_cs_debug, -1, 0, 0, 0, 0 };
109 static service_data **services;
110 static unsigned int nb_services;
111 static HANDLE service_event;
112 static BOOL stop_service;
114 extern HANDLE CDECL __wine_make_process_system(void);
116 /******************************************************************************
117 * String management functions (same behaviour as strdup)
118 * NOTE: the caller of those functions is responsible for calling HeapFree
119 * in order to release the memory allocated by those functions.
121 LPWSTR SERV_dup( LPCSTR str )
123 UINT len;
124 LPWSTR wstr;
126 if( !str )
127 return NULL;
128 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
129 wstr = heap_alloc( len*sizeof (WCHAR) );
130 MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
131 return wstr;
134 static inline LPWSTR SERV_dupmulti(LPCSTR str)
136 UINT len = 0, n = 0;
137 LPWSTR wstr;
139 if( !str )
140 return NULL;
141 do {
142 len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
143 n += (strlen( &str[n] ) + 1);
144 } while (str[n]);
145 len++;
146 n++;
148 wstr = heap_alloc( len*sizeof (WCHAR) );
149 MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
150 return wstr;
153 static inline DWORD multisz_cb(LPCWSTR wmultisz)
155 const WCHAR *wptr = wmultisz;
157 if (wmultisz == NULL)
158 return 0;
160 while (*wptr)
161 wptr += lstrlenW(wptr)+1;
162 return (wptr - wmultisz + 1)*sizeof(WCHAR);
165 /******************************************************************************
166 * RPC connection with services.exe
168 static handle_t rpc_wstr_bind(RPC_WSTR str)
170 WCHAR transport[] = SVCCTL_TRANSPORT;
171 WCHAR endpoint[] = SVCCTL_ENDPOINT;
172 RPC_WSTR binding_str;
173 RPC_STATUS status;
174 handle_t rpc_handle;
176 status = RpcStringBindingComposeW(NULL, transport, str, endpoint, NULL, &binding_str);
177 if (status != RPC_S_OK)
179 ERR("RpcStringBindingComposeW failed (%d)\n", (DWORD)status);
180 return NULL;
183 status = RpcBindingFromStringBindingW(binding_str, &rpc_handle);
184 RpcStringFreeW(&binding_str);
186 if (status != RPC_S_OK)
188 ERR("Couldn't connect to services.exe: error code %u\n", (DWORD)status);
189 return NULL;
192 return rpc_handle;
195 static handle_t rpc_cstr_bind(RPC_CSTR str)
197 RPC_CSTR transport = (RPC_CSTR)SVCCTL_TRANSPORTA;
198 RPC_CSTR endpoint = (RPC_CSTR)SVCCTL_ENDPOINTA;
199 RPC_CSTR binding_str;
200 RPC_STATUS status;
201 handle_t rpc_handle;
203 status = RpcStringBindingComposeA(NULL, transport, str, endpoint, NULL, &binding_str);
204 if (status != RPC_S_OK)
206 ERR("RpcStringBindingComposeW failed (%d)\n", (DWORD)status);
207 return NULL;
210 status = RpcBindingFromStringBindingA(binding_str, &rpc_handle);
211 RpcStringFreeA(&binding_str);
213 if (status != RPC_S_OK)
215 ERR("Couldn't connect to services.exe: error code %u\n", (DWORD)status);
216 return NULL;
219 return rpc_handle;
222 DECLSPEC_HIDDEN handle_t __RPC_USER MACHINE_HANDLEA_bind(MACHINE_HANDLEA MachineName)
224 return rpc_cstr_bind((RPC_CSTR)MachineName);
227 DECLSPEC_HIDDEN void __RPC_USER MACHINE_HANDLEA_unbind(MACHINE_HANDLEA MachineName, handle_t h)
229 RpcBindingFree(&h);
232 DECLSPEC_HIDDEN handle_t __RPC_USER MACHINE_HANDLEW_bind(MACHINE_HANDLEW MachineName)
234 return rpc_wstr_bind((RPC_WSTR)MachineName);
237 DECLSPEC_HIDDEN void __RPC_USER MACHINE_HANDLEW_unbind(MACHINE_HANDLEW MachineName, handle_t h)
239 RpcBindingFree(&h);
242 DECLSPEC_HIDDEN handle_t __RPC_USER SVCCTL_HANDLEW_bind(SVCCTL_HANDLEW MachineName)
244 return rpc_wstr_bind((RPC_WSTR)MachineName);
247 DECLSPEC_HIDDEN void __RPC_USER SVCCTL_HANDLEW_unbind(SVCCTL_HANDLEW MachineName, handle_t h)
249 RpcBindingFree(&h);
252 static LONG WINAPI rpc_filter(EXCEPTION_POINTERS *eptr)
254 return I_RpcExceptionFilter(eptr->ExceptionRecord->ExceptionCode);
257 static DWORD map_exception_code(DWORD exception_code)
259 switch (exception_code)
261 case RPC_X_NULL_REF_POINTER:
262 return ERROR_INVALID_ADDRESS;
263 case RPC_X_ENUM_VALUE_OUT_OF_RANGE:
264 case RPC_X_BYTE_COUNT_TOO_SMALL:
265 return ERROR_INVALID_PARAMETER;
266 case RPC_S_INVALID_BINDING:
267 case RPC_X_SS_IN_NULL_CONTEXT:
268 return ERROR_INVALID_HANDLE;
269 default:
270 return exception_code;
274 /******************************************************************************
275 * Service IPC functions
277 static LPWSTR service_get_pipe_name(void)
279 static const WCHAR format[] = { '\\','\\','.','\\','p','i','p','e','\\',
280 'n','e','t','\\','N','t','C','o','n','t','r','o','l','P','i','p','e','%','u',0};
281 static const WCHAR service_current_key_str[] = { 'S','Y','S','T','E','M','\\',
282 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
283 'C','o','n','t','r','o','l','\\',
284 'S','e','r','v','i','c','e','C','u','r','r','e','n','t',0};
285 LPWSTR name;
286 DWORD len;
287 HKEY service_current_key;
288 DWORD service_current;
289 LONG ret;
290 DWORD type;
292 ret = RegOpenKeyExW(HKEY_LOCAL_MACHINE, service_current_key_str, 0,
293 KEY_QUERY_VALUE, &service_current_key);
294 if (ret != ERROR_SUCCESS)
295 return NULL;
296 len = sizeof(service_current);
297 ret = RegQueryValueExW(service_current_key, NULL, NULL, &type,
298 (BYTE *)&service_current, &len);
299 RegCloseKey(service_current_key);
300 if (ret != ERROR_SUCCESS || type != REG_DWORD)
301 return NULL;
302 len = ARRAY_SIZE(format) + 10 /* strlenW("4294967295") */;
303 name = heap_alloc(len * sizeof(WCHAR));
304 if (!name)
305 return NULL;
306 snprintfW(name, len, format, service_current);
307 return name;
310 static HANDLE service_open_pipe(void)
312 LPWSTR szPipe = service_get_pipe_name();
313 HANDLE handle = INVALID_HANDLE_VALUE;
315 do {
316 handle = CreateFileW(szPipe, GENERIC_READ|GENERIC_WRITE,
317 0, NULL, OPEN_ALWAYS, 0, NULL);
318 if (handle != INVALID_HANDLE_VALUE)
319 break;
320 if (GetLastError() != ERROR_PIPE_BUSY)
321 break;
322 } while (WaitNamedPipeW(szPipe, NMPWAIT_USE_DEFAULT_WAIT));
323 heap_free(szPipe);
325 return handle;
328 static service_data *find_service_by_name( const WCHAR *name )
330 unsigned int i;
332 if (nb_services == 1) /* only one service (FIXME: should depend on OWN_PROCESS etc.) */
333 return services[0];
334 for (i = 0; i < nb_services; i++)
335 if (!strcmpiW( name, services[i]->name )) return services[i];
336 return NULL;
339 /******************************************************************************
340 * service_thread
342 * Call into the main service routine provided by StartServiceCtrlDispatcher.
344 static DWORD WINAPI service_thread(LPVOID arg)
346 service_data *info = arg;
347 LPWSTR str = info->args;
348 DWORD argc = 0, len = 0;
350 TRACE("%p\n", arg);
352 while (str[len])
354 len += strlenW(&str[len]) + 1;
355 argc++;
357 len++;
359 if (info->unicode)
361 LPWSTR *argv, p;
363 argv = heap_alloc((argc+1)*sizeof(LPWSTR));
364 for (argc=0, p=str; *p; p += strlenW(p) + 1)
365 argv[argc++] = p;
366 argv[argc] = NULL;
368 info->proc.w(argc, argv);
369 heap_free(argv);
371 else
373 LPSTR strA, *argv, p;
374 DWORD lenA;
376 lenA = WideCharToMultiByte(CP_ACP,0, str, len, NULL, 0, NULL, NULL);
377 strA = heap_alloc(lenA);
378 WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL);
380 argv = heap_alloc((argc+1)*sizeof(LPSTR));
381 for (argc=0, p=strA; *p; p += strlen(p) + 1)
382 argv[argc++] = p;
383 argv[argc] = NULL;
385 info->proc.a(argc, argv);
386 heap_free(argv);
387 heap_free(strA);
389 return 0;
392 /******************************************************************************
393 * service_handle_start
395 static DWORD service_handle_start(service_data *service, const void *data, DWORD data_size)
397 DWORD count = data_size / sizeof(WCHAR);
399 if (service->thread)
401 WARN("service is not stopped\n");
402 return ERROR_SERVICE_ALREADY_RUNNING;
405 heap_free(service->args);
406 service->args = heap_alloc((count + 2) * sizeof(WCHAR));
407 if (count) memcpy( service->args, data, count * sizeof(WCHAR) );
408 service->args[count++] = 0;
409 service->args[count++] = 0;
411 service->thread = CreateThread( NULL, 0, service_thread,
412 service, 0, NULL );
413 SetEvent( service_event ); /* notify the main loop */
414 return 0;
417 /******************************************************************************
418 * service_handle_control
420 static DWORD service_handle_control(service_data *service, DWORD control, const void *data, DWORD data_size)
422 DWORD ret = ERROR_INVALID_SERVICE_CONTROL;
424 TRACE("%s control %u data %p data_size %u\n", debugstr_w(service->name), control, data, data_size);
426 if (control == SERVICE_CONTROL_START)
427 ret = service_handle_start(service, data, data_size);
428 else if (service->handler)
429 ret = service->handler(control, 0, (void *)data, service->context);
430 return ret;
433 /******************************************************************************
434 * service_control_dispatcher
436 static DWORD WINAPI service_control_dispatcher(LPVOID arg)
438 dispatcher_data *disp = arg;
440 /* dispatcher loop */
441 while (1)
443 service_data *service;
444 service_start_info info;
445 BYTE *data = NULL;
446 WCHAR *name;
447 BOOL r;
448 DWORD data_size = 0, count, result;
450 r = ReadFile( disp->pipe, &info, FIELD_OFFSET(service_start_info,data), &count, NULL );
451 if (!r)
453 if (GetLastError() != ERROR_BROKEN_PIPE)
454 ERR( "pipe read failed error %u\n", GetLastError() );
455 break;
457 if (count != FIELD_OFFSET(service_start_info,data))
459 ERR( "partial pipe read %u\n", count );
460 break;
462 if (count < info.total_size)
464 data_size = info.total_size - FIELD_OFFSET(service_start_info,data);
465 data = heap_alloc( data_size );
466 r = ReadFile( disp->pipe, data, data_size, &count, NULL );
467 if (!r)
469 if (GetLastError() != ERROR_BROKEN_PIPE)
470 ERR( "pipe read failed error %u\n", GetLastError() );
471 heap_free( data );
472 break;
474 if (count != data_size)
476 ERR( "partial pipe read %u/%u\n", count, data_size );
477 heap_free( data );
478 break;
482 EnterCriticalSection( &service_cs );
484 /* validate service name */
485 name = (WCHAR *)data;
486 if (!info.name_size || data_size < info.name_size * sizeof(WCHAR) || name[info.name_size - 1])
488 ERR( "got request without valid service name\n" );
489 result = ERROR_INVALID_PARAMETER;
490 goto done;
493 if (info.magic != SERVICE_PROTOCOL_MAGIC)
495 ERR( "received invalid request for service %s\n", debugstr_w(name) );
496 result = ERROR_INVALID_PARAMETER;
497 goto done;
500 /* find the service */
501 if (!(service = find_service_by_name( name )))
503 FIXME( "got request for unknown service %s\n", debugstr_w(name) );
504 result = ERROR_INVALID_PARAMETER;
505 goto done;
508 if (!service->handle)
510 if (!(service->handle = OpenServiceW( disp->manager, name, SERVICE_SET_STATUS )) ||
511 !(service->full_access_handle = OpenServiceW( disp->manager, name,
512 GENERIC_READ|GENERIC_WRITE )))
513 FIXME( "failed to open service %s\n", debugstr_w(name) );
516 data_size -= info.name_size * sizeof(WCHAR);
517 result = service_handle_control(service, info.control, data_size ?
518 &data[info.name_size * sizeof(WCHAR)] : NULL, data_size);
520 done:
521 LeaveCriticalSection( &service_cs );
522 WriteFile( disp->pipe, &result, sizeof(result), &count, NULL );
523 heap_free( data );
526 CloseHandle( disp->pipe );
527 CloseServiceHandle( disp->manager );
528 heap_free( disp );
529 return 1;
532 /* wait for services which accept this type of message to become STOPPED */
533 static void handle_shutdown_msg(DWORD msg, DWORD accept)
535 SERVICE_STATUS st;
536 SERVICE_PRESHUTDOWN_INFO spi;
537 DWORD i, n = 0, sz, timeout = 2000;
538 ULONGLONG stop_time;
539 BOOL res, done = TRUE;
540 SC_HANDLE *wait_handles = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SC_HANDLE) * nb_services );
542 EnterCriticalSection( &service_cs );
543 for (i = 0; i < nb_services; i++)
545 res = QueryServiceStatus( services[i]->full_access_handle, &st );
546 if (!res || st.dwCurrentState == SERVICE_STOPPED || !(st.dwControlsAccepted & accept))
547 continue;
549 done = FALSE;
551 if (accept == SERVICE_ACCEPT_PRESHUTDOWN)
553 res = QueryServiceConfig2W( services[i]->full_access_handle, SERVICE_CONFIG_PRESHUTDOWN_INFO,
554 (LPBYTE)&spi, sizeof(spi), &sz );
555 if (res)
557 FIXME( "service should be able to delay shutdown\n" );
558 timeout = max( spi.dwPreshutdownTimeout, timeout );
562 service_handle_control( services[i], msg, NULL, 0 );
563 wait_handles[n++] = services[i]->full_access_handle;
565 LeaveCriticalSection( &service_cs );
567 /* FIXME: these timeouts should be more generous, but we can't currently delay prefix shutdown */
568 timeout = min( timeout, 3000 );
569 stop_time = GetTickCount64() + timeout;
571 while (!done && GetTickCount64() < stop_time)
573 done = TRUE;
574 for (i = 0; i < n; i++)
576 res = QueryServiceStatus( wait_handles[i], &st );
577 if (!res || st.dwCurrentState == SERVICE_STOPPED)
578 continue;
580 done = FALSE;
581 Sleep( 100 );
582 break;
586 HeapFree( GetProcessHeap(), 0, wait_handles );
589 /******************************************************************************
590 * service_run_main_thread
592 static BOOL service_run_main_thread(void)
594 DWORD i, n, ret;
595 HANDLE wait_handles[MAXIMUM_WAIT_OBJECTS];
596 UINT wait_services[MAXIMUM_WAIT_OBJECTS];
597 dispatcher_data *disp = heap_alloc( sizeof(*disp) );
599 disp->manager = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
600 if (!disp->manager)
602 ERR("failed to open service manager error %u\n", GetLastError());
603 heap_free( disp );
604 return FALSE;
607 disp->pipe = service_open_pipe();
608 if (disp->pipe == INVALID_HANDLE_VALUE)
610 WARN("failed to create control pipe error %u\n", GetLastError());
611 CloseServiceHandle( disp->manager );
612 heap_free( disp );
613 SetLastError( ERROR_FAILED_SERVICE_CONTROLLER_CONNECT );
614 return FALSE;
617 service_event = CreateEventW( NULL, FALSE, FALSE, NULL );
618 stop_service = FALSE;
620 /* FIXME: service_control_dispatcher should be merged into the main thread */
621 wait_handles[0] = __wine_make_process_system();
622 wait_handles[1] = CreateThread( NULL, 0, service_control_dispatcher, disp, 0, NULL );
623 wait_handles[2] = service_event;
625 TRACE("Starting %d services running as process %d\n",
626 nb_services, GetCurrentProcessId());
628 /* wait for all the threads to pack up and exit */
629 while (!stop_service)
631 EnterCriticalSection( &service_cs );
632 for (i = 0, n = 3; i < nb_services && n < MAXIMUM_WAIT_OBJECTS; i++)
634 if (!services[i]->thread) continue;
635 wait_services[n] = i;
636 wait_handles[n++] = services[i]->thread;
638 LeaveCriticalSection( &service_cs );
640 ret = WaitForMultipleObjects( n, wait_handles, FALSE, INFINITE );
641 if (!ret) /* system process event */
643 handle_shutdown_msg(SERVICE_CONTROL_PRESHUTDOWN, SERVICE_ACCEPT_PRESHUTDOWN);
644 handle_shutdown_msg(SERVICE_CONTROL_SHUTDOWN, SERVICE_ACCEPT_SHUTDOWN);
645 ExitProcess(0);
647 else if (ret == 1)
649 TRACE( "control dispatcher exited, shutting down\n" );
650 /* FIXME: we should maybe send a shutdown control to running services */
651 ExitProcess(0);
653 else if (ret == 2)
655 continue; /* rebuild the list */
657 else if (ret < n)
659 i = wait_services[ret];
660 EnterCriticalSection( &service_cs );
661 CloseHandle( services[i]->thread );
662 services[i]->thread = NULL;
663 LeaveCriticalSection( &service_cs );
665 else return FALSE;
668 return TRUE;
671 /******************************************************************************
672 * StartServiceCtrlDispatcherA [ADVAPI32.@]
674 * See StartServiceCtrlDispatcherW.
676 BOOL WINAPI StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *servent )
678 service_data *info;
679 unsigned int i;
681 TRACE("%p\n", servent);
683 if (nb_services)
685 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
686 return FALSE;
688 while (servent[nb_services].lpServiceName) nb_services++;
689 if (!nb_services)
691 SetLastError( ERROR_INVALID_PARAMETER );
692 return FALSE;
695 services = heap_alloc( nb_services * sizeof(*services) );
697 for (i = 0; i < nb_services; i++)
699 DWORD len = MultiByteToWideChar(CP_ACP, 0, servent[i].lpServiceName, -1, NULL, 0);
700 DWORD sz = FIELD_OFFSET( service_data, name[len] );
701 info = heap_alloc_zero( sz );
702 MultiByteToWideChar(CP_ACP, 0, servent[i].lpServiceName, -1, info->name, len);
703 info->proc.a = servent[i].lpServiceProc;
704 info->unicode = FALSE;
705 services[i] = info;
708 return service_run_main_thread();
711 /******************************************************************************
712 * StartServiceCtrlDispatcherW [ADVAPI32.@]
714 * Connects a process containing one or more services to the service control
715 * manager.
717 * PARAMS
718 * servent [I] A list of the service names and service procedures
720 * RETURNS
721 * Success: TRUE.
722 * Failure: FALSE.
724 BOOL WINAPI StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW *servent )
726 service_data *info;
727 unsigned int i;
729 TRACE("%p\n", servent);
731 if (nb_services)
733 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
734 return FALSE;
736 while (servent[nb_services].lpServiceName) nb_services++;
737 if (!nb_services)
739 SetLastError( ERROR_INVALID_PARAMETER );
740 return FALSE;
743 services = heap_alloc( nb_services * sizeof(*services) );
745 for (i = 0; i < nb_services; i++)
747 DWORD len = strlenW(servent[i].lpServiceName) + 1;
748 DWORD sz = FIELD_OFFSET( service_data, name[len] );
749 info = heap_alloc_zero( sz );
750 strcpyW(info->name, servent[i].lpServiceName);
751 info->proc.w = servent[i].lpServiceProc;
752 info->unicode = TRUE;
753 services[i] = info;
756 return service_run_main_thread();
759 /******************************************************************************
760 * LockServiceDatabase [ADVAPI32.@]
762 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
764 SC_RPC_LOCK hLock = NULL;
765 DWORD err;
767 TRACE("%p\n",hSCManager);
769 __TRY
771 err = svcctl_LockServiceDatabase(hSCManager, &hLock);
773 __EXCEPT(rpc_filter)
775 err = map_exception_code(GetExceptionCode());
777 __ENDTRY
778 if (err != ERROR_SUCCESS)
780 SetLastError(err);
781 return NULL;
783 return hLock;
786 /******************************************************************************
787 * UnlockServiceDatabase [ADVAPI32.@]
789 BOOL WINAPI UnlockServiceDatabase (SC_LOCK ScLock)
791 DWORD err;
792 SC_RPC_LOCK hRpcLock = ScLock;
794 TRACE("%p\n",ScLock);
796 __TRY
798 err = svcctl_UnlockServiceDatabase(&hRpcLock);
800 __EXCEPT(rpc_filter)
802 err = map_exception_code(GetExceptionCode());
804 __ENDTRY
805 if (err != ERROR_SUCCESS)
807 SetLastError(err);
808 return FALSE;
810 return TRUE;
813 /******************************************************************************
814 * SetServiceStatus [ADVAPI32.@]
816 * PARAMS
817 * hService []
818 * lpStatus []
820 BOOL WINAPI
821 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
823 DWORD err;
825 TRACE("%p %x %x %x %x %x %x %x\n", hService,
826 lpStatus->dwServiceType, lpStatus->dwCurrentState,
827 lpStatus->dwControlsAccepted, lpStatus->dwWin32ExitCode,
828 lpStatus->dwServiceSpecificExitCode, lpStatus->dwCheckPoint,
829 lpStatus->dwWaitHint);
831 __TRY
833 err = svcctl_SetServiceStatus( hService, lpStatus );
835 __EXCEPT(rpc_filter)
837 err = map_exception_code(GetExceptionCode());
839 __ENDTRY
840 if (err != ERROR_SUCCESS)
842 SetLastError(err);
843 return FALSE;
846 if (lpStatus->dwCurrentState == SERVICE_STOPPED)
848 unsigned int i, count = 0;
849 EnterCriticalSection( &service_cs );
850 for (i = 0; i < nb_services; i++)
852 if (services[i]->handle == (SC_HANDLE)hService) continue;
853 if (services[i]->thread) count++;
855 if (!count)
857 stop_service = TRUE;
858 SetEvent( service_event ); /* notify the main loop */
860 LeaveCriticalSection( &service_cs );
863 return TRUE;
867 /******************************************************************************
868 * OpenSCManagerA [ADVAPI32.@]
870 * Establish a connection to the service control manager and open its database.
872 * PARAMS
873 * lpMachineName [I] Pointer to machine name string
874 * lpDatabaseName [I] Pointer to database name string
875 * dwDesiredAccess [I] Type of access
877 * RETURNS
878 * Success: A Handle to the service control manager database
879 * Failure: NULL
881 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
882 DWORD dwDesiredAccess )
884 LPWSTR machineW, databaseW;
885 SC_HANDLE ret;
887 machineW = SERV_dup(lpMachineName);
888 databaseW = SERV_dup(lpDatabaseName);
889 ret = OpenSCManagerW(machineW, databaseW, dwDesiredAccess);
890 heap_free(databaseW);
891 heap_free(machineW);
892 return ret;
895 /******************************************************************************
896 * OpenSCManagerW [ADVAPI32.@]
898 * See OpenSCManagerA.
900 DWORD SERV_OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
901 DWORD dwDesiredAccess, SC_HANDLE *handle )
903 DWORD r;
905 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName),
906 debugstr_w(lpDatabaseName), dwDesiredAccess);
908 __TRY
910 r = svcctl_OpenSCManagerW(lpMachineName, lpDatabaseName, dwDesiredAccess, (SC_RPC_HANDLE *)handle);
912 __EXCEPT(rpc_filter)
914 r = map_exception_code(GetExceptionCode());
916 __ENDTRY
918 if (r!=ERROR_SUCCESS)
919 *handle = 0;
921 TRACE("returning %p\n", *handle);
922 return r;
925 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
926 DWORD dwDesiredAccess )
928 SC_HANDLE handle = 0;
929 DWORD r;
931 r = SERV_OpenSCManagerW(lpMachineName, lpDatabaseName, dwDesiredAccess, &handle);
932 if (r!=ERROR_SUCCESS)
933 SetLastError(r);
934 return handle;
937 /******************************************************************************
938 * ControlService [ADVAPI32.@]
940 * Send a control code to a service.
942 * PARAMS
943 * hService [I] Handle of the service control manager database
944 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
945 * lpServiceStatus [O] Destination for the status of the service, if available
947 * RETURNS
948 * Success: TRUE.
949 * Failure: FALSE.
951 * BUGS
952 * Unlike M$' implementation, control requests are not serialized and may be
953 * processed asynchronously.
955 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
956 LPSERVICE_STATUS lpServiceStatus )
958 DWORD err;
960 TRACE("%p %d %p\n", hService, dwControl, lpServiceStatus);
962 __TRY
964 err = svcctl_ControlService(hService, dwControl, lpServiceStatus);
966 __EXCEPT(rpc_filter)
968 err = map_exception_code(GetExceptionCode());
970 __ENDTRY
971 if (err != ERROR_SUCCESS)
973 SetLastError(err);
974 return FALSE;
977 return TRUE;
980 /******************************************************************************
981 * CloseServiceHandle [ADVAPI32.@]
983 * Close a handle to a service or the service control manager database.
985 * PARAMS
986 * hSCObject [I] Handle to service or service control manager database
988 * RETURNS
989 * Success: TRUE
990 * Failure: FALSE
992 BOOL WINAPI
993 CloseServiceHandle( SC_HANDLE hSCObject )
995 DWORD err;
997 TRACE("%p\n", hSCObject);
999 __TRY
1001 err = svcctl_CloseServiceHandle((SC_RPC_HANDLE *)&hSCObject);
1003 __EXCEPT(rpc_filter)
1005 err = map_exception_code(GetExceptionCode());
1007 __ENDTRY
1009 if (err != ERROR_SUCCESS)
1011 SetLastError(err);
1012 return FALSE;
1014 return TRUE;
1018 /******************************************************************************
1019 * OpenServiceA [ADVAPI32.@]
1021 * Open a handle to a service.
1023 * PARAMS
1024 * hSCManager [I] Handle of the service control manager database
1025 * lpServiceName [I] Name of the service to open
1026 * dwDesiredAccess [I] Access required to the service
1028 * RETURNS
1029 * Success: Handle to the service
1030 * Failure: NULL
1032 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1033 DWORD dwDesiredAccess )
1035 LPWSTR lpServiceNameW;
1036 SC_HANDLE ret;
1038 TRACE("%p %s 0x%08x\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
1040 lpServiceNameW = SERV_dup(lpServiceName);
1041 ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
1042 heap_free(lpServiceNameW);
1043 return ret;
1047 /******************************************************************************
1048 * OpenServiceW [ADVAPI32.@]
1050 * See OpenServiceA.
1052 DWORD SERV_OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1053 DWORD dwDesiredAccess, SC_HANDLE *handle )
1055 DWORD err;
1057 TRACE("%p %s 0x%08x\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
1059 if (!hSCManager)
1060 return ERROR_INVALID_HANDLE;
1062 __TRY
1064 err = svcctl_OpenServiceW(hSCManager, lpServiceName, dwDesiredAccess, (SC_RPC_HANDLE *)handle);
1066 __EXCEPT(rpc_filter)
1068 err = map_exception_code(GetExceptionCode());
1070 __ENDTRY
1072 if (err != ERROR_SUCCESS)
1073 *handle = 0;
1075 TRACE("returning %p\n", *handle);
1076 return err;
1079 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1080 DWORD dwDesiredAccess)
1082 SC_HANDLE handle = 0;
1083 DWORD err;
1085 err = SERV_OpenServiceW(hSCManager, lpServiceName, dwDesiredAccess, &handle);
1086 if (err != ERROR_SUCCESS)
1087 SetLastError(err);
1088 return handle;
1091 /******************************************************************************
1092 * CreateServiceW [ADVAPI32.@]
1094 SC_HANDLE WINAPI
1095 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1096 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
1097 DWORD dwServiceType, DWORD dwStartType,
1098 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1099 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1100 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
1101 LPCWSTR lpPassword )
1103 SC_HANDLE handle = 0;
1104 DWORD err;
1105 SIZE_T passwdlen;
1107 TRACE("%p %s %s\n", hSCManager,
1108 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
1110 if (!hSCManager)
1112 SetLastError( ERROR_INVALID_HANDLE );
1113 return 0;
1116 if (lpPassword)
1117 passwdlen = (strlenW(lpPassword) + 1) * sizeof(WCHAR);
1118 else
1119 passwdlen = 0;
1121 __TRY
1123 BOOL is_wow64;
1125 IsWow64Process(GetCurrentProcess(), &is_wow64);
1127 if (is_wow64)
1128 err = svcctl_CreateServiceWOW64W(hSCManager, lpServiceName,
1129 lpDisplayName, dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1130 lpBinaryPathName, lpLoadOrderGroup, lpdwTagId, (const BYTE*)lpDependencies,
1131 multisz_cb(lpDependencies), lpServiceStartName, (const BYTE*)lpPassword, passwdlen,
1132 (SC_RPC_HANDLE *)&handle);
1133 else
1134 err = svcctl_CreateServiceW(hSCManager, lpServiceName,
1135 lpDisplayName, dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1136 lpBinaryPathName, lpLoadOrderGroup, lpdwTagId, (const BYTE*)lpDependencies,
1137 multisz_cb(lpDependencies), lpServiceStartName, (const BYTE*)lpPassword, passwdlen,
1138 (SC_RPC_HANDLE *)&handle);
1140 __EXCEPT(rpc_filter)
1142 err = map_exception_code(GetExceptionCode());
1144 __ENDTRY
1146 if (err != ERROR_SUCCESS)
1148 SetLastError(err);
1149 handle = 0;
1151 return handle;
1155 /******************************************************************************
1156 * CreateServiceA [ADVAPI32.@]
1158 SC_HANDLE WINAPI
1159 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1160 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1161 DWORD dwServiceType, DWORD dwStartType,
1162 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1163 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1164 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1165 LPCSTR lpPassword )
1167 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1168 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1169 SC_HANDLE r;
1171 TRACE("%p %s %s\n", hSCManager,
1172 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1174 lpServiceNameW = SERV_dup( lpServiceName );
1175 lpDisplayNameW = SERV_dup( lpDisplayName );
1176 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1177 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1178 lpDependenciesW = SERV_dupmulti( lpDependencies );
1179 lpServiceStartNameW = SERV_dup( lpServiceStartName );
1180 lpPasswordW = SERV_dup( lpPassword );
1182 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1183 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1184 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1185 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1187 heap_free( lpServiceNameW );
1188 heap_free( lpDisplayNameW );
1189 heap_free( lpBinaryPathNameW );
1190 heap_free( lpLoadOrderGroupW );
1191 heap_free( lpDependenciesW );
1192 heap_free( lpServiceStartNameW );
1193 heap_free( lpPasswordW );
1195 return r;
1199 /******************************************************************************
1200 * DeleteService [ADVAPI32.@]
1202 * Delete a service from the service control manager database.
1204 * PARAMS
1205 * hService [I] Handle of the service to delete
1207 * RETURNS
1208 * Success: TRUE
1209 * Failure: FALSE
1211 BOOL WINAPI DeleteService( SC_HANDLE hService )
1213 DWORD err;
1215 TRACE("%p\n", hService);
1217 __TRY
1219 err = svcctl_DeleteService(hService);
1221 __EXCEPT(rpc_filter)
1223 err = map_exception_code(GetExceptionCode());
1225 __ENDTRY
1226 if (err != 0)
1228 SetLastError(err);
1229 return FALSE;
1232 return TRUE;
1236 /******************************************************************************
1237 * StartServiceA [ADVAPI32.@]
1239 * Start a service
1241 * PARAMS
1242 * hService [I] Handle of service
1243 * dwNumServiceArgs [I] Number of arguments
1244 * lpServiceArgVectors [I] Address of array of argument strings
1246 * NOTES
1247 * - NT implements this function using an obscure RPC call.
1248 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1249 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1250 * - This will only work for shared address space. How should the service
1251 * args be transferred when address spaces are separated?
1252 * - Can only start one service at a time.
1253 * - Has no concept of privilege.
1255 * RETURNS
1256 * Success: TRUE.
1257 * Failure: FALSE
1259 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1260 LPCSTR *lpServiceArgVectors )
1262 LPWSTR *lpwstr=NULL;
1263 unsigned int i;
1264 BOOL r;
1266 TRACE("(%p,%d,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1268 if (dwNumServiceArgs)
1269 lpwstr = heap_alloc( dwNumServiceArgs*sizeof(LPWSTR) );
1271 for(i=0; i<dwNumServiceArgs; i++)
1272 lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1274 r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1276 if (dwNumServiceArgs)
1278 for(i=0; i<dwNumServiceArgs; i++)
1279 heap_free(lpwstr[i]);
1280 heap_free(lpwstr);
1283 return r;
1287 /******************************************************************************
1288 * StartServiceW [ADVAPI32.@]
1290 * See StartServiceA.
1292 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1293 LPCWSTR *lpServiceArgVectors)
1295 DWORD err;
1297 TRACE("%p %d %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1299 __TRY
1301 err = svcctl_StartServiceW(hService, dwNumServiceArgs, lpServiceArgVectors);
1303 __EXCEPT(rpc_filter)
1305 err = map_exception_code(GetExceptionCode());
1307 __ENDTRY
1308 if (err != ERROR_SUCCESS)
1310 SetLastError(err);
1311 return FALSE;
1314 return TRUE;
1317 /******************************************************************************
1318 * QueryServiceStatus [ADVAPI32.@]
1320 * PARAMS
1321 * hService [I] Handle to service to get information about
1322 * lpservicestatus [O] buffer to receive the status information for the service
1325 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1326 LPSERVICE_STATUS lpservicestatus)
1328 SERVICE_STATUS_PROCESS SvcStatusData;
1329 BOOL ret;
1330 DWORD dummy;
1332 TRACE("%p %p\n", hService, lpservicestatus);
1334 if (!hService)
1336 SetLastError(ERROR_INVALID_HANDLE);
1337 return FALSE;
1339 if (!lpservicestatus)
1341 SetLastError(ERROR_INVALID_ADDRESS);
1342 return FALSE;
1345 ret = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&SvcStatusData,
1346 sizeof(SERVICE_STATUS_PROCESS), &dummy);
1347 if (ret) memcpy(lpservicestatus, &SvcStatusData, sizeof(SERVICE_STATUS)) ;
1348 return ret;
1352 /******************************************************************************
1353 * QueryServiceStatusEx [ADVAPI32.@]
1355 * Get information about a service.
1357 * PARAMS
1358 * hService [I] Handle to service to get information about
1359 * InfoLevel [I] Level of information to get
1360 * lpBuffer [O] Destination for requested information
1361 * cbBufSize [I] Size of lpBuffer in bytes
1362 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1364 * RETURNS
1365 * Success: TRUE
1366 * FAILURE: FALSE
1368 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1369 LPBYTE lpBuffer, DWORD cbBufSize,
1370 LPDWORD pcbBytesNeeded)
1372 DWORD err;
1374 TRACE("%p %d %p %d %p\n", hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1376 if (InfoLevel != SC_STATUS_PROCESS_INFO)
1378 err = ERROR_INVALID_LEVEL;
1380 else if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
1382 *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
1383 err = ERROR_INSUFFICIENT_BUFFER;
1385 else
1387 __TRY
1389 err = svcctl_QueryServiceStatusEx(hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1391 __EXCEPT(rpc_filter)
1393 err = map_exception_code(GetExceptionCode());
1395 __ENDTRY
1397 if (err != ERROR_SUCCESS)
1399 SetLastError(err);
1400 return FALSE;
1402 return TRUE;
1405 /******************************************************************************
1406 * QueryServiceConfigA [ADVAPI32.@]
1408 BOOL WINAPI QueryServiceConfigA( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGA config,
1409 DWORD size, LPDWORD needed )
1411 DWORD n;
1412 LPSTR p, buffer;
1413 BOOL ret;
1414 QUERY_SERVICE_CONFIGW *configW;
1416 TRACE("%p %p %d %p\n", hService, config, size, needed);
1418 if (!(buffer = heap_alloc( 2 * size )))
1420 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1421 return FALSE;
1423 configW = (QUERY_SERVICE_CONFIGW *)buffer;
1424 ret = QueryServiceConfigW( hService, configW, 2 * size, needed );
1425 if (!ret) goto done;
1427 config->dwServiceType = configW->dwServiceType;
1428 config->dwStartType = configW->dwStartType;
1429 config->dwErrorControl = configW->dwErrorControl;
1430 config->lpBinaryPathName = NULL;
1431 config->lpLoadOrderGroup = NULL;
1432 config->dwTagId = configW->dwTagId;
1433 config->lpDependencies = NULL;
1434 config->lpServiceStartName = NULL;
1435 config->lpDisplayName = NULL;
1437 p = (LPSTR)(config + 1);
1438 n = size - sizeof(*config);
1439 ret = FALSE;
1441 #define MAP_STR(str) \
1442 do { \
1443 if (configW->str) \
1445 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1446 if (!sz) goto done; \
1447 config->str = p; \
1448 p += sz; \
1449 n -= sz; \
1451 } while (0)
1453 MAP_STR( lpBinaryPathName );
1454 MAP_STR( lpLoadOrderGroup );
1455 MAP_STR( lpDependencies );
1456 MAP_STR( lpServiceStartName );
1457 MAP_STR( lpDisplayName );
1458 #undef MAP_STR
1460 *needed = p - (LPSTR)config;
1461 ret = TRUE;
1463 done:
1464 heap_free( buffer );
1465 return ret;
1468 static DWORD move_string_to_buffer(BYTE **buf, LPWSTR *string_ptr)
1470 DWORD cb;
1472 if (!*string_ptr)
1474 cb = sizeof(WCHAR);
1475 memset(*buf, 0, cb);
1477 else
1479 cb = (strlenW(*string_ptr) + 1)*sizeof(WCHAR);
1480 memcpy(*buf, *string_ptr, cb);
1481 MIDL_user_free(*string_ptr);
1484 *string_ptr = (LPWSTR)*buf;
1485 *buf += cb;
1487 return cb;
1490 static DWORD size_string(LPCWSTR string)
1492 return (string ? (strlenW(string) + 1)*sizeof(WCHAR) : sizeof(WCHAR));
1495 /******************************************************************************
1496 * QueryServiceConfigW [ADVAPI32.@]
1498 BOOL WINAPI
1499 QueryServiceConfigW( SC_HANDLE hService,
1500 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1501 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1503 QUERY_SERVICE_CONFIGW config;
1504 DWORD total;
1505 DWORD err;
1506 BYTE *bufpos;
1508 TRACE("%p %p %d %p\n", hService, lpServiceConfig,
1509 cbBufSize, pcbBytesNeeded);
1511 memset(&config, 0, sizeof(config));
1513 __TRY
1515 err = svcctl_QueryServiceConfigW(hService, &config, cbBufSize, pcbBytesNeeded);
1517 __EXCEPT(rpc_filter)
1519 err = map_exception_code(GetExceptionCode());
1521 __ENDTRY
1523 if (err != ERROR_SUCCESS)
1525 TRACE("services.exe: error %u\n", err);
1526 SetLastError(err);
1527 return FALSE;
1530 /* calculate the size required first */
1531 total = sizeof (QUERY_SERVICE_CONFIGW);
1532 total += size_string(config.lpBinaryPathName);
1533 total += size_string(config.lpLoadOrderGroup);
1534 total += size_string(config.lpDependencies);
1535 total += size_string(config.lpServiceStartName);
1536 total += size_string(config.lpDisplayName);
1538 *pcbBytesNeeded = total;
1540 /* if there's not enough memory, return an error */
1541 if( total > cbBufSize )
1543 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1544 MIDL_user_free(config.lpBinaryPathName);
1545 MIDL_user_free(config.lpLoadOrderGroup);
1546 MIDL_user_free(config.lpDependencies);
1547 MIDL_user_free(config.lpServiceStartName);
1548 MIDL_user_free(config.lpDisplayName);
1549 return FALSE;
1552 *lpServiceConfig = config;
1553 bufpos = ((BYTE *)lpServiceConfig) + sizeof(QUERY_SERVICE_CONFIGW);
1554 move_string_to_buffer(&bufpos, &lpServiceConfig->lpBinaryPathName);
1555 move_string_to_buffer(&bufpos, &lpServiceConfig->lpLoadOrderGroup);
1556 move_string_to_buffer(&bufpos, &lpServiceConfig->lpDependencies);
1557 move_string_to_buffer(&bufpos, &lpServiceConfig->lpServiceStartName);
1558 move_string_to_buffer(&bufpos, &lpServiceConfig->lpDisplayName);
1560 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1561 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1562 TRACE("Dependencies = %s\n", debugstr_w(lpServiceConfig->lpDependencies) );
1563 TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig->lpServiceStartName) );
1564 TRACE("Display name = %s\n", debugstr_w(lpServiceConfig->lpDisplayName) );
1566 return TRUE;
1569 /******************************************************************************
1570 * QueryServiceConfig2A [ADVAPI32.@]
1572 * Note
1573 * observed under win2k:
1574 * The functions QueryServiceConfig2A and QueryServiceConfig2W return the same
1575 * required buffer size (in byte) at least for dwLevel SERVICE_CONFIG_DESCRIPTION
1577 BOOL WINAPI QueryServiceConfig2A(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffer,
1578 DWORD size, LPDWORD needed)
1580 BOOL ret;
1581 LPBYTE bufferW = NULL;
1583 TRACE("%p %u %p %u %p\n", hService, dwLevel, buffer, size, needed);
1585 if(buffer && size)
1586 bufferW = heap_alloc(size);
1588 ret = QueryServiceConfig2W(hService, dwLevel, bufferW, size, needed);
1589 if(!ret) goto cleanup;
1591 switch(dwLevel) {
1592 case SERVICE_CONFIG_DESCRIPTION:
1593 if (buffer && bufferW) {
1594 LPSERVICE_DESCRIPTIONA configA = (LPSERVICE_DESCRIPTIONA) buffer;
1595 LPSERVICE_DESCRIPTIONW configW = (LPSERVICE_DESCRIPTIONW) bufferW;
1596 if (configW->lpDescription && (size > sizeof(SERVICE_DESCRIPTIONA))) {
1597 DWORD sz;
1598 configA->lpDescription = (LPSTR)(configA + 1);
1599 sz = WideCharToMultiByte( CP_ACP, 0, configW->lpDescription, -1,
1600 configA->lpDescription, size - sizeof(SERVICE_DESCRIPTIONA), NULL, NULL );
1601 if (!sz) {
1602 FIXME("WideCharToMultiByte failed for configW->lpDescription\n");
1603 ret = FALSE;
1604 configA->lpDescription = NULL;
1607 else configA->lpDescription = NULL;
1609 break;
1610 case SERVICE_CONFIG_PRESHUTDOWN_INFO:
1611 if (buffer && bufferW && *needed<=size)
1612 memcpy(buffer, bufferW, *needed);
1613 break;
1614 default:
1615 FIXME("conversation W->A not implemented for level %d\n", dwLevel);
1616 ret = FALSE;
1617 break;
1620 cleanup:
1621 heap_free( bufferW);
1622 return ret;
1625 /******************************************************************************
1626 * QueryServiceConfig2W [ADVAPI32.@]
1628 * See QueryServiceConfig2A.
1630 BOOL WINAPI QueryServiceConfig2W(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffer,
1631 DWORD size, LPDWORD needed)
1633 BYTE *bufptr;
1634 DWORD err;
1636 TRACE("%p %u %p %u %p\n", hService, dwLevel, buffer, size, needed);
1638 if (!buffer && size)
1640 SetLastError(ERROR_INVALID_ADDRESS);
1641 return FALSE;
1644 switch (dwLevel)
1646 case SERVICE_CONFIG_DESCRIPTION:
1647 if (!(bufptr = heap_alloc( size )))
1649 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1650 return FALSE;
1652 break;
1654 case SERVICE_CONFIG_PRESHUTDOWN_INFO:
1655 bufptr = buffer;
1656 break;
1658 default:
1659 FIXME("Level %d not implemented\n", dwLevel);
1660 SetLastError(ERROR_INVALID_LEVEL);
1661 return FALSE;
1664 if (!needed)
1666 if (dwLevel == SERVICE_CONFIG_DESCRIPTION) heap_free(bufptr);
1667 SetLastError(ERROR_INVALID_ADDRESS);
1668 return FALSE;
1671 __TRY
1673 err = svcctl_QueryServiceConfig2W(hService, dwLevel, bufptr, size, needed);
1675 __EXCEPT(rpc_filter)
1677 err = map_exception_code(GetExceptionCode());
1679 __ENDTRY
1681 switch (dwLevel)
1683 case SERVICE_CONFIG_DESCRIPTION:
1685 SERVICE_DESCRIPTIONW *desc = (SERVICE_DESCRIPTIONW *)buffer;
1686 struct service_description *s = (struct service_description *)bufptr;
1688 if (err != ERROR_SUCCESS && err != ERROR_INSUFFICIENT_BUFFER)
1690 heap_free( bufptr );
1691 SetLastError( err );
1692 return FALSE;
1695 /* adjust for potentially larger SERVICE_DESCRIPTIONW structure */
1696 if (*needed == sizeof(*s)) *needed = sizeof(*desc);
1697 else
1698 *needed = *needed - FIELD_OFFSET(struct service_description, description) + sizeof(*desc);
1700 if (size < *needed)
1702 heap_free( bufptr );
1703 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1704 return FALSE;
1706 if (desc)
1708 if (!s->size) desc->lpDescription = NULL;
1709 else
1711 desc->lpDescription = (WCHAR *)(desc + 1);
1712 memcpy( desc->lpDescription, s->description, s->size );
1715 heap_free( bufptr );
1716 break;
1718 case SERVICE_CONFIG_PRESHUTDOWN_INFO:
1719 if (err != ERROR_SUCCESS)
1721 SetLastError( err );
1722 return FALSE;
1724 break;
1726 default:
1727 break;
1730 return TRUE;
1733 /******************************************************************************
1734 * EnumServicesStatusA [ADVAPI32.@]
1736 BOOL WINAPI
1737 EnumServicesStatusA( SC_HANDLE hmngr, DWORD type, DWORD state, LPENUM_SERVICE_STATUSA
1738 services, DWORD size, LPDWORD needed, LPDWORD returned,
1739 LPDWORD resume_handle )
1741 BOOL ret;
1742 unsigned int i;
1743 ENUM_SERVICE_STATUSW *servicesW = NULL;
1744 DWORD sz, n;
1745 char *p;
1747 TRACE("%p 0x%x 0x%x %p %u %p %p %p\n", hmngr, type, state, services, size, needed,
1748 returned, resume_handle);
1750 if (!hmngr)
1752 SetLastError( ERROR_INVALID_HANDLE );
1753 return FALSE;
1755 if (!needed || !returned)
1757 SetLastError( ERROR_INVALID_ADDRESS );
1758 return FALSE;
1761 sz = max( 2 * size, sizeof(*servicesW) );
1762 if (!(servicesW = heap_alloc( sz )))
1764 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1765 return FALSE;
1768 ret = EnumServicesStatusW( hmngr, type, state, servicesW, sz, needed, returned, resume_handle );
1769 if (!ret) goto done;
1771 p = (char *)services + *returned * sizeof(ENUM_SERVICE_STATUSA);
1772 n = size - (p - (char *)services);
1773 ret = FALSE;
1774 for (i = 0; i < *returned; i++)
1776 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpServiceName, -1, p, n, NULL, NULL );
1777 if (!sz) goto done;
1778 services[i].lpServiceName = p;
1779 p += sz;
1780 n -= sz;
1781 if (servicesW[i].lpDisplayName)
1783 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpDisplayName, -1, p, n, NULL, NULL );
1784 if (!sz) goto done;
1785 services[i].lpDisplayName = p;
1786 p += sz;
1787 n -= sz;
1789 else services[i].lpDisplayName = NULL;
1790 services[i].ServiceStatus = servicesW[i].ServiceStatus;
1793 ret = TRUE;
1795 done:
1796 heap_free( servicesW );
1797 return ret;
1800 /******************************************************************************
1801 * EnumServicesStatusW [ADVAPI32.@]
1803 BOOL WINAPI
1804 EnumServicesStatusW( SC_HANDLE hmngr, DWORD type, DWORD state, LPENUM_SERVICE_STATUSW
1805 services, DWORD size, LPDWORD needed, LPDWORD returned,
1806 LPDWORD resume_handle )
1808 DWORD err, i, offset, buflen, count, total_size = 0;
1809 struct enum_service_status *entry;
1810 const WCHAR *str;
1811 BYTE *buf;
1813 TRACE("%p 0x%x 0x%x %p %u %p %p %p\n", hmngr, type, state, services, size, needed,
1814 returned, resume_handle);
1816 if (!hmngr)
1818 SetLastError( ERROR_INVALID_HANDLE );
1819 return FALSE;
1821 if (!needed || !returned)
1823 SetLastError( ERROR_INVALID_ADDRESS );
1824 return FALSE;
1827 /* make sure we pass a valid pointer */
1828 buflen = max( size, sizeof(*services) );
1829 if (!(buf = heap_alloc( buflen )))
1831 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1832 return FALSE;
1835 __TRY
1837 err = svcctl_EnumServicesStatusW( hmngr, type, state, buf, buflen, needed, &count, resume_handle );
1839 __EXCEPT(rpc_filter)
1841 err = map_exception_code( GetExceptionCode() );
1843 __ENDTRY
1845 *returned = 0;
1846 if (err != ERROR_SUCCESS)
1848 /* double the needed size to fit the potentially larger ENUM_SERVICE_STATUSW */
1849 if (err == ERROR_MORE_DATA) *needed *= 2;
1850 heap_free( buf );
1851 SetLastError( err );
1852 return FALSE;
1855 entry = (struct enum_service_status *)buf;
1856 for (i = 0; i < count; i++)
1858 total_size += sizeof(*services);
1859 if (entry->service_name)
1861 str = (const WCHAR *)(buf + entry->service_name);
1862 total_size += (strlenW( str ) + 1) * sizeof(WCHAR);
1864 if (entry->display_name)
1866 str = (const WCHAR *)(buf + entry->display_name);
1867 total_size += (strlenW( str ) + 1) * sizeof(WCHAR);
1869 entry++;
1872 if (total_size > size)
1874 heap_free( buf );
1875 *needed = total_size;
1876 SetLastError( ERROR_MORE_DATA );
1877 return FALSE;
1880 offset = count * sizeof(*services);
1881 entry = (struct enum_service_status *)buf;
1882 for (i = 0; i < count; i++)
1884 DWORD str_size;
1885 str = (const WCHAR *)(buf + entry->service_name);
1886 str_size = (strlenW( str ) + 1) * sizeof(WCHAR);
1887 services[i].lpServiceName = (WCHAR *)((char *)services + offset);
1888 memcpy( services[i].lpServiceName, str, str_size );
1889 offset += str_size;
1891 if (!entry->display_name) services[i].lpDisplayName = NULL;
1892 else
1894 str = (const WCHAR *)(buf + entry->display_name);
1895 str_size = (strlenW( str ) + 1) * sizeof(WCHAR);
1896 services[i].lpDisplayName = (WCHAR *)((char *)services + offset);
1897 memcpy( services[i].lpDisplayName, str, str_size );
1898 offset += str_size;
1900 services[i].ServiceStatus = entry->service_status;
1901 entry++;
1904 heap_free( buf );
1905 *needed = 0;
1906 *returned = count;
1907 return TRUE;
1910 /******************************************************************************
1911 * EnumServicesStatusExA [ADVAPI32.@]
1913 BOOL WINAPI
1914 EnumServicesStatusExA( SC_HANDLE hmngr, SC_ENUM_TYPE level, DWORD type, DWORD state,
1915 LPBYTE buffer, DWORD size, LPDWORD needed, LPDWORD returned,
1916 LPDWORD resume_handle, LPCSTR group )
1918 BOOL ret;
1919 unsigned int i;
1920 ENUM_SERVICE_STATUS_PROCESSA *services = (ENUM_SERVICE_STATUS_PROCESSA *)buffer;
1921 ENUM_SERVICE_STATUS_PROCESSW *servicesW = NULL;
1922 WCHAR *groupW = NULL;
1923 DWORD sz, n;
1924 char *p;
1926 TRACE("%p %u 0x%x 0x%x %p %u %p %p %p %s\n", hmngr, level, type, state, buffer,
1927 size, needed, returned, resume_handle, debugstr_a(group));
1929 sz = max( 2 * size, sizeof(*servicesW) );
1930 if (!(servicesW = heap_alloc( sz )))
1932 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1933 return FALSE;
1935 if (group)
1937 int len = MultiByteToWideChar( CP_ACP, 0, group, -1, NULL, 0 );
1938 if (!(groupW = heap_alloc( len * sizeof(WCHAR) )))
1940 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1941 heap_free( servicesW );
1942 return FALSE;
1944 MultiByteToWideChar( CP_ACP, 0, group, -1, groupW, len * sizeof(WCHAR) );
1947 ret = EnumServicesStatusExW( hmngr, level, type, state, (BYTE *)servicesW, sz,
1948 needed, returned, resume_handle, groupW );
1949 if (!ret) goto done;
1951 p = (char *)services + *returned * sizeof(ENUM_SERVICE_STATUS_PROCESSA);
1952 n = size - (p - (char *)services);
1953 ret = FALSE;
1954 for (i = 0; i < *returned; i++)
1956 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpServiceName, -1, p, n, NULL, NULL );
1957 if (!sz) goto done;
1958 services[i].lpServiceName = p;
1959 p += sz;
1960 n -= sz;
1961 if (servicesW[i].lpDisplayName)
1963 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpDisplayName, -1, p, n, NULL, NULL );
1964 if (!sz) goto done;
1965 services[i].lpDisplayName = p;
1966 p += sz;
1967 n -= sz;
1969 else services[i].lpDisplayName = NULL;
1970 services[i].ServiceStatusProcess = servicesW[i].ServiceStatusProcess;
1973 ret = TRUE;
1975 done:
1976 heap_free( servicesW );
1977 heap_free( groupW );
1978 return ret;
1981 /******************************************************************************
1982 * EnumServicesStatusExW [ADVAPI32.@]
1984 BOOL WINAPI
1985 EnumServicesStatusExW( SC_HANDLE hmngr, SC_ENUM_TYPE level, DWORD type, DWORD state,
1986 LPBYTE buffer, DWORD size, LPDWORD needed, LPDWORD returned,
1987 LPDWORD resume_handle, LPCWSTR group )
1989 DWORD err, i, offset, buflen, count, total_size = 0;
1990 ENUM_SERVICE_STATUS_PROCESSW *services = (ENUM_SERVICE_STATUS_PROCESSW *)buffer;
1991 struct enum_service_status_process *entry;
1992 const WCHAR *str;
1993 BYTE *buf;
1995 TRACE("%p %u 0x%x 0x%x %p %u %p %p %p %s\n", hmngr, level, type, state, buffer,
1996 size, needed, returned, resume_handle, debugstr_w(group));
1998 if (level != SC_ENUM_PROCESS_INFO)
2000 SetLastError( ERROR_INVALID_LEVEL );
2001 return FALSE;
2003 if (!hmngr)
2005 SetLastError( ERROR_INVALID_HANDLE );
2006 return FALSE;
2008 if (!needed || !returned)
2010 SetLastError( ERROR_INVALID_ADDRESS );
2011 return FALSE;
2014 /* make sure we pass a valid pointer */
2015 buflen = max( size, sizeof(*services) );
2016 if (!(buf = heap_alloc( buflen )))
2018 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
2019 return FALSE;
2022 __TRY
2024 err = svcctl_EnumServicesStatusExW( hmngr, SC_ENUM_PROCESS_INFO, type, state, buf, buflen, needed,
2025 &count, resume_handle, group );
2027 __EXCEPT(rpc_filter)
2029 err = map_exception_code( GetExceptionCode() );
2031 __ENDTRY
2033 *returned = 0;
2034 if (err != ERROR_SUCCESS)
2036 /* double the needed size to fit the potentially larger ENUM_SERVICE_STATUS_PROCESSW */
2037 if (err == ERROR_MORE_DATA) *needed *= 2;
2038 heap_free( buf );
2039 SetLastError( err );
2040 return FALSE;
2043 entry = (struct enum_service_status_process *)buf;
2044 for (i = 0; i < count; i++)
2046 total_size += sizeof(*services);
2047 if (entry->service_name)
2049 str = (const WCHAR *)(buf + entry->service_name);
2050 total_size += (strlenW( str ) + 1) * sizeof(WCHAR);
2052 if (entry->display_name)
2054 str = (const WCHAR *)(buf + entry->display_name);
2055 total_size += (strlenW( str ) + 1) * sizeof(WCHAR);
2057 entry++;
2060 if (total_size > size)
2062 heap_free( buf );
2063 *needed = total_size;
2064 SetLastError( ERROR_MORE_DATA );
2065 return FALSE;
2068 offset = count * sizeof(*services);
2069 entry = (struct enum_service_status_process *)buf;
2070 for (i = 0; i < count; i++)
2072 DWORD str_size;
2073 str = (const WCHAR *)(buf + entry->service_name);
2074 str_size = (strlenW( str ) + 1) * sizeof(WCHAR);
2075 services[i].lpServiceName = (WCHAR *)((char *)services + offset);
2076 memcpy( services[i].lpServiceName, str, str_size );
2077 offset += str_size;
2079 if (!entry->display_name) services[i].lpDisplayName = NULL;
2080 else
2082 str = (const WCHAR *)(buf + entry->display_name);
2083 str_size = (strlenW( str ) + 1) * sizeof(WCHAR);
2084 services[i].lpDisplayName = (WCHAR *)((char *)services + offset);
2085 memcpy( services[i].lpDisplayName, str, str_size );
2086 offset += str_size;
2088 services[i].ServiceStatusProcess = entry->service_status_process;
2089 entry++;
2092 heap_free( buf );
2093 *needed = 0;
2094 *returned = count;
2095 return TRUE;
2098 /******************************************************************************
2099 * GetServiceKeyNameA [ADVAPI32.@]
2101 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
2102 LPSTR lpServiceName, LPDWORD lpcchBuffer )
2104 LPWSTR lpDisplayNameW, lpServiceNameW;
2105 DWORD sizeW;
2106 BOOL ret = FALSE;
2108 TRACE("%p %s %p %p\n", hSCManager,
2109 debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
2111 lpDisplayNameW = SERV_dup(lpDisplayName);
2112 if (lpServiceName)
2113 lpServiceNameW = heap_alloc(*lpcchBuffer * sizeof(WCHAR));
2114 else
2115 lpServiceNameW = NULL;
2117 sizeW = *lpcchBuffer;
2118 if (!GetServiceKeyNameW(hSCManager, lpDisplayNameW, lpServiceNameW, &sizeW))
2120 if (lpServiceName && *lpcchBuffer)
2121 lpServiceName[0] = 0;
2122 *lpcchBuffer = sizeW*2; /* we can only provide an upper estimation of string length */
2123 goto cleanup;
2126 if (!WideCharToMultiByte(CP_ACP, 0, lpServiceNameW, (sizeW + 1), lpServiceName,
2127 *lpcchBuffer, NULL, NULL ))
2129 if (*lpcchBuffer && lpServiceName)
2130 lpServiceName[0] = 0;
2131 *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpServiceNameW, -1, NULL, 0, NULL, NULL);
2132 goto cleanup;
2135 /* lpcchBuffer not updated - same as in GetServiceDisplayNameA */
2136 ret = TRUE;
2138 cleanup:
2139 heap_free(lpServiceNameW);
2140 heap_free(lpDisplayNameW);
2141 return ret;
2144 /******************************************************************************
2145 * GetServiceKeyNameW [ADVAPI32.@]
2147 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
2148 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
2150 DWORD err;
2151 WCHAR buffer[2];
2152 DWORD size;
2154 TRACE("%p %s %p %p\n", hSCManager,
2155 debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
2157 if (!hSCManager)
2159 SetLastError( ERROR_INVALID_HANDLE );
2160 return FALSE;
2163 /* provide a buffer if the caller didn't */
2164 if (!lpServiceName || *lpcchBuffer < 2)
2166 lpServiceName = buffer;
2167 /* A size of 1 would be enough, but tests show that Windows returns 2,
2168 * probably because of a WCHAR/bytes mismatch in their code.
2170 *lpcchBuffer = 2;
2173 /* RPC call takes size excluding nul-terminator, whereas *lpcchBuffer
2174 * includes the nul-terminator on input. */
2175 size = *lpcchBuffer - 1;
2177 __TRY
2179 err = svcctl_GetServiceKeyNameW(hSCManager, lpDisplayName, lpServiceName,
2180 &size);
2182 __EXCEPT(rpc_filter)
2184 err = map_exception_code(GetExceptionCode());
2186 __ENDTRY
2188 /* The value of *lpcchBuffer excludes nul-terminator on output. */
2189 if (err == ERROR_SUCCESS || err == ERROR_INSUFFICIENT_BUFFER)
2190 *lpcchBuffer = size;
2192 if (err)
2193 SetLastError(err);
2194 return err == ERROR_SUCCESS;
2197 /******************************************************************************
2198 * QueryServiceLockStatusA [ADVAPI32.@]
2200 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
2201 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
2202 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2204 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2206 return FALSE;
2209 /******************************************************************************
2210 * QueryServiceLockStatusW [ADVAPI32.@]
2212 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
2213 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2214 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2216 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2218 return FALSE;
2221 /******************************************************************************
2222 * GetServiceDisplayNameA [ADVAPI32.@]
2224 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
2225 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
2227 LPWSTR lpServiceNameW, lpDisplayNameW;
2228 DWORD sizeW;
2229 BOOL ret = FALSE;
2231 TRACE("%p %s %p %p\n", hSCManager,
2232 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
2234 lpServiceNameW = SERV_dup(lpServiceName);
2235 if (lpDisplayName)
2236 lpDisplayNameW = heap_alloc(*lpcchBuffer * sizeof(WCHAR));
2237 else
2238 lpDisplayNameW = NULL;
2240 sizeW = *lpcchBuffer;
2241 if (!GetServiceDisplayNameW(hSCManager, lpServiceNameW, lpDisplayNameW, &sizeW))
2243 if (lpDisplayName && *lpcchBuffer)
2244 lpDisplayName[0] = 0;
2245 *lpcchBuffer = sizeW*2; /* we can only provide an upper estimation of string length */
2246 goto cleanup;
2249 if (!WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, (sizeW + 1), lpDisplayName,
2250 *lpcchBuffer, NULL, NULL ))
2252 if (*lpcchBuffer && lpDisplayName)
2253 lpDisplayName[0] = 0;
2254 *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, -1, NULL, 0, NULL, NULL);
2255 goto cleanup;
2258 /* probably due to a bug GetServiceDisplayNameA doesn't modify lpcchBuffer on success.
2259 * (but if the function succeeded it means that is a good upper estimation of the size) */
2260 ret = TRUE;
2262 cleanup:
2263 heap_free(lpDisplayNameW);
2264 heap_free(lpServiceNameW);
2265 return ret;
2268 /******************************************************************************
2269 * GetServiceDisplayNameW [ADVAPI32.@]
2271 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
2272 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
2274 DWORD err;
2275 DWORD size;
2276 WCHAR buffer[2];
2278 TRACE("%p %s %p %p\n", hSCManager,
2279 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
2281 if (!hSCManager)
2283 SetLastError( ERROR_INVALID_HANDLE );
2284 return FALSE;
2287 /* provide a buffer if the caller didn't */
2288 if (!lpDisplayName || *lpcchBuffer < 2)
2290 lpDisplayName = buffer;
2291 /* A size of 1 would be enough, but tests show that Windows returns 2,
2292 * probably because of a WCHAR/bytes mismatch in their code.
2294 *lpcchBuffer = 2;
2297 /* RPC call takes size excluding nul-terminator, whereas *lpcchBuffer
2298 * includes the nul-terminator on input. */
2299 size = *lpcchBuffer - 1;
2301 __TRY
2303 err = svcctl_GetServiceDisplayNameW(hSCManager, lpServiceName, lpDisplayName,
2304 &size);
2306 __EXCEPT(rpc_filter)
2308 err = map_exception_code(GetExceptionCode());
2310 __ENDTRY
2312 /* The value of *lpcchBuffer excludes nul-terminator on output. */
2313 if (err == ERROR_SUCCESS || err == ERROR_INSUFFICIENT_BUFFER)
2314 *lpcchBuffer = size;
2316 if (err)
2317 SetLastError(err);
2318 return err == ERROR_SUCCESS;
2321 /******************************************************************************
2322 * ChangeServiceConfigW [ADVAPI32.@]
2324 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
2325 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
2326 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
2327 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
2329 DWORD cb_pwd;
2330 DWORD err;
2332 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2333 hService, dwServiceType, dwStartType, dwErrorControl,
2334 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2335 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2336 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2338 cb_pwd = lpPassword ? (strlenW(lpPassword) + 1)*sizeof(WCHAR) : 0;
2340 __TRY
2342 err = svcctl_ChangeServiceConfigW(hService, dwServiceType,
2343 dwStartType, dwErrorControl, lpBinaryPathName, lpLoadOrderGroup, lpdwTagId,
2344 (const BYTE *)lpDependencies, multisz_cb(lpDependencies), lpServiceStartName,
2345 (const BYTE *)lpPassword, cb_pwd, lpDisplayName);
2347 __EXCEPT(rpc_filter)
2349 err = map_exception_code(GetExceptionCode());
2351 __ENDTRY
2353 if (err != ERROR_SUCCESS)
2354 SetLastError(err);
2356 return err == ERROR_SUCCESS;
2359 /******************************************************************************
2360 * ChangeServiceConfigA [ADVAPI32.@]
2362 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2363 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2364 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2365 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2367 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2368 LPWSTR wServiceStartName, wPassword, wDisplayName;
2369 BOOL r;
2371 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2372 hService, dwServiceType, dwStartType, dwErrorControl,
2373 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2374 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2375 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2377 wBinaryPathName = SERV_dup( lpBinaryPathName );
2378 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2379 wDependencies = SERV_dupmulti( lpDependencies );
2380 wServiceStartName = SERV_dup( lpServiceStartName );
2381 wPassword = SERV_dup( lpPassword );
2382 wDisplayName = SERV_dup( lpDisplayName );
2384 r = ChangeServiceConfigW( hService, dwServiceType,
2385 dwStartType, dwErrorControl, wBinaryPathName,
2386 wLoadOrderGroup, lpdwTagId, wDependencies,
2387 wServiceStartName, wPassword, wDisplayName);
2389 heap_free( wBinaryPathName );
2390 heap_free( wLoadOrderGroup );
2391 heap_free( wDependencies );
2392 heap_free( wServiceStartName );
2393 heap_free( wPassword );
2394 heap_free( wDisplayName );
2396 return r;
2399 /******************************************************************************
2400 * ChangeServiceConfig2A [ADVAPI32.@]
2402 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2403 LPVOID lpInfo)
2405 BOOL r = FALSE;
2407 TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo);
2409 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2411 LPSERVICE_DESCRIPTIONA sd = lpInfo;
2412 SERVICE_DESCRIPTIONW sdw;
2414 sdw.lpDescription = SERV_dup( sd->lpDescription );
2416 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2418 heap_free( sdw.lpDescription );
2420 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2422 LPSERVICE_FAILURE_ACTIONSA fa = lpInfo;
2423 SERVICE_FAILURE_ACTIONSW faw;
2425 faw.dwResetPeriod = fa->dwResetPeriod;
2426 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2427 faw.lpCommand = SERV_dup( fa->lpCommand );
2428 faw.cActions = fa->cActions;
2429 faw.lpsaActions = fa->lpsaActions;
2431 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2433 heap_free( faw.lpRebootMsg );
2434 heap_free( faw.lpCommand );
2436 else if (dwInfoLevel == SERVICE_CONFIG_PRESHUTDOWN_INFO)
2438 r = ChangeServiceConfig2W( hService, dwInfoLevel, lpInfo);
2440 else
2441 SetLastError( ERROR_INVALID_PARAMETER );
2443 return r;
2446 /******************************************************************************
2447 * ChangeServiceConfig2W [ADVAPI32.@]
2449 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2450 LPVOID lpInfo)
2452 SERVICE_RPC_REQUIRED_PRIVILEGES_INFO rpc_privinfo;
2453 DWORD err;
2455 __TRY
2457 SC_RPC_CONFIG_INFOW info;
2459 info.dwInfoLevel = dwInfoLevel;
2460 if (dwInfoLevel == SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO)
2462 SERVICE_REQUIRED_PRIVILEGES_INFOW *privinfo = lpInfo;
2463 WCHAR *p;
2465 for (p = privinfo->pmszRequiredPrivileges; *p; p += strlenW(p) + 1);
2466 rpc_privinfo.cbRequiredPrivileges =
2467 (p - privinfo->pmszRequiredPrivileges + 1) * sizeof(WCHAR);
2468 rpc_privinfo.pRequiredPrivileges = (BYTE *)privinfo->pmszRequiredPrivileges;
2469 info.u.privinfo = &rpc_privinfo;
2471 else
2472 info.u.descr = lpInfo;
2473 err = svcctl_ChangeServiceConfig2W( hService, info );
2475 __EXCEPT(rpc_filter)
2477 err = map_exception_code(GetExceptionCode());
2479 __ENDTRY
2481 if (err != ERROR_SUCCESS)
2482 SetLastError(err);
2484 return err == ERROR_SUCCESS;
2487 NTSTATUS SERV_QueryServiceObjectSecurity(SC_HANDLE hService,
2488 SECURITY_INFORMATION dwSecurityInformation,
2489 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2490 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2492 SECURITY_DESCRIPTOR descriptor;
2493 NTSTATUS status;
2494 DWORD size;
2495 ACL acl;
2497 FIXME("%p %d %p %u %p - semi-stub\n", hService, dwSecurityInformation,
2498 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2500 if (dwSecurityInformation != DACL_SECURITY_INFORMATION)
2501 FIXME("information %d not supported\n", dwSecurityInformation);
2503 InitializeSecurityDescriptor(&descriptor, SECURITY_DESCRIPTOR_REVISION);
2505 InitializeAcl(&acl, sizeof(ACL), ACL_REVISION);
2506 SetSecurityDescriptorDacl(&descriptor, TRUE, &acl, TRUE);
2508 size = cbBufSize;
2509 status = RtlMakeSelfRelativeSD(&descriptor, lpSecurityDescriptor, &size);
2510 *pcbBytesNeeded = size;
2511 return status;
2514 /******************************************************************************
2515 * QueryServiceObjectSecurity [ADVAPI32.@]
2517 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2518 SECURITY_INFORMATION dwSecurityInformation,
2519 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2520 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2522 NTSTATUS status = SERV_QueryServiceObjectSecurity(hService, dwSecurityInformation, lpSecurityDescriptor,
2523 cbBufSize, pcbBytesNeeded);
2524 if (status != STATUS_SUCCESS)
2526 SetLastError(RtlNtStatusToDosError(status));
2527 return FALSE;
2529 return TRUE;
2532 /******************************************************************************
2533 * SetServiceObjectSecurity [ADVAPI32.@]
2535 * NOTES
2536 * - SetSecurityInfo should be updated to call this function once it's implemented.
2538 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2539 SECURITY_INFORMATION dwSecurityInformation,
2540 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2542 FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2543 return TRUE;
2546 /******************************************************************************
2547 * SetServiceBits [ADVAPI32.@]
2549 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2550 DWORD dwServiceBits,
2551 BOOL bSetBitsOn,
2552 BOOL bUpdateImmediately)
2554 FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2555 bSetBitsOn, bUpdateImmediately);
2556 return TRUE;
2559 /* thunk for calling the RegisterServiceCtrlHandler handler function */
2560 static DWORD WINAPI ctrl_handler_thunk( DWORD control, DWORD type, void *data, void *context )
2562 LPHANDLER_FUNCTION func = context;
2564 func( control );
2565 return ERROR_SUCCESS;
2568 /******************************************************************************
2569 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
2571 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerA( LPCSTR name, LPHANDLER_FUNCTION handler )
2573 return RegisterServiceCtrlHandlerExA( name, ctrl_handler_thunk, handler );
2576 /******************************************************************************
2577 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
2579 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR name, LPHANDLER_FUNCTION handler )
2581 return RegisterServiceCtrlHandlerExW( name, ctrl_handler_thunk, handler );
2584 /******************************************************************************
2585 * RegisterServiceCtrlHandlerExA [ADVAPI32.@]
2587 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR name, LPHANDLER_FUNCTION_EX handler, LPVOID context )
2589 LPWSTR nameW;
2590 SERVICE_STATUS_HANDLE ret;
2592 nameW = SERV_dup(name);
2593 ret = RegisterServiceCtrlHandlerExW( nameW, handler, context );
2594 heap_free( nameW );
2595 return ret;
2598 /******************************************************************************
2599 * RegisterServiceCtrlHandlerExW [ADVAPI32.@]
2601 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2602 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2604 service_data *service;
2605 SC_HANDLE hService = 0;
2607 TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2609 EnterCriticalSection( &service_cs );
2610 if ((service = find_service_by_name( lpServiceName )))
2612 service->handler = lpHandlerProc;
2613 service->context = lpContext;
2614 hService = service->handle;
2616 LeaveCriticalSection( &service_cs );
2618 if (!hService) SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
2619 return (SERVICE_STATUS_HANDLE)hService;
2622 /******************************************************************************
2623 * EnumDependentServicesA [ADVAPI32.@]
2625 BOOL WINAPI EnumDependentServicesA( SC_HANDLE hService, DWORD dwServiceState,
2626 LPENUM_SERVICE_STATUSA lpServices, DWORD cbBufSize,
2627 LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
2629 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
2630 lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
2632 *lpServicesReturned = 0;
2633 return TRUE;
2636 /******************************************************************************
2637 * EnumDependentServicesW [ADVAPI32.@]
2639 BOOL WINAPI EnumDependentServicesW( SC_HANDLE hService, DWORD dwServiceState,
2640 LPENUM_SERVICE_STATUSW lpServices, DWORD cbBufSize,
2641 LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
2643 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
2644 lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
2646 *lpServicesReturned = 0;
2647 return TRUE;
2650 static DWORD WINAPI notify_thread(void *user)
2652 DWORD err;
2653 notify_data *data = user;
2654 SC_RPC_NOTIFY_PARAMS_LIST *list = NULL;
2655 SERVICE_NOTIFY_STATUS_CHANGE_PARAMS_2 *cparams;
2656 BOOL dummy;
2658 __TRY
2660 /* GetNotifyResults blocks until there is an event */
2661 err = svcctl_GetNotifyResults(data->notify_handle, &list);
2663 __EXCEPT(rpc_filter)
2665 err = map_exception_code(GetExceptionCode());
2667 __ENDTRY
2669 EnterCriticalSection( &service_cs );
2671 list_remove(&data->entry);
2673 LeaveCriticalSection( &service_cs );
2675 if (err == ERROR_SUCCESS && list)
2677 cparams = list->NotifyParamsArray[0].u.params;
2679 data->notify_buffer->dwNotificationStatus = cparams->dwNotificationStatus;
2680 memcpy(&data->notify_buffer->ServiceStatus, &cparams->ServiceStatus,
2681 sizeof(SERVICE_STATUS_PROCESS));
2682 data->notify_buffer->dwNotificationTriggered = cparams->dwNotificationTriggered;
2683 data->notify_buffer->pszServiceNames = NULL;
2685 QueueUserAPC((PAPCFUNC)data->notify_buffer->pfnNotifyCallback,
2686 data->calling_thread, (ULONG_PTR)data->notify_buffer);
2688 HeapFree(GetProcessHeap(), 0, list);
2690 else
2691 WARN("GetNotifyResults server call failed: %u\n", err);
2694 __TRY
2696 err = svcctl_CloseNotifyHandle(&data->notify_handle, &dummy);
2698 __EXCEPT(rpc_filter)
2700 err = map_exception_code(GetExceptionCode());
2702 __ENDTRY
2704 if (err != ERROR_SUCCESS)
2705 WARN("CloseNotifyHandle server call failed: %u\n", err);
2707 CloseHandle(data->calling_thread);
2708 HeapFree(GetProcessHeap(), 0, data);
2710 return 0;
2713 /******************************************************************************
2714 * NotifyServiceStatusChangeW [ADVAPI32.@]
2716 DWORD WINAPI NotifyServiceStatusChangeW(SC_HANDLE hService, DWORD dwNotifyMask,
2717 SERVICE_NOTIFYW *pNotifyBuffer)
2719 DWORD err;
2720 BOOL b_dummy = FALSE;
2721 GUID g_dummy = {0};
2722 notify_data *data;
2724 TRACE("%p 0x%x %p\n", hService, dwNotifyMask, pNotifyBuffer);
2726 data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data));
2727 if (!data)
2728 return ERROR_NOT_ENOUGH_MEMORY;
2730 data->service = hService;
2731 data->notify_buffer = pNotifyBuffer;
2732 if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
2733 GetCurrentProcess(), &data->calling_thread, 0, FALSE,
2734 DUPLICATE_SAME_ACCESS))
2736 ERR("DuplicateHandle failed: %u\n", GetLastError());
2737 HeapFree(GetProcessHeap(), 0, data);
2738 return ERROR_NOT_ENOUGH_MEMORY;
2741 data->params.dwInfoLevel = 2;
2742 data->params.u.params = &data->cparams;
2744 data->cparams.dwNotifyMask = dwNotifyMask;
2746 EnterCriticalSection( &service_cs );
2748 __TRY
2750 err = svcctl_NotifyServiceStatusChange(hService, data->params,
2751 &g_dummy, &g_dummy, &b_dummy, &data->notify_handle);
2753 __EXCEPT(rpc_filter)
2755 err = map_exception_code(GetExceptionCode());
2757 __ENDTRY
2759 if (err != ERROR_SUCCESS)
2761 WARN("NotifyServiceStatusChange server call failed: %u\n", err);
2762 LeaveCriticalSection( &service_cs );
2763 CloseHandle(data->calling_thread);
2764 CloseHandle(data->ready_evt);
2765 HeapFree(GetProcessHeap(), 0, data);
2766 return err;
2769 CloseHandle(CreateThread(NULL, 0, &notify_thread, data, 0, NULL));
2771 list_add_tail(&notify_list, &data->entry);
2773 LeaveCriticalSection( &service_cs );
2775 return ERROR_SUCCESS;