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 szLocalSystem
[] = {'L','o','c','a','l','S','y','s','t','e','m',0};
43 static const WCHAR szServiceManagerKey
[] = { 'S','y','s','t','e','m','\\',
44 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
45 'S','e','r','v','i','c','e','s',0 };
46 static const WCHAR szSCMLock
[] = {'A','D','V','A','P','I','_','S','C','M',
49 static const GENERIC_MAPPING scm_generic
= {
50 (STANDARD_RIGHTS_READ
| SC_MANAGER_ENUMERATE_SERVICE
| SC_MANAGER_QUERY_LOCK_STATUS
),
51 (STANDARD_RIGHTS_WRITE
| SC_MANAGER_CREATE_SERVICE
| SC_MANAGER_MODIFY_BOOT_CONFIG
),
52 (STANDARD_RIGHTS_EXECUTE
| SC_MANAGER_CONNECT
| SC_MANAGER_LOCK
),
56 static const GENERIC_MAPPING svc_generic
= {
57 (STANDARD_RIGHTS_READ
| SERVICE_QUERY_CONFIG
| SERVICE_QUERY_STATUS
| SERVICE_INTERROGATE
| SERVICE_ENUMERATE_DEPENDENTS
),
58 (STANDARD_RIGHTS_WRITE
| SERVICE_CHANGE_CONFIG
),
59 (STANDARD_RIGHTS_EXECUTE
| SERVICE_START
| SERVICE_STOP
| SERVICE_PAUSE_CONTINUE
| SERVICE_USER_DEFINED_CONTROL
),
63 typedef struct service_start_info_t
70 #define WINESERV_STARTINFO 1
71 #define WINESERV_GETSTATUS 2
72 #define WINESERV_SENDCONTROL 3
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 (same behaviour as strdup)
202 * NOTE: the caller of those functions is responsible for calling HeapFree
203 * in order to release the memory allocated by those functions.
205 static inline LPWSTR
SERV_dup( LPCSTR str
)
212 len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
213 wstr
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof (WCHAR
) );
214 MultiByteToWideChar( CP_ACP
, 0, str
, -1, wstr
, len
);
218 static inline LPWSTR
SERV_dupmulti(LPCSTR str
)
226 len
+= MultiByteToWideChar( CP_ACP
, 0, &str
[n
], -1, NULL
, 0 );
227 n
+= (strlen( &str
[n
] ) + 1);
232 wstr
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof (WCHAR
) );
233 MultiByteToWideChar( CP_ACP
, 0, str
, n
, wstr
, len
);
237 /******************************************************************************
238 * registry access functions and data
240 static const WCHAR szDisplayName
[] = {
241 'D','i','s','p','l','a','y','N','a','m','e', 0 };
242 static const WCHAR szType
[] = {'T','y','p','e',0};
243 static const WCHAR szStart
[] = {'S','t','a','r','t',0};
244 static const WCHAR szError
[] = {
245 'E','r','r','o','r','C','o','n','t','r','o','l', 0};
246 static const WCHAR szImagePath
[] = {'I','m','a','g','e','P','a','t','h',0};
247 static const WCHAR szGroup
[] = {'G','r','o','u','p',0};
248 static const WCHAR szDependencies
[] = {
249 'D','e','p','e','n','d','e','n','c','i','e','s',0};
250 static const WCHAR szDependOnService
[] = {
251 'D','e','p','e','n','d','O','n','S','e','r','v','i','c','e',0};
252 static const WCHAR szObjectName
[] = {
253 'O','b','j','e','c','t','N','a','m','e',0};
254 static const WCHAR szTag
[] = {
264 static inline void service_set_value( struct reg_value
*val
,
265 DWORD type
, LPCWSTR name
, LPCVOID data
, DWORD size
)
273 static inline void service_set_dword( struct reg_value
*val
,
274 LPCWSTR name
, const DWORD
*data
)
276 service_set_value( val
, REG_DWORD
, name
, data
, sizeof (DWORD
));
279 static inline void service_set_string( struct reg_value
*val
,
280 LPCWSTR name
, LPCWSTR string
)
282 DWORD len
= (lstrlenW(string
)+1) * sizeof (WCHAR
);
283 service_set_value( val
, REG_SZ
, name
, string
, len
);
286 static inline void service_set_multi_string( struct reg_value
*val
,
287 LPCWSTR name
, LPCWSTR string
)
291 /* determine the length of a double null terminated multi string */
293 len
+= (lstrlenW( &string
[ len
] )+1);
294 } while ( string
[ len
++ ] );
296 len
*= sizeof (WCHAR
);
297 service_set_value( val
, REG_MULTI_SZ
, name
, string
, len
);
300 static inline LONG
service_write_values( HKEY hKey
,
301 const struct reg_value
*val
, int n
)
303 LONG r
= ERROR_SUCCESS
;
308 r
= RegSetValueExW(hKey
, val
[i
].name
, 0, val
[i
].type
,
309 (const BYTE
*)val
[i
].data
, val
[i
].size
);
310 if( r
!= ERROR_SUCCESS
)
316 /******************************************************************************
317 * Service IPC functions
319 static LPWSTR
service_get_pipe_name(LPCWSTR service
)
321 static const WCHAR prefix
[] = { '\\','\\','.','\\','p','i','p','e','\\',
322 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
326 len
= sizeof prefix
+ strlenW(service
)*sizeof(WCHAR
);
327 name
= HeapAlloc(GetProcessHeap(), 0, len
);
328 strcpyW(name
, prefix
);
329 strcatW(name
, service
);
333 static HANDLE
service_open_pipe(LPCWSTR service
)
335 LPWSTR szPipe
= service_get_pipe_name( service
);
336 HANDLE handle
= INVALID_HANDLE_VALUE
;
339 handle
= CreateFileW(szPipe
, GENERIC_READ
|GENERIC_WRITE
,
340 0, NULL
, OPEN_ALWAYS
, 0, NULL
);
341 if (handle
!= INVALID_HANDLE_VALUE
)
343 if (GetLastError() != ERROR_PIPE_BUSY
)
345 } while (WaitNamedPipeW(szPipe
, NMPWAIT_WAIT_FOREVER
));
346 HeapFree(GetProcessHeap(), 0, szPipe
);
351 /******************************************************************************
352 * service_get_event_handle
354 static HANDLE
service_get_event_handle(LPCWSTR service
)
356 static const WCHAR prefix
[] = {
357 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
362 len
= sizeof prefix
+ strlenW(service
)*sizeof(WCHAR
);
363 name
= HeapAlloc(GetProcessHeap(), 0, len
);
364 strcpyW(name
, prefix
);
365 strcatW(name
, service
);
366 handle
= CreateEventW(NULL
, TRUE
, FALSE
, name
);
367 HeapFree(GetProcessHeap(), 0, name
);
371 /******************************************************************************
374 * Call into the main service routine provided by StartServiceCtrlDispatcher.
376 static DWORD WINAPI
service_thread(LPVOID arg
)
378 service_data
*info
= arg
;
379 LPWSTR str
= info
->args
;
380 DWORD argc
= 0, len
= 0;
386 len
+= strlenW(&str
[len
]) + 1;
393 info
->proc
.w(0, NULL
);
395 info
->proc
.a(0, NULL
);
403 argv
= HeapAlloc(GetProcessHeap(), 0, (argc
+1)*sizeof(LPWSTR
));
404 for (argc
=0, p
=str
; *p
; p
+= strlenW(p
) + 1)
408 info
->proc
.w(argc
, argv
);
409 HeapFree(GetProcessHeap(), 0, argv
);
413 LPSTR strA
, *argv
, p
;
416 lenA
= WideCharToMultiByte(CP_ACP
,0, str
, len
, NULL
, 0, NULL
, NULL
);
417 strA
= HeapAlloc(GetProcessHeap(), 0, lenA
);
418 WideCharToMultiByte(CP_ACP
,0, str
, len
, strA
, lenA
, NULL
, NULL
);
420 argv
= HeapAlloc(GetProcessHeap(), 0, (argc
+1)*sizeof(LPSTR
));
421 for (argc
=0, p
=strA
; *p
; p
+= strlen(p
) + 1)
425 info
->proc
.a(argc
, argv
);
426 HeapFree(GetProcessHeap(), 0, argv
);
427 HeapFree(GetProcessHeap(), 0, strA
);
432 /******************************************************************************
433 * service_handle_start
435 static BOOL
service_handle_start(HANDLE pipe
, service_data
*service
, DWORD count
)
437 DWORD read
= 0, result
= 0;
441 TRACE("%p %p %d\n", pipe
, service
, count
);
443 args
= HeapAlloc(GetProcessHeap(), 0, count
*sizeof(WCHAR
));
444 r
= ReadFile(pipe
, args
, count
*sizeof(WCHAR
), &read
, NULL
);
445 if (!r
|| count
!=read
/sizeof(WCHAR
) || args
[count
-1])
447 ERR("pipe read failed r = %d count = %d read = %d args[n-1]=%s\n",
448 r
, count
, read
, debugstr_wn(args
, count
));
454 WARN("service is not stopped\n");
455 result
= ERROR_SERVICE_ALREADY_RUNNING
;
459 HeapFree(GetProcessHeap(), 0, service
->args
);
460 service
->args
= args
;
462 service
->thread
= CreateThread( NULL
, 0, service_thread
,
466 HeapFree(GetProcessHeap(), 0, args
);
467 WriteFile( pipe
, &result
, sizeof result
, &read
, NULL
);
472 /******************************************************************************
473 * service_send_start_message
475 static BOOL
service_send_start_message(HANDLE pipe
, LPCWSTR
*argv
, DWORD argc
)
477 DWORD i
, len
, count
, result
;
478 service_start_info
*ssi
;
482 TRACE("%p %p %d\n", pipe
, argv
, argc
);
484 /* calculate how much space do we need to send the startup info */
486 for (i
=0; i
<argc
; i
++)
487 len
+= strlenW(argv
[i
])+1;
489 ssi
= HeapAlloc(GetProcessHeap(),0,sizeof *ssi
+ (len
-1)*sizeof(WCHAR
));
490 ssi
->cmd
= WINESERV_STARTINFO
;
493 /* copy service args into a single buffer*/
495 for (i
=0; i
<argc
; i
++)
502 r
= WriteFile(pipe
, ssi
, sizeof *ssi
+ len
*sizeof(WCHAR
), &count
, NULL
);
505 r
= ReadFile(pipe
, &result
, sizeof result
, &count
, NULL
);
508 SetLastError(result
);
513 HeapFree(GetProcessHeap(),0,ssi
);
518 /******************************************************************************
519 * service_handle_get_status
521 static BOOL
service_handle_get_status(HANDLE pipe
, const service_data
*service
)
525 return WriteFile(pipe
, &service
->status
,
526 sizeof service
->status
, &count
, NULL
);
529 /******************************************************************************
532 static BOOL
service_get_status(HANDLE pipe
, LPSERVICE_STATUS_PROCESS status
)
534 DWORD cmd
[2], count
= 0;
537 cmd
[0] = WINESERV_GETSTATUS
;
539 r
= WriteFile( pipe
, cmd
, sizeof cmd
, &count
, NULL
);
540 if (!r
|| count
!= sizeof cmd
)
542 ERR("service protocol error - failed to write pipe!\n");
545 r
= ReadFile( pipe
, status
, sizeof *status
, &count
, NULL
);
546 if (!r
|| count
!= sizeof *status
)
547 ERR("service protocol error - failed to read pipe "
548 "r = %d count = %d!\n", r
, count
);
552 /******************************************************************************
553 * service_send_control
555 static BOOL
service_send_control(HANDLE pipe
, DWORD dwControl
, DWORD
*result
)
557 DWORD cmd
[2], count
= 0;
560 cmd
[0] = WINESERV_SENDCONTROL
;
562 r
= WriteFile(pipe
, cmd
, sizeof cmd
, &count
, NULL
);
563 if (!r
|| count
!= sizeof cmd
)
565 ERR("service protocol error - failed to write pipe!\n");
568 r
= ReadFile(pipe
, result
, sizeof *result
, &count
, NULL
);
569 if (!r
|| count
!= sizeof *result
)
570 ERR("service protocol error - failed to read pipe "
571 "r = %d count = %d!\n", r
, count
);
575 /******************************************************************************
576 * service_accepts_control
578 static BOOL
service_accepts_control(const service_data
*service
, DWORD dwControl
)
580 DWORD a
= service
->status
.dwControlsAccepted
;
584 case SERVICE_CONTROL_INTERROGATE
:
586 case SERVICE_CONTROL_STOP
:
587 if (a
&SERVICE_ACCEPT_STOP
)
590 case SERVICE_CONTROL_SHUTDOWN
:
591 if (a
&SERVICE_ACCEPT_SHUTDOWN
)
594 case SERVICE_CONTROL_PAUSE
:
595 case SERVICE_CONTROL_CONTINUE
:
596 if (a
&SERVICE_ACCEPT_PAUSE_CONTINUE
)
599 case SERVICE_CONTROL_PARAMCHANGE
:
600 if (a
&SERVICE_ACCEPT_PARAMCHANGE
)
603 case SERVICE_CONTROL_NETBINDADD
:
604 case SERVICE_CONTROL_NETBINDREMOVE
:
605 case SERVICE_CONTROL_NETBINDENABLE
:
606 case SERVICE_CONTROL_NETBINDDISABLE
:
607 if (a
&SERVICE_ACCEPT_NETBINDCHANGE
)
610 if (!service
->extended
)
614 case SERVICE_CONTROL_HARDWAREPROFILECHANGE
:
615 if (a
&SERVICE_ACCEPT_HARDWAREPROFILECHANGE
)
618 case SERVICE_CONTROL_POWEREVENT
:
619 if (a
&SERVICE_ACCEPT_POWEREVENT
)
622 case SERVICE_CONTROL_SESSIONCHANGE
:
623 if (a
&SERVICE_ACCEPT_SESSIONCHANGE
)
630 /******************************************************************************
631 * service_handle_control
633 static BOOL
service_handle_control(HANDLE pipe
, service_data
*service
,
636 DWORD count
, ret
= ERROR_INVALID_SERVICE_CONTROL
;
638 TRACE("received control %d\n", dwControl
);
640 if (service_accepts_control(service
, dwControl
))
642 if (service
->extended
&& service
->handler
.handler_ex
)
644 service
->handler
.handler_ex(dwControl
, 0, NULL
, service
->context
);
647 else if (service
->handler
.handler
)
649 service
->handler
.handler(dwControl
);
653 return WriteFile(pipe
, &ret
, sizeof ret
, &count
, NULL
);
656 /******************************************************************************
657 * service_reap_thread
659 static DWORD
service_reap_thread(service_data
*service
)
663 if (!service
->thread
)
665 GetExitCodeThread(service
->thread
, &exitcode
);
666 if (exitcode
!=STILL_ACTIVE
)
668 CloseHandle(service
->thread
);
674 /******************************************************************************
675 * service_control_dispatcher
677 static DWORD WINAPI
service_control_dispatcher(LPVOID arg
)
679 service_data
*service
= arg
;
683 TRACE("%p %s\n", service
, debugstr_w(service
->name
));
685 /* create a pipe to talk to the rest of the world with */
686 name
= service_get_pipe_name(service
->name
);
687 pipe
= CreateNamedPipeW(name
, PIPE_ACCESS_DUPLEX
,
688 PIPE_TYPE_BYTE
|PIPE_WAIT
, 1, 256, 256, 10000, NULL
);
689 HeapFree(GetProcessHeap(), 0, name
);
691 /* let the process who started us know we've tried to create a pipe */
692 event
= service_get_event_handle(service
->name
);
696 if (pipe
==INVALID_HANDLE_VALUE
)
698 ERR("failed to create pipe for %s, error = %d\n",
699 debugstr_w(service
->name
), GetLastError());
703 /* dispatcher loop */
707 DWORD count
, req
[2] = {0,0};
709 r
= ConnectNamedPipe(pipe
, NULL
);
710 if (!r
&& GetLastError() != ERROR_PIPE_CONNECTED
)
712 ERR("pipe connect failed\n");
716 r
= ReadFile( pipe
, &req
, sizeof req
, &count
, NULL
);
717 if (!r
|| count
!=sizeof req
)
719 ERR("pipe read failed\n");
723 service_reap_thread(service
);
725 /* handle the request */
728 case WINESERV_STARTINFO
:
729 service_handle_start(pipe
, service
, req
[1]);
731 case WINESERV_GETSTATUS
:
732 service_handle_get_status(pipe
, service
);
734 case WINESERV_SENDCONTROL
:
735 service_handle_control(pipe
, service
, req
[1]);
738 ERR("received invalid command %d length %d\n", req
[0], req
[1]);
741 FlushFileBuffers(pipe
);
742 DisconnectNamedPipe(pipe
);
749 /******************************************************************************
750 * service_run_threads
752 static BOOL
service_run_threads(void)
754 service_data
*service
;
758 EnterCriticalSection( &service_cs
);
760 count
= list_count( &service_list
);
762 TRACE("Starting %d pipe listener threads. Services running as process %d\n", count
, GetCurrentProcessId());
764 handles
= HeapAlloc(GetProcessHeap(), 0, sizeof(HANDLE
) * (count
+ 1));
766 handles
[n
++] = __wine_make_process_system();
768 LIST_FOR_EACH_ENTRY( service
, &service_list
, service_data
, entry
)
770 service
->status
.dwProcessId
= GetCurrentProcessId();
771 handles
[n
++] = CreateThread( NULL
, 0, service_control_dispatcher
,
774 assert(n
== count
+ 1);
776 LeaveCriticalSection( &service_cs
);
778 /* wait for all the threads to pack up and exit */
781 DWORD ret
= WaitForMultipleObjects( min(n
,MAXIMUM_WAIT_OBJECTS
), handles
, FALSE
, INFINITE
);
782 if (!ret
) /* system process event */
784 TRACE( "last user process exited, shutting down\n" );
785 /* FIXME: we should maybe send a shutdown control to running services */
788 if (ret
< MAXIMUM_WAIT_OBJECTS
)
790 CloseHandle( handles
[ret
] );
791 memmove( &handles
[ret
], &handles
[ret
+1], (n
- ret
- 1) * sizeof(HANDLE
) );
797 while (n
) CloseHandle( handles
[--n
] );
798 HeapFree(GetProcessHeap(), 0, handles
);
803 /******************************************************************************
804 * StartServiceCtrlDispatcherA [ADVAPI32.@]
806 * See StartServiceCtrlDispatcherW.
808 BOOL WINAPI
StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA
*servent
)
814 TRACE("%p\n", servent
);
816 EnterCriticalSection( &service_cs
);
817 while (servent
->lpServiceName
)
819 LPSTR name
= servent
->lpServiceName
;
821 len
= MultiByteToWideChar(CP_ACP
, 0, name
, -1, NULL
, 0);
822 sz
= len
*sizeof(WCHAR
) + sizeof *info
;
823 info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sz
);
824 MultiByteToWideChar(CP_ACP
, 0, name
, -1, info
->name
, len
);
825 info
->proc
.a
= servent
->lpServiceProc
;
826 info
->unicode
= FALSE
;
827 list_add_head( &service_list
, &info
->entry
);
830 LeaveCriticalSection( &service_cs
);
832 service_run_threads();
837 /******************************************************************************
838 * StartServiceCtrlDispatcherW [ADVAPI32.@]
840 * Connects a process containing one or more services to the service control
844 * servent [I] A list of the service names and service procedures
850 BOOL WINAPI
StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW
*servent
)
856 TRACE("%p\n", servent
);
858 EnterCriticalSection( &service_cs
);
859 while (servent
->lpServiceName
)
861 LPWSTR name
= servent
->lpServiceName
;
864 sz
= len
*sizeof(WCHAR
) + sizeof *info
;
865 info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sz
);
866 strcpyW(info
->name
, name
);
867 info
->proc
.w
= servent
->lpServiceProc
;
868 info
->unicode
= TRUE
;
869 list_add_head( &service_list
, &info
->entry
);
872 LeaveCriticalSection( &service_cs
);
874 service_run_threads();
879 /******************************************************************************
880 * LockServiceDatabase [ADVAPI32.@]
882 SC_LOCK WINAPI
LockServiceDatabase (SC_HANDLE hSCManager
)
886 TRACE("%p\n",hSCManager
);
888 ret
= CreateSemaphoreW( NULL
, 1, 1, szSCMLock
);
889 if( ret
&& GetLastError() == ERROR_ALREADY_EXISTS
)
893 SetLastError( ERROR_SERVICE_DATABASE_LOCKED
);
896 TRACE("returning %p\n", ret
);
901 /******************************************************************************
902 * UnlockServiceDatabase [ADVAPI32.@]
904 BOOL WINAPI
UnlockServiceDatabase (SC_LOCK ScLock
)
906 TRACE("%p\n",ScLock
);
908 return CloseHandle( ScLock
);
911 /******************************************************************************
912 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
914 SERVICE_STATUS_HANDLE WINAPI
915 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName
, LPHANDLER_FUNCTION lpfHandler
)
917 LPWSTR lpServiceNameW
;
918 SERVICE_STATUS_HANDLE ret
;
920 lpServiceNameW
= SERV_dup(lpServiceName
);
921 ret
= RegisterServiceCtrlHandlerW( lpServiceNameW
, lpfHandler
);
922 HeapFree(GetProcessHeap(), 0, lpServiceNameW
);
926 /******************************************************************************
927 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
933 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName
,
934 LPHANDLER_FUNCTION lpfHandler
)
936 service_data
*service
;
937 SERVICE_STATUS_HANDLE handle
= 0;
939 EnterCriticalSection( &service_cs
);
940 LIST_FOR_EACH_ENTRY( service
, &service_list
, service_data
, entry
)
942 if(!strcmpW(lpServiceName
, service
->name
))
944 service
->handler
.handler
= lpfHandler
;
945 handle
= (SERVICE_STATUS_HANDLE
)service
;
949 LeaveCriticalSection( &service_cs
);
953 /******************************************************************************
954 * SetServiceStatus [ADVAPI32.@]
961 SetServiceStatus( SERVICE_STATUS_HANDLE hService
, LPSERVICE_STATUS lpStatus
)
963 service_data
*service
;
966 TRACE("%p %x %x %x %x %x %x %x\n", hService
,
967 lpStatus
->dwServiceType
, lpStatus
->dwCurrentState
,
968 lpStatus
->dwControlsAccepted
, lpStatus
->dwWin32ExitCode
,
969 lpStatus
->dwServiceSpecificExitCode
, lpStatus
->dwCheckPoint
,
970 lpStatus
->dwWaitHint
);
972 EnterCriticalSection( &service_cs
);
973 LIST_FOR_EACH_ENTRY( service
, &service_list
, service_data
, entry
)
975 if(service
== (service_data
*)hService
)
977 memcpy( &service
->status
, lpStatus
, sizeof(SERVICE_STATUS
) );
978 TRACE("Set service status to %d\n",service
->status
.dwCurrentState
);
983 LeaveCriticalSection( &service_cs
);
989 /******************************************************************************
990 * OpenSCManagerA [ADVAPI32.@]
992 * Establish a connection to the service control manager and open its database.
995 * lpMachineName [I] Pointer to machine name string
996 * lpDatabaseName [I] Pointer to database name string
997 * dwDesiredAccess [I] Type of access
1000 * Success: A Handle to the service control manager database
1003 SC_HANDLE WINAPI
OpenSCManagerA( LPCSTR lpMachineName
, LPCSTR lpDatabaseName
,
1004 DWORD dwDesiredAccess
)
1006 LPWSTR lpMachineNameW
, lpDatabaseNameW
;
1009 lpMachineNameW
= SERV_dup(lpMachineName
);
1010 lpDatabaseNameW
= SERV_dup(lpDatabaseName
);
1011 ret
= OpenSCManagerW(lpMachineNameW
, lpDatabaseNameW
, dwDesiredAccess
);
1012 HeapFree(GetProcessHeap(), 0, lpDatabaseNameW
);
1013 HeapFree(GetProcessHeap(), 0, lpMachineNameW
);
1017 /******************************************************************************
1018 * OpenSCManagerW [ADVAPI32.@]
1020 * See OpenSCManagerA.
1022 SC_HANDLE WINAPI
OpenSCManagerW( LPCWSTR lpMachineName
, LPCWSTR lpDatabaseName
,
1023 DWORD dwDesiredAccess
)
1025 struct sc_manager
*manager
;
1028 DWORD new_mask
= dwDesiredAccess
;
1030 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName
),
1031 debugstr_w(lpDatabaseName
), dwDesiredAccess
);
1033 if( lpDatabaseName
&& lpDatabaseName
[0] )
1035 if( strcmpiW( lpDatabaseName
, SERVICES_ACTIVE_DATABASEW
) == 0 )
1037 /* noop, all right */
1039 else if( strcmpiW( lpDatabaseName
, SERVICES_FAILED_DATABASEW
) == 0 )
1041 SetLastError( ERROR_DATABASE_DOES_NOT_EXIST
);
1046 SetLastError( ERROR_INVALID_NAME
);
1051 manager
= sc_handle_alloc( SC_HTYPE_MANAGER
, sizeof (struct sc_manager
),
1052 sc_handle_destroy_manager
);
1056 r
= RegConnectRegistryW(lpMachineName
,HKEY_LOCAL_MACHINE
,&hReg
);
1057 if (r
!=ERROR_SUCCESS
)
1060 r
= RegCreateKeyW(hReg
, szServiceManagerKey
, &manager
->hkey
);
1061 RegCloseKey( hReg
);
1062 if (r
!=ERROR_SUCCESS
)
1065 RtlMapGenericMask(&new_mask
, &scm_generic
);
1066 manager
->dwAccess
= new_mask
;
1067 TRACE("returning %p (access : 0x%08x)\n", manager
, manager
->dwAccess
);
1069 return (SC_HANDLE
) &manager
->hdr
;
1072 sc_handle_free( &manager
->hdr
);
1077 /******************************************************************************
1078 * ControlService [ADVAPI32.@]
1080 * Send a control code to a service.
1083 * hService [I] Handle of the service control manager database
1084 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
1085 * lpServiceStatus [O] Destination for the status of the service, if available
1092 * Unlike M$' implementation, control requests are not serialized and may be
1093 * processed asynchronously.
1095 BOOL WINAPI
ControlService( SC_HANDLE hService
, DWORD dwControl
,
1096 LPSERVICE_STATUS lpServiceStatus
)
1098 struct sc_service
*hsvc
;
1102 TRACE("%p %d %p\n", hService
, dwControl
, lpServiceStatus
);
1104 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1107 SetLastError( ERROR_INVALID_HANDLE
);
1111 ret
= QueryServiceStatus(hService
, lpServiceStatus
);
1114 ERR("failed to query service status\n");
1115 SetLastError(ERROR_SERVICE_NOT_ACTIVE
);
1119 switch (lpServiceStatus
->dwCurrentState
)
1121 case SERVICE_STOPPED
:
1122 SetLastError(ERROR_SERVICE_NOT_ACTIVE
);
1124 case SERVICE_START_PENDING
:
1125 if (dwControl
==SERVICE_CONTROL_STOP
)
1128 case SERVICE_STOP_PENDING
:
1129 SetLastError(ERROR_SERVICE_CANNOT_ACCEPT_CTRL
);
1133 handle
= service_open_pipe(hsvc
->name
);
1134 if (handle
!=INVALID_HANDLE_VALUE
)
1136 DWORD result
= ERROR_SUCCESS
;
1137 ret
= service_send_control(handle
, dwControl
, &result
);
1138 CloseHandle(handle
);
1139 if (result
!=ERROR_SUCCESS
)
1141 SetLastError(result
);
1149 /******************************************************************************
1150 * CloseServiceHandle [ADVAPI32.@]
1152 * Close a handle to a service or the service control manager database.
1155 * hSCObject [I] Handle to service or service control manager database
1162 CloseServiceHandle( SC_HANDLE hSCObject
)
1164 TRACE("%p\n", hSCObject
);
1166 sc_handle_free( (struct sc_handle
*) hSCObject
);
1172 /******************************************************************************
1173 * OpenServiceA [ADVAPI32.@]
1175 * Open a handle to a service.
1178 * hSCManager [I] Handle of the service control manager database
1179 * lpServiceName [I] Name of the service to open
1180 * dwDesiredAccess [I] Access required to the service
1183 * Success: Handle to the service
1186 SC_HANDLE WINAPI
OpenServiceA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
1187 DWORD dwDesiredAccess
)
1189 LPWSTR lpServiceNameW
;
1192 TRACE("%p %s %d\n", hSCManager
, debugstr_a(lpServiceName
), dwDesiredAccess
);
1194 lpServiceNameW
= SERV_dup(lpServiceName
);
1195 ret
= OpenServiceW( hSCManager
, lpServiceNameW
, dwDesiredAccess
);
1196 HeapFree(GetProcessHeap(), 0, lpServiceNameW
);
1201 /******************************************************************************
1202 * OpenServiceW [ADVAPI32.@]
1206 SC_HANDLE WINAPI
OpenServiceW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
1207 DWORD dwDesiredAccess
)
1209 struct sc_manager
*hscm
;
1210 struct sc_service
*hsvc
;
1214 DWORD new_mask
= dwDesiredAccess
;
1216 TRACE("%p %s %d\n", hSCManager
, debugstr_w(lpServiceName
), dwDesiredAccess
);
1218 hscm
= sc_handle_get_handle_data( hSCManager
, SC_HTYPE_MANAGER
);
1221 SetLastError( ERROR_INVALID_HANDLE
);
1227 SetLastError(ERROR_INVALID_ADDRESS
);
1231 r
= RegOpenKeyExW( hscm
->hkey
, lpServiceName
, 0, KEY_ALL_ACCESS
, &hKey
);
1232 if (r
!=ERROR_SUCCESS
)
1234 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST
);
1238 len
= strlenW(lpServiceName
)+1;
1239 hsvc
= sc_handle_alloc( SC_HTYPE_SERVICE
,
1240 sizeof (struct sc_service
) + len
*sizeof(WCHAR
),
1241 sc_handle_destroy_service
);
1247 strcpyW( hsvc
->name
, lpServiceName
);
1250 RtlMapGenericMask(&new_mask
, &svc_generic
);
1251 hsvc
->dwAccess
= new_mask
;
1253 /* add reference to SCM handle */
1254 hscm
->hdr
.ref_count
++;
1257 TRACE("returning %p\n",hsvc
);
1259 return (SC_HANDLE
) &hsvc
->hdr
;
1262 /******************************************************************************
1263 * CreateServiceW [ADVAPI32.@]
1266 CreateServiceW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
1267 LPCWSTR lpDisplayName
, DWORD dwDesiredAccess
,
1268 DWORD dwServiceType
, DWORD dwStartType
,
1269 DWORD dwErrorControl
, LPCWSTR lpBinaryPathName
,
1270 LPCWSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
,
1271 LPCWSTR lpDependencies
, LPCWSTR lpServiceStartName
,
1272 LPCWSTR lpPassword
)
1274 struct sc_manager
*hscm
;
1275 struct sc_service
*hsvc
= NULL
;
1279 struct reg_value val
[10];
1281 DWORD new_mask
= dwDesiredAccess
;
1283 WCHAR buffer
[MAX_PATH
];
1284 BOOL displayname_exists
= FALSE
;
1286 TRACE("%p %s %s\n", hSCManager
,
1287 debugstr_w(lpServiceName
), debugstr_w(lpDisplayName
));
1289 hscm
= sc_handle_get_handle_data( hSCManager
, SC_HTYPE_MANAGER
);
1292 SetLastError( ERROR_INVALID_HANDLE
);
1296 if (!lpServiceName
|| !lpBinaryPathName
)
1298 SetLastError(ERROR_INVALID_ADDRESS
);
1302 if (!(hscm
->dwAccess
& SC_MANAGER_CREATE_SERVICE
))
1304 SetLastError(ERROR_ACCESS_DENIED
);
1308 if (!lpServiceName
[0])
1310 SetLastError(ERROR_INVALID_NAME
);
1314 if (!lpBinaryPathName
[0])
1316 SetLastError(ERROR_INVALID_PARAMETER
);
1320 /* ServiceType can only be one value (except for SERVICE_INTERACTIVE_PROCESS which can be used
1321 * together with SERVICE_WIN32_OWN_PROCESS or SERVICE_WIN32_SHARE_PROCESS when the service
1322 * runs under the LocalSystem account)
1324 switch (dwServiceType
)
1326 case SERVICE_KERNEL_DRIVER
:
1327 case SERVICE_FILE_SYSTEM_DRIVER
:
1328 case SERVICE_WIN32_OWN_PROCESS
:
1329 case SERVICE_WIN32_SHARE_PROCESS
:
1332 case SERVICE_WIN32_OWN_PROCESS
| SERVICE_INTERACTIVE_PROCESS
:
1333 case SERVICE_WIN32_SHARE_PROCESS
| SERVICE_INTERACTIVE_PROCESS
:
1334 /* FIXME : Do we need a more thorough check? */
1335 if (lpServiceStartName
)
1337 SetLastError(ERROR_INVALID_PARAMETER
);
1342 SetLastError(ERROR_INVALID_PARAMETER
);
1346 if (!lpServiceStartName
&& (dwServiceType
& SERVICE_WIN32
))
1347 lpServiceStartName
= szLocalSystem
;
1349 /* StartType can only be a single value (if several values are mixed the result is probably not what was intended) */
1350 if (dwStartType
> SERVICE_DISABLED
)
1352 SetLastError(ERROR_INVALID_PARAMETER
);
1356 /* SERVICE_BOOT_START and SERVICE_SYSTEM_START or only allowed for driver services */
1357 if (((dwStartType
== SERVICE_BOOT_START
) || (dwStartType
== SERVICE_SYSTEM_START
)) &&
1358 ((dwServiceType
& SERVICE_WIN32_OWN_PROCESS
) || (dwServiceType
& SERVICE_WIN32_SHARE_PROCESS
)))
1360 SetLastError(ERROR_INVALID_PARAMETER
);
1364 /* Loop through the registry to check if the service already exists and to
1365 * check if we can use the given displayname.
1366 * FIXME: Should we use EnumServicesStatusEx?
1368 len
= sizeof(buffer
);
1369 while (RegEnumKeyExW(hscm
->hkey
, index
, buffer
, &len
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
)
1373 /* The service already exists, so bail out */
1374 if(!lstrcmpiW(lpServiceName
, buffer
))
1376 SetLastError(ERROR_SERVICE_EXISTS
);
1380 /* The given displayname matches the found servicename. We don't bail out
1381 * as servicename is checked before a duplicate displayname
1383 if(!lstrcmpiW(lpDisplayName
, buffer
))
1384 displayname_exists
= TRUE
;
1386 if (RegOpenKeyExW(hscm
->hkey
, buffer
, 0, KEY_READ
, &service_key
) == ERROR_SUCCESS
)
1388 WCHAR name
[MAX_PATH
];
1389 DWORD size
= sizeof(name
);
1391 if (RegQueryValueExW(service_key
, szDisplayName
, NULL
, NULL
, (LPBYTE
)name
, &size
) == ERROR_SUCCESS
)
1393 /* The given displayname matches the found displayname */
1394 if (!lstrcmpiW(lpDisplayName
, name
))
1395 displayname_exists
= TRUE
;
1397 RegCloseKey(service_key
);
1400 len
= sizeof(buffer
);
1403 if (lpDisplayName
&& displayname_exists
)
1405 SetLastError(ERROR_DUPLICATE_SERVICE_NAME
);
1409 r
= RegCreateKeyExW(hscm
->hkey
, lpServiceName
, 0, NULL
,
1410 REG_OPTION_NON_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &hKey
, &dp
);
1411 if (r
!=ERROR_SUCCESS
)
1413 /* FIXME: Should we set an error? */
1418 service_set_string( &val
[n
++], szDisplayName
, lpDisplayName
);
1420 service_set_dword( &val
[n
++], szType
, &dwServiceType
);
1421 service_set_dword( &val
[n
++], szStart
, &dwStartType
);
1422 service_set_dword( &val
[n
++], szError
, &dwErrorControl
);
1424 service_set_string( &val
[n
++], szImagePath
, lpBinaryPathName
);
1426 if( lpLoadOrderGroup
)
1427 service_set_string( &val
[n
++], szGroup
, lpLoadOrderGroup
);
1429 /* FIXME: lpDependencies is used to create both DependOnService and DependOnGroup
1430 * There is no such key as what szDependencies refers to */
1431 if( lpDependencies
)
1432 service_set_multi_string( &val
[n
++], szDependencies
, lpDependencies
);
1435 FIXME("Don't know how to add a Password for a service.\n");
1437 if( lpServiceStartName
)
1438 service_set_string( &val
[n
++], szObjectName
, lpServiceStartName
);
1440 r
= service_write_values( hKey
, val
, n
);
1441 if( r
!= ERROR_SUCCESS
)
1444 len
= strlenW(lpServiceName
)+1;
1445 len
= sizeof (struct sc_service
) + len
*sizeof(WCHAR
);
1446 hsvc
= sc_handle_alloc( SC_HTYPE_SERVICE
, len
, sc_handle_destroy_service
);
1449 lstrcpyW( hsvc
->name
, lpServiceName
);
1452 RtlMapGenericMask(&new_mask
, &svc_generic
);
1453 hsvc
->dwAccess
= new_mask
;
1456 hscm
->hdr
.ref_count
++;
1458 return (SC_HANDLE
) &hsvc
->hdr
;
1461 RegCloseKey( hKey
);
1466 /******************************************************************************
1467 * CreateServiceA [ADVAPI32.@]
1470 CreateServiceA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
1471 LPCSTR lpDisplayName
, DWORD dwDesiredAccess
,
1472 DWORD dwServiceType
, DWORD dwStartType
,
1473 DWORD dwErrorControl
, LPCSTR lpBinaryPathName
,
1474 LPCSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
,
1475 LPCSTR lpDependencies
, LPCSTR lpServiceStartName
,
1478 LPWSTR lpServiceNameW
, lpDisplayNameW
, lpBinaryPathNameW
,
1479 lpLoadOrderGroupW
, lpDependenciesW
, lpServiceStartNameW
, lpPasswordW
;
1482 TRACE("%p %s %s\n", hSCManager
,
1483 debugstr_a(lpServiceName
), debugstr_a(lpDisplayName
));
1485 lpServiceNameW
= SERV_dup( lpServiceName
);
1486 lpDisplayNameW
= SERV_dup( lpDisplayName
);
1487 lpBinaryPathNameW
= SERV_dup( lpBinaryPathName
);
1488 lpLoadOrderGroupW
= SERV_dup( lpLoadOrderGroup
);
1489 lpDependenciesW
= SERV_dupmulti( lpDependencies
);
1490 lpServiceStartNameW
= SERV_dup( lpServiceStartName
);
1491 lpPasswordW
= SERV_dup( lpPassword
);
1493 r
= CreateServiceW( hSCManager
, lpServiceNameW
, lpDisplayNameW
,
1494 dwDesiredAccess
, dwServiceType
, dwStartType
, dwErrorControl
,
1495 lpBinaryPathNameW
, lpLoadOrderGroupW
, lpdwTagId
,
1496 lpDependenciesW
, lpServiceStartNameW
, lpPasswordW
);
1498 HeapFree( GetProcessHeap(), 0, lpServiceNameW
);
1499 HeapFree( GetProcessHeap(), 0, lpDisplayNameW
);
1500 HeapFree( GetProcessHeap(), 0, lpBinaryPathNameW
);
1501 HeapFree( GetProcessHeap(), 0, lpLoadOrderGroupW
);
1502 HeapFree( GetProcessHeap(), 0, lpDependenciesW
);
1503 HeapFree( GetProcessHeap(), 0, lpServiceStartNameW
);
1504 HeapFree( GetProcessHeap(), 0, lpPasswordW
);
1510 /******************************************************************************
1511 * DeleteService [ADVAPI32.@]
1513 * Delete a service from the service control manager database.
1516 * hService [I] Handle of the service to delete
1522 BOOL WINAPI
DeleteService( SC_HANDLE hService
)
1524 struct sc_service
*hsvc
;
1526 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1529 SetLastError( ERROR_INVALID_HANDLE
);
1533 if (!(hsvc
->dwAccess
& DELETE
))
1535 SetLastError(ERROR_ACCESS_DENIED
);
1539 /* Close the key to the service */
1540 RegCloseKey(hsvc
->hkey
);
1542 /* Delete the service under the Service Control Manager key */
1543 RegDeleteTreeW(hsvc
->scm
->hkey
, hsvc
->name
);
1551 /******************************************************************************
1552 * StartServiceA [ADVAPI32.@]
1557 * hService [I] Handle of service
1558 * dwNumServiceArgs [I] Number of arguments
1559 * lpServiceArgVectors [I] Address of array of argument strings
1562 * - NT implements this function using an obscure RPC call.
1563 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1564 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1565 * - This will only work for shared address space. How should the service
1566 * args be transferred when address spaces are separated?
1567 * - Can only start one service at a time.
1568 * - Has no concept of privilege.
1574 BOOL WINAPI
StartServiceA( SC_HANDLE hService
, DWORD dwNumServiceArgs
,
1575 LPCSTR
*lpServiceArgVectors
)
1577 LPWSTR
*lpwstr
=NULL
;
1581 TRACE("(%p,%d,%p)\n",hService
,dwNumServiceArgs
,lpServiceArgVectors
);
1583 if (dwNumServiceArgs
)
1584 lpwstr
= HeapAlloc( GetProcessHeap(), 0,
1585 dwNumServiceArgs
*sizeof(LPWSTR
) );
1587 for(i
=0; i
<dwNumServiceArgs
; i
++)
1588 lpwstr
[i
]=SERV_dup(lpServiceArgVectors
[i
]);
1590 r
= StartServiceW(hService
, dwNumServiceArgs
, (LPCWSTR
*)lpwstr
);
1592 if (dwNumServiceArgs
)
1594 for(i
=0; i
<dwNumServiceArgs
; i
++)
1595 HeapFree(GetProcessHeap(), 0, lpwstr
[i
]);
1596 HeapFree(GetProcessHeap(), 0, lpwstr
);
1602 /******************************************************************************
1603 * service_start_process [INTERNAL]
1605 static DWORD
service_start_process(struct sc_service
*hsvc
, LPDWORD ppid
)
1607 static const WCHAR _ImagePathW
[] = {'I','m','a','g','e','P','a','t','h',0};
1608 PROCESS_INFORMATION pi
;
1610 LPWSTR path
= NULL
, str
;
1611 DWORD type
, size
, ret
, svc_type
;
1615 size
= sizeof(svc_type
);
1616 if (RegQueryValueExW(hsvc
->hkey
, szType
, NULL
, &type
, (LPBYTE
)&svc_type
, &size
) || type
!= REG_DWORD
)
1619 if (svc_type
== SERVICE_KERNEL_DRIVER
)
1621 static const WCHAR winedeviceW
[] = {'\\','w','i','n','e','d','e','v','i','c','e','.','e','x','e',' ',0};
1622 DWORD len
= GetSystemDirectoryW( NULL
, 0 ) + sizeof(winedeviceW
)/sizeof(WCHAR
) + strlenW(hsvc
->name
);
1624 if (!(path
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) ))) return FALSE
;
1625 GetSystemDirectoryW( path
, len
);
1626 lstrcatW( path
, winedeviceW
);
1627 lstrcatW( path
, hsvc
->name
);
1631 /* read the executable path from the registry */
1633 ret
= RegQueryValueExW(hsvc
->hkey
, _ImagePathW
, NULL
, &type
, NULL
, &size
);
1634 if (ret
!=ERROR_SUCCESS
)
1636 str
= HeapAlloc(GetProcessHeap(),0,size
);
1637 ret
= RegQueryValueExW(hsvc
->hkey
, _ImagePathW
, NULL
, &type
, (LPBYTE
)str
, &size
);
1638 if (ret
==ERROR_SUCCESS
)
1640 size
= ExpandEnvironmentStringsW(str
,NULL
,0);
1641 path
= HeapAlloc(GetProcessHeap(),0,size
*sizeof(WCHAR
));
1642 ExpandEnvironmentStringsW(str
,path
,size
);
1644 HeapFree(GetProcessHeap(),0,str
);
1649 /* wait for the process to start and set an event or terminate */
1650 handles
[0] = service_get_event_handle( hsvc
->name
);
1651 ZeroMemory(&si
, sizeof(STARTUPINFOW
));
1652 si
.cb
= sizeof(STARTUPINFOW
);
1653 r
= CreateProcessW(NULL
, path
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
1656 if (ppid
) *ppid
= pi
.dwProcessId
;
1658 handles
[1] = pi
.hProcess
;
1659 ret
= WaitForMultipleObjectsEx(2, handles
, FALSE
, 30000, FALSE
);
1660 if(ret
!= WAIT_OBJECT_0
)
1662 SetLastError(ERROR_IO_PENDING
);
1666 CloseHandle( pi
.hThread
);
1667 CloseHandle( pi
.hProcess
);
1669 CloseHandle( handles
[0] );
1670 HeapFree(GetProcessHeap(),0,path
);
1674 static BOOL
service_wait_for_startup(SC_HANDLE hService
)
1677 SERVICE_STATUS status
;
1680 TRACE("%p\n", hService
);
1682 for (i
=0; i
<30; i
++)
1684 status
.dwCurrentState
= 0;
1685 r
= QueryServiceStatus(hService
, &status
);
1688 if (status
.dwCurrentState
== SERVICE_RUNNING
)
1690 TRACE("Service started successfully\n");
1699 /******************************************************************************
1700 * StartServiceW [ADVAPI32.@]
1702 * See StartServiceA.
1704 BOOL WINAPI
StartServiceW(SC_HANDLE hService
, DWORD dwNumServiceArgs
,
1705 LPCWSTR
*lpServiceArgVectors
)
1707 struct sc_service
*hsvc
;
1710 HANDLE handle
= INVALID_HANDLE_VALUE
;
1712 TRACE("%p %d %p\n", hService
, dwNumServiceArgs
, lpServiceArgVectors
);
1714 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1717 SetLastError(ERROR_INVALID_HANDLE
);
1721 hLock
= LockServiceDatabase((SC_HANDLE
)hsvc
->scm
);
1725 handle
= service_open_pipe(hsvc
->name
);
1726 if (handle
==INVALID_HANDLE_VALUE
)
1728 /* start the service process */
1729 if (service_start_process(hsvc
, NULL
))
1730 handle
= service_open_pipe(hsvc
->name
);
1733 if (handle
!= INVALID_HANDLE_VALUE
)
1735 r
= service_send_start_message(handle
, lpServiceArgVectors
, dwNumServiceArgs
);
1736 CloseHandle(handle
);
1739 UnlockServiceDatabase( hLock
);
1741 TRACE("returning %d\n", r
);
1744 service_wait_for_startup(hService
);
1749 /******************************************************************************
1750 * QueryServiceStatus [ADVAPI32.@]
1753 * hService [I] Handle to service to get information about
1754 * lpservicestatus [O] buffer to receive the status information for the service
1757 BOOL WINAPI
QueryServiceStatus(SC_HANDLE hService
,
1758 LPSERVICE_STATUS lpservicestatus
)
1760 SERVICE_STATUS_PROCESS SvcStatusData
;
1763 TRACE("%p %p\n", hService
, lpservicestatus
);
1765 ret
= QueryServiceStatusEx(hService
, SC_STATUS_PROCESS_INFO
, (LPBYTE
)&SvcStatusData
,
1766 sizeof(SERVICE_STATUS_PROCESS
), NULL
);
1767 if (ret
) memcpy(lpservicestatus
, &SvcStatusData
, sizeof(SERVICE_STATUS
)) ;
1772 /******************************************************************************
1773 * QueryServiceStatusEx [ADVAPI32.@]
1775 * Get information about a service.
1778 * hService [I] Handle to service to get information about
1779 * InfoLevel [I] Level of information to get
1780 * lpBuffer [O] Destination for requested information
1781 * cbBufSize [I] Size of lpBuffer in bytes
1782 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1788 BOOL WINAPI
QueryServiceStatusEx(SC_HANDLE hService
, SC_STATUS_TYPE InfoLevel
,
1789 LPBYTE lpBuffer
, DWORD cbBufSize
,
1790 LPDWORD pcbBytesNeeded
)
1792 struct sc_service
*hsvc
;
1793 DWORD size
, type
, val
;
1796 LPSERVICE_STATUS_PROCESS pSvcStatusData
;
1798 TRACE("%p %d %p %d %p\n", hService
, InfoLevel
, lpBuffer
, cbBufSize
, pcbBytesNeeded
);
1800 if (InfoLevel
!= SC_STATUS_PROCESS_INFO
)
1802 SetLastError( ERROR_INVALID_LEVEL
);
1806 pSvcStatusData
= (LPSERVICE_STATUS_PROCESS
) lpBuffer
;
1807 if (pSvcStatusData
== NULL
)
1809 SetLastError( ERROR_INVALID_PARAMETER
);
1813 if (cbBufSize
< sizeof(SERVICE_STATUS_PROCESS
))
1815 if( pcbBytesNeeded
!= NULL
)
1816 *pcbBytesNeeded
= sizeof(SERVICE_STATUS_PROCESS
);
1818 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1822 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1825 SetLastError( ERROR_INVALID_HANDLE
);
1829 pipe
= service_open_pipe(hsvc
->name
);
1830 if (pipe
!= INVALID_HANDLE_VALUE
)
1832 r
= service_get_status(pipe
, pSvcStatusData
);
1838 TRACE("Failed to read service status\n");
1840 /* read the service type from the registry */
1842 r
= RegQueryValueExA(hsvc
->hkey
, "Type", NULL
, &type
, (LPBYTE
)&val
, &size
);
1843 if (r
!= ERROR_SUCCESS
|| type
!= REG_DWORD
)
1846 pSvcStatusData
->dwServiceType
= val
;
1847 pSvcStatusData
->dwCurrentState
= SERVICE_STOPPED
; /* stopped */
1848 pSvcStatusData
->dwControlsAccepted
= 0;
1849 pSvcStatusData
->dwWin32ExitCode
= ERROR_SERVICE_NEVER_STARTED
;
1850 pSvcStatusData
->dwServiceSpecificExitCode
= 0;
1851 pSvcStatusData
->dwCheckPoint
= 0;
1852 pSvcStatusData
->dwWaitHint
= 0;
1857 /******************************************************************************
1858 * QueryServiceConfigA [ADVAPI32.@]
1860 BOOL WINAPI
QueryServiceConfigA( SC_HANDLE hService
, LPQUERY_SERVICE_CONFIGA config
,
1861 DWORD size
, LPDWORD needed
)
1866 QUERY_SERVICE_CONFIGW
*configW
;
1868 TRACE("%p %p %d %p\n", hService
, config
, size
, needed
);
1870 if (!(buffer
= HeapAlloc( GetProcessHeap(), 0, 2 * size
)))
1872 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1875 configW
= (QUERY_SERVICE_CONFIGW
*)buffer
;
1876 ret
= QueryServiceConfigW( hService
, configW
, 2 * size
, needed
);
1877 if (!ret
) goto done
;
1879 config
->dwServiceType
= configW
->dwServiceType
;
1880 config
->dwStartType
= configW
->dwStartType
;
1881 config
->dwErrorControl
= configW
->dwErrorControl
;
1882 config
->lpBinaryPathName
= NULL
;
1883 config
->lpLoadOrderGroup
= NULL
;
1884 config
->dwTagId
= configW
->dwTagId
;
1885 config
->lpDependencies
= NULL
;
1886 config
->lpServiceStartName
= NULL
;
1887 config
->lpDisplayName
= NULL
;
1889 p
= (LPSTR
)(config
+ 1);
1890 n
= size
- sizeof(*config
);
1893 #define MAP_STR(str) \
1897 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1898 if (!sz) goto done; \
1905 MAP_STR( lpBinaryPathName
);
1906 MAP_STR( lpLoadOrderGroup
);
1907 MAP_STR( lpDependencies
);
1908 MAP_STR( lpServiceStartName
);
1909 MAP_STR( lpDisplayName
);
1912 *needed
= p
- (LPSTR
)config
;
1916 HeapFree( GetProcessHeap(), 0, buffer
);
1920 /******************************************************************************
1921 * QueryServiceConfigW [ADVAPI32.@]
1924 QueryServiceConfigW( SC_HANDLE hService
,
1925 LPQUERY_SERVICE_CONFIGW lpServiceConfig
,
1926 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
1928 WCHAR str_buffer
[ MAX_PATH
];
1930 DWORD type
, val
, sz
, total
, n
;
1933 struct sc_service
*hsvc
;
1935 TRACE("%p %p %d %p\n", hService
, lpServiceConfig
,
1936 cbBufSize
, pcbBytesNeeded
);
1938 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1941 SetLastError( ERROR_INVALID_HANDLE
);
1946 /* TODO: Check which members are mandatory and what the registry types
1947 * should be. This should of course also be tested when a service is
1951 /* calculate the size required first */
1952 total
= sizeof (QUERY_SERVICE_CONFIGW
);
1954 sz
= sizeof(str_buffer
);
1955 r
= RegQueryValueExW( hKey
, szImagePath
, 0, &type
, (LPBYTE
) str_buffer
, &sz
);
1956 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
|| type
== REG_EXPAND_SZ
) )
1958 sz
= ExpandEnvironmentStringsW(str_buffer
,NULL
,0);
1959 if( 0 == sz
) return FALSE
;
1961 total
+= sizeof(WCHAR
) * sz
;
1965 /* FIXME: set last error */
1970 r
= RegQueryValueExW( hKey
, szGroup
, 0, &type
, NULL
, &sz
);
1971 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1974 total
+= sizeof(WCHAR
);
1977 r
= RegQueryValueExW( hKey
, szDependencies
, 0, &type
, NULL
, &sz
);
1978 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_MULTI_SZ
) )
1981 total
+= sizeof(WCHAR
);
1984 r
= RegQueryValueExW( hKey
, szObjectName
, 0, &type
, NULL
, &sz
);
1985 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1988 total
+= sizeof(WCHAR
);
1991 r
= RegQueryValueExW( hKey
, szDisplayName
, 0, &type
, NULL
, &sz
);
1992 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1995 total
+= sizeof(WCHAR
);
1997 *pcbBytesNeeded
= total
;
1999 /* if there's not enough memory, return an error */
2000 if( total
> cbBufSize
)
2002 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
2006 ZeroMemory( lpServiceConfig
, total
);
2009 r
= RegQueryValueExW( hKey
, szType
, 0, &type
, (LPBYTE
)&val
, &sz
);
2010 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_DWORD
) )
2011 lpServiceConfig
->dwServiceType
= val
;
2014 r
= RegQueryValueExW( hKey
, szStart
, 0, &type
, (LPBYTE
)&val
, &sz
);
2015 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_DWORD
) )
2016 lpServiceConfig
->dwStartType
= val
;
2019 r
= RegQueryValueExW( hKey
, szError
, 0, &type
, (LPBYTE
)&val
, &sz
);
2020 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_DWORD
) )
2021 lpServiceConfig
->dwErrorControl
= val
;
2024 r
= RegQueryValueExW( hKey
, szTag
, 0, &type
, (LPBYTE
)&val
, &sz
);
2025 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_DWORD
) )
2026 lpServiceConfig
->dwTagId
= val
;
2028 /* now do the strings */
2029 p
= (LPBYTE
) &lpServiceConfig
[1];
2030 n
= total
- sizeof (QUERY_SERVICE_CONFIGW
);
2032 sz
= sizeof(str_buffer
);
2033 r
= RegQueryValueExW( hKey
, szImagePath
, 0, &type
, (LPBYTE
) str_buffer
, &sz
);
2034 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
|| type
== REG_EXPAND_SZ
) )
2036 sz
= ExpandEnvironmentStringsW(str_buffer
, (LPWSTR
) p
, n
);
2037 sz
*= sizeof(WCHAR
);
2038 if( 0 == sz
|| sz
> n
) return FALSE
;
2040 lpServiceConfig
->lpBinaryPathName
= (LPWSTR
) p
;
2046 /* FIXME: set last error */
2051 r
= RegQueryValueExW( hKey
, szGroup
, 0, &type
, p
, &sz
);
2052 lpServiceConfig
->lpLoadOrderGroup
= (LPWSTR
) p
;
2053 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
2066 r
= RegQueryValueExW( hKey
, szDependencies
, 0, &type
, p
, &sz
);
2067 lpServiceConfig
->lpDependencies
= (LPWSTR
) p
;
2068 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
2081 r
= RegQueryValueExW( hKey
, szObjectName
, 0, &type
, p
, &sz
);
2082 lpServiceConfig
->lpServiceStartName
= (LPWSTR
) p
;
2083 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
2096 r
= RegQueryValueExW( hKey
, szDisplayName
, 0, &type
, p
, &sz
);
2097 lpServiceConfig
->lpDisplayName
= (LPWSTR
) p
;
2098 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
2111 ERR("Buffer overflow!\n");
2113 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig
->lpBinaryPathName
) );
2114 TRACE("Group = %s\n", debugstr_w(lpServiceConfig
->lpLoadOrderGroup
) );
2115 TRACE("Dependencies = %s\n", debugstr_w(lpServiceConfig
->lpDependencies
) );
2116 TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig
->lpServiceStartName
) );
2117 TRACE("Display name = %s\n", debugstr_w(lpServiceConfig
->lpDisplayName
) );
2122 /******************************************************************************
2123 * EnumServicesStatusA [ADVAPI32.@]
2126 EnumServicesStatusA( SC_HANDLE hSCManager
, DWORD dwServiceType
,
2127 DWORD dwServiceState
, LPENUM_SERVICE_STATUSA lpServices
,
2128 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
2129 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
)
2131 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager
,
2132 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
2133 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
);
2134 SetLastError (ERROR_ACCESS_DENIED
);
2138 /******************************************************************************
2139 * EnumServicesStatusW [ADVAPI32.@]
2142 EnumServicesStatusW( SC_HANDLE hSCManager
, DWORD dwServiceType
,
2143 DWORD dwServiceState
, LPENUM_SERVICE_STATUSW lpServices
,
2144 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
2145 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
)
2147 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager
,
2148 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
2149 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
);
2150 SetLastError (ERROR_ACCESS_DENIED
);
2154 /******************************************************************************
2155 * EnumServicesStatusExA [ADVAPI32.@]
2158 EnumServicesStatusExA(SC_HANDLE hSCManager
, SC_ENUM_TYPE InfoLevel
, DWORD dwServiceType
,
2159 DWORD dwServiceState
, LPBYTE lpServices
, DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
2160 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
, LPCSTR pszGroupName
)
2162 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager
, InfoLevel
,
2163 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
2164 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
, debugstr_a(pszGroupName
));
2165 SetLastError (ERROR_ACCESS_DENIED
);
2169 /******************************************************************************
2170 * EnumServicesStatusExW [ADVAPI32.@]
2173 EnumServicesStatusExW(SC_HANDLE hSCManager
, SC_ENUM_TYPE InfoLevel
, DWORD dwServiceType
,
2174 DWORD dwServiceState
, LPBYTE lpServices
, DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
2175 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
, LPCWSTR pszGroupName
)
2177 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager
, InfoLevel
,
2178 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
2179 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
, debugstr_w(pszGroupName
));
2180 SetLastError (ERROR_ACCESS_DENIED
);
2184 /******************************************************************************
2185 * GetServiceKeyNameA [ADVAPI32.@]
2187 BOOL WINAPI
GetServiceKeyNameA( SC_HANDLE hSCManager
, LPCSTR lpDisplayName
,
2188 LPSTR lpServiceName
, LPDWORD lpcchBuffer
)
2190 FIXME("%p %s %p %p\n", hSCManager
, debugstr_a(lpDisplayName
), lpServiceName
, lpcchBuffer
);
2194 /******************************************************************************
2195 * GetServiceKeyNameW [ADVAPI32.@]
2197 BOOL WINAPI
GetServiceKeyNameW( SC_HANDLE hSCManager
, LPCWSTR lpDisplayName
,
2198 LPWSTR lpServiceName
, LPDWORD lpcchBuffer
)
2200 FIXME("%p %s %p %p\n", hSCManager
, debugstr_w(lpDisplayName
), lpServiceName
, lpcchBuffer
);
2204 /******************************************************************************
2205 * QueryServiceLockStatusA [ADVAPI32.@]
2207 BOOL WINAPI
QueryServiceLockStatusA( SC_HANDLE hSCManager
,
2208 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus
,
2209 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
2211 FIXME("%p %p %08x %p\n", hSCManager
, lpLockStatus
, cbBufSize
, pcbBytesNeeded
);
2216 /******************************************************************************
2217 * QueryServiceLockStatusW [ADVAPI32.@]
2219 BOOL WINAPI
QueryServiceLockStatusW( SC_HANDLE hSCManager
,
2220 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus
,
2221 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
2223 FIXME("%p %p %08x %p\n", hSCManager
, lpLockStatus
, cbBufSize
, pcbBytesNeeded
);
2228 /******************************************************************************
2229 * GetServiceDisplayNameA [ADVAPI32.@]
2231 BOOL WINAPI
GetServiceDisplayNameA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
2232 LPSTR lpDisplayName
, LPDWORD lpcchBuffer
)
2234 LPWSTR lpServiceNameW
, lpDisplayNameW
;
2238 TRACE("%p %s %p %p\n", hSCManager
,
2239 debugstr_a(lpServiceName
), lpDisplayName
, lpcchBuffer
);
2241 lpServiceNameW
= SERV_dup(lpServiceName
);
2243 lpDisplayNameW
= HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer
* sizeof(WCHAR
));
2245 lpDisplayNameW
= NULL
;
2247 sizeW
= *lpcchBuffer
;
2248 if (!GetServiceDisplayNameW(hSCManager
, lpServiceNameW
, lpDisplayNameW
, &sizeW
))
2250 *lpcchBuffer
= sizeW
*2; /* we can only provide an upper estimation of string length */
2254 if (!WideCharToMultiByte(CP_ACP
, 0, lpDisplayNameW
, (sizeW
+ 1), lpDisplayName
,
2255 *lpcchBuffer
, NULL
, NULL
))
2257 *lpcchBuffer
= WideCharToMultiByte(CP_ACP
, 0, lpDisplayNameW
, -1, NULL
, 0, NULL
, NULL
);
2261 /* probably due to a bug GetServiceDisplayNameA doesn't modify lpcchBuffer on success.
2262 * (but if the function succeeded it means that is a good upper estimation of the size) */
2266 HeapFree(GetProcessHeap(), 0, lpDisplayNameW
);
2267 HeapFree(GetProcessHeap(), 0, lpServiceNameW
);
2271 /******************************************************************************
2272 * GetServiceDisplayNameW [ADVAPI32.@]
2274 BOOL WINAPI
GetServiceDisplayNameW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
2275 LPWSTR lpDisplayName
, LPDWORD lpcchBuffer
)
2277 struct sc_manager
*hscm
;
2281 TRACE("%p %s %p %p\n", hSCManager
,
2282 debugstr_w(lpServiceName
), lpDisplayName
, lpcchBuffer
);
2284 hscm
= sc_handle_get_handle_data(hSCManager
, SC_HTYPE_MANAGER
);
2287 SetLastError(ERROR_INVALID_HANDLE
);
2293 SetLastError(ERROR_INVALID_ADDRESS
);
2297 size
= *lpcchBuffer
* sizeof(WCHAR
);
2298 ret
= RegGetValueW(hscm
->hkey
, lpServiceName
, szDisplayName
, RRF_RT_REG_SZ
, &type
, lpDisplayName
, &size
);
2299 if (!ret
&& !lpDisplayName
&& size
)
2300 ret
= ERROR_MORE_DATA
;
2304 if (lpDisplayName
&& *lpcchBuffer
) *lpDisplayName
= 0;
2306 if (ret
== ERROR_MORE_DATA
)
2308 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2309 *lpcchBuffer
= (size
/ sizeof(WCHAR
)) - 1;
2311 else if (ret
== ERROR_FILE_NOT_FOUND
)
2315 if (!RegOpenKeyW(hscm
->hkey
, lpServiceName
, &hkey
))
2317 UINT len
= lstrlenW(lpServiceName
);
2320 if ((*lpcchBuffer
<= len
) || (!lpDisplayName
&& *lpcchBuffer
))
2321 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2322 else if (lpDisplayName
&& *lpcchBuffer
)
2324 /* No displayname, but the service exists and the buffer
2325 * is big enough. We should return the servicename.
2327 lstrcpyW(lpDisplayName
, lpServiceName
);
2336 SetLastError(ERROR_SERVICE_DOES_NOT_EXIST
);
2343 /* Always return the correct needed size on success */
2344 *lpcchBuffer
= (size
/ sizeof(WCHAR
)) - 1;
2349 /******************************************************************************
2350 * ChangeServiceConfigW [ADVAPI32.@]
2352 BOOL WINAPI
ChangeServiceConfigW( SC_HANDLE hService
, DWORD dwServiceType
,
2353 DWORD dwStartType
, DWORD dwErrorControl
, LPCWSTR lpBinaryPathName
,
2354 LPCWSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
, LPCWSTR lpDependencies
,
2355 LPCWSTR lpServiceStartName
, LPCWSTR lpPassword
, LPCWSTR lpDisplayName
)
2357 struct reg_value val
[10];
2358 struct sc_service
*hsvc
;
2359 DWORD r
= ERROR_SUCCESS
;
2363 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2364 hService
, dwServiceType
, dwStartType
, dwErrorControl
,
2365 debugstr_w(lpBinaryPathName
), debugstr_w(lpLoadOrderGroup
),
2366 lpdwTagId
, lpDependencies
, debugstr_w(lpServiceStartName
),
2367 debugstr_w(lpPassword
), debugstr_w(lpDisplayName
) );
2369 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
2372 SetLastError( ERROR_INVALID_HANDLE
);
2377 if( dwServiceType
!= SERVICE_NO_CHANGE
)
2378 service_set_dword( &val
[n
++], szType
, &dwServiceType
);
2380 if( dwStartType
!= SERVICE_NO_CHANGE
)
2381 service_set_dword( &val
[n
++], szStart
, &dwStartType
);
2383 if( dwErrorControl
!= SERVICE_NO_CHANGE
)
2384 service_set_dword( &val
[n
++], szError
, &dwErrorControl
);
2386 if( lpBinaryPathName
)
2387 service_set_string( &val
[n
++], szImagePath
, lpBinaryPathName
);
2389 if( lpLoadOrderGroup
)
2390 service_set_string( &val
[n
++], szGroup
, lpLoadOrderGroup
);
2392 /* FIXME: lpDependencies is used to create/change both DependOnService and DependOnGroup
2393 * There is no such key as what szDependencies refers to */
2394 if( lpDependencies
)
2395 service_set_multi_string( &val
[n
++], szDependencies
, lpDependencies
);
2398 FIXME("ignoring password\n");
2400 if( lpServiceStartName
)
2401 service_set_string( &val
[n
++], szObjectName
, lpServiceStartName
);
2403 r
= service_write_values( hsvc
->hkey
, val
, n
);
2405 return (r
== ERROR_SUCCESS
) ? TRUE
: FALSE
;
2408 /******************************************************************************
2409 * ChangeServiceConfigA [ADVAPI32.@]
2411 BOOL WINAPI
ChangeServiceConfigA( SC_HANDLE hService
, DWORD dwServiceType
,
2412 DWORD dwStartType
, DWORD dwErrorControl
, LPCSTR lpBinaryPathName
,
2413 LPCSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
, LPCSTR lpDependencies
,
2414 LPCSTR lpServiceStartName
, LPCSTR lpPassword
, LPCSTR lpDisplayName
)
2416 LPWSTR wBinaryPathName
, wLoadOrderGroup
, wDependencies
;
2417 LPWSTR wServiceStartName
, wPassword
, wDisplayName
;
2420 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2421 hService
, dwServiceType
, dwStartType
, dwErrorControl
,
2422 debugstr_a(lpBinaryPathName
), debugstr_a(lpLoadOrderGroup
),
2423 lpdwTagId
, lpDependencies
, debugstr_a(lpServiceStartName
),
2424 debugstr_a(lpPassword
), debugstr_a(lpDisplayName
) );
2426 wBinaryPathName
= SERV_dup( lpBinaryPathName
);
2427 wLoadOrderGroup
= SERV_dup( lpLoadOrderGroup
);
2428 wDependencies
= SERV_dupmulti( lpDependencies
);
2429 wServiceStartName
= SERV_dup( lpServiceStartName
);
2430 wPassword
= SERV_dup( lpPassword
);
2431 wDisplayName
= SERV_dup( lpDisplayName
);
2433 r
= ChangeServiceConfigW( hService
, dwServiceType
,
2434 dwStartType
, dwErrorControl
, wBinaryPathName
,
2435 wLoadOrderGroup
, lpdwTagId
, wDependencies
,
2436 wServiceStartName
, wPassword
, wDisplayName
);
2438 HeapFree( GetProcessHeap(), 0, wBinaryPathName
);
2439 HeapFree( GetProcessHeap(), 0, wLoadOrderGroup
);
2440 HeapFree( GetProcessHeap(), 0, wDependencies
);
2441 HeapFree( GetProcessHeap(), 0, wServiceStartName
);
2442 HeapFree( GetProcessHeap(), 0, wPassword
);
2443 HeapFree( GetProcessHeap(), 0, wDisplayName
);
2448 /******************************************************************************
2449 * ChangeServiceConfig2A [ADVAPI32.@]
2451 BOOL WINAPI
ChangeServiceConfig2A( SC_HANDLE hService
, DWORD dwInfoLevel
,
2456 TRACE("%p %d %p\n",hService
, dwInfoLevel
, lpInfo
);
2458 if (dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
2460 LPSERVICE_DESCRIPTIONA sd
= (LPSERVICE_DESCRIPTIONA
) lpInfo
;
2461 SERVICE_DESCRIPTIONW sdw
;
2463 sdw
.lpDescription
= SERV_dup( sd
->lpDescription
);
2465 r
= ChangeServiceConfig2W( hService
, dwInfoLevel
, &sdw
);
2467 HeapFree( GetProcessHeap(), 0, sdw
.lpDescription
);
2469 else if (dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
2471 LPSERVICE_FAILURE_ACTIONSA fa
= (LPSERVICE_FAILURE_ACTIONSA
) lpInfo
;
2472 SERVICE_FAILURE_ACTIONSW faw
;
2474 faw
.dwResetPeriod
= fa
->dwResetPeriod
;
2475 faw
.lpRebootMsg
= SERV_dup( fa
->lpRebootMsg
);
2476 faw
.lpCommand
= SERV_dup( fa
->lpCommand
);
2477 faw
.cActions
= fa
->cActions
;
2478 faw
.lpsaActions
= fa
->lpsaActions
;
2480 r
= ChangeServiceConfig2W( hService
, dwInfoLevel
, &faw
);
2482 HeapFree( GetProcessHeap(), 0, faw
.lpRebootMsg
);
2483 HeapFree( GetProcessHeap(), 0, faw
.lpCommand
);
2486 SetLastError( ERROR_INVALID_PARAMETER
);
2491 /******************************************************************************
2492 * ChangeServiceConfig2W [ADVAPI32.@]
2494 BOOL WINAPI
ChangeServiceConfig2W( SC_HANDLE hService
, DWORD dwInfoLevel
,
2498 struct sc_service
*hsvc
;
2500 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
2503 SetLastError( ERROR_INVALID_HANDLE
);
2508 if (dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
2510 static const WCHAR szDescription
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2511 LPSERVICE_DESCRIPTIONW sd
= (LPSERVICE_DESCRIPTIONW
)lpInfo
;
2512 if (sd
->lpDescription
)
2514 TRACE("Setting Description to %s\n",debugstr_w(sd
->lpDescription
));
2515 if (sd
->lpDescription
[0] == 0)
2516 RegDeleteValueW(hKey
,szDescription
);
2518 RegSetValueExW(hKey
, szDescription
, 0, REG_SZ
,
2519 (LPVOID
)sd
->lpDescription
,
2520 sizeof(WCHAR
)*(strlenW(sd
->lpDescription
)+1));
2524 FIXME("STUB: %p %d %p\n",hService
, dwInfoLevel
, lpInfo
);
2528 /******************************************************************************
2529 * QueryServiceObjectSecurity [ADVAPI32.@]
2531 BOOL WINAPI
QueryServiceObjectSecurity(SC_HANDLE hService
,
2532 SECURITY_INFORMATION dwSecurityInformation
,
2533 PSECURITY_DESCRIPTOR lpSecurityDescriptor
,
2534 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
2536 SECURITY_DESCRIPTOR descriptor
;
2541 FIXME("%p %d %p %u %p - semi-stub\n", hService
, dwSecurityInformation
,
2542 lpSecurityDescriptor
, cbBufSize
, pcbBytesNeeded
);
2544 if (dwSecurityInformation
!= DACL_SECURITY_INFORMATION
)
2545 FIXME("information %d not supported\n", dwSecurityInformation
);
2547 InitializeSecurityDescriptor(&descriptor
, SECURITY_DESCRIPTOR_REVISION
);
2549 InitializeAcl(&acl
, sizeof(ACL
), ACL_REVISION
);
2550 SetSecurityDescriptorDacl(&descriptor
, TRUE
, &acl
, TRUE
);
2553 succ
= MakeSelfRelativeSD(&descriptor
, lpSecurityDescriptor
, &size
);
2554 *pcbBytesNeeded
= size
;
2558 /******************************************************************************
2559 * SetServiceObjectSecurity [ADVAPI32.@]
2561 BOOL WINAPI
SetServiceObjectSecurity(SC_HANDLE hService
,
2562 SECURITY_INFORMATION dwSecurityInformation
,
2563 PSECURITY_DESCRIPTOR lpSecurityDescriptor
)
2565 FIXME("%p %d %p\n", hService
, dwSecurityInformation
, lpSecurityDescriptor
);
2569 /******************************************************************************
2570 * SetServiceBits [ADVAPI32.@]
2572 BOOL WINAPI
SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus
,
2573 DWORD dwServiceBits
,
2575 BOOL bUpdateImmediately
)
2577 FIXME("%p %08x %x %x\n", hServiceStatus
, dwServiceBits
,
2578 bSetBitsOn
, bUpdateImmediately
);
2582 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerExA( LPCSTR lpServiceName
,
2583 LPHANDLER_FUNCTION_EX lpHandlerProc
, LPVOID lpContext
)
2585 FIXME("%s %p %p\n", debugstr_a(lpServiceName
), lpHandlerProc
, lpContext
);
2589 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName
,
2590 LPHANDLER_FUNCTION_EX lpHandlerProc
, LPVOID lpContext
)
2592 service_data
*service
;
2593 SERVICE_STATUS_HANDLE handle
= 0;
2595 TRACE("%s %p %p\n", debugstr_w(lpServiceName
), lpHandlerProc
, lpContext
);
2597 EnterCriticalSection( &service_cs
);
2598 LIST_FOR_EACH_ENTRY( service
, &service_list
, service_data
, entry
)
2600 if(!strcmpW(lpServiceName
, service
->name
))
2602 service
->handler
.handler_ex
= lpHandlerProc
;
2603 service
->context
= lpContext
;
2604 service
->extended
= TRUE
;
2605 handle
= (SERVICE_STATUS_HANDLE
)service
;
2609 LeaveCriticalSection( &service_cs
);