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 typedef struct service_start_info_t
62 #define WINESERV_STARTINFO 1
63 #define WINESERV_GETSTATUS 2
64 #define WINESERV_SENDCONTROL 3
65 #define WINESERV_SETPID 4
67 typedef struct service_data_t
71 LPHANDLER_FUNCTION handler
;
72 LPHANDLER_FUNCTION_EX handler_ex
;
75 SERVICE_STATUS_PROCESS status
;
78 BOOL extended
: 1; /* uses handler_ex instead of handler? */
80 LPSERVICE_MAIN_FUNCTIONA a
;
81 LPSERVICE_MAIN_FUNCTIONW w
;
87 static CRITICAL_SECTION service_cs
;
88 static CRITICAL_SECTION_DEBUG service_cs_debug
=
91 { &service_cs_debug
.ProcessLocksList
,
92 &service_cs_debug
.ProcessLocksList
},
93 0, 0, { (DWORD_PTR
)(__FILE__
": service_cs") }
95 static CRITICAL_SECTION service_cs
= { &service_cs_debug
, -1, 0, 0, 0, 0 };
97 static struct list service_list
= LIST_INIT(service_list
);
99 extern HANDLE
__wine_make_process_system(void);
101 /******************************************************************************
105 #define MAX_SERVICE_NAME 256
107 typedef enum { SC_HTYPE_MANAGER
, SC_HTYPE_SERVICE
} SC_HANDLE_TYPE
;
110 typedef VOID (*sc_handle_destructor
)(struct sc_handle
*);
114 SC_HANDLE_TYPE htype
;
116 sc_handle_destructor destroy
;
119 struct sc_manager
/* service control manager handle */
121 struct sc_handle hdr
;
122 HKEY hkey
; /* handle to services database in the registry */
126 struct sc_service
/* service handle */
128 struct sc_handle hdr
;
129 HKEY hkey
; /* handle to service entry in the registry (under hkey) */
131 struct sc_manager
*scm
; /* pointer to SCM handle */
135 static void *sc_handle_alloc(SC_HANDLE_TYPE htype
, DWORD size
,
136 sc_handle_destructor destroy
)
138 struct sc_handle
*hdr
;
140 hdr
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
145 hdr
->destroy
= destroy
;
147 TRACE("sc_handle type=%d -> %p\n", htype
, hdr
);
151 static void *sc_handle_get_handle_data(SC_HANDLE handle
, DWORD htype
)
153 struct sc_handle
*hdr
= (struct sc_handle
*) handle
;
157 if (hdr
->htype
!= htype
)
162 static void sc_handle_free(struct sc_handle
* hdr
)
166 if (--hdr
->ref_count
)
169 HeapFree(GetProcessHeap(), 0, hdr
);
172 static void sc_handle_destroy_manager(struct sc_handle
*handle
)
174 struct sc_manager
*mgr
= (struct sc_manager
*) handle
;
176 TRACE("destroying SC Manager %p\n", mgr
);
178 RegCloseKey(mgr
->hkey
);
181 static void sc_handle_destroy_service(struct sc_handle
*handle
)
183 struct sc_service
*svc
= (struct sc_service
*) handle
;
185 TRACE("destroying service %p\n", svc
);
187 RegCloseKey(svc
->hkey
);
189 sc_handle_free(&svc
->scm
->hdr
);
193 /******************************************************************************
194 * String management functions
196 static inline LPWSTR
SERV_dup( LPCSTR str
)
203 len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
204 wstr
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof (WCHAR
) );
205 MultiByteToWideChar( CP_ACP
, 0, str
, -1, wstr
, len
);
209 static inline LPWSTR
SERV_dupmulti(LPCSTR str
)
217 len
+= MultiByteToWideChar( CP_ACP
, 0, &str
[n
], -1, NULL
, 0 );
218 n
+= (strlen( &str
[n
] ) + 1);
223 wstr
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof (WCHAR
) );
224 MultiByteToWideChar( CP_ACP
, 0, str
, n
, wstr
, len
);
228 static inline VOID
SERV_free( LPWSTR wstr
)
230 HeapFree( GetProcessHeap(), 0, wstr
);
233 /******************************************************************************
234 * registry access functions and data
236 static const WCHAR szDisplayName
[] = {
237 'D','i','s','p','l','a','y','N','a','m','e', 0 };
238 static const WCHAR szType
[] = {'T','y','p','e',0};
239 static const WCHAR szStart
[] = {'S','t','a','r','t',0};
240 static const WCHAR szError
[] = {
241 'E','r','r','o','r','C','o','n','t','r','o','l', 0};
242 static const WCHAR szImagePath
[] = {'I','m','a','g','e','P','a','t','h',0};
243 static const WCHAR szGroup
[] = {'G','r','o','u','p',0};
244 static const WCHAR szDependencies
[] = {
245 'D','e','p','e','n','d','e','n','c','i','e','s',0};
246 static const WCHAR szDependOnService
[] = {
247 'D','e','p','e','n','d','O','n','S','e','r','v','i','c','e',0};
248 static const WCHAR szObjectName
[] = {
249 'O','b','j','e','c','t','N','a','m','e',0};
250 static const WCHAR szTag
[] = {
260 static inline void service_set_value( struct reg_value
*val
,
261 DWORD type
, LPCWSTR name
, LPCVOID data
, DWORD size
)
269 static inline void service_set_dword( struct reg_value
*val
,
270 LPCWSTR name
, const DWORD
*data
)
272 service_set_value( val
, REG_DWORD
, name
, data
, sizeof (DWORD
));
275 static inline void service_set_string( struct reg_value
*val
,
276 LPCWSTR name
, LPCWSTR string
)
278 DWORD len
= (lstrlenW(string
)+1) * sizeof (WCHAR
);
279 service_set_value( val
, REG_SZ
, name
, string
, len
);
282 static inline void service_set_multi_string( struct reg_value
*val
,
283 LPCWSTR name
, LPCWSTR string
)
287 /* determine the length of a double null terminated multi string */
289 len
+= (lstrlenW( &string
[ len
] )+1);
290 } while ( string
[ len
++ ] );
292 len
*= sizeof (WCHAR
);
293 service_set_value( val
, REG_MULTI_SZ
, name
, string
, len
);
296 static inline LONG
service_write_values( HKEY hKey
,
297 const struct reg_value
*val
, int n
)
299 LONG r
= ERROR_SUCCESS
;
304 r
= RegSetValueExW(hKey
, val
[i
].name
, 0, val
[i
].type
,
305 (const BYTE
*)val
[i
].data
, val
[i
].size
);
306 if( r
!= ERROR_SUCCESS
)
312 /******************************************************************************
313 * Service IPC functions
315 static LPWSTR
service_get_pipe_name(LPCWSTR service
)
317 static const WCHAR prefix
[] = { '\\','\\','.','\\','p','i','p','e','\\',
318 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
322 len
= sizeof prefix
+ strlenW(service
)*sizeof(WCHAR
);
323 name
= HeapAlloc(GetProcessHeap(), 0, len
);
324 strcpyW(name
, prefix
);
325 strcatW(name
, service
);
329 static HANDLE
service_open_pipe(LPCWSTR service
)
331 LPWSTR szPipe
= service_get_pipe_name( service
);
332 HANDLE handle
= INVALID_HANDLE_VALUE
;
335 handle
= CreateFileW(szPipe
, GENERIC_READ
|GENERIC_WRITE
,
336 0, NULL
, OPEN_ALWAYS
, 0, NULL
);
337 if (handle
!= INVALID_HANDLE_VALUE
)
339 if (GetLastError() != ERROR_PIPE_BUSY
)
341 } while (WaitNamedPipeW(szPipe
, NMPWAIT_WAIT_FOREVER
));
347 /******************************************************************************
348 * service_get_event_handle
350 static HANDLE
service_get_event_handle(LPCWSTR service
)
352 static const WCHAR prefix
[] = {
353 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
358 len
= sizeof prefix
+ strlenW(service
)*sizeof(WCHAR
);
359 name
= HeapAlloc(GetProcessHeap(), 0, len
);
360 strcpyW(name
, prefix
);
361 strcatW(name
, service
);
362 handle
= CreateEventW(NULL
, TRUE
, FALSE
, name
);
367 /******************************************************************************
370 * Call into the main service routine provided by StartServiceCtrlDispatcher.
372 static DWORD WINAPI
service_thread(LPVOID arg
)
374 service_data
*info
= arg
;
375 LPWSTR str
= info
->args
;
376 DWORD argc
= 0, len
= 0;
382 len
+= strlenW(&str
[len
]) + 1;
389 info
->proc
.w(0, NULL
);
391 info
->proc
.a(0, NULL
);
399 argv
= HeapAlloc(GetProcessHeap(), 0, (argc
+1)*sizeof(LPWSTR
));
400 for (argc
=0, p
=str
; *p
; p
+= strlenW(p
) + 1)
404 info
->proc
.w(argc
, argv
);
405 HeapFree(GetProcessHeap(), 0, argv
);
409 LPSTR strA
, *argv
, p
;
412 lenA
= WideCharToMultiByte(CP_ACP
,0, str
, len
, NULL
, 0, NULL
, NULL
);
413 strA
= HeapAlloc(GetProcessHeap(), 0, lenA
);
414 WideCharToMultiByte(CP_ACP
,0, str
, len
, strA
, lenA
, NULL
, NULL
);
416 argv
= HeapAlloc(GetProcessHeap(), 0, (argc
+1)*sizeof(LPSTR
));
417 for (argc
=0, p
=strA
; *p
; p
+= strlen(p
) + 1)
421 info
->proc
.a(argc
, argv
);
422 HeapFree(GetProcessHeap(), 0, argv
);
423 HeapFree(GetProcessHeap(), 0, strA
);
428 /******************************************************************************
429 * service_handle_start
431 static BOOL
service_handle_start(HANDLE pipe
, service_data
*service
, DWORD count
)
433 DWORD read
= 0, result
= 0;
437 TRACE("%p %p %d\n", pipe
, service
, count
);
439 args
= HeapAlloc(GetProcessHeap(), 0, count
*sizeof(WCHAR
));
440 r
= ReadFile(pipe
, args
, count
*sizeof(WCHAR
), &read
, NULL
);
441 if (!r
|| count
!=read
/sizeof(WCHAR
) || args
[count
-1])
443 ERR("pipe read failed r = %d count = %d read = %d args[n-1]=%s\n",
444 r
, count
, read
, debugstr_wn(args
, count
));
450 ERR("service is not stopped\n");
454 SERV_free(service
->args
);
455 service
->args
= args
;
457 service
->thread
= CreateThread( NULL
, 0, service_thread
,
461 HeapFree(GetProcessHeap(), 0, args
);
462 WriteFile( pipe
, &result
, sizeof result
, &read
, NULL
);
467 /******************************************************************************
468 * service_send_start_message
470 static BOOL
service_send_start_message(HANDLE pipe
, LPCWSTR
*argv
, DWORD argc
)
472 DWORD i
, len
, count
, result
;
473 service_start_info
*ssi
;
477 TRACE("%p %p %d\n", pipe
, argv
, argc
);
479 /* calculate how much space do we need to send the startup info */
481 for (i
=0; i
<argc
; i
++)
482 len
+= strlenW(argv
[i
])+1;
484 ssi
= HeapAlloc(GetProcessHeap(),0,sizeof *ssi
+ (len
-1)*sizeof(WCHAR
));
485 ssi
->cmd
= WINESERV_STARTINFO
;
488 /* copy service args into a single buffer*/
490 for (i
=0; i
<argc
; i
++)
497 r
= WriteFile(pipe
, ssi
, sizeof *ssi
+ len
*sizeof(WCHAR
), &count
, NULL
);
499 r
= ReadFile(pipe
, &result
, sizeof result
, &count
, NULL
);
501 HeapFree(GetProcessHeap(),0,ssi
);
506 /******************************************************************************
507 * service_handle_get_status
509 static BOOL
service_handle_get_status(HANDLE pipe
, const service_data
*service
)
513 return WriteFile(pipe
, &service
->status
,
514 sizeof service
->status
, &count
, NULL
);
517 /******************************************************************************
520 static BOOL
service_get_status(HANDLE pipe
, LPSERVICE_STATUS_PROCESS status
)
522 DWORD cmd
[2], count
= 0;
525 cmd
[0] = WINESERV_GETSTATUS
;
527 r
= WriteFile( pipe
, cmd
, sizeof cmd
, &count
, NULL
);
528 if (!r
|| count
!= sizeof cmd
)
530 ERR("service protocol error - failed to write pipe!\n");
533 r
= ReadFile( pipe
, status
, sizeof *status
, &count
, NULL
);
534 if (!r
|| count
!= sizeof *status
)
535 ERR("service protocol error - failed to read pipe "
536 "r = %d count = %d!\n", r
, count
);
540 /******************************************************************************
541 * service_handle_set_processID
543 static BOOL
service_handle_set_processID(HANDLE pipe
, service_data
*service
, DWORD dwProcessId
)
545 DWORD count
, ret
= ERROR_SUCCESS
;
547 TRACE("received control %d\n", dwProcessId
);
548 service
->status
.dwProcessId
= dwProcessId
;
549 return WriteFile(pipe
, &ret
, sizeof ret
, &count
, NULL
);
552 /******************************************************************************
553 * service_set_processID
555 static BOOL
service_set_processID(HANDLE pipe
, DWORD dwprocessId
, LPDWORD dwResult
)
557 DWORD cmd
[2], count
= 0;
560 cmd
[0] = WINESERV_SETPID
;
561 cmd
[1] = dwprocessId
;
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
, dwResult
, sizeof *dwResult
, &count
, NULL
);
569 if (!r
|| count
!= sizeof *dwResult
)
570 ERR("service protocol error - failed to read pipe "
571 "r = %d count = %d!\n", r
, count
);
575 /******************************************************************************
576 * service_send_control
578 static BOOL
service_send_control(HANDLE pipe
, DWORD dwControl
, DWORD
*result
)
580 DWORD cmd
[2], count
= 0;
583 cmd
[0] = WINESERV_SENDCONTROL
;
585 r
= WriteFile(pipe
, cmd
, sizeof cmd
, &count
, NULL
);
586 if (!r
|| count
!= sizeof cmd
)
588 ERR("service protocol error - failed to write pipe!\n");
591 r
= ReadFile(pipe
, result
, sizeof *result
, &count
, NULL
);
592 if (!r
|| count
!= sizeof *result
)
593 ERR("service protocol error - failed to read pipe "
594 "r = %d count = %d!\n", r
, count
);
598 /******************************************************************************
599 * service_accepts_control
601 static BOOL
service_accepts_control(const service_data
*service
, DWORD dwControl
)
603 DWORD a
= service
->status
.dwControlsAccepted
;
607 case SERVICE_CONTROL_INTERROGATE
:
609 case SERVICE_CONTROL_STOP
:
610 if (a
&SERVICE_ACCEPT_STOP
)
613 case SERVICE_CONTROL_SHUTDOWN
:
614 if (a
&SERVICE_ACCEPT_SHUTDOWN
)
617 case SERVICE_CONTROL_PAUSE
:
618 case SERVICE_CONTROL_CONTINUE
:
619 if (a
&SERVICE_ACCEPT_PAUSE_CONTINUE
)
622 case SERVICE_CONTROL_PARAMCHANGE
:
623 if (a
&SERVICE_ACCEPT_PARAMCHANGE
)
626 case SERVICE_CONTROL_NETBINDADD
:
627 case SERVICE_CONTROL_NETBINDREMOVE
:
628 case SERVICE_CONTROL_NETBINDENABLE
:
629 case SERVICE_CONTROL_NETBINDDISABLE
:
630 if (a
&SERVICE_ACCEPT_NETBINDCHANGE
)
633 if (!service
->extended
)
637 case SERVICE_CONTROL_HARDWAREPROFILECHANGE
:
638 if (a
&SERVICE_ACCEPT_HARDWAREPROFILECHANGE
)
641 case SERVICE_CONTROL_POWEREVENT
:
642 if (a
&SERVICE_ACCEPT_POWEREVENT
)
645 case SERVICE_CONTROL_SESSIONCHANGE
:
646 if (a
&SERVICE_ACCEPT_SESSIONCHANGE
)
653 /******************************************************************************
654 * service_handle_control
656 static BOOL
service_handle_control(HANDLE pipe
, service_data
*service
,
659 DWORD count
, ret
= ERROR_INVALID_SERVICE_CONTROL
;
661 TRACE("received control %d\n", dwControl
);
663 if (service_accepts_control(service
, dwControl
))
665 if (service
->extended
&& service
->handler
.handler_ex
)
667 service
->handler
.handler_ex(dwControl
, 0, NULL
, service
->context
);
670 else if (service
->handler
.handler
)
672 service
->handler
.handler(dwControl
);
676 return WriteFile(pipe
, &ret
, sizeof ret
, &count
, NULL
);
679 /******************************************************************************
680 * service_reap_thread
682 static DWORD
service_reap_thread(service_data
*service
)
686 if (!service
->thread
)
688 GetExitCodeThread(service
->thread
, &exitcode
);
689 if (exitcode
!=STILL_ACTIVE
)
691 CloseHandle(service
->thread
);
697 /******************************************************************************
698 * service_control_dispatcher
700 static DWORD WINAPI
service_control_dispatcher(LPVOID arg
)
702 service_data
*service
= arg
;
706 TRACE("%p %s\n", service
, debugstr_w(service
->name
));
708 /* create a pipe to talk to the rest of the world with */
709 name
= service_get_pipe_name(service
->name
);
710 pipe
= CreateNamedPipeW(name
, PIPE_ACCESS_DUPLEX
,
711 PIPE_TYPE_BYTE
|PIPE_WAIT
, 1, 256, 256, 10000, NULL
);
714 /* let the process who started us know we've tried to create a pipe */
715 event
= service_get_event_handle(service
->name
);
719 if (pipe
==INVALID_HANDLE_VALUE
)
721 ERR("failed to create pipe for %s, error = %d\n",
722 debugstr_w(service
->name
), GetLastError());
726 /* dispatcher loop */
730 DWORD count
, req
[2] = {0,0};
732 r
= ConnectNamedPipe(pipe
, NULL
);
733 if (!r
&& GetLastError() != ERROR_PIPE_CONNECTED
)
735 ERR("pipe connect failed\n");
739 r
= ReadFile( pipe
, &req
, sizeof req
, &count
, NULL
);
740 if (!r
|| count
!=sizeof req
)
742 ERR("pipe read failed\n");
746 service_reap_thread(service
);
748 /* handle the request */
751 case WINESERV_STARTINFO
:
752 service_handle_start(pipe
, service
, req
[1]);
754 case WINESERV_GETSTATUS
:
755 service_handle_get_status(pipe
, service
);
757 case WINESERV_SENDCONTROL
:
758 service_handle_control(pipe
, service
, req
[1]);
760 case WINESERV_SETPID
:
761 service_handle_set_processID(pipe
, service
, req
[1]);
764 ERR("received invalid command %d length %d\n", req
[0], req
[1]);
767 FlushFileBuffers(pipe
);
768 DisconnectNamedPipe(pipe
);
775 /******************************************************************************
776 * service_run_threads
778 static BOOL
service_run_threads(void)
780 service_data
*service
;
784 EnterCriticalSection( &service_cs
);
786 count
= list_count( &service_list
);
788 TRACE("starting %d pipe listener threads\n", count
);
790 handles
= HeapAlloc(GetProcessHeap(), 0, sizeof(HANDLE
) * (count
+ 1));
792 handles
[n
++] = __wine_make_process_system();
794 LIST_FOR_EACH_ENTRY( service
, &service_list
, service_data
, entry
)
795 handles
[n
++] = CreateThread( NULL
, 0, service_control_dispatcher
,
797 assert(n
== count
+ 1);
799 LeaveCriticalSection( &service_cs
);
801 /* wait for all the threads to pack up and exit */
804 DWORD ret
= WaitForMultipleObjects( min(n
,MAXIMUM_WAIT_OBJECTS
), handles
, FALSE
, INFINITE
);
805 if (!ret
) /* system process event */
807 TRACE( "last user process exited, shutting down\n" );
808 /* FIXME: we should maybe send a shutdown control to running services */
811 if (ret
< MAXIMUM_WAIT_OBJECTS
)
813 CloseHandle( handles
[ret
] );
814 memmove( &handles
[ret
], &handles
[ret
+1], (n
- ret
- 1) * sizeof(HANDLE
) );
820 while (n
) CloseHandle( handles
[--n
] );
821 HeapFree(GetProcessHeap(), 0, handles
);
826 /******************************************************************************
827 * StartServiceCtrlDispatcherA [ADVAPI32.@]
829 * See StartServiceCtrlDispatcherW.
831 BOOL WINAPI
StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA
*servent
)
837 TRACE("%p\n", servent
);
839 EnterCriticalSection( &service_cs
);
840 while (servent
->lpServiceName
)
842 LPSTR name
= servent
->lpServiceName
;
844 len
= MultiByteToWideChar(CP_ACP
, 0, name
, -1, NULL
, 0);
845 sz
= len
*sizeof(WCHAR
) + sizeof *info
;
846 info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sz
);
847 MultiByteToWideChar(CP_ACP
, 0, name
, -1, info
->name
, len
);
848 info
->proc
.a
= servent
->lpServiceProc
;
849 info
->unicode
= FALSE
;
850 list_add_head( &service_list
, &info
->entry
);
853 LeaveCriticalSection( &service_cs
);
855 service_run_threads();
860 /******************************************************************************
861 * StartServiceCtrlDispatcherW [ADVAPI32.@]
863 * Connects a process containing one or more services to the service control
867 * servent [I] A list of the service names and service procedures
873 BOOL WINAPI
StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW
*servent
)
879 TRACE("%p\n", servent
);
881 EnterCriticalSection( &service_cs
);
882 while (servent
->lpServiceName
)
884 LPWSTR name
= servent
->lpServiceName
;
887 sz
= len
*sizeof(WCHAR
) + sizeof *info
;
888 info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sz
);
889 strcpyW(info
->name
, name
);
890 info
->proc
.w
= servent
->lpServiceProc
;
891 info
->unicode
= TRUE
;
892 list_add_head( &service_list
, &info
->entry
);
895 LeaveCriticalSection( &service_cs
);
897 service_run_threads();
902 /******************************************************************************
903 * LockServiceDatabase [ADVAPI32.@]
905 SC_LOCK WINAPI
LockServiceDatabase (SC_HANDLE hSCManager
)
909 TRACE("%p\n",hSCManager
);
911 ret
= CreateSemaphoreW( NULL
, 1, 1, szSCMLock
);
912 if( ret
&& GetLastError() == ERROR_ALREADY_EXISTS
)
916 SetLastError( ERROR_SERVICE_DATABASE_LOCKED
);
919 TRACE("returning %p\n", ret
);
924 /******************************************************************************
925 * UnlockServiceDatabase [ADVAPI32.@]
927 BOOL WINAPI
UnlockServiceDatabase (SC_LOCK ScLock
)
929 TRACE("%p\n",ScLock
);
931 return CloseHandle( ScLock
);
934 /******************************************************************************
935 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
937 SERVICE_STATUS_HANDLE WINAPI
938 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName
, LPHANDLER_FUNCTION lpfHandler
)
940 LPWSTR lpServiceNameW
;
941 SERVICE_STATUS_HANDLE ret
;
943 lpServiceNameW
= SERV_dup(lpServiceName
);
944 ret
= RegisterServiceCtrlHandlerW( lpServiceNameW
, lpfHandler
);
945 SERV_free(lpServiceNameW
);
949 /******************************************************************************
950 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
956 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName
,
957 LPHANDLER_FUNCTION lpfHandler
)
959 service_data
*service
;
960 SERVICE_STATUS_HANDLE handle
= 0;
962 EnterCriticalSection( &service_cs
);
963 LIST_FOR_EACH_ENTRY( service
, &service_list
, service_data
, entry
)
965 if(!strcmpW(lpServiceName
, service
->name
))
967 service
->handler
.handler
= lpfHandler
;
968 handle
= (SERVICE_STATUS_HANDLE
)service
;
972 LeaveCriticalSection( &service_cs
);
976 /******************************************************************************
977 * SetServiceStatus [ADVAPI32.@]
984 SetServiceStatus( SERVICE_STATUS_HANDLE hService
, LPSERVICE_STATUS lpStatus
)
986 service_data
*service
;
989 TRACE("%p %x %x %x %x %x %x %x\n", hService
,
990 lpStatus
->dwServiceType
, lpStatus
->dwCurrentState
,
991 lpStatus
->dwControlsAccepted
, lpStatus
->dwWin32ExitCode
,
992 lpStatus
->dwServiceSpecificExitCode
, lpStatus
->dwCheckPoint
,
993 lpStatus
->dwWaitHint
);
995 EnterCriticalSection( &service_cs
);
996 LIST_FOR_EACH_ENTRY( service
, &service_list
, service_data
, entry
)
998 if(service
== (service_data
*)hService
)
1000 memcpy( &service
->status
, lpStatus
, sizeof(SERVICE_STATUS
) );
1001 TRACE("Set service status to %d\n",service
->status
.dwCurrentState
);
1006 LeaveCriticalSection( &service_cs
);
1012 /******************************************************************************
1013 * OpenSCManagerA [ADVAPI32.@]
1015 * Establish a connection to the service control manager and open its database.
1018 * lpMachineName [I] Pointer to machine name string
1019 * lpDatabaseName [I] Pointer to database name string
1020 * dwDesiredAccess [I] Type of access
1023 * Success: A Handle to the service control manager database
1026 SC_HANDLE WINAPI
OpenSCManagerA( LPCSTR lpMachineName
, LPCSTR lpDatabaseName
,
1027 DWORD dwDesiredAccess
)
1029 LPWSTR lpMachineNameW
, lpDatabaseNameW
;
1032 lpMachineNameW
= SERV_dup(lpMachineName
);
1033 lpDatabaseNameW
= SERV_dup(lpDatabaseName
);
1034 ret
= OpenSCManagerW(lpMachineNameW
, lpDatabaseNameW
, dwDesiredAccess
);
1035 SERV_free(lpDatabaseNameW
);
1036 SERV_free(lpMachineNameW
);
1040 /******************************************************************************
1041 * OpenSCManagerW [ADVAPI32.@]
1043 * See OpenSCManagerA.
1045 SC_HANDLE WINAPI
OpenSCManagerW( LPCWSTR lpMachineName
, LPCWSTR lpDatabaseName
,
1046 DWORD dwDesiredAccess
)
1048 struct sc_manager
*manager
;
1051 DWORD new_mask
= dwDesiredAccess
;
1053 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName
),
1054 debugstr_w(lpDatabaseName
), dwDesiredAccess
);
1056 if( lpDatabaseName
&& lpDatabaseName
[0] )
1058 if( strcmpiW( lpDatabaseName
, SERVICES_ACTIVE_DATABASEW
) == 0 )
1060 /* noop, all right */
1062 else if( strcmpiW( lpDatabaseName
, SERVICES_FAILED_DATABASEW
) == 0 )
1064 SetLastError( ERROR_DATABASE_DOES_NOT_EXIST
);
1069 SetLastError( ERROR_INVALID_NAME
);
1074 manager
= sc_handle_alloc( SC_HTYPE_MANAGER
, sizeof (struct sc_manager
),
1075 sc_handle_destroy_manager
);
1079 r
= RegConnectRegistryW(lpMachineName
,HKEY_LOCAL_MACHINE
,&hReg
);
1080 if (r
!=ERROR_SUCCESS
)
1083 r
= RegCreateKeyW(hReg
, szServiceManagerKey
, &manager
->hkey
);
1084 RegCloseKey( hReg
);
1085 if (r
!=ERROR_SUCCESS
)
1088 RtlMapGenericMask(&new_mask
, &scm_generic
);
1089 manager
->dwAccess
= new_mask
;
1090 TRACE("returning %p (access : 0x%08x)\n", manager
, manager
->dwAccess
);
1092 return (SC_HANDLE
) &manager
->hdr
;
1095 sc_handle_free( &manager
->hdr
);
1100 /******************************************************************************
1101 * ControlService [ADVAPI32.@]
1103 * Send a control code to a service.
1106 * hService [I] Handle of the service control manager database
1107 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
1108 * lpServiceStatus [O] Destination for the status of the service, if available
1115 * Unlike M$' implementation, control requests are not serialized and may be
1116 * processed asynchronously.
1118 BOOL WINAPI
ControlService( SC_HANDLE hService
, DWORD dwControl
,
1119 LPSERVICE_STATUS lpServiceStatus
)
1121 struct sc_service
*hsvc
;
1125 TRACE("%p %d %p\n", hService
, dwControl
, lpServiceStatus
);
1127 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1130 SetLastError( ERROR_INVALID_HANDLE
);
1134 ret
= QueryServiceStatus(hService
, lpServiceStatus
);
1137 ERR("failed to query service status\n");
1138 SetLastError(ERROR_SERVICE_NOT_ACTIVE
);
1142 switch (lpServiceStatus
->dwCurrentState
)
1144 case SERVICE_STOPPED
:
1145 SetLastError(ERROR_SERVICE_NOT_ACTIVE
);
1147 case SERVICE_START_PENDING
:
1148 if (dwControl
==SERVICE_CONTROL_STOP
)
1151 case SERVICE_STOP_PENDING
:
1152 SetLastError(ERROR_SERVICE_CANNOT_ACCEPT_CTRL
);
1156 handle
= service_open_pipe(hsvc
->name
);
1157 if (handle
!=INVALID_HANDLE_VALUE
)
1159 DWORD result
= ERROR_SUCCESS
;
1160 ret
= service_send_control(handle
, dwControl
, &result
);
1161 CloseHandle(handle
);
1162 if (result
!=ERROR_SUCCESS
)
1164 SetLastError(result
);
1172 /******************************************************************************
1173 * CloseServiceHandle [ADVAPI32.@]
1175 * Close a handle to a service or the service control manager database.
1178 * hSCObject [I] Handle to service or service control manager database
1185 CloseServiceHandle( SC_HANDLE hSCObject
)
1187 TRACE("%p\n", hSCObject
);
1189 sc_handle_free( (struct sc_handle
*) hSCObject
);
1195 /******************************************************************************
1196 * OpenServiceA [ADVAPI32.@]
1198 * Open a handle to a service.
1201 * hSCManager [I] Handle of the service control manager database
1202 * lpServiceName [I] Name of the service to open
1203 * dwDesiredAccess [I] Access required to the service
1206 * Success: Handle to the service
1209 SC_HANDLE WINAPI
OpenServiceA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
1210 DWORD dwDesiredAccess
)
1212 LPWSTR lpServiceNameW
;
1215 TRACE("%p %s %d\n", hSCManager
, debugstr_a(lpServiceName
), dwDesiredAccess
);
1217 lpServiceNameW
= SERV_dup(lpServiceName
);
1218 ret
= OpenServiceW( hSCManager
, lpServiceNameW
, dwDesiredAccess
);
1219 SERV_free(lpServiceNameW
);
1224 /******************************************************************************
1225 * OpenServiceW [ADVAPI32.@]
1229 SC_HANDLE WINAPI
OpenServiceW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
1230 DWORD dwDesiredAccess
)
1232 struct sc_manager
*hscm
;
1233 struct sc_service
*hsvc
;
1238 TRACE("%p %s %d\n", hSCManager
, debugstr_w(lpServiceName
), dwDesiredAccess
);
1240 hscm
= sc_handle_get_handle_data( hSCManager
, SC_HTYPE_MANAGER
);
1243 SetLastError( ERROR_INVALID_HANDLE
);
1249 SetLastError(ERROR_INVALID_ADDRESS
);
1253 r
= RegOpenKeyExW( hscm
->hkey
, lpServiceName
, 0, KEY_ALL_ACCESS
, &hKey
);
1254 if (r
!=ERROR_SUCCESS
)
1256 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST
);
1260 len
= strlenW(lpServiceName
)+1;
1261 hsvc
= sc_handle_alloc( SC_HTYPE_SERVICE
,
1262 sizeof (struct sc_service
) + len
*sizeof(WCHAR
),
1263 sc_handle_destroy_service
);
1269 strcpyW( hsvc
->name
, lpServiceName
);
1271 hsvc
->dwAccess
= dwDesiredAccess
;
1273 /* add reference to SCM handle */
1274 hscm
->hdr
.ref_count
++;
1277 TRACE("returning %p\n",hsvc
);
1279 return (SC_HANDLE
) &hsvc
->hdr
;
1282 /******************************************************************************
1283 * CreateServiceW [ADVAPI32.@]
1286 CreateServiceW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
1287 LPCWSTR lpDisplayName
, DWORD dwDesiredAccess
,
1288 DWORD dwServiceType
, DWORD dwStartType
,
1289 DWORD dwErrorControl
, LPCWSTR lpBinaryPathName
,
1290 LPCWSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
,
1291 LPCWSTR lpDependencies
, LPCWSTR lpServiceStartName
,
1292 LPCWSTR lpPassword
)
1294 struct sc_manager
*hscm
;
1295 struct sc_service
*hsvc
= NULL
;
1299 struct reg_value val
[10];
1302 TRACE("%p %s %s\n", hSCManager
,
1303 debugstr_w(lpServiceName
), debugstr_w(lpDisplayName
));
1305 hscm
= sc_handle_get_handle_data( hSCManager
, SC_HTYPE_MANAGER
);
1308 SetLastError( ERROR_INVALID_HANDLE
);
1312 r
= RegCreateKeyExW(hscm
->hkey
, lpServiceName
, 0, NULL
,
1313 REG_OPTION_NON_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &hKey
, &dp
);
1314 if (r
!=ERROR_SUCCESS
)
1317 if (dp
!= REG_CREATED_NEW_KEY
)
1319 SetLastError(ERROR_SERVICE_EXISTS
);
1324 service_set_string( &val
[n
++], szDisplayName
, lpDisplayName
);
1326 service_set_dword( &val
[n
++], szType
, &dwServiceType
);
1327 service_set_dword( &val
[n
++], szStart
, &dwStartType
);
1328 service_set_dword( &val
[n
++], szError
, &dwErrorControl
);
1330 if( lpBinaryPathName
)
1331 service_set_string( &val
[n
++], szImagePath
, lpBinaryPathName
);
1333 if( lpLoadOrderGroup
)
1334 service_set_string( &val
[n
++], szGroup
, lpLoadOrderGroup
);
1336 /* FIXME: lpDependencies is used to create both DependOnService and DependOnGroup
1337 * There is no such key as what szDependencies refers to */
1338 if( lpDependencies
)
1339 service_set_multi_string( &val
[n
++], szDependencies
, lpDependencies
);
1342 FIXME("Don't know how to add a Password for a service.\n");
1344 if( lpServiceStartName
)
1345 service_set_string( &val
[n
++], szObjectName
, lpServiceStartName
);
1347 r
= service_write_values( hKey
, val
, n
);
1348 if( r
!= ERROR_SUCCESS
)
1351 len
= strlenW(lpServiceName
)+1;
1352 len
= sizeof (struct sc_service
) + len
*sizeof(WCHAR
);
1353 hsvc
= sc_handle_alloc( SC_HTYPE_SERVICE
, len
, sc_handle_destroy_service
);
1356 lstrcpyW( hsvc
->name
, lpServiceName
);
1359 hscm
->hdr
.ref_count
++;
1361 return (SC_HANDLE
) &hsvc
->hdr
;
1364 RegCloseKey( hKey
);
1369 /******************************************************************************
1370 * CreateServiceA [ADVAPI32.@]
1373 CreateServiceA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
1374 LPCSTR lpDisplayName
, DWORD dwDesiredAccess
,
1375 DWORD dwServiceType
, DWORD dwStartType
,
1376 DWORD dwErrorControl
, LPCSTR lpBinaryPathName
,
1377 LPCSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
,
1378 LPCSTR lpDependencies
, LPCSTR lpServiceStartName
,
1381 LPWSTR lpServiceNameW
, lpDisplayNameW
, lpBinaryPathNameW
,
1382 lpLoadOrderGroupW
, lpDependenciesW
, lpServiceStartNameW
, lpPasswordW
;
1385 TRACE("%p %s %s\n", hSCManager
,
1386 debugstr_a(lpServiceName
), debugstr_a(lpDisplayName
));
1388 lpServiceNameW
= SERV_dup( lpServiceName
);
1389 lpDisplayNameW
= SERV_dup( lpDisplayName
);
1390 lpBinaryPathNameW
= SERV_dup( lpBinaryPathName
);
1391 lpLoadOrderGroupW
= SERV_dup( lpLoadOrderGroup
);
1392 lpDependenciesW
= SERV_dupmulti( lpDependencies
);
1393 lpServiceStartNameW
= SERV_dup( lpServiceStartName
);
1394 lpPasswordW
= SERV_dup( lpPassword
);
1396 r
= CreateServiceW( hSCManager
, lpServiceNameW
, lpDisplayNameW
,
1397 dwDesiredAccess
, dwServiceType
, dwStartType
, dwErrorControl
,
1398 lpBinaryPathNameW
, lpLoadOrderGroupW
, lpdwTagId
,
1399 lpDependenciesW
, lpServiceStartNameW
, lpPasswordW
);
1401 SERV_free( lpServiceNameW
);
1402 SERV_free( lpDisplayNameW
);
1403 SERV_free( lpBinaryPathNameW
);
1404 SERV_free( lpLoadOrderGroupW
);
1405 SERV_free( lpDependenciesW
);
1406 SERV_free( lpServiceStartNameW
);
1407 SERV_free( lpPasswordW
);
1413 /******************************************************************************
1414 * DeleteService [ADVAPI32.@]
1416 * Delete a service from the service control manager database.
1419 * hService [I] Handle of the service to delete
1425 BOOL WINAPI
DeleteService( SC_HANDLE hService
)
1427 struct sc_service
*hsvc
;
1429 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1432 SetLastError( ERROR_INVALID_HANDLE
);
1436 /* Close the key to the service */
1437 RegCloseKey(hsvc
->hkey
);
1439 /* Delete the service under the Service Control Manager key */
1440 RegDeleteTreeW(hsvc
->scm
->hkey
, hsvc
->name
);
1448 /******************************************************************************
1449 * StartServiceA [ADVAPI32.@]
1454 * hService [I] Handle of service
1455 * dwNumServiceArgs [I] Number of arguments
1456 * lpServiceArgVectors [I] Address of array of argument strings
1459 * - NT implements this function using an obscure RPC call.
1460 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1461 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1462 * - This will only work for shared address space. How should the service
1463 * args be transferred when address spaces are separated?
1464 * - Can only start one service at a time.
1465 * - Has no concept of privilege.
1471 BOOL WINAPI
StartServiceA( SC_HANDLE hService
, DWORD dwNumServiceArgs
,
1472 LPCSTR
*lpServiceArgVectors
)
1474 LPWSTR
*lpwstr
=NULL
;
1478 TRACE("(%p,%d,%p)\n",hService
,dwNumServiceArgs
,lpServiceArgVectors
);
1480 if (dwNumServiceArgs
)
1481 lpwstr
= HeapAlloc( GetProcessHeap(), 0,
1482 dwNumServiceArgs
*sizeof(LPWSTR
) );
1484 for(i
=0; i
<dwNumServiceArgs
; i
++)
1485 lpwstr
[i
]=SERV_dup(lpServiceArgVectors
[i
]);
1487 r
= StartServiceW(hService
, dwNumServiceArgs
, (LPCWSTR
*)lpwstr
);
1489 if (dwNumServiceArgs
)
1491 for(i
=0; i
<dwNumServiceArgs
; i
++)
1492 SERV_free(lpwstr
[i
]);
1493 HeapFree(GetProcessHeap(), 0, lpwstr
);
1499 /******************************************************************************
1500 * service_start_process [INTERNAL]
1502 static DWORD
service_start_process(struct sc_service
*hsvc
, LPDWORD ppid
)
1504 static const WCHAR _ImagePathW
[] = {'I','m','a','g','e','P','a','t','h',0};
1505 PROCESS_INFORMATION pi
;
1507 LPWSTR path
= NULL
, str
;
1508 DWORD type
, size
, ret
, svc_type
;
1512 size
= sizeof(svc_type
);
1513 if (RegQueryValueExW(hsvc
->hkey
, szType
, NULL
, &type
, (LPBYTE
)&svc_type
, &size
) || type
!= REG_DWORD
)
1516 if (svc_type
== SERVICE_KERNEL_DRIVER
)
1518 static const WCHAR winedeviceW
[] = {'\\','w','i','n','e','d','e','v','i','c','e','.','e','x','e',' ',0};
1519 DWORD len
= GetSystemDirectoryW( NULL
, 0 ) + sizeof(winedeviceW
)/sizeof(WCHAR
) + strlenW(hsvc
->name
);
1521 if (!(path
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) ))) return FALSE
;
1522 GetSystemDirectoryW( path
, len
);
1523 lstrcatW( path
, winedeviceW
);
1524 lstrcatW( path
, hsvc
->name
);
1528 /* read the executable path from the registry */
1530 ret
= RegQueryValueExW(hsvc
->hkey
, _ImagePathW
, NULL
, &type
, NULL
, &size
);
1531 if (ret
!=ERROR_SUCCESS
)
1533 str
= HeapAlloc(GetProcessHeap(),0,size
);
1534 ret
= RegQueryValueExW(hsvc
->hkey
, _ImagePathW
, NULL
, &type
, (LPBYTE
)str
, &size
);
1535 if (ret
==ERROR_SUCCESS
)
1537 size
= ExpandEnvironmentStringsW(str
,NULL
,0);
1538 path
= HeapAlloc(GetProcessHeap(),0,size
*sizeof(WCHAR
));
1539 ExpandEnvironmentStringsW(str
,path
,size
);
1541 HeapFree(GetProcessHeap(),0,str
);
1546 /* wait for the process to start and set an event or terminate */
1547 handles
[0] = service_get_event_handle( hsvc
->name
);
1548 ZeroMemory(&si
, sizeof(STARTUPINFOW
));
1549 si
.cb
= sizeof(STARTUPINFOW
);
1550 r
= CreateProcessW(NULL
, path
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
1553 if (ppid
) *ppid
= pi
.dwProcessId
;
1555 handles
[1] = pi
.hProcess
;
1556 ret
= WaitForMultipleObjectsEx(2, handles
, FALSE
, 30000, FALSE
);
1557 if(ret
!= WAIT_OBJECT_0
)
1559 SetLastError(ERROR_IO_PENDING
);
1563 CloseHandle( pi
.hThread
);
1564 CloseHandle( pi
.hProcess
);
1566 CloseHandle( handles
[0] );
1567 HeapFree(GetProcessHeap(),0,path
);
1571 static BOOL
service_wait_for_startup(SC_HANDLE hService
)
1574 SERVICE_STATUS status
;
1577 TRACE("%p\n", hService
);
1579 for (i
=0; i
<30; i
++)
1581 status
.dwCurrentState
= 0;
1582 r
= QueryServiceStatus(hService
, &status
);
1585 if (status
.dwCurrentState
== SERVICE_RUNNING
)
1587 TRACE("Service started successfully\n");
1596 /******************************************************************************
1597 * StartServiceW [ADVAPI32.@]
1599 * See StartServiceA.
1601 BOOL WINAPI
StartServiceW(SC_HANDLE hService
, DWORD dwNumServiceArgs
,
1602 LPCWSTR
*lpServiceArgVectors
)
1604 struct sc_service
*hsvc
;
1606 DWORD dwResult
, dwProcessId
= 0;
1608 HANDLE handle
= INVALID_HANDLE_VALUE
;
1610 TRACE("%p %d %p\n", hService
, dwNumServiceArgs
, lpServiceArgVectors
);
1612 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1615 SetLastError(ERROR_INVALID_HANDLE
);
1619 hLock
= LockServiceDatabase((SC_HANDLE
)hsvc
->scm
);
1623 handle
= service_open_pipe(hsvc
->name
);
1624 if (handle
==INVALID_HANDLE_VALUE
)
1626 /* start the service process */
1627 if (service_start_process(hsvc
, &dwProcessId
))
1628 handle
= service_open_pipe(hsvc
->name
);
1631 if (handle
!= INVALID_HANDLE_VALUE
)
1633 r
= service_send_start_message(handle
, lpServiceArgVectors
, dwNumServiceArgs
);
1634 CloseHandle(handle
);
1637 handle
= service_open_pipe(hsvc
->name
);
1638 if (handle
!= INVALID_HANDLE_VALUE
)
1640 service_set_processID(handle
, dwProcessId
, &dwResult
);
1641 CloseHandle(handle
);
1644 UnlockServiceDatabase( hLock
);
1646 TRACE("returning %d\n", r
);
1649 service_wait_for_startup(hService
);
1654 /******************************************************************************
1655 * QueryServiceStatus [ADVAPI32.@]
1658 * hService [I] Handle to service to get information about
1659 * lpservicestatus [O] buffer to receive the status information for the service
1662 BOOL WINAPI
QueryServiceStatus(SC_HANDLE hService
,
1663 LPSERVICE_STATUS lpservicestatus
)
1665 SERVICE_STATUS_PROCESS SvcStatusData
;
1668 TRACE("%p %p\n", hService
, lpservicestatus
);
1670 ret
= QueryServiceStatusEx(hService
, SC_STATUS_PROCESS_INFO
, (LPBYTE
)&SvcStatusData
,
1671 sizeof(SERVICE_STATUS_PROCESS
), NULL
);
1672 if (ret
) memcpy(lpservicestatus
, &SvcStatusData
, sizeof(SERVICE_STATUS
)) ;
1677 /******************************************************************************
1678 * QueryServiceStatusEx [ADVAPI32.@]
1680 * Get information about a service.
1683 * hService [I] Handle to service to get information about
1684 * InfoLevel [I] Level of information to get
1685 * lpBuffer [O] Destination for requested information
1686 * cbBufSize [I] Size of lpBuffer in bytes
1687 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1693 BOOL WINAPI
QueryServiceStatusEx(SC_HANDLE hService
, SC_STATUS_TYPE InfoLevel
,
1694 LPBYTE lpBuffer
, DWORD cbBufSize
,
1695 LPDWORD pcbBytesNeeded
)
1697 struct sc_service
*hsvc
;
1698 DWORD size
, type
, val
;
1701 LPSERVICE_STATUS_PROCESS pSvcStatusData
;
1703 TRACE("%p %d %p %d %p\n", hService
, InfoLevel
, lpBuffer
, cbBufSize
, pcbBytesNeeded
);
1705 if (InfoLevel
!= SC_STATUS_PROCESS_INFO
)
1707 SetLastError( ERROR_INVALID_LEVEL
);
1711 pSvcStatusData
= (LPSERVICE_STATUS_PROCESS
) lpBuffer
;
1712 if (pSvcStatusData
== NULL
)
1714 SetLastError( ERROR_INVALID_PARAMETER
);
1718 if (cbBufSize
< sizeof(SERVICE_STATUS_PROCESS
))
1720 if( pcbBytesNeeded
!= NULL
)
1721 *pcbBytesNeeded
= sizeof(SERVICE_STATUS_PROCESS
);
1723 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1727 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1730 SetLastError( ERROR_INVALID_HANDLE
);
1734 pipe
= service_open_pipe(hsvc
->name
);
1735 if (pipe
!= INVALID_HANDLE_VALUE
)
1737 r
= service_get_status(pipe
, pSvcStatusData
);
1743 TRACE("Failed to read service status\n");
1745 /* read the service type from the registry */
1747 r
= RegQueryValueExA(hsvc
->hkey
, "Type", NULL
, &type
, (LPBYTE
)&val
, &size
);
1748 if (r
!= ERROR_SUCCESS
|| type
!= REG_DWORD
)
1751 pSvcStatusData
->dwServiceType
= val
;
1752 pSvcStatusData
->dwCurrentState
= SERVICE_STOPPED
; /* stopped */
1753 pSvcStatusData
->dwControlsAccepted
= 0;
1754 pSvcStatusData
->dwWin32ExitCode
= ERROR_SERVICE_NEVER_STARTED
;
1755 pSvcStatusData
->dwServiceSpecificExitCode
= 0;
1756 pSvcStatusData
->dwCheckPoint
= 0;
1757 pSvcStatusData
->dwWaitHint
= 0;
1762 /******************************************************************************
1763 * QueryServiceConfigA [ADVAPI32.@]
1765 BOOL WINAPI
QueryServiceConfigA( SC_HANDLE hService
, LPQUERY_SERVICE_CONFIGA config
,
1766 DWORD size
, LPDWORD needed
)
1771 QUERY_SERVICE_CONFIGW
*configW
;
1773 TRACE("%p %p %d %p\n", hService
, config
, size
, needed
);
1775 if (!(buffer
= HeapAlloc( GetProcessHeap(), 0, 2 * size
)))
1777 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1780 configW
= (QUERY_SERVICE_CONFIGW
*)buffer
;
1781 ret
= QueryServiceConfigW( hService
, configW
, 2 * size
, needed
);
1782 if (!ret
) goto done
;
1784 config
->dwServiceType
= configW
->dwServiceType
;
1785 config
->dwStartType
= configW
->dwStartType
;
1786 config
->dwErrorControl
= configW
->dwErrorControl
;
1787 config
->lpBinaryPathName
= NULL
;
1788 config
->lpLoadOrderGroup
= NULL
;
1789 config
->dwTagId
= configW
->dwTagId
;
1790 config
->lpDependencies
= NULL
;
1791 config
->lpServiceStartName
= NULL
;
1792 config
->lpDisplayName
= NULL
;
1794 p
= (LPSTR
)(config
+ 1);
1795 n
= size
- sizeof(*config
);
1798 #define MAP_STR(str) \
1802 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1803 if (!sz) goto done; \
1810 MAP_STR( lpBinaryPathName
);
1811 MAP_STR( lpLoadOrderGroup
);
1812 MAP_STR( lpDependencies
);
1813 MAP_STR( lpServiceStartName
);
1814 MAP_STR( lpDisplayName
);
1817 *needed
= p
- (LPSTR
)config
;
1821 HeapFree( GetProcessHeap(), 0, buffer
);
1825 /******************************************************************************
1826 * QueryServiceConfigW [ADVAPI32.@]
1829 QueryServiceConfigW( SC_HANDLE hService
,
1830 LPQUERY_SERVICE_CONFIGW lpServiceConfig
,
1831 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
1833 WCHAR str_buffer
[ MAX_PATH
];
1835 DWORD type
, val
, sz
, total
, n
;
1838 struct sc_service
*hsvc
;
1840 TRACE("%p %p %d %p\n", hService
, lpServiceConfig
,
1841 cbBufSize
, pcbBytesNeeded
);
1843 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1846 SetLastError( ERROR_INVALID_HANDLE
);
1851 /* TODO: Check which members are mandatory and what the registry types
1852 * should be. This should of course also be tested when a service is
1856 /* calculate the size required first */
1857 total
= sizeof (QUERY_SERVICE_CONFIGW
);
1859 sz
= sizeof(str_buffer
);
1860 r
= RegQueryValueExW( hKey
, szImagePath
, 0, &type
, (LPBYTE
) str_buffer
, &sz
);
1861 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
|| type
== REG_EXPAND_SZ
) )
1863 sz
= ExpandEnvironmentStringsW(str_buffer
,NULL
,0);
1864 if( 0 == sz
) return FALSE
;
1866 total
+= sizeof(WCHAR
) * sz
;
1870 /* FIXME: set last error */
1875 r
= RegQueryValueExW( hKey
, szGroup
, 0, &type
, NULL
, &sz
);
1876 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1879 total
+= sizeof(WCHAR
);
1882 r
= RegQueryValueExW( hKey
, szDependencies
, 0, &type
, NULL
, &sz
);
1883 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_MULTI_SZ
) )
1886 total
+= sizeof(WCHAR
);
1889 r
= RegQueryValueExW( hKey
, szObjectName
, 0, &type
, NULL
, &sz
);
1890 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1893 total
+= sizeof(WCHAR
);
1896 r
= RegQueryValueExW( hKey
, szDisplayName
, 0, &type
, NULL
, &sz
);
1897 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1900 total
+= sizeof(WCHAR
);
1902 *pcbBytesNeeded
= total
;
1904 /* if there's not enough memory, return an error */
1905 if( total
> cbBufSize
)
1907 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1911 ZeroMemory( lpServiceConfig
, total
);
1914 r
= RegQueryValueExW( hKey
, szType
, 0, &type
, (LPBYTE
)&val
, &sz
);
1915 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_DWORD
) )
1916 lpServiceConfig
->dwServiceType
= val
;
1919 r
= RegQueryValueExW( hKey
, szStart
, 0, &type
, (LPBYTE
)&val
, &sz
);
1920 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_DWORD
) )
1921 lpServiceConfig
->dwStartType
= val
;
1924 r
= RegQueryValueExW( hKey
, szError
, 0, &type
, (LPBYTE
)&val
, &sz
);
1925 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_DWORD
) )
1926 lpServiceConfig
->dwErrorControl
= val
;
1929 r
= RegQueryValueExW( hKey
, szTag
, 0, &type
, (LPBYTE
)&val
, &sz
);
1930 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_DWORD
) )
1931 lpServiceConfig
->dwTagId
= val
;
1933 /* now do the strings */
1934 p
= (LPBYTE
) &lpServiceConfig
[1];
1935 n
= total
- sizeof (QUERY_SERVICE_CONFIGW
);
1937 sz
= sizeof(str_buffer
);
1938 r
= RegQueryValueExW( hKey
, szImagePath
, 0, &type
, (LPBYTE
) str_buffer
, &sz
);
1939 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
|| type
== REG_EXPAND_SZ
) )
1941 sz
= ExpandEnvironmentStringsW(str_buffer
, (LPWSTR
) p
, n
);
1942 sz
*= sizeof(WCHAR
);
1943 if( 0 == sz
|| sz
> n
) return FALSE
;
1945 lpServiceConfig
->lpBinaryPathName
= (LPWSTR
) p
;
1951 /* FIXME: set last error */
1956 r
= RegQueryValueExW( hKey
, szGroup
, 0, &type
, p
, &sz
);
1957 lpServiceConfig
->lpLoadOrderGroup
= (LPWSTR
) p
;
1958 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1971 r
= RegQueryValueExW( hKey
, szDependencies
, 0, &type
, p
, &sz
);
1972 lpServiceConfig
->lpDependencies
= (LPWSTR
) p
;
1973 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1986 r
= RegQueryValueExW( hKey
, szObjectName
, 0, &type
, p
, &sz
);
1987 lpServiceConfig
->lpServiceStartName
= (LPWSTR
) p
;
1988 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
2001 r
= RegQueryValueExW( hKey
, szDisplayName
, 0, &type
, p
, &sz
);
2002 lpServiceConfig
->lpDisplayName
= (LPWSTR
) p
;
2003 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
2016 ERR("Buffer overflow!\n");
2018 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig
->lpBinaryPathName
) );
2019 TRACE("Group = %s\n", debugstr_w(lpServiceConfig
->lpLoadOrderGroup
) );
2020 TRACE("Dependencies = %s\n", debugstr_w(lpServiceConfig
->lpDependencies
) );
2021 TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig
->lpServiceStartName
) );
2022 TRACE("Display name = %s\n", debugstr_w(lpServiceConfig
->lpDisplayName
) );
2027 /******************************************************************************
2028 * EnumServicesStatusA [ADVAPI32.@]
2031 EnumServicesStatusA( SC_HANDLE hSCManager
, DWORD dwServiceType
,
2032 DWORD dwServiceState
, LPENUM_SERVICE_STATUSA lpServices
,
2033 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
2034 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
)
2036 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager
,
2037 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
2038 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
);
2039 SetLastError (ERROR_ACCESS_DENIED
);
2043 /******************************************************************************
2044 * EnumServicesStatusW [ADVAPI32.@]
2047 EnumServicesStatusW( SC_HANDLE hSCManager
, DWORD dwServiceType
,
2048 DWORD dwServiceState
, LPENUM_SERVICE_STATUSW lpServices
,
2049 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
2050 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
)
2052 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager
,
2053 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
2054 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
);
2055 SetLastError (ERROR_ACCESS_DENIED
);
2059 /******************************************************************************
2060 * EnumServicesStatusExA [ADVAPI32.@]
2063 EnumServicesStatusExA(SC_HANDLE hSCManager
, SC_ENUM_TYPE InfoLevel
, DWORD dwServiceType
,
2064 DWORD dwServiceState
, LPBYTE lpServices
, DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
2065 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
, LPCSTR pszGroupName
)
2067 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager
, InfoLevel
,
2068 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
2069 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
, debugstr_a(pszGroupName
));
2070 SetLastError (ERROR_ACCESS_DENIED
);
2074 /******************************************************************************
2075 * EnumServicesStatusExW [ADVAPI32.@]
2078 EnumServicesStatusExW(SC_HANDLE hSCManager
, SC_ENUM_TYPE InfoLevel
, DWORD dwServiceType
,
2079 DWORD dwServiceState
, LPBYTE lpServices
, DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
2080 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
, LPCWSTR pszGroupName
)
2082 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager
, InfoLevel
,
2083 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
2084 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
, debugstr_w(pszGroupName
));
2085 SetLastError (ERROR_ACCESS_DENIED
);
2089 /******************************************************************************
2090 * GetServiceKeyNameA [ADVAPI32.@]
2092 BOOL WINAPI
GetServiceKeyNameA( SC_HANDLE hSCManager
, LPCSTR lpDisplayName
,
2093 LPSTR lpServiceName
, LPDWORD lpcchBuffer
)
2095 FIXME("%p %s %p %p\n", hSCManager
, debugstr_a(lpDisplayName
), lpServiceName
, lpcchBuffer
);
2099 /******************************************************************************
2100 * GetServiceKeyNameW [ADVAPI32.@]
2102 BOOL WINAPI
GetServiceKeyNameW( SC_HANDLE hSCManager
, LPCWSTR lpDisplayName
,
2103 LPWSTR lpServiceName
, LPDWORD lpcchBuffer
)
2105 FIXME("%p %s %p %p\n", hSCManager
, debugstr_w(lpDisplayName
), lpServiceName
, lpcchBuffer
);
2109 /******************************************************************************
2110 * QueryServiceLockStatusA [ADVAPI32.@]
2112 BOOL WINAPI
QueryServiceLockStatusA( SC_HANDLE hSCManager
,
2113 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus
,
2114 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
2116 FIXME("%p %p %08x %p\n", hSCManager
, lpLockStatus
, cbBufSize
, pcbBytesNeeded
);
2121 /******************************************************************************
2122 * QueryServiceLockStatusW [ADVAPI32.@]
2124 BOOL WINAPI
QueryServiceLockStatusW( SC_HANDLE hSCManager
,
2125 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus
,
2126 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
2128 FIXME("%p %p %08x %p\n", hSCManager
, lpLockStatus
, cbBufSize
, pcbBytesNeeded
);
2133 /******************************************************************************
2134 * GetServiceDisplayNameA [ADVAPI32.@]
2136 BOOL WINAPI
GetServiceDisplayNameA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
2137 LPSTR lpDisplayName
, LPDWORD lpcchBuffer
)
2139 struct sc_manager
*hscm
;
2143 TRACE("%p %s %p %p\n", hSCManager
,
2144 debugstr_a(lpServiceName
), lpDisplayName
, lpcchBuffer
);
2148 SetLastError(ERROR_INVALID_PARAMETER
);
2152 hscm
= sc_handle_get_handle_data(hSCManager
, SC_HTYPE_MANAGER
);
2155 SetLastError(ERROR_INVALID_HANDLE
);
2159 size
= *lpcchBuffer
;
2160 ret
= RegGetValueA(hscm
->hkey
, lpServiceName
, "DisplayName", RRF_RT_REG_SZ
, &type
, lpDisplayName
, &size
);
2161 if (!ret
&& !lpDisplayName
&& size
)
2162 ret
= ERROR_MORE_DATA
;
2166 if (lpDisplayName
&& *lpcchBuffer
) *lpDisplayName
= 0;
2168 if (ret
== ERROR_MORE_DATA
)
2170 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2171 *lpcchBuffer
= size
- 1;
2180 /******************************************************************************
2181 * GetServiceDisplayNameW [ADVAPI32.@]
2183 BOOL WINAPI
GetServiceDisplayNameW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
2184 LPWSTR lpDisplayName
, LPDWORD lpcchBuffer
)
2186 struct sc_manager
*hscm
;
2190 TRACE("%p %s %p %p\n", hSCManager
,
2191 debugstr_w(lpServiceName
), lpDisplayName
, lpcchBuffer
);
2195 SetLastError(ERROR_INVALID_PARAMETER
);
2199 hscm
= sc_handle_get_handle_data(hSCManager
, SC_HTYPE_MANAGER
);
2202 SetLastError(ERROR_INVALID_HANDLE
);
2206 size
= *lpcchBuffer
* sizeof(WCHAR
);
2207 ret
= RegGetValueW(hscm
->hkey
, lpServiceName
, szDisplayName
, RRF_RT_REG_SZ
, &type
, lpDisplayName
, &size
);
2208 if (!ret
&& !lpDisplayName
&& size
)
2209 ret
= ERROR_MORE_DATA
;
2213 if (lpDisplayName
&& *lpcchBuffer
) *lpDisplayName
= 0;
2215 if (ret
== ERROR_MORE_DATA
)
2217 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2218 *lpcchBuffer
= (size
/ sizeof(WCHAR
)) - 1;
2227 /******************************************************************************
2228 * ChangeServiceConfigW [ADVAPI32.@]
2230 BOOL WINAPI
ChangeServiceConfigW( SC_HANDLE hService
, DWORD dwServiceType
,
2231 DWORD dwStartType
, DWORD dwErrorControl
, LPCWSTR lpBinaryPathName
,
2232 LPCWSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
, LPCWSTR lpDependencies
,
2233 LPCWSTR lpServiceStartName
, LPCWSTR lpPassword
, LPCWSTR lpDisplayName
)
2235 struct reg_value val
[10];
2236 struct sc_service
*hsvc
;
2237 DWORD r
= ERROR_SUCCESS
;
2241 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2242 hService
, dwServiceType
, dwStartType
, dwErrorControl
,
2243 debugstr_w(lpBinaryPathName
), debugstr_w(lpLoadOrderGroup
),
2244 lpdwTagId
, lpDependencies
, debugstr_w(lpServiceStartName
),
2245 debugstr_w(lpPassword
), debugstr_w(lpDisplayName
) );
2247 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
2250 SetLastError( ERROR_INVALID_HANDLE
);
2255 if( dwServiceType
!= SERVICE_NO_CHANGE
)
2256 service_set_dword( &val
[n
++], szType
, &dwServiceType
);
2258 if( dwStartType
!= SERVICE_NO_CHANGE
)
2259 service_set_dword( &val
[n
++], szStart
, &dwStartType
);
2261 if( dwErrorControl
!= SERVICE_NO_CHANGE
)
2262 service_set_dword( &val
[n
++], szError
, &dwErrorControl
);
2264 if( lpBinaryPathName
)
2265 service_set_string( &val
[n
++], szImagePath
, lpBinaryPathName
);
2267 if( lpLoadOrderGroup
)
2268 service_set_string( &val
[n
++], szGroup
, lpLoadOrderGroup
);
2270 /* FIXME: lpDependencies is used to create/change both DependOnService and DependOnGroup
2271 * There is no such key as what szDependencies refers to */
2272 if( lpDependencies
)
2273 service_set_multi_string( &val
[n
++], szDependencies
, lpDependencies
);
2276 FIXME("ignoring password\n");
2278 if( lpServiceStartName
)
2279 service_set_string( &val
[n
++], szObjectName
, lpServiceStartName
);
2281 r
= service_write_values( hsvc
->hkey
, val
, n
);
2283 return (r
== ERROR_SUCCESS
) ? TRUE
: FALSE
;
2286 /******************************************************************************
2287 * ChangeServiceConfigA [ADVAPI32.@]
2289 BOOL WINAPI
ChangeServiceConfigA( SC_HANDLE hService
, DWORD dwServiceType
,
2290 DWORD dwStartType
, DWORD dwErrorControl
, LPCSTR lpBinaryPathName
,
2291 LPCSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
, LPCSTR lpDependencies
,
2292 LPCSTR lpServiceStartName
, LPCSTR lpPassword
, LPCSTR lpDisplayName
)
2294 LPWSTR wBinaryPathName
, wLoadOrderGroup
, wDependencies
;
2295 LPWSTR wServiceStartName
, wPassword
, wDisplayName
;
2298 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2299 hService
, dwServiceType
, dwStartType
, dwErrorControl
,
2300 debugstr_a(lpBinaryPathName
), debugstr_a(lpLoadOrderGroup
),
2301 lpdwTagId
, lpDependencies
, debugstr_a(lpServiceStartName
),
2302 debugstr_a(lpPassword
), debugstr_a(lpDisplayName
) );
2304 wBinaryPathName
= SERV_dup( lpBinaryPathName
);
2305 wLoadOrderGroup
= SERV_dup( lpLoadOrderGroup
);
2306 wDependencies
= SERV_dupmulti( lpDependencies
);
2307 wServiceStartName
= SERV_dup( lpServiceStartName
);
2308 wPassword
= SERV_dup( lpPassword
);
2309 wDisplayName
= SERV_dup( lpDisplayName
);
2311 r
= ChangeServiceConfigW( hService
, dwServiceType
,
2312 dwStartType
, dwErrorControl
, wBinaryPathName
,
2313 wLoadOrderGroup
, lpdwTagId
, wDependencies
,
2314 wServiceStartName
, wPassword
, wDisplayName
);
2316 SERV_free( wBinaryPathName
);
2317 SERV_free( wLoadOrderGroup
);
2318 SERV_free( wDependencies
);
2319 SERV_free( wServiceStartName
);
2320 SERV_free( wPassword
);
2321 SERV_free( wDisplayName
);
2326 /******************************************************************************
2327 * ChangeServiceConfig2A [ADVAPI32.@]
2329 BOOL WINAPI
ChangeServiceConfig2A( SC_HANDLE hService
, DWORD dwInfoLevel
,
2334 TRACE("%p %d %p\n",hService
, dwInfoLevel
, lpInfo
);
2336 if (dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
2338 LPSERVICE_DESCRIPTIONA sd
= (LPSERVICE_DESCRIPTIONA
) lpInfo
;
2339 SERVICE_DESCRIPTIONW sdw
;
2341 sdw
.lpDescription
= SERV_dup( sd
->lpDescription
);
2343 r
= ChangeServiceConfig2W( hService
, dwInfoLevel
, &sdw
);
2345 SERV_free( sdw
.lpDescription
);
2347 else if (dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
2349 LPSERVICE_FAILURE_ACTIONSA fa
= (LPSERVICE_FAILURE_ACTIONSA
) lpInfo
;
2350 SERVICE_FAILURE_ACTIONSW faw
;
2352 faw
.dwResetPeriod
= fa
->dwResetPeriod
;
2353 faw
.lpRebootMsg
= SERV_dup( fa
->lpRebootMsg
);
2354 faw
.lpCommand
= SERV_dup( fa
->lpCommand
);
2355 faw
.cActions
= fa
->cActions
;
2356 faw
.lpsaActions
= fa
->lpsaActions
;
2358 r
= ChangeServiceConfig2W( hService
, dwInfoLevel
, &faw
);
2360 SERV_free( faw
.lpRebootMsg
);
2361 SERV_free( faw
.lpCommand
);
2364 SetLastError( ERROR_INVALID_PARAMETER
);
2369 /******************************************************************************
2370 * ChangeServiceConfig2W [ADVAPI32.@]
2372 BOOL WINAPI
ChangeServiceConfig2W( SC_HANDLE hService
, DWORD dwInfoLevel
,
2376 struct sc_service
*hsvc
;
2378 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
2381 SetLastError( ERROR_INVALID_HANDLE
);
2386 if (dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
2388 static const WCHAR szDescription
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2389 LPSERVICE_DESCRIPTIONW sd
= (LPSERVICE_DESCRIPTIONW
)lpInfo
;
2390 if (sd
->lpDescription
)
2392 TRACE("Setting Description to %s\n",debugstr_w(sd
->lpDescription
));
2393 if (sd
->lpDescription
[0] == 0)
2394 RegDeleteValueW(hKey
,szDescription
);
2396 RegSetValueExW(hKey
, szDescription
, 0, REG_SZ
,
2397 (LPVOID
)sd
->lpDescription
,
2398 sizeof(WCHAR
)*(strlenW(sd
->lpDescription
)+1));
2402 FIXME("STUB: %p %d %p\n",hService
, dwInfoLevel
, lpInfo
);
2406 /******************************************************************************
2407 * QueryServiceObjectSecurity [ADVAPI32.@]
2409 BOOL WINAPI
QueryServiceObjectSecurity(SC_HANDLE hService
,
2410 SECURITY_INFORMATION dwSecurityInformation
,
2411 PSECURITY_DESCRIPTOR lpSecurityDescriptor
,
2412 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
2416 FIXME("%p %d %p %u %p\n", hService
, dwSecurityInformation
,
2417 lpSecurityDescriptor
, cbBufSize
, pcbBytesNeeded
);
2419 InitializeSecurityDescriptor(lpSecurityDescriptor
, SECURITY_DESCRIPTOR_REVISION
);
2421 pACL
= HeapAlloc( GetProcessHeap(), 0, sizeof(ACL
) );
2422 InitializeAcl(pACL
, sizeof(ACL
), ACL_REVISION
);
2423 SetSecurityDescriptorDacl(lpSecurityDescriptor
, TRUE
, pACL
, TRUE
);
2427 /******************************************************************************
2428 * SetServiceObjectSecurity [ADVAPI32.@]
2430 BOOL WINAPI
SetServiceObjectSecurity(SC_HANDLE hService
,
2431 SECURITY_INFORMATION dwSecurityInformation
,
2432 PSECURITY_DESCRIPTOR lpSecurityDescriptor
)
2434 FIXME("%p %d %p\n", hService
, dwSecurityInformation
, lpSecurityDescriptor
);
2438 /******************************************************************************
2439 * SetServiceBits [ADVAPI32.@]
2441 BOOL WINAPI
SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus
,
2442 DWORD dwServiceBits
,
2444 BOOL bUpdateImmediately
)
2446 FIXME("%p %08x %x %x\n", hServiceStatus
, dwServiceBits
,
2447 bSetBitsOn
, bUpdateImmediately
);
2451 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerExA( LPCSTR lpServiceName
,
2452 LPHANDLER_FUNCTION_EX lpHandlerProc
, LPVOID lpContext
)
2454 FIXME("%s %p %p\n", debugstr_a(lpServiceName
), lpHandlerProc
, lpContext
);
2458 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName
,
2459 LPHANDLER_FUNCTION_EX lpHandlerProc
, LPVOID lpContext
)
2461 service_data
*service
;
2462 SERVICE_STATUS_HANDLE handle
= 0;
2464 TRACE("%s %p %p\n", debugstr_w(lpServiceName
), lpHandlerProc
, lpContext
);
2466 EnterCriticalSection( &service_cs
);
2467 LIST_FOR_EACH_ENTRY( service
, &service_list
, service_data
, entry
)
2469 if(!strcmpW(lpServiceName
, service
->name
))
2471 service
->handler
.handler_ex
= lpHandlerProc
;
2472 service
->context
= lpContext
;
2473 service
->extended
= TRUE
;
2474 handle
= (SERVICE_STATUS_HANDLE
)service
;
2478 LeaveCriticalSection( &service_cs
);