include: Be consistent in naming regarding MSF's block.
[wine.git] / dlls / sechost / service.c
blobb00e5536edaefa9828628b105c624f19e86af936
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 #define WINADVAPI
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winsvc.h"
29 #include "winternl.h"
30 #include "winuser.h"
31 #include "dbt.h"
33 #include "wine/debug.h"
34 #include "wine/exception.h"
35 #include "wine/heap.h"
36 #include "wine/list.h"
38 #include "svcctl.h"
39 #include "plugplay.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(service);
43 struct notify_data
45 SC_HANDLE service;
46 SC_RPC_NOTIFY_PARAMS params;
47 SERVICE_NOTIFY_STATUS_CHANGE_PARAMS_2 cparams;
48 SC_NOTIFY_RPC_HANDLE notify_handle;
49 SERVICE_NOTIFYW *notify_buffer;
50 HANDLE calling_thread, ready_evt;
51 struct list entry;
54 static struct list notify_list = LIST_INIT(notify_list);
56 static CRITICAL_SECTION service_cs;
57 static CRITICAL_SECTION_DEBUG service_cs_debug =
59 0, 0, &service_cs,
60 { &service_cs_debug.ProcessLocksList,
61 &service_cs_debug.ProcessLocksList },
62 0, 0, { (DWORD_PTR)(__FILE__ ": service_cs") }
64 static CRITICAL_SECTION service_cs = { &service_cs_debug, -1, 0, 0, 0, 0 };
66 struct service_data
68 LPHANDLER_FUNCTION_EX handler;
69 void *context;
70 HANDLE thread;
71 SC_HANDLE handle;
72 SC_HANDLE full_access_handle;
73 unsigned int unicode : 1;
74 union
76 LPSERVICE_MAIN_FUNCTIONA a;
77 LPSERVICE_MAIN_FUNCTIONW w;
78 } proc;
79 WCHAR *args;
80 WCHAR name[1];
83 struct dispatcher_data
85 SC_HANDLE manager;
86 HANDLE pipe;
89 static struct service_data **services;
90 static unsigned int nb_services;
91 static HANDLE service_event;
92 static BOOL stop_service;
94 static WCHAR *heap_strdupAtoW( const char *src )
96 WCHAR *dst = NULL;
97 if (src)
99 DWORD len = MultiByteToWideChar( CP_ACP, 0, src, -1, NULL, 0 );
100 if ((dst = heap_alloc( len * sizeof(WCHAR) ))) MultiByteToWideChar( CP_ACP, 0, src, -1, dst, len );
102 return dst;
105 static WCHAR *heap_strdup_multi_AtoW( const char *src )
107 WCHAR *dst = NULL;
108 const char *p = src;
109 DWORD len;
111 if (!src) return NULL;
113 while (*p) p += strlen(p) + 1;
114 for (p = src; *p; p += strlen(p) + 1);
115 p++; /* final null */
116 len = MultiByteToWideChar( CP_ACP, 0, src, p - src, NULL, 0 );
117 if ((dst = heap_alloc( len * sizeof(WCHAR) ))) MultiByteToWideChar( CP_ACP, 0, src, p - src, dst, len );
118 return dst;
121 static inline DWORD multisz_size( const WCHAR *str )
123 const WCHAR *p = str;
125 if (!str) return 0;
127 while (*p) p += wcslen(p) + 1;
128 return (p - str + 1) * sizeof(WCHAR);
131 void __RPC_FAR * __RPC_USER MIDL_user_allocate( SIZE_T len )
133 return heap_alloc(len);
136 void __RPC_USER MIDL_user_free( void __RPC_FAR *ptr )
138 heap_free(ptr);
141 static LONG WINAPI rpc_filter( EXCEPTION_POINTERS *eptr )
143 return I_RpcExceptionFilter( eptr->ExceptionRecord->ExceptionCode );
146 static DWORD map_exception_code( DWORD exception_code )
148 switch (exception_code)
150 case RPC_X_NULL_REF_POINTER:
151 return ERROR_INVALID_ADDRESS;
152 case RPC_X_ENUM_VALUE_OUT_OF_RANGE:
153 case RPC_X_BYTE_COUNT_TOO_SMALL:
154 return ERROR_INVALID_PARAMETER;
155 case RPC_S_INVALID_BINDING:
156 case RPC_X_SS_IN_NULL_CONTEXT:
157 return ERROR_INVALID_HANDLE;
158 default:
159 return exception_code;
163 static handle_t rpc_wstr_bind( RPC_WSTR str )
165 WCHAR transport[] = SVCCTL_TRANSPORT;
166 WCHAR endpoint[] = SVCCTL_ENDPOINT;
167 RPC_WSTR binding_str;
168 RPC_STATUS status;
169 handle_t rpc_handle;
171 status = RpcStringBindingComposeW( NULL, transport, str, endpoint, NULL, &binding_str );
172 if (status != RPC_S_OK)
174 ERR("RpcStringBindingComposeW failed, error %ld\n", status);
175 return NULL;
178 status = RpcBindingFromStringBindingW( binding_str, &rpc_handle );
179 RpcStringFreeW( &binding_str );
181 if (status != RPC_S_OK)
183 ERR("Couldn't connect to services.exe, error %ld\n", status);
184 return NULL;
187 return rpc_handle;
190 static handle_t rpc_cstr_bind(RPC_CSTR str)
192 RPC_CSTR transport = (RPC_CSTR)SVCCTL_TRANSPORTA;
193 RPC_CSTR endpoint = (RPC_CSTR)SVCCTL_ENDPOINTA;
194 RPC_CSTR binding_str;
195 RPC_STATUS status;
196 handle_t rpc_handle;
198 status = RpcStringBindingComposeA( NULL, transport, str, endpoint, NULL, &binding_str );
199 if (status != RPC_S_OK)
201 ERR("RpcStringBindingComposeA failed, error %ld\n", status);
202 return NULL;
205 status = RpcBindingFromStringBindingA( binding_str, &rpc_handle );
206 RpcStringFreeA( &binding_str );
208 if (status != RPC_S_OK)
210 ERR("Couldn't connect to services.exe, error %ld\n", status);
211 return NULL;
214 return rpc_handle;
217 DECLSPEC_HIDDEN handle_t __RPC_USER MACHINE_HANDLEA_bind( MACHINE_HANDLEA name )
219 return rpc_cstr_bind( (RPC_CSTR)name );
222 DECLSPEC_HIDDEN void __RPC_USER MACHINE_HANDLEA_unbind( MACHINE_HANDLEA name, handle_t h )
224 RpcBindingFree( &h );
227 DECLSPEC_HIDDEN handle_t __RPC_USER MACHINE_HANDLEW_bind( MACHINE_HANDLEW name )
229 return rpc_wstr_bind( (RPC_WSTR)name );
232 DECLSPEC_HIDDEN void __RPC_USER MACHINE_HANDLEW_unbind( MACHINE_HANDLEW name, handle_t h )
234 RpcBindingFree( &h );
237 DECLSPEC_HIDDEN handle_t __RPC_USER SVCCTL_HANDLEW_bind( SVCCTL_HANDLEW name )
239 return rpc_wstr_bind( (RPC_WSTR)name );
242 DECLSPEC_HIDDEN void __RPC_USER SVCCTL_HANDLEW_unbind( SVCCTL_HANDLEW name, handle_t h )
244 RpcBindingFree( &h );
247 static BOOL set_error( DWORD err )
249 if (err) SetLastError( err );
250 return !err;
253 /******************************************************************************
254 * OpenSCManagerA (sechost.@)
256 SC_HANDLE WINAPI DECLSPEC_HOTPATCH OpenSCManagerA( const char *machine, const char *database, DWORD access )
258 WCHAR *machineW, *databaseW;
259 SC_HANDLE ret;
261 machineW = heap_strdupAtoW( machine );
262 databaseW = heap_strdupAtoW( database );
263 ret = OpenSCManagerW( machineW, databaseW, access );
264 heap_free( databaseW );
265 heap_free( machineW );
266 return ret;
269 /******************************************************************************
270 * OpenSCManagerW (sechost.@)
272 SC_HANDLE WINAPI DECLSPEC_HOTPATCH OpenSCManagerW( const WCHAR *machine, const WCHAR *database, DWORD access )
274 SC_RPC_HANDLE handle = NULL;
275 DWORD err;
277 TRACE( "%s %s %#lx\n", debugstr_w(machine), debugstr_w(database), access );
279 __TRY
281 err = svcctl_OpenSCManagerW( machine, database, access, &handle );
283 __EXCEPT(rpc_filter)
285 err = map_exception_code( GetExceptionCode() );
287 __ENDTRY
289 if (!err) return handle;
290 SetLastError( err );
291 return NULL;
294 /******************************************************************************
295 * OpenServiceA (sechost.@)
297 SC_HANDLE WINAPI DECLSPEC_HOTPATCH OpenServiceA( SC_HANDLE manager, const char *name, DWORD access )
299 WCHAR *nameW;
300 SC_HANDLE ret;
302 TRACE( "%p %s %#lx\n", manager, debugstr_a(name), access );
304 nameW = heap_strdupAtoW( name );
305 ret = OpenServiceW( manager, nameW, access );
306 heap_free( nameW );
307 return ret;
310 /******************************************************************************
311 * OpenServiceW (sechost.@)
313 SC_HANDLE WINAPI DECLSPEC_HOTPATCH OpenServiceW( SC_HANDLE manager, const WCHAR *name, DWORD access )
315 SC_RPC_HANDLE handle = NULL;
316 DWORD err;
318 TRACE( "%p %s %#lx\n", manager, debugstr_w(name), access );
320 if (!manager)
322 SetLastError( ERROR_INVALID_HANDLE );
323 return NULL;
326 __TRY
328 err = svcctl_OpenServiceW( manager, name, access, &handle );
330 __EXCEPT(rpc_filter)
332 err = map_exception_code( GetExceptionCode() );
334 __ENDTRY
336 if (!err) return handle;
337 SetLastError( err );
338 return 0;
341 /******************************************************************************
342 * CreateServiceA (sechost.@)
344 SC_HANDLE WINAPI DECLSPEC_HOTPATCH CreateServiceA( SC_HANDLE manager, const char *name, const char *display_name,
345 DWORD access, DWORD service_type, DWORD start_type,
346 DWORD error_control, const char *path, const char *group,
347 DWORD *tag, const char *dependencies, const char *username,
348 const char *password )
350 WCHAR *nameW, *display_nameW, *pathW, *groupW, *dependenciesW, *usernameW, *passwordW;
351 SC_HANDLE handle;
353 TRACE( "%p %s %s\n", manager, debugstr_a(name), debugstr_a(display_name) );
355 nameW = heap_strdupAtoW( name );
356 display_nameW = heap_strdupAtoW( display_name );
357 pathW = heap_strdupAtoW( path );
358 groupW = heap_strdupAtoW( group );
359 dependenciesW = heap_strdup_multi_AtoW( dependencies );
360 usernameW = heap_strdupAtoW( username );
361 passwordW = heap_strdupAtoW( password );
363 handle = CreateServiceW( manager, nameW, display_nameW, access, service_type, start_type, error_control,
364 pathW, groupW, tag, dependenciesW, usernameW, passwordW );
366 heap_free( nameW );
367 heap_free( display_nameW );
368 heap_free( pathW );
369 heap_free( groupW );
370 heap_free( dependenciesW );
371 heap_free( usernameW );
372 heap_free( passwordW );
374 return handle;
377 /******************************************************************************
378 * CreateServiceW (sechost.@)
380 SC_HANDLE WINAPI DECLSPEC_HOTPATCH CreateServiceW( SC_HANDLE manager, const WCHAR *name, const WCHAR *display_name,
381 DWORD access, DWORD service_type, DWORD start_type,
382 DWORD error_control, const WCHAR *path, const WCHAR *group,
383 DWORD *tag, const WCHAR *dependencies, const WCHAR *username,
384 const WCHAR *password )
386 SC_RPC_HANDLE handle = NULL;
387 DWORD err;
388 SIZE_T password_size = 0;
390 TRACE( "%p %s %s\n", manager, debugstr_w(name), debugstr_w(display_name) );
392 if (!manager)
394 SetLastError( ERROR_INVALID_HANDLE );
395 return 0;
398 if (password) password_size = (wcslen(password) + 1) * sizeof(WCHAR);
400 __TRY
402 BOOL is_wow64;
404 if (IsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64)
405 err = svcctl_CreateServiceWOW64W( manager, name, display_name, access, service_type, start_type,
406 error_control, path, group, tag, (const BYTE *)dependencies,
407 multisz_size( dependencies ), username, (const BYTE *)password,
408 password_size, &handle );
409 else
410 err = svcctl_CreateServiceW( manager, name, display_name, access, service_type, start_type,
411 error_control, path, group, tag, (const BYTE *)dependencies,
412 multisz_size( dependencies ), username, (const BYTE *)password,
413 password_size, &handle );
415 __EXCEPT(rpc_filter)
417 err = map_exception_code( GetExceptionCode() );
419 __ENDTRY
421 if (!err) return handle;
422 SetLastError( err );
423 return NULL;
426 /******************************************************************************
427 * DeleteService (sechost.@)
429 BOOL WINAPI DECLSPEC_HOTPATCH DeleteService( SC_HANDLE service )
431 DWORD err;
433 TRACE( "%p\n", service );
435 __TRY
437 err = svcctl_DeleteService( service );
439 __EXCEPT(rpc_filter)
441 err = map_exception_code( GetExceptionCode() );
443 __ENDTRY
445 return set_error( err );
448 /******************************************************************************
449 * CloseServiceHandle (sechost.@)
451 BOOL WINAPI DECLSPEC_HOTPATCH CloseServiceHandle( SC_HANDLE handle )
453 DWORD err;
455 TRACE( "%p\n", handle );
457 __TRY
459 err = svcctl_CloseServiceHandle( (SC_RPC_HANDLE *)&handle );
461 __EXCEPT(rpc_filter)
463 err = map_exception_code( GetExceptionCode() );
465 __ENDTRY
467 return set_error( err );
470 /******************************************************************************
471 * ChangeServiceConfig2A (sechost.@)
473 BOOL WINAPI DECLSPEC_HOTPATCH ChangeServiceConfig2A( SC_HANDLE service, DWORD level, void *info)
475 BOOL r = FALSE;
477 TRACE( "%p %ld %p\n", service, level, info );
479 if (level == SERVICE_CONFIG_DESCRIPTION)
481 SERVICE_DESCRIPTIONA *sd = info;
482 SERVICE_DESCRIPTIONW sdw;
484 sdw.lpDescription = heap_strdupAtoW( sd->lpDescription );
486 r = ChangeServiceConfig2W( service, level, &sdw );
488 heap_free( sdw.lpDescription );
490 else if (level == SERVICE_CONFIG_FAILURE_ACTIONS)
492 SERVICE_FAILURE_ACTIONSA *fa = info;
493 SERVICE_FAILURE_ACTIONSW faw;
495 faw.dwResetPeriod = fa->dwResetPeriod;
496 faw.lpRebootMsg = heap_strdupAtoW( fa->lpRebootMsg );
497 faw.lpCommand = heap_strdupAtoW( fa->lpCommand );
498 faw.cActions = fa->cActions;
499 faw.lpsaActions = fa->lpsaActions;
501 r = ChangeServiceConfig2W( service, level, &faw );
503 heap_free( faw.lpRebootMsg );
504 heap_free( faw.lpCommand );
506 else if (level == SERVICE_CONFIG_PRESHUTDOWN_INFO)
508 r = ChangeServiceConfig2W( service, level, info );
510 else
511 SetLastError( ERROR_INVALID_PARAMETER );
513 return r;
516 /******************************************************************************
517 * ChangeServiceConfig2W (sechost.@)
519 BOOL WINAPI DECLSPEC_HOTPATCH ChangeServiceConfig2W( SC_HANDLE service, DWORD level, void *info )
521 SERVICE_RPC_REQUIRED_PRIVILEGES_INFO rpc_privinfo;
522 DWORD err;
524 __TRY
526 SC_RPC_CONFIG_INFOW rpc_info;
528 rpc_info.dwInfoLevel = level;
529 if (level == SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO)
531 SERVICE_REQUIRED_PRIVILEGES_INFOW *privinfo = info;
533 rpc_privinfo.cbRequiredPrivileges = multisz_size( privinfo->pmszRequiredPrivileges );
534 rpc_privinfo.pRequiredPrivileges = (BYTE *)privinfo->pmszRequiredPrivileges;
535 rpc_info.privinfo = &rpc_privinfo;
537 else
538 rpc_info.descr = info;
539 err = svcctl_ChangeServiceConfig2W( service, rpc_info );
541 __EXCEPT(rpc_filter)
543 err = map_exception_code( GetExceptionCode() );
545 __ENDTRY
547 return set_error( err );
550 /******************************************************************************
551 * ChangeServiceConfigA (sechost.@)
553 BOOL WINAPI DECLSPEC_HOTPATCH ChangeServiceConfigA( SC_HANDLE service, DWORD service_type, DWORD start_type,
554 DWORD error_control, const char *path, const char *group,
555 DWORD *tag, const char *dependencies, const char *username,
556 const char *password, const char *display_name )
558 WCHAR *pathW, *groupW, *dependenciesW, *usernameW, *passwordW, *display_nameW;
559 BOOL r;
561 TRACE( "%p %ld %ld %ld %s %s %p %p %s %s %s\n", service, service_type, start_type,
562 error_control, debugstr_a(path), debugstr_a(group), tag, dependencies,
563 debugstr_a(username), debugstr_a(password), debugstr_a(display_name) );
565 pathW = heap_strdupAtoW( path );
566 groupW = heap_strdupAtoW( group );
567 dependenciesW = heap_strdup_multi_AtoW( dependencies );
568 usernameW = heap_strdupAtoW( username );
569 passwordW = heap_strdupAtoW( password );
570 display_nameW = heap_strdupAtoW( display_name );
572 r = ChangeServiceConfigW( service, service_type, start_type, error_control, pathW,
573 groupW, tag, dependenciesW, usernameW, passwordW, display_nameW );
575 heap_free( pathW );
576 heap_free( groupW );
577 heap_free( dependenciesW );
578 heap_free( usernameW );
579 heap_free( passwordW );
580 heap_free( display_nameW );
582 return r;
585 /******************************************************************************
586 * ChangeServiceConfigW (sechost.@)
588 BOOL WINAPI DECLSPEC_HOTPATCH ChangeServiceConfigW( SC_HANDLE service, DWORD service_type, DWORD start_type,
589 DWORD error_control, const WCHAR *path, const WCHAR *group,
590 DWORD *tag, const WCHAR *dependencies, const WCHAR *username,
591 const WCHAR *password, const WCHAR *display_name )
593 DWORD password_size;
594 DWORD err;
596 TRACE( "%p %ld %ld %ld %s %s %p %p %s %s %s\n", service, service_type, start_type,
597 error_control, debugstr_w(path), debugstr_w(group), tag, dependencies,
598 debugstr_w(username), debugstr_w(password), debugstr_w(display_name) );
600 password_size = password ? (wcslen(password) + 1) * sizeof(WCHAR) : 0;
602 __TRY
604 err = svcctl_ChangeServiceConfigW( service, service_type, start_type, error_control, path, group, tag,
605 (const BYTE *)dependencies, multisz_size(dependencies), username,
606 (const BYTE *)password, password_size, display_name );
608 __EXCEPT(rpc_filter)
610 err = map_exception_code( GetExceptionCode() );
612 __ENDTRY
614 return set_error( err );
617 /******************************************************************************
618 * QueryServiceConfigA (sechost.@)
620 BOOL WINAPI DECLSPEC_HOTPATCH QueryServiceConfigA( SC_HANDLE service, QUERY_SERVICE_CONFIGA *config,
621 DWORD size, DWORD *ret_size )
623 DWORD n;
624 char *p, *buffer;
625 BOOL ret;
626 QUERY_SERVICE_CONFIGW *configW;
628 TRACE( "%p %p %ld %p\n", service, config, size, ret_size );
630 if (!(buffer = heap_alloc( 2 * size ))) return set_error( ERROR_NOT_ENOUGH_MEMORY );
631 configW = (QUERY_SERVICE_CONFIGW *)buffer;
632 ret = QueryServiceConfigW( service, configW, 2 * size, ret_size );
633 if (!ret) goto done;
635 config->dwServiceType = configW->dwServiceType;
636 config->dwStartType = configW->dwStartType;
637 config->dwErrorControl = configW->dwErrorControl;
638 config->lpBinaryPathName = NULL;
639 config->lpLoadOrderGroup = NULL;
640 config->dwTagId = configW->dwTagId;
641 config->lpDependencies = NULL;
642 config->lpServiceStartName = NULL;
643 config->lpDisplayName = NULL;
645 p = (char *)(config + 1);
646 n = size - sizeof(*config);
647 ret = FALSE;
649 #define MAP_STR(str) \
650 do { \
651 if (configW->str) \
653 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
654 if (!sz) goto done; \
655 config->str = p; \
656 p += sz; \
657 n -= sz; \
659 } while (0)
661 MAP_STR( lpBinaryPathName );
662 MAP_STR( lpLoadOrderGroup );
663 MAP_STR( lpDependencies );
664 MAP_STR( lpServiceStartName );
665 MAP_STR( lpDisplayName );
666 #undef MAP_STR
668 *ret_size = p - (char *)config;
669 ret = TRUE;
671 done:
672 heap_free( buffer );
673 return ret;
676 static DWORD move_string_to_buffer(BYTE **buf, WCHAR **string_ptr)
678 DWORD cb;
680 if (!*string_ptr)
682 cb = sizeof(WCHAR);
683 memset(*buf, 0, cb);
685 else
687 cb = (wcslen( *string_ptr ) + 1) * sizeof(WCHAR);
688 memcpy(*buf, *string_ptr, cb);
689 MIDL_user_free( *string_ptr );
692 *string_ptr = (WCHAR *)*buf;
693 *buf += cb;
695 return cb;
698 static DWORD size_string( const WCHAR *string )
700 return (string ? (wcslen( string ) + 1) * sizeof(WCHAR) : sizeof(WCHAR));
703 /******************************************************************************
704 * QueryServiceConfigW (sechost.@)
706 BOOL WINAPI DECLSPEC_HOTPATCH QueryServiceConfigW( SC_HANDLE service, QUERY_SERVICE_CONFIGW *ret_config,
707 DWORD size, DWORD *ret_size )
709 QUERY_SERVICE_CONFIGW config;
710 DWORD total;
711 DWORD err;
712 BYTE *bufpos;
714 TRACE( "%p %p %ld %p\n", service, ret_config, size, ret_size );
716 memset(&config, 0, sizeof(config));
718 __TRY
720 err = svcctl_QueryServiceConfigW( service, &config, size, ret_size );
722 __EXCEPT(rpc_filter)
724 err = map_exception_code( GetExceptionCode() );
726 __ENDTRY
728 if (err) return set_error( err );
730 /* calculate the size required first */
731 total = sizeof(QUERY_SERVICE_CONFIGW);
732 total += size_string( config.lpBinaryPathName );
733 total += size_string( config.lpLoadOrderGroup );
734 total += size_string( config.lpDependencies );
735 total += size_string( config.lpServiceStartName );
736 total += size_string( config.lpDisplayName );
738 *ret_size = total;
740 /* if there's not enough memory, return an error */
741 if (size < total)
743 SetLastError( ERROR_INSUFFICIENT_BUFFER );
744 MIDL_user_free( config.lpBinaryPathName );
745 MIDL_user_free( config.lpLoadOrderGroup );
746 MIDL_user_free( config.lpDependencies );
747 MIDL_user_free( config.lpServiceStartName );
748 MIDL_user_free( config.lpDisplayName );
749 return FALSE;
752 *ret_config = config;
753 bufpos = ((BYTE *)ret_config) + sizeof(QUERY_SERVICE_CONFIGW);
754 move_string_to_buffer( &bufpos, &ret_config->lpBinaryPathName );
755 move_string_to_buffer( &bufpos, &ret_config->lpLoadOrderGroup );
756 move_string_to_buffer( &bufpos, &ret_config->lpDependencies );
757 move_string_to_buffer( &bufpos, &ret_config->lpServiceStartName );
758 move_string_to_buffer( &bufpos, &ret_config->lpDisplayName );
760 TRACE( "Image path = %s\n", debugstr_w( ret_config->lpBinaryPathName ) );
761 TRACE( "Group = %s\n", debugstr_w( ret_config->lpLoadOrderGroup ) );
762 TRACE( "Dependencies = %s\n", debugstr_w( ret_config->lpDependencies ) );
763 TRACE( "Service account name = %s\n", debugstr_w( ret_config->lpServiceStartName ) );
764 TRACE( "Display name = %s\n", debugstr_w( ret_config->lpDisplayName ) );
766 return TRUE;
769 /******************************************************************************
770 * QueryServiceConfig2A (sechost.@)
772 BOOL WINAPI DECLSPEC_HOTPATCH QueryServiceConfig2A( SC_HANDLE service, DWORD level, BYTE *buffer,
773 DWORD size, DWORD *ret_size )
775 BYTE *bufferW = NULL;
777 TRACE( "%p %lu %p %lu %p\n", service, level, buffer, size, ret_size );
779 if (buffer && size)
780 bufferW = heap_alloc( size );
782 if (!QueryServiceConfig2W( service, level, bufferW, size, ret_size ))
784 heap_free( bufferW );
785 return FALSE;
788 switch (level)
790 case SERVICE_CONFIG_DESCRIPTION:
791 if (buffer && bufferW) {
792 SERVICE_DESCRIPTIONA *configA = (SERVICE_DESCRIPTIONA *)buffer;
793 SERVICE_DESCRIPTIONW *configW = (SERVICE_DESCRIPTIONW *)bufferW;
794 if (configW->lpDescription && size > sizeof(SERVICE_DESCRIPTIONA))
796 configA->lpDescription = (char *)(configA + 1);
797 WideCharToMultiByte( CP_ACP, 0, configW->lpDescription, -1, configA->lpDescription,
798 size - sizeof(SERVICE_DESCRIPTIONA), NULL, NULL );
800 else configA->lpDescription = NULL;
802 break;
803 case SERVICE_CONFIG_PRESHUTDOWN_INFO:
804 if (buffer && bufferW && *ret_size <= size)
805 memcpy(buffer, bufferW, *ret_size);
806 break;
807 default:
808 FIXME("conversion W->A not implemented for level %ld\n", level);
809 heap_free( bufferW );
810 return FALSE;
813 heap_free( bufferW );
814 return TRUE;
817 /******************************************************************************
818 * QueryServiceConfig2W (sechost.@)
820 BOOL WINAPI DECLSPEC_HOTPATCH QueryServiceConfig2W( SC_HANDLE service, DWORD level, BYTE *buffer,
821 DWORD size, DWORD *ret_size )
823 BYTE *bufptr;
824 DWORD err;
826 TRACE( "%p %lu %p %lu %p\n", service, level, buffer, size, ret_size );
828 if (!buffer && size)
830 SetLastError(ERROR_INVALID_ADDRESS);
831 return FALSE;
834 switch (level)
836 case SERVICE_CONFIG_DESCRIPTION:
837 if (!(bufptr = heap_alloc( size )))
839 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
840 return FALSE;
842 break;
844 case SERVICE_CONFIG_PRESHUTDOWN_INFO:
845 bufptr = buffer;
846 break;
848 default:
849 FIXME("Level %ld not implemented\n", level);
850 SetLastError(ERROR_INVALID_LEVEL);
851 return FALSE;
854 if (!ret_size)
856 if (level == SERVICE_CONFIG_DESCRIPTION) heap_free( bufptr );
857 SetLastError(ERROR_INVALID_ADDRESS);
858 return FALSE;
861 __TRY
863 err = svcctl_QueryServiceConfig2W( service, level, bufptr, size, ret_size );
865 __EXCEPT(rpc_filter)
867 err = map_exception_code( GetExceptionCode() );
869 __ENDTRY
871 switch (level)
873 case SERVICE_CONFIG_DESCRIPTION:
875 SERVICE_DESCRIPTIONW *desc = (SERVICE_DESCRIPTIONW *)buffer;
876 struct service_description *s = (struct service_description *)bufptr;
878 if (err != ERROR_SUCCESS && err != ERROR_INSUFFICIENT_BUFFER)
880 heap_free( bufptr );
881 SetLastError( err );
882 return FALSE;
885 /* adjust for potentially larger SERVICE_DESCRIPTIONW structure */
886 if (*ret_size == sizeof(*s))
887 *ret_size = sizeof(*desc);
888 else
889 *ret_size = *ret_size - FIELD_OFFSET(struct service_description, description) + sizeof(*desc);
891 if (size < *ret_size)
893 heap_free( bufptr );
894 SetLastError( ERROR_INSUFFICIENT_BUFFER );
895 return FALSE;
897 if (desc)
899 if (!s->size) desc->lpDescription = NULL;
900 else
902 desc->lpDescription = (WCHAR *)(desc + 1);
903 memcpy( desc->lpDescription, s->description, s->size );
906 heap_free( bufptr );
907 break;
909 case SERVICE_CONFIG_PRESHUTDOWN_INFO:
910 return set_error( err );
912 default:
913 break;
916 return TRUE;
919 /******************************************************************************
920 * GetServiceDisplayNameW (sechost.@)
922 BOOL WINAPI DECLSPEC_HOTPATCH GetServiceDisplayNameW( SC_HANDLE manager, const WCHAR *service,
923 WCHAR *display_name, DWORD *len )
925 DWORD err;
926 DWORD size;
927 WCHAR buffer[2];
929 TRACE( "%p %s %p %p\n", manager, debugstr_w(service), display_name, len );
931 if (!manager)
933 SetLastError( ERROR_INVALID_HANDLE );
934 return FALSE;
937 /* provide a buffer if the caller didn't */
938 if (!display_name || *len < sizeof(WCHAR))
940 display_name = buffer;
941 /* A size of 1 would be enough, but tests show that Windows returns 2,
942 * probably because of a WCHAR/bytes mismatch in their code. */
943 *len = 2;
946 /* RPC call takes size excluding nul-terminator, whereas *len
947 * includes the nul-terminator on input. */
948 size = *len - 1;
950 __TRY
952 err = svcctl_GetServiceDisplayNameW( manager, service, display_name, &size );
954 __EXCEPT(rpc_filter)
956 err = map_exception_code( GetExceptionCode() );
958 __ENDTRY
960 /* The value of *len excludes nul-terminator on output. */
961 if (err == ERROR_SUCCESS || err == ERROR_INSUFFICIENT_BUFFER)
962 *len = size;
963 return set_error( err );
966 /******************************************************************************
967 * GetServiceKeyNameW (sechost.@)
969 BOOL WINAPI DECLSPEC_HOTPATCH GetServiceKeyNameW( SC_HANDLE manager, const WCHAR *display_name,
970 WCHAR *key_name, DWORD *len )
972 DWORD err;
973 WCHAR buffer[2];
974 DWORD size;
976 TRACE( "%p %s %p %p\n", manager, debugstr_w(display_name), key_name, len );
978 if (!manager)
980 SetLastError( ERROR_INVALID_HANDLE );
981 return FALSE;
984 /* provide a buffer if the caller didn't */
985 if (!key_name || *len < 2)
987 key_name = buffer;
988 /* A size of 1 would be enough, but tests show that Windows returns 2,
989 * probably because of a WCHAR/bytes mismatch in their code.
991 *len = 2;
994 /* RPC call takes size excluding nul-terminator, whereas *len
995 * includes the nul-terminator on input. */
996 size = *len - 1;
998 __TRY
1000 err = svcctl_GetServiceKeyNameW( manager, display_name, key_name, &size );
1002 __EXCEPT(rpc_filter)
1004 err = map_exception_code( GetExceptionCode() );
1006 __ENDTRY
1008 /* The value of *lpcchBuffer excludes nul-terminator on output. */
1009 if (err == ERROR_SUCCESS || err == ERROR_INSUFFICIENT_BUFFER)
1010 *len = size;
1011 return set_error( err );
1014 /******************************************************************************
1015 * StartServiceA (sechost.@)
1017 BOOL WINAPI DECLSPEC_HOTPATCH StartServiceA( SC_HANDLE service, DWORD argc, const char **argv )
1019 WCHAR **argvW = NULL;
1020 DWORD i;
1021 BOOL r;
1023 if (argc)
1024 argvW = heap_alloc( argc * sizeof(*argvW) );
1026 for (i = 0; i < argc; i++)
1027 argvW[i] = heap_strdupAtoW( argv[i] );
1029 r = StartServiceW( service, argc, (const WCHAR **)argvW );
1031 for (i = 0; i < argc; i++)
1032 heap_free( argvW[i] );
1033 heap_free( argvW );
1034 return r;
1038 /******************************************************************************
1039 * StartServiceW (sechost.@)
1041 BOOL WINAPI DECLSPEC_HOTPATCH StartServiceW( SC_HANDLE service, DWORD argc, const WCHAR **argv )
1043 DWORD err;
1045 TRACE( "%p %lu %p\n", service, argc, argv );
1047 __TRY
1049 err = svcctl_StartServiceW( service, argc, argv );
1051 __EXCEPT(rpc_filter)
1053 err = map_exception_code( GetExceptionCode() );
1055 __ENDTRY
1057 return set_error( err );
1060 /******************************************************************************
1061 * ControlService (sechost.@)
1063 BOOL WINAPI DECLSPEC_HOTPATCH ControlService( SC_HANDLE service, DWORD control, SERVICE_STATUS *status )
1065 DWORD err;
1067 TRACE( "%p %ld %p\n", service, control, status );
1069 __TRY
1071 err = svcctl_ControlService( service, control, status );
1073 __EXCEPT(rpc_filter)
1075 err = map_exception_code( GetExceptionCode() );
1077 __ENDTRY
1079 return set_error( err );
1082 /******************************************************************************
1083 * QueryServiceStatus (sechost.@)
1085 BOOL WINAPI DECLSPEC_HOTPATCH QueryServiceStatus( SC_HANDLE service, SERVICE_STATUS *status )
1087 SERVICE_STATUS_PROCESS process_status;
1088 BOOL ret;
1089 DWORD size;
1091 TRACE( "%p %p\n", service, status );
1093 if (!service) return set_error( ERROR_INVALID_HANDLE );
1094 if (!status) return set_error( ERROR_INVALID_ADDRESS );
1096 ret = QueryServiceStatusEx( service, SC_STATUS_PROCESS_INFO, (BYTE *)&process_status,
1097 sizeof(SERVICE_STATUS_PROCESS), &size );
1098 if (ret) memcpy(status, &process_status, sizeof(SERVICE_STATUS) );
1099 return ret;
1102 /******************************************************************************
1103 * QueryServiceStatusEx (sechost.@)
1105 BOOL WINAPI DECLSPEC_HOTPATCH QueryServiceStatusEx( SC_HANDLE service, SC_STATUS_TYPE level,
1106 BYTE *buffer, DWORD size, DWORD *ret_size )
1108 DWORD err;
1110 TRACE( "%p %d %p %ld %p\n", service, level, buffer, size, ret_size );
1112 if (level != SC_STATUS_PROCESS_INFO) return set_error( ERROR_INVALID_LEVEL );
1114 if (size < sizeof(SERVICE_STATUS_PROCESS))
1116 *ret_size = sizeof(SERVICE_STATUS_PROCESS);
1117 return set_error( ERROR_INSUFFICIENT_BUFFER );
1120 __TRY
1122 err = svcctl_QueryServiceStatusEx( service, level, buffer, size, ret_size );
1124 __EXCEPT(rpc_filter)
1126 err = map_exception_code( GetExceptionCode() );
1128 __ENDTRY
1130 return set_error( err );
1133 /******************************************************************************
1134 * EnumServicesStatusExW (sechost.@)
1136 BOOL WINAPI DECLSPEC_HOTPATCH EnumServicesStatusExW( SC_HANDLE manager, SC_ENUM_TYPE level, DWORD type, DWORD state,
1137 BYTE *buffer, DWORD size, DWORD *needed, DWORD *returned,
1138 DWORD *resume_handle, const WCHAR *group )
1140 DWORD err, i, offset, buflen, count, total_size = 0;
1141 ENUM_SERVICE_STATUS_PROCESSW *services = (ENUM_SERVICE_STATUS_PROCESSW *)buffer;
1142 struct enum_service_status_process *entry;
1143 const WCHAR *str;
1144 BYTE *buf;
1146 TRACE( "%p %u 0x%lx 0x%lx %p %lu %p %p %p %s\n", manager, level, type, state, buffer,
1147 size, needed, returned, resume_handle, debugstr_w(group) );
1149 if (level != SC_ENUM_PROCESS_INFO) return set_error( ERROR_INVALID_LEVEL );
1150 if (!manager) return set_error( ERROR_INVALID_HANDLE );
1151 if (!needed || !returned) return set_error( ERROR_INVALID_ADDRESS );
1153 /* make sure we pass a valid pointer */
1154 buflen = max( size, sizeof(*services) );
1155 if (!(buf = heap_alloc( buflen ))) return set_error( ERROR_NOT_ENOUGH_MEMORY );
1157 __TRY
1159 err = svcctl_EnumServicesStatusExW( manager, SC_ENUM_PROCESS_INFO, type, state, buf, buflen, needed,
1160 &count, resume_handle, group );
1162 __EXCEPT(rpc_filter)
1164 err = map_exception_code( GetExceptionCode() );
1166 __ENDTRY
1168 *returned = 0;
1169 if (err != ERROR_SUCCESS)
1171 /* double the needed size to fit the potentially larger ENUM_SERVICE_STATUS_PROCESSW */
1172 if (err == ERROR_MORE_DATA) *needed *= 2;
1173 heap_free( buf );
1174 SetLastError( err );
1175 return FALSE;
1178 entry = (struct enum_service_status_process *)buf;
1179 for (i = 0; i < count; i++)
1181 total_size += sizeof(*services);
1182 if (entry->service_name)
1184 str = (const WCHAR *)(buf + entry->service_name);
1185 total_size += (wcslen( str ) + 1) * sizeof(WCHAR);
1187 if (entry->display_name)
1189 str = (const WCHAR *)(buf + entry->display_name);
1190 total_size += (wcslen( str ) + 1) * sizeof(WCHAR);
1192 entry++;
1195 if (total_size > size)
1197 heap_free( buf );
1198 *needed = total_size;
1199 SetLastError( ERROR_MORE_DATA );
1200 return FALSE;
1203 offset = count * sizeof(*services);
1204 entry = (struct enum_service_status_process *)buf;
1205 for (i = 0; i < count; i++)
1207 DWORD str_size;
1208 str = (const WCHAR *)(buf + entry->service_name);
1209 str_size = (wcslen( str ) + 1) * sizeof(WCHAR);
1210 services[i].lpServiceName = (WCHAR *)((char *)services + offset);
1211 memcpy( services[i].lpServiceName, str, str_size );
1212 offset += str_size;
1214 if (!entry->display_name) services[i].lpDisplayName = NULL;
1215 else
1217 str = (const WCHAR *)(buf + entry->display_name);
1218 str_size = (wcslen( str ) + 1) * sizeof(WCHAR);
1219 services[i].lpDisplayName = (WCHAR *)((char *)services + offset);
1220 memcpy( services[i].lpDisplayName, str, str_size );
1221 offset += str_size;
1223 services[i].ServiceStatusProcess = entry->service_status_process;
1224 entry++;
1227 heap_free( buf );
1228 *needed = 0;
1229 *returned = count;
1230 return TRUE;
1233 /******************************************************************************
1234 * EnumDependentServicesW (sechost.@)
1236 BOOL WINAPI EnumDependentServicesW( SC_HANDLE hService, DWORD dwServiceState,
1237 LPENUM_SERVICE_STATUSW lpServices, DWORD cbBufSize,
1238 LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
1240 FIXME("%p 0x%08lx %p 0x%08lx %p %p - stub\n", hService, dwServiceState,
1241 lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
1243 *lpServicesReturned = 0;
1244 return TRUE;
1247 /******************************************************************************
1248 * QueryServiceObjectSecurity (sechost.@)
1250 BOOL WINAPI DECLSPEC_HOTPATCH QueryServiceObjectSecurity( SC_HANDLE service, SECURITY_INFORMATION type,
1251 PSECURITY_DESCRIPTOR ret_descriptor, DWORD size, DWORD *ret_size )
1253 SECURITY_DESCRIPTOR descriptor;
1254 NTSTATUS status;
1255 ACL acl;
1257 FIXME( "%p %ld %p %lu %p - semi-stub\n", service, type, ret_descriptor, size, ret_size );
1259 if (type != DACL_SECURITY_INFORMATION)
1260 FIXME("information %ld not supported\n", type);
1262 InitializeSecurityDescriptor( &descriptor, SECURITY_DESCRIPTOR_REVISION );
1264 InitializeAcl( &acl, sizeof(ACL), ACL_REVISION );
1265 SetSecurityDescriptorDacl( &descriptor, TRUE, &acl, TRUE );
1267 status = RtlMakeSelfRelativeSD( &descriptor, ret_descriptor, &size );
1268 *ret_size = size;
1270 return set_error( RtlNtStatusToDosError( status ) );
1273 /******************************************************************************
1274 * SetServiceObjectSecurity (sechost.@)
1276 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
1277 SECURITY_INFORMATION dwSecurityInformation,
1278 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
1280 FIXME("%p %ld %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
1281 return TRUE;
1284 static DWORD WINAPI notify_thread(void *user)
1286 DWORD err;
1287 struct notify_data *data = user;
1288 SC_RPC_NOTIFY_PARAMS_LIST *list = NULL;
1289 SERVICE_NOTIFY_STATUS_CHANGE_PARAMS_2 *cparams;
1290 BOOL dummy;
1292 SetThreadDescription(GetCurrentThread(), L"wine_sechost_notify_service_status");
1294 __TRY
1296 /* GetNotifyResults blocks until there is an event */
1297 err = svcctl_GetNotifyResults(data->notify_handle, &list);
1299 __EXCEPT(rpc_filter)
1301 err = map_exception_code(GetExceptionCode());
1303 __ENDTRY
1305 EnterCriticalSection( &service_cs );
1307 list_remove(&data->entry);
1309 LeaveCriticalSection( &service_cs );
1311 if (err == ERROR_SUCCESS && list)
1313 cparams = list->NotifyParamsArray[0].params;
1315 data->notify_buffer->dwNotificationStatus = cparams->dwNotificationStatus;
1316 memcpy(&data->notify_buffer->ServiceStatus, &cparams->ServiceStatus,
1317 sizeof(SERVICE_STATUS_PROCESS));
1318 data->notify_buffer->dwNotificationTriggered = cparams->dwNotificationTriggered;
1319 data->notify_buffer->pszServiceNames = NULL;
1321 QueueUserAPC((PAPCFUNC)data->notify_buffer->pfnNotifyCallback,
1322 data->calling_thread, (ULONG_PTR)data->notify_buffer);
1324 HeapFree(GetProcessHeap(), 0, list);
1326 else
1327 WARN("GetNotifyResults server call failed: %lu\n", err);
1330 __TRY
1332 err = svcctl_CloseNotifyHandle(&data->notify_handle, &dummy);
1334 __EXCEPT(rpc_filter)
1336 err = map_exception_code(GetExceptionCode());
1338 __ENDTRY
1340 if (err != ERROR_SUCCESS)
1341 WARN("CloseNotifyHandle server call failed: %lu\n", err);
1343 CloseHandle(data->calling_thread);
1344 HeapFree(GetProcessHeap(), 0, data);
1346 return 0;
1349 /******************************************************************************
1350 * NotifyServiceStatusChangeW (sechost.@)
1352 DWORD WINAPI DECLSPEC_HOTPATCH NotifyServiceStatusChangeW( SC_HANDLE service, DWORD mask,
1353 SERVICE_NOTIFYW *notify_buffer )
1355 DWORD err;
1356 BOOL b_dummy = FALSE;
1357 GUID g_dummy = {0};
1358 struct notify_data *data;
1360 TRACE( "%p 0x%lx %p\n", service, mask, notify_buffer );
1362 if (!(data = heap_alloc_zero( sizeof(*data) )))
1363 return ERROR_NOT_ENOUGH_MEMORY;
1365 data->service = service;
1366 data->notify_buffer = notify_buffer;
1367 if (!DuplicateHandle( GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(),
1368 &data->calling_thread, 0, FALSE, DUPLICATE_SAME_ACCESS ))
1370 ERR("DuplicateHandle failed: %lu\n", GetLastError());
1371 heap_free( data );
1372 return ERROR_NOT_ENOUGH_MEMORY;
1375 data->params.dwInfoLevel = 2;
1376 data->params.params = &data->cparams;
1378 data->cparams.dwNotifyMask = mask;
1380 EnterCriticalSection( &service_cs );
1382 __TRY
1384 err = svcctl_NotifyServiceStatusChange( service, data->params, &g_dummy,
1385 &g_dummy, &b_dummy, &data->notify_handle );
1387 __EXCEPT(rpc_filter)
1389 err = map_exception_code( GetExceptionCode() );
1391 __ENDTRY
1393 if (err != ERROR_SUCCESS)
1395 WARN("NotifyServiceStatusChange server call failed: %lu\n", err);
1396 LeaveCriticalSection( &service_cs );
1397 CloseHandle( data->calling_thread );
1398 CloseHandle( data->ready_evt );
1399 heap_free( data );
1400 return err;
1403 CloseHandle( CreateThread( NULL, 0, &notify_thread, data, 0, NULL ) );
1405 list_add_tail( &notify_list, &data->entry );
1407 LeaveCriticalSection( &service_cs );
1409 return ERROR_SUCCESS;
1412 /* thunk for calling the RegisterServiceCtrlHandler handler function */
1413 static DWORD WINAPI ctrl_handler_thunk( DWORD control, DWORD type, void *data, void *context )
1415 LPHANDLER_FUNCTION func = context;
1417 func( control );
1418 return ERROR_SUCCESS;
1421 /******************************************************************************
1422 * RegisterServiceCtrlHandlerA (sechost.@)
1424 SERVICE_STATUS_HANDLE WINAPI DECLSPEC_HOTPATCH RegisterServiceCtrlHandlerA(
1425 const char *name, LPHANDLER_FUNCTION handler )
1427 return RegisterServiceCtrlHandlerExA( name, ctrl_handler_thunk, handler );
1430 /******************************************************************************
1431 * RegisterServiceCtrlHandlerW (sechost.@)
1433 SERVICE_STATUS_HANDLE WINAPI DECLSPEC_HOTPATCH RegisterServiceCtrlHandlerW(
1434 const WCHAR *name, LPHANDLER_FUNCTION handler )
1436 return RegisterServiceCtrlHandlerExW( name, ctrl_handler_thunk, handler );
1439 /******************************************************************************
1440 * RegisterServiceCtrlHandlerExA (sechost.@)
1442 SERVICE_STATUS_HANDLE WINAPI DECLSPEC_HOTPATCH RegisterServiceCtrlHandlerExA(
1443 const char *name, LPHANDLER_FUNCTION_EX handler, void *context )
1445 WCHAR *nameW;
1446 SERVICE_STATUS_HANDLE ret;
1448 nameW = heap_strdupAtoW( name );
1449 ret = RegisterServiceCtrlHandlerExW( nameW, handler, context );
1450 heap_free( nameW );
1451 return ret;
1454 static struct service_data *find_service_by_name( const WCHAR *name )
1456 unsigned int i;
1458 if (nb_services == 1) /* only one service (FIXME: should depend on OWN_PROCESS etc.) */
1459 return services[0];
1460 for (i = 0; i < nb_services; i++)
1461 if (!wcsicmp( name, services[i]->name )) return services[i];
1462 return NULL;
1465 /******************************************************************************
1466 * RegisterServiceCtrlHandlerExW (sechost.@)
1468 SERVICE_STATUS_HANDLE WINAPI DECLSPEC_HOTPATCH RegisterServiceCtrlHandlerExW(
1469 const WCHAR *name, LPHANDLER_FUNCTION_EX handler, void *context )
1471 struct service_data *service;
1472 SC_HANDLE handle = 0;
1474 TRACE( "%s %p %p\n", debugstr_w(name), handler, context );
1476 EnterCriticalSection( &service_cs );
1477 if ((service = find_service_by_name( name )))
1479 service->handler = handler;
1480 service->context = context;
1481 handle = service->handle;
1483 LeaveCriticalSection( &service_cs );
1485 if (!handle) SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
1486 return (SERVICE_STATUS_HANDLE)handle;
1489 /******************************************************************************
1490 * SetServiceStatus (sechost.@)
1492 BOOL WINAPI DECLSPEC_HOTPATCH SetServiceStatus( SERVICE_STATUS_HANDLE service, SERVICE_STATUS *status )
1494 DWORD err;
1496 TRACE( "%p %#lx %#lx %#lx %#lx %#lx %#lx %#lx\n", service, status->dwServiceType,
1497 status->dwCurrentState, status->dwControlsAccepted, status->dwWin32ExitCode,
1498 status->dwServiceSpecificExitCode, status->dwCheckPoint, status->dwWaitHint );
1500 __TRY
1502 err = svcctl_SetServiceStatus( service, status );
1504 __EXCEPT(rpc_filter)
1506 err = map_exception_code( GetExceptionCode() );
1508 __ENDTRY
1510 if (!set_error( err ))
1511 return FALSE;
1513 if (status->dwCurrentState == SERVICE_STOPPED)
1515 unsigned int i, count = 0;
1516 EnterCriticalSection( &service_cs );
1517 for (i = 0; i < nb_services; i++)
1519 if (services[i]->handle == (SC_HANDLE)service) continue;
1520 if (services[i]->thread) count++;
1522 if (!count)
1524 stop_service = TRUE;
1525 SetEvent( service_event ); /* notify the main loop */
1527 LeaveCriticalSection( &service_cs );
1530 return TRUE;
1533 static WCHAR *service_get_pipe_name(void)
1535 static const WCHAR format[] = L"\\\\.\\pipe\\net\\NtControlPipe%u";
1536 WCHAR *name;
1537 DWORD len;
1538 HKEY service_current_key;
1539 DWORD service_current;
1540 LONG ret;
1541 DWORD type;
1543 ret = RegOpenKeyExW( HKEY_LOCAL_MACHINE,
1544 L"SYSTEM\\CurrentControlSet\\Control\\ServiceCurrent",
1545 0, KEY_QUERY_VALUE, &service_current_key );
1546 if (ret != ERROR_SUCCESS)
1547 return NULL;
1549 len = sizeof(service_current);
1550 ret = RegQueryValueExW( service_current_key, NULL, NULL, &type,
1551 (BYTE *)&service_current, &len );
1552 RegCloseKey(service_current_key);
1553 if (ret != ERROR_SUCCESS || type != REG_DWORD)
1554 return NULL;
1556 len = ARRAY_SIZE(format) + 10 /* strlenW("4294967295") */;
1557 name = heap_alloc(len * sizeof(WCHAR));
1558 if (!name)
1559 return NULL;
1561 swprintf( name, len, format, service_current );
1562 return name;
1565 static HANDLE service_open_pipe(void)
1567 WCHAR *pipe_name = service_get_pipe_name();
1568 HANDLE handle = INVALID_HANDLE_VALUE;
1572 handle = CreateFileW( pipe_name, GENERIC_READ|GENERIC_WRITE,
1573 0, NULL, OPEN_ALWAYS, 0, NULL );
1574 if (handle != INVALID_HANDLE_VALUE)
1575 break;
1576 if (GetLastError() != ERROR_PIPE_BUSY)
1577 break;
1578 } while (WaitNamedPipeW( pipe_name, NMPWAIT_USE_DEFAULT_WAIT ));
1579 heap_free(pipe_name);
1581 return handle;
1584 static DWORD WINAPI service_thread( void *arg )
1586 struct service_data *info = arg;
1587 WCHAR *str = info->args;
1588 DWORD argc = 0, len = 0;
1590 TRACE("%p\n", arg);
1591 SetThreadDescription(GetCurrentThread(), L"wine_sechost_service");
1593 while (str[len])
1595 len += wcslen( &str[len] ) + 1;
1596 argc++;
1598 len++;
1600 if (info->unicode)
1602 WCHAR **argv, *p;
1604 argv = heap_alloc( (argc+1)*sizeof(*argv) );
1605 for (argc = 0, p = str; *p; p += wcslen( p ) + 1)
1606 argv[argc++] = p;
1607 argv[argc] = NULL;
1609 info->proc.w( argc, argv );
1610 heap_free( argv );
1612 else
1614 char *strA, **argv, *p;
1615 DWORD lenA;
1617 lenA = WideCharToMultiByte( CP_ACP,0, str, len, NULL, 0, NULL, NULL );
1618 strA = heap_alloc(lenA);
1619 WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL);
1621 argv = heap_alloc( (argc+1)*sizeof(*argv) );
1622 for (argc = 0, p = strA; *p; p += strlen( p ) + 1)
1623 argv[argc++] = p;
1624 argv[argc] = NULL;
1626 info->proc.a( argc, argv );
1627 heap_free( argv );
1628 heap_free( strA );
1630 return 0;
1633 static DWORD service_handle_start( struct service_data *service, const void *data, DWORD data_size )
1635 DWORD count = data_size / sizeof(WCHAR);
1637 if (service->thread)
1639 WARN("service is not stopped\n");
1640 return ERROR_SERVICE_ALREADY_RUNNING;
1643 heap_free( service->args );
1644 service->args = heap_alloc( (count + 2) * sizeof(WCHAR) );
1645 if (count) memcpy( service->args, data, count * sizeof(WCHAR) );
1646 service->args[count++] = 0;
1647 service->args[count++] = 0;
1649 service->thread = CreateThread( NULL, 0, service_thread,
1650 service, 0, NULL );
1651 SetEvent( service_event ); /* notify the main loop */
1652 return 0;
1655 static DWORD service_handle_control( struct service_data *service, DWORD control, const void *data, DWORD data_size )
1657 DWORD ret = ERROR_INVALID_SERVICE_CONTROL;
1659 TRACE( "%s control %lu data %p data_size %lu\n", debugstr_w(service->name), control, data, data_size );
1661 if (control == SERVICE_CONTROL_START)
1662 ret = service_handle_start( service, data, data_size );
1663 else if (service->handler)
1664 ret = service->handler( control, 0, (void *)data, service->context );
1665 return ret;
1668 static DWORD WINAPI service_control_dispatcher( void *arg )
1670 struct dispatcher_data *disp = arg;
1672 /* dispatcher loop */
1673 while (1)
1675 struct service_data *service;
1676 service_start_info info;
1677 BYTE *data = NULL;
1678 WCHAR *name;
1679 BOOL r;
1680 DWORD data_size = 0, count, result;
1682 r = ReadFile( disp->pipe, &info, FIELD_OFFSET(service_start_info,data), &count, NULL );
1683 if (!r)
1685 if (GetLastError() != ERROR_BROKEN_PIPE)
1686 ERR( "pipe read failed error %lu\n", GetLastError() );
1687 break;
1689 if (count != FIELD_OFFSET(service_start_info,data))
1691 ERR( "partial pipe read %lu\n", count );
1692 break;
1694 if (count < info.total_size)
1696 data_size = info.total_size - FIELD_OFFSET(service_start_info,data);
1697 data = heap_alloc( data_size );
1698 r = ReadFile( disp->pipe, data, data_size, &count, NULL );
1699 if (!r)
1701 if (GetLastError() != ERROR_BROKEN_PIPE)
1702 ERR( "pipe read failed error %lu\n", GetLastError() );
1703 heap_free( data );
1704 break;
1706 if (count != data_size)
1708 ERR( "partial pipe read %lu/%lu\n", count, data_size );
1709 heap_free( data );
1710 break;
1714 EnterCriticalSection( &service_cs );
1716 /* validate service name */
1717 name = (WCHAR *)data;
1718 if (!info.name_size || data_size < info.name_size * sizeof(WCHAR) || name[info.name_size - 1])
1720 ERR( "got request without valid service name\n" );
1721 result = ERROR_INVALID_PARAMETER;
1722 goto done;
1725 if (info.magic != SERVICE_PROTOCOL_MAGIC)
1727 ERR( "received invalid request for service %s\n", debugstr_w(name) );
1728 result = ERROR_INVALID_PARAMETER;
1729 goto done;
1732 /* find the service */
1733 if (!(service = find_service_by_name( name )))
1735 FIXME( "got request for unknown service %s\n", debugstr_w(name) );
1736 result = ERROR_INVALID_PARAMETER;
1737 goto done;
1740 if (!service->handle)
1742 if (!(service->handle = OpenServiceW( disp->manager, name, SERVICE_SET_STATUS )) ||
1743 !(service->full_access_handle = OpenServiceW( disp->manager, name,
1744 GENERIC_READ|GENERIC_WRITE )))
1745 FIXME( "failed to open service %s\n", debugstr_w(name) );
1748 data_size -= info.name_size * sizeof(WCHAR);
1749 result = service_handle_control(service, info.control, data_size ?
1750 &data[info.name_size * sizeof(WCHAR)] : NULL, data_size);
1752 done:
1753 LeaveCriticalSection( &service_cs );
1754 WriteFile( disp->pipe, &result, sizeof(result), &count, NULL );
1755 heap_free( data );
1758 CloseHandle( disp->pipe );
1759 CloseServiceHandle( disp->manager );
1760 heap_free( disp );
1761 return 1;
1764 /* wait for services which accept this type of message to become STOPPED */
1765 static void handle_shutdown_msg(DWORD msg, DWORD accept)
1767 SERVICE_STATUS st;
1768 SERVICE_PRESHUTDOWN_INFO spi;
1769 DWORD i, n = 0, sz, timeout = 2000;
1770 ULONGLONG stop_time;
1771 BOOL res, done = TRUE;
1772 SC_HANDLE *wait_handles = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SC_HANDLE) * nb_services );
1774 EnterCriticalSection( &service_cs );
1775 for (i = 0; i < nb_services; i++)
1777 res = QueryServiceStatus( services[i]->full_access_handle, &st );
1778 if (!res || st.dwCurrentState == SERVICE_STOPPED || !(st.dwControlsAccepted & accept))
1779 continue;
1781 done = FALSE;
1783 if (accept == SERVICE_ACCEPT_PRESHUTDOWN)
1785 res = QueryServiceConfig2W( services[i]->full_access_handle, SERVICE_CONFIG_PRESHUTDOWN_INFO,
1786 (BYTE *)&spi, sizeof(spi), &sz );
1787 if (res)
1789 FIXME( "service should be able to delay shutdown\n" );
1790 timeout = max( spi.dwPreshutdownTimeout, timeout );
1794 service_handle_control( services[i], msg, NULL, 0 );
1795 wait_handles[n++] = services[i]->full_access_handle;
1797 LeaveCriticalSection( &service_cs );
1799 /* FIXME: these timeouts should be more generous, but we can't currently delay prefix shutdown */
1800 timeout = min( timeout, 3000 );
1801 stop_time = GetTickCount64() + timeout;
1803 while (!done && GetTickCount64() < stop_time)
1805 done = TRUE;
1806 for (i = 0; i < n; i++)
1808 res = QueryServiceStatus( wait_handles[i], &st );
1809 if (!res || st.dwCurrentState == SERVICE_STOPPED)
1810 continue;
1812 done = FALSE;
1813 Sleep( 100 );
1814 break;
1818 HeapFree( GetProcessHeap(), 0, wait_handles );
1821 static BOOL service_run_main_thread(void)
1823 DWORD i, n, ret;
1824 HANDLE wait_handles[MAXIMUM_WAIT_OBJECTS];
1825 UINT wait_services[MAXIMUM_WAIT_OBJECTS];
1826 struct dispatcher_data *disp = heap_alloc( sizeof(*disp) );
1828 disp->manager = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
1829 if (!disp->manager)
1831 ERR("failed to open service manager error %lu\n", GetLastError());
1832 heap_free( disp );
1833 return FALSE;
1836 disp->pipe = service_open_pipe();
1837 if (disp->pipe == INVALID_HANDLE_VALUE)
1839 WARN("failed to create control pipe error %lu\n", GetLastError());
1840 CloseServiceHandle( disp->manager );
1841 heap_free( disp );
1842 SetLastError( ERROR_FAILED_SERVICE_CONTROLLER_CONNECT );
1843 return FALSE;
1846 service_event = CreateEventW( NULL, FALSE, FALSE, NULL );
1847 stop_service = FALSE;
1849 /* FIXME: service_control_dispatcher should be merged into the main thread */
1850 NtSetInformationProcess( GetCurrentProcess(), ProcessWineMakeProcessSystem,
1851 &wait_handles[0], sizeof(HANDLE *) );
1852 wait_handles[1] = CreateThread( NULL, 0, service_control_dispatcher, disp, 0, NULL );
1853 wait_handles[2] = service_event;
1855 TRACE("Starting %d services running as process %ld\n",
1856 nb_services, GetCurrentProcessId());
1858 /* wait for all the threads to pack up and exit */
1859 while (!stop_service)
1861 EnterCriticalSection( &service_cs );
1862 for (i = 0, n = 3; i < nb_services && n < MAXIMUM_WAIT_OBJECTS; i++)
1864 if (!services[i]->thread) continue;
1865 wait_services[n] = i;
1866 wait_handles[n++] = services[i]->thread;
1868 LeaveCriticalSection( &service_cs );
1870 ret = WaitForMultipleObjects( n, wait_handles, FALSE, INFINITE );
1871 if (!ret) /* system process event */
1873 handle_shutdown_msg(SERVICE_CONTROL_PRESHUTDOWN, SERVICE_ACCEPT_PRESHUTDOWN);
1874 handle_shutdown_msg(SERVICE_CONTROL_SHUTDOWN, SERVICE_ACCEPT_SHUTDOWN);
1875 ExitProcess(0);
1877 else if (ret == 1)
1879 TRACE( "control dispatcher exited, shutting down\n" );
1880 /* FIXME: we should maybe send a shutdown control to running services */
1881 ExitProcess(0);
1883 else if (ret == 2)
1885 continue; /* rebuild the list */
1887 else if (ret < n)
1889 i = wait_services[ret];
1890 EnterCriticalSection( &service_cs );
1891 CloseHandle( services[i]->thread );
1892 services[i]->thread = NULL;
1893 LeaveCriticalSection( &service_cs );
1895 else return FALSE;
1898 return TRUE;
1901 /******************************************************************************
1902 * StartServiceCtrlDispatcherA (sechost.@)
1904 BOOL WINAPI DECLSPEC_HOTPATCH StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *servent )
1906 struct service_data *info;
1907 unsigned int i;
1909 TRACE("%p\n", servent);
1911 if (nb_services)
1913 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
1914 return FALSE;
1916 while (servent[nb_services].lpServiceName) nb_services++;
1917 if (!nb_services)
1919 SetLastError( ERROR_INVALID_PARAMETER );
1920 return FALSE;
1923 services = heap_alloc( nb_services * sizeof(*services) );
1925 for (i = 0; i < nb_services; i++)
1927 DWORD len = MultiByteToWideChar( CP_ACP, 0, servent[i].lpServiceName, -1, NULL, 0 );
1928 DWORD sz = FIELD_OFFSET( struct service_data, name[len] );
1929 info = heap_alloc_zero( sz );
1930 MultiByteToWideChar( CP_ACP, 0, servent[i].lpServiceName, -1, info->name, len );
1931 info->proc.a = servent[i].lpServiceProc;
1932 info->unicode = FALSE;
1933 services[i] = info;
1936 return service_run_main_thread();
1939 /******************************************************************************
1940 * StartServiceCtrlDispatcherW (sechost.@)
1942 BOOL WINAPI DECLSPEC_HOTPATCH StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW *servent )
1944 struct service_data *info;
1945 unsigned int i;
1947 TRACE("%p\n", servent);
1949 if (nb_services)
1951 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
1952 return FALSE;
1954 while (servent[nb_services].lpServiceName) nb_services++;
1955 if (!nb_services)
1957 SetLastError( ERROR_INVALID_PARAMETER );
1958 return FALSE;
1961 services = heap_alloc( nb_services * sizeof(*services) );
1963 for (i = 0; i < nb_services; i++)
1965 DWORD len = wcslen( servent[i].lpServiceName ) + 1;
1966 DWORD sz = FIELD_OFFSET( struct service_data, name[len] );
1967 info = heap_alloc_zero( sz );
1968 wcscpy( info->name, servent[i].lpServiceName );
1969 info->proc.w = servent[i].lpServiceProc;
1970 info->unicode = TRUE;
1971 services[i] = info;
1974 return service_run_main_thread();
1977 struct device_notification_details
1979 DWORD (CALLBACK *cb)(HANDLE handle, DWORD flags, DEV_BROADCAST_HDR *header);
1980 HANDLE handle;
1981 union
1983 DEV_BROADCAST_HDR header;
1984 DEV_BROADCAST_DEVICEINTERFACE_W iface;
1985 } filter;
1988 static HANDLE device_notify_thread;
1989 static struct list device_notify_list = LIST_INIT(device_notify_list);
1991 struct device_notify_registration
1993 struct list entry;
1994 struct device_notification_details details;
1997 static BOOL notification_filter_matches( DEV_BROADCAST_HDR *filter, DEV_BROADCAST_HDR *event )
1999 if (!filter->dbch_devicetype) return TRUE;
2000 if (filter->dbch_devicetype != event->dbch_devicetype) return FALSE;
2002 if (filter->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
2004 DEV_BROADCAST_DEVICEINTERFACE_W *filter_iface = (DEV_BROADCAST_DEVICEINTERFACE_W *)filter;
2005 DEV_BROADCAST_DEVICEINTERFACE_W *event_iface = (DEV_BROADCAST_DEVICEINTERFACE_W *)event;
2006 if (filter_iface->dbcc_size == offsetof(DEV_BROADCAST_DEVICEINTERFACE_W, dbcc_classguid)) return TRUE;
2007 return IsEqualGUID( &filter_iface->dbcc_classguid, &event_iface->dbcc_classguid );
2010 FIXME( "Filter dbch_devicetype %lu not implemented\n", filter->dbch_devicetype );
2011 return TRUE;
2014 static DWORD WINAPI device_notify_proc( void *arg )
2016 WCHAR endpoint[] = L"\\pipe\\wine_plugplay";
2017 WCHAR protseq[] = L"ncacn_np";
2018 RPC_WSTR binding_str;
2019 DWORD err = ERROR_SUCCESS;
2020 struct device_notify_registration *registration;
2021 struct device_notification_details *details_copy;
2022 unsigned int details_copy_nelems, details_copy_size;
2023 plugplay_rpc_handle handle = NULL;
2024 DWORD code = 0;
2025 unsigned int i, size;
2026 BYTE *buf;
2028 SetThreadDescription( GetCurrentThread(), L"wine_sechost_device_notify" );
2030 if ((err = RpcStringBindingComposeW( NULL, protseq, NULL, endpoint, NULL, &binding_str )))
2032 ERR("RpcStringBindingCompose() failed, error %#lx\n", err);
2033 return err;
2035 err = RpcBindingFromStringBindingW( binding_str, &plugplay_binding_handle );
2036 RpcStringFreeW( &binding_str );
2037 if (err)
2039 ERR("RpcBindingFromStringBinding() failed, error %#lx\n", err);
2040 return err;
2043 __TRY
2045 handle = plugplay_register_listener();
2047 __EXCEPT(rpc_filter)
2049 err = map_exception_code( GetExceptionCode() );
2051 __ENDTRY
2053 if (!handle)
2055 ERR("failed to open RPC handle, error %lu\n", err);
2056 return 1;
2059 details_copy_size = 8;
2060 details_copy = heap_alloc( details_copy_size * sizeof(*details_copy) );
2062 for (;;)
2064 buf = NULL;
2065 __TRY
2067 code = plugplay_get_event( handle, &buf, &size );
2068 err = ERROR_SUCCESS;
2070 __EXCEPT(rpc_filter)
2072 err = map_exception_code( GetExceptionCode() );
2074 __ENDTRY
2076 if (err)
2078 ERR("failed to get event, error %lu\n", err);
2079 break;
2082 /* Make a copy to avoid a hang if a callback tries to register or unregister for notifications. */
2083 i = 0;
2084 details_copy_nelems = 0;
2085 EnterCriticalSection( &service_cs );
2086 LIST_FOR_EACH_ENTRY(registration, &device_notify_list, struct device_notify_registration, entry)
2088 details_copy[i++] = registration->details;
2089 details_copy_nelems++;
2090 if (i == details_copy_size)
2092 details_copy_size *= 2;
2093 details_copy = heap_realloc( details_copy, details_copy_size * sizeof(*details_copy) );
2096 LeaveCriticalSection(&service_cs);
2098 for (i = 0; i < details_copy_nelems; i++)
2100 if (!notification_filter_matches( &details_copy[i].filter.header, (DEV_BROADCAST_HDR *)buf )) continue;
2101 details_copy[i].cb( details_copy[i].handle, code, (DEV_BROADCAST_HDR *)buf );
2103 MIDL_user_free(buf);
2106 heap_free( details_copy );
2108 __TRY
2110 plugplay_unregister_listener( handle );
2112 __EXCEPT(rpc_filter)
2115 __ENDTRY
2117 RpcBindingFree( &plugplay_binding_handle );
2118 return 0;
2121 /******************************************************************************
2122 * I_ScRegisterDeviceNotification (sechost.@)
2124 HDEVNOTIFY WINAPI I_ScRegisterDeviceNotification( struct device_notification_details *details,
2125 void *filter, DWORD flags )
2127 struct device_notify_registration *registration;
2129 TRACE("callback %p, handle %p, filter %p, flags %#lx\n", details->cb, details->handle, filter, flags);
2131 if (!(registration = heap_alloc(sizeof(struct device_notify_registration))))
2133 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2134 return NULL;
2137 registration->details = *details;
2139 EnterCriticalSection( &service_cs );
2140 list_add_tail( &device_notify_list, &registration->entry );
2142 if (!device_notify_thread)
2143 device_notify_thread = CreateThread( NULL, 0, device_notify_proc, NULL, 0, NULL );
2145 LeaveCriticalSection( &service_cs );
2147 return registration;
2150 /******************************************************************************
2151 * I_ScUnregisterDeviceNotification (sechost.@)
2153 BOOL WINAPI I_ScUnregisterDeviceNotification( HDEVNOTIFY handle )
2155 struct device_notify_registration *registration = handle;
2157 TRACE("%p\n", handle);
2159 if (!handle)
2160 return FALSE;
2162 EnterCriticalSection( &service_cs );
2163 list_remove( &registration->entry );
2164 LeaveCriticalSection(&service_cs);
2165 heap_free( registration );
2166 return TRUE;