comctl32: Use SetRect() instead of open coding it.
[wine.git] / dlls / advapi32 / service.c
blob0eb0a47f74429ac4e1b6a353527ebc98c4e753de
1 /*
2 * Win32 advapi functions
4 * Copyright 1995 Sven Verdoolaege
5 * Copyright 2005 Mike McCormack
6 * Copyright 2007 Rolf Kalbermatter
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include "config.h"
24 #include "wine/port.h"
26 #include <stdarg.h>
27 #include <string.h>
28 #include <time.h>
29 #include <assert.h>
31 #define NONAMELESSUNION
33 #include "ntstatus.h"
34 #define WIN32_NO_STATUS
35 #include "windef.h"
36 #include "winbase.h"
37 #include "winsvc.h"
38 #include "winerror.h"
39 #include "winreg.h"
40 #include "wine/unicode.h"
41 #include "wine/debug.h"
42 #include "winternl.h"
43 #include "lmcons.h"
44 #include "lmserver.h"
46 #include "svcctl.h"
48 #include "advapi32_misc.h"
50 #include "wine/exception.h"
52 WINE_DEFAULT_DEBUG_CHANNEL(service);
54 void __RPC_FAR * __RPC_USER MIDL_user_allocate(SIZE_T len)
56 return heap_alloc(len);
59 void __RPC_USER MIDL_user_free(void __RPC_FAR * ptr)
61 heap_free(ptr);
64 typedef struct service_data_t
66 LPHANDLER_FUNCTION_EX handler;
67 LPVOID context;
68 HANDLE thread;
69 SC_HANDLE handle;
70 SC_HANDLE full_access_handle;
71 BOOL unicode : 1;
72 union {
73 LPSERVICE_MAIN_FUNCTIONA a;
74 LPSERVICE_MAIN_FUNCTIONW w;
75 } proc;
76 LPWSTR args;
77 WCHAR name[1];
78 } service_data;
80 typedef struct dispatcher_data_t
82 SC_HANDLE manager;
83 HANDLE pipe;
84 } dispatcher_data;
86 static CRITICAL_SECTION service_cs;
87 static CRITICAL_SECTION_DEBUG service_cs_debug =
89 0, 0, &service_cs,
90 { &service_cs_debug.ProcessLocksList,
91 &service_cs_debug.ProcessLocksList },
92 0, 0, { (DWORD_PTR)(__FILE__ ": service_cs") }
94 static CRITICAL_SECTION service_cs = { &service_cs_debug, -1, 0, 0, 0, 0 };
96 static service_data **services;
97 static unsigned int nb_services;
98 static HANDLE service_event;
99 static HANDLE stop_event;
101 extern HANDLE CDECL __wine_make_process_system(void);
103 /******************************************************************************
104 * String management functions (same behaviour as strdup)
105 * NOTE: the caller of those functions is responsible for calling HeapFree
106 * in order to release the memory allocated by those functions.
108 LPWSTR SERV_dup( LPCSTR str )
110 UINT len;
111 LPWSTR wstr;
113 if( !str )
114 return NULL;
115 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
116 wstr = heap_alloc( len*sizeof (WCHAR) );
117 MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
118 return wstr;
121 static inline LPWSTR SERV_dupmulti(LPCSTR str)
123 UINT len = 0, n = 0;
124 LPWSTR wstr;
126 if( !str )
127 return NULL;
128 do {
129 len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
130 n += (strlen( &str[n] ) + 1);
131 } while (str[n]);
132 len++;
133 n++;
135 wstr = heap_alloc( len*sizeof (WCHAR) );
136 MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
137 return wstr;
140 static inline DWORD multisz_cb(LPCWSTR wmultisz)
142 const WCHAR *wptr = wmultisz;
144 if (wmultisz == NULL)
145 return 0;
147 while (*wptr)
148 wptr += lstrlenW(wptr)+1;
149 return (wptr - wmultisz + 1)*sizeof(WCHAR);
152 /******************************************************************************
153 * RPC connection with services.exe
155 static handle_t rpc_wstr_bind(RPC_WSTR str)
157 WCHAR transport[] = SVCCTL_TRANSPORT;
158 WCHAR endpoint[] = SVCCTL_ENDPOINT;
159 RPC_WSTR binding_str;
160 RPC_STATUS status;
161 handle_t rpc_handle;
163 status = RpcStringBindingComposeW(NULL, transport, str, endpoint, NULL, &binding_str);
164 if (status != RPC_S_OK)
166 ERR("RpcStringBindingComposeW failed (%d)\n", (DWORD)status);
167 return NULL;
170 status = RpcBindingFromStringBindingW(binding_str, &rpc_handle);
171 RpcStringFreeW(&binding_str);
173 if (status != RPC_S_OK)
175 ERR("Couldn't connect to services.exe: error code %u\n", (DWORD)status);
176 return NULL;
179 return rpc_handle;
182 static handle_t rpc_cstr_bind(RPC_CSTR str)
184 RPC_CSTR transport = (RPC_CSTR)SVCCTL_TRANSPORTA;
185 RPC_CSTR endpoint = (RPC_CSTR)SVCCTL_ENDPOINTA;
186 RPC_CSTR binding_str;
187 RPC_STATUS status;
188 handle_t rpc_handle;
190 status = RpcStringBindingComposeA(NULL, transport, str, endpoint, NULL, &binding_str);
191 if (status != RPC_S_OK)
193 ERR("RpcStringBindingComposeW failed (%d)\n", (DWORD)status);
194 return NULL;
197 status = RpcBindingFromStringBindingA(binding_str, &rpc_handle);
198 RpcStringFreeA(&binding_str);
200 if (status != RPC_S_OK)
202 ERR("Couldn't connect to services.exe: error code %u\n", (DWORD)status);
203 return NULL;
206 return rpc_handle;
209 DECLSPEC_HIDDEN handle_t __RPC_USER MACHINE_HANDLEA_bind(MACHINE_HANDLEA MachineName)
211 return rpc_cstr_bind((RPC_CSTR)MachineName);
214 DECLSPEC_HIDDEN void __RPC_USER MACHINE_HANDLEA_unbind(MACHINE_HANDLEA MachineName, handle_t h)
216 RpcBindingFree(&h);
219 DECLSPEC_HIDDEN handle_t __RPC_USER MACHINE_HANDLEW_bind(MACHINE_HANDLEW MachineName)
221 return rpc_wstr_bind((RPC_WSTR)MachineName);
224 DECLSPEC_HIDDEN void __RPC_USER MACHINE_HANDLEW_unbind(MACHINE_HANDLEW MachineName, handle_t h)
226 RpcBindingFree(&h);
229 DECLSPEC_HIDDEN handle_t __RPC_USER SVCCTL_HANDLEW_bind(SVCCTL_HANDLEW MachineName)
231 return rpc_wstr_bind((RPC_WSTR)MachineName);
234 DECLSPEC_HIDDEN void __RPC_USER SVCCTL_HANDLEW_unbind(SVCCTL_HANDLEW MachineName, handle_t h)
236 RpcBindingFree(&h);
239 static LONG WINAPI rpc_filter(EXCEPTION_POINTERS *eptr)
241 return I_RpcExceptionFilter(eptr->ExceptionRecord->ExceptionCode);
244 static DWORD map_exception_code(DWORD exception_code)
246 switch (exception_code)
248 case RPC_X_NULL_REF_POINTER:
249 return ERROR_INVALID_ADDRESS;
250 case RPC_X_ENUM_VALUE_OUT_OF_RANGE:
251 case RPC_X_BYTE_COUNT_TOO_SMALL:
252 return ERROR_INVALID_PARAMETER;
253 case RPC_S_INVALID_BINDING:
254 case RPC_X_SS_IN_NULL_CONTEXT:
255 return ERROR_INVALID_HANDLE;
256 default:
257 return exception_code;
261 /******************************************************************************
262 * Service IPC functions
264 static LPWSTR service_get_pipe_name(void)
266 static const WCHAR format[] = { '\\','\\','.','\\','p','i','p','e','\\',
267 'n','e','t','\\','N','t','C','o','n','t','r','o','l','P','i','p','e','%','u',0};
268 static const WCHAR service_current_key_str[] = { 'S','Y','S','T','E','M','\\',
269 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
270 'C','o','n','t','r','o','l','\\',
271 'S','e','r','v','i','c','e','C','u','r','r','e','n','t',0};
272 LPWSTR name;
273 DWORD len;
274 HKEY service_current_key;
275 DWORD service_current;
276 LONG ret;
277 DWORD type;
279 ret = RegOpenKeyExW(HKEY_LOCAL_MACHINE, service_current_key_str, 0,
280 KEY_QUERY_VALUE, &service_current_key);
281 if (ret != ERROR_SUCCESS)
282 return NULL;
283 len = sizeof(service_current);
284 ret = RegQueryValueExW(service_current_key, NULL, NULL, &type,
285 (BYTE *)&service_current, &len);
286 RegCloseKey(service_current_key);
287 if (ret != ERROR_SUCCESS || type != REG_DWORD)
288 return NULL;
289 len = sizeof(format)/sizeof(WCHAR) + 10 /* strlenW("4294967295") */;
290 name = heap_alloc(len * sizeof(WCHAR));
291 if (!name)
292 return NULL;
293 snprintfW(name, len, format, service_current);
294 return name;
297 static HANDLE service_open_pipe(void)
299 LPWSTR szPipe = service_get_pipe_name();
300 HANDLE handle = INVALID_HANDLE_VALUE;
302 do {
303 handle = CreateFileW(szPipe, GENERIC_READ|GENERIC_WRITE,
304 0, NULL, OPEN_ALWAYS, 0, NULL);
305 if (handle != INVALID_HANDLE_VALUE)
306 break;
307 if (GetLastError() != ERROR_PIPE_BUSY)
308 break;
309 } while (WaitNamedPipeW(szPipe, NMPWAIT_USE_DEFAULT_WAIT));
310 heap_free(szPipe);
312 return handle;
315 static service_data *find_service_by_name( const WCHAR *name )
317 unsigned int i;
319 if (nb_services == 1) /* only one service (FIXME: should depend on OWN_PROCESS etc.) */
320 return services[0];
321 for (i = 0; i < nb_services; i++)
322 if (!strcmpiW( name, services[i]->name )) return services[i];
323 return NULL;
326 /******************************************************************************
327 * service_thread
329 * Call into the main service routine provided by StartServiceCtrlDispatcher.
331 static DWORD WINAPI service_thread(LPVOID arg)
333 service_data *info = arg;
334 LPWSTR str = info->args;
335 DWORD argc = 0, len = 0;
337 TRACE("%p\n", arg);
339 while (str[len])
341 len += strlenW(&str[len]) + 1;
342 argc++;
344 len++;
346 if (info->unicode)
348 LPWSTR *argv, p;
350 argv = heap_alloc((argc+1)*sizeof(LPWSTR));
351 for (argc=0, p=str; *p; p += strlenW(p) + 1)
352 argv[argc++] = p;
353 argv[argc] = NULL;
355 info->proc.w(argc, argv);
356 heap_free(argv);
358 else
360 LPSTR strA, *argv, p;
361 DWORD lenA;
363 lenA = WideCharToMultiByte(CP_ACP,0, str, len, NULL, 0, NULL, NULL);
364 strA = heap_alloc(lenA);
365 WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL);
367 argv = heap_alloc((argc+1)*sizeof(LPSTR));
368 for (argc=0, p=strA; *p; p += strlen(p) + 1)
369 argv[argc++] = p;
370 argv[argc] = NULL;
372 info->proc.a(argc, argv);
373 heap_free(argv);
374 heap_free(strA);
376 return 0;
379 /******************************************************************************
380 * service_handle_start
382 static DWORD service_handle_start(service_data *service, const WCHAR *data, DWORD count)
384 TRACE("%s argsize %u\n", debugstr_w(service->name), count);
386 if (service->thread)
388 WARN("service is not stopped\n");
389 return ERROR_SERVICE_ALREADY_RUNNING;
392 heap_free(service->args);
393 service->args = heap_alloc(count * sizeof(WCHAR));
394 memcpy( service->args, data, count * sizeof(WCHAR) );
395 service->thread = CreateThread( NULL, 0, service_thread,
396 service, 0, NULL );
397 SetEvent( service_event ); /* notify the main loop */
398 return 0;
401 /******************************************************************************
402 * service_handle_control
404 static DWORD service_handle_control(const service_data *service, DWORD dwControl)
406 DWORD ret = ERROR_INVALID_SERVICE_CONTROL;
408 TRACE("%s control %u\n", debugstr_w(service->name), dwControl);
410 if (service->handler)
411 ret = service->handler(dwControl, 0, NULL, service->context);
412 return ret;
415 /******************************************************************************
416 * service_control_dispatcher
418 static DWORD WINAPI service_control_dispatcher(LPVOID arg)
420 dispatcher_data *disp = arg;
422 /* dispatcher loop */
423 while (1)
425 service_data *service;
426 service_start_info info;
427 WCHAR *data = NULL;
428 BOOL r;
429 DWORD data_size = 0, count, result;
431 r = ReadFile( disp->pipe, &info, FIELD_OFFSET(service_start_info,data), &count, NULL );
432 if (!r)
434 if (GetLastError() != ERROR_BROKEN_PIPE)
435 ERR( "pipe read failed error %u\n", GetLastError() );
436 break;
438 if (count != FIELD_OFFSET(service_start_info,data))
440 ERR( "partial pipe read %u\n", count );
441 break;
443 if (count < info.total_size)
445 data_size = info.total_size - FIELD_OFFSET(service_start_info,data);
446 data = heap_alloc( data_size );
447 r = ReadFile( disp->pipe, data, data_size, &count, NULL );
448 if (!r)
450 if (GetLastError() != ERROR_BROKEN_PIPE)
451 ERR( "pipe read failed error %u\n", GetLastError() );
452 heap_free( data );
453 break;
455 if (count != data_size)
457 ERR( "partial pipe read %u/%u\n", count, data_size );
458 heap_free( data );
459 break;
463 /* find the service */
465 if (!(service = find_service_by_name( data )))
467 FIXME( "got request %u for unknown service %s\n", info.cmd, debugstr_w(data));
468 result = ERROR_INVALID_PARAMETER;
469 goto done;
472 TRACE( "got request %u for service %s\n", info.cmd, debugstr_w(data) );
474 /* handle the request */
475 switch (info.cmd)
477 case WINESERV_STARTINFO:
478 if (!service->handle)
480 if (!(service->handle = OpenServiceW( disp->manager, data, SERVICE_SET_STATUS )) ||
481 !(service->full_access_handle = OpenServiceW( disp->manager, data,
482 GENERIC_READ|GENERIC_WRITE )))
483 FIXME( "failed to open service %s\n", debugstr_w(data) );
485 result = service_handle_start(service, data, data_size / sizeof(WCHAR));
486 break;
487 case WINESERV_SENDCONTROL:
488 result = service_handle_control(service, info.control);
489 break;
490 default:
491 ERR("received invalid command %u\n", info.cmd);
492 result = ERROR_INVALID_PARAMETER;
493 break;
496 done:
497 WriteFile( disp->pipe, &result, sizeof(result), &count, NULL );
498 heap_free( data );
501 CloseHandle( disp->pipe );
502 CloseServiceHandle( disp->manager );
503 heap_free( disp );
504 return 1;
507 /******************************************************************************
508 * service_run_main_thread
510 static BOOL service_run_main_thread(void)
512 DWORD i, n, ret;
513 HANDLE wait_handles[MAXIMUM_WAIT_OBJECTS];
514 UINT wait_services[MAXIMUM_WAIT_OBJECTS];
515 dispatcher_data *disp = heap_alloc( sizeof(*disp) );
517 disp->manager = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
518 if (!disp->manager)
520 ERR("failed to open service manager error %u\n", GetLastError());
521 heap_free( disp );
522 return FALSE;
525 disp->pipe = service_open_pipe();
526 if (disp->pipe == INVALID_HANDLE_VALUE)
528 WARN("failed to create control pipe error %u\n", GetLastError());
529 CloseServiceHandle( disp->manager );
530 heap_free( disp );
531 SetLastError( ERROR_FAILED_SERVICE_CONTROLLER_CONNECT );
532 return FALSE;
535 service_event = CreateEventW( NULL, FALSE, FALSE, NULL );
536 stop_event = CreateEventW( NULL, FALSE, FALSE, NULL );
538 /* FIXME: service_control_dispatcher should be merged into the main thread */
539 wait_handles[0] = __wine_make_process_system();
540 wait_handles[1] = CreateThread( NULL, 0, service_control_dispatcher, disp, 0, NULL );
541 wait_handles[2] = service_event;
542 wait_handles[3] = stop_event;
544 TRACE("Starting %d services running as process %d\n",
545 nb_services, GetCurrentProcessId());
547 /* wait for all the threads to pack up and exit */
548 for (;;)
550 EnterCriticalSection( &service_cs );
551 for (i = 0, n = 4; i < nb_services && n < MAXIMUM_WAIT_OBJECTS; i++)
553 if (!services[i]->thread) continue;
554 wait_services[n] = i;
555 wait_handles[n++] = services[i]->thread;
557 LeaveCriticalSection( &service_cs );
559 ret = WaitForMultipleObjects( n, wait_handles, FALSE, INFINITE );
560 if (!ret) /* system process event */
562 SERVICE_STATUS st;
563 SERVICE_PRESHUTDOWN_INFO spi;
564 DWORD timeout = 5000;
565 BOOL res;
567 EnterCriticalSection( &service_cs );
568 n = 0;
569 for (i = 0; i < nb_services && n < MAXIMUM_WAIT_OBJECTS; i++)
571 if (!services[i]->thread) continue;
573 res = QueryServiceStatus(services[i]->full_access_handle, &st);
574 ret = ERROR_SUCCESS;
575 if (res && (st.dwControlsAccepted & SERVICE_ACCEPT_PRESHUTDOWN))
577 res = QueryServiceConfig2W( services[i]->full_access_handle, SERVICE_CONFIG_PRESHUTDOWN_INFO,
578 (LPBYTE)&spi, sizeof(spi), &i );
579 if (res)
581 FIXME("service should be able to delay shutdown\n");
582 timeout += spi.dwPreshutdownTimeout;
583 ret = service_handle_control( services[i], SERVICE_CONTROL_PRESHUTDOWN );
584 wait_handles[n++] = services[i]->thread;
587 else if (res && (st.dwControlsAccepted & SERVICE_ACCEPT_SHUTDOWN))
589 ret = service_handle_control( services[i], SERVICE_CONTROL_SHUTDOWN );
590 wait_handles[n++] = services[i]->thread;
593 LeaveCriticalSection( &service_cs );
595 TRACE("last user process exited, shutting down (timeout: %d)\n", timeout);
596 WaitForMultipleObjects( n, wait_handles, TRUE, timeout );
597 ExitProcess(0);
599 else if (ret == 1)
601 TRACE( "control dispatcher exited, shutting down\n" );
602 /* FIXME: we should maybe send a shutdown control to running services */
603 ExitProcess(0);
605 else if (ret == 2)
607 continue; /* rebuild the list */
609 else if (ret == 3)
611 return TRUE;
613 else if (ret < n)
615 services[wait_services[ret]]->thread = 0;
616 CloseHandle( wait_handles[ret] );
618 else return FALSE;
622 /******************************************************************************
623 * StartServiceCtrlDispatcherA [ADVAPI32.@]
625 * See StartServiceCtrlDispatcherW.
627 BOOL WINAPI StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *servent )
629 service_data *info;
630 unsigned int i;
632 TRACE("%p\n", servent);
634 if (nb_services)
636 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
637 return FALSE;
639 while (servent[nb_services].lpServiceName) nb_services++;
640 if (!nb_services)
642 SetLastError( ERROR_INVALID_PARAMETER );
643 return FALSE;
646 services = heap_alloc( nb_services * sizeof(*services) );
648 for (i = 0; i < nb_services; i++)
650 DWORD len = MultiByteToWideChar(CP_ACP, 0, servent[i].lpServiceName, -1, NULL, 0);
651 DWORD sz = FIELD_OFFSET( service_data, name[len] );
652 info = heap_alloc_zero( sz );
653 MultiByteToWideChar(CP_ACP, 0, servent[i].lpServiceName, -1, info->name, len);
654 info->proc.a = servent[i].lpServiceProc;
655 info->unicode = FALSE;
656 services[i] = info;
659 return service_run_main_thread();
662 /******************************************************************************
663 * StartServiceCtrlDispatcherW [ADVAPI32.@]
665 * Connects a process containing one or more services to the service control
666 * manager.
668 * PARAMS
669 * servent [I] A list of the service names and service procedures
671 * RETURNS
672 * Success: TRUE.
673 * Failure: FALSE.
675 BOOL WINAPI StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW *servent )
677 service_data *info;
678 unsigned int i;
680 TRACE("%p\n", servent);
682 if (nb_services)
684 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
685 return FALSE;
687 while (servent[nb_services].lpServiceName) nb_services++;
688 if (!nb_services)
690 SetLastError( ERROR_INVALID_PARAMETER );
691 return FALSE;
694 services = heap_alloc( nb_services * sizeof(*services) );
696 for (i = 0; i < nb_services; i++)
698 DWORD len = strlenW(servent[i].lpServiceName) + 1;
699 DWORD sz = FIELD_OFFSET( service_data, name[len] );
700 info = heap_alloc_zero( sz );
701 strcpyW(info->name, servent[i].lpServiceName);
702 info->proc.w = servent[i].lpServiceProc;
703 info->unicode = TRUE;
704 services[i] = info;
707 return service_run_main_thread();
710 /******************************************************************************
711 * LockServiceDatabase [ADVAPI32.@]
713 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
715 SC_RPC_LOCK hLock = NULL;
716 DWORD err;
718 TRACE("%p\n",hSCManager);
720 __TRY
722 err = svcctl_LockServiceDatabase(hSCManager, &hLock);
724 __EXCEPT(rpc_filter)
726 err = map_exception_code(GetExceptionCode());
728 __ENDTRY
729 if (err != ERROR_SUCCESS)
731 SetLastError(err);
732 return NULL;
734 return hLock;
737 /******************************************************************************
738 * UnlockServiceDatabase [ADVAPI32.@]
740 BOOL WINAPI UnlockServiceDatabase (SC_LOCK ScLock)
742 DWORD err;
743 SC_RPC_LOCK hRpcLock = ScLock;
745 TRACE("%p\n",ScLock);
747 __TRY
749 err = svcctl_UnlockServiceDatabase(&hRpcLock);
751 __EXCEPT(rpc_filter)
753 err = map_exception_code(GetExceptionCode());
755 __ENDTRY
756 if (err != ERROR_SUCCESS)
758 SetLastError(err);
759 return FALSE;
761 return TRUE;
764 /******************************************************************************
765 * SetServiceStatus [ADVAPI32.@]
767 * PARAMS
768 * hService []
769 * lpStatus []
771 BOOL WINAPI
772 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
774 DWORD err;
776 TRACE("%p %x %x %x %x %x %x %x\n", hService,
777 lpStatus->dwServiceType, lpStatus->dwCurrentState,
778 lpStatus->dwControlsAccepted, lpStatus->dwWin32ExitCode,
779 lpStatus->dwServiceSpecificExitCode, lpStatus->dwCheckPoint,
780 lpStatus->dwWaitHint);
782 __TRY
784 err = svcctl_SetServiceStatus( hService, lpStatus );
786 __EXCEPT(rpc_filter)
788 err = map_exception_code(GetExceptionCode());
790 __ENDTRY
791 if (err != ERROR_SUCCESS)
793 SetLastError(err);
794 return FALSE;
797 if (lpStatus->dwCurrentState == SERVICE_STOPPED) {
798 SetEvent(stop_event);
799 CloseServiceHandle((SC_HANDLE)hService);
802 return TRUE;
806 /******************************************************************************
807 * OpenSCManagerA [ADVAPI32.@]
809 * Establish a connection to the service control manager and open its database.
811 * PARAMS
812 * lpMachineName [I] Pointer to machine name string
813 * lpDatabaseName [I] Pointer to database name string
814 * dwDesiredAccess [I] Type of access
816 * RETURNS
817 * Success: A Handle to the service control manager database
818 * Failure: NULL
820 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
821 DWORD dwDesiredAccess )
823 LPWSTR machineW, databaseW;
824 SC_HANDLE ret;
826 machineW = SERV_dup(lpMachineName);
827 databaseW = SERV_dup(lpDatabaseName);
828 ret = OpenSCManagerW(machineW, databaseW, dwDesiredAccess);
829 heap_free(databaseW);
830 heap_free(machineW);
831 return ret;
834 /******************************************************************************
835 * OpenSCManagerW [ADVAPI32.@]
837 * See OpenSCManagerA.
839 DWORD SERV_OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
840 DWORD dwDesiredAccess, SC_HANDLE *handle )
842 DWORD r;
844 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName),
845 debugstr_w(lpDatabaseName), dwDesiredAccess);
847 __TRY
849 r = svcctl_OpenSCManagerW(lpMachineName, lpDatabaseName, dwDesiredAccess, (SC_RPC_HANDLE *)handle);
851 __EXCEPT(rpc_filter)
853 r = map_exception_code(GetExceptionCode());
855 __ENDTRY
857 if (r!=ERROR_SUCCESS)
858 *handle = 0;
860 TRACE("returning %p\n", *handle);
861 return r;
864 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
865 DWORD dwDesiredAccess )
867 SC_HANDLE handle = 0;
868 DWORD r;
870 r = SERV_OpenSCManagerW(lpMachineName, lpDatabaseName, dwDesiredAccess, &handle);
871 if (r!=ERROR_SUCCESS)
872 SetLastError(r);
873 return handle;
876 /******************************************************************************
877 * ControlService [ADVAPI32.@]
879 * Send a control code to a service.
881 * PARAMS
882 * hService [I] Handle of the service control manager database
883 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
884 * lpServiceStatus [O] Destination for the status of the service, if available
886 * RETURNS
887 * Success: TRUE.
888 * Failure: FALSE.
890 * BUGS
891 * Unlike M$' implementation, control requests are not serialized and may be
892 * processed asynchronously.
894 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
895 LPSERVICE_STATUS lpServiceStatus )
897 DWORD err;
899 TRACE("%p %d %p\n", hService, dwControl, lpServiceStatus);
901 __TRY
903 err = svcctl_ControlService(hService, dwControl, lpServiceStatus);
905 __EXCEPT(rpc_filter)
907 err = map_exception_code(GetExceptionCode());
909 __ENDTRY
910 if (err != ERROR_SUCCESS)
912 SetLastError(err);
913 return FALSE;
916 return TRUE;
919 /******************************************************************************
920 * CloseServiceHandle [ADVAPI32.@]
922 * Close a handle to a service or the service control manager database.
924 * PARAMS
925 * hSCObject [I] Handle to service or service control manager database
927 * RETURNS
928 * Success: TRUE
929 * Failure: FALSE
931 BOOL WINAPI
932 CloseServiceHandle( SC_HANDLE hSCObject )
934 DWORD err;
936 TRACE("%p\n", hSCObject);
938 __TRY
940 err = svcctl_CloseServiceHandle((SC_RPC_HANDLE *)&hSCObject);
942 __EXCEPT(rpc_filter)
944 err = map_exception_code(GetExceptionCode());
946 __ENDTRY
948 if (err != ERROR_SUCCESS)
950 SetLastError(err);
951 return FALSE;
953 return TRUE;
957 /******************************************************************************
958 * OpenServiceA [ADVAPI32.@]
960 * Open a handle to a service.
962 * PARAMS
963 * hSCManager [I] Handle of the service control manager database
964 * lpServiceName [I] Name of the service to open
965 * dwDesiredAccess [I] Access required to the service
967 * RETURNS
968 * Success: Handle to the service
969 * Failure: NULL
971 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
972 DWORD dwDesiredAccess )
974 LPWSTR lpServiceNameW;
975 SC_HANDLE ret;
977 TRACE("%p %s 0x%08x\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
979 lpServiceNameW = SERV_dup(lpServiceName);
980 ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
981 heap_free(lpServiceNameW);
982 return ret;
986 /******************************************************************************
987 * OpenServiceW [ADVAPI32.@]
989 * See OpenServiceA.
991 DWORD SERV_OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
992 DWORD dwDesiredAccess, SC_HANDLE *handle )
994 DWORD err;
996 TRACE("%p %s 0x%08x\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
998 if (!hSCManager)
999 return ERROR_INVALID_HANDLE;
1001 __TRY
1003 err = svcctl_OpenServiceW(hSCManager, lpServiceName, dwDesiredAccess, (SC_RPC_HANDLE *)handle);
1005 __EXCEPT(rpc_filter)
1007 err = map_exception_code(GetExceptionCode());
1009 __ENDTRY
1011 if (err != ERROR_SUCCESS)
1012 *handle = 0;
1014 TRACE("returning %p\n", *handle);
1015 return err;
1018 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1019 DWORD dwDesiredAccess)
1021 SC_HANDLE handle = 0;
1022 DWORD err;
1024 err = SERV_OpenServiceW(hSCManager, lpServiceName, dwDesiredAccess, &handle);
1025 if (err != ERROR_SUCCESS)
1026 SetLastError(err);
1027 return handle;
1030 /******************************************************************************
1031 * CreateServiceW [ADVAPI32.@]
1033 SC_HANDLE WINAPI
1034 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1035 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
1036 DWORD dwServiceType, DWORD dwStartType,
1037 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1038 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1039 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
1040 LPCWSTR lpPassword )
1042 SC_HANDLE handle = 0;
1043 DWORD err;
1044 SIZE_T passwdlen;
1046 TRACE("%p %s %s\n", hSCManager,
1047 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
1049 if (!hSCManager)
1051 SetLastError( ERROR_INVALID_HANDLE );
1052 return 0;
1055 if (lpPassword)
1056 passwdlen = (strlenW(lpPassword) + 1) * sizeof(WCHAR);
1057 else
1058 passwdlen = 0;
1060 __TRY
1062 BOOL is_wow64;
1064 IsWow64Process(GetCurrentProcess(), &is_wow64);
1066 if (is_wow64)
1067 err = svcctl_CreateServiceWOW64W(hSCManager, lpServiceName,
1068 lpDisplayName, dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1069 lpBinaryPathName, lpLoadOrderGroup, lpdwTagId, (const BYTE*)lpDependencies,
1070 multisz_cb(lpDependencies), lpServiceStartName, (const BYTE*)lpPassword, passwdlen,
1071 (SC_RPC_HANDLE *)&handle);
1072 else
1073 err = svcctl_CreateServiceW(hSCManager, lpServiceName,
1074 lpDisplayName, dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1075 lpBinaryPathName, lpLoadOrderGroup, lpdwTagId, (const BYTE*)lpDependencies,
1076 multisz_cb(lpDependencies), lpServiceStartName, (const BYTE*)lpPassword, passwdlen,
1077 (SC_RPC_HANDLE *)&handle);
1079 __EXCEPT(rpc_filter)
1081 err = map_exception_code(GetExceptionCode());
1083 __ENDTRY
1085 if (err != ERROR_SUCCESS)
1087 SetLastError(err);
1088 handle = 0;
1090 return handle;
1094 /******************************************************************************
1095 * CreateServiceA [ADVAPI32.@]
1097 SC_HANDLE WINAPI
1098 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1099 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1100 DWORD dwServiceType, DWORD dwStartType,
1101 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1102 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1103 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1104 LPCSTR lpPassword )
1106 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1107 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1108 SC_HANDLE r;
1110 TRACE("%p %s %s\n", hSCManager,
1111 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1113 lpServiceNameW = SERV_dup( lpServiceName );
1114 lpDisplayNameW = SERV_dup( lpDisplayName );
1115 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1116 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1117 lpDependenciesW = SERV_dupmulti( lpDependencies );
1118 lpServiceStartNameW = SERV_dup( lpServiceStartName );
1119 lpPasswordW = SERV_dup( lpPassword );
1121 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1122 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1123 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1124 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1126 heap_free( lpServiceNameW );
1127 heap_free( lpDisplayNameW );
1128 heap_free( lpBinaryPathNameW );
1129 heap_free( lpLoadOrderGroupW );
1130 heap_free( lpDependenciesW );
1131 heap_free( lpServiceStartNameW );
1132 heap_free( lpPasswordW );
1134 return r;
1138 /******************************************************************************
1139 * DeleteService [ADVAPI32.@]
1141 * Delete a service from the service control manager database.
1143 * PARAMS
1144 * hService [I] Handle of the service to delete
1146 * RETURNS
1147 * Success: TRUE
1148 * Failure: FALSE
1150 BOOL WINAPI DeleteService( SC_HANDLE hService )
1152 DWORD err;
1154 TRACE("%p\n", hService);
1156 __TRY
1158 err = svcctl_DeleteService(hService);
1160 __EXCEPT(rpc_filter)
1162 err = map_exception_code(GetExceptionCode());
1164 __ENDTRY
1165 if (err != 0)
1167 SetLastError(err);
1168 return FALSE;
1171 return TRUE;
1175 /******************************************************************************
1176 * StartServiceA [ADVAPI32.@]
1178 * Start a service
1180 * PARAMS
1181 * hService [I] Handle of service
1182 * dwNumServiceArgs [I] Number of arguments
1183 * lpServiceArgVectors [I] Address of array of argument strings
1185 * NOTES
1186 * - NT implements this function using an obscure RPC call.
1187 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1188 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1189 * - This will only work for shared address space. How should the service
1190 * args be transferred when address spaces are separated?
1191 * - Can only start one service at a time.
1192 * - Has no concept of privilege.
1194 * RETURNS
1195 * Success: TRUE.
1196 * Failure: FALSE
1198 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1199 LPCSTR *lpServiceArgVectors )
1201 LPWSTR *lpwstr=NULL;
1202 unsigned int i;
1203 BOOL r;
1205 TRACE("(%p,%d,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1207 if (dwNumServiceArgs)
1208 lpwstr = heap_alloc( dwNumServiceArgs*sizeof(LPWSTR) );
1210 for(i=0; i<dwNumServiceArgs; i++)
1211 lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1213 r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1215 if (dwNumServiceArgs)
1217 for(i=0; i<dwNumServiceArgs; i++)
1218 heap_free(lpwstr[i]);
1219 heap_free(lpwstr);
1222 return r;
1226 /******************************************************************************
1227 * StartServiceW [ADVAPI32.@]
1229 * See StartServiceA.
1231 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1232 LPCWSTR *lpServiceArgVectors)
1234 DWORD err;
1236 TRACE("%p %d %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1238 __TRY
1240 err = svcctl_StartServiceW(hService, dwNumServiceArgs, lpServiceArgVectors);
1242 __EXCEPT(rpc_filter)
1244 err = map_exception_code(GetExceptionCode());
1246 __ENDTRY
1247 if (err != ERROR_SUCCESS)
1249 SetLastError(err);
1250 return FALSE;
1253 return TRUE;
1256 /******************************************************************************
1257 * QueryServiceStatus [ADVAPI32.@]
1259 * PARAMS
1260 * hService [I] Handle to service to get information about
1261 * lpservicestatus [O] buffer to receive the status information for the service
1264 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1265 LPSERVICE_STATUS lpservicestatus)
1267 SERVICE_STATUS_PROCESS SvcStatusData;
1268 BOOL ret;
1269 DWORD dummy;
1271 TRACE("%p %p\n", hService, lpservicestatus);
1273 if (!hService)
1275 SetLastError(ERROR_INVALID_HANDLE);
1276 return FALSE;
1278 if (!lpservicestatus)
1280 SetLastError(ERROR_INVALID_ADDRESS);
1281 return FALSE;
1284 ret = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&SvcStatusData,
1285 sizeof(SERVICE_STATUS_PROCESS), &dummy);
1286 if (ret) memcpy(lpservicestatus, &SvcStatusData, sizeof(SERVICE_STATUS)) ;
1287 return ret;
1291 /******************************************************************************
1292 * QueryServiceStatusEx [ADVAPI32.@]
1294 * Get information about a service.
1296 * PARAMS
1297 * hService [I] Handle to service to get information about
1298 * InfoLevel [I] Level of information to get
1299 * lpBuffer [O] Destination for requested information
1300 * cbBufSize [I] Size of lpBuffer in bytes
1301 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1303 * RETURNS
1304 * Success: TRUE
1305 * FAILURE: FALSE
1307 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1308 LPBYTE lpBuffer, DWORD cbBufSize,
1309 LPDWORD pcbBytesNeeded)
1311 DWORD err;
1313 TRACE("%p %d %p %d %p\n", hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1315 if (InfoLevel != SC_STATUS_PROCESS_INFO)
1317 err = ERROR_INVALID_LEVEL;
1319 else if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
1321 *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
1322 err = ERROR_INSUFFICIENT_BUFFER;
1324 else
1326 __TRY
1328 err = svcctl_QueryServiceStatusEx(hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1330 __EXCEPT(rpc_filter)
1332 err = map_exception_code(GetExceptionCode());
1334 __ENDTRY
1336 if (err != ERROR_SUCCESS)
1338 SetLastError(err);
1339 return FALSE;
1341 return TRUE;
1344 /******************************************************************************
1345 * QueryServiceConfigA [ADVAPI32.@]
1347 BOOL WINAPI QueryServiceConfigA( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGA config,
1348 DWORD size, LPDWORD needed )
1350 DWORD n;
1351 LPSTR p, buffer;
1352 BOOL ret;
1353 QUERY_SERVICE_CONFIGW *configW;
1355 TRACE("%p %p %d %p\n", hService, config, size, needed);
1357 if (!(buffer = heap_alloc( 2 * size )))
1359 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1360 return FALSE;
1362 configW = (QUERY_SERVICE_CONFIGW *)buffer;
1363 ret = QueryServiceConfigW( hService, configW, 2 * size, needed );
1364 if (!ret) goto done;
1366 config->dwServiceType = configW->dwServiceType;
1367 config->dwStartType = configW->dwStartType;
1368 config->dwErrorControl = configW->dwErrorControl;
1369 config->lpBinaryPathName = NULL;
1370 config->lpLoadOrderGroup = NULL;
1371 config->dwTagId = configW->dwTagId;
1372 config->lpDependencies = NULL;
1373 config->lpServiceStartName = NULL;
1374 config->lpDisplayName = NULL;
1376 p = (LPSTR)(config + 1);
1377 n = size - sizeof(*config);
1378 ret = FALSE;
1380 #define MAP_STR(str) \
1381 do { \
1382 if (configW->str) \
1384 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1385 if (!sz) goto done; \
1386 config->str = p; \
1387 p += sz; \
1388 n -= sz; \
1390 } while (0)
1392 MAP_STR( lpBinaryPathName );
1393 MAP_STR( lpLoadOrderGroup );
1394 MAP_STR( lpDependencies );
1395 MAP_STR( lpServiceStartName );
1396 MAP_STR( lpDisplayName );
1397 #undef MAP_STR
1399 *needed = p - (LPSTR)config;
1400 ret = TRUE;
1402 done:
1403 heap_free( buffer );
1404 return ret;
1407 static DWORD move_string_to_buffer(BYTE **buf, LPWSTR *string_ptr)
1409 DWORD cb;
1411 if (!*string_ptr)
1413 cb = sizeof(WCHAR);
1414 memset(*buf, 0, cb);
1416 else
1418 cb = (strlenW(*string_ptr) + 1)*sizeof(WCHAR);
1419 memcpy(*buf, *string_ptr, cb);
1420 MIDL_user_free(*string_ptr);
1423 *string_ptr = (LPWSTR)*buf;
1424 *buf += cb;
1426 return cb;
1429 static DWORD size_string(LPCWSTR string)
1431 return (string ? (strlenW(string) + 1)*sizeof(WCHAR) : sizeof(WCHAR));
1434 /******************************************************************************
1435 * QueryServiceConfigW [ADVAPI32.@]
1437 BOOL WINAPI
1438 QueryServiceConfigW( SC_HANDLE hService,
1439 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1440 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1442 QUERY_SERVICE_CONFIGW config;
1443 DWORD total;
1444 DWORD err;
1445 BYTE *bufpos;
1447 TRACE("%p %p %d %p\n", hService, lpServiceConfig,
1448 cbBufSize, pcbBytesNeeded);
1450 memset(&config, 0, sizeof(config));
1452 __TRY
1454 err = svcctl_QueryServiceConfigW(hService, &config, cbBufSize, pcbBytesNeeded);
1456 __EXCEPT(rpc_filter)
1458 err = map_exception_code(GetExceptionCode());
1460 __ENDTRY
1462 if (err != ERROR_SUCCESS)
1464 TRACE("services.exe: error %u\n", err);
1465 SetLastError(err);
1466 return FALSE;
1469 /* calculate the size required first */
1470 total = sizeof (QUERY_SERVICE_CONFIGW);
1471 total += size_string(config.lpBinaryPathName);
1472 total += size_string(config.lpLoadOrderGroup);
1473 total += size_string(config.lpDependencies);
1474 total += size_string(config.lpServiceStartName);
1475 total += size_string(config.lpDisplayName);
1477 *pcbBytesNeeded = total;
1479 /* if there's not enough memory, return an error */
1480 if( total > cbBufSize )
1482 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1483 MIDL_user_free(config.lpBinaryPathName);
1484 MIDL_user_free(config.lpLoadOrderGroup);
1485 MIDL_user_free(config.lpDependencies);
1486 MIDL_user_free(config.lpServiceStartName);
1487 MIDL_user_free(config.lpDisplayName);
1488 return FALSE;
1491 *lpServiceConfig = config;
1492 bufpos = ((BYTE *)lpServiceConfig) + sizeof(QUERY_SERVICE_CONFIGW);
1493 move_string_to_buffer(&bufpos, &lpServiceConfig->lpBinaryPathName);
1494 move_string_to_buffer(&bufpos, &lpServiceConfig->lpLoadOrderGroup);
1495 move_string_to_buffer(&bufpos, &lpServiceConfig->lpDependencies);
1496 move_string_to_buffer(&bufpos, &lpServiceConfig->lpServiceStartName);
1497 move_string_to_buffer(&bufpos, &lpServiceConfig->lpDisplayName);
1499 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1500 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1501 TRACE("Dependencies = %s\n", debugstr_w(lpServiceConfig->lpDependencies) );
1502 TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig->lpServiceStartName) );
1503 TRACE("Display name = %s\n", debugstr_w(lpServiceConfig->lpDisplayName) );
1505 return TRUE;
1508 /******************************************************************************
1509 * QueryServiceConfig2A [ADVAPI32.@]
1511 * Note
1512 * observed under win2k:
1513 * The functions QueryServiceConfig2A and QueryServiceConfig2W return the same
1514 * required buffer size (in byte) at least for dwLevel SERVICE_CONFIG_DESCRIPTION
1516 BOOL WINAPI QueryServiceConfig2A(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffer,
1517 DWORD size, LPDWORD needed)
1519 BOOL ret;
1520 LPBYTE bufferW = NULL;
1522 if(buffer && size)
1523 bufferW = heap_alloc(size);
1525 ret = QueryServiceConfig2W(hService, dwLevel, bufferW, size, needed);
1526 if(!ret) goto cleanup;
1528 switch(dwLevel) {
1529 case SERVICE_CONFIG_DESCRIPTION:
1530 if (buffer && bufferW) {
1531 LPSERVICE_DESCRIPTIONA configA = (LPSERVICE_DESCRIPTIONA) buffer;
1532 LPSERVICE_DESCRIPTIONW configW = (LPSERVICE_DESCRIPTIONW) bufferW;
1533 if (configW->lpDescription && (size > sizeof(SERVICE_DESCRIPTIONA))) {
1534 DWORD sz;
1535 configA->lpDescription = (LPSTR)(configA + 1);
1536 sz = WideCharToMultiByte( CP_ACP, 0, configW->lpDescription, -1,
1537 configA->lpDescription, size - sizeof(SERVICE_DESCRIPTIONA), NULL, NULL );
1538 if (!sz) {
1539 FIXME("WideCharToMultiByte failed for configW->lpDescription\n");
1540 ret = FALSE;
1541 configA->lpDescription = NULL;
1544 else configA->lpDescription = NULL;
1546 break;
1547 case SERVICE_CONFIG_PRESHUTDOWN_INFO:
1548 if (buffer && bufferW && *needed<=size)
1549 memcpy(buffer, bufferW, *needed);
1550 break;
1551 default:
1552 FIXME("conversation W->A not implemented for level %d\n", dwLevel);
1553 ret = FALSE;
1554 break;
1557 cleanup:
1558 heap_free( bufferW);
1559 return ret;
1562 /******************************************************************************
1563 * QueryServiceConfig2W [ADVAPI32.@]
1565 * See QueryServiceConfig2A.
1567 BOOL WINAPI QueryServiceConfig2W(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffer,
1568 DWORD size, LPDWORD needed)
1570 DWORD err;
1572 if(dwLevel!=SERVICE_CONFIG_DESCRIPTION && dwLevel!=SERVICE_CONFIG_PRESHUTDOWN_INFO) {
1573 FIXME("Level %d not implemented\n", dwLevel);
1574 SetLastError(ERROR_INVALID_LEVEL);
1575 return FALSE;
1578 if(!buffer && size) {
1579 SetLastError(ERROR_INVALID_ADDRESS);
1580 return FALSE;
1583 TRACE("%p 0x%d %p 0x%d %p\n", hService, dwLevel, buffer, size, needed);
1585 __TRY
1587 err = svcctl_QueryServiceConfig2W(hService, dwLevel, buffer, size, needed);
1589 __EXCEPT(rpc_filter)
1591 err = map_exception_code(GetExceptionCode());
1593 __ENDTRY
1595 if (err != ERROR_SUCCESS)
1597 SetLastError( err );
1598 return FALSE;
1601 switch (dwLevel)
1603 case SERVICE_CONFIG_DESCRIPTION:
1604 if (buffer)
1606 SERVICE_DESCRIPTIONW *descr = (SERVICE_DESCRIPTIONW *)buffer;
1607 if (descr->lpDescription) /* make it an absolute pointer */
1608 descr->lpDescription = (WCHAR *)(buffer + (ULONG_PTR)descr->lpDescription);
1609 break;
1613 return TRUE;
1616 /******************************************************************************
1617 * EnumServicesStatusA [ADVAPI32.@]
1619 BOOL WINAPI
1620 EnumServicesStatusA( SC_HANDLE hmngr, DWORD type, DWORD state, LPENUM_SERVICE_STATUSA
1621 services, DWORD size, LPDWORD needed, LPDWORD returned,
1622 LPDWORD resume_handle )
1624 BOOL ret;
1625 unsigned int i;
1626 ENUM_SERVICE_STATUSW *servicesW = NULL;
1627 DWORD sz, n;
1628 char *p;
1630 TRACE("%p 0x%x 0x%x %p %u %p %p %p\n", hmngr, type, state, services, size, needed,
1631 returned, resume_handle);
1633 sz = max( 2 * size, sizeof(*servicesW) );
1634 if (!(servicesW = heap_alloc( sz )))
1636 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1637 return FALSE;
1640 ret = EnumServicesStatusW( hmngr, type, state, servicesW, sz, needed, returned, resume_handle );
1641 if (!ret) goto done;
1643 p = (char *)services + *returned * sizeof(ENUM_SERVICE_STATUSA);
1644 n = size - (p - (char *)services);
1645 ret = FALSE;
1646 for (i = 0; i < *returned; i++)
1648 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpServiceName, -1, p, n, NULL, NULL );
1649 if (!sz) goto done;
1650 services[i].lpServiceName = p;
1651 p += sz;
1652 n -= sz;
1653 if (servicesW[i].lpDisplayName)
1655 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpDisplayName, -1, p, n, NULL, NULL );
1656 if (!sz) goto done;
1657 services[i].lpDisplayName = p;
1658 p += sz;
1659 n -= sz;
1661 else services[i].lpDisplayName = NULL;
1662 services[i].ServiceStatus = servicesW[i].ServiceStatus;
1665 ret = TRUE;
1667 done:
1668 heap_free( servicesW );
1669 return ret;
1672 /******************************************************************************
1673 * EnumServicesStatusW [ADVAPI32.@]
1675 BOOL WINAPI
1676 EnumServicesStatusW( SC_HANDLE hmngr, DWORD type, DWORD state, LPENUM_SERVICE_STATUSW
1677 services, DWORD size, LPDWORD needed, LPDWORD returned,
1678 LPDWORD resume_handle )
1680 DWORD err, i;
1681 ENUM_SERVICE_STATUSW dummy_status;
1683 TRACE("%p 0x%x 0x%x %p %u %p %p %p\n", hmngr, type, state, services, size, needed,
1684 returned, resume_handle);
1686 if (!hmngr)
1688 SetLastError( ERROR_INVALID_HANDLE );
1689 return FALSE;
1692 /* make sure we pass a valid pointer */
1693 if (!services || size < sizeof(*services))
1695 services = &dummy_status;
1696 size = sizeof(dummy_status);
1699 __TRY
1701 err = svcctl_EnumServicesStatusW( hmngr, type, state, (BYTE *)services, size, needed, returned, resume_handle );
1703 __EXCEPT(rpc_filter)
1705 err = map_exception_code( GetExceptionCode() );
1707 __ENDTRY
1709 if (err != ERROR_SUCCESS)
1711 SetLastError( err );
1712 return FALSE;
1715 for (i = 0; i < *returned; i++)
1717 /* convert buffer offsets into pointers */
1718 services[i].lpServiceName = (WCHAR *)((char *)services + (DWORD_PTR)services[i].lpServiceName);
1719 if (services[i].lpDisplayName)
1720 services[i].lpDisplayName = (WCHAR *)((char *)services + (DWORD_PTR)services[i].lpDisplayName);
1723 return TRUE;
1726 /******************************************************************************
1727 * EnumServicesStatusExA [ADVAPI32.@]
1729 BOOL WINAPI
1730 EnumServicesStatusExA( SC_HANDLE hmngr, SC_ENUM_TYPE level, DWORD type, DWORD state,
1731 LPBYTE buffer, DWORD size, LPDWORD needed, LPDWORD returned,
1732 LPDWORD resume_handle, LPCSTR group )
1734 BOOL ret;
1735 unsigned int i;
1736 ENUM_SERVICE_STATUS_PROCESSA *services = (ENUM_SERVICE_STATUS_PROCESSA *)buffer;
1737 ENUM_SERVICE_STATUS_PROCESSW *servicesW = NULL;
1738 WCHAR *groupW = NULL;
1739 DWORD sz, n;
1740 char *p;
1742 TRACE("%p %u 0x%x 0x%x %p %u %p %p %p %s\n", hmngr, level, type, state, buffer,
1743 size, needed, returned, resume_handle, debugstr_a(group));
1745 sz = max( 2 * size, sizeof(*servicesW) );
1746 if (!(servicesW = heap_alloc( sz )))
1748 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1749 return FALSE;
1751 if (group)
1753 int len = MultiByteToWideChar( CP_ACP, 0, group, -1, NULL, 0 );
1754 if (!(groupW = heap_alloc( len * sizeof(WCHAR) )))
1756 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1757 heap_free( servicesW );
1758 return FALSE;
1760 MultiByteToWideChar( CP_ACP, 0, group, -1, groupW, len * sizeof(WCHAR) );
1763 ret = EnumServicesStatusExW( hmngr, level, type, state, (BYTE *)servicesW, sz,
1764 needed, returned, resume_handle, groupW );
1765 if (!ret) goto done;
1767 p = (char *)services + *returned * sizeof(ENUM_SERVICE_STATUS_PROCESSA);
1768 n = size - (p - (char *)services);
1769 ret = FALSE;
1770 for (i = 0; i < *returned; i++)
1772 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpServiceName, -1, p, n, NULL, NULL );
1773 if (!sz) goto done;
1774 services[i].lpServiceName = p;
1775 p += sz;
1776 n -= sz;
1777 if (servicesW[i].lpDisplayName)
1779 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpDisplayName, -1, p, n, NULL, NULL );
1780 if (!sz) goto done;
1781 services[i].lpDisplayName = p;
1782 p += sz;
1783 n -= sz;
1785 else services[i].lpDisplayName = NULL;
1786 services[i].ServiceStatusProcess = servicesW[i].ServiceStatusProcess;
1789 ret = TRUE;
1791 done:
1792 heap_free( servicesW );
1793 heap_free( groupW );
1794 return ret;
1797 /******************************************************************************
1798 * EnumServicesStatusExW [ADVAPI32.@]
1800 BOOL WINAPI
1801 EnumServicesStatusExW( SC_HANDLE hmngr, SC_ENUM_TYPE level, DWORD type, DWORD state,
1802 LPBYTE buffer, DWORD size, LPDWORD needed, LPDWORD returned,
1803 LPDWORD resume_handle, LPCWSTR group )
1805 DWORD err, i;
1806 ENUM_SERVICE_STATUS_PROCESSW dummy_status;
1807 ENUM_SERVICE_STATUS_PROCESSW *services = (ENUM_SERVICE_STATUS_PROCESSW *)buffer;
1809 TRACE("%p %u 0x%x 0x%x %p %u %p %p %p %s\n", hmngr, level, type, state, buffer,
1810 size, needed, returned, resume_handle, debugstr_w(group));
1812 if (level != SC_ENUM_PROCESS_INFO)
1814 SetLastError( ERROR_INVALID_LEVEL );
1815 return FALSE;
1817 if (!hmngr)
1819 SetLastError( ERROR_INVALID_HANDLE );
1820 return FALSE;
1823 /* make sure we pass a valid buffer pointer */
1824 if (!services || size < sizeof(*services))
1826 buffer = (BYTE *)&dummy_status;
1827 size = sizeof(dummy_status);
1830 __TRY
1832 err = svcctl_EnumServicesStatusExW( hmngr, SC_ENUM_PROCESS_INFO, type, state, buffer, size, needed,
1833 returned, resume_handle, group );
1835 __EXCEPT(rpc_filter)
1837 err = map_exception_code( GetExceptionCode() );
1839 __ENDTRY
1841 if (err != ERROR_SUCCESS)
1843 SetLastError( err );
1844 return FALSE;
1847 for (i = 0; i < *returned; i++)
1849 /* convert buffer offsets into pointers */
1850 services[i].lpServiceName = (WCHAR *)((char *)services + (DWORD_PTR)services[i].lpServiceName);
1851 if (services[i].lpDisplayName)
1852 services[i].lpDisplayName = (WCHAR *)((char *)services + (DWORD_PTR)services[i].lpDisplayName);
1855 return TRUE;
1858 /******************************************************************************
1859 * GetServiceKeyNameA [ADVAPI32.@]
1861 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
1862 LPSTR lpServiceName, LPDWORD lpcchBuffer )
1864 LPWSTR lpDisplayNameW, lpServiceNameW;
1865 DWORD sizeW;
1866 BOOL ret = FALSE;
1868 TRACE("%p %s %p %p\n", hSCManager,
1869 debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
1871 lpDisplayNameW = SERV_dup(lpDisplayName);
1872 if (lpServiceName)
1873 lpServiceNameW = heap_alloc(*lpcchBuffer * sizeof(WCHAR));
1874 else
1875 lpServiceNameW = NULL;
1877 sizeW = *lpcchBuffer;
1878 if (!GetServiceKeyNameW(hSCManager, lpDisplayNameW, lpServiceNameW, &sizeW))
1880 if (lpServiceName && *lpcchBuffer)
1881 lpServiceName[0] = 0;
1882 *lpcchBuffer = sizeW*2; /* we can only provide an upper estimation of string length */
1883 goto cleanup;
1886 if (!WideCharToMultiByte(CP_ACP, 0, lpServiceNameW, (sizeW + 1), lpServiceName,
1887 *lpcchBuffer, NULL, NULL ))
1889 if (*lpcchBuffer && lpServiceName)
1890 lpServiceName[0] = 0;
1891 *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpServiceNameW, -1, NULL, 0, NULL, NULL);
1892 goto cleanup;
1895 /* lpcchBuffer not updated - same as in GetServiceDisplayNameA */
1896 ret = TRUE;
1898 cleanup:
1899 heap_free(lpServiceNameW);
1900 heap_free(lpDisplayNameW);
1901 return ret;
1904 /******************************************************************************
1905 * GetServiceKeyNameW [ADVAPI32.@]
1907 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
1908 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
1910 DWORD err;
1911 WCHAR buffer[2];
1912 DWORD size;
1914 TRACE("%p %s %p %p\n", hSCManager,
1915 debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
1917 if (!hSCManager)
1919 SetLastError( ERROR_INVALID_HANDLE );
1920 return FALSE;
1923 /* provide a buffer if the caller didn't */
1924 if (!lpServiceName || *lpcchBuffer < 2)
1926 lpServiceName = buffer;
1927 /* A size of 1 would be enough, but tests show that Windows returns 2,
1928 * probably because of a WCHAR/bytes mismatch in their code.
1930 *lpcchBuffer = 2;
1933 /* RPC call takes size excluding nul-terminator, whereas *lpcchBuffer
1934 * includes the nul-terminator on input. */
1935 size = *lpcchBuffer - 1;
1937 __TRY
1939 err = svcctl_GetServiceKeyNameW(hSCManager, lpDisplayName, lpServiceName,
1940 &size);
1942 __EXCEPT(rpc_filter)
1944 err = map_exception_code(GetExceptionCode());
1946 __ENDTRY
1948 /* The value of *lpcchBuffer excludes nul-terminator on output. */
1949 if (err == ERROR_SUCCESS || err == ERROR_INSUFFICIENT_BUFFER)
1950 *lpcchBuffer = size;
1952 if (err)
1953 SetLastError(err);
1954 return err == ERROR_SUCCESS;
1957 /******************************************************************************
1958 * QueryServiceLockStatusA [ADVAPI32.@]
1960 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
1961 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
1962 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1964 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1966 return FALSE;
1969 /******************************************************************************
1970 * QueryServiceLockStatusW [ADVAPI32.@]
1972 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
1973 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
1974 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1976 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1978 return FALSE;
1981 /******************************************************************************
1982 * GetServiceDisplayNameA [ADVAPI32.@]
1984 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1985 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
1987 LPWSTR lpServiceNameW, lpDisplayNameW;
1988 DWORD sizeW;
1989 BOOL ret = FALSE;
1991 TRACE("%p %s %p %p\n", hSCManager,
1992 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
1994 lpServiceNameW = SERV_dup(lpServiceName);
1995 if (lpDisplayName)
1996 lpDisplayNameW = heap_alloc(*lpcchBuffer * sizeof(WCHAR));
1997 else
1998 lpDisplayNameW = NULL;
2000 sizeW = *lpcchBuffer;
2001 if (!GetServiceDisplayNameW(hSCManager, lpServiceNameW, lpDisplayNameW, &sizeW))
2003 if (lpDisplayName && *lpcchBuffer)
2004 lpDisplayName[0] = 0;
2005 *lpcchBuffer = sizeW*2; /* we can only provide an upper estimation of string length */
2006 goto cleanup;
2009 if (!WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, (sizeW + 1), lpDisplayName,
2010 *lpcchBuffer, NULL, NULL ))
2012 if (*lpcchBuffer && lpDisplayName)
2013 lpDisplayName[0] = 0;
2014 *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, -1, NULL, 0, NULL, NULL);
2015 goto cleanup;
2018 /* probably due to a bug GetServiceDisplayNameA doesn't modify lpcchBuffer on success.
2019 * (but if the function succeeded it means that is a good upper estimation of the size) */
2020 ret = TRUE;
2022 cleanup:
2023 heap_free(lpDisplayNameW);
2024 heap_free(lpServiceNameW);
2025 return ret;
2028 /******************************************************************************
2029 * GetServiceDisplayNameW [ADVAPI32.@]
2031 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
2032 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
2034 DWORD err;
2035 DWORD size;
2036 WCHAR buffer[2];
2038 TRACE("%p %s %p %p\n", hSCManager,
2039 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
2041 if (!hSCManager)
2043 SetLastError( ERROR_INVALID_HANDLE );
2044 return FALSE;
2047 /* provide a buffer if the caller didn't */
2048 if (!lpDisplayName || *lpcchBuffer < 2)
2050 lpDisplayName = buffer;
2051 /* A size of 1 would be enough, but tests show that Windows returns 2,
2052 * probably because of a WCHAR/bytes mismatch in their code.
2054 *lpcchBuffer = 2;
2057 /* RPC call takes size excluding nul-terminator, whereas *lpcchBuffer
2058 * includes the nul-terminator on input. */
2059 size = *lpcchBuffer - 1;
2061 __TRY
2063 err = svcctl_GetServiceDisplayNameW(hSCManager, lpServiceName, lpDisplayName,
2064 &size);
2066 __EXCEPT(rpc_filter)
2068 err = map_exception_code(GetExceptionCode());
2070 __ENDTRY
2072 /* The value of *lpcchBuffer excludes nul-terminator on output. */
2073 if (err == ERROR_SUCCESS || err == ERROR_INSUFFICIENT_BUFFER)
2074 *lpcchBuffer = size;
2076 if (err)
2077 SetLastError(err);
2078 return err == ERROR_SUCCESS;
2081 /******************************************************************************
2082 * ChangeServiceConfigW [ADVAPI32.@]
2084 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
2085 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
2086 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
2087 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
2089 DWORD cb_pwd;
2090 DWORD err;
2092 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2093 hService, dwServiceType, dwStartType, dwErrorControl,
2094 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2095 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2096 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2098 cb_pwd = lpPassword ? (strlenW(lpPassword) + 1)*sizeof(WCHAR) : 0;
2100 __TRY
2102 err = svcctl_ChangeServiceConfigW(hService, dwServiceType,
2103 dwStartType, dwErrorControl, lpBinaryPathName, lpLoadOrderGroup, lpdwTagId,
2104 (const BYTE *)lpDependencies, multisz_cb(lpDependencies), lpServiceStartName,
2105 (const BYTE *)lpPassword, cb_pwd, lpDisplayName);
2107 __EXCEPT(rpc_filter)
2109 err = map_exception_code(GetExceptionCode());
2111 __ENDTRY
2113 if (err != ERROR_SUCCESS)
2114 SetLastError(err);
2116 return err == ERROR_SUCCESS;
2119 /******************************************************************************
2120 * ChangeServiceConfigA [ADVAPI32.@]
2122 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2123 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2124 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2125 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2127 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2128 LPWSTR wServiceStartName, wPassword, wDisplayName;
2129 BOOL r;
2131 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2132 hService, dwServiceType, dwStartType, dwErrorControl,
2133 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2134 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2135 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2137 wBinaryPathName = SERV_dup( lpBinaryPathName );
2138 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2139 wDependencies = SERV_dupmulti( lpDependencies );
2140 wServiceStartName = SERV_dup( lpServiceStartName );
2141 wPassword = SERV_dup( lpPassword );
2142 wDisplayName = SERV_dup( lpDisplayName );
2144 r = ChangeServiceConfigW( hService, dwServiceType,
2145 dwStartType, dwErrorControl, wBinaryPathName,
2146 wLoadOrderGroup, lpdwTagId, wDependencies,
2147 wServiceStartName, wPassword, wDisplayName);
2149 heap_free( wBinaryPathName );
2150 heap_free( wLoadOrderGroup );
2151 heap_free( wDependencies );
2152 heap_free( wServiceStartName );
2153 heap_free( wPassword );
2154 heap_free( wDisplayName );
2156 return r;
2159 /******************************************************************************
2160 * ChangeServiceConfig2A [ADVAPI32.@]
2162 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2163 LPVOID lpInfo)
2165 BOOL r = FALSE;
2167 TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo);
2169 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2171 LPSERVICE_DESCRIPTIONA sd = lpInfo;
2172 SERVICE_DESCRIPTIONW sdw;
2174 sdw.lpDescription = SERV_dup( sd->lpDescription );
2176 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2178 heap_free( sdw.lpDescription );
2180 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2182 LPSERVICE_FAILURE_ACTIONSA fa = lpInfo;
2183 SERVICE_FAILURE_ACTIONSW faw;
2185 faw.dwResetPeriod = fa->dwResetPeriod;
2186 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2187 faw.lpCommand = SERV_dup( fa->lpCommand );
2188 faw.cActions = fa->cActions;
2189 faw.lpsaActions = fa->lpsaActions;
2191 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2193 heap_free( faw.lpRebootMsg );
2194 heap_free( faw.lpCommand );
2196 else if (dwInfoLevel == SERVICE_CONFIG_PRESHUTDOWN_INFO)
2198 r = ChangeServiceConfig2W( hService, dwInfoLevel, lpInfo);
2200 else
2201 SetLastError( ERROR_INVALID_PARAMETER );
2203 return r;
2206 /******************************************************************************
2207 * ChangeServiceConfig2W [ADVAPI32.@]
2209 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2210 LPVOID lpInfo)
2212 DWORD err;
2214 __TRY
2216 SC_RPC_CONFIG_INFOW info;
2218 info.dwInfoLevel = dwInfoLevel;
2219 info.u.descr = lpInfo;
2220 err = svcctl_ChangeServiceConfig2W( hService, info );
2222 __EXCEPT(rpc_filter)
2224 err = map_exception_code(GetExceptionCode());
2226 __ENDTRY
2228 if (err != ERROR_SUCCESS)
2229 SetLastError(err);
2231 return err == ERROR_SUCCESS;
2234 NTSTATUS SERV_QueryServiceObjectSecurity(SC_HANDLE hService,
2235 SECURITY_INFORMATION dwSecurityInformation,
2236 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2237 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2239 SECURITY_DESCRIPTOR descriptor;
2240 NTSTATUS status;
2241 DWORD size;
2242 ACL acl;
2244 FIXME("%p %d %p %u %p - semi-stub\n", hService, dwSecurityInformation,
2245 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2247 if (dwSecurityInformation != DACL_SECURITY_INFORMATION)
2248 FIXME("information %d not supported\n", dwSecurityInformation);
2250 InitializeSecurityDescriptor(&descriptor, SECURITY_DESCRIPTOR_REVISION);
2252 InitializeAcl(&acl, sizeof(ACL), ACL_REVISION);
2253 SetSecurityDescriptorDacl(&descriptor, TRUE, &acl, TRUE);
2255 size = cbBufSize;
2256 status = RtlMakeSelfRelativeSD(&descriptor, lpSecurityDescriptor, &size);
2257 *pcbBytesNeeded = size;
2258 return status;
2261 /******************************************************************************
2262 * QueryServiceObjectSecurity [ADVAPI32.@]
2264 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2265 SECURITY_INFORMATION dwSecurityInformation,
2266 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2267 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2269 NTSTATUS status = SERV_QueryServiceObjectSecurity(hService, dwSecurityInformation, lpSecurityDescriptor,
2270 cbBufSize, pcbBytesNeeded);
2271 if (status != STATUS_SUCCESS)
2273 SetLastError(RtlNtStatusToDosError(status));
2274 return FALSE;
2276 return TRUE;
2279 /******************************************************************************
2280 * SetServiceObjectSecurity [ADVAPI32.@]
2282 * NOTES
2283 * - SetSecurityInfo should be updated to call this function once it's implemented.
2285 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2286 SECURITY_INFORMATION dwSecurityInformation,
2287 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2289 FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2290 return TRUE;
2293 /******************************************************************************
2294 * SetServiceBits [ADVAPI32.@]
2296 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2297 DWORD dwServiceBits,
2298 BOOL bSetBitsOn,
2299 BOOL bUpdateImmediately)
2301 FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2302 bSetBitsOn, bUpdateImmediately);
2303 return TRUE;
2306 /* thunk for calling the RegisterServiceCtrlHandler handler function */
2307 static DWORD WINAPI ctrl_handler_thunk( DWORD control, DWORD type, void *data, void *context )
2309 LPHANDLER_FUNCTION func = context;
2311 func( control );
2312 return ERROR_SUCCESS;
2315 /******************************************************************************
2316 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
2318 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerA( LPCSTR name, LPHANDLER_FUNCTION handler )
2320 return RegisterServiceCtrlHandlerExA( name, ctrl_handler_thunk, handler );
2323 /******************************************************************************
2324 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
2326 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR name, LPHANDLER_FUNCTION handler )
2328 return RegisterServiceCtrlHandlerExW( name, ctrl_handler_thunk, handler );
2331 /******************************************************************************
2332 * RegisterServiceCtrlHandlerExA [ADVAPI32.@]
2334 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR name, LPHANDLER_FUNCTION_EX handler, LPVOID context )
2336 LPWSTR nameW;
2337 SERVICE_STATUS_HANDLE ret;
2339 nameW = SERV_dup(name);
2340 ret = RegisterServiceCtrlHandlerExW( nameW, handler, context );
2341 heap_free( nameW );
2342 return ret;
2345 /******************************************************************************
2346 * RegisterServiceCtrlHandlerExW [ADVAPI32.@]
2348 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2349 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2351 service_data *service;
2352 SC_HANDLE hService = 0;
2353 BOOL found = FALSE;
2355 TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2357 EnterCriticalSection( &service_cs );
2358 if ((service = find_service_by_name( lpServiceName )))
2360 service->handler = lpHandlerProc;
2361 service->context = lpContext;
2362 hService = service->handle;
2363 found = TRUE;
2365 LeaveCriticalSection( &service_cs );
2367 if (!found) SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
2369 return (SERVICE_STATUS_HANDLE)hService;
2372 /******************************************************************************
2373 * EnumDependentServicesA [ADVAPI32.@]
2375 BOOL WINAPI EnumDependentServicesA( SC_HANDLE hService, DWORD dwServiceState,
2376 LPENUM_SERVICE_STATUSA lpServices, DWORD cbBufSize,
2377 LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
2379 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
2380 lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
2382 *lpServicesReturned = 0;
2383 return TRUE;
2386 /******************************************************************************
2387 * EnumDependentServicesW [ADVAPI32.@]
2389 BOOL WINAPI EnumDependentServicesW( SC_HANDLE hService, DWORD dwServiceState,
2390 LPENUM_SERVICE_STATUSW lpServices, DWORD cbBufSize,
2391 LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
2393 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
2394 lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
2396 *lpServicesReturned = 0;
2397 return TRUE;
2400 /******************************************************************************
2401 * NotifyServiceStatusChangeW [ADVAPI32.@]
2403 DWORD WINAPI NotifyServiceStatusChangeW(SC_HANDLE hService, DWORD dwNotifyMask,
2404 SERVICE_NOTIFYW *pNotifyBuffer)
2406 DWORD dummy;
2407 BOOL ret;
2408 SERVICE_STATUS_PROCESS st;
2410 FIXME("%p 0x%x %p - semi-stub\n", hService, dwNotifyMask, pNotifyBuffer);
2412 ret = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (void*)&st, sizeof(st), &dummy);
2413 if (ret)
2415 /* dwNotifyMask is a set of bitflags in same order as SERVICE_ statuses */
2416 if (dwNotifyMask & (1 << (st.dwCurrentState - SERVICE_STOPPED)))
2418 pNotifyBuffer->dwNotificationStatus = ERROR_SUCCESS;
2419 memcpy(&pNotifyBuffer->ServiceStatus, &st, sizeof(pNotifyBuffer->ServiceStatus));
2420 pNotifyBuffer->dwNotificationTriggered = 1 << (st.dwCurrentState - SERVICE_STOPPED);
2421 pNotifyBuffer->pszServiceNames = NULL;
2422 TRACE("Queueing notification: 0x%x\n", pNotifyBuffer->dwNotificationTriggered);
2423 QueueUserAPC((PAPCFUNC)pNotifyBuffer->pfnNotifyCallback,
2424 GetCurrentThread(), (ULONG_PTR)pNotifyBuffer);
2428 /* TODO: If the service is not currently in a matching state, we should
2429 * tell `services` to monitor it. */
2431 return ERROR_SUCCESS;