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