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 static WCHAR
*heap_strdupAtoW( const char *src
)
98 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, src
, -1, NULL
, 0 );
99 if ((dst
= heap_alloc( len
* sizeof(WCHAR
) ))) MultiByteToWideChar( CP_ACP
, 0, src
, -1, dst
, len
);
104 static WCHAR
*heap_strdup_multi_AtoW( const char *src
)
110 if (!src
) return NULL
;
112 while (*p
) p
+= strlen(p
) + 1;
113 for (p
= src
; *p
; p
+= strlen(p
) + 1);
114 p
++; /* final null */
115 len
= MultiByteToWideChar( CP_ACP
, 0, src
, p
- src
, NULL
, 0 );
116 if ((dst
= heap_alloc( len
* sizeof(WCHAR
) ))) MultiByteToWideChar( CP_ACP
, 0, src
, p
- src
, dst
, len
);
120 static inline DWORD
multisz_size( const WCHAR
*str
)
122 const WCHAR
*p
= str
;
126 while (*p
) p
+= wcslen(p
) + 1;
127 return (p
- str
+ 1) * sizeof(WCHAR
);
130 void __RPC_FAR
* __RPC_USER
MIDL_user_allocate( SIZE_T len
)
132 return heap_alloc(len
);
135 void __RPC_USER
MIDL_user_free( void __RPC_FAR
*ptr
)
140 static LONG WINAPI
rpc_filter( EXCEPTION_POINTERS
*eptr
)
142 return I_RpcExceptionFilter( eptr
->ExceptionRecord
->ExceptionCode
);
145 static DWORD
map_exception_code( DWORD exception_code
)
147 switch (exception_code
)
149 case RPC_X_NULL_REF_POINTER
:
150 return ERROR_INVALID_ADDRESS
;
151 case RPC_X_ENUM_VALUE_OUT_OF_RANGE
:
152 case RPC_X_BYTE_COUNT_TOO_SMALL
:
153 return ERROR_INVALID_PARAMETER
;
154 case RPC_S_INVALID_BINDING
:
155 case RPC_X_SS_IN_NULL_CONTEXT
:
156 return ERROR_INVALID_HANDLE
;
158 return exception_code
;
162 static handle_t
rpc_wstr_bind( RPC_WSTR str
)
164 WCHAR transport
[] = SVCCTL_TRANSPORT
;
165 WCHAR endpoint
[] = SVCCTL_ENDPOINT
;
166 RPC_WSTR binding_str
;
170 status
= RpcStringBindingComposeW( NULL
, transport
, str
, endpoint
, NULL
, &binding_str
);
171 if (status
!= RPC_S_OK
)
173 ERR("RpcStringBindingComposeW failed, error %d\n", status
);
177 status
= RpcBindingFromStringBindingW( binding_str
, &rpc_handle
);
178 RpcStringFreeW( &binding_str
);
180 if (status
!= RPC_S_OK
)
182 ERR("Couldn't connect to services.exe, error %d\n", status
);
189 static handle_t
rpc_cstr_bind(RPC_CSTR str
)
191 RPC_CSTR transport
= (RPC_CSTR
)SVCCTL_TRANSPORTA
;
192 RPC_CSTR endpoint
= (RPC_CSTR
)SVCCTL_ENDPOINTA
;
193 RPC_CSTR binding_str
;
197 status
= RpcStringBindingComposeA( NULL
, transport
, str
, endpoint
, NULL
, &binding_str
);
198 if (status
!= RPC_S_OK
)
200 ERR("RpcStringBindingComposeA failed, error %d\n", status
);
204 status
= RpcBindingFromStringBindingA( binding_str
, &rpc_handle
);
205 RpcStringFreeA( &binding_str
);
207 if (status
!= RPC_S_OK
)
209 ERR("Couldn't connect to services.exe, error %d\n", status
);
216 DECLSPEC_HIDDEN handle_t __RPC_USER
MACHINE_HANDLEA_bind( MACHINE_HANDLEA name
)
218 return rpc_cstr_bind( (RPC_CSTR
)name
);
221 DECLSPEC_HIDDEN
void __RPC_USER
MACHINE_HANDLEA_unbind( MACHINE_HANDLEA name
, handle_t h
)
223 RpcBindingFree( &h
);
226 DECLSPEC_HIDDEN handle_t __RPC_USER
MACHINE_HANDLEW_bind( MACHINE_HANDLEW name
)
228 return rpc_wstr_bind( (RPC_WSTR
)name
);
231 DECLSPEC_HIDDEN
void __RPC_USER
MACHINE_HANDLEW_unbind( MACHINE_HANDLEW name
, handle_t h
)
233 RpcBindingFree( &h
);
236 DECLSPEC_HIDDEN handle_t __RPC_USER
SVCCTL_HANDLEW_bind( SVCCTL_HANDLEW name
)
238 return rpc_wstr_bind( (RPC_WSTR
)name
);
241 DECLSPEC_HIDDEN
void __RPC_USER
SVCCTL_HANDLEW_unbind( SVCCTL_HANDLEW name
, handle_t h
)
243 RpcBindingFree( &h
);
246 static BOOL
set_error( DWORD err
)
248 if (err
) SetLastError( err
);
252 /******************************************************************************
253 * OpenSCManagerA (sechost.@)
255 SC_HANDLE WINAPI DECLSPEC_HOTPATCH
OpenSCManagerA( const char *machine
, const char *database
, DWORD access
)
257 WCHAR
*machineW
, *databaseW
;
260 machineW
= heap_strdupAtoW( machine
);
261 databaseW
= heap_strdupAtoW( database
);
262 ret
= OpenSCManagerW( machineW
, databaseW
, access
);
263 heap_free( databaseW
);
264 heap_free( machineW
);
268 /******************************************************************************
269 * OpenSCManagerW (sechost.@)
271 SC_HANDLE WINAPI DECLSPEC_HOTPATCH
OpenSCManagerW( const WCHAR
*machine
, const WCHAR
*database
, DWORD access
)
273 SC_RPC_HANDLE handle
= NULL
;
276 TRACE( "%s %s %#x\n", debugstr_w(machine
), debugstr_w(database
), access
);
280 err
= svcctl_OpenSCManagerW( machine
, database
, access
, &handle
);
284 err
= map_exception_code( GetExceptionCode() );
288 if (!err
) return handle
;
293 /******************************************************************************
294 * OpenServiceA (sechost.@)
296 SC_HANDLE WINAPI DECLSPEC_HOTPATCH
OpenServiceA( SC_HANDLE manager
, const char *name
, DWORD access
)
301 TRACE( "%p %s %#x\n", manager
, debugstr_a(name
), access
);
303 nameW
= heap_strdupAtoW( name
);
304 ret
= OpenServiceW( manager
, nameW
, access
);
309 /******************************************************************************
310 * OpenServiceW (sechost.@)
312 SC_HANDLE WINAPI DECLSPEC_HOTPATCH
OpenServiceW( SC_HANDLE manager
, const WCHAR
*name
, DWORD access
)
314 SC_RPC_HANDLE handle
= NULL
;
317 TRACE( "%p %s %#x\n", manager
, debugstr_w(name
), access
);
321 SetLastError( ERROR_INVALID_HANDLE
);
327 err
= svcctl_OpenServiceW( manager
, name
, access
, &handle
);
331 err
= map_exception_code( GetExceptionCode() );
335 if (!err
) return handle
;
340 /******************************************************************************
341 * CreateServiceA (sechost.@)
343 SC_HANDLE WINAPI DECLSPEC_HOTPATCH
CreateServiceA( SC_HANDLE manager
, const char *name
, const char *display_name
,
344 DWORD access
, DWORD service_type
, DWORD start_type
,
345 DWORD error_control
, const char *path
, const char *group
,
346 DWORD
*tag
, const char *dependencies
, const char *username
,
347 const char *password
)
349 WCHAR
*nameW
, *display_nameW
, *pathW
, *groupW
, *dependenciesW
, *usernameW
, *passwordW
;
352 TRACE( "%p %s %s\n", manager
, debugstr_a(name
), debugstr_a(display_name
) );
354 nameW
= heap_strdupAtoW( name
);
355 display_nameW
= heap_strdupAtoW( display_name
);
356 pathW
= heap_strdupAtoW( path
);
357 groupW
= heap_strdupAtoW( group
);
358 dependenciesW
= heap_strdupAtoW( dependencies
);
359 usernameW
= heap_strdupAtoW( username
);
360 passwordW
= heap_strdupAtoW( password
);
362 handle
= CreateServiceW( manager
, nameW
, display_nameW
, access
, service_type
, start_type
, error_control
,
363 pathW
, groupW
, tag
, dependenciesW
, usernameW
, passwordW
);
366 heap_free( display_nameW
);
369 heap_free( dependenciesW
);
370 heap_free( usernameW
);
371 heap_free( passwordW
);
376 /******************************************************************************
377 * CreateServiceW (sechost.@)
379 SC_HANDLE WINAPI DECLSPEC_HOTPATCH
CreateServiceW( SC_HANDLE manager
, const WCHAR
*name
, const WCHAR
*display_name
,
380 DWORD access
, DWORD service_type
, DWORD start_type
,
381 DWORD error_control
, const WCHAR
*path
, const WCHAR
*group
,
382 DWORD
*tag
, const WCHAR
*dependencies
, const WCHAR
*username
,
383 const WCHAR
*password
)
385 SC_RPC_HANDLE handle
= NULL
;
387 SIZE_T password_size
= 0;
389 TRACE( "%p %s %s\n", manager
, debugstr_w(name
), debugstr_w(display_name
) );
393 SetLastError( ERROR_INVALID_HANDLE
);
397 if (password
) password_size
= (wcslen(password
) + 1) * sizeof(WCHAR
);
403 if (IsWow64Process(GetCurrentProcess(), &is_wow64
) && is_wow64
)
404 err
= svcctl_CreateServiceWOW64W( manager
, name
, display_name
, access
, service_type
, start_type
,
405 error_control
, path
, group
, tag
, (const BYTE
*)dependencies
,
406 multisz_size( dependencies
), username
, (const BYTE
*)password
,
407 password_size
, &handle
);
409 err
= svcctl_CreateServiceW( manager
, name
, display_name
, access
, service_type
, start_type
,
410 error_control
, path
, group
, tag
, (const BYTE
*)dependencies
,
411 multisz_size( dependencies
), username
, (const BYTE
*)password
,
412 password_size
, &handle
);
416 err
= map_exception_code( GetExceptionCode() );
420 if (!err
) return handle
;
425 /******************************************************************************
426 * DeleteService (sechost.@)
428 BOOL WINAPI DECLSPEC_HOTPATCH
DeleteService( SC_HANDLE service
)
432 TRACE( "%p\n", service
);
436 err
= svcctl_DeleteService( service
);
440 err
= map_exception_code( GetExceptionCode() );
444 return set_error( err
);
447 /******************************************************************************
448 * CloseServiceHandle (sechost.@)
450 BOOL WINAPI DECLSPEC_HOTPATCH
CloseServiceHandle( SC_HANDLE handle
)
454 TRACE( "%p\n", handle
);
458 err
= svcctl_CloseServiceHandle( (SC_RPC_HANDLE
*)&handle
);
462 err
= map_exception_code( GetExceptionCode() );
466 return set_error( err
);
469 /******************************************************************************
470 * ChangeServiceConfig2A (sechost.@)
472 BOOL WINAPI DECLSPEC_HOTPATCH
ChangeServiceConfig2A( SC_HANDLE service
, DWORD level
, void *info
)
476 TRACE( "%p %d %p\n", service
, level
, info
);
478 if (level
== SERVICE_CONFIG_DESCRIPTION
)
480 SERVICE_DESCRIPTIONA
*sd
= info
;
481 SERVICE_DESCRIPTIONW sdw
;
483 sdw
.lpDescription
= heap_strdupAtoW( sd
->lpDescription
);
485 r
= ChangeServiceConfig2W( service
, level
, &sdw
);
487 heap_free( sdw
.lpDescription
);
489 else if (level
== SERVICE_CONFIG_FAILURE_ACTIONS
)
491 SERVICE_FAILURE_ACTIONSA
*fa
= info
;
492 SERVICE_FAILURE_ACTIONSW faw
;
494 faw
.dwResetPeriod
= fa
->dwResetPeriod
;
495 faw
.lpRebootMsg
= heap_strdupAtoW( fa
->lpRebootMsg
);
496 faw
.lpCommand
= heap_strdupAtoW( fa
->lpCommand
);
497 faw
.cActions
= fa
->cActions
;
498 faw
.lpsaActions
= fa
->lpsaActions
;
500 r
= ChangeServiceConfig2W( service
, level
, &faw
);
502 heap_free( faw
.lpRebootMsg
);
503 heap_free( faw
.lpCommand
);
505 else if (level
== SERVICE_CONFIG_PRESHUTDOWN_INFO
)
507 r
= ChangeServiceConfig2W( service
, level
, info
);
510 SetLastError( ERROR_INVALID_PARAMETER
);
515 /******************************************************************************
516 * ChangeServiceConfig2W (sechost.@)
518 BOOL WINAPI DECLSPEC_HOTPATCH
ChangeServiceConfig2W( SC_HANDLE service
, DWORD level
, void *info
)
520 SERVICE_RPC_REQUIRED_PRIVILEGES_INFO rpc_privinfo
;
525 SC_RPC_CONFIG_INFOW rpc_info
;
527 rpc_info
.dwInfoLevel
= level
;
528 if (level
== SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO
)
530 SERVICE_REQUIRED_PRIVILEGES_INFOW
*privinfo
= info
;
532 rpc_privinfo
.cbRequiredPrivileges
= multisz_size( privinfo
->pmszRequiredPrivileges
);
533 rpc_privinfo
.pRequiredPrivileges
= (BYTE
*)privinfo
->pmszRequiredPrivileges
;
534 rpc_info
.privinfo
= &rpc_privinfo
;
537 rpc_info
.descr
= info
;
538 err
= svcctl_ChangeServiceConfig2W( service
, rpc_info
);
542 err
= map_exception_code( GetExceptionCode() );
546 return set_error( err
);
549 /******************************************************************************
550 * ChangeServiceConfigA (sechost.@)
552 BOOL WINAPI DECLSPEC_HOTPATCH
ChangeServiceConfigA( SC_HANDLE service
, DWORD service_type
, DWORD start_type
,
553 DWORD error_control
, const char *path
, const char *group
,
554 DWORD
*tag
, const char *dependencies
, const char *username
,
555 const char *password
, const char *display_name
)
557 WCHAR
*pathW
, *groupW
, *dependenciesW
, *usernameW
, *passwordW
, *display_nameW
;
560 TRACE( "%p %d %d %d %s %s %p %p %s %s %s\n", service
, service_type
, start_type
,
561 error_control
, debugstr_a(path
), debugstr_a(group
), tag
, dependencies
,
562 debugstr_a(username
), debugstr_a(password
), debugstr_a(display_name
) );
564 pathW
= heap_strdupAtoW( path
);
565 groupW
= heap_strdupAtoW( group
);
566 dependenciesW
= heap_strdup_multi_AtoW( dependencies
);
567 usernameW
= heap_strdupAtoW( username
);
568 passwordW
= heap_strdupAtoW( password
);
569 display_nameW
= heap_strdupAtoW( display_name
);
571 r
= ChangeServiceConfigW( service
, service_type
, start_type
, error_control
, pathW
,
572 groupW
, tag
, dependenciesW
, usernameW
, passwordW
, display_nameW
);
576 heap_free( dependenciesW
);
577 heap_free( usernameW
);
578 heap_free( passwordW
);
579 heap_free( display_nameW
);
584 /******************************************************************************
585 * ChangeServiceConfigW (sechost.@)
587 BOOL WINAPI DECLSPEC_HOTPATCH
ChangeServiceConfigW( SC_HANDLE service
, DWORD service_type
, DWORD start_type
,
588 DWORD error_control
, const WCHAR
*path
, const WCHAR
*group
,
589 DWORD
*tag
, const WCHAR
*dependencies
, const WCHAR
*username
,
590 const WCHAR
*password
, const WCHAR
*display_name
)
595 TRACE( "%p %d %d %d %s %s %p %p %s %s %s\n", service
, service_type
, start_type
,
596 error_control
, debugstr_w(path
), debugstr_w(group
), tag
, dependencies
,
597 debugstr_w(username
), debugstr_w(password
), debugstr_w(display_name
) );
599 password_size
= password
? (wcslen(password
) + 1) * sizeof(WCHAR
) : 0;
603 err
= svcctl_ChangeServiceConfigW( service
, service_type
, start_type
, error_control
, path
, group
, tag
,
604 (const BYTE
*)dependencies
, multisz_size(dependencies
), username
,
605 (const BYTE
*)password
, password_size
, display_name
);
609 err
= map_exception_code( GetExceptionCode() );
613 return set_error( err
);
616 /******************************************************************************
617 * QueryServiceConfigA (sechost.@)
619 BOOL WINAPI DECLSPEC_HOTPATCH
QueryServiceConfigA( SC_HANDLE service
, QUERY_SERVICE_CONFIGA
*config
,
620 DWORD size
, DWORD
*ret_size
)
625 QUERY_SERVICE_CONFIGW
*configW
;
627 TRACE( "%p %p %d %p\n", service
, config
, size
, ret_size
);
629 if (!(buffer
= heap_alloc( 2 * size
))) return set_error( ERROR_NOT_ENOUGH_MEMORY
);
630 configW
= (QUERY_SERVICE_CONFIGW
*)buffer
;
631 ret
= QueryServiceConfigW( service
, configW
, 2 * size
, ret_size
);
634 config
->dwServiceType
= configW
->dwServiceType
;
635 config
->dwStartType
= configW
->dwStartType
;
636 config
->dwErrorControl
= configW
->dwErrorControl
;
637 config
->lpBinaryPathName
= NULL
;
638 config
->lpLoadOrderGroup
= NULL
;
639 config
->dwTagId
= configW
->dwTagId
;
640 config
->lpDependencies
= NULL
;
641 config
->lpServiceStartName
= NULL
;
642 config
->lpDisplayName
= NULL
;
644 p
= (char *)(config
+ 1);
645 n
= size
- sizeof(*config
);
648 #define MAP_STR(str) \
652 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
653 if (!sz) goto done; \
660 MAP_STR( lpBinaryPathName
);
661 MAP_STR( lpLoadOrderGroup
);
662 MAP_STR( lpDependencies
);
663 MAP_STR( lpServiceStartName
);
664 MAP_STR( lpDisplayName
);
667 *ret_size
= p
- (char *)config
;
675 static DWORD
move_string_to_buffer(BYTE
**buf
, WCHAR
**string_ptr
)
686 cb
= (wcslen( *string_ptr
) + 1) * sizeof(WCHAR
);
687 memcpy(*buf
, *string_ptr
, cb
);
688 MIDL_user_free( *string_ptr
);
691 *string_ptr
= (WCHAR
*)*buf
;
697 static DWORD
size_string( const WCHAR
*string
)
699 return (string
? (wcslen( string
) + 1) * sizeof(WCHAR
) : sizeof(WCHAR
));
702 /******************************************************************************
703 * QueryServiceConfigW (sechost.@)
705 BOOL WINAPI DECLSPEC_HOTPATCH
QueryServiceConfigW( SC_HANDLE service
, QUERY_SERVICE_CONFIGW
*ret_config
,
706 DWORD size
, DWORD
*ret_size
)
708 QUERY_SERVICE_CONFIGW config
;
713 TRACE( "%p %p %d %p\n", service
, ret_config
, size
, ret_size
);
715 memset(&config
, 0, sizeof(config
));
719 err
= svcctl_QueryServiceConfigW( service
, &config
, size
, ret_size
);
723 err
= map_exception_code( GetExceptionCode() );
727 if (err
) return set_error( err
);
729 /* calculate the size required first */
730 total
= sizeof(QUERY_SERVICE_CONFIGW
);
731 total
+= size_string( config
.lpBinaryPathName
);
732 total
+= size_string( config
.lpLoadOrderGroup
);
733 total
+= size_string( config
.lpDependencies
);
734 total
+= size_string( config
.lpServiceStartName
);
735 total
+= size_string( config
.lpDisplayName
);
739 /* if there's not enough memory, return an error */
742 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
743 MIDL_user_free( config
.lpBinaryPathName
);
744 MIDL_user_free( config
.lpLoadOrderGroup
);
745 MIDL_user_free( config
.lpDependencies
);
746 MIDL_user_free( config
.lpServiceStartName
);
747 MIDL_user_free( config
.lpDisplayName
);
751 *ret_config
= config
;
752 bufpos
= ((BYTE
*)ret_config
) + sizeof(QUERY_SERVICE_CONFIGW
);
753 move_string_to_buffer( &bufpos
, &ret_config
->lpBinaryPathName
);
754 move_string_to_buffer( &bufpos
, &ret_config
->lpLoadOrderGroup
);
755 move_string_to_buffer( &bufpos
, &ret_config
->lpDependencies
);
756 move_string_to_buffer( &bufpos
, &ret_config
->lpServiceStartName
);
757 move_string_to_buffer( &bufpos
, &ret_config
->lpDisplayName
);
759 TRACE( "Image path = %s\n", debugstr_w( ret_config
->lpBinaryPathName
) );
760 TRACE( "Group = %s\n", debugstr_w( ret_config
->lpLoadOrderGroup
) );
761 TRACE( "Dependencies = %s\n", debugstr_w( ret_config
->lpDependencies
) );
762 TRACE( "Service account name = %s\n", debugstr_w( ret_config
->lpServiceStartName
) );
763 TRACE( "Display name = %s\n", debugstr_w( ret_config
->lpDisplayName
) );
768 /******************************************************************************
769 * QueryServiceConfig2A (sechost.@)
771 BOOL WINAPI DECLSPEC_HOTPATCH
QueryServiceConfig2A( SC_HANDLE service
, DWORD level
, BYTE
*buffer
,
772 DWORD size
, DWORD
*ret_size
)
774 BYTE
*bufferW
= NULL
;
776 TRACE( "%p %u %p %u %p\n", service
, level
, buffer
, size
, ret_size
);
779 bufferW
= heap_alloc( size
);
781 if (!QueryServiceConfig2W( service
, level
, bufferW
, size
, ret_size
))
783 heap_free( bufferW
);
789 case SERVICE_CONFIG_DESCRIPTION
:
790 if (buffer
&& bufferW
) {
791 SERVICE_DESCRIPTIONA
*configA
= (SERVICE_DESCRIPTIONA
*)buffer
;
792 SERVICE_DESCRIPTIONW
*configW
= (SERVICE_DESCRIPTIONW
*)bufferW
;
793 if (configW
->lpDescription
&& size
> sizeof(SERVICE_DESCRIPTIONA
))
795 configA
->lpDescription
= (char *)(configA
+ 1);
796 WideCharToMultiByte( CP_ACP
, 0, configW
->lpDescription
, -1, configA
->lpDescription
,
797 size
- sizeof(SERVICE_DESCRIPTIONA
), NULL
, NULL
);
799 else configA
->lpDescription
= NULL
;
802 case SERVICE_CONFIG_PRESHUTDOWN_INFO
:
803 if (buffer
&& bufferW
&& *ret_size
<= size
)
804 memcpy(buffer
, bufferW
, *ret_size
);
807 FIXME("conversion W->A not implemented for level %d\n", level
);
808 heap_free( bufferW
);
812 heap_free( bufferW
);
816 /******************************************************************************
817 * QueryServiceConfig2W (sechost.@)
819 BOOL WINAPI DECLSPEC_HOTPATCH
QueryServiceConfig2W( SC_HANDLE service
, DWORD level
, BYTE
*buffer
,
820 DWORD size
, DWORD
*ret_size
)
825 TRACE( "%p %u %p %u %p\n", service
, level
, buffer
, size
, ret_size
);
829 SetLastError(ERROR_INVALID_ADDRESS
);
835 case SERVICE_CONFIG_DESCRIPTION
:
836 if (!(bufptr
= heap_alloc( size
)))
838 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
843 case SERVICE_CONFIG_PRESHUTDOWN_INFO
:
848 FIXME("Level %d not implemented\n", level
);
849 SetLastError(ERROR_INVALID_LEVEL
);
855 if (level
== SERVICE_CONFIG_DESCRIPTION
) heap_free( bufptr
);
856 SetLastError(ERROR_INVALID_ADDRESS
);
862 err
= svcctl_QueryServiceConfig2W( service
, level
, bufptr
, size
, ret_size
);
866 err
= map_exception_code( GetExceptionCode() );
872 case SERVICE_CONFIG_DESCRIPTION
:
874 SERVICE_DESCRIPTIONW
*desc
= (SERVICE_DESCRIPTIONW
*)buffer
;
875 struct service_description
*s
= (struct service_description
*)bufptr
;
877 if (err
!= ERROR_SUCCESS
&& err
!= ERROR_INSUFFICIENT_BUFFER
)
884 /* adjust for potentially larger SERVICE_DESCRIPTIONW structure */
885 if (*ret_size
== sizeof(*s
))
886 *ret_size
= sizeof(*desc
);
888 *ret_size
= *ret_size
- FIELD_OFFSET(struct service_description
, description
) + sizeof(*desc
);
890 if (size
< *ret_size
)
893 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
898 if (!s
->size
) desc
->lpDescription
= NULL
;
901 desc
->lpDescription
= (WCHAR
*)(desc
+ 1);
902 memcpy( desc
->lpDescription
, s
->description
, s
->size
);
908 case SERVICE_CONFIG_PRESHUTDOWN_INFO
:
909 return set_error( err
);
918 /******************************************************************************
919 * GetServiceDisplayNameW (sechost.@)
921 BOOL WINAPI DECLSPEC_HOTPATCH
GetServiceDisplayNameW( SC_HANDLE manager
, const WCHAR
*service
,
922 WCHAR
*display_name
, DWORD
*len
)
928 TRACE( "%p %s %p %p\n", manager
, debugstr_w(service
), display_name
, len
);
932 SetLastError( ERROR_INVALID_HANDLE
);
936 /* provide a buffer if the caller didn't */
937 if (!display_name
|| *len
< sizeof(WCHAR
))
939 display_name
= buffer
;
940 /* A size of 1 would be enough, but tests show that Windows returns 2,
941 * probably because of a WCHAR/bytes mismatch in their code. */
945 /* RPC call takes size excluding nul-terminator, whereas *len
946 * includes the nul-terminator on input. */
951 err
= svcctl_GetServiceDisplayNameW( manager
, service
, display_name
, &size
);
955 err
= map_exception_code( GetExceptionCode() );
959 /* The value of *len excludes nul-terminator on output. */
960 if (err
== ERROR_SUCCESS
|| err
== ERROR_INSUFFICIENT_BUFFER
)
962 return set_error( err
);
965 /******************************************************************************
966 * GetServiceKeyNameW (sechost.@)
968 BOOL WINAPI DECLSPEC_HOTPATCH
GetServiceKeyNameW( SC_HANDLE manager
, const WCHAR
*display_name
,
969 WCHAR
*key_name
, DWORD
*len
)
975 TRACE( "%p %s %p %p\n", manager
, debugstr_w(display_name
), key_name
, len
);
979 SetLastError( ERROR_INVALID_HANDLE
);
983 /* provide a buffer if the caller didn't */
984 if (!key_name
|| *len
< 2)
987 /* A size of 1 would be enough, but tests show that Windows returns 2,
988 * probably because of a WCHAR/bytes mismatch in their code.
993 /* RPC call takes size excluding nul-terminator, whereas *len
994 * includes the nul-terminator on input. */
999 err
= svcctl_GetServiceKeyNameW( manager
, display_name
, key_name
, &size
);
1001 __EXCEPT(rpc_filter
)
1003 err
= map_exception_code( GetExceptionCode() );
1007 /* The value of *lpcchBuffer excludes nul-terminator on output. */
1008 if (err
== ERROR_SUCCESS
|| err
== ERROR_INSUFFICIENT_BUFFER
)
1010 return set_error( err
);
1013 /******************************************************************************
1014 * StartServiceA (sechost.@)
1016 BOOL WINAPI DECLSPEC_HOTPATCH
StartServiceA( SC_HANDLE service
, DWORD argc
, const char **argv
)
1018 WCHAR
**argvW
= NULL
;
1023 argvW
= heap_alloc( argc
* sizeof(WCHAR
) );
1025 for (i
= 0; i
< argc
; i
++)
1026 argvW
[i
] = heap_strdupAtoW( argv
[i
] );
1028 r
= StartServiceW( service
, argc
, (const WCHAR
**)argvW
);
1030 for (i
= 0; i
< argc
; i
++)
1031 heap_free( argvW
[i
] );
1037 /******************************************************************************
1038 * StartServiceW (sechost.@)
1040 BOOL WINAPI DECLSPEC_HOTPATCH
StartServiceW( SC_HANDLE service
, DWORD argc
, const WCHAR
**argv
)
1044 TRACE( "%p %u %p\n", service
, argc
, argv
);
1048 err
= svcctl_StartServiceW( service
, argc
, argv
);
1050 __EXCEPT(rpc_filter
)
1052 err
= map_exception_code( GetExceptionCode() );
1056 return set_error( err
);
1059 /******************************************************************************
1060 * ControlService (sechost.@)
1062 BOOL WINAPI DECLSPEC_HOTPATCH
ControlService( SC_HANDLE service
, DWORD control
, SERVICE_STATUS
*status
)
1066 TRACE( "%p %d %p\n", service
, control
, status
);
1070 err
= svcctl_ControlService( service
, control
, status
);
1072 __EXCEPT(rpc_filter
)
1074 err
= map_exception_code( GetExceptionCode() );
1078 return set_error( err
);
1081 /******************************************************************************
1082 * QueryServiceStatus (sechost.@)
1084 BOOL WINAPI DECLSPEC_HOTPATCH
QueryServiceStatus( SC_HANDLE service
, SERVICE_STATUS
*status
)
1086 SERVICE_STATUS_PROCESS process_status
;
1090 TRACE( "%p %p\n", service
, status
);
1092 if (!service
) return set_error( ERROR_INVALID_HANDLE
);
1093 if (!status
) return set_error( ERROR_INVALID_ADDRESS
);
1095 ret
= QueryServiceStatusEx( service
, SC_STATUS_PROCESS_INFO
, (BYTE
*)&process_status
,
1096 sizeof(SERVICE_STATUS_PROCESS
), &size
);
1097 if (ret
) memcpy(status
, &process_status
, sizeof(SERVICE_STATUS
) );
1101 /******************************************************************************
1102 * QueryServiceStatusEx (sechost.@)
1104 BOOL WINAPI DECLSPEC_HOTPATCH
QueryServiceStatusEx( SC_HANDLE service
, SC_STATUS_TYPE level
,
1105 BYTE
*buffer
, DWORD size
, DWORD
*ret_size
)
1109 TRACE( "%p %d %p %d %p\n", service
, level
, buffer
, size
, ret_size
);
1111 if (level
!= SC_STATUS_PROCESS_INFO
) return set_error( ERROR_INVALID_LEVEL
);
1113 if (size
< sizeof(SERVICE_STATUS_PROCESS
))
1115 *ret_size
= sizeof(SERVICE_STATUS_PROCESS
);
1116 return set_error( ERROR_INSUFFICIENT_BUFFER
);
1121 err
= svcctl_QueryServiceStatusEx( service
, level
, buffer
, size
, ret_size
);
1123 __EXCEPT(rpc_filter
)
1125 err
= map_exception_code( GetExceptionCode() );
1129 return set_error( err
);
1132 /******************************************************************************
1133 * EnumServicesStatusExW (sechost.@)
1135 BOOL WINAPI DECLSPEC_HOTPATCH
EnumServicesStatusExW( SC_HANDLE manager
, SC_ENUM_TYPE level
, DWORD type
, DWORD state
,
1136 BYTE
*buffer
, DWORD size
, DWORD
*needed
, DWORD
*returned
,
1137 DWORD
*resume_handle
, const WCHAR
*group
)
1139 DWORD err
, i
, offset
, buflen
, count
, total_size
= 0;
1140 ENUM_SERVICE_STATUS_PROCESSW
*services
= (ENUM_SERVICE_STATUS_PROCESSW
*)buffer
;
1141 struct enum_service_status_process
*entry
;
1145 TRACE( "%p %u 0x%x 0x%x %p %u %p %p %p %s\n", manager
, level
, type
, state
, buffer
,
1146 size
, needed
, returned
, resume_handle
, debugstr_w(group
) );
1148 if (level
!= SC_ENUM_PROCESS_INFO
) return set_error( ERROR_INVALID_LEVEL
);
1149 if (!manager
) return set_error( ERROR_INVALID_HANDLE
);
1150 if (!needed
|| !returned
) return set_error( ERROR_INVALID_ADDRESS
);
1152 /* make sure we pass a valid pointer */
1153 buflen
= max( size
, sizeof(*services
) );
1154 if (!(buf
= heap_alloc( buflen
))) return set_error( ERROR_NOT_ENOUGH_MEMORY
);
1158 err
= svcctl_EnumServicesStatusExW( manager
, SC_ENUM_PROCESS_INFO
, type
, state
, buf
, buflen
, needed
,
1159 &count
, resume_handle
, group
);
1161 __EXCEPT(rpc_filter
)
1163 err
= map_exception_code( GetExceptionCode() );
1168 if (err
!= ERROR_SUCCESS
)
1170 /* double the needed size to fit the potentially larger ENUM_SERVICE_STATUS_PROCESSW */
1171 if (err
== ERROR_MORE_DATA
) *needed
*= 2;
1173 SetLastError( err
);
1177 entry
= (struct enum_service_status_process
*)buf
;
1178 for (i
= 0; i
< count
; i
++)
1180 total_size
+= sizeof(*services
);
1181 if (entry
->service_name
)
1183 str
= (const WCHAR
*)(buf
+ entry
->service_name
);
1184 total_size
+= (wcslen( str
) + 1) * sizeof(WCHAR
);
1186 if (entry
->display_name
)
1188 str
= (const WCHAR
*)(buf
+ entry
->display_name
);
1189 total_size
+= (wcslen( str
) + 1) * sizeof(WCHAR
);
1194 if (total_size
> size
)
1197 *needed
= total_size
;
1198 SetLastError( ERROR_MORE_DATA
);
1202 offset
= count
* sizeof(*services
);
1203 entry
= (struct enum_service_status_process
*)buf
;
1204 for (i
= 0; i
< count
; i
++)
1207 str
= (const WCHAR
*)(buf
+ entry
->service_name
);
1208 str_size
= (wcslen( str
) + 1) * sizeof(WCHAR
);
1209 services
[i
].lpServiceName
= (WCHAR
*)((char *)services
+ offset
);
1210 memcpy( services
[i
].lpServiceName
, str
, str_size
);
1213 if (!entry
->display_name
) services
[i
].lpDisplayName
= NULL
;
1216 str
= (const WCHAR
*)(buf
+ entry
->display_name
);
1217 str_size
= (wcslen( str
) + 1) * sizeof(WCHAR
);
1218 services
[i
].lpDisplayName
= (WCHAR
*)((char *)services
+ offset
);
1219 memcpy( services
[i
].lpDisplayName
, str
, str_size
);
1222 services
[i
].ServiceStatusProcess
= entry
->service_status_process
;
1232 /******************************************************************************
1233 * EnumDependentServicesW (sechost.@)
1235 BOOL WINAPI
EnumDependentServicesW( SC_HANDLE hService
, DWORD dwServiceState
,
1236 LPENUM_SERVICE_STATUSW lpServices
, DWORD cbBufSize
,
1237 LPDWORD pcbBytesNeeded
, LPDWORD lpServicesReturned
)
1239 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService
, dwServiceState
,
1240 lpServices
, cbBufSize
, pcbBytesNeeded
, lpServicesReturned
);
1242 *lpServicesReturned
= 0;
1246 /******************************************************************************
1247 * QueryServiceObjectSecurity (sechost.@)
1249 BOOL WINAPI DECLSPEC_HOTPATCH
QueryServiceObjectSecurity( SC_HANDLE service
, SECURITY_INFORMATION type
,
1250 PSECURITY_DESCRIPTOR ret_descriptor
, DWORD size
, DWORD
*ret_size
)
1252 SECURITY_DESCRIPTOR descriptor
;
1256 FIXME( "%p %d %p %u %p - semi-stub\n", service
, type
, ret_descriptor
, size
, ret_size
);
1258 if (type
!= DACL_SECURITY_INFORMATION
)
1259 FIXME("information %d not supported\n", type
);
1261 InitializeSecurityDescriptor( &descriptor
, SECURITY_DESCRIPTOR_REVISION
);
1263 InitializeAcl( &acl
, sizeof(ACL
), ACL_REVISION
);
1264 SetSecurityDescriptorDacl( &descriptor
, TRUE
, &acl
, TRUE
);
1266 status
= RtlMakeSelfRelativeSD( &descriptor
, ret_descriptor
, &size
);
1269 return set_error( RtlNtStatusToDosError( status
) );
1272 /******************************************************************************
1273 * SetServiceObjectSecurity (sechost.@)
1275 BOOL WINAPI
SetServiceObjectSecurity(SC_HANDLE hService
,
1276 SECURITY_INFORMATION dwSecurityInformation
,
1277 PSECURITY_DESCRIPTOR lpSecurityDescriptor
)
1279 FIXME("%p %d %p\n", hService
, dwSecurityInformation
, lpSecurityDescriptor
);
1283 static DWORD WINAPI
notify_thread(void *user
)
1286 struct notify_data
*data
= user
;
1287 SC_RPC_NOTIFY_PARAMS_LIST
*list
= NULL
;
1288 SERVICE_NOTIFY_STATUS_CHANGE_PARAMS_2
*cparams
;
1293 /* GetNotifyResults blocks until there is an event */
1294 err
= svcctl_GetNotifyResults(data
->notify_handle
, &list
);
1296 __EXCEPT(rpc_filter
)
1298 err
= map_exception_code(GetExceptionCode());
1302 EnterCriticalSection( &service_cs
);
1304 list_remove(&data
->entry
);
1306 LeaveCriticalSection( &service_cs
);
1308 if (err
== ERROR_SUCCESS
&& list
)
1310 cparams
= list
->NotifyParamsArray
[0].params
;
1312 data
->notify_buffer
->dwNotificationStatus
= cparams
->dwNotificationStatus
;
1313 memcpy(&data
->notify_buffer
->ServiceStatus
, &cparams
->ServiceStatus
,
1314 sizeof(SERVICE_STATUS_PROCESS
));
1315 data
->notify_buffer
->dwNotificationTriggered
= cparams
->dwNotificationTriggered
;
1316 data
->notify_buffer
->pszServiceNames
= NULL
;
1318 QueueUserAPC((PAPCFUNC
)data
->notify_buffer
->pfnNotifyCallback
,
1319 data
->calling_thread
, (ULONG_PTR
)data
->notify_buffer
);
1321 HeapFree(GetProcessHeap(), 0, list
);
1324 WARN("GetNotifyResults server call failed: %u\n", err
);
1329 err
= svcctl_CloseNotifyHandle(&data
->notify_handle
, &dummy
);
1331 __EXCEPT(rpc_filter
)
1333 err
= map_exception_code(GetExceptionCode());
1337 if (err
!= ERROR_SUCCESS
)
1338 WARN("CloseNotifyHandle server call failed: %u\n", err
);
1340 CloseHandle(data
->calling_thread
);
1341 HeapFree(GetProcessHeap(), 0, data
);
1346 /******************************************************************************
1347 * NotifyServiceStatusChangeW (sechost.@)
1349 DWORD WINAPI DECLSPEC_HOTPATCH
NotifyServiceStatusChangeW( SC_HANDLE service
, DWORD mask
,
1350 SERVICE_NOTIFYW
*notify_buffer
)
1353 BOOL b_dummy
= FALSE
;
1355 struct notify_data
*data
;
1357 TRACE( "%p 0x%x %p\n", service
, mask
, notify_buffer
);
1359 if (!(data
= heap_alloc_zero( sizeof(*data
) )))
1360 return ERROR_NOT_ENOUGH_MEMORY
;
1362 data
->service
= service
;
1363 data
->notify_buffer
= notify_buffer
;
1364 if (!DuplicateHandle( GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(),
1365 &data
->calling_thread
, 0, FALSE
, DUPLICATE_SAME_ACCESS
))
1367 ERR("DuplicateHandle failed: %u\n", GetLastError());
1369 return ERROR_NOT_ENOUGH_MEMORY
;
1372 data
->params
.dwInfoLevel
= 2;
1373 data
->params
.params
= &data
->cparams
;
1375 data
->cparams
.dwNotifyMask
= mask
;
1377 EnterCriticalSection( &service_cs
);
1381 err
= svcctl_NotifyServiceStatusChange( service
, data
->params
, &g_dummy
,
1382 &g_dummy
, &b_dummy
, &data
->notify_handle
);
1384 __EXCEPT(rpc_filter
)
1386 err
= map_exception_code( GetExceptionCode() );
1390 if (err
!= ERROR_SUCCESS
)
1392 WARN("NotifyServiceStatusChange server call failed: %u\n", err
);
1393 LeaveCriticalSection( &service_cs
);
1394 CloseHandle( data
->calling_thread
);
1395 CloseHandle( data
->ready_evt
);
1400 CloseHandle( CreateThread( NULL
, 0, ¬ify_thread
, data
, 0, NULL
) );
1402 list_add_tail( ¬ify_list
, &data
->entry
);
1404 LeaveCriticalSection( &service_cs
);
1406 return ERROR_SUCCESS
;
1409 /* thunk for calling the RegisterServiceCtrlHandler handler function */
1410 static DWORD WINAPI
ctrl_handler_thunk( DWORD control
, DWORD type
, void *data
, void *context
)
1412 LPHANDLER_FUNCTION func
= context
;
1415 return ERROR_SUCCESS
;
1418 /******************************************************************************
1419 * RegisterServiceCtrlHandlerA (sechost.@)
1421 SERVICE_STATUS_HANDLE WINAPI DECLSPEC_HOTPATCH
RegisterServiceCtrlHandlerA(
1422 const char *name
, LPHANDLER_FUNCTION handler
)
1424 return RegisterServiceCtrlHandlerExA( name
, ctrl_handler_thunk
, handler
);
1427 /******************************************************************************
1428 * RegisterServiceCtrlHandlerW (sechost.@)
1430 SERVICE_STATUS_HANDLE WINAPI DECLSPEC_HOTPATCH
RegisterServiceCtrlHandlerW(
1431 const WCHAR
*name
, LPHANDLER_FUNCTION handler
)
1433 return RegisterServiceCtrlHandlerExW( name
, ctrl_handler_thunk
, handler
);
1436 /******************************************************************************
1437 * RegisterServiceCtrlHandlerExA (sechost.@)
1439 SERVICE_STATUS_HANDLE WINAPI DECLSPEC_HOTPATCH
RegisterServiceCtrlHandlerExA(
1440 const char *name
, LPHANDLER_FUNCTION_EX handler
, void *context
)
1443 SERVICE_STATUS_HANDLE ret
;
1445 nameW
= heap_strdupAtoW( name
);
1446 ret
= RegisterServiceCtrlHandlerExW( nameW
, handler
, context
);
1451 static struct service_data
*find_service_by_name( const WCHAR
*name
)
1455 if (nb_services
== 1) /* only one service (FIXME: should depend on OWN_PROCESS etc.) */
1457 for (i
= 0; i
< nb_services
; i
++)
1458 if (!wcsicmp( name
, services
[i
]->name
)) return services
[i
];
1462 /******************************************************************************
1463 * RegisterServiceCtrlHandlerExW (sechost.@)
1465 SERVICE_STATUS_HANDLE WINAPI DECLSPEC_HOTPATCH
RegisterServiceCtrlHandlerExW(
1466 const WCHAR
*name
, LPHANDLER_FUNCTION_EX handler
, void *context
)
1468 struct service_data
*service
;
1469 SC_HANDLE handle
= 0;
1471 TRACE( "%s %p %p\n", debugstr_w(name
), handler
, context
);
1473 EnterCriticalSection( &service_cs
);
1474 if ((service
= find_service_by_name( name
)))
1476 service
->handler
= handler
;
1477 service
->context
= context
;
1478 handle
= service
->handle
;
1480 LeaveCriticalSection( &service_cs
);
1482 if (!handle
) SetLastError( ERROR_SERVICE_DOES_NOT_EXIST
);
1483 return (SERVICE_STATUS_HANDLE
)handle
;
1486 /******************************************************************************
1487 * SetServiceStatus (sechost.@)
1489 BOOL WINAPI DECLSPEC_HOTPATCH
SetServiceStatus( SERVICE_STATUS_HANDLE service
, SERVICE_STATUS
*status
)
1493 TRACE( "%p %#x %#x %#x %#x %#x %#x %#x\n", service
, status
->dwServiceType
,
1494 status
->dwCurrentState
, status
->dwControlsAccepted
, status
->dwWin32ExitCode
,
1495 status
->dwServiceSpecificExitCode
, status
->dwCheckPoint
, status
->dwWaitHint
);
1499 err
= svcctl_SetServiceStatus( service
, status
);
1501 __EXCEPT(rpc_filter
)
1503 err
= map_exception_code( GetExceptionCode() );
1507 if (!set_error( err
))
1510 if (status
->dwCurrentState
== SERVICE_STOPPED
)
1512 unsigned int i
, count
= 0;
1513 EnterCriticalSection( &service_cs
);
1514 for (i
= 0; i
< nb_services
; i
++)
1516 if (services
[i
]->handle
== (SC_HANDLE
)service
) continue;
1517 if (services
[i
]->thread
) count
++;
1521 stop_service
= TRUE
;
1522 SetEvent( service_event
); /* notify the main loop */
1524 LeaveCriticalSection( &service_cs
);
1530 static WCHAR
*service_get_pipe_name(void)
1532 static const WCHAR format
[] = L
"\\\\.\\pipe\\net\\NtControlPipe%u";
1535 HKEY service_current_key
;
1536 DWORD service_current
;
1540 ret
= RegOpenKeyExW( HKEY_LOCAL_MACHINE
,
1541 L
"SYSTEM\\CurrentControlSet\\Control\\ServiceCurrent",
1542 0, KEY_QUERY_VALUE
, &service_current_key
);
1543 if (ret
!= ERROR_SUCCESS
)
1546 len
= sizeof(service_current
);
1547 ret
= RegQueryValueExW( service_current_key
, NULL
, NULL
, &type
,
1548 (BYTE
*)&service_current
, &len
);
1549 RegCloseKey(service_current_key
);
1550 if (ret
!= ERROR_SUCCESS
|| type
!= REG_DWORD
)
1553 len
= ARRAY_SIZE(format
) + 10 /* strlenW("4294967295") */;
1554 name
= heap_alloc(len
* sizeof(WCHAR
));
1558 swprintf( name
, len
, format
, service_current
);
1562 static HANDLE
service_open_pipe(void)
1564 WCHAR
*pipe_name
= service_get_pipe_name();
1565 HANDLE handle
= INVALID_HANDLE_VALUE
;
1569 handle
= CreateFileW( pipe_name
, GENERIC_READ
|GENERIC_WRITE
,
1570 0, NULL
, OPEN_ALWAYS
, 0, NULL
);
1571 if (handle
!= INVALID_HANDLE_VALUE
)
1573 if (GetLastError() != ERROR_PIPE_BUSY
)
1575 } while (WaitNamedPipeW( pipe_name
, NMPWAIT_USE_DEFAULT_WAIT
));
1576 heap_free(pipe_name
);
1581 static DWORD WINAPI
service_thread( void *arg
)
1583 struct service_data
*info
= arg
;
1584 WCHAR
*str
= info
->args
;
1585 DWORD argc
= 0, len
= 0;
1591 len
+= wcslen( &str
[len
] ) + 1;
1600 argv
= heap_alloc( (argc
+1)*sizeof(*argv
) );
1601 for (argc
= 0, p
= str
; *p
; p
+= wcslen( p
) + 1)
1605 info
->proc
.w( argc
, argv
);
1610 char *strA
, **argv
, *p
;
1613 lenA
= WideCharToMultiByte( CP_ACP
,0, str
, len
, NULL
, 0, NULL
, NULL
);
1614 strA
= heap_alloc(lenA
);
1615 WideCharToMultiByte(CP_ACP
,0, str
, len
, strA
, lenA
, NULL
, NULL
);
1617 argv
= heap_alloc( (argc
+1)*sizeof(*argv
) );
1618 for (argc
= 0, p
= strA
; *p
; p
+= strlen( p
) + 1)
1622 info
->proc
.a( argc
, argv
);
1629 static DWORD
service_handle_start( struct service_data
*service
, const void *data
, DWORD data_size
)
1631 DWORD count
= data_size
/ sizeof(WCHAR
);
1633 if (service
->thread
)
1635 WARN("service is not stopped\n");
1636 return ERROR_SERVICE_ALREADY_RUNNING
;
1639 heap_free( service
->args
);
1640 service
->args
= heap_alloc( (count
+ 2) * sizeof(WCHAR
) );
1641 if (count
) memcpy( service
->args
, data
, count
* sizeof(WCHAR
) );
1642 service
->args
[count
++] = 0;
1643 service
->args
[count
++] = 0;
1645 service
->thread
= CreateThread( NULL
, 0, service_thread
,
1647 SetEvent( service_event
); /* notify the main loop */
1651 static DWORD
service_handle_control( struct service_data
*service
, DWORD control
, const void *data
, DWORD data_size
)
1653 DWORD ret
= ERROR_INVALID_SERVICE_CONTROL
;
1655 TRACE( "%s control %u data %p data_size %u\n", debugstr_w(service
->name
), control
, data
, data_size
);
1657 if (control
== SERVICE_CONTROL_START
)
1658 ret
= service_handle_start( service
, data
, data_size
);
1659 else if (service
->handler
)
1660 ret
= service
->handler( control
, 0, (void *)data
, service
->context
);
1664 static DWORD WINAPI
service_control_dispatcher( void *arg
)
1666 struct dispatcher_data
*disp
= arg
;
1668 /* dispatcher loop */
1671 struct service_data
*service
;
1672 service_start_info info
;
1676 DWORD data_size
= 0, count
, result
;
1678 r
= ReadFile( disp
->pipe
, &info
, FIELD_OFFSET(service_start_info
,data
), &count
, NULL
);
1681 if (GetLastError() != ERROR_BROKEN_PIPE
)
1682 ERR( "pipe read failed error %u\n", GetLastError() );
1685 if (count
!= FIELD_OFFSET(service_start_info
,data
))
1687 ERR( "partial pipe read %u\n", count
);
1690 if (count
< info
.total_size
)
1692 data_size
= info
.total_size
- FIELD_OFFSET(service_start_info
,data
);
1693 data
= heap_alloc( data_size
);
1694 r
= ReadFile( disp
->pipe
, data
, data_size
, &count
, NULL
);
1697 if (GetLastError() != ERROR_BROKEN_PIPE
)
1698 ERR( "pipe read failed error %u\n", GetLastError() );
1702 if (count
!= data_size
)
1704 ERR( "partial pipe read %u/%u\n", count
, data_size
);
1710 EnterCriticalSection( &service_cs
);
1712 /* validate service name */
1713 name
= (WCHAR
*)data
;
1714 if (!info
.name_size
|| data_size
< info
.name_size
* sizeof(WCHAR
) || name
[info
.name_size
- 1])
1716 ERR( "got request without valid service name\n" );
1717 result
= ERROR_INVALID_PARAMETER
;
1721 if (info
.magic
!= SERVICE_PROTOCOL_MAGIC
)
1723 ERR( "received invalid request for service %s\n", debugstr_w(name
) );
1724 result
= ERROR_INVALID_PARAMETER
;
1728 /* find the service */
1729 if (!(service
= find_service_by_name( name
)))
1731 FIXME( "got request for unknown service %s\n", debugstr_w(name
) );
1732 result
= ERROR_INVALID_PARAMETER
;
1736 if (!service
->handle
)
1738 if (!(service
->handle
= OpenServiceW( disp
->manager
, name
, SERVICE_SET_STATUS
)) ||
1739 !(service
->full_access_handle
= OpenServiceW( disp
->manager
, name
,
1740 GENERIC_READ
|GENERIC_WRITE
)))
1741 FIXME( "failed to open service %s\n", debugstr_w(name
) );
1744 data_size
-= info
.name_size
* sizeof(WCHAR
);
1745 result
= service_handle_control(service
, info
.control
, data_size
?
1746 &data
[info
.name_size
* sizeof(WCHAR
)] : NULL
, data_size
);
1749 LeaveCriticalSection( &service_cs
);
1750 WriteFile( disp
->pipe
, &result
, sizeof(result
), &count
, NULL
);
1754 CloseHandle( disp
->pipe
);
1755 CloseServiceHandle( disp
->manager
);
1760 /* wait for services which accept this type of message to become STOPPED */
1761 static void handle_shutdown_msg(DWORD msg
, DWORD accept
)
1764 SERVICE_PRESHUTDOWN_INFO spi
;
1765 DWORD i
, n
= 0, sz
, timeout
= 2000;
1766 ULONGLONG stop_time
;
1767 BOOL res
, done
= TRUE
;
1768 SC_HANDLE
*wait_handles
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(SC_HANDLE
) * nb_services
);
1770 EnterCriticalSection( &service_cs
);
1771 for (i
= 0; i
< nb_services
; i
++)
1773 res
= QueryServiceStatus( services
[i
]->full_access_handle
, &st
);
1774 if (!res
|| st
.dwCurrentState
== SERVICE_STOPPED
|| !(st
.dwControlsAccepted
& accept
))
1779 if (accept
== SERVICE_ACCEPT_PRESHUTDOWN
)
1781 res
= QueryServiceConfig2W( services
[i
]->full_access_handle
, SERVICE_CONFIG_PRESHUTDOWN_INFO
,
1782 (BYTE
*)&spi
, sizeof(spi
), &sz
);
1785 FIXME( "service should be able to delay shutdown\n" );
1786 timeout
= max( spi
.dwPreshutdownTimeout
, timeout
);
1790 service_handle_control( services
[i
], msg
, NULL
, 0 );
1791 wait_handles
[n
++] = services
[i
]->full_access_handle
;
1793 LeaveCriticalSection( &service_cs
);
1795 /* FIXME: these timeouts should be more generous, but we can't currently delay prefix shutdown */
1796 timeout
= min( timeout
, 3000 );
1797 stop_time
= GetTickCount64() + timeout
;
1799 while (!done
&& GetTickCount64() < stop_time
)
1802 for (i
= 0; i
< n
; i
++)
1804 res
= QueryServiceStatus( wait_handles
[i
], &st
);
1805 if (!res
|| st
.dwCurrentState
== SERVICE_STOPPED
)
1814 HeapFree( GetProcessHeap(), 0, wait_handles
);
1817 static BOOL
service_run_main_thread(void)
1820 HANDLE wait_handles
[MAXIMUM_WAIT_OBJECTS
];
1821 UINT wait_services
[MAXIMUM_WAIT_OBJECTS
];
1822 struct dispatcher_data
*disp
= heap_alloc( sizeof(*disp
) );
1824 disp
->manager
= OpenSCManagerW( NULL
, NULL
, SC_MANAGER_CONNECT
);
1827 ERR("failed to open service manager error %u\n", GetLastError());
1832 disp
->pipe
= service_open_pipe();
1833 if (disp
->pipe
== INVALID_HANDLE_VALUE
)
1835 WARN("failed to create control pipe error %u\n", GetLastError());
1836 CloseServiceHandle( disp
->manager
);
1838 SetLastError( ERROR_FAILED_SERVICE_CONTROLLER_CONNECT
);
1842 service_event
= CreateEventW( NULL
, FALSE
, FALSE
, NULL
);
1843 stop_service
= FALSE
;
1845 /* FIXME: service_control_dispatcher should be merged into the main thread */
1846 NtSetInformationProcess( GetCurrentProcess(), ProcessWineMakeProcessSystem
,
1847 &wait_handles
[0], sizeof(HANDLE
*) );
1848 wait_handles
[1] = CreateThread( NULL
, 0, service_control_dispatcher
, disp
, 0, NULL
);
1849 wait_handles
[2] = service_event
;
1851 TRACE("Starting %d services running as process %d\n",
1852 nb_services
, GetCurrentProcessId());
1854 /* wait for all the threads to pack up and exit */
1855 while (!stop_service
)
1857 EnterCriticalSection( &service_cs
);
1858 for (i
= 0, n
= 3; i
< nb_services
&& n
< MAXIMUM_WAIT_OBJECTS
; i
++)
1860 if (!services
[i
]->thread
) continue;
1861 wait_services
[n
] = i
;
1862 wait_handles
[n
++] = services
[i
]->thread
;
1864 LeaveCriticalSection( &service_cs
);
1866 ret
= WaitForMultipleObjects( n
, wait_handles
, FALSE
, INFINITE
);
1867 if (!ret
) /* system process event */
1869 handle_shutdown_msg(SERVICE_CONTROL_PRESHUTDOWN
, SERVICE_ACCEPT_PRESHUTDOWN
);
1870 handle_shutdown_msg(SERVICE_CONTROL_SHUTDOWN
, SERVICE_ACCEPT_SHUTDOWN
);
1875 TRACE( "control dispatcher exited, shutting down\n" );
1876 /* FIXME: we should maybe send a shutdown control to running services */
1881 continue; /* rebuild the list */
1885 i
= wait_services
[ret
];
1886 EnterCriticalSection( &service_cs
);
1887 CloseHandle( services
[i
]->thread
);
1888 services
[i
]->thread
= NULL
;
1889 LeaveCriticalSection( &service_cs
);
1897 /******************************************************************************
1898 * StartServiceCtrlDispatcherA (sechost.@)
1900 BOOL WINAPI DECLSPEC_HOTPATCH
StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA
*servent
)
1902 struct service_data
*info
;
1905 TRACE("%p\n", servent
);
1909 SetLastError( ERROR_SERVICE_ALREADY_RUNNING
);
1912 while (servent
[nb_services
].lpServiceName
) nb_services
++;
1915 SetLastError( ERROR_INVALID_PARAMETER
);
1919 services
= heap_alloc( nb_services
* sizeof(*services
) );
1921 for (i
= 0; i
< nb_services
; i
++)
1923 DWORD len
= MultiByteToWideChar( CP_ACP
, 0, servent
[i
].lpServiceName
, -1, NULL
, 0 );
1924 DWORD sz
= FIELD_OFFSET( struct service_data
, name
[len
] );
1925 info
= heap_alloc_zero( sz
);
1926 MultiByteToWideChar( CP_ACP
, 0, servent
[i
].lpServiceName
, -1, info
->name
, len
);
1927 info
->proc
.a
= servent
[i
].lpServiceProc
;
1928 info
->unicode
= FALSE
;
1932 return service_run_main_thread();
1935 /******************************************************************************
1936 * StartServiceCtrlDispatcherW (sechost.@)
1938 BOOL WINAPI DECLSPEC_HOTPATCH
StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW
*servent
)
1940 struct service_data
*info
;
1943 TRACE("%p\n", servent
);
1947 SetLastError( ERROR_SERVICE_ALREADY_RUNNING
);
1950 while (servent
[nb_services
].lpServiceName
) nb_services
++;
1953 SetLastError( ERROR_INVALID_PARAMETER
);
1957 services
= heap_alloc( nb_services
* sizeof(*services
) );
1959 for (i
= 0; i
< nb_services
; i
++)
1961 DWORD len
= wcslen( servent
[i
].lpServiceName
) + 1;
1962 DWORD sz
= FIELD_OFFSET( struct service_data
, name
[len
] );
1963 info
= heap_alloc_zero( sz
);
1964 wcscpy( info
->name
, servent
[i
].lpServiceName
);
1965 info
->proc
.w
= servent
[i
].lpServiceProc
;
1966 info
->unicode
= TRUE
;
1970 return service_run_main_thread();
1973 struct device_notification_details
1975 DWORD (CALLBACK
*cb
)(HANDLE handle
, DWORD flags
, DEV_BROADCAST_HDR
*header
);
1979 static HANDLE device_notify_thread
;
1980 static struct list device_notify_list
= LIST_INIT(device_notify_list
);
1982 struct device_notify_registration
1985 struct device_notification_details details
;
1988 static DWORD WINAPI
device_notify_proc( void *arg
)
1990 WCHAR endpoint
[] = L
"\\pipe\\wine_plugplay";
1991 WCHAR protseq
[] = L
"ncalrpc";
1992 RPC_WSTR binding_str
;
1993 DWORD err
= ERROR_SUCCESS
;
1994 struct device_notify_registration
*registration
;
1995 plugplay_rpc_handle handle
= NULL
;
2000 if ((err
= RpcStringBindingComposeW( NULL
, protseq
, NULL
, endpoint
, NULL
, &binding_str
)))
2002 ERR("RpcStringBindingCompose() failed, error %#x\n", err
);
2005 err
= RpcBindingFromStringBindingW( binding_str
, &plugplay_binding_handle
);
2006 RpcStringFreeW( &binding_str
);
2009 ERR("RpcBindingFromStringBinding() failed, error %#x\n", err
);
2015 handle
= plugplay_register_listener();
2017 __EXCEPT(rpc_filter
)
2019 err
= map_exception_code( GetExceptionCode() );
2025 ERR("failed to open RPC handle, error %u\n", err
);
2034 code
= plugplay_get_event( handle
, &buf
, &size
);
2035 err
= ERROR_SUCCESS
;
2037 __EXCEPT(rpc_filter
)
2039 err
= map_exception_code( GetExceptionCode() );
2045 ERR("failed to get event, error %u\n", err
);
2049 EnterCriticalSection( &service_cs
);
2050 LIST_FOR_EACH_ENTRY(registration
, &device_notify_list
, struct device_notify_registration
, entry
)
2052 registration
->details
.cb( registration
->details
.handle
, code
, (DEV_BROADCAST_HDR
*)buf
);
2054 LeaveCriticalSection(&service_cs
);
2055 MIDL_user_free(buf
);
2060 plugplay_unregister_listener( handle
);
2062 __EXCEPT(rpc_filter
)
2067 RpcBindingFree( &plugplay_binding_handle
);
2071 /******************************************************************************
2072 * I_ScRegisterDeviceNotification (sechost.@)
2074 HDEVNOTIFY WINAPI
I_ScRegisterDeviceNotification( struct device_notification_details
*details
,
2075 void *filter
, DWORD flags
)
2077 struct device_notify_registration
*registration
;
2079 TRACE("callback %p, handle %p, filter %p, flags %#x\n", details
->cb
, details
->handle
, filter
, flags
);
2081 if (filter
) FIXME("Notification filters are not yet implemented.\n");
2083 if (!(registration
= heap_alloc(sizeof(struct device_notify_registration
))))
2085 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
2089 registration
->details
= *details
;
2091 EnterCriticalSection( &service_cs
);
2092 list_add_tail( &device_notify_list
, ®istration
->entry
);
2094 if (!device_notify_thread
)
2095 device_notify_thread
= CreateThread( NULL
, 0, device_notify_proc
, NULL
, 0, NULL
);
2097 LeaveCriticalSection( &service_cs
);
2099 return registration
;
2102 /******************************************************************************
2103 * I_ScUnregisterDeviceNotification (sechost.@)
2105 BOOL WINAPI
I_ScUnregisterDeviceNotification( HDEVNOTIFY handle
)
2107 struct device_notify_registration
*registration
= handle
;
2109 TRACE("%p\n", handle
);
2114 EnterCriticalSection( &service_cs
);
2115 list_remove( ®istration
->entry
);
2116 LeaveCriticalSection(&service_cs
);
2117 heap_free( registration
);