oleaut32/tests: Test more return values.
[wine.git] / dlls / advapi32 / service.c
blobddd6a2142978b0800c671dcd973b8e5bed051c64
1 /*
2 * Win32 advapi functions
4 * Copyright 1995 Sven Verdoolaege
5 * Copyright 2005 Mike McCormack
6 * Copyright 2007 Rolf Kalbermatter
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include "config.h"
24 #include "wine/port.h"
26 #include <stdarg.h>
27 #include <string.h>
28 #include <time.h>
29 #include <assert.h>
31 #define NONAMELESSUNION
33 #include "ntstatus.h"
34 #define WIN32_NO_STATUS
35 #include "windef.h"
36 #include "winbase.h"
37 #include "winsvc.h"
38 #include "winerror.h"
39 #include "winreg.h"
40 #include "wine/unicode.h"
41 #include "wine/debug.h"
42 #include "winternl.h"
43 #include "lmcons.h"
44 #include "lmserver.h"
46 #include "svcctl.h"
48 #include "advapi32_misc.h"
50 #include "wine/exception.h"
52 WINE_DEFAULT_DEBUG_CHANNEL(service);
54 void __RPC_FAR * __RPC_USER MIDL_user_allocate(SIZE_T len)
56 return heap_alloc(len);
59 void __RPC_USER MIDL_user_free(void __RPC_FAR * ptr)
61 heap_free(ptr);
64 typedef struct service_data_t
66 LPHANDLER_FUNCTION_EX handler;
67 LPVOID context;
68 HANDLE thread;
69 SC_HANDLE handle;
70 SC_HANDLE full_access_handle;
71 BOOL unicode : 1;
72 union {
73 LPSERVICE_MAIN_FUNCTIONA a;
74 LPSERVICE_MAIN_FUNCTIONW w;
75 } proc;
76 LPWSTR args;
77 WCHAR name[1];
78 } service_data;
80 typedef struct dispatcher_data_t
82 SC_HANDLE manager;
83 HANDLE pipe;
84 } dispatcher_data;
86 static CRITICAL_SECTION service_cs;
87 static CRITICAL_SECTION_DEBUG service_cs_debug =
89 0, 0, &service_cs,
90 { &service_cs_debug.ProcessLocksList,
91 &service_cs_debug.ProcessLocksList },
92 0, 0, { (DWORD_PTR)(__FILE__ ": service_cs") }
94 static CRITICAL_SECTION service_cs = { &service_cs_debug, -1, 0, 0, 0, 0 };
96 static service_data **services;
97 static unsigned int nb_services;
98 static HANDLE service_event;
99 static BOOL stop_service;
101 extern HANDLE CDECL __wine_make_process_system(void);
103 /******************************************************************************
104 * String management functions (same behaviour as strdup)
105 * NOTE: the caller of those functions is responsible for calling HeapFree
106 * in order to release the memory allocated by those functions.
108 LPWSTR SERV_dup( LPCSTR str )
110 UINT len;
111 LPWSTR wstr;
113 if( !str )
114 return NULL;
115 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
116 wstr = heap_alloc( len*sizeof (WCHAR) );
117 MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
118 return wstr;
121 static inline LPWSTR SERV_dupmulti(LPCSTR str)
123 UINT len = 0, n = 0;
124 LPWSTR wstr;
126 if( !str )
127 return NULL;
128 do {
129 len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
130 n += (strlen( &str[n] ) + 1);
131 } while (str[n]);
132 len++;
133 n++;
135 wstr = heap_alloc( len*sizeof (WCHAR) );
136 MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
137 return wstr;
140 static inline DWORD multisz_cb(LPCWSTR wmultisz)
142 const WCHAR *wptr = wmultisz;
144 if (wmultisz == NULL)
145 return 0;
147 while (*wptr)
148 wptr += lstrlenW(wptr)+1;
149 return (wptr - wmultisz + 1)*sizeof(WCHAR);
152 /******************************************************************************
153 * RPC connection with services.exe
155 static handle_t rpc_wstr_bind(RPC_WSTR str)
157 WCHAR transport[] = SVCCTL_TRANSPORT;
158 WCHAR endpoint[] = SVCCTL_ENDPOINT;
159 RPC_WSTR binding_str;
160 RPC_STATUS status;
161 handle_t rpc_handle;
163 status = RpcStringBindingComposeW(NULL, transport, str, endpoint, NULL, &binding_str);
164 if (status != RPC_S_OK)
166 ERR("RpcStringBindingComposeW failed (%d)\n", (DWORD)status);
167 return NULL;
170 status = RpcBindingFromStringBindingW(binding_str, &rpc_handle);
171 RpcStringFreeW(&binding_str);
173 if (status != RPC_S_OK)
175 ERR("Couldn't connect to services.exe: error code %u\n", (DWORD)status);
176 return NULL;
179 return rpc_handle;
182 static handle_t rpc_cstr_bind(RPC_CSTR str)
184 RPC_CSTR transport = (RPC_CSTR)SVCCTL_TRANSPORTA;
185 RPC_CSTR endpoint = (RPC_CSTR)SVCCTL_ENDPOINTA;
186 RPC_CSTR binding_str;
187 RPC_STATUS status;
188 handle_t rpc_handle;
190 status = RpcStringBindingComposeA(NULL, transport, str, endpoint, NULL, &binding_str);
191 if (status != RPC_S_OK)
193 ERR("RpcStringBindingComposeW failed (%d)\n", (DWORD)status);
194 return NULL;
197 status = RpcBindingFromStringBindingA(binding_str, &rpc_handle);
198 RpcStringFreeA(&binding_str);
200 if (status != RPC_S_OK)
202 ERR("Couldn't connect to services.exe: error code %u\n", (DWORD)status);
203 return NULL;
206 return rpc_handle;
209 DECLSPEC_HIDDEN handle_t __RPC_USER MACHINE_HANDLEA_bind(MACHINE_HANDLEA MachineName)
211 return rpc_cstr_bind((RPC_CSTR)MachineName);
214 DECLSPEC_HIDDEN void __RPC_USER MACHINE_HANDLEA_unbind(MACHINE_HANDLEA MachineName, handle_t h)
216 RpcBindingFree(&h);
219 DECLSPEC_HIDDEN handle_t __RPC_USER MACHINE_HANDLEW_bind(MACHINE_HANDLEW MachineName)
221 return rpc_wstr_bind((RPC_WSTR)MachineName);
224 DECLSPEC_HIDDEN void __RPC_USER MACHINE_HANDLEW_unbind(MACHINE_HANDLEW MachineName, handle_t h)
226 RpcBindingFree(&h);
229 DECLSPEC_HIDDEN handle_t __RPC_USER SVCCTL_HANDLEW_bind(SVCCTL_HANDLEW MachineName)
231 return rpc_wstr_bind((RPC_WSTR)MachineName);
234 DECLSPEC_HIDDEN void __RPC_USER SVCCTL_HANDLEW_unbind(SVCCTL_HANDLEW MachineName, handle_t h)
236 RpcBindingFree(&h);
239 static LONG WINAPI rpc_filter(EXCEPTION_POINTERS *eptr)
241 return I_RpcExceptionFilter(eptr->ExceptionRecord->ExceptionCode);
244 static DWORD map_exception_code(DWORD exception_code)
246 switch (exception_code)
248 case RPC_X_NULL_REF_POINTER:
249 return ERROR_INVALID_ADDRESS;
250 case RPC_X_ENUM_VALUE_OUT_OF_RANGE:
251 case RPC_X_BYTE_COUNT_TOO_SMALL:
252 return ERROR_INVALID_PARAMETER;
253 case RPC_S_INVALID_BINDING:
254 case RPC_X_SS_IN_NULL_CONTEXT:
255 return ERROR_INVALID_HANDLE;
256 default:
257 return exception_code;
261 /******************************************************************************
262 * Service IPC functions
264 static LPWSTR service_get_pipe_name(void)
266 static const WCHAR format[] = { '\\','\\','.','\\','p','i','p','e','\\',
267 'n','e','t','\\','N','t','C','o','n','t','r','o','l','P','i','p','e','%','u',0};
268 static const WCHAR service_current_key_str[] = { 'S','Y','S','T','E','M','\\',
269 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
270 'C','o','n','t','r','o','l','\\',
271 'S','e','r','v','i','c','e','C','u','r','r','e','n','t',0};
272 LPWSTR name;
273 DWORD len;
274 HKEY service_current_key;
275 DWORD service_current;
276 LONG ret;
277 DWORD type;
279 ret = RegOpenKeyExW(HKEY_LOCAL_MACHINE, service_current_key_str, 0,
280 KEY_QUERY_VALUE, &service_current_key);
281 if (ret != ERROR_SUCCESS)
282 return NULL;
283 len = sizeof(service_current);
284 ret = RegQueryValueExW(service_current_key, NULL, NULL, &type,
285 (BYTE *)&service_current, &len);
286 RegCloseKey(service_current_key);
287 if (ret != ERROR_SUCCESS || type != REG_DWORD)
288 return NULL;
289 len = sizeof(format)/sizeof(WCHAR) + 10 /* strlenW("4294967295") */;
290 name = heap_alloc(len * sizeof(WCHAR));
291 if (!name)
292 return NULL;
293 snprintfW(name, len, format, service_current);
294 return name;
297 static HANDLE service_open_pipe(void)
299 LPWSTR szPipe = service_get_pipe_name();
300 HANDLE handle = INVALID_HANDLE_VALUE;
302 do {
303 handle = CreateFileW(szPipe, GENERIC_READ|GENERIC_WRITE,
304 0, NULL, OPEN_ALWAYS, 0, NULL);
305 if (handle != INVALID_HANDLE_VALUE)
306 break;
307 if (GetLastError() != ERROR_PIPE_BUSY)
308 break;
309 } while (WaitNamedPipeW(szPipe, NMPWAIT_USE_DEFAULT_WAIT));
310 heap_free(szPipe);
312 return handle;
315 static service_data *find_service_by_name( const WCHAR *name )
317 unsigned int i;
319 if (nb_services == 1) /* only one service (FIXME: should depend on OWN_PROCESS etc.) */
320 return services[0];
321 for (i = 0; i < nb_services; i++)
322 if (!strcmpiW( name, services[i]->name )) return services[i];
323 return NULL;
326 /******************************************************************************
327 * service_thread
329 * Call into the main service routine provided by StartServiceCtrlDispatcher.
331 static DWORD WINAPI service_thread(LPVOID arg)
333 service_data *info = arg;
334 LPWSTR str = info->args;
335 DWORD argc = 0, len = 0;
337 TRACE("%p\n", arg);
339 while (str[len])
341 len += strlenW(&str[len]) + 1;
342 argc++;
344 len++;
346 if (info->unicode)
348 LPWSTR *argv, p;
350 argv = heap_alloc((argc+1)*sizeof(LPWSTR));
351 for (argc=0, p=str; *p; p += strlenW(p) + 1)
352 argv[argc++] = p;
353 argv[argc] = NULL;
355 info->proc.w(argc, argv);
356 heap_free(argv);
358 else
360 LPSTR strA, *argv, p;
361 DWORD lenA;
363 lenA = WideCharToMultiByte(CP_ACP,0, str, len, NULL, 0, NULL, NULL);
364 strA = heap_alloc(lenA);
365 WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL);
367 argv = heap_alloc((argc+1)*sizeof(LPSTR));
368 for (argc=0, p=strA; *p; p += strlen(p) + 1)
369 argv[argc++] = p;
370 argv[argc] = NULL;
372 info->proc.a(argc, argv);
373 heap_free(argv);
374 heap_free(strA);
376 return 0;
379 /******************************************************************************
380 * service_handle_start
382 static DWORD service_handle_start(service_data *service, const void *data, DWORD data_size)
384 DWORD count = data_size / sizeof(WCHAR);
386 if (service->thread)
388 WARN("service is not stopped\n");
389 return ERROR_SERVICE_ALREADY_RUNNING;
392 heap_free(service->args);
393 service->args = heap_alloc((count + 2) * sizeof(WCHAR));
394 if (count) memcpy( service->args, data, count * sizeof(WCHAR) );
395 service->args[count++] = 0;
396 service->args[count++] = 0;
398 service->thread = CreateThread( NULL, 0, service_thread,
399 service, 0, NULL );
400 SetEvent( service_event ); /* notify the main loop */
401 return 0;
404 /******************************************************************************
405 * service_handle_control
407 static DWORD service_handle_control(service_data *service, DWORD control, const void *data, DWORD data_size)
409 DWORD ret = ERROR_INVALID_SERVICE_CONTROL;
411 TRACE("%s control %u data %p data_size %u\n", debugstr_w(service->name), control, data, data_size);
413 if (control == SERVICE_CONTROL_START)
414 ret = service_handle_start(service, data, data_size);
415 else if (service->handler)
416 ret = service->handler(control, 0, (void *)data, service->context);
417 return ret;
420 /******************************************************************************
421 * service_control_dispatcher
423 static DWORD WINAPI service_control_dispatcher(LPVOID arg)
425 dispatcher_data *disp = arg;
427 /* dispatcher loop */
428 while (1)
430 service_data *service;
431 service_start_info info;
432 BYTE *data = NULL;
433 WCHAR *name;
434 BOOL r;
435 DWORD data_size = 0, count, result;
437 r = ReadFile( disp->pipe, &info, FIELD_OFFSET(service_start_info,data), &count, NULL );
438 if (!r)
440 if (GetLastError() != ERROR_BROKEN_PIPE)
441 ERR( "pipe read failed error %u\n", GetLastError() );
442 break;
444 if (count != FIELD_OFFSET(service_start_info,data))
446 ERR( "partial pipe read %u\n", count );
447 break;
449 if (count < info.total_size)
451 data_size = info.total_size - FIELD_OFFSET(service_start_info,data);
452 data = heap_alloc( data_size );
453 r = ReadFile( disp->pipe, data, data_size, &count, NULL );
454 if (!r)
456 if (GetLastError() != ERROR_BROKEN_PIPE)
457 ERR( "pipe read failed error %u\n", GetLastError() );
458 heap_free( data );
459 break;
461 if (count != data_size)
463 ERR( "partial pipe read %u/%u\n", count, data_size );
464 heap_free( data );
465 break;
469 EnterCriticalSection( &service_cs );
471 /* validate service name */
472 name = (WCHAR *)data;
473 if (!info.name_size || data_size < info.name_size * sizeof(WCHAR) || name[info.name_size - 1])
475 ERR( "got request without valid service name\n" );
476 result = ERROR_INVALID_PARAMETER;
477 goto done;
480 if (info.magic != SERVICE_PROTOCOL_MAGIC)
482 ERR( "received invalid request for service %s\n", debugstr_w(name) );
483 result = ERROR_INVALID_PARAMETER;
484 goto done;
487 /* find the service */
488 if (!(service = find_service_by_name( name )))
490 FIXME( "got request for unknown service %s\n", debugstr_w(name) );
491 result = ERROR_INVALID_PARAMETER;
492 goto done;
495 if (!service->handle)
497 if (!(service->handle = OpenServiceW( disp->manager, name, SERVICE_SET_STATUS )) ||
498 !(service->full_access_handle = OpenServiceW( disp->manager, name,
499 GENERIC_READ|GENERIC_WRITE )))
500 FIXME( "failed to open service %s\n", debugstr_w(name) );
503 data_size -= info.name_size * sizeof(WCHAR);
504 result = service_handle_control(service, info.control, data_size ?
505 &data[info.name_size * sizeof(WCHAR)] : NULL, data_size);
507 done:
508 LeaveCriticalSection( &service_cs );
509 WriteFile( disp->pipe, &result, sizeof(result), &count, NULL );
510 heap_free( data );
513 CloseHandle( disp->pipe );
514 CloseServiceHandle( disp->manager );
515 heap_free( disp );
516 return 1;
519 /******************************************************************************
520 * service_run_main_thread
522 static BOOL service_run_main_thread(void)
524 DWORD i, n, ret;
525 HANDLE wait_handles[MAXIMUM_WAIT_OBJECTS];
526 UINT wait_services[MAXIMUM_WAIT_OBJECTS];
527 dispatcher_data *disp = heap_alloc( sizeof(*disp) );
529 disp->manager = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
530 if (!disp->manager)
532 ERR("failed to open service manager error %u\n", GetLastError());
533 heap_free( disp );
534 return FALSE;
537 disp->pipe = service_open_pipe();
538 if (disp->pipe == INVALID_HANDLE_VALUE)
540 WARN("failed to create control pipe error %u\n", GetLastError());
541 CloseServiceHandle( disp->manager );
542 heap_free( disp );
543 SetLastError( ERROR_FAILED_SERVICE_CONTROLLER_CONNECT );
544 return FALSE;
547 service_event = CreateEventW( NULL, FALSE, FALSE, NULL );
548 stop_service = FALSE;
550 /* FIXME: service_control_dispatcher should be merged into the main thread */
551 wait_handles[0] = __wine_make_process_system();
552 wait_handles[1] = CreateThread( NULL, 0, service_control_dispatcher, disp, 0, NULL );
553 wait_handles[2] = service_event;
555 TRACE("Starting %d services running as process %d\n",
556 nb_services, GetCurrentProcessId());
558 /* wait for all the threads to pack up and exit */
559 while (!stop_service)
561 EnterCriticalSection( &service_cs );
562 for (i = 0, n = 3; i < nb_services && n < MAXIMUM_WAIT_OBJECTS; i++)
564 if (!services[i]->thread) continue;
565 wait_services[n] = i;
566 wait_handles[n++] = services[i]->thread;
568 LeaveCriticalSection( &service_cs );
570 ret = WaitForMultipleObjects( n, wait_handles, FALSE, INFINITE );
571 if (!ret) /* system process event */
573 SERVICE_STATUS st;
574 SERVICE_PRESHUTDOWN_INFO spi;
575 DWORD timeout = 5000;
576 BOOL res;
578 EnterCriticalSection( &service_cs );
579 n = 0;
580 for (i = 0; i < nb_services && n < MAXIMUM_WAIT_OBJECTS; i++)
582 if (!services[i]->thread) continue;
584 res = QueryServiceStatus(services[i]->full_access_handle, &st);
585 ret = ERROR_SUCCESS;
586 if (res && (st.dwControlsAccepted & SERVICE_ACCEPT_PRESHUTDOWN))
588 res = QueryServiceConfig2W( services[i]->full_access_handle, SERVICE_CONFIG_PRESHUTDOWN_INFO,
589 (LPBYTE)&spi, sizeof(spi), &i );
590 if (res)
592 FIXME("service should be able to delay shutdown\n");
593 timeout += spi.dwPreshutdownTimeout;
594 ret = service_handle_control( services[i], SERVICE_CONTROL_PRESHUTDOWN, NULL, 0 );
595 wait_handles[n++] = services[i]->thread;
598 else if (res && (st.dwControlsAccepted & SERVICE_ACCEPT_SHUTDOWN))
600 ret = service_handle_control( services[i], SERVICE_CONTROL_SHUTDOWN, NULL, 0 );
601 wait_handles[n++] = services[i]->thread;
604 LeaveCriticalSection( &service_cs );
606 TRACE("last user process exited, shutting down (timeout: %d)\n", timeout);
607 WaitForMultipleObjects( n, wait_handles, TRUE, timeout );
608 ExitProcess(0);
610 else if (ret == 1)
612 TRACE( "control dispatcher exited, shutting down\n" );
613 /* FIXME: we should maybe send a shutdown control to running services */
614 ExitProcess(0);
616 else if (ret == 2)
618 continue; /* rebuild the list */
620 else if (ret < n)
622 i = wait_services[ret];
623 EnterCriticalSection( &service_cs );
624 CloseHandle( services[i]->thread );
625 services[i]->thread = NULL;
626 LeaveCriticalSection( &service_cs );
628 else return FALSE;
631 return TRUE;
634 /******************************************************************************
635 * StartServiceCtrlDispatcherA [ADVAPI32.@]
637 * See StartServiceCtrlDispatcherW.
639 BOOL WINAPI StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *servent )
641 service_data *info;
642 unsigned int i;
644 TRACE("%p\n", servent);
646 if (nb_services)
648 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
649 return FALSE;
651 while (servent[nb_services].lpServiceName) nb_services++;
652 if (!nb_services)
654 SetLastError( ERROR_INVALID_PARAMETER );
655 return FALSE;
658 services = heap_alloc( nb_services * sizeof(*services) );
660 for (i = 0; i < nb_services; i++)
662 DWORD len = MultiByteToWideChar(CP_ACP, 0, servent[i].lpServiceName, -1, NULL, 0);
663 DWORD sz = FIELD_OFFSET( service_data, name[len] );
664 info = heap_alloc_zero( sz );
665 MultiByteToWideChar(CP_ACP, 0, servent[i].lpServiceName, -1, info->name, len);
666 info->proc.a = servent[i].lpServiceProc;
667 info->unicode = FALSE;
668 services[i] = info;
671 return service_run_main_thread();
674 /******************************************************************************
675 * StartServiceCtrlDispatcherW [ADVAPI32.@]
677 * Connects a process containing one or more services to the service control
678 * manager.
680 * PARAMS
681 * servent [I] A list of the service names and service procedures
683 * RETURNS
684 * Success: TRUE.
685 * Failure: FALSE.
687 BOOL WINAPI StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW *servent )
689 service_data *info;
690 unsigned int i;
692 TRACE("%p\n", servent);
694 if (nb_services)
696 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
697 return FALSE;
699 while (servent[nb_services].lpServiceName) nb_services++;
700 if (!nb_services)
702 SetLastError( ERROR_INVALID_PARAMETER );
703 return FALSE;
706 services = heap_alloc( nb_services * sizeof(*services) );
708 for (i = 0; i < nb_services; i++)
710 DWORD len = strlenW(servent[i].lpServiceName) + 1;
711 DWORD sz = FIELD_OFFSET( service_data, name[len] );
712 info = heap_alloc_zero( sz );
713 strcpyW(info->name, servent[i].lpServiceName);
714 info->proc.w = servent[i].lpServiceProc;
715 info->unicode = TRUE;
716 services[i] = info;
719 return service_run_main_thread();
722 /******************************************************************************
723 * LockServiceDatabase [ADVAPI32.@]
725 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
727 SC_RPC_LOCK hLock = NULL;
728 DWORD err;
730 TRACE("%p\n",hSCManager);
732 __TRY
734 err = svcctl_LockServiceDatabase(hSCManager, &hLock);
736 __EXCEPT(rpc_filter)
738 err = map_exception_code(GetExceptionCode());
740 __ENDTRY
741 if (err != ERROR_SUCCESS)
743 SetLastError(err);
744 return NULL;
746 return hLock;
749 /******************************************************************************
750 * UnlockServiceDatabase [ADVAPI32.@]
752 BOOL WINAPI UnlockServiceDatabase (SC_LOCK ScLock)
754 DWORD err;
755 SC_RPC_LOCK hRpcLock = ScLock;
757 TRACE("%p\n",ScLock);
759 __TRY
761 err = svcctl_UnlockServiceDatabase(&hRpcLock);
763 __EXCEPT(rpc_filter)
765 err = map_exception_code(GetExceptionCode());
767 __ENDTRY
768 if (err != ERROR_SUCCESS)
770 SetLastError(err);
771 return FALSE;
773 return TRUE;
776 /******************************************************************************
777 * SetServiceStatus [ADVAPI32.@]
779 * PARAMS
780 * hService []
781 * lpStatus []
783 BOOL WINAPI
784 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
786 DWORD err;
788 TRACE("%p %x %x %x %x %x %x %x\n", hService,
789 lpStatus->dwServiceType, lpStatus->dwCurrentState,
790 lpStatus->dwControlsAccepted, lpStatus->dwWin32ExitCode,
791 lpStatus->dwServiceSpecificExitCode, lpStatus->dwCheckPoint,
792 lpStatus->dwWaitHint);
794 __TRY
796 err = svcctl_SetServiceStatus( hService, lpStatus );
798 __EXCEPT(rpc_filter)
800 err = map_exception_code(GetExceptionCode());
802 __ENDTRY
803 if (err != ERROR_SUCCESS)
805 SetLastError(err);
806 return FALSE;
809 if (lpStatus->dwCurrentState == SERVICE_STOPPED)
811 unsigned int i, count = 0;
812 EnterCriticalSection( &service_cs );
813 for (i = 0; i < nb_services; i++)
815 if (services[i]->handle == (SC_HANDLE)hService) continue;
816 if (services[i]->thread) count++;
818 if (!count)
820 stop_service = TRUE;
821 SetEvent( service_event ); /* notify the main loop */
823 LeaveCriticalSection( &service_cs );
826 return TRUE;
830 /******************************************************************************
831 * OpenSCManagerA [ADVAPI32.@]
833 * Establish a connection to the service control manager and open its database.
835 * PARAMS
836 * lpMachineName [I] Pointer to machine name string
837 * lpDatabaseName [I] Pointer to database name string
838 * dwDesiredAccess [I] Type of access
840 * RETURNS
841 * Success: A Handle to the service control manager database
842 * Failure: NULL
844 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
845 DWORD dwDesiredAccess )
847 LPWSTR machineW, databaseW;
848 SC_HANDLE ret;
850 machineW = SERV_dup(lpMachineName);
851 databaseW = SERV_dup(lpDatabaseName);
852 ret = OpenSCManagerW(machineW, databaseW, dwDesiredAccess);
853 heap_free(databaseW);
854 heap_free(machineW);
855 return ret;
858 /******************************************************************************
859 * OpenSCManagerW [ADVAPI32.@]
861 * See OpenSCManagerA.
863 DWORD SERV_OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
864 DWORD dwDesiredAccess, SC_HANDLE *handle )
866 DWORD r;
868 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName),
869 debugstr_w(lpDatabaseName), dwDesiredAccess);
871 __TRY
873 r = svcctl_OpenSCManagerW(lpMachineName, lpDatabaseName, dwDesiredAccess, (SC_RPC_HANDLE *)handle);
875 __EXCEPT(rpc_filter)
877 r = map_exception_code(GetExceptionCode());
879 __ENDTRY
881 if (r!=ERROR_SUCCESS)
882 *handle = 0;
884 TRACE("returning %p\n", *handle);
885 return r;
888 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
889 DWORD dwDesiredAccess )
891 SC_HANDLE handle = 0;
892 DWORD r;
894 r = SERV_OpenSCManagerW(lpMachineName, lpDatabaseName, dwDesiredAccess, &handle);
895 if (r!=ERROR_SUCCESS)
896 SetLastError(r);
897 return handle;
900 /******************************************************************************
901 * ControlService [ADVAPI32.@]
903 * Send a control code to a service.
905 * PARAMS
906 * hService [I] Handle of the service control manager database
907 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
908 * lpServiceStatus [O] Destination for the status of the service, if available
910 * RETURNS
911 * Success: TRUE.
912 * Failure: FALSE.
914 * BUGS
915 * Unlike M$' implementation, control requests are not serialized and may be
916 * processed asynchronously.
918 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
919 LPSERVICE_STATUS lpServiceStatus )
921 DWORD err;
923 TRACE("%p %d %p\n", hService, dwControl, lpServiceStatus);
925 __TRY
927 err = svcctl_ControlService(hService, dwControl, lpServiceStatus);
929 __EXCEPT(rpc_filter)
931 err = map_exception_code(GetExceptionCode());
933 __ENDTRY
934 if (err != ERROR_SUCCESS)
936 SetLastError(err);
937 return FALSE;
940 return TRUE;
943 /******************************************************************************
944 * CloseServiceHandle [ADVAPI32.@]
946 * Close a handle to a service or the service control manager database.
948 * PARAMS
949 * hSCObject [I] Handle to service or service control manager database
951 * RETURNS
952 * Success: TRUE
953 * Failure: FALSE
955 BOOL WINAPI
956 CloseServiceHandle( SC_HANDLE hSCObject )
958 DWORD err;
960 TRACE("%p\n", hSCObject);
962 __TRY
964 err = svcctl_CloseServiceHandle((SC_RPC_HANDLE *)&hSCObject);
966 __EXCEPT(rpc_filter)
968 err = map_exception_code(GetExceptionCode());
970 __ENDTRY
972 if (err != ERROR_SUCCESS)
974 SetLastError(err);
975 return FALSE;
977 return TRUE;
981 /******************************************************************************
982 * OpenServiceA [ADVAPI32.@]
984 * Open a handle to a service.
986 * PARAMS
987 * hSCManager [I] Handle of the service control manager database
988 * lpServiceName [I] Name of the service to open
989 * dwDesiredAccess [I] Access required to the service
991 * RETURNS
992 * Success: Handle to the service
993 * Failure: NULL
995 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
996 DWORD dwDesiredAccess )
998 LPWSTR lpServiceNameW;
999 SC_HANDLE ret;
1001 TRACE("%p %s 0x%08x\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
1003 lpServiceNameW = SERV_dup(lpServiceName);
1004 ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
1005 heap_free(lpServiceNameW);
1006 return ret;
1010 /******************************************************************************
1011 * OpenServiceW [ADVAPI32.@]
1013 * See OpenServiceA.
1015 DWORD SERV_OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1016 DWORD dwDesiredAccess, SC_HANDLE *handle )
1018 DWORD err;
1020 TRACE("%p %s 0x%08x\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
1022 if (!hSCManager)
1023 return ERROR_INVALID_HANDLE;
1025 __TRY
1027 err = svcctl_OpenServiceW(hSCManager, lpServiceName, dwDesiredAccess, (SC_RPC_HANDLE *)handle);
1029 __EXCEPT(rpc_filter)
1031 err = map_exception_code(GetExceptionCode());
1033 __ENDTRY
1035 if (err != ERROR_SUCCESS)
1036 *handle = 0;
1038 TRACE("returning %p\n", *handle);
1039 return err;
1042 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1043 DWORD dwDesiredAccess)
1045 SC_HANDLE handle = 0;
1046 DWORD err;
1048 err = SERV_OpenServiceW(hSCManager, lpServiceName, dwDesiredAccess, &handle);
1049 if (err != ERROR_SUCCESS)
1050 SetLastError(err);
1051 return handle;
1054 /******************************************************************************
1055 * CreateServiceW [ADVAPI32.@]
1057 SC_HANDLE WINAPI
1058 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1059 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
1060 DWORD dwServiceType, DWORD dwStartType,
1061 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1062 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1063 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
1064 LPCWSTR lpPassword )
1066 SC_HANDLE handle = 0;
1067 DWORD err;
1068 SIZE_T passwdlen;
1070 TRACE("%p %s %s\n", hSCManager,
1071 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
1073 if (!hSCManager)
1075 SetLastError( ERROR_INVALID_HANDLE );
1076 return 0;
1079 if (lpPassword)
1080 passwdlen = (strlenW(lpPassword) + 1) * sizeof(WCHAR);
1081 else
1082 passwdlen = 0;
1084 __TRY
1086 BOOL is_wow64;
1088 IsWow64Process(GetCurrentProcess(), &is_wow64);
1090 if (is_wow64)
1091 err = svcctl_CreateServiceWOW64W(hSCManager, lpServiceName,
1092 lpDisplayName, dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1093 lpBinaryPathName, lpLoadOrderGroup, lpdwTagId, (const BYTE*)lpDependencies,
1094 multisz_cb(lpDependencies), lpServiceStartName, (const BYTE*)lpPassword, passwdlen,
1095 (SC_RPC_HANDLE *)&handle);
1096 else
1097 err = svcctl_CreateServiceW(hSCManager, lpServiceName,
1098 lpDisplayName, dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1099 lpBinaryPathName, lpLoadOrderGroup, lpdwTagId, (const BYTE*)lpDependencies,
1100 multisz_cb(lpDependencies), lpServiceStartName, (const BYTE*)lpPassword, passwdlen,
1101 (SC_RPC_HANDLE *)&handle);
1103 __EXCEPT(rpc_filter)
1105 err = map_exception_code(GetExceptionCode());
1107 __ENDTRY
1109 if (err != ERROR_SUCCESS)
1111 SetLastError(err);
1112 handle = 0;
1114 return handle;
1118 /******************************************************************************
1119 * CreateServiceA [ADVAPI32.@]
1121 SC_HANDLE WINAPI
1122 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1123 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1124 DWORD dwServiceType, DWORD dwStartType,
1125 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1126 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1127 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1128 LPCSTR lpPassword )
1130 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1131 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1132 SC_HANDLE r;
1134 TRACE("%p %s %s\n", hSCManager,
1135 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1137 lpServiceNameW = SERV_dup( lpServiceName );
1138 lpDisplayNameW = SERV_dup( lpDisplayName );
1139 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1140 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1141 lpDependenciesW = SERV_dupmulti( lpDependencies );
1142 lpServiceStartNameW = SERV_dup( lpServiceStartName );
1143 lpPasswordW = SERV_dup( lpPassword );
1145 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1146 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1147 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1148 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1150 heap_free( lpServiceNameW );
1151 heap_free( lpDisplayNameW );
1152 heap_free( lpBinaryPathNameW );
1153 heap_free( lpLoadOrderGroupW );
1154 heap_free( lpDependenciesW );
1155 heap_free( lpServiceStartNameW );
1156 heap_free( lpPasswordW );
1158 return r;
1162 /******************************************************************************
1163 * DeleteService [ADVAPI32.@]
1165 * Delete a service from the service control manager database.
1167 * PARAMS
1168 * hService [I] Handle of the service to delete
1170 * RETURNS
1171 * Success: TRUE
1172 * Failure: FALSE
1174 BOOL WINAPI DeleteService( SC_HANDLE hService )
1176 DWORD err;
1178 TRACE("%p\n", hService);
1180 __TRY
1182 err = svcctl_DeleteService(hService);
1184 __EXCEPT(rpc_filter)
1186 err = map_exception_code(GetExceptionCode());
1188 __ENDTRY
1189 if (err != 0)
1191 SetLastError(err);
1192 return FALSE;
1195 return TRUE;
1199 /******************************************************************************
1200 * StartServiceA [ADVAPI32.@]
1202 * Start a service
1204 * PARAMS
1205 * hService [I] Handle of service
1206 * dwNumServiceArgs [I] Number of arguments
1207 * lpServiceArgVectors [I] Address of array of argument strings
1209 * NOTES
1210 * - NT implements this function using an obscure RPC call.
1211 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1212 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1213 * - This will only work for shared address space. How should the service
1214 * args be transferred when address spaces are separated?
1215 * - Can only start one service at a time.
1216 * - Has no concept of privilege.
1218 * RETURNS
1219 * Success: TRUE.
1220 * Failure: FALSE
1222 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1223 LPCSTR *lpServiceArgVectors )
1225 LPWSTR *lpwstr=NULL;
1226 unsigned int i;
1227 BOOL r;
1229 TRACE("(%p,%d,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1231 if (dwNumServiceArgs)
1232 lpwstr = heap_alloc( dwNumServiceArgs*sizeof(LPWSTR) );
1234 for(i=0; i<dwNumServiceArgs; i++)
1235 lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1237 r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1239 if (dwNumServiceArgs)
1241 for(i=0; i<dwNumServiceArgs; i++)
1242 heap_free(lpwstr[i]);
1243 heap_free(lpwstr);
1246 return r;
1250 /******************************************************************************
1251 * StartServiceW [ADVAPI32.@]
1253 * See StartServiceA.
1255 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1256 LPCWSTR *lpServiceArgVectors)
1258 DWORD err;
1260 TRACE("%p %d %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1262 __TRY
1264 err = svcctl_StartServiceW(hService, dwNumServiceArgs, lpServiceArgVectors);
1266 __EXCEPT(rpc_filter)
1268 err = map_exception_code(GetExceptionCode());
1270 __ENDTRY
1271 if (err != ERROR_SUCCESS)
1273 SetLastError(err);
1274 return FALSE;
1277 return TRUE;
1280 /******************************************************************************
1281 * QueryServiceStatus [ADVAPI32.@]
1283 * PARAMS
1284 * hService [I] Handle to service to get information about
1285 * lpservicestatus [O] buffer to receive the status information for the service
1288 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1289 LPSERVICE_STATUS lpservicestatus)
1291 SERVICE_STATUS_PROCESS SvcStatusData;
1292 BOOL ret;
1293 DWORD dummy;
1295 TRACE("%p %p\n", hService, lpservicestatus);
1297 if (!hService)
1299 SetLastError(ERROR_INVALID_HANDLE);
1300 return FALSE;
1302 if (!lpservicestatus)
1304 SetLastError(ERROR_INVALID_ADDRESS);
1305 return FALSE;
1308 ret = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&SvcStatusData,
1309 sizeof(SERVICE_STATUS_PROCESS), &dummy);
1310 if (ret) memcpy(lpservicestatus, &SvcStatusData, sizeof(SERVICE_STATUS)) ;
1311 return ret;
1315 /******************************************************************************
1316 * QueryServiceStatusEx [ADVAPI32.@]
1318 * Get information about a service.
1320 * PARAMS
1321 * hService [I] Handle to service to get information about
1322 * InfoLevel [I] Level of information to get
1323 * lpBuffer [O] Destination for requested information
1324 * cbBufSize [I] Size of lpBuffer in bytes
1325 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1327 * RETURNS
1328 * Success: TRUE
1329 * FAILURE: FALSE
1331 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1332 LPBYTE lpBuffer, DWORD cbBufSize,
1333 LPDWORD pcbBytesNeeded)
1335 DWORD err;
1337 TRACE("%p %d %p %d %p\n", hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1339 if (InfoLevel != SC_STATUS_PROCESS_INFO)
1341 err = ERROR_INVALID_LEVEL;
1343 else if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
1345 *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
1346 err = ERROR_INSUFFICIENT_BUFFER;
1348 else
1350 __TRY
1352 err = svcctl_QueryServiceStatusEx(hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1354 __EXCEPT(rpc_filter)
1356 err = map_exception_code(GetExceptionCode());
1358 __ENDTRY
1360 if (err != ERROR_SUCCESS)
1362 SetLastError(err);
1363 return FALSE;
1365 return TRUE;
1368 /******************************************************************************
1369 * QueryServiceConfigA [ADVAPI32.@]
1371 BOOL WINAPI QueryServiceConfigA( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGA config,
1372 DWORD size, LPDWORD needed )
1374 DWORD n;
1375 LPSTR p, buffer;
1376 BOOL ret;
1377 QUERY_SERVICE_CONFIGW *configW;
1379 TRACE("%p %p %d %p\n", hService, config, size, needed);
1381 if (!(buffer = heap_alloc( 2 * size )))
1383 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1384 return FALSE;
1386 configW = (QUERY_SERVICE_CONFIGW *)buffer;
1387 ret = QueryServiceConfigW( hService, configW, 2 * size, needed );
1388 if (!ret) goto done;
1390 config->dwServiceType = configW->dwServiceType;
1391 config->dwStartType = configW->dwStartType;
1392 config->dwErrorControl = configW->dwErrorControl;
1393 config->lpBinaryPathName = NULL;
1394 config->lpLoadOrderGroup = NULL;
1395 config->dwTagId = configW->dwTagId;
1396 config->lpDependencies = NULL;
1397 config->lpServiceStartName = NULL;
1398 config->lpDisplayName = NULL;
1400 p = (LPSTR)(config + 1);
1401 n = size - sizeof(*config);
1402 ret = FALSE;
1404 #define MAP_STR(str) \
1405 do { \
1406 if (configW->str) \
1408 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1409 if (!sz) goto done; \
1410 config->str = p; \
1411 p += sz; \
1412 n -= sz; \
1414 } while (0)
1416 MAP_STR( lpBinaryPathName );
1417 MAP_STR( lpLoadOrderGroup );
1418 MAP_STR( lpDependencies );
1419 MAP_STR( lpServiceStartName );
1420 MAP_STR( lpDisplayName );
1421 #undef MAP_STR
1423 *needed = p - (LPSTR)config;
1424 ret = TRUE;
1426 done:
1427 heap_free( buffer );
1428 return ret;
1431 static DWORD move_string_to_buffer(BYTE **buf, LPWSTR *string_ptr)
1433 DWORD cb;
1435 if (!*string_ptr)
1437 cb = sizeof(WCHAR);
1438 memset(*buf, 0, cb);
1440 else
1442 cb = (strlenW(*string_ptr) + 1)*sizeof(WCHAR);
1443 memcpy(*buf, *string_ptr, cb);
1444 MIDL_user_free(*string_ptr);
1447 *string_ptr = (LPWSTR)*buf;
1448 *buf += cb;
1450 return cb;
1453 static DWORD size_string(LPCWSTR string)
1455 return (string ? (strlenW(string) + 1)*sizeof(WCHAR) : sizeof(WCHAR));
1458 /******************************************************************************
1459 * QueryServiceConfigW [ADVAPI32.@]
1461 BOOL WINAPI
1462 QueryServiceConfigW( SC_HANDLE hService,
1463 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1464 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1466 QUERY_SERVICE_CONFIGW config;
1467 DWORD total;
1468 DWORD err;
1469 BYTE *bufpos;
1471 TRACE("%p %p %d %p\n", hService, lpServiceConfig,
1472 cbBufSize, pcbBytesNeeded);
1474 memset(&config, 0, sizeof(config));
1476 __TRY
1478 err = svcctl_QueryServiceConfigW(hService, &config, cbBufSize, pcbBytesNeeded);
1480 __EXCEPT(rpc_filter)
1482 err = map_exception_code(GetExceptionCode());
1484 __ENDTRY
1486 if (err != ERROR_SUCCESS)
1488 TRACE("services.exe: error %u\n", err);
1489 SetLastError(err);
1490 return FALSE;
1493 /* calculate the size required first */
1494 total = sizeof (QUERY_SERVICE_CONFIGW);
1495 total += size_string(config.lpBinaryPathName);
1496 total += size_string(config.lpLoadOrderGroup);
1497 total += size_string(config.lpDependencies);
1498 total += size_string(config.lpServiceStartName);
1499 total += size_string(config.lpDisplayName);
1501 *pcbBytesNeeded = total;
1503 /* if there's not enough memory, return an error */
1504 if( total > cbBufSize )
1506 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1507 MIDL_user_free(config.lpBinaryPathName);
1508 MIDL_user_free(config.lpLoadOrderGroup);
1509 MIDL_user_free(config.lpDependencies);
1510 MIDL_user_free(config.lpServiceStartName);
1511 MIDL_user_free(config.lpDisplayName);
1512 return FALSE;
1515 *lpServiceConfig = config;
1516 bufpos = ((BYTE *)lpServiceConfig) + sizeof(QUERY_SERVICE_CONFIGW);
1517 move_string_to_buffer(&bufpos, &lpServiceConfig->lpBinaryPathName);
1518 move_string_to_buffer(&bufpos, &lpServiceConfig->lpLoadOrderGroup);
1519 move_string_to_buffer(&bufpos, &lpServiceConfig->lpDependencies);
1520 move_string_to_buffer(&bufpos, &lpServiceConfig->lpServiceStartName);
1521 move_string_to_buffer(&bufpos, &lpServiceConfig->lpDisplayName);
1523 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1524 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1525 TRACE("Dependencies = %s\n", debugstr_w(lpServiceConfig->lpDependencies) );
1526 TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig->lpServiceStartName) );
1527 TRACE("Display name = %s\n", debugstr_w(lpServiceConfig->lpDisplayName) );
1529 return TRUE;
1532 /******************************************************************************
1533 * QueryServiceConfig2A [ADVAPI32.@]
1535 * Note
1536 * observed under win2k:
1537 * The functions QueryServiceConfig2A and QueryServiceConfig2W return the same
1538 * required buffer size (in byte) at least for dwLevel SERVICE_CONFIG_DESCRIPTION
1540 BOOL WINAPI QueryServiceConfig2A(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffer,
1541 DWORD size, LPDWORD needed)
1543 BOOL ret;
1544 LPBYTE bufferW = NULL;
1546 TRACE("%p %u %p %u %p\n", hService, dwLevel, buffer, size, needed);
1548 if(buffer && size)
1549 bufferW = heap_alloc(size);
1551 ret = QueryServiceConfig2W(hService, dwLevel, bufferW, size, needed);
1552 if(!ret) goto cleanup;
1554 switch(dwLevel) {
1555 case SERVICE_CONFIG_DESCRIPTION:
1556 if (buffer && bufferW) {
1557 LPSERVICE_DESCRIPTIONA configA = (LPSERVICE_DESCRIPTIONA) buffer;
1558 LPSERVICE_DESCRIPTIONW configW = (LPSERVICE_DESCRIPTIONW) bufferW;
1559 if (configW->lpDescription && (size > sizeof(SERVICE_DESCRIPTIONA))) {
1560 DWORD sz;
1561 configA->lpDescription = (LPSTR)(configA + 1);
1562 sz = WideCharToMultiByte( CP_ACP, 0, configW->lpDescription, -1,
1563 configA->lpDescription, size - sizeof(SERVICE_DESCRIPTIONA), NULL, NULL );
1564 if (!sz) {
1565 FIXME("WideCharToMultiByte failed for configW->lpDescription\n");
1566 ret = FALSE;
1567 configA->lpDescription = NULL;
1570 else configA->lpDescription = NULL;
1572 break;
1573 case SERVICE_CONFIG_PRESHUTDOWN_INFO:
1574 if (buffer && bufferW && *needed<=size)
1575 memcpy(buffer, bufferW, *needed);
1576 break;
1577 default:
1578 FIXME("conversation W->A not implemented for level %d\n", dwLevel);
1579 ret = FALSE;
1580 break;
1583 cleanup:
1584 heap_free( bufferW);
1585 return ret;
1588 /******************************************************************************
1589 * QueryServiceConfig2W [ADVAPI32.@]
1591 * See QueryServiceConfig2A.
1593 BOOL WINAPI QueryServiceConfig2W(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffer,
1594 DWORD size, LPDWORD needed)
1596 BYTE *bufptr;
1597 DWORD err;
1599 TRACE("%p %u %p %u %p\n", hService, dwLevel, buffer, size, needed);
1601 if (!buffer && size)
1603 SetLastError(ERROR_INVALID_ADDRESS);
1604 return FALSE;
1607 switch (dwLevel)
1609 case SERVICE_CONFIG_DESCRIPTION:
1610 if (!(bufptr = heap_alloc( size )))
1612 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1613 return FALSE;
1615 break;
1617 case SERVICE_CONFIG_PRESHUTDOWN_INFO:
1618 bufptr = buffer;
1619 break;
1621 default:
1622 FIXME("Level %d not implemented\n", dwLevel);
1623 SetLastError(ERROR_INVALID_LEVEL);
1624 return FALSE;
1627 if (!needed)
1629 SetLastError(ERROR_INVALID_ADDRESS);
1630 return FALSE;
1633 __TRY
1635 err = svcctl_QueryServiceConfig2W(hService, dwLevel, bufptr, size, needed);
1637 __EXCEPT(rpc_filter)
1639 err = map_exception_code(GetExceptionCode());
1641 __ENDTRY
1643 switch (dwLevel)
1645 case SERVICE_CONFIG_DESCRIPTION:
1647 SERVICE_DESCRIPTIONW *desc = (SERVICE_DESCRIPTIONW *)buffer;
1648 struct service_description *s = (struct service_description *)bufptr;
1650 if (err != ERROR_SUCCESS && err != ERROR_INSUFFICIENT_BUFFER)
1652 heap_free( bufptr );
1653 SetLastError( err );
1654 return FALSE;
1657 /* adjust for potentially larger SERVICE_DESCRIPTIONW structure */
1658 if (*needed == sizeof(*s)) *needed = sizeof(*desc);
1659 else
1660 *needed = *needed - FIELD_OFFSET(struct service_description, description) + sizeof(*desc);
1662 if (size < *needed)
1664 heap_free( bufptr );
1665 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1666 return FALSE;
1668 if (desc)
1670 if (!s->size) desc->lpDescription = NULL;
1671 else
1673 desc->lpDescription = (WCHAR *)(desc + 1);
1674 memcpy( desc->lpDescription, s->description, s->size );
1677 heap_free( bufptr );
1678 break;
1680 case SERVICE_CONFIG_PRESHUTDOWN_INFO:
1681 if (err != ERROR_SUCCESS)
1683 SetLastError( err );
1684 return FALSE;
1686 break;
1688 default:
1689 break;
1692 return TRUE;
1695 /******************************************************************************
1696 * EnumServicesStatusA [ADVAPI32.@]
1698 BOOL WINAPI
1699 EnumServicesStatusA( SC_HANDLE hmngr, DWORD type, DWORD state, LPENUM_SERVICE_STATUSA
1700 services, DWORD size, LPDWORD needed, LPDWORD returned,
1701 LPDWORD resume_handle )
1703 BOOL ret;
1704 unsigned int i;
1705 ENUM_SERVICE_STATUSW *servicesW = NULL;
1706 DWORD sz, n;
1707 char *p;
1709 TRACE("%p 0x%x 0x%x %p %u %p %p %p\n", hmngr, type, state, services, size, needed,
1710 returned, resume_handle);
1712 if (!hmngr)
1714 SetLastError( ERROR_INVALID_HANDLE );
1715 return FALSE;
1717 if (!needed || !returned)
1719 SetLastError( ERROR_INVALID_ADDRESS );
1720 return FALSE;
1723 sz = max( 2 * size, sizeof(*servicesW) );
1724 if (!(servicesW = heap_alloc( sz )))
1726 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1727 return FALSE;
1730 ret = EnumServicesStatusW( hmngr, type, state, servicesW, sz, needed, returned, resume_handle );
1731 if (!ret) goto done;
1733 p = (char *)services + *returned * sizeof(ENUM_SERVICE_STATUSA);
1734 n = size - (p - (char *)services);
1735 ret = FALSE;
1736 for (i = 0; i < *returned; i++)
1738 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpServiceName, -1, p, n, NULL, NULL );
1739 if (!sz) goto done;
1740 services[i].lpServiceName = p;
1741 p += sz;
1742 n -= sz;
1743 if (servicesW[i].lpDisplayName)
1745 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpDisplayName, -1, p, n, NULL, NULL );
1746 if (!sz) goto done;
1747 services[i].lpDisplayName = p;
1748 p += sz;
1749 n -= sz;
1751 else services[i].lpDisplayName = NULL;
1752 services[i].ServiceStatus = servicesW[i].ServiceStatus;
1755 ret = TRUE;
1757 done:
1758 heap_free( servicesW );
1759 return ret;
1762 /******************************************************************************
1763 * EnumServicesStatusW [ADVAPI32.@]
1765 BOOL WINAPI
1766 EnumServicesStatusW( SC_HANDLE hmngr, DWORD type, DWORD state, LPENUM_SERVICE_STATUSW
1767 services, DWORD size, LPDWORD needed, LPDWORD returned,
1768 LPDWORD resume_handle )
1770 DWORD err, i, offset, buflen, count, total_size = 0;
1771 struct enum_service_status *entry;
1772 const WCHAR *str;
1773 BYTE *buf;
1775 TRACE("%p 0x%x 0x%x %p %u %p %p %p\n", hmngr, type, state, services, size, needed,
1776 returned, resume_handle);
1778 if (!hmngr)
1780 SetLastError( ERROR_INVALID_HANDLE );
1781 return FALSE;
1783 if (!needed || !returned)
1785 SetLastError( ERROR_INVALID_ADDRESS );
1786 return FALSE;
1789 /* make sure we pass a valid pointer */
1790 buflen = max( size, sizeof(*services) );
1791 if (!(buf = heap_alloc( buflen )))
1793 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1794 return FALSE;
1797 __TRY
1799 err = svcctl_EnumServicesStatusW( hmngr, type, state, buf, buflen, needed, &count, resume_handle );
1801 __EXCEPT(rpc_filter)
1803 err = map_exception_code( GetExceptionCode() );
1805 __ENDTRY
1807 *returned = 0;
1808 if (err != ERROR_SUCCESS)
1810 /* double the needed size to fit the potentially larger ENUM_SERVICE_STATUSW */
1811 if (err == ERROR_MORE_DATA) *needed *= 2;
1812 heap_free( buf );
1813 SetLastError( err );
1814 return FALSE;
1817 entry = (struct enum_service_status *)buf;
1818 for (i = 0; i < count; i++)
1820 total_size += sizeof(*services);
1821 if (entry->service_name)
1823 str = (const WCHAR *)(buf + entry->service_name);
1824 total_size += (strlenW( str ) + 1) * sizeof(WCHAR);
1826 if (entry->display_name)
1828 str = (const WCHAR *)(buf + entry->display_name);
1829 total_size += (strlenW( str ) + 1) * sizeof(WCHAR);
1831 entry++;
1834 if (total_size > size)
1836 heap_free( buf );
1837 *needed = total_size;
1838 SetLastError( ERROR_MORE_DATA );
1839 return FALSE;
1842 offset = count * sizeof(*services);
1843 entry = (struct enum_service_status *)buf;
1844 for (i = 0; i < count; i++)
1846 DWORD str_size;
1847 str = (const WCHAR *)(buf + entry->service_name);
1848 str_size = (strlenW( str ) + 1) * sizeof(WCHAR);
1849 services[i].lpServiceName = (WCHAR *)((char *)services + offset);
1850 memcpy( services[i].lpServiceName, str, str_size );
1851 offset += str_size;
1853 if (!entry->display_name) services[i].lpDisplayName = NULL;
1854 else
1856 str = (const WCHAR *)(buf + entry->display_name);
1857 str_size = (strlenW( str ) + 1) * sizeof(WCHAR);
1858 services[i].lpDisplayName = (WCHAR *)((char *)services + offset);
1859 memcpy( services[i].lpDisplayName, str, str_size );
1860 offset += str_size;
1862 services[i].ServiceStatus = entry->service_status;
1863 entry++;
1866 heap_free( buf );
1867 *needed = 0;
1868 *returned = count;
1869 return TRUE;
1872 /******************************************************************************
1873 * EnumServicesStatusExA [ADVAPI32.@]
1875 BOOL WINAPI
1876 EnumServicesStatusExA( SC_HANDLE hmngr, SC_ENUM_TYPE level, DWORD type, DWORD state,
1877 LPBYTE buffer, DWORD size, LPDWORD needed, LPDWORD returned,
1878 LPDWORD resume_handle, LPCSTR group )
1880 BOOL ret;
1881 unsigned int i;
1882 ENUM_SERVICE_STATUS_PROCESSA *services = (ENUM_SERVICE_STATUS_PROCESSA *)buffer;
1883 ENUM_SERVICE_STATUS_PROCESSW *servicesW = NULL;
1884 WCHAR *groupW = NULL;
1885 DWORD sz, n;
1886 char *p;
1888 TRACE("%p %u 0x%x 0x%x %p %u %p %p %p %s\n", hmngr, level, type, state, buffer,
1889 size, needed, returned, resume_handle, debugstr_a(group));
1891 sz = max( 2 * size, sizeof(*servicesW) );
1892 if (!(servicesW = heap_alloc( sz )))
1894 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1895 return FALSE;
1897 if (group)
1899 int len = MultiByteToWideChar( CP_ACP, 0, group, -1, NULL, 0 );
1900 if (!(groupW = heap_alloc( len * sizeof(WCHAR) )))
1902 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1903 heap_free( servicesW );
1904 return FALSE;
1906 MultiByteToWideChar( CP_ACP, 0, group, -1, groupW, len * sizeof(WCHAR) );
1909 ret = EnumServicesStatusExW( hmngr, level, type, state, (BYTE *)servicesW, sz,
1910 needed, returned, resume_handle, groupW );
1911 if (!ret) goto done;
1913 p = (char *)services + *returned * sizeof(ENUM_SERVICE_STATUS_PROCESSA);
1914 n = size - (p - (char *)services);
1915 ret = FALSE;
1916 for (i = 0; i < *returned; i++)
1918 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpServiceName, -1, p, n, NULL, NULL );
1919 if (!sz) goto done;
1920 services[i].lpServiceName = p;
1921 p += sz;
1922 n -= sz;
1923 if (servicesW[i].lpDisplayName)
1925 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpDisplayName, -1, p, n, NULL, NULL );
1926 if (!sz) goto done;
1927 services[i].lpDisplayName = p;
1928 p += sz;
1929 n -= sz;
1931 else services[i].lpDisplayName = NULL;
1932 services[i].ServiceStatusProcess = servicesW[i].ServiceStatusProcess;
1935 ret = TRUE;
1937 done:
1938 heap_free( servicesW );
1939 heap_free( groupW );
1940 return ret;
1943 /******************************************************************************
1944 * EnumServicesStatusExW [ADVAPI32.@]
1946 BOOL WINAPI
1947 EnumServicesStatusExW( SC_HANDLE hmngr, SC_ENUM_TYPE level, DWORD type, DWORD state,
1948 LPBYTE buffer, DWORD size, LPDWORD needed, LPDWORD returned,
1949 LPDWORD resume_handle, LPCWSTR group )
1951 DWORD err, i, offset, buflen, count, total_size = 0;
1952 ENUM_SERVICE_STATUS_PROCESSW *services = (ENUM_SERVICE_STATUS_PROCESSW *)buffer;
1953 struct enum_service_status_process *entry;
1954 const WCHAR *str;
1955 BYTE *buf;
1957 TRACE("%p %u 0x%x 0x%x %p %u %p %p %p %s\n", hmngr, level, type, state, buffer,
1958 size, needed, returned, resume_handle, debugstr_w(group));
1960 if (level != SC_ENUM_PROCESS_INFO)
1962 SetLastError( ERROR_INVALID_LEVEL );
1963 return FALSE;
1965 if (!hmngr)
1967 SetLastError( ERROR_INVALID_HANDLE );
1968 return FALSE;
1970 if (!needed || !returned)
1972 SetLastError( ERROR_INVALID_ADDRESS );
1973 return FALSE;
1976 /* make sure we pass a valid pointer */
1977 buflen = max( size, sizeof(*services) );
1978 if (!(buf = heap_alloc( buflen )))
1980 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1981 return FALSE;
1984 __TRY
1986 err = svcctl_EnumServicesStatusExW( hmngr, SC_ENUM_PROCESS_INFO, type, state, buf, buflen, needed,
1987 &count, resume_handle, group );
1989 __EXCEPT(rpc_filter)
1991 err = map_exception_code( GetExceptionCode() );
1993 __ENDTRY
1995 *returned = 0;
1996 if (err != ERROR_SUCCESS)
1998 /* double the needed size to fit the potentially larger ENUM_SERVICE_STATUS_PROCESSW */
1999 if (err == ERROR_MORE_DATA) *needed *= 2;
2000 heap_free( buf );
2001 SetLastError( err );
2002 return FALSE;
2005 entry = (struct enum_service_status_process *)buf;
2006 for (i = 0; i < count; i++)
2008 total_size += sizeof(*services);
2009 if (entry->service_name)
2011 str = (const WCHAR *)(buf + entry->service_name);
2012 total_size += (strlenW( str ) + 1) * sizeof(WCHAR);
2014 if (entry->display_name)
2016 str = (const WCHAR *)(buf + entry->display_name);
2017 total_size += (strlenW( str ) + 1) * sizeof(WCHAR);
2019 entry++;
2022 if (total_size > size)
2024 heap_free( buf );
2025 *needed = total_size;
2026 SetLastError( ERROR_MORE_DATA );
2027 return FALSE;
2030 offset = count * sizeof(*services);
2031 entry = (struct enum_service_status_process *)buf;
2032 for (i = 0; i < count; i++)
2034 DWORD str_size;
2035 str = (const WCHAR *)(buf + entry->service_name);
2036 str_size = (strlenW( str ) + 1) * sizeof(WCHAR);
2037 services[i].lpServiceName = (WCHAR *)((char *)services + offset);
2038 memcpy( services[i].lpServiceName, str, str_size );
2039 offset += str_size;
2041 if (!entry->display_name) services[i].lpDisplayName = NULL;
2042 else
2044 str = (const WCHAR *)(buf + entry->display_name);
2045 str_size = (strlenW( str ) + 1) * sizeof(WCHAR);
2046 services[i].lpDisplayName = (WCHAR *)((char *)services + offset);
2047 memcpy( services[i].lpDisplayName, str, str_size );
2048 offset += str_size;
2050 services[i].ServiceStatusProcess = entry->service_status_process;
2051 entry++;
2054 heap_free( buf );
2055 *needed = 0;
2056 *returned = count;
2057 return TRUE;
2060 /******************************************************************************
2061 * GetServiceKeyNameA [ADVAPI32.@]
2063 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
2064 LPSTR lpServiceName, LPDWORD lpcchBuffer )
2066 LPWSTR lpDisplayNameW, lpServiceNameW;
2067 DWORD sizeW;
2068 BOOL ret = FALSE;
2070 TRACE("%p %s %p %p\n", hSCManager,
2071 debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
2073 lpDisplayNameW = SERV_dup(lpDisplayName);
2074 if (lpServiceName)
2075 lpServiceNameW = heap_alloc(*lpcchBuffer * sizeof(WCHAR));
2076 else
2077 lpServiceNameW = NULL;
2079 sizeW = *lpcchBuffer;
2080 if (!GetServiceKeyNameW(hSCManager, lpDisplayNameW, lpServiceNameW, &sizeW))
2082 if (lpServiceName && *lpcchBuffer)
2083 lpServiceName[0] = 0;
2084 *lpcchBuffer = sizeW*2; /* we can only provide an upper estimation of string length */
2085 goto cleanup;
2088 if (!WideCharToMultiByte(CP_ACP, 0, lpServiceNameW, (sizeW + 1), lpServiceName,
2089 *lpcchBuffer, NULL, NULL ))
2091 if (*lpcchBuffer && lpServiceName)
2092 lpServiceName[0] = 0;
2093 *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpServiceNameW, -1, NULL, 0, NULL, NULL);
2094 goto cleanup;
2097 /* lpcchBuffer not updated - same as in GetServiceDisplayNameA */
2098 ret = TRUE;
2100 cleanup:
2101 heap_free(lpServiceNameW);
2102 heap_free(lpDisplayNameW);
2103 return ret;
2106 /******************************************************************************
2107 * GetServiceKeyNameW [ADVAPI32.@]
2109 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
2110 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
2112 DWORD err;
2113 WCHAR buffer[2];
2114 DWORD size;
2116 TRACE("%p %s %p %p\n", hSCManager,
2117 debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
2119 if (!hSCManager)
2121 SetLastError( ERROR_INVALID_HANDLE );
2122 return FALSE;
2125 /* provide a buffer if the caller didn't */
2126 if (!lpServiceName || *lpcchBuffer < 2)
2128 lpServiceName = buffer;
2129 /* A size of 1 would be enough, but tests show that Windows returns 2,
2130 * probably because of a WCHAR/bytes mismatch in their code.
2132 *lpcchBuffer = 2;
2135 /* RPC call takes size excluding nul-terminator, whereas *lpcchBuffer
2136 * includes the nul-terminator on input. */
2137 size = *lpcchBuffer - 1;
2139 __TRY
2141 err = svcctl_GetServiceKeyNameW(hSCManager, lpDisplayName, lpServiceName,
2142 &size);
2144 __EXCEPT(rpc_filter)
2146 err = map_exception_code(GetExceptionCode());
2148 __ENDTRY
2150 /* The value of *lpcchBuffer excludes nul-terminator on output. */
2151 if (err == ERROR_SUCCESS || err == ERROR_INSUFFICIENT_BUFFER)
2152 *lpcchBuffer = size;
2154 if (err)
2155 SetLastError(err);
2156 return err == ERROR_SUCCESS;
2159 /******************************************************************************
2160 * QueryServiceLockStatusA [ADVAPI32.@]
2162 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
2163 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
2164 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2166 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2168 return FALSE;
2171 /******************************************************************************
2172 * QueryServiceLockStatusW [ADVAPI32.@]
2174 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
2175 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2176 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2178 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2180 return FALSE;
2183 /******************************************************************************
2184 * GetServiceDisplayNameA [ADVAPI32.@]
2186 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
2187 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
2189 LPWSTR lpServiceNameW, lpDisplayNameW;
2190 DWORD sizeW;
2191 BOOL ret = FALSE;
2193 TRACE("%p %s %p %p\n", hSCManager,
2194 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
2196 lpServiceNameW = SERV_dup(lpServiceName);
2197 if (lpDisplayName)
2198 lpDisplayNameW = heap_alloc(*lpcchBuffer * sizeof(WCHAR));
2199 else
2200 lpDisplayNameW = NULL;
2202 sizeW = *lpcchBuffer;
2203 if (!GetServiceDisplayNameW(hSCManager, lpServiceNameW, lpDisplayNameW, &sizeW))
2205 if (lpDisplayName && *lpcchBuffer)
2206 lpDisplayName[0] = 0;
2207 *lpcchBuffer = sizeW*2; /* we can only provide an upper estimation of string length */
2208 goto cleanup;
2211 if (!WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, (sizeW + 1), lpDisplayName,
2212 *lpcchBuffer, NULL, NULL ))
2214 if (*lpcchBuffer && lpDisplayName)
2215 lpDisplayName[0] = 0;
2216 *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, -1, NULL, 0, NULL, NULL);
2217 goto cleanup;
2220 /* probably due to a bug GetServiceDisplayNameA doesn't modify lpcchBuffer on success.
2221 * (but if the function succeeded it means that is a good upper estimation of the size) */
2222 ret = TRUE;
2224 cleanup:
2225 heap_free(lpDisplayNameW);
2226 heap_free(lpServiceNameW);
2227 return ret;
2230 /******************************************************************************
2231 * GetServiceDisplayNameW [ADVAPI32.@]
2233 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
2234 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
2236 DWORD err;
2237 DWORD size;
2238 WCHAR buffer[2];
2240 TRACE("%p %s %p %p\n", hSCManager,
2241 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
2243 if (!hSCManager)
2245 SetLastError( ERROR_INVALID_HANDLE );
2246 return FALSE;
2249 /* provide a buffer if the caller didn't */
2250 if (!lpDisplayName || *lpcchBuffer < 2)
2252 lpDisplayName = buffer;
2253 /* A size of 1 would be enough, but tests show that Windows returns 2,
2254 * probably because of a WCHAR/bytes mismatch in their code.
2256 *lpcchBuffer = 2;
2259 /* RPC call takes size excluding nul-terminator, whereas *lpcchBuffer
2260 * includes the nul-terminator on input. */
2261 size = *lpcchBuffer - 1;
2263 __TRY
2265 err = svcctl_GetServiceDisplayNameW(hSCManager, lpServiceName, lpDisplayName,
2266 &size);
2268 __EXCEPT(rpc_filter)
2270 err = map_exception_code(GetExceptionCode());
2272 __ENDTRY
2274 /* The value of *lpcchBuffer excludes nul-terminator on output. */
2275 if (err == ERROR_SUCCESS || err == ERROR_INSUFFICIENT_BUFFER)
2276 *lpcchBuffer = size;
2278 if (err)
2279 SetLastError(err);
2280 return err == ERROR_SUCCESS;
2283 /******************************************************************************
2284 * ChangeServiceConfigW [ADVAPI32.@]
2286 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
2287 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
2288 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
2289 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
2291 DWORD cb_pwd;
2292 DWORD err;
2294 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2295 hService, dwServiceType, dwStartType, dwErrorControl,
2296 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2297 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2298 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2300 cb_pwd = lpPassword ? (strlenW(lpPassword) + 1)*sizeof(WCHAR) : 0;
2302 __TRY
2304 err = svcctl_ChangeServiceConfigW(hService, dwServiceType,
2305 dwStartType, dwErrorControl, lpBinaryPathName, lpLoadOrderGroup, lpdwTagId,
2306 (const BYTE *)lpDependencies, multisz_cb(lpDependencies), lpServiceStartName,
2307 (const BYTE *)lpPassword, cb_pwd, lpDisplayName);
2309 __EXCEPT(rpc_filter)
2311 err = map_exception_code(GetExceptionCode());
2313 __ENDTRY
2315 if (err != ERROR_SUCCESS)
2316 SetLastError(err);
2318 return err == ERROR_SUCCESS;
2321 /******************************************************************************
2322 * ChangeServiceConfigA [ADVAPI32.@]
2324 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2325 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2326 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2327 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2329 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2330 LPWSTR wServiceStartName, wPassword, wDisplayName;
2331 BOOL r;
2333 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2334 hService, dwServiceType, dwStartType, dwErrorControl,
2335 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2336 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2337 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2339 wBinaryPathName = SERV_dup( lpBinaryPathName );
2340 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2341 wDependencies = SERV_dupmulti( lpDependencies );
2342 wServiceStartName = SERV_dup( lpServiceStartName );
2343 wPassword = SERV_dup( lpPassword );
2344 wDisplayName = SERV_dup( lpDisplayName );
2346 r = ChangeServiceConfigW( hService, dwServiceType,
2347 dwStartType, dwErrorControl, wBinaryPathName,
2348 wLoadOrderGroup, lpdwTagId, wDependencies,
2349 wServiceStartName, wPassword, wDisplayName);
2351 heap_free( wBinaryPathName );
2352 heap_free( wLoadOrderGroup );
2353 heap_free( wDependencies );
2354 heap_free( wServiceStartName );
2355 heap_free( wPassword );
2356 heap_free( wDisplayName );
2358 return r;
2361 /******************************************************************************
2362 * ChangeServiceConfig2A [ADVAPI32.@]
2364 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2365 LPVOID lpInfo)
2367 BOOL r = FALSE;
2369 TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo);
2371 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2373 LPSERVICE_DESCRIPTIONA sd = lpInfo;
2374 SERVICE_DESCRIPTIONW sdw;
2376 sdw.lpDescription = SERV_dup( sd->lpDescription );
2378 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2380 heap_free( sdw.lpDescription );
2382 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2384 LPSERVICE_FAILURE_ACTIONSA fa = lpInfo;
2385 SERVICE_FAILURE_ACTIONSW faw;
2387 faw.dwResetPeriod = fa->dwResetPeriod;
2388 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2389 faw.lpCommand = SERV_dup( fa->lpCommand );
2390 faw.cActions = fa->cActions;
2391 faw.lpsaActions = fa->lpsaActions;
2393 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2395 heap_free( faw.lpRebootMsg );
2396 heap_free( faw.lpCommand );
2398 else if (dwInfoLevel == SERVICE_CONFIG_PRESHUTDOWN_INFO)
2400 r = ChangeServiceConfig2W( hService, dwInfoLevel, lpInfo);
2402 else
2403 SetLastError( ERROR_INVALID_PARAMETER );
2405 return r;
2408 /******************************************************************************
2409 * ChangeServiceConfig2W [ADVAPI32.@]
2411 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2412 LPVOID lpInfo)
2414 DWORD err;
2416 __TRY
2418 SC_RPC_CONFIG_INFOW info;
2420 info.dwInfoLevel = dwInfoLevel;
2421 info.u.descr = lpInfo;
2422 err = svcctl_ChangeServiceConfig2W( hService, info );
2424 __EXCEPT(rpc_filter)
2426 err = map_exception_code(GetExceptionCode());
2428 __ENDTRY
2430 if (err != ERROR_SUCCESS)
2431 SetLastError(err);
2433 return err == ERROR_SUCCESS;
2436 NTSTATUS SERV_QueryServiceObjectSecurity(SC_HANDLE hService,
2437 SECURITY_INFORMATION dwSecurityInformation,
2438 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2439 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2441 SECURITY_DESCRIPTOR descriptor;
2442 NTSTATUS status;
2443 DWORD size;
2444 ACL acl;
2446 FIXME("%p %d %p %u %p - semi-stub\n", hService, dwSecurityInformation,
2447 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2449 if (dwSecurityInformation != DACL_SECURITY_INFORMATION)
2450 FIXME("information %d not supported\n", dwSecurityInformation);
2452 InitializeSecurityDescriptor(&descriptor, SECURITY_DESCRIPTOR_REVISION);
2454 InitializeAcl(&acl, sizeof(ACL), ACL_REVISION);
2455 SetSecurityDescriptorDacl(&descriptor, TRUE, &acl, TRUE);
2457 size = cbBufSize;
2458 status = RtlMakeSelfRelativeSD(&descriptor, lpSecurityDescriptor, &size);
2459 *pcbBytesNeeded = size;
2460 return status;
2463 /******************************************************************************
2464 * QueryServiceObjectSecurity [ADVAPI32.@]
2466 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2467 SECURITY_INFORMATION dwSecurityInformation,
2468 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2469 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2471 NTSTATUS status = SERV_QueryServiceObjectSecurity(hService, dwSecurityInformation, lpSecurityDescriptor,
2472 cbBufSize, pcbBytesNeeded);
2473 if (status != STATUS_SUCCESS)
2475 SetLastError(RtlNtStatusToDosError(status));
2476 return FALSE;
2478 return TRUE;
2481 /******************************************************************************
2482 * SetServiceObjectSecurity [ADVAPI32.@]
2484 * NOTES
2485 * - SetSecurityInfo should be updated to call this function once it's implemented.
2487 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2488 SECURITY_INFORMATION dwSecurityInformation,
2489 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2491 FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2492 return TRUE;
2495 /******************************************************************************
2496 * SetServiceBits [ADVAPI32.@]
2498 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2499 DWORD dwServiceBits,
2500 BOOL bSetBitsOn,
2501 BOOL bUpdateImmediately)
2503 FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2504 bSetBitsOn, bUpdateImmediately);
2505 return TRUE;
2508 /* thunk for calling the RegisterServiceCtrlHandler handler function */
2509 static DWORD WINAPI ctrl_handler_thunk( DWORD control, DWORD type, void *data, void *context )
2511 LPHANDLER_FUNCTION func = context;
2513 func( control );
2514 return ERROR_SUCCESS;
2517 /******************************************************************************
2518 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
2520 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerA( LPCSTR name, LPHANDLER_FUNCTION handler )
2522 return RegisterServiceCtrlHandlerExA( name, ctrl_handler_thunk, handler );
2525 /******************************************************************************
2526 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
2528 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR name, LPHANDLER_FUNCTION handler )
2530 return RegisterServiceCtrlHandlerExW( name, ctrl_handler_thunk, handler );
2533 /******************************************************************************
2534 * RegisterServiceCtrlHandlerExA [ADVAPI32.@]
2536 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR name, LPHANDLER_FUNCTION_EX handler, LPVOID context )
2538 LPWSTR nameW;
2539 SERVICE_STATUS_HANDLE ret;
2541 nameW = SERV_dup(name);
2542 ret = RegisterServiceCtrlHandlerExW( nameW, handler, context );
2543 heap_free( nameW );
2544 return ret;
2547 /******************************************************************************
2548 * RegisterServiceCtrlHandlerExW [ADVAPI32.@]
2550 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2551 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2553 service_data *service;
2554 SC_HANDLE hService = 0;
2556 TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2558 EnterCriticalSection( &service_cs );
2559 if ((service = find_service_by_name( lpServiceName )))
2561 service->handler = lpHandlerProc;
2562 service->context = lpContext;
2563 hService = service->handle;
2565 LeaveCriticalSection( &service_cs );
2567 if (!hService) SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
2568 return (SERVICE_STATUS_HANDLE)hService;
2571 /******************************************************************************
2572 * EnumDependentServicesA [ADVAPI32.@]
2574 BOOL WINAPI EnumDependentServicesA( SC_HANDLE hService, DWORD dwServiceState,
2575 LPENUM_SERVICE_STATUSA lpServices, DWORD cbBufSize,
2576 LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
2578 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
2579 lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
2581 *lpServicesReturned = 0;
2582 return TRUE;
2585 /******************************************************************************
2586 * EnumDependentServicesW [ADVAPI32.@]
2588 BOOL WINAPI EnumDependentServicesW( SC_HANDLE hService, DWORD dwServiceState,
2589 LPENUM_SERVICE_STATUSW lpServices, DWORD cbBufSize,
2590 LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
2592 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
2593 lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
2595 *lpServicesReturned = 0;
2596 return TRUE;
2599 /******************************************************************************
2600 * NotifyServiceStatusChangeW [ADVAPI32.@]
2602 DWORD WINAPI NotifyServiceStatusChangeW(SC_HANDLE hService, DWORD dwNotifyMask,
2603 SERVICE_NOTIFYW *pNotifyBuffer)
2605 DWORD dummy;
2606 BOOL ret;
2607 SERVICE_STATUS_PROCESS st;
2608 static int once;
2610 if (!once++) FIXME("%p 0x%x %p - semi-stub\n", hService, dwNotifyMask, pNotifyBuffer);
2612 ret = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (void*)&st, sizeof(st), &dummy);
2613 if (ret)
2615 /* dwNotifyMask is a set of bitflags in same order as SERVICE_ statuses */
2616 if (dwNotifyMask & (1 << (st.dwCurrentState - SERVICE_STOPPED)))
2618 pNotifyBuffer->dwNotificationStatus = ERROR_SUCCESS;
2619 memcpy(&pNotifyBuffer->ServiceStatus, &st, sizeof(pNotifyBuffer->ServiceStatus));
2620 pNotifyBuffer->dwNotificationTriggered = 1 << (st.dwCurrentState - SERVICE_STOPPED);
2621 pNotifyBuffer->pszServiceNames = NULL;
2622 TRACE("Queueing notification: 0x%x\n", pNotifyBuffer->dwNotificationTriggered);
2623 QueueUserAPC((PAPCFUNC)pNotifyBuffer->pfnNotifyCallback,
2624 GetCurrentThread(), (ULONG_PTR)pNotifyBuffer);
2628 /* TODO: If the service is not currently in a matching state, we should
2629 * tell `services` to monitor it. */
2631 return ERROR_SUCCESS;