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
33 #include "wine/debug.h"
34 #include "wine/exception.h"
35 #include "wine/heap.h"
36 #include "wine/list.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(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
;
54 static struct list notify_list
= LIST_INIT(notify_list
);
56 static CRITICAL_SECTION service_cs
;
57 static CRITICAL_SECTION_DEBUG service_cs_debug
=
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 };
68 LPHANDLER_FUNCTION_EX handler
;
72 SC_HANDLE full_access_handle
;
73 unsigned int unicode
: 1;
76 LPSERVICE_MAIN_FUNCTIONA a
;
77 LPSERVICE_MAIN_FUNCTIONW w
;
83 struct dispatcher_data
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
)
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
);
105 static WCHAR
*heap_strdup_multi_AtoW( const char *src
)
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
);
121 static inline DWORD
multisz_size( const WCHAR
*str
)
123 const WCHAR
*p
= str
;
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
)
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
;
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
;
171 status
= RpcStringBindingComposeW( NULL
, transport
, str
, endpoint
, NULL
, &binding_str
);
172 if (status
!= RPC_S_OK
)
174 ERR("RpcStringBindingComposeW failed, error %ld\n", status
);
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
);
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
;
198 status
= RpcStringBindingComposeA( NULL
, transport
, str
, endpoint
, NULL
, &binding_str
);
199 if (status
!= RPC_S_OK
)
201 ERR("RpcStringBindingComposeA failed, error %ld\n", status
);
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
);
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
);
253 /******************************************************************************
254 * OpenSCManagerA (sechost.@)
256 SC_HANDLE WINAPI DECLSPEC_HOTPATCH
OpenSCManagerA( const char *machine
, const char *database
, DWORD access
)
258 WCHAR
*machineW
, *databaseW
;
261 machineW
= heap_strdupAtoW( machine
);
262 databaseW
= heap_strdupAtoW( database
);
263 ret
= OpenSCManagerW( machineW
, databaseW
, access
);
264 heap_free( databaseW
);
265 heap_free( machineW
);
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
;
277 TRACE( "%s %s %#lx\n", debugstr_w(machine
), debugstr_w(database
), access
);
281 err
= svcctl_OpenSCManagerW( machine
, database
, access
, &handle
);
285 err
= map_exception_code( GetExceptionCode() );
289 if (!err
) return handle
;
294 /******************************************************************************
295 * OpenServiceA (sechost.@)
297 SC_HANDLE WINAPI DECLSPEC_HOTPATCH
OpenServiceA( SC_HANDLE manager
, const char *name
, DWORD access
)
302 TRACE( "%p %s %#lx\n", manager
, debugstr_a(name
), access
);
304 nameW
= heap_strdupAtoW( name
);
305 ret
= OpenServiceW( manager
, nameW
, access
);
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
;
318 TRACE( "%p %s %#lx\n", manager
, debugstr_w(name
), access
);
322 SetLastError( ERROR_INVALID_HANDLE
);
328 err
= svcctl_OpenServiceW( manager
, name
, access
, &handle
);
332 err
= map_exception_code( GetExceptionCode() );
336 if (!err
) return handle
;
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
;
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
);
367 heap_free( display_nameW
);
370 heap_free( dependenciesW
);
371 heap_free( usernameW
);
372 heap_free( passwordW
);
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
;
388 SIZE_T password_size
= 0;
390 TRACE( "%p %s %s\n", manager
, debugstr_w(name
), debugstr_w(display_name
) );
394 SetLastError( ERROR_INVALID_HANDLE
);
398 if (password
) password_size
= (wcslen(password
) + 1) * sizeof(WCHAR
);
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
);
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
);
417 err
= map_exception_code( GetExceptionCode() );
421 if (!err
) return handle
;
426 /******************************************************************************
427 * DeleteService (sechost.@)
429 BOOL WINAPI DECLSPEC_HOTPATCH
DeleteService( SC_HANDLE service
)
433 TRACE( "%p\n", service
);
437 err
= svcctl_DeleteService( service
);
441 err
= map_exception_code( GetExceptionCode() );
445 return set_error( err
);
448 /******************************************************************************
449 * CloseServiceHandle (sechost.@)
451 BOOL WINAPI DECLSPEC_HOTPATCH
CloseServiceHandle( SC_HANDLE handle
)
455 TRACE( "%p\n", handle
);
459 err
= svcctl_CloseServiceHandle( (SC_RPC_HANDLE
*)&handle
);
463 err
= map_exception_code( GetExceptionCode() );
467 return set_error( err
);
470 /******************************************************************************
471 * ChangeServiceConfig2A (sechost.@)
473 BOOL WINAPI DECLSPEC_HOTPATCH
ChangeServiceConfig2A( SC_HANDLE service
, DWORD level
, void *info
)
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
);
511 SetLastError( ERROR_INVALID_PARAMETER
);
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
;
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
;
538 rpc_info
.descr
= info
;
539 err
= svcctl_ChangeServiceConfig2W( service
, rpc_info
);
543 err
= map_exception_code( GetExceptionCode() );
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
;
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
);
577 heap_free( dependenciesW
);
578 heap_free( usernameW
);
579 heap_free( passwordW
);
580 heap_free( display_nameW
);
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
)
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;
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
);
610 err
= map_exception_code( GetExceptionCode() );
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
)
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
);
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
);
649 #define MAP_STR(str) \
653 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
654 if (!sz) goto done; \
661 MAP_STR( lpBinaryPathName
);
662 MAP_STR( lpLoadOrderGroup
);
663 MAP_STR( lpDependencies
);
664 MAP_STR( lpServiceStartName
);
665 MAP_STR( lpDisplayName
);
668 *ret_size
= p
- (char *)config
;
676 static DWORD
move_string_to_buffer(BYTE
**buf
, WCHAR
**string_ptr
)
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
;
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
;
714 TRACE( "%p %p %ld %p\n", service
, ret_config
, size
, ret_size
);
716 memset(&config
, 0, sizeof(config
));
720 err
= svcctl_QueryServiceConfigW( service
, &config
, size
, ret_size
);
724 err
= map_exception_code( GetExceptionCode() );
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
);
740 /* if there's not enough memory, return an error */
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
);
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
) );
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
);
780 bufferW
= heap_alloc( size
);
782 if (!QueryServiceConfig2W( service
, level
, bufferW
, size
, ret_size
))
784 heap_free( bufferW
);
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
;
803 case SERVICE_CONFIG_PRESHUTDOWN_INFO
:
804 if (buffer
&& bufferW
&& *ret_size
<= size
)
805 memcpy(buffer
, bufferW
, *ret_size
);
808 FIXME("conversion W->A not implemented for level %ld\n", level
);
809 heap_free( bufferW
);
813 heap_free( bufferW
);
817 /******************************************************************************
818 * QueryServiceConfig2W (sechost.@)
820 BOOL WINAPI DECLSPEC_HOTPATCH
QueryServiceConfig2W( SC_HANDLE service
, DWORD level
, BYTE
*buffer
,
821 DWORD size
, DWORD
*ret_size
)
826 TRACE( "%p %lu %p %lu %p\n", service
, level
, buffer
, size
, ret_size
);
830 SetLastError(ERROR_INVALID_ADDRESS
);
836 case SERVICE_CONFIG_DESCRIPTION
:
837 if (!(bufptr
= heap_alloc( size
)))
839 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
844 case SERVICE_CONFIG_PRESHUTDOWN_INFO
:
849 FIXME("Level %ld not implemented\n", level
);
850 SetLastError(ERROR_INVALID_LEVEL
);
856 if (level
== SERVICE_CONFIG_DESCRIPTION
) heap_free( bufptr
);
857 SetLastError(ERROR_INVALID_ADDRESS
);
863 err
= svcctl_QueryServiceConfig2W( service
, level
, bufptr
, size
, ret_size
);
867 err
= map_exception_code( GetExceptionCode() );
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
)
885 /* adjust for potentially larger SERVICE_DESCRIPTIONW structure */
886 if (*ret_size
== sizeof(*s
))
887 *ret_size
= sizeof(*desc
);
889 *ret_size
= *ret_size
- FIELD_OFFSET(struct service_description
, description
) + sizeof(*desc
);
891 if (size
< *ret_size
)
894 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
899 if (!s
->size
) desc
->lpDescription
= NULL
;
902 desc
->lpDescription
= (WCHAR
*)(desc
+ 1);
903 memcpy( desc
->lpDescription
, s
->description
, s
->size
);
909 case SERVICE_CONFIG_PRESHUTDOWN_INFO
:
910 return set_error( err
);
919 /******************************************************************************
920 * GetServiceDisplayNameW (sechost.@)
922 BOOL WINAPI DECLSPEC_HOTPATCH
GetServiceDisplayNameW( SC_HANDLE manager
, const WCHAR
*service
,
923 WCHAR
*display_name
, DWORD
*len
)
929 TRACE( "%p %s %p %p\n", manager
, debugstr_w(service
), display_name
, len
);
933 SetLastError( ERROR_INVALID_HANDLE
);
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. */
946 /* RPC call takes size excluding nul-terminator, whereas *len
947 * includes the nul-terminator on input. */
952 err
= svcctl_GetServiceDisplayNameW( manager
, service
, display_name
, &size
);
956 err
= map_exception_code( GetExceptionCode() );
960 /* The value of *len excludes nul-terminator on output. */
961 if (err
== ERROR_SUCCESS
|| err
== ERROR_INSUFFICIENT_BUFFER
)
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
)
976 TRACE( "%p %s %p %p\n", manager
, debugstr_w(display_name
), key_name
, len
);
980 SetLastError( ERROR_INVALID_HANDLE
);
984 /* provide a buffer if the caller didn't */
985 if (!key_name
|| *len
< 2)
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.
994 /* RPC call takes size excluding nul-terminator, whereas *len
995 * includes the nul-terminator on input. */
1000 err
= svcctl_GetServiceKeyNameW( manager
, display_name
, key_name
, &size
);
1002 __EXCEPT(rpc_filter
)
1004 err
= map_exception_code( GetExceptionCode() );
1008 /* The value of *lpcchBuffer excludes nul-terminator on output. */
1009 if (err
== ERROR_SUCCESS
|| err
== ERROR_INSUFFICIENT_BUFFER
)
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
;
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
] );
1038 /******************************************************************************
1039 * StartServiceW (sechost.@)
1041 BOOL WINAPI DECLSPEC_HOTPATCH
StartServiceW( SC_HANDLE service
, DWORD argc
, const WCHAR
**argv
)
1045 TRACE( "%p %lu %p\n", service
, argc
, argv
);
1049 err
= svcctl_StartServiceW( service
, argc
, argv
);
1051 __EXCEPT(rpc_filter
)
1053 err
= map_exception_code( GetExceptionCode() );
1057 return set_error( err
);
1060 /******************************************************************************
1061 * ControlService (sechost.@)
1063 BOOL WINAPI DECLSPEC_HOTPATCH
ControlService( SC_HANDLE service
, DWORD control
, SERVICE_STATUS
*status
)
1067 TRACE( "%p %ld %p\n", service
, control
, status
);
1071 err
= svcctl_ControlService( service
, control
, status
);
1073 __EXCEPT(rpc_filter
)
1075 err
= map_exception_code( GetExceptionCode() );
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
;
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
) );
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
)
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
);
1122 err
= svcctl_QueryServiceStatusEx( service
, level
, buffer
, size
, ret_size
);
1124 __EXCEPT(rpc_filter
)
1126 err
= map_exception_code( GetExceptionCode() );
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
;
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
);
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() );
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;
1174 SetLastError( err
);
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
);
1195 if (total_size
> size
)
1198 *needed
= total_size
;
1199 SetLastError( ERROR_MORE_DATA
);
1203 offset
= count
* sizeof(*services
);
1204 entry
= (struct enum_service_status_process
*)buf
;
1205 for (i
= 0; i
< count
; i
++)
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
);
1214 if (!entry
->display_name
) services
[i
].lpDisplayName
= NULL
;
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
);
1223 services
[i
].ServiceStatusProcess
= entry
->service_status_process
;
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;
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
;
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
);
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
);
1284 static DWORD WINAPI
notify_thread(void *user
)
1287 struct notify_data
*data
= user
;
1288 SC_RPC_NOTIFY_PARAMS_LIST
*list
= NULL
;
1289 SERVICE_NOTIFY_STATUS_CHANGE_PARAMS_2
*cparams
;
1292 SetThreadDescription(GetCurrentThread(), L
"wine_sechost_notify_service_status");
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());
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
);
1327 WARN("GetNotifyResults server call failed: %lu\n", err
);
1332 err
= svcctl_CloseNotifyHandle(&data
->notify_handle
, &dummy
);
1334 __EXCEPT(rpc_filter
)
1336 err
= map_exception_code(GetExceptionCode());
1340 if (err
!= ERROR_SUCCESS
)
1341 WARN("CloseNotifyHandle server call failed: %lu\n", err
);
1343 CloseHandle(data
->calling_thread
);
1344 HeapFree(GetProcessHeap(), 0, data
);
1349 /******************************************************************************
1350 * NotifyServiceStatusChangeW (sechost.@)
1352 DWORD WINAPI DECLSPEC_HOTPATCH
NotifyServiceStatusChangeW( SC_HANDLE service
, DWORD mask
,
1353 SERVICE_NOTIFYW
*notify_buffer
)
1356 BOOL b_dummy
= FALSE
;
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());
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
);
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() );
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
);
1403 CloseHandle( CreateThread( NULL
, 0, ¬ify_thread
, data
, 0, NULL
) );
1405 list_add_tail( ¬ify_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
;
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
)
1446 SERVICE_STATUS_HANDLE ret
;
1448 nameW
= heap_strdupAtoW( name
);
1449 ret
= RegisterServiceCtrlHandlerExW( nameW
, handler
, context
);
1454 static struct service_data
*find_service_by_name( const WCHAR
*name
)
1458 if (nb_services
== 1) /* only one service (FIXME: should depend on OWN_PROCESS etc.) */
1460 for (i
= 0; i
< nb_services
; i
++)
1461 if (!wcsicmp( name
, services
[i
]->name
)) return services
[i
];
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
)
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
);
1502 err
= svcctl_SetServiceStatus( service
, status
);
1504 __EXCEPT(rpc_filter
)
1506 err
= map_exception_code( GetExceptionCode() );
1510 if (!set_error( err
))
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
++;
1524 stop_service
= TRUE
;
1525 SetEvent( service_event
); /* notify the main loop */
1527 LeaveCriticalSection( &service_cs
);
1533 static WCHAR
*service_get_pipe_name(void)
1535 static const WCHAR format
[] = L
"\\\\.\\pipe\\net\\NtControlPipe%u";
1538 HKEY service_current_key
;
1539 DWORD service_current
;
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
)
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
)
1556 len
= ARRAY_SIZE(format
) + 10 /* strlenW("4294967295") */;
1557 name
= heap_alloc(len
* sizeof(WCHAR
));
1561 swprintf( name
, len
, format
, service_current
);
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
)
1576 if (GetLastError() != ERROR_PIPE_BUSY
)
1578 } while (WaitNamedPipeW( pipe_name
, NMPWAIT_USE_DEFAULT_WAIT
));
1579 heap_free(pipe_name
);
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;
1591 SetThreadDescription(GetCurrentThread(), L
"wine_sechost_service");
1595 len
+= wcslen( &str
[len
] ) + 1;
1604 argv
= heap_alloc( (argc
+1)*sizeof(*argv
) );
1605 for (argc
= 0, p
= str
; *p
; p
+= wcslen( p
) + 1)
1609 info
->proc
.w( argc
, argv
);
1614 char *strA
, **argv
, *p
;
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)
1626 info
->proc
.a( argc
, argv
);
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
,
1651 SetEvent( service_event
); /* notify the main loop */
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
);
1668 static DWORD WINAPI
service_control_dispatcher( void *arg
)
1670 struct dispatcher_data
*disp
= arg
;
1672 /* dispatcher loop */
1675 struct service_data
*service
;
1676 service_start_info info
;
1680 DWORD data_size
= 0, count
, result
;
1682 r
= ReadFile( disp
->pipe
, &info
, FIELD_OFFSET(service_start_info
,data
), &count
, NULL
);
1685 if (GetLastError() != ERROR_BROKEN_PIPE
)
1686 ERR( "pipe read failed error %lu\n", GetLastError() );
1689 if (count
!= FIELD_OFFSET(service_start_info
,data
))
1691 ERR( "partial pipe read %lu\n", count
);
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
);
1701 if (GetLastError() != ERROR_BROKEN_PIPE
)
1702 ERR( "pipe read failed error %lu\n", GetLastError() );
1706 if (count
!= data_size
)
1708 ERR( "partial pipe read %lu/%lu\n", count
, data_size
);
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
;
1725 if (info
.magic
!= SERVICE_PROTOCOL_MAGIC
)
1727 ERR( "received invalid request for service %s\n", debugstr_w(name
) );
1728 result
= ERROR_INVALID_PARAMETER
;
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
;
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
);
1753 LeaveCriticalSection( &service_cs
);
1754 WriteFile( disp
->pipe
, &result
, sizeof(result
), &count
, NULL
);
1758 CloseHandle( disp
->pipe
);
1759 CloseServiceHandle( disp
->manager
);
1764 /* wait for services which accept this type of message to become STOPPED */
1765 static void handle_shutdown_msg(DWORD msg
, DWORD accept
)
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
))
1783 if (accept
== SERVICE_ACCEPT_PRESHUTDOWN
)
1785 res
= QueryServiceConfig2W( services
[i
]->full_access_handle
, SERVICE_CONFIG_PRESHUTDOWN_INFO
,
1786 (BYTE
*)&spi
, sizeof(spi
), &sz
);
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
)
1806 for (i
= 0; i
< n
; i
++)
1808 res
= QueryServiceStatus( wait_handles
[i
], &st
);
1809 if (!res
|| st
.dwCurrentState
== SERVICE_STOPPED
)
1818 HeapFree( GetProcessHeap(), 0, wait_handles
);
1821 static BOOL
service_run_main_thread(void)
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
);
1831 ERR("failed to open service manager error %lu\n", GetLastError());
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
);
1842 SetLastError( ERROR_FAILED_SERVICE_CONTROLLER_CONNECT
);
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
);
1879 TRACE( "control dispatcher exited, shutting down\n" );
1880 /* FIXME: we should maybe send a shutdown control to running services */
1885 continue; /* rebuild the list */
1889 i
= wait_services
[ret
];
1890 EnterCriticalSection( &service_cs
);
1891 CloseHandle( services
[i
]->thread
);
1892 services
[i
]->thread
= NULL
;
1893 LeaveCriticalSection( &service_cs
);
1901 /******************************************************************************
1902 * StartServiceCtrlDispatcherA (sechost.@)
1904 BOOL WINAPI DECLSPEC_HOTPATCH
StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA
*servent
)
1906 struct service_data
*info
;
1909 TRACE("%p\n", servent
);
1913 SetLastError( ERROR_SERVICE_ALREADY_RUNNING
);
1916 while (servent
[nb_services
].lpServiceName
) nb_services
++;
1919 SetLastError( ERROR_INVALID_PARAMETER
);
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
;
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
;
1947 TRACE("%p\n", servent
);
1951 SetLastError( ERROR_SERVICE_ALREADY_RUNNING
);
1954 while (servent
[nb_services
].lpServiceName
) nb_services
++;
1957 SetLastError( ERROR_INVALID_PARAMETER
);
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
;
1974 return service_run_main_thread();
1977 struct device_notification_details
1979 DWORD (CALLBACK
*cb
)(HANDLE handle
, DWORD flags
, DEV_BROADCAST_HDR
*header
);
1983 DEV_BROADCAST_HDR header
;
1984 DEV_BROADCAST_DEVICEINTERFACE_W iface
;
1988 static HANDLE device_notify_thread
;
1989 static struct list device_notify_list
= LIST_INIT(device_notify_list
);
1991 struct device_notify_registration
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
);
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
;
2025 unsigned int i
, size
;
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
);
2035 err
= RpcBindingFromStringBindingW( binding_str
, &plugplay_binding_handle
);
2036 RpcStringFreeW( &binding_str
);
2039 ERR("RpcBindingFromStringBinding() failed, error %#lx\n", err
);
2045 handle
= plugplay_register_listener();
2047 __EXCEPT(rpc_filter
)
2049 err
= map_exception_code( GetExceptionCode() );
2055 ERR("failed to open RPC handle, error %lu\n", err
);
2059 details_copy_size
= 8;
2060 details_copy
= heap_alloc( details_copy_size
* sizeof(*details_copy
) );
2067 code
= plugplay_get_event( handle
, &buf
, &size
);
2068 err
= ERROR_SUCCESS
;
2070 __EXCEPT(rpc_filter
)
2072 err
= map_exception_code( GetExceptionCode() );
2078 ERR("failed to get event, error %lu\n", err
);
2082 /* Make a copy to avoid a hang if a callback tries to register or unregister for notifications. */
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
);
2110 plugplay_unregister_listener( handle
);
2112 __EXCEPT(rpc_filter
)
2117 RpcBindingFree( &plugplay_binding_handle
);
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
);
2137 registration
->details
= *details
;
2139 EnterCriticalSection( &service_cs
);
2140 list_add_tail( &device_notify_list
, ®istration
->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
);
2162 EnterCriticalSection( &service_cs
);
2163 list_remove( ®istration
->entry
);
2164 LeaveCriticalSection(&service_cs
);
2165 heap_free( registration
);