localspl: Add unixname port extension.
[wine.git] / dlls / sechost / service.c
blobcb5e140b3cf84b9a344fd60158cdf1669d585f4a
1 /*
2 * Service control API
4 * Copyright 1995 Sven Verdoolaege
5 * Copyright 2005 Mike McCormack
6 * Copyright 2007 Rolf Kalbermatter
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #define NONAMELESSUNION
24 #include <stdarg.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winsvc.h"
28 #include "winternl.h"
29 #include "winuser.h"
30 #include "dbt.h"
32 #include "wine/debug.h"
33 #include "wine/exception.h"
34 #include "wine/heap.h"
35 #include "wine/list.h"
37 #include "svcctl.h"
38 #include "plugplay.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(service);
42 struct notify_data
44 SC_HANDLE service;
45 SC_RPC_NOTIFY_PARAMS params;
46 SERVICE_NOTIFY_STATUS_CHANGE_PARAMS_2 cparams;
47 SC_NOTIFY_RPC_HANDLE notify_handle;
48 SERVICE_NOTIFYW *notify_buffer;
49 HANDLE calling_thread, ready_evt;
50 struct list entry;
53 static struct list notify_list = LIST_INIT(notify_list);
55 static CRITICAL_SECTION service_cs;
56 static CRITICAL_SECTION_DEBUG service_cs_debug =
58 0, 0, &service_cs,
59 { &service_cs_debug.ProcessLocksList,
60 &service_cs_debug.ProcessLocksList },
61 0, 0, { (DWORD_PTR)(__FILE__ ": service_cs") }
63 static CRITICAL_SECTION service_cs = { &service_cs_debug, -1, 0, 0, 0, 0 };
65 struct service_data
67 LPHANDLER_FUNCTION_EX handler;
68 void *context;
69 HANDLE thread;
70 SC_HANDLE handle;
71 SC_HANDLE full_access_handle;
72 unsigned int unicode : 1;
73 union
75 LPSERVICE_MAIN_FUNCTIONA a;
76 LPSERVICE_MAIN_FUNCTIONW w;
77 } proc;
78 WCHAR *args;
79 WCHAR name[1];
82 struct dispatcher_data
84 SC_HANDLE manager;
85 HANDLE pipe;
88 static struct service_data **services;
89 static unsigned int nb_services;
90 static HANDLE service_event;
91 static BOOL stop_service;
93 static WCHAR *heap_strdupAtoW( const char *src )
95 WCHAR *dst = NULL;
96 if (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 );
101 return dst;
104 static WCHAR *heap_strdup_multi_AtoW( const char *src )
106 WCHAR *dst = NULL;
107 const char *p = src;
108 DWORD len;
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 );
117 return dst;
120 static inline DWORD multisz_size( const WCHAR *str )
122 const WCHAR *p = str;
124 if (!str) return 0;
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 )
137 heap_free(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;
157 default:
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;
167 RPC_STATUS status;
168 handle_t rpc_handle;
170 status = RpcStringBindingComposeW( NULL, transport, str, endpoint, NULL, &binding_str );
171 if (status != RPC_S_OK)
173 ERR("RpcStringBindingComposeW failed, error %ld\n", status);
174 return NULL;
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 %ld\n", status);
183 return NULL;
186 return rpc_handle;
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;
194 RPC_STATUS status;
195 handle_t rpc_handle;
197 status = RpcStringBindingComposeA( NULL, transport, str, endpoint, NULL, &binding_str );
198 if (status != RPC_S_OK)
200 ERR("RpcStringBindingComposeA failed, error %ld\n", status);
201 return NULL;
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 %ld\n", status);
210 return NULL;
213 return rpc_handle;
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 );
249 return !err;
252 /******************************************************************************
253 * OpenSCManagerA (sechost.@)
255 SC_HANDLE WINAPI DECLSPEC_HOTPATCH OpenSCManagerA( const char *machine, const char *database, DWORD access )
257 WCHAR *machineW, *databaseW;
258 SC_HANDLE ret;
260 machineW = heap_strdupAtoW( machine );
261 databaseW = heap_strdupAtoW( database );
262 ret = OpenSCManagerW( machineW, databaseW, access );
263 heap_free( databaseW );
264 heap_free( machineW );
265 return ret;
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;
274 DWORD err;
276 TRACE( "%s %s %#lx\n", debugstr_w(machine), debugstr_w(database), access );
278 __TRY
280 err = svcctl_OpenSCManagerW( machine, database, access, &handle );
282 __EXCEPT(rpc_filter)
284 err = map_exception_code( GetExceptionCode() );
286 __ENDTRY
288 if (!err) return handle;
289 SetLastError( err );
290 return NULL;
293 /******************************************************************************
294 * OpenServiceA (sechost.@)
296 SC_HANDLE WINAPI DECLSPEC_HOTPATCH OpenServiceA( SC_HANDLE manager, const char *name, DWORD access )
298 WCHAR *nameW;
299 SC_HANDLE ret;
301 TRACE( "%p %s %#lx\n", manager, debugstr_a(name), access );
303 nameW = heap_strdupAtoW( name );
304 ret = OpenServiceW( manager, nameW, access );
305 heap_free( nameW );
306 return ret;
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;
315 DWORD err;
317 TRACE( "%p %s %#lx\n", manager, debugstr_w(name), access );
319 if (!manager)
321 SetLastError( ERROR_INVALID_HANDLE );
322 return NULL;
325 __TRY
327 err = svcctl_OpenServiceW( manager, name, access, &handle );
329 __EXCEPT(rpc_filter)
331 err = map_exception_code( GetExceptionCode() );
333 __ENDTRY
335 if (!err) return handle;
336 SetLastError( err );
337 return 0;
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;
350 SC_HANDLE handle;
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 );
365 heap_free( nameW );
366 heap_free( display_nameW );
367 heap_free( pathW );
368 heap_free( groupW );
369 heap_free( dependenciesW );
370 heap_free( usernameW );
371 heap_free( passwordW );
373 return handle;
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;
386 DWORD err;
387 SIZE_T password_size = 0;
389 TRACE( "%p %s %s\n", manager, debugstr_w(name), debugstr_w(display_name) );
391 if (!manager)
393 SetLastError( ERROR_INVALID_HANDLE );
394 return 0;
397 if (password) password_size = (wcslen(password) + 1) * sizeof(WCHAR);
399 __TRY
401 BOOL is_wow64;
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 );
408 else
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 );
414 __EXCEPT(rpc_filter)
416 err = map_exception_code( GetExceptionCode() );
418 __ENDTRY
420 if (!err) return handle;
421 SetLastError( err );
422 return NULL;
425 /******************************************************************************
426 * DeleteService (sechost.@)
428 BOOL WINAPI DECLSPEC_HOTPATCH DeleteService( SC_HANDLE service )
430 DWORD err;
432 TRACE( "%p\n", service );
434 __TRY
436 err = svcctl_DeleteService( service );
438 __EXCEPT(rpc_filter)
440 err = map_exception_code( GetExceptionCode() );
442 __ENDTRY
444 return set_error( err );
447 /******************************************************************************
448 * CloseServiceHandle (sechost.@)
450 BOOL WINAPI DECLSPEC_HOTPATCH CloseServiceHandle( SC_HANDLE handle )
452 DWORD err;
454 TRACE( "%p\n", handle );
456 __TRY
458 err = svcctl_CloseServiceHandle( (SC_RPC_HANDLE *)&handle );
460 __EXCEPT(rpc_filter)
462 err = map_exception_code( GetExceptionCode() );
464 __ENDTRY
466 return set_error( err );
469 /******************************************************************************
470 * ChangeServiceConfig2A (sechost.@)
472 BOOL WINAPI DECLSPEC_HOTPATCH ChangeServiceConfig2A( SC_HANDLE service, DWORD level, void *info)
474 BOOL r = FALSE;
476 TRACE( "%p %ld %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 );
509 else
510 SetLastError( ERROR_INVALID_PARAMETER );
512 return r;
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;
521 DWORD err;
523 __TRY
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;
536 else
537 rpc_info.descr = info;
538 err = svcctl_ChangeServiceConfig2W( service, rpc_info );
540 __EXCEPT(rpc_filter)
542 err = map_exception_code( GetExceptionCode() );
544 __ENDTRY
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;
558 BOOL r;
560 TRACE( "%p %ld %ld %ld %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 );
574 heap_free( pathW );
575 heap_free( groupW );
576 heap_free( dependenciesW );
577 heap_free( usernameW );
578 heap_free( passwordW );
579 heap_free( display_nameW );
581 return r;
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 )
592 DWORD password_size;
593 DWORD err;
595 TRACE( "%p %ld %ld %ld %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;
601 __TRY
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 );
607 __EXCEPT(rpc_filter)
609 err = map_exception_code( GetExceptionCode() );
611 __ENDTRY
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 )
622 DWORD n;
623 char *p, *buffer;
624 BOOL ret;
625 QUERY_SERVICE_CONFIGW *configW;
627 TRACE( "%p %p %ld %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 );
632 if (!ret) goto done;
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);
646 ret = FALSE;
648 #define MAP_STR(str) \
649 do { \
650 if (configW->str) \
652 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
653 if (!sz) goto done; \
654 config->str = p; \
655 p += sz; \
656 n -= sz; \
658 } while (0)
660 MAP_STR( lpBinaryPathName );
661 MAP_STR( lpLoadOrderGroup );
662 MAP_STR( lpDependencies );
663 MAP_STR( lpServiceStartName );
664 MAP_STR( lpDisplayName );
665 #undef MAP_STR
667 *ret_size = p - (char *)config;
668 ret = TRUE;
670 done:
671 heap_free( buffer );
672 return ret;
675 static DWORD move_string_to_buffer(BYTE **buf, WCHAR **string_ptr)
677 DWORD cb;
679 if (!*string_ptr)
681 cb = sizeof(WCHAR);
682 memset(*buf, 0, cb);
684 else
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;
692 *buf += cb;
694 return cb;
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;
709 DWORD total;
710 DWORD err;
711 BYTE *bufpos;
713 TRACE( "%p %p %ld %p\n", service, ret_config, size, ret_size );
715 memset(&config, 0, sizeof(config));
717 __TRY
719 err = svcctl_QueryServiceConfigW( service, &config, size, ret_size );
721 __EXCEPT(rpc_filter)
723 err = map_exception_code( GetExceptionCode() );
725 __ENDTRY
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 );
737 *ret_size = total;
739 /* if there's not enough memory, return an error */
740 if (size < total)
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 );
748 return FALSE;
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 ) );
765 return TRUE;
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 %lu %p %lu %p\n", service, level, buffer, size, ret_size );
778 if (buffer && size)
779 bufferW = heap_alloc( size );
781 if (!QueryServiceConfig2W( service, level, bufferW, size, ret_size ))
783 heap_free( bufferW );
784 return FALSE;
787 switch (level)
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;
801 break;
802 case SERVICE_CONFIG_PRESHUTDOWN_INFO:
803 if (buffer && bufferW && *ret_size <= size)
804 memcpy(buffer, bufferW, *ret_size);
805 break;
806 default:
807 FIXME("conversion W->A not implemented for level %ld\n", level);
808 heap_free( bufferW );
809 return FALSE;
812 heap_free( bufferW );
813 return TRUE;
816 /******************************************************************************
817 * QueryServiceConfig2W (sechost.@)
819 BOOL WINAPI DECLSPEC_HOTPATCH QueryServiceConfig2W( SC_HANDLE service, DWORD level, BYTE *buffer,
820 DWORD size, DWORD *ret_size )
822 BYTE *bufptr;
823 DWORD err;
825 TRACE( "%p %lu %p %lu %p\n", service, level, buffer, size, ret_size );
827 if (!buffer && size)
829 SetLastError(ERROR_INVALID_ADDRESS);
830 return FALSE;
833 switch (level)
835 case SERVICE_CONFIG_DESCRIPTION:
836 if (!(bufptr = heap_alloc( size )))
838 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
839 return FALSE;
841 break;
843 case SERVICE_CONFIG_PRESHUTDOWN_INFO:
844 bufptr = buffer;
845 break;
847 default:
848 FIXME("Level %ld not implemented\n", level);
849 SetLastError(ERROR_INVALID_LEVEL);
850 return FALSE;
853 if (!ret_size)
855 if (level == SERVICE_CONFIG_DESCRIPTION) heap_free( bufptr );
856 SetLastError(ERROR_INVALID_ADDRESS);
857 return FALSE;
860 __TRY
862 err = svcctl_QueryServiceConfig2W( service, level, bufptr, size, ret_size );
864 __EXCEPT(rpc_filter)
866 err = map_exception_code( GetExceptionCode() );
868 __ENDTRY
870 switch (level)
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)
879 heap_free( bufptr );
880 SetLastError( err );
881 return FALSE;
884 /* adjust for potentially larger SERVICE_DESCRIPTIONW structure */
885 if (*ret_size == sizeof(*s))
886 *ret_size = sizeof(*desc);
887 else
888 *ret_size = *ret_size - FIELD_OFFSET(struct service_description, description) + sizeof(*desc);
890 if (size < *ret_size)
892 heap_free( bufptr );
893 SetLastError( ERROR_INSUFFICIENT_BUFFER );
894 return FALSE;
896 if (desc)
898 if (!s->size) desc->lpDescription = NULL;
899 else
901 desc->lpDescription = (WCHAR *)(desc + 1);
902 memcpy( desc->lpDescription, s->description, s->size );
905 heap_free( bufptr );
906 break;
908 case SERVICE_CONFIG_PRESHUTDOWN_INFO:
909 return set_error( err );
911 default:
912 break;
915 return TRUE;
918 /******************************************************************************
919 * GetServiceDisplayNameW (sechost.@)
921 BOOL WINAPI DECLSPEC_HOTPATCH GetServiceDisplayNameW( SC_HANDLE manager, const WCHAR *service,
922 WCHAR *display_name, DWORD *len )
924 DWORD err;
925 DWORD size;
926 WCHAR buffer[2];
928 TRACE( "%p %s %p %p\n", manager, debugstr_w(service), display_name, len );
930 if (!manager)
932 SetLastError( ERROR_INVALID_HANDLE );
933 return FALSE;
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. */
942 *len = 2;
945 /* RPC call takes size excluding nul-terminator, whereas *len
946 * includes the nul-terminator on input. */
947 size = *len - 1;
949 __TRY
951 err = svcctl_GetServiceDisplayNameW( manager, service, display_name, &size );
953 __EXCEPT(rpc_filter)
955 err = map_exception_code( GetExceptionCode() );
957 __ENDTRY
959 /* The value of *len excludes nul-terminator on output. */
960 if (err == ERROR_SUCCESS || err == ERROR_INSUFFICIENT_BUFFER)
961 *len = size;
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 )
971 DWORD err;
972 WCHAR buffer[2];
973 DWORD size;
975 TRACE( "%p %s %p %p\n", manager, debugstr_w(display_name), key_name, len );
977 if (!manager)
979 SetLastError( ERROR_INVALID_HANDLE );
980 return FALSE;
983 /* provide a buffer if the caller didn't */
984 if (!key_name || *len < 2)
986 key_name = buffer;
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.
990 *len = 2;
993 /* RPC call takes size excluding nul-terminator, whereas *len
994 * includes the nul-terminator on input. */
995 size = *len - 1;
997 __TRY
999 err = svcctl_GetServiceKeyNameW( manager, display_name, key_name, &size );
1001 __EXCEPT(rpc_filter)
1003 err = map_exception_code( GetExceptionCode() );
1005 __ENDTRY
1007 /* The value of *lpcchBuffer excludes nul-terminator on output. */
1008 if (err == ERROR_SUCCESS || err == ERROR_INSUFFICIENT_BUFFER)
1009 *len = size;
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;
1019 DWORD i;
1020 BOOL r;
1022 if (argc)
1023 argvW = heap_alloc( argc * sizeof(*argvW) );
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] );
1032 heap_free( argvW );
1033 return r;
1037 /******************************************************************************
1038 * StartServiceW (sechost.@)
1040 BOOL WINAPI DECLSPEC_HOTPATCH StartServiceW( SC_HANDLE service, DWORD argc, const WCHAR **argv )
1042 DWORD err;
1044 TRACE( "%p %lu %p\n", service, argc, argv );
1046 __TRY
1048 err = svcctl_StartServiceW( service, argc, argv );
1050 __EXCEPT(rpc_filter)
1052 err = map_exception_code( GetExceptionCode() );
1054 __ENDTRY
1056 return set_error( err );
1059 /******************************************************************************
1060 * ControlService (sechost.@)
1062 BOOL WINAPI DECLSPEC_HOTPATCH ControlService( SC_HANDLE service, DWORD control, SERVICE_STATUS *status )
1064 DWORD err;
1066 TRACE( "%p %ld %p\n", service, control, status );
1068 __TRY
1070 err = svcctl_ControlService( service, control, status );
1072 __EXCEPT(rpc_filter)
1074 err = map_exception_code( GetExceptionCode() );
1076 __ENDTRY
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;
1087 BOOL ret;
1088 DWORD size;
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) );
1098 return ret;
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 )
1107 DWORD err;
1109 TRACE( "%p %d %p %ld %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 );
1119 __TRY
1121 err = svcctl_QueryServiceStatusEx( service, level, buffer, size, ret_size );
1123 __EXCEPT(rpc_filter)
1125 err = map_exception_code( GetExceptionCode() );
1127 __ENDTRY
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;
1142 const WCHAR *str;
1143 BYTE *buf;
1145 TRACE( "%p %u 0x%lx 0x%lx %p %lu %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 );
1156 __TRY
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() );
1165 __ENDTRY
1167 *returned = 0;
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;
1172 heap_free( buf );
1173 SetLastError( err );
1174 return FALSE;
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);
1191 entry++;
1194 if (total_size > size)
1196 heap_free( buf );
1197 *needed = total_size;
1198 SetLastError( ERROR_MORE_DATA );
1199 return FALSE;
1202 offset = count * sizeof(*services);
1203 entry = (struct enum_service_status_process *)buf;
1204 for (i = 0; i < count; i++)
1206 DWORD str_size;
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 );
1211 offset += str_size;
1213 if (!entry->display_name) services[i].lpDisplayName = NULL;
1214 else
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 );
1220 offset += str_size;
1222 services[i].ServiceStatusProcess = entry->service_status_process;
1223 entry++;
1226 heap_free( buf );
1227 *needed = 0;
1228 *returned = count;
1229 return TRUE;
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%08lx %p 0x%08lx %p %p - stub\n", hService, dwServiceState,
1240 lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
1242 *lpServicesReturned = 0;
1243 return TRUE;
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;
1253 NTSTATUS status;
1254 ACL acl;
1256 FIXME( "%p %ld %p %lu %p - semi-stub\n", service, type, ret_descriptor, size, ret_size );
1258 if (type != DACL_SECURITY_INFORMATION)
1259 FIXME("information %ld 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 );
1267 *ret_size = 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 %ld %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
1280 return TRUE;
1283 static DWORD WINAPI notify_thread(void *user)
1285 DWORD err;
1286 struct notify_data *data = user;
1287 SC_RPC_NOTIFY_PARAMS_LIST *list = NULL;
1288 SERVICE_NOTIFY_STATUS_CHANGE_PARAMS_2 *cparams;
1289 BOOL dummy;
1291 SetThreadDescription(GetCurrentThread(), L"wine_sechost_notify_service_status");
1293 __TRY
1295 /* GetNotifyResults blocks until there is an event */
1296 err = svcctl_GetNotifyResults(data->notify_handle, &list);
1298 __EXCEPT(rpc_filter)
1300 err = map_exception_code(GetExceptionCode());
1302 __ENDTRY
1304 EnterCriticalSection( &service_cs );
1306 list_remove(&data->entry);
1308 LeaveCriticalSection( &service_cs );
1310 if (err == ERROR_SUCCESS && list)
1312 cparams = list->NotifyParamsArray[0].params;
1314 data->notify_buffer->dwNotificationStatus = cparams->dwNotificationStatus;
1315 memcpy(&data->notify_buffer->ServiceStatus, &cparams->ServiceStatus,
1316 sizeof(SERVICE_STATUS_PROCESS));
1317 data->notify_buffer->dwNotificationTriggered = cparams->dwNotificationTriggered;
1318 data->notify_buffer->pszServiceNames = NULL;
1320 QueueUserAPC((PAPCFUNC)data->notify_buffer->pfnNotifyCallback,
1321 data->calling_thread, (ULONG_PTR)data->notify_buffer);
1323 HeapFree(GetProcessHeap(), 0, list);
1325 else
1326 WARN("GetNotifyResults server call failed: %lu\n", err);
1329 __TRY
1331 err = svcctl_CloseNotifyHandle(&data->notify_handle, &dummy);
1333 __EXCEPT(rpc_filter)
1335 err = map_exception_code(GetExceptionCode());
1337 __ENDTRY
1339 if (err != ERROR_SUCCESS)
1340 WARN("CloseNotifyHandle server call failed: %lu\n", err);
1342 CloseHandle(data->calling_thread);
1343 HeapFree(GetProcessHeap(), 0, data);
1345 return 0;
1348 /******************************************************************************
1349 * NotifyServiceStatusChangeW (sechost.@)
1351 DWORD WINAPI DECLSPEC_HOTPATCH NotifyServiceStatusChangeW( SC_HANDLE service, DWORD mask,
1352 SERVICE_NOTIFYW *notify_buffer )
1354 DWORD err;
1355 BOOL b_dummy = FALSE;
1356 GUID g_dummy = {0};
1357 struct notify_data *data;
1359 TRACE( "%p 0x%lx %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: %lu\n", GetLastError());
1370 heap_free( data );
1371 return ERROR_NOT_ENOUGH_MEMORY;
1374 data->params.dwInfoLevel = 2;
1375 data->params.params = &data->cparams;
1377 data->cparams.dwNotifyMask = mask;
1379 EnterCriticalSection( &service_cs );
1381 __TRY
1383 err = svcctl_NotifyServiceStatusChange( service, data->params, &g_dummy,
1384 &g_dummy, &b_dummy, &data->notify_handle );
1386 __EXCEPT(rpc_filter)
1388 err = map_exception_code( GetExceptionCode() );
1390 __ENDTRY
1392 if (err != ERROR_SUCCESS)
1394 WARN("NotifyServiceStatusChange server call failed: %lu\n", err);
1395 LeaveCriticalSection( &service_cs );
1396 CloseHandle( data->calling_thread );
1397 CloseHandle( data->ready_evt );
1398 heap_free( data );
1399 return err;
1402 CloseHandle( CreateThread( NULL, 0, &notify_thread, data, 0, NULL ) );
1404 list_add_tail( &notify_list, &data->entry );
1406 LeaveCriticalSection( &service_cs );
1408 return ERROR_SUCCESS;
1411 /* thunk for calling the RegisterServiceCtrlHandler handler function */
1412 static DWORD WINAPI ctrl_handler_thunk( DWORD control, DWORD type, void *data, void *context )
1414 LPHANDLER_FUNCTION func = context;
1416 func( control );
1417 return ERROR_SUCCESS;
1420 /******************************************************************************
1421 * RegisterServiceCtrlHandlerA (sechost.@)
1423 SERVICE_STATUS_HANDLE WINAPI DECLSPEC_HOTPATCH RegisterServiceCtrlHandlerA(
1424 const char *name, LPHANDLER_FUNCTION handler )
1426 return RegisterServiceCtrlHandlerExA( name, ctrl_handler_thunk, handler );
1429 /******************************************************************************
1430 * RegisterServiceCtrlHandlerW (sechost.@)
1432 SERVICE_STATUS_HANDLE WINAPI DECLSPEC_HOTPATCH RegisterServiceCtrlHandlerW(
1433 const WCHAR *name, LPHANDLER_FUNCTION handler )
1435 return RegisterServiceCtrlHandlerExW( name, ctrl_handler_thunk, handler );
1438 /******************************************************************************
1439 * RegisterServiceCtrlHandlerExA (sechost.@)
1441 SERVICE_STATUS_HANDLE WINAPI DECLSPEC_HOTPATCH RegisterServiceCtrlHandlerExA(
1442 const char *name, LPHANDLER_FUNCTION_EX handler, void *context )
1444 WCHAR *nameW;
1445 SERVICE_STATUS_HANDLE ret;
1447 nameW = heap_strdupAtoW( name );
1448 ret = RegisterServiceCtrlHandlerExW( nameW, handler, context );
1449 heap_free( nameW );
1450 return ret;
1453 static struct service_data *find_service_by_name( const WCHAR *name )
1455 unsigned int i;
1457 if (nb_services == 1) /* only one service (FIXME: should depend on OWN_PROCESS etc.) */
1458 return services[0];
1459 for (i = 0; i < nb_services; i++)
1460 if (!wcsicmp( name, services[i]->name )) return services[i];
1461 return NULL;
1464 /******************************************************************************
1465 * RegisterServiceCtrlHandlerExW (sechost.@)
1467 SERVICE_STATUS_HANDLE WINAPI DECLSPEC_HOTPATCH RegisterServiceCtrlHandlerExW(
1468 const WCHAR *name, LPHANDLER_FUNCTION_EX handler, void *context )
1470 struct service_data *service;
1471 SC_HANDLE handle = 0;
1473 TRACE( "%s %p %p\n", debugstr_w(name), handler, context );
1475 EnterCriticalSection( &service_cs );
1476 if ((service = find_service_by_name( name )))
1478 service->handler = handler;
1479 service->context = context;
1480 handle = service->handle;
1482 LeaveCriticalSection( &service_cs );
1484 if (!handle) SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
1485 return (SERVICE_STATUS_HANDLE)handle;
1488 /******************************************************************************
1489 * SetServiceStatus (sechost.@)
1491 BOOL WINAPI DECLSPEC_HOTPATCH SetServiceStatus( SERVICE_STATUS_HANDLE service, SERVICE_STATUS *status )
1493 DWORD err;
1495 TRACE( "%p %#lx %#lx %#lx %#lx %#lx %#lx %#lx\n", service, status->dwServiceType,
1496 status->dwCurrentState, status->dwControlsAccepted, status->dwWin32ExitCode,
1497 status->dwServiceSpecificExitCode, status->dwCheckPoint, status->dwWaitHint );
1499 __TRY
1501 err = svcctl_SetServiceStatus( service, status );
1503 __EXCEPT(rpc_filter)
1505 err = map_exception_code( GetExceptionCode() );
1507 __ENDTRY
1509 if (!set_error( err ))
1510 return FALSE;
1512 if (status->dwCurrentState == SERVICE_STOPPED)
1514 unsigned int i, count = 0;
1515 EnterCriticalSection( &service_cs );
1516 for (i = 0; i < nb_services; i++)
1518 if (services[i]->handle == (SC_HANDLE)service) continue;
1519 if (services[i]->thread) count++;
1521 if (!count)
1523 stop_service = TRUE;
1524 SetEvent( service_event ); /* notify the main loop */
1526 LeaveCriticalSection( &service_cs );
1529 return TRUE;
1532 static WCHAR *service_get_pipe_name(void)
1534 static const WCHAR format[] = L"\\\\.\\pipe\\net\\NtControlPipe%u";
1535 WCHAR *name;
1536 DWORD len;
1537 HKEY service_current_key;
1538 DWORD service_current;
1539 LONG ret;
1540 DWORD type;
1542 ret = RegOpenKeyExW( HKEY_LOCAL_MACHINE,
1543 L"SYSTEM\\CurrentControlSet\\Control\\ServiceCurrent",
1544 0, KEY_QUERY_VALUE, &service_current_key );
1545 if (ret != ERROR_SUCCESS)
1546 return NULL;
1548 len = sizeof(service_current);
1549 ret = RegQueryValueExW( service_current_key, NULL, NULL, &type,
1550 (BYTE *)&service_current, &len );
1551 RegCloseKey(service_current_key);
1552 if (ret != ERROR_SUCCESS || type != REG_DWORD)
1553 return NULL;
1555 len = ARRAY_SIZE(format) + 10 /* strlenW("4294967295") */;
1556 name = heap_alloc(len * sizeof(WCHAR));
1557 if (!name)
1558 return NULL;
1560 swprintf( name, len, format, service_current );
1561 return name;
1564 static HANDLE service_open_pipe(void)
1566 WCHAR *pipe_name = service_get_pipe_name();
1567 HANDLE handle = INVALID_HANDLE_VALUE;
1571 handle = CreateFileW( pipe_name, GENERIC_READ|GENERIC_WRITE,
1572 0, NULL, OPEN_ALWAYS, 0, NULL );
1573 if (handle != INVALID_HANDLE_VALUE)
1574 break;
1575 if (GetLastError() != ERROR_PIPE_BUSY)
1576 break;
1577 } while (WaitNamedPipeW( pipe_name, NMPWAIT_USE_DEFAULT_WAIT ));
1578 heap_free(pipe_name);
1580 return handle;
1583 static DWORD WINAPI service_thread( void *arg )
1585 struct service_data *info = arg;
1586 WCHAR *str = info->args;
1587 DWORD argc = 0, len = 0;
1589 TRACE("%p\n", arg);
1590 SetThreadDescription(GetCurrentThread(), L"wine_sechost_service");
1592 while (str[len])
1594 len += wcslen( &str[len] ) + 1;
1595 argc++;
1597 len++;
1599 if (info->unicode)
1601 WCHAR **argv, *p;
1603 argv = heap_alloc( (argc+1)*sizeof(*argv) );
1604 for (argc = 0, p = str; *p; p += wcslen( p ) + 1)
1605 argv[argc++] = p;
1606 argv[argc] = NULL;
1608 info->proc.w( argc, argv );
1609 heap_free( argv );
1611 else
1613 char *strA, **argv, *p;
1614 DWORD lenA;
1616 lenA = WideCharToMultiByte( CP_ACP,0, str, len, NULL, 0, NULL, NULL );
1617 strA = heap_alloc(lenA);
1618 WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL);
1620 argv = heap_alloc( (argc+1)*sizeof(*argv) );
1621 for (argc = 0, p = strA; *p; p += strlen( p ) + 1)
1622 argv[argc++] = p;
1623 argv[argc] = NULL;
1625 info->proc.a( argc, argv );
1626 heap_free( argv );
1627 heap_free( strA );
1629 return 0;
1632 static DWORD service_handle_start( struct service_data *service, const void *data, DWORD data_size )
1634 DWORD count = data_size / sizeof(WCHAR);
1636 if (service->thread)
1638 WARN("service is not stopped\n");
1639 return ERROR_SERVICE_ALREADY_RUNNING;
1642 heap_free( service->args );
1643 service->args = heap_alloc( (count + 2) * sizeof(WCHAR) );
1644 if (count) memcpy( service->args, data, count * sizeof(WCHAR) );
1645 service->args[count++] = 0;
1646 service->args[count++] = 0;
1648 service->thread = CreateThread( NULL, 0, service_thread,
1649 service, 0, NULL );
1650 SetEvent( service_event ); /* notify the main loop */
1651 return 0;
1654 static DWORD service_handle_control( struct service_data *service, DWORD control, const void *data, DWORD data_size )
1656 DWORD ret = ERROR_INVALID_SERVICE_CONTROL;
1658 TRACE( "%s control %lu data %p data_size %lu\n", debugstr_w(service->name), control, data, data_size );
1660 if (control == SERVICE_CONTROL_START)
1661 ret = service_handle_start( service, data, data_size );
1662 else if (service->handler)
1663 ret = service->handler( control, 0, (void *)data, service->context );
1664 return ret;
1667 static DWORD WINAPI service_control_dispatcher( void *arg )
1669 struct dispatcher_data *disp = arg;
1671 /* dispatcher loop */
1672 while (1)
1674 struct service_data *service;
1675 service_start_info info;
1676 BYTE *data = NULL;
1677 WCHAR *name;
1678 BOOL r;
1679 DWORD data_size = 0, count, result;
1681 r = ReadFile( disp->pipe, &info, FIELD_OFFSET(service_start_info,data), &count, NULL );
1682 if (!r)
1684 if (GetLastError() != ERROR_BROKEN_PIPE)
1685 ERR( "pipe read failed error %lu\n", GetLastError() );
1686 break;
1688 if (count != FIELD_OFFSET(service_start_info,data))
1690 ERR( "partial pipe read %lu\n", count );
1691 break;
1693 if (count < info.total_size)
1695 data_size = info.total_size - FIELD_OFFSET(service_start_info,data);
1696 data = heap_alloc( data_size );
1697 r = ReadFile( disp->pipe, data, data_size, &count, NULL );
1698 if (!r)
1700 if (GetLastError() != ERROR_BROKEN_PIPE)
1701 ERR( "pipe read failed error %lu\n", GetLastError() );
1702 heap_free( data );
1703 break;
1705 if (count != data_size)
1707 ERR( "partial pipe read %lu/%lu\n", count, data_size );
1708 heap_free( data );
1709 break;
1713 EnterCriticalSection( &service_cs );
1715 /* validate service name */
1716 name = (WCHAR *)data;
1717 if (!info.name_size || data_size < info.name_size * sizeof(WCHAR) || name[info.name_size - 1])
1719 ERR( "got request without valid service name\n" );
1720 result = ERROR_INVALID_PARAMETER;
1721 goto done;
1724 if (info.magic != SERVICE_PROTOCOL_MAGIC)
1726 ERR( "received invalid request for service %s\n", debugstr_w(name) );
1727 result = ERROR_INVALID_PARAMETER;
1728 goto done;
1731 /* find the service */
1732 if (!(service = find_service_by_name( name )))
1734 FIXME( "got request for unknown service %s\n", debugstr_w(name) );
1735 result = ERROR_INVALID_PARAMETER;
1736 goto done;
1739 if (!service->handle)
1741 if (!(service->handle = OpenServiceW( disp->manager, name, SERVICE_SET_STATUS )) ||
1742 !(service->full_access_handle = OpenServiceW( disp->manager, name,
1743 GENERIC_READ|GENERIC_WRITE )))
1744 FIXME( "failed to open service %s\n", debugstr_w(name) );
1747 data_size -= info.name_size * sizeof(WCHAR);
1748 result = service_handle_control(service, info.control, data_size ?
1749 &data[info.name_size * sizeof(WCHAR)] : NULL, data_size);
1751 done:
1752 LeaveCriticalSection( &service_cs );
1753 WriteFile( disp->pipe, &result, sizeof(result), &count, NULL );
1754 heap_free( data );
1757 CloseHandle( disp->pipe );
1758 CloseServiceHandle( disp->manager );
1759 heap_free( disp );
1760 return 1;
1763 /* wait for services which accept this type of message to become STOPPED */
1764 static void handle_shutdown_msg(DWORD msg, DWORD accept)
1766 SERVICE_STATUS st;
1767 SERVICE_PRESHUTDOWN_INFO spi;
1768 DWORD i, n = 0, sz, timeout = 2000;
1769 ULONGLONG stop_time;
1770 BOOL res, done = TRUE;
1771 SC_HANDLE *wait_handles = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SC_HANDLE) * nb_services );
1773 EnterCriticalSection( &service_cs );
1774 for (i = 0; i < nb_services; i++)
1776 res = QueryServiceStatus( services[i]->full_access_handle, &st );
1777 if (!res || st.dwCurrentState == SERVICE_STOPPED || !(st.dwControlsAccepted & accept))
1778 continue;
1780 done = FALSE;
1782 if (accept == SERVICE_ACCEPT_PRESHUTDOWN)
1784 res = QueryServiceConfig2W( services[i]->full_access_handle, SERVICE_CONFIG_PRESHUTDOWN_INFO,
1785 (BYTE *)&spi, sizeof(spi), &sz );
1786 if (res)
1788 FIXME( "service should be able to delay shutdown\n" );
1789 timeout = max( spi.dwPreshutdownTimeout, timeout );
1793 service_handle_control( services[i], msg, NULL, 0 );
1794 wait_handles[n++] = services[i]->full_access_handle;
1796 LeaveCriticalSection( &service_cs );
1798 /* FIXME: these timeouts should be more generous, but we can't currently delay prefix shutdown */
1799 timeout = min( timeout, 3000 );
1800 stop_time = GetTickCount64() + timeout;
1802 while (!done && GetTickCount64() < stop_time)
1804 done = TRUE;
1805 for (i = 0; i < n; i++)
1807 res = QueryServiceStatus( wait_handles[i], &st );
1808 if (!res || st.dwCurrentState == SERVICE_STOPPED)
1809 continue;
1811 done = FALSE;
1812 Sleep( 100 );
1813 break;
1817 HeapFree( GetProcessHeap(), 0, wait_handles );
1820 static BOOL service_run_main_thread(void)
1822 DWORD i, n, ret;
1823 HANDLE wait_handles[MAXIMUM_WAIT_OBJECTS];
1824 UINT wait_services[MAXIMUM_WAIT_OBJECTS];
1825 struct dispatcher_data *disp = heap_alloc( sizeof(*disp) );
1827 disp->manager = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
1828 if (!disp->manager)
1830 ERR("failed to open service manager error %lu\n", GetLastError());
1831 heap_free( disp );
1832 return FALSE;
1835 disp->pipe = service_open_pipe();
1836 if (disp->pipe == INVALID_HANDLE_VALUE)
1838 WARN("failed to create control pipe error %lu\n", GetLastError());
1839 CloseServiceHandle( disp->manager );
1840 heap_free( disp );
1841 SetLastError( ERROR_FAILED_SERVICE_CONTROLLER_CONNECT );
1842 return FALSE;
1845 service_event = CreateEventW( NULL, FALSE, FALSE, NULL );
1846 stop_service = FALSE;
1848 /* FIXME: service_control_dispatcher should be merged into the main thread */
1849 NtSetInformationProcess( GetCurrentProcess(), ProcessWineMakeProcessSystem,
1850 &wait_handles[0], sizeof(HANDLE *) );
1851 wait_handles[1] = CreateThread( NULL, 0, service_control_dispatcher, disp, 0, NULL );
1852 wait_handles[2] = service_event;
1854 TRACE("Starting %d services running as process %ld\n",
1855 nb_services, GetCurrentProcessId());
1857 /* wait for all the threads to pack up and exit */
1858 while (!stop_service)
1860 EnterCriticalSection( &service_cs );
1861 for (i = 0, n = 3; i < nb_services && n < MAXIMUM_WAIT_OBJECTS; i++)
1863 if (!services[i]->thread) continue;
1864 wait_services[n] = i;
1865 wait_handles[n++] = services[i]->thread;
1867 LeaveCriticalSection( &service_cs );
1869 ret = WaitForMultipleObjects( n, wait_handles, FALSE, INFINITE );
1870 if (!ret) /* system process event */
1872 handle_shutdown_msg(SERVICE_CONTROL_PRESHUTDOWN, SERVICE_ACCEPT_PRESHUTDOWN);
1873 handle_shutdown_msg(SERVICE_CONTROL_SHUTDOWN, SERVICE_ACCEPT_SHUTDOWN);
1874 ExitProcess(0);
1876 else if (ret == 1)
1878 TRACE( "control dispatcher exited, shutting down\n" );
1879 /* FIXME: we should maybe send a shutdown control to running services */
1880 ExitProcess(0);
1882 else if (ret == 2)
1884 continue; /* rebuild the list */
1886 else if (ret < n)
1888 i = wait_services[ret];
1889 EnterCriticalSection( &service_cs );
1890 CloseHandle( services[i]->thread );
1891 services[i]->thread = NULL;
1892 LeaveCriticalSection( &service_cs );
1894 else return FALSE;
1897 return TRUE;
1900 /******************************************************************************
1901 * StartServiceCtrlDispatcherA (sechost.@)
1903 BOOL WINAPI DECLSPEC_HOTPATCH StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *servent )
1905 struct service_data *info;
1906 unsigned int i;
1908 TRACE("%p\n", servent);
1910 if (nb_services)
1912 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
1913 return FALSE;
1915 while (servent[nb_services].lpServiceName) nb_services++;
1916 if (!nb_services)
1918 SetLastError( ERROR_INVALID_PARAMETER );
1919 return FALSE;
1922 services = heap_alloc( nb_services * sizeof(*services) );
1924 for (i = 0; i < nb_services; i++)
1926 DWORD len = MultiByteToWideChar( CP_ACP, 0, servent[i].lpServiceName, -1, NULL, 0 );
1927 DWORD sz = FIELD_OFFSET( struct service_data, name[len] );
1928 info = heap_alloc_zero( sz );
1929 MultiByteToWideChar( CP_ACP, 0, servent[i].lpServiceName, -1, info->name, len );
1930 info->proc.a = servent[i].lpServiceProc;
1931 info->unicode = FALSE;
1932 services[i] = info;
1935 return service_run_main_thread();
1938 /******************************************************************************
1939 * StartServiceCtrlDispatcherW (sechost.@)
1941 BOOL WINAPI DECLSPEC_HOTPATCH StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW *servent )
1943 struct service_data *info;
1944 unsigned int i;
1946 TRACE("%p\n", servent);
1948 if (nb_services)
1950 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
1951 return FALSE;
1953 while (servent[nb_services].lpServiceName) nb_services++;
1954 if (!nb_services)
1956 SetLastError( ERROR_INVALID_PARAMETER );
1957 return FALSE;
1960 services = heap_alloc( nb_services * sizeof(*services) );
1962 for (i = 0; i < nb_services; i++)
1964 DWORD len = wcslen( servent[i].lpServiceName ) + 1;
1965 DWORD sz = FIELD_OFFSET( struct service_data, name[len] );
1966 info = heap_alloc_zero( sz );
1967 wcscpy( info->name, servent[i].lpServiceName );
1968 info->proc.w = servent[i].lpServiceProc;
1969 info->unicode = TRUE;
1970 services[i] = info;
1973 return service_run_main_thread();
1976 struct device_notification_details
1978 DWORD (CALLBACK *cb)(HANDLE handle, DWORD flags, DEV_BROADCAST_HDR *header);
1979 HANDLE handle;
1980 union
1982 DEV_BROADCAST_HDR header;
1983 DEV_BROADCAST_DEVICEINTERFACE_W iface;
1984 } filter;
1987 static HANDLE device_notify_thread;
1988 static struct list device_notify_list = LIST_INIT(device_notify_list);
1990 struct device_notify_registration
1992 struct list entry;
1993 struct device_notification_details details;
1996 static BOOL notification_filter_matches( DEV_BROADCAST_HDR *filter, DEV_BROADCAST_HDR *event )
1998 if (!filter->dbch_devicetype) return TRUE;
1999 if (filter->dbch_devicetype != event->dbch_devicetype) return FALSE;
2001 if (filter->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
2003 DEV_BROADCAST_DEVICEINTERFACE_W *filter_iface = (DEV_BROADCAST_DEVICEINTERFACE_W *)filter;
2004 DEV_BROADCAST_DEVICEINTERFACE_W *event_iface = (DEV_BROADCAST_DEVICEINTERFACE_W *)event;
2005 if (filter_iface->dbcc_size == offsetof(DEV_BROADCAST_DEVICEINTERFACE_W, dbcc_classguid)) return TRUE;
2006 return IsEqualGUID( &filter_iface->dbcc_classguid, &event_iface->dbcc_classguid );
2009 FIXME( "Filter dbch_devicetype %lu not implemented\n", filter->dbch_devicetype );
2010 return TRUE;
2013 static DWORD WINAPI device_notify_proc( void *arg )
2015 WCHAR endpoint[] = L"\\pipe\\wine_plugplay";
2016 WCHAR protseq[] = L"ncacn_np";
2017 RPC_WSTR binding_str;
2018 DWORD err = ERROR_SUCCESS;
2019 struct device_notify_registration *registration;
2020 struct device_notification_details *details_copy;
2021 unsigned int details_copy_nelems, details_copy_size;
2022 plugplay_rpc_handle handle = NULL;
2023 DWORD code = 0;
2024 unsigned int i, size;
2025 BYTE *buf;
2027 SetThreadDescription( GetCurrentThread(), L"wine_sechost_device_notify" );
2029 if ((err = RpcStringBindingComposeW( NULL, protseq, NULL, endpoint, NULL, &binding_str )))
2031 ERR("RpcStringBindingCompose() failed, error %#lx\n", err);
2032 return err;
2034 err = RpcBindingFromStringBindingW( binding_str, &plugplay_binding_handle );
2035 RpcStringFreeW( &binding_str );
2036 if (err)
2038 ERR("RpcBindingFromStringBinding() failed, error %#lx\n", err);
2039 return err;
2042 __TRY
2044 handle = plugplay_register_listener();
2046 __EXCEPT(rpc_filter)
2048 err = map_exception_code( GetExceptionCode() );
2050 __ENDTRY
2052 if (!handle)
2054 ERR("failed to open RPC handle, error %lu\n", err);
2055 return 1;
2058 details_copy_size = 8;
2059 details_copy = heap_alloc( details_copy_size * sizeof(*details_copy) );
2061 for (;;)
2063 buf = NULL;
2064 __TRY
2066 code = plugplay_get_event( handle, &buf, &size );
2067 err = ERROR_SUCCESS;
2069 __EXCEPT(rpc_filter)
2071 err = map_exception_code( GetExceptionCode() );
2073 __ENDTRY
2075 if (err)
2077 ERR("failed to get event, error %lu\n", err);
2078 break;
2081 /* Make a copy to avoid a hang if a callback tries to register or unregister for notifications. */
2082 i = 0;
2083 details_copy_nelems = 0;
2084 EnterCriticalSection( &service_cs );
2085 LIST_FOR_EACH_ENTRY(registration, &device_notify_list, struct device_notify_registration, entry)
2087 details_copy[i++] = registration->details;
2088 details_copy_nelems++;
2089 if (i == details_copy_size)
2091 details_copy_size *= 2;
2092 details_copy = heap_realloc( details_copy, details_copy_size * sizeof(*details_copy) );
2095 LeaveCriticalSection(&service_cs);
2097 for (i = 0; i < details_copy_nelems; i++)
2099 if (!notification_filter_matches( &details_copy[i].filter.header, (DEV_BROADCAST_HDR *)buf )) continue;
2100 details_copy[i].cb( details_copy[i].handle, code, (DEV_BROADCAST_HDR *)buf );
2102 MIDL_user_free(buf);
2105 heap_free( details_copy );
2107 __TRY
2109 plugplay_unregister_listener( handle );
2111 __EXCEPT(rpc_filter)
2114 __ENDTRY
2116 RpcBindingFree( &plugplay_binding_handle );
2117 return 0;
2120 /******************************************************************************
2121 * I_ScRegisterDeviceNotification (sechost.@)
2123 HDEVNOTIFY WINAPI I_ScRegisterDeviceNotification( struct device_notification_details *details,
2124 void *filter, DWORD flags )
2126 struct device_notify_registration *registration;
2128 TRACE("callback %p, handle %p, filter %p, flags %#lx\n", details->cb, details->handle, filter, flags);
2130 if (!(registration = heap_alloc(sizeof(struct device_notify_registration))))
2132 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2133 return NULL;
2136 registration->details = *details;
2138 EnterCriticalSection( &service_cs );
2139 list_add_tail( &device_notify_list, &registration->entry );
2141 if (!device_notify_thread)
2142 device_notify_thread = CreateThread( NULL, 0, device_notify_proc, NULL, 0, NULL );
2144 LeaveCriticalSection( &service_cs );
2146 return registration;
2149 /******************************************************************************
2150 * I_ScUnregisterDeviceNotification (sechost.@)
2152 BOOL WINAPI I_ScUnregisterDeviceNotification( HDEVNOTIFY handle )
2154 struct device_notify_registration *registration = handle;
2156 TRACE("%p\n", handle);
2158 if (!handle)
2159 return FALSE;
2161 EnterCriticalSection( &service_cs );
2162 list_remove( &registration->entry );
2163 LeaveCriticalSection(&service_cs);
2164 heap_free( registration );
2165 return TRUE;