mf/session: Forward more events to the application.
[wine/zf.git] / dlls / sechost / service.c
blob305c1169bd423b6b248b769d65a1563abf89c444
1 /*
2 * Service control API
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 #define NONAMELESSUNION
24 #include <stdarg.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winsvc.h"
28 #include "winternl.h"
29 #include "winuser.h"
30 #include "dbt.h"
32 #include "wine/debug.h"
33 #include "wine/exception.h"
34 #include "wine/heap.h"
35 #include "wine/list.h"
37 #include "svcctl.h"
38 #include "plugplay.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(service);
42 struct notify_data
44 SC_HANDLE service;
45 SC_RPC_NOTIFY_PARAMS params;
46 SERVICE_NOTIFY_STATUS_CHANGE_PARAMS_2 cparams;
47 SC_NOTIFY_RPC_HANDLE notify_handle;
48 SERVICE_NOTIFYW *notify_buffer;
49 HANDLE calling_thread, ready_evt;
50 struct list entry;
53 static struct list notify_list = LIST_INIT(notify_list);
55 static CRITICAL_SECTION service_cs;
56 static CRITICAL_SECTION_DEBUG service_cs_debug =
58 0, 0, &service_cs,
59 { &service_cs_debug.ProcessLocksList,
60 &service_cs_debug.ProcessLocksList },
61 0, 0, { (DWORD_PTR)(__FILE__ ": service_cs") }
63 static CRITICAL_SECTION service_cs = { &service_cs_debug, -1, 0, 0, 0, 0 };
65 struct service_data
67 LPHANDLER_FUNCTION_EX handler;
68 void *context;
69 HANDLE thread;
70 SC_HANDLE handle;
71 SC_HANDLE full_access_handle;
72 unsigned int unicode : 1;
73 union
75 LPSERVICE_MAIN_FUNCTIONA a;
76 LPSERVICE_MAIN_FUNCTIONW w;
77 } proc;
78 WCHAR *args;
79 WCHAR name[1];
82 struct dispatcher_data
84 SC_HANDLE manager;
85 HANDLE pipe;
88 static struct service_data **services;
89 static unsigned int nb_services;
90 static HANDLE service_event;
91 static BOOL stop_service;
93 extern HANDLE CDECL __wine_make_process_system(void);
95 static WCHAR *heap_strdupAtoW( const char *src )
97 WCHAR *dst = NULL;
98 if (src)
100 DWORD len = MultiByteToWideChar( CP_ACP, 0, src, -1, NULL, 0 );
101 if ((dst = heap_alloc( len * sizeof(WCHAR) ))) MultiByteToWideChar( CP_ACP, 0, src, -1, dst, len );
103 return dst;
106 static WCHAR *heap_strdup_multi_AtoW( const char *src )
108 WCHAR *dst = NULL;
109 const char *p = src;
110 DWORD len;
112 if (!src) return NULL;
114 while (*p) p += strlen(p) + 1;
115 for (p = src; *p; p += strlen(p) + 1);
116 p++; /* final null */
117 len = MultiByteToWideChar( CP_ACP, 0, src, p - src, NULL, 0 );
118 if ((dst = heap_alloc( len * sizeof(WCHAR) ))) MultiByteToWideChar( CP_ACP, 0, src, p - src, dst, len );
119 return dst;
122 static inline DWORD multisz_size( const WCHAR *str )
124 const WCHAR *p = str;
126 if (!str) return 0;
128 while (*p) p += wcslen(p) + 1;
129 return (p - str + 1) * sizeof(WCHAR);
132 void __RPC_FAR * __RPC_USER MIDL_user_allocate( SIZE_T len )
134 return heap_alloc(len);
137 void __RPC_USER MIDL_user_free( void __RPC_FAR *ptr )
139 heap_free(ptr);
142 static LONG WINAPI rpc_filter( EXCEPTION_POINTERS *eptr )
144 return I_RpcExceptionFilter( eptr->ExceptionRecord->ExceptionCode );
147 static DWORD map_exception_code( DWORD exception_code )
149 switch (exception_code)
151 case RPC_X_NULL_REF_POINTER:
152 return ERROR_INVALID_ADDRESS;
153 case RPC_X_ENUM_VALUE_OUT_OF_RANGE:
154 case RPC_X_BYTE_COUNT_TOO_SMALL:
155 return ERROR_INVALID_PARAMETER;
156 case RPC_S_INVALID_BINDING:
157 case RPC_X_SS_IN_NULL_CONTEXT:
158 return ERROR_INVALID_HANDLE;
159 default:
160 return exception_code;
164 static handle_t rpc_wstr_bind( RPC_WSTR str )
166 WCHAR transport[] = SVCCTL_TRANSPORT;
167 WCHAR endpoint[] = SVCCTL_ENDPOINT;
168 RPC_WSTR binding_str;
169 RPC_STATUS status;
170 handle_t rpc_handle;
172 status = RpcStringBindingComposeW( NULL, transport, str, endpoint, NULL, &binding_str );
173 if (status != RPC_S_OK)
175 ERR("RpcStringBindingComposeW failed, error %d\n", status);
176 return NULL;
179 status = RpcBindingFromStringBindingW( binding_str, &rpc_handle );
180 RpcStringFreeW( &binding_str );
182 if (status != RPC_S_OK)
184 ERR("Couldn't connect to services.exe, error %d\n", status);
185 return NULL;
188 return rpc_handle;
191 static handle_t rpc_cstr_bind(RPC_CSTR str)
193 RPC_CSTR transport = (RPC_CSTR)SVCCTL_TRANSPORTA;
194 RPC_CSTR endpoint = (RPC_CSTR)SVCCTL_ENDPOINTA;
195 RPC_CSTR binding_str;
196 RPC_STATUS status;
197 handle_t rpc_handle;
199 status = RpcStringBindingComposeA( NULL, transport, str, endpoint, NULL, &binding_str );
200 if (status != RPC_S_OK)
202 ERR("RpcStringBindingComposeA failed, error %d\n", status);
203 return NULL;
206 status = RpcBindingFromStringBindingA( binding_str, &rpc_handle );
207 RpcStringFreeA( &binding_str );
209 if (status != RPC_S_OK)
211 ERR("Couldn't connect to services.exe, error %d\n", status);
212 return NULL;
215 return rpc_handle;
218 DECLSPEC_HIDDEN handle_t __RPC_USER MACHINE_HANDLEA_bind( MACHINE_HANDLEA name )
220 return rpc_cstr_bind( (RPC_CSTR)name );
223 DECLSPEC_HIDDEN void __RPC_USER MACHINE_HANDLEA_unbind( MACHINE_HANDLEA name, handle_t h )
225 RpcBindingFree( &h );
228 DECLSPEC_HIDDEN handle_t __RPC_USER MACHINE_HANDLEW_bind( MACHINE_HANDLEW name )
230 return rpc_wstr_bind( (RPC_WSTR)name );
233 DECLSPEC_HIDDEN void __RPC_USER MACHINE_HANDLEW_unbind( MACHINE_HANDLEW name, handle_t h )
235 RpcBindingFree( &h );
238 DECLSPEC_HIDDEN handle_t __RPC_USER SVCCTL_HANDLEW_bind( SVCCTL_HANDLEW name )
240 return rpc_wstr_bind( (RPC_WSTR)name );
243 DECLSPEC_HIDDEN void __RPC_USER SVCCTL_HANDLEW_unbind( SVCCTL_HANDLEW name, handle_t h )
245 RpcBindingFree( &h );
248 static BOOL set_error( DWORD err )
250 if (err) SetLastError( err );
251 return !err;
254 /******************************************************************************
255 * OpenSCManagerA (sechost.@)
257 SC_HANDLE WINAPI DECLSPEC_HOTPATCH OpenSCManagerA( const char *machine, const char *database, DWORD access )
259 WCHAR *machineW, *databaseW;
260 SC_HANDLE ret;
262 machineW = heap_strdupAtoW( machine );
263 databaseW = heap_strdupAtoW( database );
264 ret = OpenSCManagerW( machineW, databaseW, access );
265 heap_free( databaseW );
266 heap_free( machineW );
267 return ret;
270 /******************************************************************************
271 * OpenSCManagerW (sechost.@)
273 SC_HANDLE WINAPI DECLSPEC_HOTPATCH OpenSCManagerW( const WCHAR *machine, const WCHAR *database, DWORD access )
275 SC_RPC_HANDLE handle = NULL;
276 DWORD err;
278 TRACE( "%s %s %#x\n", debugstr_w(machine), debugstr_w(database), access );
280 __TRY
282 err = svcctl_OpenSCManagerW( machine, database, access, &handle );
284 __EXCEPT(rpc_filter)
286 err = map_exception_code( GetExceptionCode() );
288 __ENDTRY
290 if (!err) return handle;
291 SetLastError( err );
292 return NULL;
295 /******************************************************************************
296 * OpenServiceA (sechost.@)
298 SC_HANDLE WINAPI DECLSPEC_HOTPATCH OpenServiceA( SC_HANDLE manager, const char *name, DWORD access )
300 WCHAR *nameW;
301 SC_HANDLE ret;
303 TRACE( "%p %s %#x\n", manager, debugstr_a(name), access );
305 nameW = heap_strdupAtoW( name );
306 ret = OpenServiceW( manager, nameW, access );
307 heap_free( nameW );
308 return ret;
311 /******************************************************************************
312 * OpenServiceW (sechost.@)
314 SC_HANDLE WINAPI DECLSPEC_HOTPATCH OpenServiceW( SC_HANDLE manager, const WCHAR *name, DWORD access )
316 SC_RPC_HANDLE handle = NULL;
317 DWORD err;
319 TRACE( "%p %s %#x\n", manager, debugstr_w(name), access );
321 if (!manager)
323 SetLastError( ERROR_INVALID_HANDLE );
324 return NULL;
327 __TRY
329 err = svcctl_OpenServiceW( manager, name, access, &handle );
331 __EXCEPT(rpc_filter)
333 err = map_exception_code( GetExceptionCode() );
335 __ENDTRY
337 if (!err) return handle;
338 SetLastError( err );
339 return 0;
342 /******************************************************************************
343 * CreateServiceA (sechost.@)
345 SC_HANDLE WINAPI DECLSPEC_HOTPATCH CreateServiceA( SC_HANDLE manager, const char *name, const char *display_name,
346 DWORD access, DWORD service_type, DWORD start_type,
347 DWORD error_control, const char *path, const char *group,
348 DWORD *tag, const char *dependencies, const char *username,
349 const char *password )
351 WCHAR *nameW, *display_nameW, *pathW, *groupW, *dependenciesW, *usernameW, *passwordW;
352 SC_HANDLE handle;
354 TRACE( "%p %s %s\n", manager, debugstr_a(name), debugstr_a(display_name) );
356 nameW = heap_strdupAtoW( name );
357 display_nameW = heap_strdupAtoW( display_name );
358 pathW = heap_strdupAtoW( path );
359 groupW = heap_strdupAtoW( group );
360 dependenciesW = heap_strdupAtoW( dependencies );
361 usernameW = heap_strdupAtoW( username );
362 passwordW = heap_strdupAtoW( password );
364 handle = CreateServiceW( manager, nameW, display_nameW, access, service_type, start_type, error_control,
365 pathW, groupW, tag, dependenciesW, usernameW, passwordW );
367 heap_free( nameW );
368 heap_free( display_nameW );
369 heap_free( pathW );
370 heap_free( groupW );
371 heap_free( dependenciesW );
372 heap_free( usernameW );
373 heap_free( passwordW );
375 return handle;
378 /******************************************************************************
379 * CreateServiceW (sechost.@)
381 SC_HANDLE WINAPI DECLSPEC_HOTPATCH CreateServiceW( SC_HANDLE manager, const WCHAR *name, const WCHAR *display_name,
382 DWORD access, DWORD service_type, DWORD start_type,
383 DWORD error_control, const WCHAR *path, const WCHAR *group,
384 DWORD *tag, const WCHAR *dependencies, const WCHAR *username,
385 const WCHAR *password )
387 SC_RPC_HANDLE handle = NULL;
388 DWORD err;
389 SIZE_T password_size = 0;
391 TRACE( "%p %s %s\n", manager, debugstr_w(name), debugstr_w(display_name) );
393 if (!manager)
395 SetLastError( ERROR_INVALID_HANDLE );
396 return 0;
399 if (password) password_size = (wcslen(password) + 1) * sizeof(WCHAR);
401 __TRY
403 BOOL is_wow64;
405 if (IsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64)
406 err = svcctl_CreateServiceWOW64W( manager, name, display_name, access, service_type, start_type,
407 error_control, path, group, tag, (const BYTE *)dependencies,
408 multisz_size( dependencies ), username, (const BYTE *)password,
409 password_size, &handle );
410 else
411 err = svcctl_CreateServiceW( manager, name, display_name, access, service_type, start_type,
412 error_control, path, group, tag, (const BYTE *)dependencies,
413 multisz_size( dependencies ), username, (const BYTE *)password,
414 password_size, &handle );
416 __EXCEPT(rpc_filter)
418 err = map_exception_code( GetExceptionCode() );
420 __ENDTRY
422 if (!err) return handle;
423 SetLastError( err );
424 return NULL;
427 /******************************************************************************
428 * DeleteService (sechost.@)
430 BOOL WINAPI DECLSPEC_HOTPATCH DeleteService( SC_HANDLE service )
432 DWORD err;
434 TRACE( "%p\n", service );
436 __TRY
438 err = svcctl_DeleteService( service );
440 __EXCEPT(rpc_filter)
442 err = map_exception_code( GetExceptionCode() );
444 __ENDTRY
446 return set_error( err );
449 /******************************************************************************
450 * CloseServiceHandle (sechost.@)
452 BOOL WINAPI DECLSPEC_HOTPATCH CloseServiceHandle( SC_HANDLE handle )
454 DWORD err;
456 TRACE( "%p\n", handle );
458 __TRY
460 err = svcctl_CloseServiceHandle( (SC_RPC_HANDLE *)&handle );
462 __EXCEPT(rpc_filter)
464 err = map_exception_code( GetExceptionCode() );
466 __ENDTRY
468 return set_error( err );
471 /******************************************************************************
472 * ChangeServiceConfig2A (sechost.@)
474 BOOL WINAPI DECLSPEC_HOTPATCH ChangeServiceConfig2A( SC_HANDLE service, DWORD level, void *info)
476 BOOL r = FALSE;
478 TRACE( "%p %d %p\n", service, level, info );
480 if (level == SERVICE_CONFIG_DESCRIPTION)
482 SERVICE_DESCRIPTIONA *sd = info;
483 SERVICE_DESCRIPTIONW sdw;
485 sdw.lpDescription = heap_strdupAtoW( sd->lpDescription );
487 r = ChangeServiceConfig2W( service, level, &sdw );
489 heap_free( sdw.lpDescription );
491 else if (level == SERVICE_CONFIG_FAILURE_ACTIONS)
493 SERVICE_FAILURE_ACTIONSA *fa = info;
494 SERVICE_FAILURE_ACTIONSW faw;
496 faw.dwResetPeriod = fa->dwResetPeriod;
497 faw.lpRebootMsg = heap_strdupAtoW( fa->lpRebootMsg );
498 faw.lpCommand = heap_strdupAtoW( fa->lpCommand );
499 faw.cActions = fa->cActions;
500 faw.lpsaActions = fa->lpsaActions;
502 r = ChangeServiceConfig2W( service, level, &faw );
504 heap_free( faw.lpRebootMsg );
505 heap_free( faw.lpCommand );
507 else if (level == SERVICE_CONFIG_PRESHUTDOWN_INFO)
509 r = ChangeServiceConfig2W( service, level, info );
511 else
512 SetLastError( ERROR_INVALID_PARAMETER );
514 return r;
517 /******************************************************************************
518 * ChangeServiceConfig2W (sechost.@)
520 BOOL WINAPI DECLSPEC_HOTPATCH ChangeServiceConfig2W( SC_HANDLE service, DWORD level, void *info )
522 SERVICE_RPC_REQUIRED_PRIVILEGES_INFO rpc_privinfo;
523 DWORD err;
525 __TRY
527 SC_RPC_CONFIG_INFOW rpc_info;
529 rpc_info.dwInfoLevel = level;
530 if (level == SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO)
532 SERVICE_REQUIRED_PRIVILEGES_INFOW *privinfo = info;
534 rpc_privinfo.cbRequiredPrivileges = multisz_size( privinfo->pmszRequiredPrivileges );
535 rpc_privinfo.pRequiredPrivileges = (BYTE *)privinfo->pmszRequiredPrivileges;
536 rpc_info.privinfo = &rpc_privinfo;
538 else
539 rpc_info.descr = info;
540 err = svcctl_ChangeServiceConfig2W( service, rpc_info );
542 __EXCEPT(rpc_filter)
544 err = map_exception_code( GetExceptionCode() );
546 __ENDTRY
548 return set_error( err );
551 /******************************************************************************
552 * ChangeServiceConfigA (sechost.@)
554 BOOL WINAPI DECLSPEC_HOTPATCH ChangeServiceConfigA( SC_HANDLE service, DWORD service_type, DWORD start_type,
555 DWORD error_control, const char *path, const char *group,
556 DWORD *tag, const char *dependencies, const char *username,
557 const char *password, const char *display_name )
559 WCHAR *pathW, *groupW, *dependenciesW, *usernameW, *passwordW, *display_nameW;
560 BOOL r;
562 TRACE( "%p %d %d %d %s %s %p %p %s %s %s\n", service, service_type, start_type,
563 error_control, debugstr_a(path), debugstr_a(group), tag, dependencies,
564 debugstr_a(username), debugstr_a(password), debugstr_a(display_name) );
566 pathW = heap_strdupAtoW( path );
567 groupW = heap_strdupAtoW( group );
568 dependenciesW = heap_strdup_multi_AtoW( dependencies );
569 usernameW = heap_strdupAtoW( username );
570 passwordW = heap_strdupAtoW( password );
571 display_nameW = heap_strdupAtoW( display_name );
573 r = ChangeServiceConfigW( service, service_type, start_type, error_control, pathW,
574 groupW, tag, dependenciesW, usernameW, passwordW, display_nameW );
576 heap_free( pathW );
577 heap_free( groupW );
578 heap_free( dependenciesW );
579 heap_free( usernameW );
580 heap_free( passwordW );
581 heap_free( display_nameW );
583 return r;
586 /******************************************************************************
587 * ChangeServiceConfigW (sechost.@)
589 BOOL WINAPI DECLSPEC_HOTPATCH ChangeServiceConfigW( SC_HANDLE service, DWORD service_type, DWORD start_type,
590 DWORD error_control, const WCHAR *path, const WCHAR *group,
591 DWORD *tag, const WCHAR *dependencies, const WCHAR *username,
592 const WCHAR *password, const WCHAR *display_name )
594 DWORD password_size;
595 DWORD err;
597 TRACE( "%p %d %d %d %s %s %p %p %s %s %s\n", service, service_type, start_type,
598 error_control, debugstr_w(path), debugstr_w(group), tag, dependencies,
599 debugstr_w(username), debugstr_w(password), debugstr_w(display_name) );
601 password_size = password ? (wcslen(password) + 1) * sizeof(WCHAR) : 0;
603 __TRY
605 err = svcctl_ChangeServiceConfigW( service, service_type, start_type, error_control, path, group, tag,
606 (const BYTE *)dependencies, multisz_size(dependencies), username,
607 (const BYTE *)password, password_size, display_name );
609 __EXCEPT(rpc_filter)
611 err = map_exception_code( GetExceptionCode() );
613 __ENDTRY
615 return set_error( err );
618 /******************************************************************************
619 * QueryServiceConfigA (sechost.@)
621 BOOL WINAPI DECLSPEC_HOTPATCH QueryServiceConfigA( SC_HANDLE service, QUERY_SERVICE_CONFIGA *config,
622 DWORD size, DWORD *ret_size )
624 DWORD n;
625 char *p, *buffer;
626 BOOL ret;
627 QUERY_SERVICE_CONFIGW *configW;
629 TRACE( "%p %p %d %p\n", service, config, size, ret_size );
631 if (!(buffer = heap_alloc( 2 * size ))) return set_error( ERROR_NOT_ENOUGH_MEMORY );
632 configW = (QUERY_SERVICE_CONFIGW *)buffer;
633 ret = QueryServiceConfigW( service, configW, 2 * size, ret_size );
634 if (!ret) goto done;
636 config->dwServiceType = configW->dwServiceType;
637 config->dwStartType = configW->dwStartType;
638 config->dwErrorControl = configW->dwErrorControl;
639 config->lpBinaryPathName = NULL;
640 config->lpLoadOrderGroup = NULL;
641 config->dwTagId = configW->dwTagId;
642 config->lpDependencies = NULL;
643 config->lpServiceStartName = NULL;
644 config->lpDisplayName = NULL;
646 p = (char *)(config + 1);
647 n = size - sizeof(*config);
648 ret = FALSE;
650 #define MAP_STR(str) \
651 do { \
652 if (configW->str) \
654 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
655 if (!sz) goto done; \
656 config->str = p; \
657 p += sz; \
658 n -= sz; \
660 } while (0)
662 MAP_STR( lpBinaryPathName );
663 MAP_STR( lpLoadOrderGroup );
664 MAP_STR( lpDependencies );
665 MAP_STR( lpServiceStartName );
666 MAP_STR( lpDisplayName );
667 #undef MAP_STR
669 *ret_size = p - (char *)config;
670 ret = TRUE;
672 done:
673 heap_free( buffer );
674 return ret;
677 static DWORD move_string_to_buffer(BYTE **buf, WCHAR **string_ptr)
679 DWORD cb;
681 if (!*string_ptr)
683 cb = sizeof(WCHAR);
684 memset(*buf, 0, cb);
686 else
688 cb = (wcslen( *string_ptr ) + 1) * sizeof(WCHAR);
689 memcpy(*buf, *string_ptr, cb);
690 MIDL_user_free( *string_ptr );
693 *string_ptr = (WCHAR *)*buf;
694 *buf += cb;
696 return cb;
699 static DWORD size_string( const WCHAR *string )
701 return (string ? (wcslen( string ) + 1) * sizeof(WCHAR) : sizeof(WCHAR));
704 /******************************************************************************
705 * QueryServiceConfigW (sechost.@)
707 BOOL WINAPI DECLSPEC_HOTPATCH QueryServiceConfigW( SC_HANDLE service, QUERY_SERVICE_CONFIGW *ret_config,
708 DWORD size, DWORD *ret_size )
710 QUERY_SERVICE_CONFIGW config;
711 DWORD total;
712 DWORD err;
713 BYTE *bufpos;
715 TRACE( "%p %p %d %p\n", service, ret_config, size, ret_size );
717 memset(&config, 0, sizeof(config));
719 __TRY
721 err = svcctl_QueryServiceConfigW( service, &config, size, ret_size );
723 __EXCEPT(rpc_filter)
725 err = map_exception_code( GetExceptionCode() );
727 __ENDTRY
729 if (err) return set_error( err );
731 /* calculate the size required first */
732 total = sizeof(QUERY_SERVICE_CONFIGW);
733 total += size_string( config.lpBinaryPathName );
734 total += size_string( config.lpLoadOrderGroup );
735 total += size_string( config.lpDependencies );
736 total += size_string( config.lpServiceStartName );
737 total += size_string( config.lpDisplayName );
739 *ret_size = total;
741 /* if there's not enough memory, return an error */
742 if (size < total)
744 SetLastError( ERROR_INSUFFICIENT_BUFFER );
745 MIDL_user_free( config.lpBinaryPathName );
746 MIDL_user_free( config.lpLoadOrderGroup );
747 MIDL_user_free( config.lpDependencies );
748 MIDL_user_free( config.lpServiceStartName );
749 MIDL_user_free( config.lpDisplayName );
750 return FALSE;
753 *ret_config = config;
754 bufpos = ((BYTE *)ret_config) + sizeof(QUERY_SERVICE_CONFIGW);
755 move_string_to_buffer( &bufpos, &ret_config->lpBinaryPathName );
756 move_string_to_buffer( &bufpos, &ret_config->lpLoadOrderGroup );
757 move_string_to_buffer( &bufpos, &ret_config->lpDependencies );
758 move_string_to_buffer( &bufpos, &ret_config->lpServiceStartName );
759 move_string_to_buffer( &bufpos, &ret_config->lpDisplayName );
761 TRACE( "Image path = %s\n", debugstr_w( ret_config->lpBinaryPathName ) );
762 TRACE( "Group = %s\n", debugstr_w( ret_config->lpLoadOrderGroup ) );
763 TRACE( "Dependencies = %s\n", debugstr_w( ret_config->lpDependencies ) );
764 TRACE( "Service account name = %s\n", debugstr_w( ret_config->lpServiceStartName ) );
765 TRACE( "Display name = %s\n", debugstr_w( ret_config->lpDisplayName ) );
767 return TRUE;
770 /******************************************************************************
771 * QueryServiceConfig2A (sechost.@)
773 BOOL WINAPI DECLSPEC_HOTPATCH QueryServiceConfig2A( SC_HANDLE service, DWORD level, BYTE *buffer,
774 DWORD size, DWORD *ret_size )
776 BYTE *bufferW = NULL;
778 TRACE( "%p %u %p %u %p\n", service, level, buffer, size, ret_size );
780 if (buffer && size)
781 bufferW = heap_alloc( size );
783 if (!QueryServiceConfig2W( service, level, bufferW, size, ret_size ))
785 heap_free( bufferW );
786 return FALSE;
789 switch (level)
791 case SERVICE_CONFIG_DESCRIPTION:
792 if (buffer && bufferW) {
793 SERVICE_DESCRIPTIONA *configA = (SERVICE_DESCRIPTIONA *)buffer;
794 SERVICE_DESCRIPTIONW *configW = (SERVICE_DESCRIPTIONW *)bufferW;
795 if (configW->lpDescription && size > sizeof(SERVICE_DESCRIPTIONA))
797 configA->lpDescription = (char *)(configA + 1);
798 WideCharToMultiByte( CP_ACP, 0, configW->lpDescription, -1, configA->lpDescription,
799 size - sizeof(SERVICE_DESCRIPTIONA), NULL, NULL );
801 else configA->lpDescription = NULL;
803 break;
804 case SERVICE_CONFIG_PRESHUTDOWN_INFO:
805 if (buffer && bufferW && *ret_size <= size)
806 memcpy(buffer, bufferW, *ret_size);
807 break;
808 default:
809 FIXME("conversion W->A not implemented for level %d\n", level);
810 heap_free( bufferW );
811 return FALSE;
814 heap_free( bufferW );
815 return TRUE;
818 /******************************************************************************
819 * QueryServiceConfig2W (sechost.@)
821 BOOL WINAPI DECLSPEC_HOTPATCH QueryServiceConfig2W( SC_HANDLE service, DWORD level, BYTE *buffer,
822 DWORD size, DWORD *ret_size )
824 BYTE *bufptr;
825 DWORD err;
827 TRACE( "%p %u %p %u %p\n", service, level, buffer, size, ret_size );
829 if (!buffer && size)
831 SetLastError(ERROR_INVALID_ADDRESS);
832 return FALSE;
835 switch (level)
837 case SERVICE_CONFIG_DESCRIPTION:
838 if (!(bufptr = heap_alloc( size )))
840 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
841 return FALSE;
843 break;
845 case SERVICE_CONFIG_PRESHUTDOWN_INFO:
846 bufptr = buffer;
847 break;
849 default:
850 FIXME("Level %d not implemented\n", level);
851 SetLastError(ERROR_INVALID_LEVEL);
852 return FALSE;
855 if (!ret_size)
857 if (level == SERVICE_CONFIG_DESCRIPTION) heap_free( bufptr );
858 SetLastError(ERROR_INVALID_ADDRESS);
859 return FALSE;
862 __TRY
864 err = svcctl_QueryServiceConfig2W( service, level, bufptr, size, ret_size );
866 __EXCEPT(rpc_filter)
868 err = map_exception_code( GetExceptionCode() );
870 __ENDTRY
872 switch (level)
874 case SERVICE_CONFIG_DESCRIPTION:
876 SERVICE_DESCRIPTIONW *desc = (SERVICE_DESCRIPTIONW *)buffer;
877 struct service_description *s = (struct service_description *)bufptr;
879 if (err != ERROR_SUCCESS && err != ERROR_INSUFFICIENT_BUFFER)
881 heap_free( bufptr );
882 SetLastError( err );
883 return FALSE;
886 /* adjust for potentially larger SERVICE_DESCRIPTIONW structure */
887 if (*ret_size == sizeof(*s))
888 *ret_size = sizeof(*desc);
889 else
890 *ret_size = *ret_size - FIELD_OFFSET(struct service_description, description) + sizeof(*desc);
892 if (size < *ret_size)
894 heap_free( bufptr );
895 SetLastError( ERROR_INSUFFICIENT_BUFFER );
896 return FALSE;
898 if (desc)
900 if (!s->size) desc->lpDescription = NULL;
901 else
903 desc->lpDescription = (WCHAR *)(desc + 1);
904 memcpy( desc->lpDescription, s->description, s->size );
907 heap_free( bufptr );
908 break;
910 case SERVICE_CONFIG_PRESHUTDOWN_INFO:
911 return set_error( err );
913 default:
914 break;
917 return TRUE;
920 /******************************************************************************
921 * GetServiceDisplayNameW (sechost.@)
923 BOOL WINAPI DECLSPEC_HOTPATCH GetServiceDisplayNameW( SC_HANDLE manager, const WCHAR *service,
924 WCHAR *display_name, DWORD *len )
926 DWORD err;
927 DWORD size;
928 WCHAR buffer[2];
930 TRACE( "%p %s %p %p\n", manager, debugstr_w(service), display_name, len );
932 if (!manager)
934 SetLastError( ERROR_INVALID_HANDLE );
935 return FALSE;
938 /* provide a buffer if the caller didn't */
939 if (!display_name || *len < sizeof(WCHAR))
941 display_name = buffer;
942 /* A size of 1 would be enough, but tests show that Windows returns 2,
943 * probably because of a WCHAR/bytes mismatch in their code. */
944 *len = 2;
947 /* RPC call takes size excluding nul-terminator, whereas *len
948 * includes the nul-terminator on input. */
949 size = *len - 1;
951 __TRY
953 err = svcctl_GetServiceDisplayNameW( manager, service, display_name, &size );
955 __EXCEPT(rpc_filter)
957 err = map_exception_code( GetExceptionCode() );
959 __ENDTRY
961 /* The value of *len excludes nul-terminator on output. */
962 if (err == ERROR_SUCCESS || err == ERROR_INSUFFICIENT_BUFFER)
963 *len = size;
964 return set_error( err );
967 /******************************************************************************
968 * GetServiceKeyNameW (sechost.@)
970 BOOL WINAPI DECLSPEC_HOTPATCH GetServiceKeyNameW( SC_HANDLE manager, const WCHAR *display_name,
971 WCHAR *key_name, DWORD *len )
973 DWORD err;
974 WCHAR buffer[2];
975 DWORD size;
977 TRACE( "%p %s %p %p\n", manager, debugstr_w(display_name), key_name, len );
979 if (!manager)
981 SetLastError( ERROR_INVALID_HANDLE );
982 return FALSE;
985 /* provide a buffer if the caller didn't */
986 if (!key_name || *len < 2)
988 key_name = buffer;
989 /* A size of 1 would be enough, but tests show that Windows returns 2,
990 * probably because of a WCHAR/bytes mismatch in their code.
992 *len = 2;
995 /* RPC call takes size excluding nul-terminator, whereas *len
996 * includes the nul-terminator on input. */
997 size = *len - 1;
999 __TRY
1001 err = svcctl_GetServiceKeyNameW( manager, display_name, key_name, &size );
1003 __EXCEPT(rpc_filter)
1005 err = map_exception_code( GetExceptionCode() );
1007 __ENDTRY
1009 /* The value of *lpcchBuffer excludes nul-terminator on output. */
1010 if (err == ERROR_SUCCESS || err == ERROR_INSUFFICIENT_BUFFER)
1011 *len = size;
1012 return set_error( err );
1015 /******************************************************************************
1016 * StartServiceA (sechost.@)
1018 BOOL WINAPI DECLSPEC_HOTPATCH StartServiceA( SC_HANDLE service, DWORD argc, const char **argv )
1020 WCHAR **argvW = NULL;
1021 DWORD i;
1022 BOOL r;
1024 if (argc)
1025 argvW = heap_alloc( argc * sizeof(WCHAR) );
1027 for (i = 0; i < argc; i++)
1028 argvW[i] = heap_strdupAtoW( argv[i] );
1030 r = StartServiceW( service, argc, (const WCHAR **)argvW );
1032 for (i = 0; i < argc; i++)
1033 heap_free( argvW[i] );
1034 heap_free( argvW );
1035 return r;
1039 /******************************************************************************
1040 * StartServiceW (sechost.@)
1042 BOOL WINAPI DECLSPEC_HOTPATCH StartServiceW( SC_HANDLE service, DWORD argc, const WCHAR **argv )
1044 DWORD err;
1046 TRACE( "%p %u %p\n", service, argc, argv );
1048 __TRY
1050 err = svcctl_StartServiceW( service, argc, argv );
1052 __EXCEPT(rpc_filter)
1054 err = map_exception_code( GetExceptionCode() );
1056 __ENDTRY
1058 return set_error( err );
1061 /******************************************************************************
1062 * ControlService (sechost.@)
1064 BOOL WINAPI DECLSPEC_HOTPATCH ControlService( SC_HANDLE service, DWORD control, SERVICE_STATUS *status )
1066 DWORD err;
1068 TRACE( "%p %d %p\n", service, control, status );
1070 __TRY
1072 err = svcctl_ControlService( service, control, status );
1074 __EXCEPT(rpc_filter)
1076 err = map_exception_code( GetExceptionCode() );
1078 __ENDTRY
1080 return set_error( err );
1083 /******************************************************************************
1084 * QueryServiceStatus (sechost.@)
1086 BOOL WINAPI DECLSPEC_HOTPATCH QueryServiceStatus( SC_HANDLE service, SERVICE_STATUS *status )
1088 SERVICE_STATUS_PROCESS process_status;
1089 BOOL ret;
1090 DWORD size;
1092 TRACE( "%p %p\n", service, status );
1094 if (!service) return set_error( ERROR_INVALID_HANDLE );
1095 if (!status) return set_error( ERROR_INVALID_ADDRESS );
1097 ret = QueryServiceStatusEx( service, SC_STATUS_PROCESS_INFO, (BYTE *)&process_status,
1098 sizeof(SERVICE_STATUS_PROCESS), &size );
1099 if (ret) memcpy(status, &process_status, sizeof(SERVICE_STATUS) );
1100 return ret;
1103 /******************************************************************************
1104 * QueryServiceStatusEx (sechost.@)
1106 BOOL WINAPI DECLSPEC_HOTPATCH QueryServiceStatusEx( SC_HANDLE service, SC_STATUS_TYPE level,
1107 BYTE *buffer, DWORD size, DWORD *ret_size )
1109 DWORD err;
1111 TRACE( "%p %d %p %d %p\n", service, level, buffer, size, ret_size );
1113 if (level != SC_STATUS_PROCESS_INFO) return set_error( ERROR_INVALID_LEVEL );
1115 if (size < sizeof(SERVICE_STATUS_PROCESS))
1117 *ret_size = sizeof(SERVICE_STATUS_PROCESS);
1118 return set_error( ERROR_INSUFFICIENT_BUFFER );
1121 __TRY
1123 err = svcctl_QueryServiceStatusEx( service, level, buffer, size, ret_size );
1125 __EXCEPT(rpc_filter)
1127 err = map_exception_code( GetExceptionCode() );
1129 __ENDTRY
1131 return set_error( err );
1134 /******************************************************************************
1135 * EnumServicesStatusExW (sechost.@)
1137 BOOL WINAPI DECLSPEC_HOTPATCH EnumServicesStatusExW( SC_HANDLE manager, SC_ENUM_TYPE level, DWORD type, DWORD state,
1138 BYTE *buffer, DWORD size, DWORD *needed, DWORD *returned,
1139 DWORD *resume_handle, const WCHAR *group )
1141 DWORD err, i, offset, buflen, count, total_size = 0;
1142 ENUM_SERVICE_STATUS_PROCESSW *services = (ENUM_SERVICE_STATUS_PROCESSW *)buffer;
1143 struct enum_service_status_process *entry;
1144 const WCHAR *str;
1145 BYTE *buf;
1147 TRACE( "%p %u 0x%x 0x%x %p %u %p %p %p %s\n", manager, level, type, state, buffer,
1148 size, needed, returned, resume_handle, debugstr_w(group) );
1150 if (level != SC_ENUM_PROCESS_INFO) return set_error( ERROR_INVALID_LEVEL );
1151 if (!manager) return set_error( ERROR_INVALID_HANDLE );
1152 if (!needed || !returned) return set_error( ERROR_INVALID_ADDRESS );
1154 /* make sure we pass a valid pointer */
1155 buflen = max( size, sizeof(*services) );
1156 if (!(buf = heap_alloc( buflen ))) return set_error( ERROR_NOT_ENOUGH_MEMORY );
1158 __TRY
1160 err = svcctl_EnumServicesStatusExW( manager, SC_ENUM_PROCESS_INFO, type, state, buf, buflen, needed,
1161 &count, resume_handle, group );
1163 __EXCEPT(rpc_filter)
1165 err = map_exception_code( GetExceptionCode() );
1167 __ENDTRY
1169 *returned = 0;
1170 if (err != ERROR_SUCCESS)
1172 /* double the needed size to fit the potentially larger ENUM_SERVICE_STATUS_PROCESSW */
1173 if (err == ERROR_MORE_DATA) *needed *= 2;
1174 heap_free( buf );
1175 SetLastError( err );
1176 return FALSE;
1179 entry = (struct enum_service_status_process *)buf;
1180 for (i = 0; i < count; i++)
1182 total_size += sizeof(*services);
1183 if (entry->service_name)
1185 str = (const WCHAR *)(buf + entry->service_name);
1186 total_size += (wcslen( str ) + 1) * sizeof(WCHAR);
1188 if (entry->display_name)
1190 str = (const WCHAR *)(buf + entry->display_name);
1191 total_size += (wcslen( str ) + 1) * sizeof(WCHAR);
1193 entry++;
1196 if (total_size > size)
1198 heap_free( buf );
1199 *needed = total_size;
1200 SetLastError( ERROR_MORE_DATA );
1201 return FALSE;
1204 offset = count * sizeof(*services);
1205 entry = (struct enum_service_status_process *)buf;
1206 for (i = 0; i < count; i++)
1208 DWORD str_size;
1209 str = (const WCHAR *)(buf + entry->service_name);
1210 str_size = (wcslen( str ) + 1) * sizeof(WCHAR);
1211 services[i].lpServiceName = (WCHAR *)((char *)services + offset);
1212 memcpy( services[i].lpServiceName, str, str_size );
1213 offset += str_size;
1215 if (!entry->display_name) services[i].lpDisplayName = NULL;
1216 else
1218 str = (const WCHAR *)(buf + entry->display_name);
1219 str_size = (wcslen( str ) + 1) * sizeof(WCHAR);
1220 services[i].lpDisplayName = (WCHAR *)((char *)services + offset);
1221 memcpy( services[i].lpDisplayName, str, str_size );
1222 offset += str_size;
1224 services[i].ServiceStatusProcess = entry->service_status_process;
1225 entry++;
1228 heap_free( buf );
1229 *needed = 0;
1230 *returned = count;
1231 return TRUE;
1234 /******************************************************************************
1235 * EnumDependentServicesW (sechost.@)
1237 BOOL WINAPI EnumDependentServicesW( SC_HANDLE hService, DWORD dwServiceState,
1238 LPENUM_SERVICE_STATUSW lpServices, DWORD cbBufSize,
1239 LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
1241 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
1242 lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
1244 *lpServicesReturned = 0;
1245 return TRUE;
1248 /******************************************************************************
1249 * QueryServiceObjectSecurity (sechost.@)
1251 BOOL WINAPI DECLSPEC_HOTPATCH QueryServiceObjectSecurity( SC_HANDLE service, SECURITY_INFORMATION type,
1252 PSECURITY_DESCRIPTOR ret_descriptor, DWORD size, DWORD *ret_size )
1254 SECURITY_DESCRIPTOR descriptor;
1255 NTSTATUS status;
1256 ACL acl;
1258 FIXME( "%p %d %p %u %p - semi-stub\n", service, type, ret_descriptor, size, ret_size );
1260 if (type != DACL_SECURITY_INFORMATION)
1261 FIXME("information %d not supported\n", type);
1263 InitializeSecurityDescriptor( &descriptor, SECURITY_DESCRIPTOR_REVISION );
1265 InitializeAcl( &acl, sizeof(ACL), ACL_REVISION );
1266 SetSecurityDescriptorDacl( &descriptor, TRUE, &acl, TRUE );
1268 status = RtlMakeSelfRelativeSD( &descriptor, ret_descriptor, &size );
1269 *ret_size = size;
1271 return set_error( RtlNtStatusToDosError( status ) );
1274 /******************************************************************************
1275 * SetServiceObjectSecurity (sechost.@)
1277 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
1278 SECURITY_INFORMATION dwSecurityInformation,
1279 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
1281 FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
1282 return TRUE;
1285 static DWORD WINAPI notify_thread(void *user)
1287 DWORD err;
1288 struct notify_data *data = user;
1289 SC_RPC_NOTIFY_PARAMS_LIST *list = NULL;
1290 SERVICE_NOTIFY_STATUS_CHANGE_PARAMS_2 *cparams;
1291 BOOL dummy;
1293 __TRY
1295 /* GetNotifyResults blocks until there is an event */
1296 err = svcctl_GetNotifyResults(data->notify_handle, &list);
1298 __EXCEPT(rpc_filter)
1300 err = map_exception_code(GetExceptionCode());
1302 __ENDTRY
1304 EnterCriticalSection( &service_cs );
1306 list_remove(&data->entry);
1308 LeaveCriticalSection( &service_cs );
1310 if (err == ERROR_SUCCESS && list)
1312 cparams = list->NotifyParamsArray[0].params;
1314 data->notify_buffer->dwNotificationStatus = cparams->dwNotificationStatus;
1315 memcpy(&data->notify_buffer->ServiceStatus, &cparams->ServiceStatus,
1316 sizeof(SERVICE_STATUS_PROCESS));
1317 data->notify_buffer->dwNotificationTriggered = cparams->dwNotificationTriggered;
1318 data->notify_buffer->pszServiceNames = NULL;
1320 QueueUserAPC((PAPCFUNC)data->notify_buffer->pfnNotifyCallback,
1321 data->calling_thread, (ULONG_PTR)data->notify_buffer);
1323 HeapFree(GetProcessHeap(), 0, list);
1325 else
1326 WARN("GetNotifyResults server call failed: %u\n", err);
1329 __TRY
1331 err = svcctl_CloseNotifyHandle(&data->notify_handle, &dummy);
1333 __EXCEPT(rpc_filter)
1335 err = map_exception_code(GetExceptionCode());
1337 __ENDTRY
1339 if (err != ERROR_SUCCESS)
1340 WARN("CloseNotifyHandle server call failed: %u\n", err);
1342 CloseHandle(data->calling_thread);
1343 HeapFree(GetProcessHeap(), 0, data);
1345 return 0;
1348 /******************************************************************************
1349 * NotifyServiceStatusChangeW (sechost.@)
1351 DWORD WINAPI DECLSPEC_HOTPATCH NotifyServiceStatusChangeW( SC_HANDLE service, DWORD mask,
1352 SERVICE_NOTIFYW *notify_buffer )
1354 DWORD err;
1355 BOOL b_dummy = FALSE;
1356 GUID g_dummy = {0};
1357 struct notify_data *data;
1359 TRACE( "%p 0x%x %p\n", service, mask, notify_buffer );
1361 if (!(data = heap_alloc_zero( sizeof(*data) )))
1362 return ERROR_NOT_ENOUGH_MEMORY;
1364 data->service = service;
1365 data->notify_buffer = notify_buffer;
1366 if (!DuplicateHandle( GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(),
1367 &data->calling_thread, 0, FALSE, DUPLICATE_SAME_ACCESS ))
1369 ERR("DuplicateHandle failed: %u\n", GetLastError());
1370 heap_free( data );
1371 return ERROR_NOT_ENOUGH_MEMORY;
1374 data->params.dwInfoLevel = 2;
1375 data->params.params = &data->cparams;
1377 data->cparams.dwNotifyMask = mask;
1379 EnterCriticalSection( &service_cs );
1381 __TRY
1383 err = svcctl_NotifyServiceStatusChange( service, data->params, &g_dummy,
1384 &g_dummy, &b_dummy, &data->notify_handle );
1386 __EXCEPT(rpc_filter)
1388 err = map_exception_code( GetExceptionCode() );
1390 __ENDTRY
1392 if (err != ERROR_SUCCESS)
1394 WARN("NotifyServiceStatusChange server call failed: %u\n", err);
1395 LeaveCriticalSection( &service_cs );
1396 CloseHandle( data->calling_thread );
1397 CloseHandle( data->ready_evt );
1398 heap_free( data );
1399 return err;
1402 CloseHandle( CreateThread( NULL, 0, &notify_thread, data, 0, NULL ) );
1404 list_add_tail( &notify_list, &data->entry );
1406 LeaveCriticalSection( &service_cs );
1408 return ERROR_SUCCESS;
1411 /* thunk for calling the RegisterServiceCtrlHandler handler function */
1412 static DWORD WINAPI ctrl_handler_thunk( DWORD control, DWORD type, void *data, void *context )
1414 LPHANDLER_FUNCTION func = context;
1416 func( control );
1417 return ERROR_SUCCESS;
1420 /******************************************************************************
1421 * RegisterServiceCtrlHandlerA (sechost.@)
1423 SERVICE_STATUS_HANDLE WINAPI DECLSPEC_HOTPATCH RegisterServiceCtrlHandlerA(
1424 const char *name, LPHANDLER_FUNCTION handler )
1426 return RegisterServiceCtrlHandlerExA( name, ctrl_handler_thunk, handler );
1429 /******************************************************************************
1430 * RegisterServiceCtrlHandlerW (sechost.@)
1432 SERVICE_STATUS_HANDLE WINAPI DECLSPEC_HOTPATCH RegisterServiceCtrlHandlerW(
1433 const WCHAR *name, LPHANDLER_FUNCTION handler )
1435 return RegisterServiceCtrlHandlerExW( name, ctrl_handler_thunk, handler );
1438 /******************************************************************************
1439 * RegisterServiceCtrlHandlerExA (sechost.@)
1441 SERVICE_STATUS_HANDLE WINAPI DECLSPEC_HOTPATCH RegisterServiceCtrlHandlerExA(
1442 const char *name, LPHANDLER_FUNCTION_EX handler, void *context )
1444 WCHAR *nameW;
1445 SERVICE_STATUS_HANDLE ret;
1447 nameW = heap_strdupAtoW( name );
1448 ret = RegisterServiceCtrlHandlerExW( nameW, handler, context );
1449 heap_free( nameW );
1450 return ret;
1453 static struct service_data *find_service_by_name( const WCHAR *name )
1455 unsigned int i;
1457 if (nb_services == 1) /* only one service (FIXME: should depend on OWN_PROCESS etc.) */
1458 return services[0];
1459 for (i = 0; i < nb_services; i++)
1460 if (!wcsicmp( name, services[i]->name )) return services[i];
1461 return NULL;
1464 /******************************************************************************
1465 * RegisterServiceCtrlHandlerExW (sechost.@)
1467 SERVICE_STATUS_HANDLE WINAPI DECLSPEC_HOTPATCH RegisterServiceCtrlHandlerExW(
1468 const WCHAR *name, LPHANDLER_FUNCTION_EX handler, void *context )
1470 struct service_data *service;
1471 SC_HANDLE handle = 0;
1473 TRACE( "%s %p %p\n", debugstr_w(name), handler, context );
1475 EnterCriticalSection( &service_cs );
1476 if ((service = find_service_by_name( name )))
1478 service->handler = handler;
1479 service->context = context;
1480 handle = service->handle;
1482 LeaveCriticalSection( &service_cs );
1484 if (!handle) SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
1485 return (SERVICE_STATUS_HANDLE)handle;
1488 /******************************************************************************
1489 * SetServiceStatus (sechost.@)
1491 BOOL WINAPI DECLSPEC_HOTPATCH SetServiceStatus( SERVICE_STATUS_HANDLE service, SERVICE_STATUS *status )
1493 DWORD err;
1495 TRACE( "%p %#x %#x %#x %#x %#x %#x %#x\n", service, status->dwServiceType,
1496 status->dwCurrentState, status->dwControlsAccepted, status->dwWin32ExitCode,
1497 status->dwServiceSpecificExitCode, status->dwCheckPoint, status->dwWaitHint );
1499 __TRY
1501 err = svcctl_SetServiceStatus( service, status );
1503 __EXCEPT(rpc_filter)
1505 err = map_exception_code( GetExceptionCode() );
1507 __ENDTRY
1509 if (!set_error( err ))
1510 return FALSE;
1512 if (status->dwCurrentState == SERVICE_STOPPED)
1514 unsigned int i, count = 0;
1515 EnterCriticalSection( &service_cs );
1516 for (i = 0; i < nb_services; i++)
1518 if (services[i]->handle == (SC_HANDLE)service) continue;
1519 if (services[i]->thread) count++;
1521 if (!count)
1523 stop_service = TRUE;
1524 SetEvent( service_event ); /* notify the main loop */
1526 LeaveCriticalSection( &service_cs );
1529 return TRUE;
1532 static WCHAR *service_get_pipe_name(void)
1534 static const WCHAR format[] = L"\\\\.\\pipe\\net\\NtControlPipe%u";
1535 WCHAR *name;
1536 DWORD len;
1537 HKEY service_current_key;
1538 DWORD service_current;
1539 LONG ret;
1540 DWORD type;
1542 ret = RegOpenKeyExW( HKEY_LOCAL_MACHINE,
1543 L"SYSTEM\\CurrentControlSet\\Control\\ServiceCurrent",
1544 0, KEY_QUERY_VALUE, &service_current_key );
1545 if (ret != ERROR_SUCCESS)
1546 return NULL;
1548 len = sizeof(service_current);
1549 ret = RegQueryValueExW( service_current_key, NULL, NULL, &type,
1550 (BYTE *)&service_current, &len );
1551 RegCloseKey(service_current_key);
1552 if (ret != ERROR_SUCCESS || type != REG_DWORD)
1553 return NULL;
1555 len = ARRAY_SIZE(format) + 10 /* strlenW("4294967295") */;
1556 name = heap_alloc(len * sizeof(WCHAR));
1557 if (!name)
1558 return NULL;
1560 swprintf( name, len, format, service_current );
1561 return name;
1564 static HANDLE service_open_pipe(void)
1566 WCHAR *pipe_name = service_get_pipe_name();
1567 HANDLE handle = INVALID_HANDLE_VALUE;
1571 handle = CreateFileW( pipe_name, GENERIC_READ|GENERIC_WRITE,
1572 0, NULL, OPEN_ALWAYS, 0, NULL );
1573 if (handle != INVALID_HANDLE_VALUE)
1574 break;
1575 if (GetLastError() != ERROR_PIPE_BUSY)
1576 break;
1577 } while (WaitNamedPipeW( pipe_name, NMPWAIT_USE_DEFAULT_WAIT ));
1578 heap_free(pipe_name);
1580 return handle;
1583 static DWORD WINAPI service_thread( void *arg )
1585 struct service_data *info = arg;
1586 WCHAR *str = info->args;
1587 DWORD argc = 0, len = 0;
1589 TRACE("%p\n", arg);
1591 while (str[len])
1593 len += wcslen( &str[len] ) + 1;
1594 argc++;
1596 len++;
1598 if (info->unicode)
1600 WCHAR **argv, *p;
1602 argv = heap_alloc( (argc+1)*sizeof(*argv) );
1603 for (argc = 0, p = str; *p; p += wcslen( p ) + 1)
1604 argv[argc++] = p;
1605 argv[argc] = NULL;
1607 info->proc.w( argc, argv );
1608 heap_free( argv );
1610 else
1612 char *strA, **argv, *p;
1613 DWORD lenA;
1615 lenA = WideCharToMultiByte( CP_ACP,0, str, len, NULL, 0, NULL, NULL );
1616 strA = heap_alloc(lenA);
1617 WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL);
1619 argv = heap_alloc( (argc+1)*sizeof(*argv) );
1620 for (argc = 0, p = strA; *p; p += strlen( p ) + 1)
1621 argv[argc++] = p;
1622 argv[argc] = NULL;
1624 info->proc.a( argc, argv );
1625 heap_free( argv );
1626 heap_free( strA );
1628 return 0;
1631 static DWORD service_handle_start( struct service_data *service, const void *data, DWORD data_size )
1633 DWORD count = data_size / sizeof(WCHAR);
1635 if (service->thread)
1637 WARN("service is not stopped\n");
1638 return ERROR_SERVICE_ALREADY_RUNNING;
1641 heap_free( service->args );
1642 service->args = heap_alloc( (count + 2) * sizeof(WCHAR) );
1643 if (count) memcpy( service->args, data, count * sizeof(WCHAR) );
1644 service->args[count++] = 0;
1645 service->args[count++] = 0;
1647 service->thread = CreateThread( NULL, 0, service_thread,
1648 service, 0, NULL );
1649 SetEvent( service_event ); /* notify the main loop */
1650 return 0;
1653 static DWORD service_handle_control( struct service_data *service, DWORD control, const void *data, DWORD data_size )
1655 DWORD ret = ERROR_INVALID_SERVICE_CONTROL;
1657 TRACE( "%s control %u data %p data_size %u\n", debugstr_w(service->name), control, data, data_size );
1659 if (control == SERVICE_CONTROL_START)
1660 ret = service_handle_start( service, data, data_size );
1661 else if (service->handler)
1662 ret = service->handler( control, 0, (void *)data, service->context );
1663 return ret;
1666 static DWORD WINAPI service_control_dispatcher( void *arg )
1668 struct dispatcher_data *disp = arg;
1670 /* dispatcher loop */
1671 while (1)
1673 struct service_data *service;
1674 service_start_info info;
1675 BYTE *data = NULL;
1676 WCHAR *name;
1677 BOOL r;
1678 DWORD data_size = 0, count, result;
1680 r = ReadFile( disp->pipe, &info, FIELD_OFFSET(service_start_info,data), &count, NULL );
1681 if (!r)
1683 if (GetLastError() != ERROR_BROKEN_PIPE)
1684 ERR( "pipe read failed error %u\n", GetLastError() );
1685 break;
1687 if (count != FIELD_OFFSET(service_start_info,data))
1689 ERR( "partial pipe read %u\n", count );
1690 break;
1692 if (count < info.total_size)
1694 data_size = info.total_size - FIELD_OFFSET(service_start_info,data);
1695 data = heap_alloc( data_size );
1696 r = ReadFile( disp->pipe, data, data_size, &count, NULL );
1697 if (!r)
1699 if (GetLastError() != ERROR_BROKEN_PIPE)
1700 ERR( "pipe read failed error %u\n", GetLastError() );
1701 heap_free( data );
1702 break;
1704 if (count != data_size)
1706 ERR( "partial pipe read %u/%u\n", count, data_size );
1707 heap_free( data );
1708 break;
1712 EnterCriticalSection( &service_cs );
1714 /* validate service name */
1715 name = (WCHAR *)data;
1716 if (!info.name_size || data_size < info.name_size * sizeof(WCHAR) || name[info.name_size - 1])
1718 ERR( "got request without valid service name\n" );
1719 result = ERROR_INVALID_PARAMETER;
1720 goto done;
1723 if (info.magic != SERVICE_PROTOCOL_MAGIC)
1725 ERR( "received invalid request for service %s\n", debugstr_w(name) );
1726 result = ERROR_INVALID_PARAMETER;
1727 goto done;
1730 /* find the service */
1731 if (!(service = find_service_by_name( name )))
1733 FIXME( "got request for unknown service %s\n", debugstr_w(name) );
1734 result = ERROR_INVALID_PARAMETER;
1735 goto done;
1738 if (!service->handle)
1740 if (!(service->handle = OpenServiceW( disp->manager, name, SERVICE_SET_STATUS )) ||
1741 !(service->full_access_handle = OpenServiceW( disp->manager, name,
1742 GENERIC_READ|GENERIC_WRITE )))
1743 FIXME( "failed to open service %s\n", debugstr_w(name) );
1746 data_size -= info.name_size * sizeof(WCHAR);
1747 result = service_handle_control(service, info.control, data_size ?
1748 &data[info.name_size * sizeof(WCHAR)] : NULL, data_size);
1750 done:
1751 LeaveCriticalSection( &service_cs );
1752 WriteFile( disp->pipe, &result, sizeof(result), &count, NULL );
1753 heap_free( data );
1756 CloseHandle( disp->pipe );
1757 CloseServiceHandle( disp->manager );
1758 heap_free( disp );
1759 return 1;
1762 /* wait for services which accept this type of message to become STOPPED */
1763 static void handle_shutdown_msg(DWORD msg, DWORD accept)
1765 SERVICE_STATUS st;
1766 SERVICE_PRESHUTDOWN_INFO spi;
1767 DWORD i, n = 0, sz, timeout = 2000;
1768 ULONGLONG stop_time;
1769 BOOL res, done = TRUE;
1770 SC_HANDLE *wait_handles = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SC_HANDLE) * nb_services );
1772 EnterCriticalSection( &service_cs );
1773 for (i = 0; i < nb_services; i++)
1775 res = QueryServiceStatus( services[i]->full_access_handle, &st );
1776 if (!res || st.dwCurrentState == SERVICE_STOPPED || !(st.dwControlsAccepted & accept))
1777 continue;
1779 done = FALSE;
1781 if (accept == SERVICE_ACCEPT_PRESHUTDOWN)
1783 res = QueryServiceConfig2W( services[i]->full_access_handle, SERVICE_CONFIG_PRESHUTDOWN_INFO,
1784 (BYTE *)&spi, sizeof(spi), &sz );
1785 if (res)
1787 FIXME( "service should be able to delay shutdown\n" );
1788 timeout = max( spi.dwPreshutdownTimeout, timeout );
1792 service_handle_control( services[i], msg, NULL, 0 );
1793 wait_handles[n++] = services[i]->full_access_handle;
1795 LeaveCriticalSection( &service_cs );
1797 /* FIXME: these timeouts should be more generous, but we can't currently delay prefix shutdown */
1798 timeout = min( timeout, 3000 );
1799 stop_time = GetTickCount64() + timeout;
1801 while (!done && GetTickCount64() < stop_time)
1803 done = TRUE;
1804 for (i = 0; i < n; i++)
1806 res = QueryServiceStatus( wait_handles[i], &st );
1807 if (!res || st.dwCurrentState == SERVICE_STOPPED)
1808 continue;
1810 done = FALSE;
1811 Sleep( 100 );
1812 break;
1816 HeapFree( GetProcessHeap(), 0, wait_handles );
1819 static BOOL service_run_main_thread(void)
1821 DWORD i, n, ret;
1822 HANDLE wait_handles[MAXIMUM_WAIT_OBJECTS];
1823 UINT wait_services[MAXIMUM_WAIT_OBJECTS];
1824 struct dispatcher_data *disp = heap_alloc( sizeof(*disp) );
1826 disp->manager = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
1827 if (!disp->manager)
1829 ERR("failed to open service manager error %u\n", GetLastError());
1830 heap_free( disp );
1831 return FALSE;
1834 disp->pipe = service_open_pipe();
1835 if (disp->pipe == INVALID_HANDLE_VALUE)
1837 WARN("failed to create control pipe error %u\n", GetLastError());
1838 CloseServiceHandle( disp->manager );
1839 heap_free( disp );
1840 SetLastError( ERROR_FAILED_SERVICE_CONTROLLER_CONNECT );
1841 return FALSE;
1844 service_event = CreateEventW( NULL, FALSE, FALSE, NULL );
1845 stop_service = FALSE;
1847 /* FIXME: service_control_dispatcher should be merged into the main thread */
1848 wait_handles[0] = __wine_make_process_system();
1849 wait_handles[1] = CreateThread( NULL, 0, service_control_dispatcher, disp, 0, NULL );
1850 wait_handles[2] = service_event;
1852 TRACE("Starting %d services running as process %d\n",
1853 nb_services, GetCurrentProcessId());
1855 /* wait for all the threads to pack up and exit */
1856 while (!stop_service)
1858 EnterCriticalSection( &service_cs );
1859 for (i = 0, n = 3; i < nb_services && n < MAXIMUM_WAIT_OBJECTS; i++)
1861 if (!services[i]->thread) continue;
1862 wait_services[n] = i;
1863 wait_handles[n++] = services[i]->thread;
1865 LeaveCriticalSection( &service_cs );
1867 ret = WaitForMultipleObjects( n, wait_handles, FALSE, INFINITE );
1868 if (!ret) /* system process event */
1870 handle_shutdown_msg(SERVICE_CONTROL_PRESHUTDOWN, SERVICE_ACCEPT_PRESHUTDOWN);
1871 handle_shutdown_msg(SERVICE_CONTROL_SHUTDOWN, SERVICE_ACCEPT_SHUTDOWN);
1872 ExitProcess(0);
1874 else if (ret == 1)
1876 TRACE( "control dispatcher exited, shutting down\n" );
1877 /* FIXME: we should maybe send a shutdown control to running services */
1878 ExitProcess(0);
1880 else if (ret == 2)
1882 continue; /* rebuild the list */
1884 else if (ret < n)
1886 i = wait_services[ret];
1887 EnterCriticalSection( &service_cs );
1888 CloseHandle( services[i]->thread );
1889 services[i]->thread = NULL;
1890 LeaveCriticalSection( &service_cs );
1892 else return FALSE;
1895 return TRUE;
1898 /******************************************************************************
1899 * StartServiceCtrlDispatcherA (sechost.@)
1901 BOOL WINAPI DECLSPEC_HOTPATCH StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *servent )
1903 struct service_data *info;
1904 unsigned int i;
1906 TRACE("%p\n", servent);
1908 if (nb_services)
1910 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
1911 return FALSE;
1913 while (servent[nb_services].lpServiceName) nb_services++;
1914 if (!nb_services)
1916 SetLastError( ERROR_INVALID_PARAMETER );
1917 return FALSE;
1920 services = heap_alloc( nb_services * sizeof(*services) );
1922 for (i = 0; i < nb_services; i++)
1924 DWORD len = MultiByteToWideChar( CP_ACP, 0, servent[i].lpServiceName, -1, NULL, 0 );
1925 DWORD sz = FIELD_OFFSET( struct service_data, name[len] );
1926 info = heap_alloc_zero( sz );
1927 MultiByteToWideChar( CP_ACP, 0, servent[i].lpServiceName, -1, info->name, len );
1928 info->proc.a = servent[i].lpServiceProc;
1929 info->unicode = FALSE;
1930 services[i] = info;
1933 return service_run_main_thread();
1936 /******************************************************************************
1937 * StartServiceCtrlDispatcherW (sechost.@)
1939 BOOL WINAPI DECLSPEC_HOTPATCH StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW *servent )
1941 struct service_data *info;
1942 unsigned int i;
1944 TRACE("%p\n", servent);
1946 if (nb_services)
1948 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
1949 return FALSE;
1951 while (servent[nb_services].lpServiceName) nb_services++;
1952 if (!nb_services)
1954 SetLastError( ERROR_INVALID_PARAMETER );
1955 return FALSE;
1958 services = heap_alloc( nb_services * sizeof(*services) );
1960 for (i = 0; i < nb_services; i++)
1962 DWORD len = wcslen( servent[i].lpServiceName ) + 1;
1963 DWORD sz = FIELD_OFFSET( struct service_data, name[len] );
1964 info = heap_alloc_zero( sz );
1965 wcscpy( info->name, servent[i].lpServiceName );
1966 info->proc.w = servent[i].lpServiceProc;
1967 info->unicode = TRUE;
1968 services[i] = info;
1971 return service_run_main_thread();
1974 struct device_notification_details
1976 DWORD (CALLBACK *cb)(HANDLE handle, DWORD flags, DEV_BROADCAST_HDR *header);
1977 HANDLE handle;
1980 static HANDLE device_notify_thread;
1981 static struct list device_notify_list = LIST_INIT(device_notify_list);
1983 struct device_notify_registration
1985 struct list entry;
1986 struct device_notification_details details;
1989 static DWORD WINAPI device_notify_proc( void *arg )
1991 WCHAR endpoint[] = L"\\pipe\\wine_plugplay";
1992 WCHAR protseq[] = L"ncalrpc";
1993 RPC_WSTR binding_str;
1994 DWORD err = ERROR_SUCCESS;
1995 struct device_notify_registration *registration;
1996 plugplay_rpc_handle handle = NULL;
1997 DWORD code = 0;
1998 unsigned int size;
1999 BYTE *buf;
2001 if ((err = RpcStringBindingComposeW( NULL, protseq, NULL, endpoint, NULL, &binding_str )))
2003 ERR("RpcStringBindingCompose() failed, error %#x\n", err);
2004 return err;
2006 err = RpcBindingFromStringBindingW( binding_str, &plugplay_binding_handle );
2007 RpcStringFreeW( &binding_str );
2008 if (err)
2010 ERR("RpcBindingFromStringBinding() failed, error %#x\n", err);
2011 return err;
2014 __TRY
2016 handle = plugplay_register_listener();
2018 __EXCEPT(rpc_filter)
2020 err = map_exception_code( GetExceptionCode() );
2022 __ENDTRY
2024 if (!handle)
2026 ERR("failed to open RPC handle, error %u\n", err);
2027 return 1;
2030 for (;;)
2032 buf = NULL;
2033 __TRY
2035 code = plugplay_get_event( handle, &buf, &size );
2036 err = ERROR_SUCCESS;
2038 __EXCEPT(rpc_filter)
2040 err = map_exception_code( GetExceptionCode() );
2042 __ENDTRY
2044 if (err)
2046 ERR("failed to get event, error %u\n", err);
2047 break;
2050 EnterCriticalSection( &service_cs );
2051 LIST_FOR_EACH_ENTRY(registration, &device_notify_list, struct device_notify_registration, entry)
2053 registration->details.cb( registration->details.handle, code, (DEV_BROADCAST_HDR *)buf );
2055 LeaveCriticalSection(&service_cs);
2056 MIDL_user_free(buf);
2059 __TRY
2061 plugplay_unregister_listener( handle );
2063 __EXCEPT(rpc_filter)
2066 __ENDTRY
2068 RpcBindingFree( &plugplay_binding_handle );
2069 return 0;
2072 /******************************************************************************
2073 * I_ScRegisterDeviceNotification (sechost.@)
2075 HDEVNOTIFY WINAPI I_ScRegisterDeviceNotification( struct device_notification_details *details,
2076 void *filter, DWORD flags )
2078 struct device_notify_registration *registration;
2080 TRACE("callback %p, handle %p, filter %p, flags %#x\n", details->cb, details->handle, filter, flags);
2082 if (filter) FIXME("Notification filters are not yet implemented.\n");
2084 if (!(registration = heap_alloc(sizeof(struct device_notify_registration))))
2086 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2087 return NULL;
2090 registration->details = *details;
2092 EnterCriticalSection( &service_cs );
2093 list_add_tail( &device_notify_list, &registration->entry );
2095 if (!device_notify_thread)
2096 device_notify_thread = CreateThread( NULL, 0, device_notify_proc, NULL, 0, NULL );
2098 LeaveCriticalSection( &service_cs );
2100 return registration;
2103 /******************************************************************************
2104 * I_ScUnregisterDeviceNotification (sechost.@)
2106 BOOL WINAPI I_ScUnregisterDeviceNotification( HDEVNOTIFY handle )
2108 struct device_notify_registration *registration = handle;
2110 TRACE("%p\n", handle);
2112 if (!handle)
2113 return FALSE;
2115 EnterCriticalSection( &service_cs );
2116 list_remove( &registration->entry );
2117 LeaveCriticalSection(&service_cs);
2118 heap_free( registration );
2119 return TRUE;