wbemprox: Tweak a comment.
[wine.git] / dlls / advapi32 / service.c
blob70907e1fe266dfdd525fbc4a2e54d03606feff87
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 = sizeof(format)/sizeof(WCHAR) + 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 SetLastError(ERROR_INVALID_ADDRESS);
1667 return FALSE;
1670 __TRY
1672 err = svcctl_QueryServiceConfig2W(hService, dwLevel, bufptr, size, needed);
1674 __EXCEPT(rpc_filter)
1676 err = map_exception_code(GetExceptionCode());
1678 __ENDTRY
1680 switch (dwLevel)
1682 case SERVICE_CONFIG_DESCRIPTION:
1684 SERVICE_DESCRIPTIONW *desc = (SERVICE_DESCRIPTIONW *)buffer;
1685 struct service_description *s = (struct service_description *)bufptr;
1687 if (err != ERROR_SUCCESS && err != ERROR_INSUFFICIENT_BUFFER)
1689 heap_free( bufptr );
1690 SetLastError( err );
1691 return FALSE;
1694 /* adjust for potentially larger SERVICE_DESCRIPTIONW structure */
1695 if (*needed == sizeof(*s)) *needed = sizeof(*desc);
1696 else
1697 *needed = *needed - FIELD_OFFSET(struct service_description, description) + sizeof(*desc);
1699 if (size < *needed)
1701 heap_free( bufptr );
1702 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1703 return FALSE;
1705 if (desc)
1707 if (!s->size) desc->lpDescription = NULL;
1708 else
1710 desc->lpDescription = (WCHAR *)(desc + 1);
1711 memcpy( desc->lpDescription, s->description, s->size );
1714 heap_free( bufptr );
1715 break;
1717 case SERVICE_CONFIG_PRESHUTDOWN_INFO:
1718 if (err != ERROR_SUCCESS)
1720 SetLastError( err );
1721 return FALSE;
1723 break;
1725 default:
1726 break;
1729 return TRUE;
1732 /******************************************************************************
1733 * EnumServicesStatusA [ADVAPI32.@]
1735 BOOL WINAPI
1736 EnumServicesStatusA( SC_HANDLE hmngr, DWORD type, DWORD state, LPENUM_SERVICE_STATUSA
1737 services, DWORD size, LPDWORD needed, LPDWORD returned,
1738 LPDWORD resume_handle )
1740 BOOL ret;
1741 unsigned int i;
1742 ENUM_SERVICE_STATUSW *servicesW = NULL;
1743 DWORD sz, n;
1744 char *p;
1746 TRACE("%p 0x%x 0x%x %p %u %p %p %p\n", hmngr, type, state, services, size, needed,
1747 returned, resume_handle);
1749 if (!hmngr)
1751 SetLastError( ERROR_INVALID_HANDLE );
1752 return FALSE;
1754 if (!needed || !returned)
1756 SetLastError( ERROR_INVALID_ADDRESS );
1757 return FALSE;
1760 sz = max( 2 * size, sizeof(*servicesW) );
1761 if (!(servicesW = heap_alloc( sz )))
1763 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1764 return FALSE;
1767 ret = EnumServicesStatusW( hmngr, type, state, servicesW, sz, needed, returned, resume_handle );
1768 if (!ret) goto done;
1770 p = (char *)services + *returned * sizeof(ENUM_SERVICE_STATUSA);
1771 n = size - (p - (char *)services);
1772 ret = FALSE;
1773 for (i = 0; i < *returned; i++)
1775 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpServiceName, -1, p, n, NULL, NULL );
1776 if (!sz) goto done;
1777 services[i].lpServiceName = p;
1778 p += sz;
1779 n -= sz;
1780 if (servicesW[i].lpDisplayName)
1782 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpDisplayName, -1, p, n, NULL, NULL );
1783 if (!sz) goto done;
1784 services[i].lpDisplayName = p;
1785 p += sz;
1786 n -= sz;
1788 else services[i].lpDisplayName = NULL;
1789 services[i].ServiceStatus = servicesW[i].ServiceStatus;
1792 ret = TRUE;
1794 done:
1795 heap_free( servicesW );
1796 return ret;
1799 /******************************************************************************
1800 * EnumServicesStatusW [ADVAPI32.@]
1802 BOOL WINAPI
1803 EnumServicesStatusW( SC_HANDLE hmngr, DWORD type, DWORD state, LPENUM_SERVICE_STATUSW
1804 services, DWORD size, LPDWORD needed, LPDWORD returned,
1805 LPDWORD resume_handle )
1807 DWORD err, i, offset, buflen, count, total_size = 0;
1808 struct enum_service_status *entry;
1809 const WCHAR *str;
1810 BYTE *buf;
1812 TRACE("%p 0x%x 0x%x %p %u %p %p %p\n", hmngr, type, state, services, size, needed,
1813 returned, resume_handle);
1815 if (!hmngr)
1817 SetLastError( ERROR_INVALID_HANDLE );
1818 return FALSE;
1820 if (!needed || !returned)
1822 SetLastError( ERROR_INVALID_ADDRESS );
1823 return FALSE;
1826 /* make sure we pass a valid pointer */
1827 buflen = max( size, sizeof(*services) );
1828 if (!(buf = heap_alloc( buflen )))
1830 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1831 return FALSE;
1834 __TRY
1836 err = svcctl_EnumServicesStatusW( hmngr, type, state, buf, buflen, needed, &count, resume_handle );
1838 __EXCEPT(rpc_filter)
1840 err = map_exception_code( GetExceptionCode() );
1842 __ENDTRY
1844 *returned = 0;
1845 if (err != ERROR_SUCCESS)
1847 /* double the needed size to fit the potentially larger ENUM_SERVICE_STATUSW */
1848 if (err == ERROR_MORE_DATA) *needed *= 2;
1849 heap_free( buf );
1850 SetLastError( err );
1851 return FALSE;
1854 entry = (struct enum_service_status *)buf;
1855 for (i = 0; i < count; i++)
1857 total_size += sizeof(*services);
1858 if (entry->service_name)
1860 str = (const WCHAR *)(buf + entry->service_name);
1861 total_size += (strlenW( str ) + 1) * sizeof(WCHAR);
1863 if (entry->display_name)
1865 str = (const WCHAR *)(buf + entry->display_name);
1866 total_size += (strlenW( str ) + 1) * sizeof(WCHAR);
1868 entry++;
1871 if (total_size > size)
1873 heap_free( buf );
1874 *needed = total_size;
1875 SetLastError( ERROR_MORE_DATA );
1876 return FALSE;
1879 offset = count * sizeof(*services);
1880 entry = (struct enum_service_status *)buf;
1881 for (i = 0; i < count; i++)
1883 DWORD str_size;
1884 str = (const WCHAR *)(buf + entry->service_name);
1885 str_size = (strlenW( str ) + 1) * sizeof(WCHAR);
1886 services[i].lpServiceName = (WCHAR *)((char *)services + offset);
1887 memcpy( services[i].lpServiceName, str, str_size );
1888 offset += str_size;
1890 if (!entry->display_name) services[i].lpDisplayName = NULL;
1891 else
1893 str = (const WCHAR *)(buf + entry->display_name);
1894 str_size = (strlenW( str ) + 1) * sizeof(WCHAR);
1895 services[i].lpDisplayName = (WCHAR *)((char *)services + offset);
1896 memcpy( services[i].lpDisplayName, str, str_size );
1897 offset += str_size;
1899 services[i].ServiceStatus = entry->service_status;
1900 entry++;
1903 heap_free( buf );
1904 *needed = 0;
1905 *returned = count;
1906 return TRUE;
1909 /******************************************************************************
1910 * EnumServicesStatusExA [ADVAPI32.@]
1912 BOOL WINAPI
1913 EnumServicesStatusExA( SC_HANDLE hmngr, SC_ENUM_TYPE level, DWORD type, DWORD state,
1914 LPBYTE buffer, DWORD size, LPDWORD needed, LPDWORD returned,
1915 LPDWORD resume_handle, LPCSTR group )
1917 BOOL ret;
1918 unsigned int i;
1919 ENUM_SERVICE_STATUS_PROCESSA *services = (ENUM_SERVICE_STATUS_PROCESSA *)buffer;
1920 ENUM_SERVICE_STATUS_PROCESSW *servicesW = NULL;
1921 WCHAR *groupW = NULL;
1922 DWORD sz, n;
1923 char *p;
1925 TRACE("%p %u 0x%x 0x%x %p %u %p %p %p %s\n", hmngr, level, type, state, buffer,
1926 size, needed, returned, resume_handle, debugstr_a(group));
1928 sz = max( 2 * size, sizeof(*servicesW) );
1929 if (!(servicesW = heap_alloc( sz )))
1931 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1932 return FALSE;
1934 if (group)
1936 int len = MultiByteToWideChar( CP_ACP, 0, group, -1, NULL, 0 );
1937 if (!(groupW = heap_alloc( len * sizeof(WCHAR) )))
1939 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1940 heap_free( servicesW );
1941 return FALSE;
1943 MultiByteToWideChar( CP_ACP, 0, group, -1, groupW, len * sizeof(WCHAR) );
1946 ret = EnumServicesStatusExW( hmngr, level, type, state, (BYTE *)servicesW, sz,
1947 needed, returned, resume_handle, groupW );
1948 if (!ret) goto done;
1950 p = (char *)services + *returned * sizeof(ENUM_SERVICE_STATUS_PROCESSA);
1951 n = size - (p - (char *)services);
1952 ret = FALSE;
1953 for (i = 0; i < *returned; i++)
1955 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpServiceName, -1, p, n, NULL, NULL );
1956 if (!sz) goto done;
1957 services[i].lpServiceName = p;
1958 p += sz;
1959 n -= sz;
1960 if (servicesW[i].lpDisplayName)
1962 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpDisplayName, -1, p, n, NULL, NULL );
1963 if (!sz) goto done;
1964 services[i].lpDisplayName = p;
1965 p += sz;
1966 n -= sz;
1968 else services[i].lpDisplayName = NULL;
1969 services[i].ServiceStatusProcess = servicesW[i].ServiceStatusProcess;
1972 ret = TRUE;
1974 done:
1975 heap_free( servicesW );
1976 heap_free( groupW );
1977 return ret;
1980 /******************************************************************************
1981 * EnumServicesStatusExW [ADVAPI32.@]
1983 BOOL WINAPI
1984 EnumServicesStatusExW( SC_HANDLE hmngr, SC_ENUM_TYPE level, DWORD type, DWORD state,
1985 LPBYTE buffer, DWORD size, LPDWORD needed, LPDWORD returned,
1986 LPDWORD resume_handle, LPCWSTR group )
1988 DWORD err, i, offset, buflen, count, total_size = 0;
1989 ENUM_SERVICE_STATUS_PROCESSW *services = (ENUM_SERVICE_STATUS_PROCESSW *)buffer;
1990 struct enum_service_status_process *entry;
1991 const WCHAR *str;
1992 BYTE *buf;
1994 TRACE("%p %u 0x%x 0x%x %p %u %p %p %p %s\n", hmngr, level, type, state, buffer,
1995 size, needed, returned, resume_handle, debugstr_w(group));
1997 if (level != SC_ENUM_PROCESS_INFO)
1999 SetLastError( ERROR_INVALID_LEVEL );
2000 return FALSE;
2002 if (!hmngr)
2004 SetLastError( ERROR_INVALID_HANDLE );
2005 return FALSE;
2007 if (!needed || !returned)
2009 SetLastError( ERROR_INVALID_ADDRESS );
2010 return FALSE;
2013 /* make sure we pass a valid pointer */
2014 buflen = max( size, sizeof(*services) );
2015 if (!(buf = heap_alloc( buflen )))
2017 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
2018 return FALSE;
2021 __TRY
2023 err = svcctl_EnumServicesStatusExW( hmngr, SC_ENUM_PROCESS_INFO, type, state, buf, buflen, needed,
2024 &count, resume_handle, group );
2026 __EXCEPT(rpc_filter)
2028 err = map_exception_code( GetExceptionCode() );
2030 __ENDTRY
2032 *returned = 0;
2033 if (err != ERROR_SUCCESS)
2035 /* double the needed size to fit the potentially larger ENUM_SERVICE_STATUS_PROCESSW */
2036 if (err == ERROR_MORE_DATA) *needed *= 2;
2037 heap_free( buf );
2038 SetLastError( err );
2039 return FALSE;
2042 entry = (struct enum_service_status_process *)buf;
2043 for (i = 0; i < count; i++)
2045 total_size += sizeof(*services);
2046 if (entry->service_name)
2048 str = (const WCHAR *)(buf + entry->service_name);
2049 total_size += (strlenW( str ) + 1) * sizeof(WCHAR);
2051 if (entry->display_name)
2053 str = (const WCHAR *)(buf + entry->display_name);
2054 total_size += (strlenW( str ) + 1) * sizeof(WCHAR);
2056 entry++;
2059 if (total_size > size)
2061 heap_free( buf );
2062 *needed = total_size;
2063 SetLastError( ERROR_MORE_DATA );
2064 return FALSE;
2067 offset = count * sizeof(*services);
2068 entry = (struct enum_service_status_process *)buf;
2069 for (i = 0; i < count; i++)
2071 DWORD str_size;
2072 str = (const WCHAR *)(buf + entry->service_name);
2073 str_size = (strlenW( str ) + 1) * sizeof(WCHAR);
2074 services[i].lpServiceName = (WCHAR *)((char *)services + offset);
2075 memcpy( services[i].lpServiceName, str, str_size );
2076 offset += str_size;
2078 if (!entry->display_name) services[i].lpDisplayName = NULL;
2079 else
2081 str = (const WCHAR *)(buf + entry->display_name);
2082 str_size = (strlenW( str ) + 1) * sizeof(WCHAR);
2083 services[i].lpDisplayName = (WCHAR *)((char *)services + offset);
2084 memcpy( services[i].lpDisplayName, str, str_size );
2085 offset += str_size;
2087 services[i].ServiceStatusProcess = entry->service_status_process;
2088 entry++;
2091 heap_free( buf );
2092 *needed = 0;
2093 *returned = count;
2094 return TRUE;
2097 /******************************************************************************
2098 * GetServiceKeyNameA [ADVAPI32.@]
2100 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
2101 LPSTR lpServiceName, LPDWORD lpcchBuffer )
2103 LPWSTR lpDisplayNameW, lpServiceNameW;
2104 DWORD sizeW;
2105 BOOL ret = FALSE;
2107 TRACE("%p %s %p %p\n", hSCManager,
2108 debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
2110 lpDisplayNameW = SERV_dup(lpDisplayName);
2111 if (lpServiceName)
2112 lpServiceNameW = heap_alloc(*lpcchBuffer * sizeof(WCHAR));
2113 else
2114 lpServiceNameW = NULL;
2116 sizeW = *lpcchBuffer;
2117 if (!GetServiceKeyNameW(hSCManager, lpDisplayNameW, lpServiceNameW, &sizeW))
2119 if (lpServiceName && *lpcchBuffer)
2120 lpServiceName[0] = 0;
2121 *lpcchBuffer = sizeW*2; /* we can only provide an upper estimation of string length */
2122 goto cleanup;
2125 if (!WideCharToMultiByte(CP_ACP, 0, lpServiceNameW, (sizeW + 1), lpServiceName,
2126 *lpcchBuffer, NULL, NULL ))
2128 if (*lpcchBuffer && lpServiceName)
2129 lpServiceName[0] = 0;
2130 *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpServiceNameW, -1, NULL, 0, NULL, NULL);
2131 goto cleanup;
2134 /* lpcchBuffer not updated - same as in GetServiceDisplayNameA */
2135 ret = TRUE;
2137 cleanup:
2138 heap_free(lpServiceNameW);
2139 heap_free(lpDisplayNameW);
2140 return ret;
2143 /******************************************************************************
2144 * GetServiceKeyNameW [ADVAPI32.@]
2146 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
2147 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
2149 DWORD err;
2150 WCHAR buffer[2];
2151 DWORD size;
2153 TRACE("%p %s %p %p\n", hSCManager,
2154 debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
2156 if (!hSCManager)
2158 SetLastError( ERROR_INVALID_HANDLE );
2159 return FALSE;
2162 /* provide a buffer if the caller didn't */
2163 if (!lpServiceName || *lpcchBuffer < 2)
2165 lpServiceName = buffer;
2166 /* A size of 1 would be enough, but tests show that Windows returns 2,
2167 * probably because of a WCHAR/bytes mismatch in their code.
2169 *lpcchBuffer = 2;
2172 /* RPC call takes size excluding nul-terminator, whereas *lpcchBuffer
2173 * includes the nul-terminator on input. */
2174 size = *lpcchBuffer - 1;
2176 __TRY
2178 err = svcctl_GetServiceKeyNameW(hSCManager, lpDisplayName, lpServiceName,
2179 &size);
2181 __EXCEPT(rpc_filter)
2183 err = map_exception_code(GetExceptionCode());
2185 __ENDTRY
2187 /* The value of *lpcchBuffer excludes nul-terminator on output. */
2188 if (err == ERROR_SUCCESS || err == ERROR_INSUFFICIENT_BUFFER)
2189 *lpcchBuffer = size;
2191 if (err)
2192 SetLastError(err);
2193 return err == ERROR_SUCCESS;
2196 /******************************************************************************
2197 * QueryServiceLockStatusA [ADVAPI32.@]
2199 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
2200 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
2201 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2203 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2205 return FALSE;
2208 /******************************************************************************
2209 * QueryServiceLockStatusW [ADVAPI32.@]
2211 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
2212 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2213 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2215 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2217 return FALSE;
2220 /******************************************************************************
2221 * GetServiceDisplayNameA [ADVAPI32.@]
2223 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
2224 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
2226 LPWSTR lpServiceNameW, lpDisplayNameW;
2227 DWORD sizeW;
2228 BOOL ret = FALSE;
2230 TRACE("%p %s %p %p\n", hSCManager,
2231 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
2233 lpServiceNameW = SERV_dup(lpServiceName);
2234 if (lpDisplayName)
2235 lpDisplayNameW = heap_alloc(*lpcchBuffer * sizeof(WCHAR));
2236 else
2237 lpDisplayNameW = NULL;
2239 sizeW = *lpcchBuffer;
2240 if (!GetServiceDisplayNameW(hSCManager, lpServiceNameW, lpDisplayNameW, &sizeW))
2242 if (lpDisplayName && *lpcchBuffer)
2243 lpDisplayName[0] = 0;
2244 *lpcchBuffer = sizeW*2; /* we can only provide an upper estimation of string length */
2245 goto cleanup;
2248 if (!WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, (sizeW + 1), lpDisplayName,
2249 *lpcchBuffer, NULL, NULL ))
2251 if (*lpcchBuffer && lpDisplayName)
2252 lpDisplayName[0] = 0;
2253 *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, -1, NULL, 0, NULL, NULL);
2254 goto cleanup;
2257 /* probably due to a bug GetServiceDisplayNameA doesn't modify lpcchBuffer on success.
2258 * (but if the function succeeded it means that is a good upper estimation of the size) */
2259 ret = TRUE;
2261 cleanup:
2262 heap_free(lpDisplayNameW);
2263 heap_free(lpServiceNameW);
2264 return ret;
2267 /******************************************************************************
2268 * GetServiceDisplayNameW [ADVAPI32.@]
2270 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
2271 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
2273 DWORD err;
2274 DWORD size;
2275 WCHAR buffer[2];
2277 TRACE("%p %s %p %p\n", hSCManager,
2278 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
2280 if (!hSCManager)
2282 SetLastError( ERROR_INVALID_HANDLE );
2283 return FALSE;
2286 /* provide a buffer if the caller didn't */
2287 if (!lpDisplayName || *lpcchBuffer < 2)
2289 lpDisplayName = buffer;
2290 /* A size of 1 would be enough, but tests show that Windows returns 2,
2291 * probably because of a WCHAR/bytes mismatch in their code.
2293 *lpcchBuffer = 2;
2296 /* RPC call takes size excluding nul-terminator, whereas *lpcchBuffer
2297 * includes the nul-terminator on input. */
2298 size = *lpcchBuffer - 1;
2300 __TRY
2302 err = svcctl_GetServiceDisplayNameW(hSCManager, lpServiceName, lpDisplayName,
2303 &size);
2305 __EXCEPT(rpc_filter)
2307 err = map_exception_code(GetExceptionCode());
2309 __ENDTRY
2311 /* The value of *lpcchBuffer excludes nul-terminator on output. */
2312 if (err == ERROR_SUCCESS || err == ERROR_INSUFFICIENT_BUFFER)
2313 *lpcchBuffer = size;
2315 if (err)
2316 SetLastError(err);
2317 return err == ERROR_SUCCESS;
2320 /******************************************************************************
2321 * ChangeServiceConfigW [ADVAPI32.@]
2323 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
2324 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
2325 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
2326 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
2328 DWORD cb_pwd;
2329 DWORD err;
2331 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2332 hService, dwServiceType, dwStartType, dwErrorControl,
2333 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2334 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2335 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2337 cb_pwd = lpPassword ? (strlenW(lpPassword) + 1)*sizeof(WCHAR) : 0;
2339 __TRY
2341 err = svcctl_ChangeServiceConfigW(hService, dwServiceType,
2342 dwStartType, dwErrorControl, lpBinaryPathName, lpLoadOrderGroup, lpdwTagId,
2343 (const BYTE *)lpDependencies, multisz_cb(lpDependencies), lpServiceStartName,
2344 (const BYTE *)lpPassword, cb_pwd, lpDisplayName);
2346 __EXCEPT(rpc_filter)
2348 err = map_exception_code(GetExceptionCode());
2350 __ENDTRY
2352 if (err != ERROR_SUCCESS)
2353 SetLastError(err);
2355 return err == ERROR_SUCCESS;
2358 /******************************************************************************
2359 * ChangeServiceConfigA [ADVAPI32.@]
2361 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2362 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2363 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2364 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2366 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2367 LPWSTR wServiceStartName, wPassword, wDisplayName;
2368 BOOL r;
2370 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2371 hService, dwServiceType, dwStartType, dwErrorControl,
2372 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2373 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2374 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2376 wBinaryPathName = SERV_dup( lpBinaryPathName );
2377 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2378 wDependencies = SERV_dupmulti( lpDependencies );
2379 wServiceStartName = SERV_dup( lpServiceStartName );
2380 wPassword = SERV_dup( lpPassword );
2381 wDisplayName = SERV_dup( lpDisplayName );
2383 r = ChangeServiceConfigW( hService, dwServiceType,
2384 dwStartType, dwErrorControl, wBinaryPathName,
2385 wLoadOrderGroup, lpdwTagId, wDependencies,
2386 wServiceStartName, wPassword, wDisplayName);
2388 heap_free( wBinaryPathName );
2389 heap_free( wLoadOrderGroup );
2390 heap_free( wDependencies );
2391 heap_free( wServiceStartName );
2392 heap_free( wPassword );
2393 heap_free( wDisplayName );
2395 return r;
2398 /******************************************************************************
2399 * ChangeServiceConfig2A [ADVAPI32.@]
2401 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2402 LPVOID lpInfo)
2404 BOOL r = FALSE;
2406 TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo);
2408 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2410 LPSERVICE_DESCRIPTIONA sd = lpInfo;
2411 SERVICE_DESCRIPTIONW sdw;
2413 sdw.lpDescription = SERV_dup( sd->lpDescription );
2415 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2417 heap_free( sdw.lpDescription );
2419 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2421 LPSERVICE_FAILURE_ACTIONSA fa = lpInfo;
2422 SERVICE_FAILURE_ACTIONSW faw;
2424 faw.dwResetPeriod = fa->dwResetPeriod;
2425 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2426 faw.lpCommand = SERV_dup( fa->lpCommand );
2427 faw.cActions = fa->cActions;
2428 faw.lpsaActions = fa->lpsaActions;
2430 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2432 heap_free( faw.lpRebootMsg );
2433 heap_free( faw.lpCommand );
2435 else if (dwInfoLevel == SERVICE_CONFIG_PRESHUTDOWN_INFO)
2437 r = ChangeServiceConfig2W( hService, dwInfoLevel, lpInfo);
2439 else
2440 SetLastError( ERROR_INVALID_PARAMETER );
2442 return r;
2445 /******************************************************************************
2446 * ChangeServiceConfig2W [ADVAPI32.@]
2448 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2449 LPVOID lpInfo)
2451 DWORD err;
2453 __TRY
2455 SC_RPC_CONFIG_INFOW info;
2457 info.dwInfoLevel = dwInfoLevel;
2458 info.u.descr = lpInfo;
2459 err = svcctl_ChangeServiceConfig2W( hService, info );
2461 __EXCEPT(rpc_filter)
2463 err = map_exception_code(GetExceptionCode());
2465 __ENDTRY
2467 if (err != ERROR_SUCCESS)
2468 SetLastError(err);
2470 return err == ERROR_SUCCESS;
2473 NTSTATUS SERV_QueryServiceObjectSecurity(SC_HANDLE hService,
2474 SECURITY_INFORMATION dwSecurityInformation,
2475 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2476 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2478 SECURITY_DESCRIPTOR descriptor;
2479 NTSTATUS status;
2480 DWORD size;
2481 ACL acl;
2483 FIXME("%p %d %p %u %p - semi-stub\n", hService, dwSecurityInformation,
2484 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2486 if (dwSecurityInformation != DACL_SECURITY_INFORMATION)
2487 FIXME("information %d not supported\n", dwSecurityInformation);
2489 InitializeSecurityDescriptor(&descriptor, SECURITY_DESCRIPTOR_REVISION);
2491 InitializeAcl(&acl, sizeof(ACL), ACL_REVISION);
2492 SetSecurityDescriptorDacl(&descriptor, TRUE, &acl, TRUE);
2494 size = cbBufSize;
2495 status = RtlMakeSelfRelativeSD(&descriptor, lpSecurityDescriptor, &size);
2496 *pcbBytesNeeded = size;
2497 return status;
2500 /******************************************************************************
2501 * QueryServiceObjectSecurity [ADVAPI32.@]
2503 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2504 SECURITY_INFORMATION dwSecurityInformation,
2505 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2506 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2508 NTSTATUS status = SERV_QueryServiceObjectSecurity(hService, dwSecurityInformation, lpSecurityDescriptor,
2509 cbBufSize, pcbBytesNeeded);
2510 if (status != STATUS_SUCCESS)
2512 SetLastError(RtlNtStatusToDosError(status));
2513 return FALSE;
2515 return TRUE;
2518 /******************************************************************************
2519 * SetServiceObjectSecurity [ADVAPI32.@]
2521 * NOTES
2522 * - SetSecurityInfo should be updated to call this function once it's implemented.
2524 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2525 SECURITY_INFORMATION dwSecurityInformation,
2526 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2528 FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2529 return TRUE;
2532 /******************************************************************************
2533 * SetServiceBits [ADVAPI32.@]
2535 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2536 DWORD dwServiceBits,
2537 BOOL bSetBitsOn,
2538 BOOL bUpdateImmediately)
2540 FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2541 bSetBitsOn, bUpdateImmediately);
2542 return TRUE;
2545 /* thunk for calling the RegisterServiceCtrlHandler handler function */
2546 static DWORD WINAPI ctrl_handler_thunk( DWORD control, DWORD type, void *data, void *context )
2548 LPHANDLER_FUNCTION func = context;
2550 func( control );
2551 return ERROR_SUCCESS;
2554 /******************************************************************************
2555 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
2557 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerA( LPCSTR name, LPHANDLER_FUNCTION handler )
2559 return RegisterServiceCtrlHandlerExA( name, ctrl_handler_thunk, handler );
2562 /******************************************************************************
2563 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
2565 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR name, LPHANDLER_FUNCTION handler )
2567 return RegisterServiceCtrlHandlerExW( name, ctrl_handler_thunk, handler );
2570 /******************************************************************************
2571 * RegisterServiceCtrlHandlerExA [ADVAPI32.@]
2573 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR name, LPHANDLER_FUNCTION_EX handler, LPVOID context )
2575 LPWSTR nameW;
2576 SERVICE_STATUS_HANDLE ret;
2578 nameW = SERV_dup(name);
2579 ret = RegisterServiceCtrlHandlerExW( nameW, handler, context );
2580 heap_free( nameW );
2581 return ret;
2584 /******************************************************************************
2585 * RegisterServiceCtrlHandlerExW [ADVAPI32.@]
2587 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2588 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2590 service_data *service;
2591 SC_HANDLE hService = 0;
2593 TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2595 EnterCriticalSection( &service_cs );
2596 if ((service = find_service_by_name( lpServiceName )))
2598 service->handler = lpHandlerProc;
2599 service->context = lpContext;
2600 hService = service->handle;
2602 LeaveCriticalSection( &service_cs );
2604 if (!hService) SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
2605 return (SERVICE_STATUS_HANDLE)hService;
2608 /******************************************************************************
2609 * EnumDependentServicesA [ADVAPI32.@]
2611 BOOL WINAPI EnumDependentServicesA( SC_HANDLE hService, DWORD dwServiceState,
2612 LPENUM_SERVICE_STATUSA lpServices, DWORD cbBufSize,
2613 LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
2615 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
2616 lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
2618 *lpServicesReturned = 0;
2619 return TRUE;
2622 /******************************************************************************
2623 * EnumDependentServicesW [ADVAPI32.@]
2625 BOOL WINAPI EnumDependentServicesW( SC_HANDLE hService, DWORD dwServiceState,
2626 LPENUM_SERVICE_STATUSW 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 static DWORD WINAPI notify_thread(void *user)
2638 DWORD err;
2639 notify_data *data = user;
2640 SC_RPC_NOTIFY_PARAMS_LIST *list;
2641 SERVICE_NOTIFY_STATUS_CHANGE_PARAMS_2 *cparams;
2642 BOOL dummy;
2644 __TRY
2646 /* GetNotifyResults blocks until there is an event */
2647 err = svcctl_GetNotifyResults(data->notify_handle, &list);
2649 __EXCEPT(rpc_filter)
2651 err = map_exception_code(GetExceptionCode());
2653 __ENDTRY
2655 EnterCriticalSection( &service_cs );
2657 list_remove(&data->entry);
2659 LeaveCriticalSection( &service_cs );
2661 if (err == ERROR_SUCCESS && list)
2663 cparams = list->NotifyParamsArray[0].u.params;
2665 data->notify_buffer->dwNotificationStatus = cparams->dwNotificationStatus;
2666 memcpy(&data->notify_buffer->ServiceStatus, &cparams->ServiceStatus,
2667 sizeof(SERVICE_STATUS_PROCESS));
2668 data->notify_buffer->dwNotificationTriggered = cparams->dwNotificationTriggered;
2669 data->notify_buffer->pszServiceNames = NULL;
2671 QueueUserAPC((PAPCFUNC)data->notify_buffer->pfnNotifyCallback,
2672 data->calling_thread, (ULONG_PTR)data->notify_buffer);
2674 HeapFree(GetProcessHeap(), 0, list);
2676 else
2677 WARN("GetNotifyResults server call failed: %u\n", err);
2680 __TRY
2682 err = svcctl_CloseNotifyHandle(&data->notify_handle, &dummy);
2684 __EXCEPT(rpc_filter)
2686 err = map_exception_code(GetExceptionCode());
2688 __ENDTRY
2690 if (err != ERROR_SUCCESS)
2691 WARN("CloseNotifyHandle server call failed: %u\n", err);
2693 CloseHandle(data->calling_thread);
2694 HeapFree(GetProcessHeap(), 0, data);
2696 return 0;
2699 /******************************************************************************
2700 * NotifyServiceStatusChangeW [ADVAPI32.@]
2702 DWORD WINAPI NotifyServiceStatusChangeW(SC_HANDLE hService, DWORD dwNotifyMask,
2703 SERVICE_NOTIFYW *pNotifyBuffer)
2705 DWORD err;
2706 BOOL b_dummy = FALSE;
2707 GUID g_dummy = {0};
2708 notify_data *data;
2710 TRACE("%p 0x%x %p\n", hService, dwNotifyMask, pNotifyBuffer);
2712 data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data));
2713 if (!data)
2714 return ERROR_NOT_ENOUGH_MEMORY;
2716 data->service = hService;
2717 data->notify_buffer = pNotifyBuffer;
2718 if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
2719 GetCurrentProcess(), &data->calling_thread, 0, FALSE,
2720 DUPLICATE_SAME_ACCESS))
2722 ERR("DuplicateHandle failed: %u\n", GetLastError());
2723 HeapFree(GetProcessHeap(), 0, data);
2724 return ERROR_NOT_ENOUGH_MEMORY;
2727 data->params.dwInfoLevel = 2;
2728 data->params.u.params = &data->cparams;
2730 data->cparams.dwNotifyMask = dwNotifyMask;
2732 EnterCriticalSection( &service_cs );
2734 __TRY
2736 err = svcctl_NotifyServiceStatusChange(hService, data->params,
2737 &g_dummy, &g_dummy, &b_dummy, &data->notify_handle);
2739 __EXCEPT(rpc_filter)
2741 err = map_exception_code(GetExceptionCode());
2743 __ENDTRY
2745 if (err != ERROR_SUCCESS)
2747 WARN("NotifyServiceStatusChange server call failed: %u\n", err);
2748 LeaveCriticalSection( &service_cs );
2749 CloseHandle(data->calling_thread);
2750 CloseHandle(data->ready_evt);
2751 HeapFree(GetProcessHeap(), 0, data);
2752 return err;
2755 CloseHandle(CreateThread(NULL, 0, &notify_thread, data, 0, NULL));
2757 list_add_tail(&notify_list, &data->entry);
2759 LeaveCriticalSection( &service_cs );
2761 return ERROR_SUCCESS;