2 * Win32 advapi functions
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
33 #include "wine/unicode.h"
34 #include "wine/debug.h"
38 #include "wine/list.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(advapi
);
42 static const WCHAR szServiceManagerKey
[] = { 'S','y','s','t','e','m','\\',
43 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
44 'S','e','r','v','i','c','e','s',0 };
45 static const WCHAR szSCMLock
[] = {'A','D','V','A','P','I','_','S','C','M',
48 static const GENERIC_MAPPING scm_generic
= {
49 (STANDARD_RIGHTS_READ
| SC_MANAGER_ENUMERATE_SERVICE
| SC_MANAGER_QUERY_LOCK_STATUS
),
50 (STANDARD_RIGHTS_WRITE
| SC_MANAGER_CREATE_SERVICE
| SC_MANAGER_MODIFY_BOOT_CONFIG
),
51 (STANDARD_RIGHTS_EXECUTE
| SC_MANAGER_CONNECT
| SC_MANAGER_LOCK
),
55 static const GENERIC_MAPPING svc_generic
= {
56 (STANDARD_RIGHTS_READ
| SERVICE_QUERY_CONFIG
| SERVICE_QUERY_STATUS
| SERVICE_INTERROGATE
| SERVICE_ENUMERATE_DEPENDENTS
),
57 (STANDARD_RIGHTS_WRITE
| SERVICE_CHANGE_CONFIG
),
58 (STANDARD_RIGHTS_EXECUTE
| SERVICE_START
| SERVICE_STOP
| SERVICE_PAUSE_CONTINUE
| SERVICE_USER_DEFINED_CONTROL
),
62 typedef struct service_start_info_t
69 #define WINESERV_STARTINFO 1
70 #define WINESERV_GETSTATUS 2
71 #define WINESERV_SENDCONTROL 3
72 #define WINESERV_SETPID 4
74 typedef struct service_data_t
78 LPHANDLER_FUNCTION handler
;
79 LPHANDLER_FUNCTION_EX handler_ex
;
82 SERVICE_STATUS_PROCESS status
;
85 BOOL extended
: 1; /* uses handler_ex instead of handler? */
87 LPSERVICE_MAIN_FUNCTIONA a
;
88 LPSERVICE_MAIN_FUNCTIONW w
;
94 static CRITICAL_SECTION service_cs
;
95 static CRITICAL_SECTION_DEBUG service_cs_debug
=
98 { &service_cs_debug
.ProcessLocksList
,
99 &service_cs_debug
.ProcessLocksList
},
100 0, 0, { (DWORD_PTR
)(__FILE__
": service_cs") }
102 static CRITICAL_SECTION service_cs
= { &service_cs_debug
, -1, 0, 0, 0, 0 };
104 static struct list service_list
= LIST_INIT(service_list
);
106 extern HANDLE
__wine_make_process_system(void);
108 /******************************************************************************
112 #define MAX_SERVICE_NAME 256
114 typedef enum { SC_HTYPE_MANAGER
, SC_HTYPE_SERVICE
} SC_HANDLE_TYPE
;
117 typedef VOID (*sc_handle_destructor
)(struct sc_handle
*);
121 SC_HANDLE_TYPE htype
;
123 sc_handle_destructor destroy
;
126 struct sc_manager
/* service control manager handle */
128 struct sc_handle hdr
;
129 HKEY hkey
; /* handle to services database in the registry */
133 struct sc_service
/* service handle */
135 struct sc_handle hdr
;
136 HKEY hkey
; /* handle to service entry in the registry (under hkey) */
138 struct sc_manager
*scm
; /* pointer to SCM handle */
142 static void *sc_handle_alloc(SC_HANDLE_TYPE htype
, DWORD size
,
143 sc_handle_destructor destroy
)
145 struct sc_handle
*hdr
;
147 hdr
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
152 hdr
->destroy
= destroy
;
154 TRACE("sc_handle type=%d -> %p\n", htype
, hdr
);
158 static void *sc_handle_get_handle_data(SC_HANDLE handle
, DWORD htype
)
160 struct sc_handle
*hdr
= (struct sc_handle
*) handle
;
164 if (hdr
->htype
!= htype
)
169 static void sc_handle_free(struct sc_handle
* hdr
)
173 if (--hdr
->ref_count
)
176 HeapFree(GetProcessHeap(), 0, hdr
);
179 static void sc_handle_destroy_manager(struct sc_handle
*handle
)
181 struct sc_manager
*mgr
= (struct sc_manager
*) handle
;
183 TRACE("destroying SC Manager %p\n", mgr
);
185 RegCloseKey(mgr
->hkey
);
188 static void sc_handle_destroy_service(struct sc_handle
*handle
)
190 struct sc_service
*svc
= (struct sc_service
*) handle
;
192 TRACE("destroying service %p\n", svc
);
194 RegCloseKey(svc
->hkey
);
196 sc_handle_free(&svc
->scm
->hdr
);
200 /******************************************************************************
201 * String management functions
203 static inline LPWSTR
SERV_dup( LPCSTR str
)
210 len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
211 wstr
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof (WCHAR
) );
212 MultiByteToWideChar( CP_ACP
, 0, str
, -1, wstr
, len
);
216 static inline LPWSTR
SERV_dupmulti(LPCSTR str
)
224 len
+= MultiByteToWideChar( CP_ACP
, 0, &str
[n
], -1, NULL
, 0 );
225 n
+= (strlen( &str
[n
] ) + 1);
230 wstr
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof (WCHAR
) );
231 MultiByteToWideChar( CP_ACP
, 0, str
, n
, wstr
, len
);
235 static inline VOID
SERV_free( LPWSTR wstr
)
237 HeapFree( GetProcessHeap(), 0, wstr
);
240 /******************************************************************************
241 * registry access functions and data
243 static const WCHAR szDisplayName
[] = {
244 'D','i','s','p','l','a','y','N','a','m','e', 0 };
245 static const WCHAR szType
[] = {'T','y','p','e',0};
246 static const WCHAR szStart
[] = {'S','t','a','r','t',0};
247 static const WCHAR szError
[] = {
248 'E','r','r','o','r','C','o','n','t','r','o','l', 0};
249 static const WCHAR szImagePath
[] = {'I','m','a','g','e','P','a','t','h',0};
250 static const WCHAR szGroup
[] = {'G','r','o','u','p',0};
251 static const WCHAR szDependencies
[] = {
252 'D','e','p','e','n','d','e','n','c','i','e','s',0};
253 static const WCHAR szDependOnService
[] = {
254 'D','e','p','e','n','d','O','n','S','e','r','v','i','c','e',0};
255 static const WCHAR szObjectName
[] = {
256 'O','b','j','e','c','t','N','a','m','e',0};
257 static const WCHAR szTag
[] = {
267 static inline void service_set_value( struct reg_value
*val
,
268 DWORD type
, LPCWSTR name
, LPCVOID data
, DWORD size
)
276 static inline void service_set_dword( struct reg_value
*val
,
277 LPCWSTR name
, const DWORD
*data
)
279 service_set_value( val
, REG_DWORD
, name
, data
, sizeof (DWORD
));
282 static inline void service_set_string( struct reg_value
*val
,
283 LPCWSTR name
, LPCWSTR string
)
285 DWORD len
= (lstrlenW(string
)+1) * sizeof (WCHAR
);
286 service_set_value( val
, REG_SZ
, name
, string
, len
);
289 static inline void service_set_multi_string( struct reg_value
*val
,
290 LPCWSTR name
, LPCWSTR string
)
294 /* determine the length of a double null terminated multi string */
296 len
+= (lstrlenW( &string
[ len
] )+1);
297 } while ( string
[ len
++ ] );
299 len
*= sizeof (WCHAR
);
300 service_set_value( val
, REG_MULTI_SZ
, name
, string
, len
);
303 static inline LONG
service_write_values( HKEY hKey
,
304 const struct reg_value
*val
, int n
)
306 LONG r
= ERROR_SUCCESS
;
311 r
= RegSetValueExW(hKey
, val
[i
].name
, 0, val
[i
].type
,
312 (const BYTE
*)val
[i
].data
, val
[i
].size
);
313 if( r
!= ERROR_SUCCESS
)
319 /******************************************************************************
320 * Service IPC functions
322 static LPWSTR
service_get_pipe_name(LPCWSTR service
)
324 static const WCHAR prefix
[] = { '\\','\\','.','\\','p','i','p','e','\\',
325 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
329 len
= sizeof prefix
+ strlenW(service
)*sizeof(WCHAR
);
330 name
= HeapAlloc(GetProcessHeap(), 0, len
);
331 strcpyW(name
, prefix
);
332 strcatW(name
, service
);
336 static HANDLE
service_open_pipe(LPCWSTR service
)
338 LPWSTR szPipe
= service_get_pipe_name( service
);
339 HANDLE handle
= INVALID_HANDLE_VALUE
;
342 handle
= CreateFileW(szPipe
, GENERIC_READ
|GENERIC_WRITE
,
343 0, NULL
, OPEN_ALWAYS
, 0, NULL
);
344 if (handle
!= INVALID_HANDLE_VALUE
)
346 if (GetLastError() != ERROR_PIPE_BUSY
)
348 } while (WaitNamedPipeW(szPipe
, NMPWAIT_WAIT_FOREVER
));
354 /******************************************************************************
355 * service_get_event_handle
357 static HANDLE
service_get_event_handle(LPCWSTR service
)
359 static const WCHAR prefix
[] = {
360 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
365 len
= sizeof prefix
+ strlenW(service
)*sizeof(WCHAR
);
366 name
= HeapAlloc(GetProcessHeap(), 0, len
);
367 strcpyW(name
, prefix
);
368 strcatW(name
, service
);
369 handle
= CreateEventW(NULL
, TRUE
, FALSE
, name
);
374 /******************************************************************************
377 * Call into the main service routine provided by StartServiceCtrlDispatcher.
379 static DWORD WINAPI
service_thread(LPVOID arg
)
381 service_data
*info
= arg
;
382 LPWSTR str
= info
->args
;
383 DWORD argc
= 0, len
= 0;
389 len
+= strlenW(&str
[len
]) + 1;
396 info
->proc
.w(0, NULL
);
398 info
->proc
.a(0, NULL
);
406 argv
= HeapAlloc(GetProcessHeap(), 0, (argc
+1)*sizeof(LPWSTR
));
407 for (argc
=0, p
=str
; *p
; p
+= strlenW(p
) + 1)
411 info
->proc
.w(argc
, argv
);
412 HeapFree(GetProcessHeap(), 0, argv
);
416 LPSTR strA
, *argv
, p
;
419 lenA
= WideCharToMultiByte(CP_ACP
,0, str
, len
, NULL
, 0, NULL
, NULL
);
420 strA
= HeapAlloc(GetProcessHeap(), 0, lenA
);
421 WideCharToMultiByte(CP_ACP
,0, str
, len
, strA
, lenA
, NULL
, NULL
);
423 argv
= HeapAlloc(GetProcessHeap(), 0, (argc
+1)*sizeof(LPSTR
));
424 for (argc
=0, p
=strA
; *p
; p
+= strlen(p
) + 1)
428 info
->proc
.a(argc
, argv
);
429 HeapFree(GetProcessHeap(), 0, argv
);
430 HeapFree(GetProcessHeap(), 0, strA
);
435 /******************************************************************************
436 * service_handle_start
438 static BOOL
service_handle_start(HANDLE pipe
, service_data
*service
, DWORD count
)
440 DWORD read
= 0, result
= 0;
444 TRACE("%p %p %d\n", pipe
, service
, count
);
446 args
= HeapAlloc(GetProcessHeap(), 0, count
*sizeof(WCHAR
));
447 r
= ReadFile(pipe
, args
, count
*sizeof(WCHAR
), &read
, NULL
);
448 if (!r
|| count
!=read
/sizeof(WCHAR
) || args
[count
-1])
450 ERR("pipe read failed r = %d count = %d read = %d args[n-1]=%s\n",
451 r
, count
, read
, debugstr_wn(args
, count
));
457 ERR("service is not stopped\n");
461 SERV_free(service
->args
);
462 service
->args
= args
;
464 service
->thread
= CreateThread( NULL
, 0, service_thread
,
468 HeapFree(GetProcessHeap(), 0, args
);
469 WriteFile( pipe
, &result
, sizeof result
, &read
, NULL
);
474 /******************************************************************************
475 * service_send_start_message
477 static BOOL
service_send_start_message(HANDLE pipe
, LPCWSTR
*argv
, DWORD argc
)
479 DWORD i
, len
, count
, result
;
480 service_start_info
*ssi
;
484 TRACE("%p %p %d\n", pipe
, argv
, argc
);
486 /* calculate how much space do we need to send the startup info */
488 for (i
=0; i
<argc
; i
++)
489 len
+= strlenW(argv
[i
])+1;
491 ssi
= HeapAlloc(GetProcessHeap(),0,sizeof *ssi
+ (len
-1)*sizeof(WCHAR
));
492 ssi
->cmd
= WINESERV_STARTINFO
;
495 /* copy service args into a single buffer*/
497 for (i
=0; i
<argc
; i
++)
504 r
= WriteFile(pipe
, ssi
, sizeof *ssi
+ len
*sizeof(WCHAR
), &count
, NULL
);
506 r
= ReadFile(pipe
, &result
, sizeof result
, &count
, NULL
);
508 HeapFree(GetProcessHeap(),0,ssi
);
513 /******************************************************************************
514 * service_handle_get_status
516 static BOOL
service_handle_get_status(HANDLE pipe
, const service_data
*service
)
520 return WriteFile(pipe
, &service
->status
,
521 sizeof service
->status
, &count
, NULL
);
524 /******************************************************************************
527 static BOOL
service_get_status(HANDLE pipe
, LPSERVICE_STATUS_PROCESS status
)
529 DWORD cmd
[2], count
= 0;
532 cmd
[0] = WINESERV_GETSTATUS
;
534 r
= WriteFile( pipe
, cmd
, sizeof cmd
, &count
, NULL
);
535 if (!r
|| count
!= sizeof cmd
)
537 ERR("service protocol error - failed to write pipe!\n");
540 r
= ReadFile( pipe
, status
, sizeof *status
, &count
, NULL
);
541 if (!r
|| count
!= sizeof *status
)
542 ERR("service protocol error - failed to read pipe "
543 "r = %d count = %d!\n", r
, count
);
547 /******************************************************************************
548 * service_handle_set_processID
550 static BOOL
service_handle_set_processID(HANDLE pipe
, service_data
*service
, DWORD dwProcessId
)
552 DWORD count
, ret
= ERROR_SUCCESS
;
554 TRACE("received control %d\n", dwProcessId
);
555 service
->status
.dwProcessId
= dwProcessId
;
556 return WriteFile(pipe
, &ret
, sizeof ret
, &count
, NULL
);
559 /******************************************************************************
560 * service_set_processID
562 static BOOL
service_set_processID(HANDLE pipe
, DWORD dwprocessId
, LPDWORD dwResult
)
564 DWORD cmd
[2], count
= 0;
567 cmd
[0] = WINESERV_SETPID
;
568 cmd
[1] = dwprocessId
;
569 r
= WriteFile( pipe
, cmd
, sizeof cmd
, &count
, NULL
);
570 if (!r
|| count
!= sizeof cmd
)
572 ERR("service protocol error - failed to write pipe!\n");
575 r
= ReadFile( pipe
, dwResult
, sizeof *dwResult
, &count
, NULL
);
576 if (!r
|| count
!= sizeof *dwResult
)
577 ERR("service protocol error - failed to read pipe "
578 "r = %d count = %d!\n", r
, count
);
582 /******************************************************************************
583 * service_send_control
585 static BOOL
service_send_control(HANDLE pipe
, DWORD dwControl
, DWORD
*result
)
587 DWORD cmd
[2], count
= 0;
590 cmd
[0] = WINESERV_SENDCONTROL
;
592 r
= WriteFile(pipe
, cmd
, sizeof cmd
, &count
, NULL
);
593 if (!r
|| count
!= sizeof cmd
)
595 ERR("service protocol error - failed to write pipe!\n");
598 r
= ReadFile(pipe
, result
, sizeof *result
, &count
, NULL
);
599 if (!r
|| count
!= sizeof *result
)
600 ERR("service protocol error - failed to read pipe "
601 "r = %d count = %d!\n", r
, count
);
605 /******************************************************************************
606 * service_accepts_control
608 static BOOL
service_accepts_control(const service_data
*service
, DWORD dwControl
)
610 DWORD a
= service
->status
.dwControlsAccepted
;
614 case SERVICE_CONTROL_INTERROGATE
:
616 case SERVICE_CONTROL_STOP
:
617 if (a
&SERVICE_ACCEPT_STOP
)
620 case SERVICE_CONTROL_SHUTDOWN
:
621 if (a
&SERVICE_ACCEPT_SHUTDOWN
)
624 case SERVICE_CONTROL_PAUSE
:
625 case SERVICE_CONTROL_CONTINUE
:
626 if (a
&SERVICE_ACCEPT_PAUSE_CONTINUE
)
629 case SERVICE_CONTROL_PARAMCHANGE
:
630 if (a
&SERVICE_ACCEPT_PARAMCHANGE
)
633 case SERVICE_CONTROL_NETBINDADD
:
634 case SERVICE_CONTROL_NETBINDREMOVE
:
635 case SERVICE_CONTROL_NETBINDENABLE
:
636 case SERVICE_CONTROL_NETBINDDISABLE
:
637 if (a
&SERVICE_ACCEPT_NETBINDCHANGE
)
640 if (!service
->extended
)
644 case SERVICE_CONTROL_HARDWAREPROFILECHANGE
:
645 if (a
&SERVICE_ACCEPT_HARDWAREPROFILECHANGE
)
648 case SERVICE_CONTROL_POWEREVENT
:
649 if (a
&SERVICE_ACCEPT_POWEREVENT
)
652 case SERVICE_CONTROL_SESSIONCHANGE
:
653 if (a
&SERVICE_ACCEPT_SESSIONCHANGE
)
660 /******************************************************************************
661 * service_handle_control
663 static BOOL
service_handle_control(HANDLE pipe
, service_data
*service
,
666 DWORD count
, ret
= ERROR_INVALID_SERVICE_CONTROL
;
668 TRACE("received control %d\n", dwControl
);
670 if (service_accepts_control(service
, dwControl
))
672 if (service
->extended
&& service
->handler
.handler_ex
)
674 service
->handler
.handler_ex(dwControl
, 0, NULL
, service
->context
);
677 else if (service
->handler
.handler
)
679 service
->handler
.handler(dwControl
);
683 return WriteFile(pipe
, &ret
, sizeof ret
, &count
, NULL
);
686 /******************************************************************************
687 * service_reap_thread
689 static DWORD
service_reap_thread(service_data
*service
)
693 if (!service
->thread
)
695 GetExitCodeThread(service
->thread
, &exitcode
);
696 if (exitcode
!=STILL_ACTIVE
)
698 CloseHandle(service
->thread
);
704 /******************************************************************************
705 * service_control_dispatcher
707 static DWORD WINAPI
service_control_dispatcher(LPVOID arg
)
709 service_data
*service
= arg
;
713 TRACE("%p %s\n", service
, debugstr_w(service
->name
));
715 /* create a pipe to talk to the rest of the world with */
716 name
= service_get_pipe_name(service
->name
);
717 pipe
= CreateNamedPipeW(name
, PIPE_ACCESS_DUPLEX
,
718 PIPE_TYPE_BYTE
|PIPE_WAIT
, 1, 256, 256, 10000, NULL
);
721 /* let the process who started us know we've tried to create a pipe */
722 event
= service_get_event_handle(service
->name
);
726 if (pipe
==INVALID_HANDLE_VALUE
)
728 ERR("failed to create pipe for %s, error = %d\n",
729 debugstr_w(service
->name
), GetLastError());
733 /* dispatcher loop */
737 DWORD count
, req
[2] = {0,0};
739 r
= ConnectNamedPipe(pipe
, NULL
);
740 if (!r
&& GetLastError() != ERROR_PIPE_CONNECTED
)
742 ERR("pipe connect failed\n");
746 r
= ReadFile( pipe
, &req
, sizeof req
, &count
, NULL
);
747 if (!r
|| count
!=sizeof req
)
749 ERR("pipe read failed\n");
753 service_reap_thread(service
);
755 /* handle the request */
758 case WINESERV_STARTINFO
:
759 service_handle_start(pipe
, service
, req
[1]);
761 case WINESERV_GETSTATUS
:
762 service_handle_get_status(pipe
, service
);
764 case WINESERV_SENDCONTROL
:
765 service_handle_control(pipe
, service
, req
[1]);
767 case WINESERV_SETPID
:
768 service_handle_set_processID(pipe
, service
, req
[1]);
771 ERR("received invalid command %d length %d\n", req
[0], req
[1]);
774 FlushFileBuffers(pipe
);
775 DisconnectNamedPipe(pipe
);
782 /******************************************************************************
783 * service_run_threads
785 static BOOL
service_run_threads(void)
787 service_data
*service
;
791 EnterCriticalSection( &service_cs
);
793 count
= list_count( &service_list
);
795 TRACE("starting %d pipe listener threads\n", count
);
797 handles
= HeapAlloc(GetProcessHeap(), 0, sizeof(HANDLE
) * (count
+ 1));
799 handles
[n
++] = __wine_make_process_system();
801 LIST_FOR_EACH_ENTRY( service
, &service_list
, service_data
, entry
)
802 handles
[n
++] = CreateThread( NULL
, 0, service_control_dispatcher
,
804 assert(n
== count
+ 1);
806 LeaveCriticalSection( &service_cs
);
808 /* wait for all the threads to pack up and exit */
811 DWORD ret
= WaitForMultipleObjects( min(n
,MAXIMUM_WAIT_OBJECTS
), handles
, FALSE
, INFINITE
);
812 if (!ret
) /* system process event */
814 TRACE( "last user process exited, shutting down\n" );
815 /* FIXME: we should maybe send a shutdown control to running services */
818 if (ret
< MAXIMUM_WAIT_OBJECTS
)
820 CloseHandle( handles
[ret
] );
821 memmove( &handles
[ret
], &handles
[ret
+1], (n
- ret
- 1) * sizeof(HANDLE
) );
827 while (n
) CloseHandle( handles
[--n
] );
828 HeapFree(GetProcessHeap(), 0, handles
);
833 /******************************************************************************
834 * StartServiceCtrlDispatcherA [ADVAPI32.@]
836 * See StartServiceCtrlDispatcherW.
838 BOOL WINAPI
StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA
*servent
)
844 TRACE("%p\n", servent
);
846 EnterCriticalSection( &service_cs
);
847 while (servent
->lpServiceName
)
849 LPSTR name
= servent
->lpServiceName
;
851 len
= MultiByteToWideChar(CP_ACP
, 0, name
, -1, NULL
, 0);
852 sz
= len
*sizeof(WCHAR
) + sizeof *info
;
853 info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sz
);
854 MultiByteToWideChar(CP_ACP
, 0, name
, -1, info
->name
, len
);
855 info
->proc
.a
= servent
->lpServiceProc
;
856 info
->unicode
= FALSE
;
857 list_add_head( &service_list
, &info
->entry
);
860 LeaveCriticalSection( &service_cs
);
862 service_run_threads();
867 /******************************************************************************
868 * StartServiceCtrlDispatcherW [ADVAPI32.@]
870 * Connects a process containing one or more services to the service control
874 * servent [I] A list of the service names and service procedures
880 BOOL WINAPI
StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW
*servent
)
886 TRACE("%p\n", servent
);
888 EnterCriticalSection( &service_cs
);
889 while (servent
->lpServiceName
)
891 LPWSTR name
= servent
->lpServiceName
;
894 sz
= len
*sizeof(WCHAR
) + sizeof *info
;
895 info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sz
);
896 strcpyW(info
->name
, name
);
897 info
->proc
.w
= servent
->lpServiceProc
;
898 info
->unicode
= TRUE
;
899 list_add_head( &service_list
, &info
->entry
);
902 LeaveCriticalSection( &service_cs
);
904 service_run_threads();
909 /******************************************************************************
910 * LockServiceDatabase [ADVAPI32.@]
912 SC_LOCK WINAPI
LockServiceDatabase (SC_HANDLE hSCManager
)
916 TRACE("%p\n",hSCManager
);
918 ret
= CreateSemaphoreW( NULL
, 1, 1, szSCMLock
);
919 if( ret
&& GetLastError() == ERROR_ALREADY_EXISTS
)
923 SetLastError( ERROR_SERVICE_DATABASE_LOCKED
);
926 TRACE("returning %p\n", ret
);
931 /******************************************************************************
932 * UnlockServiceDatabase [ADVAPI32.@]
934 BOOL WINAPI
UnlockServiceDatabase (SC_LOCK ScLock
)
936 TRACE("%p\n",ScLock
);
938 return CloseHandle( ScLock
);
941 /******************************************************************************
942 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
944 SERVICE_STATUS_HANDLE WINAPI
945 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName
, LPHANDLER_FUNCTION lpfHandler
)
947 LPWSTR lpServiceNameW
;
948 SERVICE_STATUS_HANDLE ret
;
950 lpServiceNameW
= SERV_dup(lpServiceName
);
951 ret
= RegisterServiceCtrlHandlerW( lpServiceNameW
, lpfHandler
);
952 SERV_free(lpServiceNameW
);
956 /******************************************************************************
957 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
963 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName
,
964 LPHANDLER_FUNCTION lpfHandler
)
966 service_data
*service
;
967 SERVICE_STATUS_HANDLE handle
= 0;
969 EnterCriticalSection( &service_cs
);
970 LIST_FOR_EACH_ENTRY( service
, &service_list
, service_data
, entry
)
972 if(!strcmpW(lpServiceName
, service
->name
))
974 service
->handler
.handler
= lpfHandler
;
975 handle
= (SERVICE_STATUS_HANDLE
)service
;
979 LeaveCriticalSection( &service_cs
);
983 /******************************************************************************
984 * SetServiceStatus [ADVAPI32.@]
991 SetServiceStatus( SERVICE_STATUS_HANDLE hService
, LPSERVICE_STATUS lpStatus
)
993 service_data
*service
;
996 TRACE("%p %x %x %x %x %x %x %x\n", hService
,
997 lpStatus
->dwServiceType
, lpStatus
->dwCurrentState
,
998 lpStatus
->dwControlsAccepted
, lpStatus
->dwWin32ExitCode
,
999 lpStatus
->dwServiceSpecificExitCode
, lpStatus
->dwCheckPoint
,
1000 lpStatus
->dwWaitHint
);
1002 EnterCriticalSection( &service_cs
);
1003 LIST_FOR_EACH_ENTRY( service
, &service_list
, service_data
, entry
)
1005 if(service
== (service_data
*)hService
)
1007 memcpy( &service
->status
, lpStatus
, sizeof(SERVICE_STATUS
) );
1008 TRACE("Set service status to %d\n",service
->status
.dwCurrentState
);
1013 LeaveCriticalSection( &service_cs
);
1019 /******************************************************************************
1020 * OpenSCManagerA [ADVAPI32.@]
1022 * Establish a connection to the service control manager and open its database.
1025 * lpMachineName [I] Pointer to machine name string
1026 * lpDatabaseName [I] Pointer to database name string
1027 * dwDesiredAccess [I] Type of access
1030 * Success: A Handle to the service control manager database
1033 SC_HANDLE WINAPI
OpenSCManagerA( LPCSTR lpMachineName
, LPCSTR lpDatabaseName
,
1034 DWORD dwDesiredAccess
)
1036 LPWSTR lpMachineNameW
, lpDatabaseNameW
;
1039 lpMachineNameW
= SERV_dup(lpMachineName
);
1040 lpDatabaseNameW
= SERV_dup(lpDatabaseName
);
1041 ret
= OpenSCManagerW(lpMachineNameW
, lpDatabaseNameW
, dwDesiredAccess
);
1042 SERV_free(lpDatabaseNameW
);
1043 SERV_free(lpMachineNameW
);
1047 /******************************************************************************
1048 * OpenSCManagerW [ADVAPI32.@]
1050 * See OpenSCManagerA.
1052 SC_HANDLE WINAPI
OpenSCManagerW( LPCWSTR lpMachineName
, LPCWSTR lpDatabaseName
,
1053 DWORD dwDesiredAccess
)
1055 struct sc_manager
*manager
;
1058 DWORD new_mask
= dwDesiredAccess
;
1060 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName
),
1061 debugstr_w(lpDatabaseName
), dwDesiredAccess
);
1063 if( lpDatabaseName
&& lpDatabaseName
[0] )
1065 if( strcmpiW( lpDatabaseName
, SERVICES_ACTIVE_DATABASEW
) == 0 )
1067 /* noop, all right */
1069 else if( strcmpiW( lpDatabaseName
, SERVICES_FAILED_DATABASEW
) == 0 )
1071 SetLastError( ERROR_DATABASE_DOES_NOT_EXIST
);
1076 SetLastError( ERROR_INVALID_NAME
);
1081 manager
= sc_handle_alloc( SC_HTYPE_MANAGER
, sizeof (struct sc_manager
),
1082 sc_handle_destroy_manager
);
1086 r
= RegConnectRegistryW(lpMachineName
,HKEY_LOCAL_MACHINE
,&hReg
);
1087 if (r
!=ERROR_SUCCESS
)
1090 r
= RegCreateKeyW(hReg
, szServiceManagerKey
, &manager
->hkey
);
1091 RegCloseKey( hReg
);
1092 if (r
!=ERROR_SUCCESS
)
1095 RtlMapGenericMask(&new_mask
, &scm_generic
);
1096 manager
->dwAccess
= new_mask
;
1097 TRACE("returning %p (access : 0x%08x)\n", manager
, manager
->dwAccess
);
1099 return (SC_HANDLE
) &manager
->hdr
;
1102 sc_handle_free( &manager
->hdr
);
1107 /******************************************************************************
1108 * ControlService [ADVAPI32.@]
1110 * Send a control code to a service.
1113 * hService [I] Handle of the service control manager database
1114 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
1115 * lpServiceStatus [O] Destination for the status of the service, if available
1122 * Unlike M$' implementation, control requests are not serialized and may be
1123 * processed asynchronously.
1125 BOOL WINAPI
ControlService( SC_HANDLE hService
, DWORD dwControl
,
1126 LPSERVICE_STATUS lpServiceStatus
)
1128 struct sc_service
*hsvc
;
1132 TRACE("%p %d %p\n", hService
, dwControl
, lpServiceStatus
);
1134 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1137 SetLastError( ERROR_INVALID_HANDLE
);
1141 ret
= QueryServiceStatus(hService
, lpServiceStatus
);
1144 ERR("failed to query service status\n");
1145 SetLastError(ERROR_SERVICE_NOT_ACTIVE
);
1149 switch (lpServiceStatus
->dwCurrentState
)
1151 case SERVICE_STOPPED
:
1152 SetLastError(ERROR_SERVICE_NOT_ACTIVE
);
1154 case SERVICE_START_PENDING
:
1155 if (dwControl
==SERVICE_CONTROL_STOP
)
1158 case SERVICE_STOP_PENDING
:
1159 SetLastError(ERROR_SERVICE_CANNOT_ACCEPT_CTRL
);
1163 handle
= service_open_pipe(hsvc
->name
);
1164 if (handle
!=INVALID_HANDLE_VALUE
)
1166 DWORD result
= ERROR_SUCCESS
;
1167 ret
= service_send_control(handle
, dwControl
, &result
);
1168 CloseHandle(handle
);
1169 if (result
!=ERROR_SUCCESS
)
1171 SetLastError(result
);
1179 /******************************************************************************
1180 * CloseServiceHandle [ADVAPI32.@]
1182 * Close a handle to a service or the service control manager database.
1185 * hSCObject [I] Handle to service or service control manager database
1192 CloseServiceHandle( SC_HANDLE hSCObject
)
1194 TRACE("%p\n", hSCObject
);
1196 sc_handle_free( (struct sc_handle
*) hSCObject
);
1202 /******************************************************************************
1203 * OpenServiceA [ADVAPI32.@]
1205 * Open a handle to a service.
1208 * hSCManager [I] Handle of the service control manager database
1209 * lpServiceName [I] Name of the service to open
1210 * dwDesiredAccess [I] Access required to the service
1213 * Success: Handle to the service
1216 SC_HANDLE WINAPI
OpenServiceA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
1217 DWORD dwDesiredAccess
)
1219 LPWSTR lpServiceNameW
;
1222 TRACE("%p %s %d\n", hSCManager
, debugstr_a(lpServiceName
), dwDesiredAccess
);
1224 lpServiceNameW
= SERV_dup(lpServiceName
);
1225 ret
= OpenServiceW( hSCManager
, lpServiceNameW
, dwDesiredAccess
);
1226 SERV_free(lpServiceNameW
);
1231 /******************************************************************************
1232 * OpenServiceW [ADVAPI32.@]
1236 SC_HANDLE WINAPI
OpenServiceW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
1237 DWORD dwDesiredAccess
)
1239 struct sc_manager
*hscm
;
1240 struct sc_service
*hsvc
;
1244 DWORD new_mask
= dwDesiredAccess
;
1246 TRACE("%p %s %d\n", hSCManager
, debugstr_w(lpServiceName
), dwDesiredAccess
);
1248 hscm
= sc_handle_get_handle_data( hSCManager
, SC_HTYPE_MANAGER
);
1251 SetLastError( ERROR_INVALID_HANDLE
);
1257 SetLastError(ERROR_INVALID_ADDRESS
);
1261 r
= RegOpenKeyExW( hscm
->hkey
, lpServiceName
, 0, KEY_ALL_ACCESS
, &hKey
);
1262 if (r
!=ERROR_SUCCESS
)
1264 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST
);
1268 len
= strlenW(lpServiceName
)+1;
1269 hsvc
= sc_handle_alloc( SC_HTYPE_SERVICE
,
1270 sizeof (struct sc_service
) + len
*sizeof(WCHAR
),
1271 sc_handle_destroy_service
);
1277 strcpyW( hsvc
->name
, lpServiceName
);
1280 RtlMapGenericMask(&new_mask
, &svc_generic
);
1281 hsvc
->dwAccess
= new_mask
;
1283 /* add reference to SCM handle */
1284 hscm
->hdr
.ref_count
++;
1287 TRACE("returning %p\n",hsvc
);
1289 return (SC_HANDLE
) &hsvc
->hdr
;
1292 /******************************************************************************
1293 * CreateServiceW [ADVAPI32.@]
1296 CreateServiceW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
1297 LPCWSTR lpDisplayName
, DWORD dwDesiredAccess
,
1298 DWORD dwServiceType
, DWORD dwStartType
,
1299 DWORD dwErrorControl
, LPCWSTR lpBinaryPathName
,
1300 LPCWSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
,
1301 LPCWSTR lpDependencies
, LPCWSTR lpServiceStartName
,
1302 LPCWSTR lpPassword
)
1304 struct sc_manager
*hscm
;
1305 struct sc_service
*hsvc
= NULL
;
1309 struct reg_value val
[10];
1311 DWORD new_mask
= dwDesiredAccess
;
1313 WCHAR buffer
[MAX_PATH
];
1314 BOOL displayname_exists
= FALSE
;
1316 TRACE("%p %s %s\n", hSCManager
,
1317 debugstr_w(lpServiceName
), debugstr_w(lpDisplayName
));
1319 hscm
= sc_handle_get_handle_data( hSCManager
, SC_HTYPE_MANAGER
);
1322 SetLastError( ERROR_INVALID_HANDLE
);
1326 if (!lpServiceName
|| !lpBinaryPathName
)
1328 SetLastError(ERROR_INVALID_ADDRESS
);
1332 if (!(hscm
->dwAccess
& SC_MANAGER_CREATE_SERVICE
))
1334 SetLastError(ERROR_ACCESS_DENIED
);
1338 if (!lpServiceName
[0])
1340 SetLastError(ERROR_INVALID_NAME
);
1344 if (!lpBinaryPathName
[0])
1346 SetLastError(ERROR_INVALID_PARAMETER
);
1350 /* ServiceType can only be one value (except for SERVICE_INTERACTIVE_PROCESS which can be used
1351 * together with SERVICE_WIN32_OWN_PROCESS or SERVICE_WIN32_SHARE_PROCESS when the service
1352 * runs under the LocalSystem account)
1354 switch (dwServiceType
)
1356 case SERVICE_KERNEL_DRIVER
:
1357 case SERVICE_FILE_SYSTEM_DRIVER
:
1358 case SERVICE_WIN32_OWN_PROCESS
:
1359 case SERVICE_WIN32_SHARE_PROCESS
:
1362 case SERVICE_WIN32_OWN_PROCESS
| SERVICE_INTERACTIVE_PROCESS
:
1363 case SERVICE_WIN32_SHARE_PROCESS
| SERVICE_INTERACTIVE_PROCESS
:
1364 /* FIXME : Do we need a more thorough check? */
1365 if (lpServiceStartName
)
1367 SetLastError(ERROR_INVALID_PARAMETER
);
1372 SetLastError(ERROR_INVALID_PARAMETER
);
1376 /* StartType can only be a single value (if several values are mixed the result is probably not what was intended) */
1377 if (dwStartType
> SERVICE_DISABLED
)
1379 SetLastError(ERROR_INVALID_PARAMETER
);
1383 /* SERVICE_BOOT_START and SERVICE_SYSTEM_START or only allowed for driver services */
1384 if (((dwStartType
== SERVICE_BOOT_START
) || (dwStartType
== SERVICE_SYSTEM_START
)) &&
1385 ((dwServiceType
& SERVICE_WIN32_OWN_PROCESS
) || (dwServiceType
& SERVICE_WIN32_SHARE_PROCESS
)))
1387 SetLastError(ERROR_INVALID_PARAMETER
);
1391 /* Loop through the registry to check if the service already exists and to
1392 * check if we can use the given displayname.
1393 * FIXME: Should we use EnumServicesStatusEx?
1395 len
= sizeof(buffer
);
1396 while (RegEnumKeyExW(hscm
->hkey
, index
, buffer
, &len
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
)
1400 /* The service already exists, so bail out */
1401 if(!lstrcmpiW(lpServiceName
, buffer
))
1403 SetLastError(ERROR_SERVICE_EXISTS
);
1407 /* The given displayname matches the found servicename. We don't bail out
1408 * as servicename is checked before a duplicate displayname
1410 if(!lstrcmpiW(lpDisplayName
, buffer
))
1411 displayname_exists
= TRUE
;
1413 if (RegOpenKeyExW(hscm
->hkey
, buffer
, 0, KEY_READ
, &service_key
) == ERROR_SUCCESS
)
1415 WCHAR name
[MAX_PATH
];
1416 DWORD size
= sizeof(name
);
1418 if (RegQueryValueExW(service_key
, szDisplayName
, NULL
, NULL
, (LPBYTE
)name
, &size
) == ERROR_SUCCESS
)
1420 /* The given displayname matches the found displayname */
1421 if (!lstrcmpiW(lpDisplayName
, name
))
1422 displayname_exists
= TRUE
;
1424 RegCloseKey(service_key
);
1427 len
= sizeof(buffer
);
1430 if (lpDisplayName
&& displayname_exists
)
1432 SetLastError(ERROR_DUPLICATE_SERVICE_NAME
);
1436 r
= RegCreateKeyExW(hscm
->hkey
, lpServiceName
, 0, NULL
,
1437 REG_OPTION_NON_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &hKey
, &dp
);
1438 if (r
!=ERROR_SUCCESS
)
1440 /* FIXME: Should we set an error? */
1445 service_set_string( &val
[n
++], szDisplayName
, lpDisplayName
);
1447 service_set_dword( &val
[n
++], szType
, &dwServiceType
);
1448 service_set_dword( &val
[n
++], szStart
, &dwStartType
);
1449 service_set_dword( &val
[n
++], szError
, &dwErrorControl
);
1451 service_set_string( &val
[n
++], szImagePath
, lpBinaryPathName
);
1453 if( lpLoadOrderGroup
)
1454 service_set_string( &val
[n
++], szGroup
, lpLoadOrderGroup
);
1456 /* FIXME: lpDependencies is used to create both DependOnService and DependOnGroup
1457 * There is no such key as what szDependencies refers to */
1458 if( lpDependencies
)
1459 service_set_multi_string( &val
[n
++], szDependencies
, lpDependencies
);
1462 FIXME("Don't know how to add a Password for a service.\n");
1464 if( lpServiceStartName
)
1465 service_set_string( &val
[n
++], szObjectName
, lpServiceStartName
);
1467 r
= service_write_values( hKey
, val
, n
);
1468 if( r
!= ERROR_SUCCESS
)
1471 len
= strlenW(lpServiceName
)+1;
1472 len
= sizeof (struct sc_service
) + len
*sizeof(WCHAR
);
1473 hsvc
= sc_handle_alloc( SC_HTYPE_SERVICE
, len
, sc_handle_destroy_service
);
1476 lstrcpyW( hsvc
->name
, lpServiceName
);
1479 RtlMapGenericMask(&new_mask
, &svc_generic
);
1480 hsvc
->dwAccess
= new_mask
;
1483 hscm
->hdr
.ref_count
++;
1485 return (SC_HANDLE
) &hsvc
->hdr
;
1488 RegCloseKey( hKey
);
1493 /******************************************************************************
1494 * CreateServiceA [ADVAPI32.@]
1497 CreateServiceA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
1498 LPCSTR lpDisplayName
, DWORD dwDesiredAccess
,
1499 DWORD dwServiceType
, DWORD dwStartType
,
1500 DWORD dwErrorControl
, LPCSTR lpBinaryPathName
,
1501 LPCSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
,
1502 LPCSTR lpDependencies
, LPCSTR lpServiceStartName
,
1505 LPWSTR lpServiceNameW
, lpDisplayNameW
, lpBinaryPathNameW
,
1506 lpLoadOrderGroupW
, lpDependenciesW
, lpServiceStartNameW
, lpPasswordW
;
1509 TRACE("%p %s %s\n", hSCManager
,
1510 debugstr_a(lpServiceName
), debugstr_a(lpDisplayName
));
1512 lpServiceNameW
= SERV_dup( lpServiceName
);
1513 lpDisplayNameW
= SERV_dup( lpDisplayName
);
1514 lpBinaryPathNameW
= SERV_dup( lpBinaryPathName
);
1515 lpLoadOrderGroupW
= SERV_dup( lpLoadOrderGroup
);
1516 lpDependenciesW
= SERV_dupmulti( lpDependencies
);
1517 lpServiceStartNameW
= SERV_dup( lpServiceStartName
);
1518 lpPasswordW
= SERV_dup( lpPassword
);
1520 r
= CreateServiceW( hSCManager
, lpServiceNameW
, lpDisplayNameW
,
1521 dwDesiredAccess
, dwServiceType
, dwStartType
, dwErrorControl
,
1522 lpBinaryPathNameW
, lpLoadOrderGroupW
, lpdwTagId
,
1523 lpDependenciesW
, lpServiceStartNameW
, lpPasswordW
);
1525 SERV_free( lpServiceNameW
);
1526 SERV_free( lpDisplayNameW
);
1527 SERV_free( lpBinaryPathNameW
);
1528 SERV_free( lpLoadOrderGroupW
);
1529 SERV_free( lpDependenciesW
);
1530 SERV_free( lpServiceStartNameW
);
1531 SERV_free( lpPasswordW
);
1537 /******************************************************************************
1538 * DeleteService [ADVAPI32.@]
1540 * Delete a service from the service control manager database.
1543 * hService [I] Handle of the service to delete
1549 BOOL WINAPI
DeleteService( SC_HANDLE hService
)
1551 struct sc_service
*hsvc
;
1553 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1556 SetLastError( ERROR_INVALID_HANDLE
);
1560 if (!(hsvc
->dwAccess
& DELETE
))
1562 SetLastError(ERROR_ACCESS_DENIED
);
1566 /* Close the key to the service */
1567 RegCloseKey(hsvc
->hkey
);
1569 /* Delete the service under the Service Control Manager key */
1570 RegDeleteTreeW(hsvc
->scm
->hkey
, hsvc
->name
);
1578 /******************************************************************************
1579 * StartServiceA [ADVAPI32.@]
1584 * hService [I] Handle of service
1585 * dwNumServiceArgs [I] Number of arguments
1586 * lpServiceArgVectors [I] Address of array of argument strings
1589 * - NT implements this function using an obscure RPC call.
1590 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1591 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1592 * - This will only work for shared address space. How should the service
1593 * args be transferred when address spaces are separated?
1594 * - Can only start one service at a time.
1595 * - Has no concept of privilege.
1601 BOOL WINAPI
StartServiceA( SC_HANDLE hService
, DWORD dwNumServiceArgs
,
1602 LPCSTR
*lpServiceArgVectors
)
1604 LPWSTR
*lpwstr
=NULL
;
1608 TRACE("(%p,%d,%p)\n",hService
,dwNumServiceArgs
,lpServiceArgVectors
);
1610 if (dwNumServiceArgs
)
1611 lpwstr
= HeapAlloc( GetProcessHeap(), 0,
1612 dwNumServiceArgs
*sizeof(LPWSTR
) );
1614 for(i
=0; i
<dwNumServiceArgs
; i
++)
1615 lpwstr
[i
]=SERV_dup(lpServiceArgVectors
[i
]);
1617 r
= StartServiceW(hService
, dwNumServiceArgs
, (LPCWSTR
*)lpwstr
);
1619 if (dwNumServiceArgs
)
1621 for(i
=0; i
<dwNumServiceArgs
; i
++)
1622 SERV_free(lpwstr
[i
]);
1623 HeapFree(GetProcessHeap(), 0, lpwstr
);
1629 /******************************************************************************
1630 * service_start_process [INTERNAL]
1632 static DWORD
service_start_process(struct sc_service
*hsvc
, LPDWORD ppid
)
1634 static const WCHAR _ImagePathW
[] = {'I','m','a','g','e','P','a','t','h',0};
1635 PROCESS_INFORMATION pi
;
1637 LPWSTR path
= NULL
, str
;
1638 DWORD type
, size
, ret
, svc_type
;
1642 size
= sizeof(svc_type
);
1643 if (RegQueryValueExW(hsvc
->hkey
, szType
, NULL
, &type
, (LPBYTE
)&svc_type
, &size
) || type
!= REG_DWORD
)
1646 if (svc_type
== SERVICE_KERNEL_DRIVER
)
1648 static const WCHAR winedeviceW
[] = {'\\','w','i','n','e','d','e','v','i','c','e','.','e','x','e',' ',0};
1649 DWORD len
= GetSystemDirectoryW( NULL
, 0 ) + sizeof(winedeviceW
)/sizeof(WCHAR
) + strlenW(hsvc
->name
);
1651 if (!(path
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) ))) return FALSE
;
1652 GetSystemDirectoryW( path
, len
);
1653 lstrcatW( path
, winedeviceW
);
1654 lstrcatW( path
, hsvc
->name
);
1658 /* read the executable path from the registry */
1660 ret
= RegQueryValueExW(hsvc
->hkey
, _ImagePathW
, NULL
, &type
, NULL
, &size
);
1661 if (ret
!=ERROR_SUCCESS
)
1663 str
= HeapAlloc(GetProcessHeap(),0,size
);
1664 ret
= RegQueryValueExW(hsvc
->hkey
, _ImagePathW
, NULL
, &type
, (LPBYTE
)str
, &size
);
1665 if (ret
==ERROR_SUCCESS
)
1667 size
= ExpandEnvironmentStringsW(str
,NULL
,0);
1668 path
= HeapAlloc(GetProcessHeap(),0,size
*sizeof(WCHAR
));
1669 ExpandEnvironmentStringsW(str
,path
,size
);
1671 HeapFree(GetProcessHeap(),0,str
);
1676 /* wait for the process to start and set an event or terminate */
1677 handles
[0] = service_get_event_handle( hsvc
->name
);
1678 ZeroMemory(&si
, sizeof(STARTUPINFOW
));
1679 si
.cb
= sizeof(STARTUPINFOW
);
1680 r
= CreateProcessW(NULL
, path
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
1683 if (ppid
) *ppid
= pi
.dwProcessId
;
1685 handles
[1] = pi
.hProcess
;
1686 ret
= WaitForMultipleObjectsEx(2, handles
, FALSE
, 30000, FALSE
);
1687 if(ret
!= WAIT_OBJECT_0
)
1689 SetLastError(ERROR_IO_PENDING
);
1693 CloseHandle( pi
.hThread
);
1694 CloseHandle( pi
.hProcess
);
1696 CloseHandle( handles
[0] );
1697 HeapFree(GetProcessHeap(),0,path
);
1701 static BOOL
service_wait_for_startup(SC_HANDLE hService
)
1704 SERVICE_STATUS status
;
1707 TRACE("%p\n", hService
);
1709 for (i
=0; i
<30; i
++)
1711 status
.dwCurrentState
= 0;
1712 r
= QueryServiceStatus(hService
, &status
);
1715 if (status
.dwCurrentState
== SERVICE_RUNNING
)
1717 TRACE("Service started successfully\n");
1726 /******************************************************************************
1727 * StartServiceW [ADVAPI32.@]
1729 * See StartServiceA.
1731 BOOL WINAPI
StartServiceW(SC_HANDLE hService
, DWORD dwNumServiceArgs
,
1732 LPCWSTR
*lpServiceArgVectors
)
1734 struct sc_service
*hsvc
;
1736 DWORD dwResult
, dwProcessId
= 0;
1738 HANDLE handle
= INVALID_HANDLE_VALUE
;
1740 TRACE("%p %d %p\n", hService
, dwNumServiceArgs
, lpServiceArgVectors
);
1742 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1745 SetLastError(ERROR_INVALID_HANDLE
);
1749 hLock
= LockServiceDatabase((SC_HANDLE
)hsvc
->scm
);
1753 handle
= service_open_pipe(hsvc
->name
);
1754 if (handle
==INVALID_HANDLE_VALUE
)
1756 /* start the service process */
1757 if (service_start_process(hsvc
, &dwProcessId
))
1758 handle
= service_open_pipe(hsvc
->name
);
1761 if (handle
!= INVALID_HANDLE_VALUE
)
1763 r
= service_send_start_message(handle
, lpServiceArgVectors
, dwNumServiceArgs
);
1764 CloseHandle(handle
);
1767 handle
= service_open_pipe(hsvc
->name
);
1768 if (handle
!= INVALID_HANDLE_VALUE
)
1770 service_set_processID(handle
, dwProcessId
, &dwResult
);
1771 CloseHandle(handle
);
1774 UnlockServiceDatabase( hLock
);
1776 TRACE("returning %d\n", r
);
1779 service_wait_for_startup(hService
);
1784 /******************************************************************************
1785 * QueryServiceStatus [ADVAPI32.@]
1788 * hService [I] Handle to service to get information about
1789 * lpservicestatus [O] buffer to receive the status information for the service
1792 BOOL WINAPI
QueryServiceStatus(SC_HANDLE hService
,
1793 LPSERVICE_STATUS lpservicestatus
)
1795 SERVICE_STATUS_PROCESS SvcStatusData
;
1798 TRACE("%p %p\n", hService
, lpservicestatus
);
1800 ret
= QueryServiceStatusEx(hService
, SC_STATUS_PROCESS_INFO
, (LPBYTE
)&SvcStatusData
,
1801 sizeof(SERVICE_STATUS_PROCESS
), NULL
);
1802 if (ret
) memcpy(lpservicestatus
, &SvcStatusData
, sizeof(SERVICE_STATUS
)) ;
1807 /******************************************************************************
1808 * QueryServiceStatusEx [ADVAPI32.@]
1810 * Get information about a service.
1813 * hService [I] Handle to service to get information about
1814 * InfoLevel [I] Level of information to get
1815 * lpBuffer [O] Destination for requested information
1816 * cbBufSize [I] Size of lpBuffer in bytes
1817 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1823 BOOL WINAPI
QueryServiceStatusEx(SC_HANDLE hService
, SC_STATUS_TYPE InfoLevel
,
1824 LPBYTE lpBuffer
, DWORD cbBufSize
,
1825 LPDWORD pcbBytesNeeded
)
1827 struct sc_service
*hsvc
;
1828 DWORD size
, type
, val
;
1831 LPSERVICE_STATUS_PROCESS pSvcStatusData
;
1833 TRACE("%p %d %p %d %p\n", hService
, InfoLevel
, lpBuffer
, cbBufSize
, pcbBytesNeeded
);
1835 if (InfoLevel
!= SC_STATUS_PROCESS_INFO
)
1837 SetLastError( ERROR_INVALID_LEVEL
);
1841 pSvcStatusData
= (LPSERVICE_STATUS_PROCESS
) lpBuffer
;
1842 if (pSvcStatusData
== NULL
)
1844 SetLastError( ERROR_INVALID_PARAMETER
);
1848 if (cbBufSize
< sizeof(SERVICE_STATUS_PROCESS
))
1850 if( pcbBytesNeeded
!= NULL
)
1851 *pcbBytesNeeded
= sizeof(SERVICE_STATUS_PROCESS
);
1853 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1857 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1860 SetLastError( ERROR_INVALID_HANDLE
);
1864 pipe
= service_open_pipe(hsvc
->name
);
1865 if (pipe
!= INVALID_HANDLE_VALUE
)
1867 r
= service_get_status(pipe
, pSvcStatusData
);
1873 TRACE("Failed to read service status\n");
1875 /* read the service type from the registry */
1877 r
= RegQueryValueExA(hsvc
->hkey
, "Type", NULL
, &type
, (LPBYTE
)&val
, &size
);
1878 if (r
!= ERROR_SUCCESS
|| type
!= REG_DWORD
)
1881 pSvcStatusData
->dwServiceType
= val
;
1882 pSvcStatusData
->dwCurrentState
= SERVICE_STOPPED
; /* stopped */
1883 pSvcStatusData
->dwControlsAccepted
= 0;
1884 pSvcStatusData
->dwWin32ExitCode
= ERROR_SERVICE_NEVER_STARTED
;
1885 pSvcStatusData
->dwServiceSpecificExitCode
= 0;
1886 pSvcStatusData
->dwCheckPoint
= 0;
1887 pSvcStatusData
->dwWaitHint
= 0;
1892 /******************************************************************************
1893 * QueryServiceConfigA [ADVAPI32.@]
1895 BOOL WINAPI
QueryServiceConfigA( SC_HANDLE hService
, LPQUERY_SERVICE_CONFIGA config
,
1896 DWORD size
, LPDWORD needed
)
1901 QUERY_SERVICE_CONFIGW
*configW
;
1903 TRACE("%p %p %d %p\n", hService
, config
, size
, needed
);
1905 if (!(buffer
= HeapAlloc( GetProcessHeap(), 0, 2 * size
)))
1907 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1910 configW
= (QUERY_SERVICE_CONFIGW
*)buffer
;
1911 ret
= QueryServiceConfigW( hService
, configW
, 2 * size
, needed
);
1912 if (!ret
) goto done
;
1914 config
->dwServiceType
= configW
->dwServiceType
;
1915 config
->dwStartType
= configW
->dwStartType
;
1916 config
->dwErrorControl
= configW
->dwErrorControl
;
1917 config
->lpBinaryPathName
= NULL
;
1918 config
->lpLoadOrderGroup
= NULL
;
1919 config
->dwTagId
= configW
->dwTagId
;
1920 config
->lpDependencies
= NULL
;
1921 config
->lpServiceStartName
= NULL
;
1922 config
->lpDisplayName
= NULL
;
1924 p
= (LPSTR
)(config
+ 1);
1925 n
= size
- sizeof(*config
);
1928 #define MAP_STR(str) \
1932 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1933 if (!sz) goto done; \
1940 MAP_STR( lpBinaryPathName
);
1941 MAP_STR( lpLoadOrderGroup
);
1942 MAP_STR( lpDependencies
);
1943 MAP_STR( lpServiceStartName
);
1944 MAP_STR( lpDisplayName
);
1947 *needed
= p
- (LPSTR
)config
;
1951 HeapFree( GetProcessHeap(), 0, buffer
);
1955 /******************************************************************************
1956 * QueryServiceConfigW [ADVAPI32.@]
1959 QueryServiceConfigW( SC_HANDLE hService
,
1960 LPQUERY_SERVICE_CONFIGW lpServiceConfig
,
1961 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
1963 WCHAR str_buffer
[ MAX_PATH
];
1965 DWORD type
, val
, sz
, total
, n
;
1968 struct sc_service
*hsvc
;
1970 TRACE("%p %p %d %p\n", hService
, lpServiceConfig
,
1971 cbBufSize
, pcbBytesNeeded
);
1973 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1976 SetLastError( ERROR_INVALID_HANDLE
);
1981 /* TODO: Check which members are mandatory and what the registry types
1982 * should be. This should of course also be tested when a service is
1986 /* calculate the size required first */
1987 total
= sizeof (QUERY_SERVICE_CONFIGW
);
1989 sz
= sizeof(str_buffer
);
1990 r
= RegQueryValueExW( hKey
, szImagePath
, 0, &type
, (LPBYTE
) str_buffer
, &sz
);
1991 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
|| type
== REG_EXPAND_SZ
) )
1993 sz
= ExpandEnvironmentStringsW(str_buffer
,NULL
,0);
1994 if( 0 == sz
) return FALSE
;
1996 total
+= sizeof(WCHAR
) * sz
;
2000 /* FIXME: set last error */
2005 r
= RegQueryValueExW( hKey
, szGroup
, 0, &type
, NULL
, &sz
);
2006 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
2009 total
+= sizeof(WCHAR
);
2012 r
= RegQueryValueExW( hKey
, szDependencies
, 0, &type
, NULL
, &sz
);
2013 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_MULTI_SZ
) )
2016 total
+= sizeof(WCHAR
);
2019 r
= RegQueryValueExW( hKey
, szObjectName
, 0, &type
, NULL
, &sz
);
2020 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
2023 total
+= sizeof(WCHAR
);
2026 r
= RegQueryValueExW( hKey
, szDisplayName
, 0, &type
, NULL
, &sz
);
2027 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
2030 total
+= sizeof(WCHAR
);
2032 *pcbBytesNeeded
= total
;
2034 /* if there's not enough memory, return an error */
2035 if( total
> cbBufSize
)
2037 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
2041 ZeroMemory( lpServiceConfig
, total
);
2044 r
= RegQueryValueExW( hKey
, szType
, 0, &type
, (LPBYTE
)&val
, &sz
);
2045 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_DWORD
) )
2046 lpServiceConfig
->dwServiceType
= val
;
2049 r
= RegQueryValueExW( hKey
, szStart
, 0, &type
, (LPBYTE
)&val
, &sz
);
2050 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_DWORD
) )
2051 lpServiceConfig
->dwStartType
= val
;
2054 r
= RegQueryValueExW( hKey
, szError
, 0, &type
, (LPBYTE
)&val
, &sz
);
2055 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_DWORD
) )
2056 lpServiceConfig
->dwErrorControl
= val
;
2059 r
= RegQueryValueExW( hKey
, szTag
, 0, &type
, (LPBYTE
)&val
, &sz
);
2060 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_DWORD
) )
2061 lpServiceConfig
->dwTagId
= val
;
2063 /* now do the strings */
2064 p
= (LPBYTE
) &lpServiceConfig
[1];
2065 n
= total
- sizeof (QUERY_SERVICE_CONFIGW
);
2067 sz
= sizeof(str_buffer
);
2068 r
= RegQueryValueExW( hKey
, szImagePath
, 0, &type
, (LPBYTE
) str_buffer
, &sz
);
2069 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
|| type
== REG_EXPAND_SZ
) )
2071 sz
= ExpandEnvironmentStringsW(str_buffer
, (LPWSTR
) p
, n
);
2072 sz
*= sizeof(WCHAR
);
2073 if( 0 == sz
|| sz
> n
) return FALSE
;
2075 lpServiceConfig
->lpBinaryPathName
= (LPWSTR
) p
;
2081 /* FIXME: set last error */
2086 r
= RegQueryValueExW( hKey
, szGroup
, 0, &type
, p
, &sz
);
2087 lpServiceConfig
->lpLoadOrderGroup
= (LPWSTR
) p
;
2088 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
2101 r
= RegQueryValueExW( hKey
, szDependencies
, 0, &type
, p
, &sz
);
2102 lpServiceConfig
->lpDependencies
= (LPWSTR
) p
;
2103 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
2116 r
= RegQueryValueExW( hKey
, szObjectName
, 0, &type
, p
, &sz
);
2117 lpServiceConfig
->lpServiceStartName
= (LPWSTR
) p
;
2118 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
2131 r
= RegQueryValueExW( hKey
, szDisplayName
, 0, &type
, p
, &sz
);
2132 lpServiceConfig
->lpDisplayName
= (LPWSTR
) p
;
2133 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
2146 ERR("Buffer overflow!\n");
2148 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig
->lpBinaryPathName
) );
2149 TRACE("Group = %s\n", debugstr_w(lpServiceConfig
->lpLoadOrderGroup
) );
2150 TRACE("Dependencies = %s\n", debugstr_w(lpServiceConfig
->lpDependencies
) );
2151 TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig
->lpServiceStartName
) );
2152 TRACE("Display name = %s\n", debugstr_w(lpServiceConfig
->lpDisplayName
) );
2157 /******************************************************************************
2158 * EnumServicesStatusA [ADVAPI32.@]
2161 EnumServicesStatusA( SC_HANDLE hSCManager
, DWORD dwServiceType
,
2162 DWORD dwServiceState
, LPENUM_SERVICE_STATUSA lpServices
,
2163 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
2164 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
)
2166 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager
,
2167 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
2168 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
);
2169 SetLastError (ERROR_ACCESS_DENIED
);
2173 /******************************************************************************
2174 * EnumServicesStatusW [ADVAPI32.@]
2177 EnumServicesStatusW( SC_HANDLE hSCManager
, DWORD dwServiceType
,
2178 DWORD dwServiceState
, LPENUM_SERVICE_STATUSW lpServices
,
2179 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
2180 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
)
2182 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager
,
2183 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
2184 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
);
2185 SetLastError (ERROR_ACCESS_DENIED
);
2189 /******************************************************************************
2190 * EnumServicesStatusExA [ADVAPI32.@]
2193 EnumServicesStatusExA(SC_HANDLE hSCManager
, SC_ENUM_TYPE InfoLevel
, DWORD dwServiceType
,
2194 DWORD dwServiceState
, LPBYTE lpServices
, DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
2195 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
, LPCSTR pszGroupName
)
2197 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager
, InfoLevel
,
2198 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
2199 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
, debugstr_a(pszGroupName
));
2200 SetLastError (ERROR_ACCESS_DENIED
);
2204 /******************************************************************************
2205 * EnumServicesStatusExW [ADVAPI32.@]
2208 EnumServicesStatusExW(SC_HANDLE hSCManager
, SC_ENUM_TYPE InfoLevel
, DWORD dwServiceType
,
2209 DWORD dwServiceState
, LPBYTE lpServices
, DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
2210 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
, LPCWSTR pszGroupName
)
2212 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager
, InfoLevel
,
2213 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
2214 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
, debugstr_w(pszGroupName
));
2215 SetLastError (ERROR_ACCESS_DENIED
);
2219 /******************************************************************************
2220 * GetServiceKeyNameA [ADVAPI32.@]
2222 BOOL WINAPI
GetServiceKeyNameA( SC_HANDLE hSCManager
, LPCSTR lpDisplayName
,
2223 LPSTR lpServiceName
, LPDWORD lpcchBuffer
)
2225 FIXME("%p %s %p %p\n", hSCManager
, debugstr_a(lpDisplayName
), lpServiceName
, lpcchBuffer
);
2229 /******************************************************************************
2230 * GetServiceKeyNameW [ADVAPI32.@]
2232 BOOL WINAPI
GetServiceKeyNameW( SC_HANDLE hSCManager
, LPCWSTR lpDisplayName
,
2233 LPWSTR lpServiceName
, LPDWORD lpcchBuffer
)
2235 FIXME("%p %s %p %p\n", hSCManager
, debugstr_w(lpDisplayName
), lpServiceName
, lpcchBuffer
);
2239 /******************************************************************************
2240 * QueryServiceLockStatusA [ADVAPI32.@]
2242 BOOL WINAPI
QueryServiceLockStatusA( SC_HANDLE hSCManager
,
2243 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus
,
2244 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
2246 FIXME("%p %p %08x %p\n", hSCManager
, lpLockStatus
, cbBufSize
, pcbBytesNeeded
);
2251 /******************************************************************************
2252 * QueryServiceLockStatusW [ADVAPI32.@]
2254 BOOL WINAPI
QueryServiceLockStatusW( SC_HANDLE hSCManager
,
2255 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus
,
2256 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
2258 FIXME("%p %p %08x %p\n", hSCManager
, lpLockStatus
, cbBufSize
, pcbBytesNeeded
);
2263 /******************************************************************************
2264 * GetServiceDisplayNameA [ADVAPI32.@]
2266 BOOL WINAPI
GetServiceDisplayNameA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
2267 LPSTR lpDisplayName
, LPDWORD lpcchBuffer
)
2269 LPWSTR lpServiceNameW
, lpDisplayNameW
= NULL
;
2270 DWORD size
, sizeW
, GLE
;
2273 TRACE("%p %s %p %p\n", hSCManager
,
2274 debugstr_a(lpServiceName
), lpDisplayName
, lpcchBuffer
);
2276 lpServiceNameW
= SERV_dup(lpServiceName
);
2277 lpDisplayNameW
= HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer
* sizeof(WCHAR
));
2279 size
= sizeW
= *lpcchBuffer
;
2280 ret
= GetServiceDisplayNameW(hSCManager
, lpServiceNameW
,
2281 lpDisplayName
? lpDisplayNameW
: NULL
,
2283 /* Last error will be set by GetServiceDisplayNameW and must be preserved */
2284 GLE
= GetLastError();
2286 if (!lpDisplayName
&& lpcchBuffer
&& !ret
&& (GLE
== ERROR_INSUFFICIENT_BUFFER
))
2288 /* Request for buffersize.
2290 * Only set the size for ERROR_INSUFFICIENT_BUFFER
2294 else if (lpDisplayName
&& lpcchBuffer
&& !ret
)
2296 /* Request for displayname.
2298 * size only has to be set if this fails
2303 WideCharToMultiByte(CP_ACP
, 0, lpDisplayNameW
, (sizeW
+ 1), lpDisplayName
,
2304 *lpcchBuffer
, NULL
, NULL
);
2306 *lpcchBuffer
= size
;
2308 HeapFree(GetProcessHeap(), 0, lpDisplayNameW
);
2309 SERV_free(lpServiceNameW
);
2315 /******************************************************************************
2316 * GetServiceDisplayNameW [ADVAPI32.@]
2318 BOOL WINAPI
GetServiceDisplayNameW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
2319 LPWSTR lpDisplayName
, LPDWORD lpcchBuffer
)
2321 struct sc_manager
*hscm
;
2325 TRACE("%p %s %p %p\n", hSCManager
,
2326 debugstr_w(lpServiceName
), lpDisplayName
, lpcchBuffer
);
2328 hscm
= sc_handle_get_handle_data(hSCManager
, SC_HTYPE_MANAGER
);
2331 SetLastError(ERROR_INVALID_HANDLE
);
2337 SetLastError(ERROR_INVALID_ADDRESS
);
2341 size
= *lpcchBuffer
* sizeof(WCHAR
);
2342 ret
= RegGetValueW(hscm
->hkey
, lpServiceName
, szDisplayName
, RRF_RT_REG_SZ
, &type
, lpDisplayName
, &size
);
2343 if (!ret
&& !lpDisplayName
&& size
)
2344 ret
= ERROR_MORE_DATA
;
2348 if (lpDisplayName
&& *lpcchBuffer
) *lpDisplayName
= 0;
2350 if (ret
== ERROR_MORE_DATA
)
2352 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2353 *lpcchBuffer
= (size
/ sizeof(WCHAR
)) - 1;
2360 /* Always return the correct needed size on success */
2361 *lpcchBuffer
= (size
/ sizeof(WCHAR
)) - 1;
2366 /******************************************************************************
2367 * ChangeServiceConfigW [ADVAPI32.@]
2369 BOOL WINAPI
ChangeServiceConfigW( SC_HANDLE hService
, DWORD dwServiceType
,
2370 DWORD dwStartType
, DWORD dwErrorControl
, LPCWSTR lpBinaryPathName
,
2371 LPCWSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
, LPCWSTR lpDependencies
,
2372 LPCWSTR lpServiceStartName
, LPCWSTR lpPassword
, LPCWSTR lpDisplayName
)
2374 struct reg_value val
[10];
2375 struct sc_service
*hsvc
;
2376 DWORD r
= ERROR_SUCCESS
;
2380 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2381 hService
, dwServiceType
, dwStartType
, dwErrorControl
,
2382 debugstr_w(lpBinaryPathName
), debugstr_w(lpLoadOrderGroup
),
2383 lpdwTagId
, lpDependencies
, debugstr_w(lpServiceStartName
),
2384 debugstr_w(lpPassword
), debugstr_w(lpDisplayName
) );
2386 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
2389 SetLastError( ERROR_INVALID_HANDLE
);
2394 if( dwServiceType
!= SERVICE_NO_CHANGE
)
2395 service_set_dword( &val
[n
++], szType
, &dwServiceType
);
2397 if( dwStartType
!= SERVICE_NO_CHANGE
)
2398 service_set_dword( &val
[n
++], szStart
, &dwStartType
);
2400 if( dwErrorControl
!= SERVICE_NO_CHANGE
)
2401 service_set_dword( &val
[n
++], szError
, &dwErrorControl
);
2403 if( lpBinaryPathName
)
2404 service_set_string( &val
[n
++], szImagePath
, lpBinaryPathName
);
2406 if( lpLoadOrderGroup
)
2407 service_set_string( &val
[n
++], szGroup
, lpLoadOrderGroup
);
2409 /* FIXME: lpDependencies is used to create/change both DependOnService and DependOnGroup
2410 * There is no such key as what szDependencies refers to */
2411 if( lpDependencies
)
2412 service_set_multi_string( &val
[n
++], szDependencies
, lpDependencies
);
2415 FIXME("ignoring password\n");
2417 if( lpServiceStartName
)
2418 service_set_string( &val
[n
++], szObjectName
, lpServiceStartName
);
2420 r
= service_write_values( hsvc
->hkey
, val
, n
);
2422 return (r
== ERROR_SUCCESS
) ? TRUE
: FALSE
;
2425 /******************************************************************************
2426 * ChangeServiceConfigA [ADVAPI32.@]
2428 BOOL WINAPI
ChangeServiceConfigA( SC_HANDLE hService
, DWORD dwServiceType
,
2429 DWORD dwStartType
, DWORD dwErrorControl
, LPCSTR lpBinaryPathName
,
2430 LPCSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
, LPCSTR lpDependencies
,
2431 LPCSTR lpServiceStartName
, LPCSTR lpPassword
, LPCSTR lpDisplayName
)
2433 LPWSTR wBinaryPathName
, wLoadOrderGroup
, wDependencies
;
2434 LPWSTR wServiceStartName
, wPassword
, wDisplayName
;
2437 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2438 hService
, dwServiceType
, dwStartType
, dwErrorControl
,
2439 debugstr_a(lpBinaryPathName
), debugstr_a(lpLoadOrderGroup
),
2440 lpdwTagId
, lpDependencies
, debugstr_a(lpServiceStartName
),
2441 debugstr_a(lpPassword
), debugstr_a(lpDisplayName
) );
2443 wBinaryPathName
= SERV_dup( lpBinaryPathName
);
2444 wLoadOrderGroup
= SERV_dup( lpLoadOrderGroup
);
2445 wDependencies
= SERV_dupmulti( lpDependencies
);
2446 wServiceStartName
= SERV_dup( lpServiceStartName
);
2447 wPassword
= SERV_dup( lpPassword
);
2448 wDisplayName
= SERV_dup( lpDisplayName
);
2450 r
= ChangeServiceConfigW( hService
, dwServiceType
,
2451 dwStartType
, dwErrorControl
, wBinaryPathName
,
2452 wLoadOrderGroup
, lpdwTagId
, wDependencies
,
2453 wServiceStartName
, wPassword
, wDisplayName
);
2455 SERV_free( wBinaryPathName
);
2456 SERV_free( wLoadOrderGroup
);
2457 SERV_free( wDependencies
);
2458 SERV_free( wServiceStartName
);
2459 SERV_free( wPassword
);
2460 SERV_free( wDisplayName
);
2465 /******************************************************************************
2466 * ChangeServiceConfig2A [ADVAPI32.@]
2468 BOOL WINAPI
ChangeServiceConfig2A( SC_HANDLE hService
, DWORD dwInfoLevel
,
2473 TRACE("%p %d %p\n",hService
, dwInfoLevel
, lpInfo
);
2475 if (dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
2477 LPSERVICE_DESCRIPTIONA sd
= (LPSERVICE_DESCRIPTIONA
) lpInfo
;
2478 SERVICE_DESCRIPTIONW sdw
;
2480 sdw
.lpDescription
= SERV_dup( sd
->lpDescription
);
2482 r
= ChangeServiceConfig2W( hService
, dwInfoLevel
, &sdw
);
2484 SERV_free( sdw
.lpDescription
);
2486 else if (dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
2488 LPSERVICE_FAILURE_ACTIONSA fa
= (LPSERVICE_FAILURE_ACTIONSA
) lpInfo
;
2489 SERVICE_FAILURE_ACTIONSW faw
;
2491 faw
.dwResetPeriod
= fa
->dwResetPeriod
;
2492 faw
.lpRebootMsg
= SERV_dup( fa
->lpRebootMsg
);
2493 faw
.lpCommand
= SERV_dup( fa
->lpCommand
);
2494 faw
.cActions
= fa
->cActions
;
2495 faw
.lpsaActions
= fa
->lpsaActions
;
2497 r
= ChangeServiceConfig2W( hService
, dwInfoLevel
, &faw
);
2499 SERV_free( faw
.lpRebootMsg
);
2500 SERV_free( faw
.lpCommand
);
2503 SetLastError( ERROR_INVALID_PARAMETER
);
2508 /******************************************************************************
2509 * ChangeServiceConfig2W [ADVAPI32.@]
2511 BOOL WINAPI
ChangeServiceConfig2W( SC_HANDLE hService
, DWORD dwInfoLevel
,
2515 struct sc_service
*hsvc
;
2517 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
2520 SetLastError( ERROR_INVALID_HANDLE
);
2525 if (dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
2527 static const WCHAR szDescription
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2528 LPSERVICE_DESCRIPTIONW sd
= (LPSERVICE_DESCRIPTIONW
)lpInfo
;
2529 if (sd
->lpDescription
)
2531 TRACE("Setting Description to %s\n",debugstr_w(sd
->lpDescription
));
2532 if (sd
->lpDescription
[0] == 0)
2533 RegDeleteValueW(hKey
,szDescription
);
2535 RegSetValueExW(hKey
, szDescription
, 0, REG_SZ
,
2536 (LPVOID
)sd
->lpDescription
,
2537 sizeof(WCHAR
)*(strlenW(sd
->lpDescription
)+1));
2541 FIXME("STUB: %p %d %p\n",hService
, dwInfoLevel
, lpInfo
);
2545 /******************************************************************************
2546 * QueryServiceObjectSecurity [ADVAPI32.@]
2548 BOOL WINAPI
QueryServiceObjectSecurity(SC_HANDLE hService
,
2549 SECURITY_INFORMATION dwSecurityInformation
,
2550 PSECURITY_DESCRIPTOR lpSecurityDescriptor
,
2551 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
2555 FIXME("%p %d %p %u %p\n", hService
, dwSecurityInformation
,
2556 lpSecurityDescriptor
, cbBufSize
, pcbBytesNeeded
);
2558 InitializeSecurityDescriptor(lpSecurityDescriptor
, SECURITY_DESCRIPTOR_REVISION
);
2560 pACL
= HeapAlloc( GetProcessHeap(), 0, sizeof(ACL
) );
2561 InitializeAcl(pACL
, sizeof(ACL
), ACL_REVISION
);
2562 SetSecurityDescriptorDacl(lpSecurityDescriptor
, TRUE
, pACL
, TRUE
);
2566 /******************************************************************************
2567 * SetServiceObjectSecurity [ADVAPI32.@]
2569 BOOL WINAPI
SetServiceObjectSecurity(SC_HANDLE hService
,
2570 SECURITY_INFORMATION dwSecurityInformation
,
2571 PSECURITY_DESCRIPTOR lpSecurityDescriptor
)
2573 FIXME("%p %d %p\n", hService
, dwSecurityInformation
, lpSecurityDescriptor
);
2577 /******************************************************************************
2578 * SetServiceBits [ADVAPI32.@]
2580 BOOL WINAPI
SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus
,
2581 DWORD dwServiceBits
,
2583 BOOL bUpdateImmediately
)
2585 FIXME("%p %08x %x %x\n", hServiceStatus
, dwServiceBits
,
2586 bSetBitsOn
, bUpdateImmediately
);
2590 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerExA( LPCSTR lpServiceName
,
2591 LPHANDLER_FUNCTION_EX lpHandlerProc
, LPVOID lpContext
)
2593 FIXME("%s %p %p\n", debugstr_a(lpServiceName
), lpHandlerProc
, lpContext
);
2597 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName
,
2598 LPHANDLER_FUNCTION_EX lpHandlerProc
, LPVOID lpContext
)
2600 service_data
*service
;
2601 SERVICE_STATUS_HANDLE handle
= 0;
2603 TRACE("%s %p %p\n", debugstr_w(lpServiceName
), lpHandlerProc
, lpContext
);
2605 EnterCriticalSection( &service_cs
);
2606 LIST_FOR_EACH_ENTRY( service
, &service_list
, service_data
, entry
)
2608 if(!strcmpW(lpServiceName
, service
->name
))
2610 service
->handler
.handler_ex
= lpHandlerProc
;
2611 service
->context
= lpContext
;
2612 service
->extended
= TRUE
;
2613 handle
= (SERVICE_STATUS_HANDLE
)service
;
2617 LeaveCriticalSection( &service_cs
);