2 * Win32 advapi functions
4 * Copyright 1995 Sven Verdoolaege
5 * Copyright 2005 Mike McCormack
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32 #include "wine/unicode.h"
33 #include "wine/debug.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(advapi
);
40 static const WCHAR szServiceManagerKey
[] = { 'S','y','s','t','e','m','\\',
41 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
42 'S','e','r','v','i','c','e','s','\\',0 };
43 static const WCHAR szSCMLock
[] = {'A','D','V','A','P','I','_','S','C','M',
46 typedef struct service_start_info_t
53 #define WINESERV_STARTINFO 1
54 #define WINESERV_GETSTATUS 2
55 #define WINESERV_SENDCONTROL 3
57 typedef struct service_data_t
59 struct service_data_t
*next
;
60 LPHANDLER_FUNCTION handler
;
61 SERVICE_STATUS status
;
65 LPSERVICE_MAIN_FUNCTIONA a
;
66 LPSERVICE_MAIN_FUNCTIONW w
;
72 static CRITICAL_SECTION service_cs
;
73 static CRITICAL_SECTION_DEBUG service_cs_debug
=
76 { &service_cs_debug
.ProcessLocksList
,
77 &service_cs_debug
.ProcessLocksList
},
78 0, 0, { (DWORD_PTR
)(__FILE__
": service_cs") }
80 static CRITICAL_SECTION service_cs
= { &service_cs_debug
, -1, 0, 0, 0, 0 };
82 service_data
*service_list
;
84 /******************************************************************************
88 #define MAX_SERVICE_NAME 256
90 typedef enum { SC_HTYPE_MANAGER
, SC_HTYPE_SERVICE
} SC_HANDLE_TYPE
;
93 typedef VOID (*sc_handle_destructor
)(struct sc_handle
*);
99 sc_handle_destructor destroy
;
102 struct sc_manager
/* service control manager handle */
104 struct sc_handle hdr
;
105 HKEY hkey
; /* handle to services database in the registry */
108 struct sc_service
/* service handle */
110 struct sc_handle hdr
;
111 HKEY hkey
; /* handle to service entry in the registry (under hkey) */
112 struct sc_manager
*scm
; /* pointer to SCM handle */
116 static void *sc_handle_alloc(SC_HANDLE_TYPE htype
, DWORD size
,
117 sc_handle_destructor destroy
)
119 struct sc_handle
*hdr
;
121 hdr
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
126 hdr
->destroy
= destroy
;
128 TRACE("sc_handle type=%d -> %p\n", htype
, hdr
);
132 static void *sc_handle_get_handle_data(SC_HANDLE handle
, DWORD htype
)
134 struct sc_handle
*hdr
= (struct sc_handle
*) handle
;
138 if (hdr
->htype
!= htype
)
143 static void sc_handle_free(struct sc_handle
* hdr
)
147 if (--hdr
->ref_count
)
150 HeapFree(GetProcessHeap(), 0, hdr
);
153 static void sc_handle_destroy_manager(struct sc_handle
*handle
)
155 struct sc_manager
*mgr
= (struct sc_manager
*) handle
;
157 TRACE("destroying SC Manager %p\n", mgr
);
159 RegCloseKey(mgr
->hkey
);
162 static void sc_handle_destroy_service(struct sc_handle
*handle
)
164 struct sc_service
*svc
= (struct sc_service
*) handle
;
166 TRACE("destroying service %p\n", svc
);
168 RegCloseKey(svc
->hkey
);
170 sc_handle_free(&svc
->scm
->hdr
);
174 /******************************************************************************
175 * String management functions
177 static inline LPWSTR
SERV_dup( LPCSTR str
)
184 len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
185 wstr
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof (WCHAR
) );
186 MultiByteToWideChar( CP_ACP
, 0, str
, -1, wstr
, len
);
190 static inline LPWSTR
SERV_dupmulti(LPCSTR str
)
198 len
+= MultiByteToWideChar( CP_ACP
, 0, &str
[n
], -1, NULL
, 0 );
199 n
+= (strlen( &str
[n
] ) + 1);
204 wstr
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof (WCHAR
) );
205 MultiByteToWideChar( CP_ACP
, 0, str
, n
, wstr
, len
);
209 static inline VOID
SERV_free( LPWSTR wstr
)
211 HeapFree( GetProcessHeap(), 0, wstr
);
214 /******************************************************************************
215 * registry access functions and data
217 static const WCHAR szDisplayName
[] = {
218 'D','i','s','p','l','a','y','N','a','m','e', 0 };
219 static const WCHAR szType
[] = {'T','y','p','e',0};
220 static const WCHAR szStart
[] = {'S','t','a','r','t',0};
221 static const WCHAR szError
[] = {
222 'E','r','r','o','r','C','o','n','t','r','o','l', 0};
223 static const WCHAR szImagePath
[] = {'I','m','a','g','e','P','a','t','h',0};
224 static const WCHAR szGroup
[] = {'G','r','o','u','p',0};
225 static const WCHAR szDependencies
[] = {
226 'D','e','p','e','n','d','e','n','c','i','e','s',0};
227 static const WCHAR szDependOnService
[] = {
228 'D','e','p','e','n','d','O','n','S','e','r','v','i','c','e',0};
237 static inline void service_set_value( struct reg_value
*val
,
238 DWORD type
, LPCWSTR name
, LPCVOID data
, DWORD size
)
246 static inline void service_set_dword( struct reg_value
*val
,
247 LPCWSTR name
, DWORD
*data
)
249 service_set_value( val
, REG_DWORD
, name
, data
, sizeof (DWORD
));
252 static inline void service_set_string( struct reg_value
*val
,
253 LPCWSTR name
, LPCWSTR string
)
255 DWORD len
= (lstrlenW(string
)+1) * sizeof (WCHAR
);
256 service_set_value( val
, REG_SZ
, name
, string
, len
);
259 static inline void service_set_multi_string( struct reg_value
*val
,
260 LPCWSTR name
, LPCWSTR string
)
264 /* determine the length of a double null terminated multi string */
266 len
+= (lstrlenW( &string
[ len
] )+1);
267 } while ( string
[ len
++ ] );
269 len
*= sizeof (WCHAR
);
270 service_set_value( val
, REG_MULTI_SZ
, name
, string
, len
);
273 static inline LONG
service_write_values( HKEY hKey
,
274 struct reg_value
*val
, int n
)
276 LONG r
= ERROR_SUCCESS
;
281 r
= RegSetValueExW(hKey
, val
[i
].name
, 0, val
[i
].type
,
282 (const BYTE
*)val
[i
].data
, val
[i
].size
);
283 if( r
!= ERROR_SUCCESS
)
289 /******************************************************************************
290 * Service IPC functions
292 static LPWSTR
service_get_pipe_name(LPWSTR service
)
294 static const WCHAR prefix
[] = { '\\','\\','.','\\','p','i','p','e','\\',
295 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
299 len
= sizeof prefix
+ strlenW(service
)*sizeof(WCHAR
);
300 name
= HeapAlloc(GetProcessHeap(), 0, len
);
301 strcpyW(name
, prefix
);
302 strcatW(name
, service
);
306 static HANDLE
service_open_pipe(LPWSTR service
)
308 LPWSTR szPipe
= service_get_pipe_name( service
);
309 HANDLE handle
= INVALID_HANDLE_VALUE
;
312 handle
= CreateFileW(szPipe
, GENERIC_READ
|GENERIC_WRITE
,
313 0, NULL
, OPEN_ALWAYS
, 0, NULL
);
314 if (handle
!= INVALID_HANDLE_VALUE
)
316 if (GetLastError() != ERROR_PIPE_BUSY
)
318 } while (WaitNamedPipeW(szPipe
, NMPWAIT_WAIT_FOREVER
));
324 /******************************************************************************
325 * service_get_event_handle
327 static HANDLE
service_get_event_handle(LPWSTR service
)
329 static const WCHAR prefix
[] = {
330 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
335 len
= sizeof prefix
+ strlenW(service
)*sizeof(WCHAR
);
336 name
= HeapAlloc(GetProcessHeap(), 0, len
);
337 strcpyW(name
, prefix
);
338 strcatW(name
, service
);
339 handle
= CreateEventW(NULL
, TRUE
, FALSE
, name
);
344 /******************************************************************************
347 * Call into the main service routine provided by StartServiceCtrlDispatcher.
349 static DWORD WINAPI
service_thread(LPVOID arg
)
351 service_data
*info
= arg
;
352 LPWSTR str
= info
->args
;
353 DWORD argc
= 0, len
= 0;
359 len
+= strlenW(&str
[len
]) + 1;
367 argv
= HeapAlloc(GetProcessHeap(), 0, (argc
+1)*sizeof(LPWSTR
));
368 for (argc
=0, p
=str
; *p
; p
+= strlenW(p
) + 1)
372 info
->proc
.w(argc
, argv
);
373 HeapFree(GetProcessHeap(), 0, argv
);
377 LPSTR strA
, *argv
, p
;
380 lenA
= WideCharToMultiByte(CP_ACP
,0, str
, len
, NULL
, 0, NULL
, NULL
);
381 strA
= HeapAlloc(GetProcessHeap(), 0, lenA
);
382 WideCharToMultiByte(CP_ACP
,0, str
, len
, strA
, lenA
, NULL
, NULL
);
384 argv
= HeapAlloc(GetProcessHeap(), 0, (argc
+1)*sizeof(LPSTR
));
385 for (argc
=0, p
=strA
; *p
; p
+= strlen(p
) + 1)
389 info
->proc
.a(argc
, argv
);
390 HeapFree(GetProcessHeap(), 0, argv
);
391 HeapFree(GetProcessHeap(), 0, strA
);
396 /******************************************************************************
397 * service_handle_start
399 static BOOL
service_handle_start(HANDLE pipe
, service_data
*service
, DWORD count
)
401 DWORD read
= 0, result
= 0;
405 TRACE("%p %p %ld\n", pipe
, service
, count
);
407 args
= HeapAlloc(GetProcessHeap(), 0, count
*sizeof(WCHAR
));
408 r
= ReadFile(pipe
, args
, count
*sizeof(WCHAR
), &read
, NULL
);
409 if (!r
|| count
!=read
/sizeof(WCHAR
) || args
[count
-1])
411 ERR("pipe read failed r = %d count = %ld/%ld args[n-1]=%s\n",
412 r
, count
, read
/sizeof(WCHAR
), debugstr_wn(args
, count
));
418 ERR("service is not stopped\n");
423 SERV_free(service
->args
);
424 service
->args
= args
;
426 service
->thread
= CreateThread( NULL
, 0, service_thread
,
430 HeapFree(GetProcessHeap(), 0, args
);
431 WriteFile( pipe
, &result
, sizeof result
, &read
, NULL
);
436 /******************************************************************************
437 * service_send_start_message
439 static BOOL
service_send_start_message(HANDLE pipe
, LPCWSTR
*argv
, DWORD argc
)
441 DWORD i
, len
, count
, result
;
442 service_start_info
*ssi
;
446 TRACE("%p %p %ld\n", pipe
, argv
, argc
);
448 /* calculate how much space do we need to send the startup info */
450 for (i
=0; i
<argc
; i
++)
451 len
+= strlenW(argv
[i
])+1;
453 ssi
= HeapAlloc(GetProcessHeap(),0,sizeof *ssi
+ (len
-1)*sizeof(WCHAR
));
454 ssi
->cmd
= WINESERV_STARTINFO
;
457 /* copy service args into a single buffer*/
459 for (i
=0; i
<argc
; i
++)
466 r
= WriteFile(pipe
, ssi
, sizeof *ssi
+ len
*sizeof(WCHAR
), &count
, NULL
);
468 r
= ReadFile(pipe
, &result
, sizeof result
, &count
, NULL
);
470 HeapFree(GetProcessHeap(),0,ssi
);
475 /******************************************************************************
476 * service_handle_get_status
478 static BOOL
service_handle_get_status(HANDLE pipe
, service_data
*service
)
482 return WriteFile(pipe
, &service
->status
,
483 sizeof service
->status
, &count
, NULL
);
486 /******************************************************************************
489 static BOOL
service_get_status(HANDLE pipe
, LPSERVICE_STATUS status
)
491 DWORD cmd
[2], count
= 0;
494 cmd
[0] = WINESERV_GETSTATUS
;
496 r
= WriteFile( pipe
, cmd
, sizeof cmd
, &count
, NULL
);
497 if (!r
|| count
!= sizeof cmd
)
499 ERR("service protocol error - failed to write pipe!\n");
502 r
= ReadFile( pipe
, status
, sizeof *status
, &count
, NULL
);
503 if (!r
|| count
!= sizeof *status
)
504 ERR("service protocol error - failed to read pipe "
505 "r = %d count = %ld/%d!\n", r
, count
, sizeof *status
);
509 /******************************************************************************
510 * service_send_control
512 static BOOL
service_send_control(HANDLE pipe
, DWORD dwControl
, DWORD
*result
)
514 DWORD cmd
[2], count
= 0;
517 cmd
[0] = WINESERV_SENDCONTROL
;
519 r
= WriteFile(pipe
, cmd
, sizeof cmd
, &count
, NULL
);
520 if (!r
|| count
!= sizeof cmd
)
522 ERR("service protocol error - failed to write pipe!\n");
525 r
= ReadFile(pipe
, result
, sizeof *result
, &count
, NULL
);
526 if (!r
|| count
!= sizeof *result
)
527 ERR("service protocol error - failed to read pipe "
528 "r = %d count = %ld/%d!\n", r
, count
, sizeof *result
);
532 /******************************************************************************
533 * service_accepts_control
535 static BOOL
service_accepts_control(service_data
*service
, DWORD dwControl
)
537 DWORD a
= service
->status
.dwControlsAccepted
;
541 case SERVICE_CONTROL_INTERROGATE
:
543 case SERVICE_CONTROL_STOP
:
544 if (a
&SERVICE_ACCEPT_STOP
)
547 case SERVICE_CONTROL_SHUTDOWN
:
548 if (a
&SERVICE_ACCEPT_SHUTDOWN
)
551 case SERVICE_CONTROL_PAUSE
:
552 case SERVICE_CONTROL_CONTINUE
:
553 if (a
&SERVICE_ACCEPT_PAUSE_CONTINUE
)
556 case SERVICE_CONTROL_PARAMCHANGE
:
557 if (a
&SERVICE_ACCEPT_PARAMCHANGE
)
560 case SERVICE_CONTROL_NETBINDADD
:
561 case SERVICE_CONTROL_NETBINDREMOVE
:
562 case SERVICE_CONTROL_NETBINDENABLE
:
563 case SERVICE_CONTROL_NETBINDDISABLE
:
564 if (a
&SERVICE_ACCEPT_NETBINDCHANGE
)
567 if (1) /* (!service->handlerex) */
571 case SERVICE_CONTROL_HARDWAREPROFILECHANGE
:
572 if (a
&SERVICE_ACCEPT_HARDWAREPROFILECHANGE
)
575 case SERVICE_CONTROL_POWEREVENT
:
576 if (a
&SERVICE_ACCEPT_POWEREVENT
)
579 case SERVICE_CONTROL_SESSIONCHANGE
:
580 if (a
&SERVICE_ACCEPT_SESSIONCHANGE
)
587 /******************************************************************************
588 * service_handle_control
590 static BOOL
service_handle_control(HANDLE pipe
, service_data
*service
,
593 DWORD count
, ret
= ERROR_INVALID_SERVICE_CONTROL
;
595 TRACE("received control %ld\n", dwControl
);
597 if (service_accepts_control(service
, dwControl
) && service
->handler
)
599 service
->handler(dwControl
);
602 return WriteFile(pipe
, &ret
, sizeof ret
, &count
, NULL
);
605 /******************************************************************************
606 * service_reap_thread
608 static DWORD
service_reap_thread(service_data
*service
)
612 if (!service
->thread
)
614 GetExitCodeThread(service
->thread
, &exitcode
);
615 if (exitcode
!=STILL_ACTIVE
)
617 CloseHandle(service
->thread
);
623 /******************************************************************************
624 * service_control_dispatcher
626 static DWORD WINAPI
service_control_dispatcher(LPVOID arg
)
628 service_data
*service
= arg
;
632 TRACE("%p %s\n", service
, debugstr_w(service
->name
));
634 /* create a pipe to talk to the rest of the world with */
635 name
= service_get_pipe_name(service
->name
);
636 pipe
= CreateNamedPipeW(name
, PIPE_ACCESS_DUPLEX
,
637 PIPE_TYPE_BYTE
|PIPE_WAIT
, 1, 256, 256, 10000, NULL
);
640 /* let the process who started us know we've tried to create a pipe */
641 event
= service_get_event_handle(service
->name
);
645 if (pipe
==INVALID_HANDLE_VALUE
)
647 ERR("failed to create pipe, error = %ld\n", GetLastError());
651 /* dispatcher loop */
655 DWORD count
, req
[2] = {0,0};
657 r
= ConnectNamedPipe(pipe
, NULL
);
658 if (!r
&& GetLastError() != ERROR_PIPE_CONNECTED
)
660 ERR("pipe connect failed\n");
664 r
= ReadFile( pipe
, &req
, sizeof req
, &count
, NULL
);
665 if (!r
|| count
!=sizeof req
)
667 ERR("pipe read failed\n");
671 service_reap_thread(service
);
673 /* handle the request */
676 case WINESERV_STARTINFO
:
677 service_handle_start(pipe
, service
, req
[1]);
679 case WINESERV_GETSTATUS
:
680 service_handle_get_status(pipe
, service
);
682 case WINESERV_SENDCONTROL
:
683 service_handle_control(pipe
, service
, req
[1]);
686 ERR("received invalid command %ld length %ld\n", req
[0], req
[1]);
689 FlushFileBuffers(pipe
);
690 DisconnectNamedPipe(pipe
);
697 /******************************************************************************
698 * service_run_threads
700 static BOOL
service_run_threads(void)
702 service_data
*service
;
703 DWORD count
= 0, n
= 0;
706 EnterCriticalSection( &service_cs
);
708 /* count how many services there are */
709 for (service
= service_list
; service
; service
= service
->next
)
712 TRACE("starting %ld pipe listener threads\n", count
);
714 handles
= HeapAlloc(GetProcessHeap(), 0, sizeof(HANDLE
)*count
);
716 for (n
=0, service
= service_list
; service
; service
= service
->next
, n
++)
717 handles
[n
] = CreateThread( NULL
, 0, service_control_dispatcher
,
721 LeaveCriticalSection( &service_cs
);
723 /* wait for all the threads to pack up and exit */
724 WaitForMultipleObjectsEx(count
, handles
, TRUE
, INFINITE
, FALSE
);
726 HeapFree(GetProcessHeap(), 0, handles
);
731 /******************************************************************************
732 * StartServiceCtrlDispatcherA [ADVAPI32.@]
734 * Connects a process containing one or more services to the service control
738 * servent [I] A list of the service names and service procedures
740 BOOL WINAPI
StartServiceCtrlDispatcherA( LPSERVICE_TABLE_ENTRYA servent
)
746 TRACE("%p\n", servent
);
748 EnterCriticalSection( &service_cs
);
749 while (servent
->lpServiceName
)
751 LPSTR name
= servent
->lpServiceName
;
753 len
= MultiByteToWideChar(CP_ACP
, 0, name
, -1, NULL
, 0);
754 sz
= len
*sizeof(WCHAR
) + sizeof *info
;
755 info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sz
);
756 MultiByteToWideChar(CP_ACP
, 0, name
, -1, info
->name
, len
);
757 info
->proc
.a
= servent
->lpServiceProc
;
758 info
->unicode
= FALSE
;
760 /* insert into the list */
761 info
->next
= service_list
;
766 LeaveCriticalSection( &service_cs
);
768 service_run_threads();
773 /******************************************************************************
774 * StartServiceCtrlDispatcherW [ADVAPI32.@]
776 * Connects a process containing one or more services to the service control
780 * servent [I] A list of the service names and service procedures
782 BOOL WINAPI
StartServiceCtrlDispatcherW( LPSERVICE_TABLE_ENTRYW servent
)
788 TRACE("%p\n", servent
);
790 EnterCriticalSection( &service_cs
);
791 while (servent
->lpServiceName
)
793 LPWSTR name
= servent
->lpServiceName
;
796 sz
= len
*sizeof(WCHAR
) + sizeof *info
;
797 info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sz
);
798 strcpyW(info
->name
, name
);
799 info
->proc
.w
= servent
->lpServiceProc
;
800 info
->unicode
= TRUE
;
802 /* insert into the list */
803 info
->next
= service_list
;
808 LeaveCriticalSection( &service_cs
);
810 service_run_threads();
815 /******************************************************************************
816 * LockServiceDatabase [ADVAPI32.@]
818 SC_LOCK WINAPI
LockServiceDatabase (SC_HANDLE hSCManager
)
822 TRACE("%p\n",hSCManager
);
824 ret
= CreateSemaphoreW( NULL
, 1, 1, szSCMLock
);
825 if( ret
&& GetLastError() == ERROR_ALREADY_EXISTS
)
829 SetLastError( ERROR_SERVICE_DATABASE_LOCKED
);
832 TRACE("returning %p\n", ret
);
837 /******************************************************************************
838 * UnlockServiceDatabase [ADVAPI32.@]
840 BOOL WINAPI
UnlockServiceDatabase (SC_LOCK ScLock
)
842 TRACE("%p\n",ScLock
);
844 return CloseHandle( ScLock
);
847 /******************************************************************************
848 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
850 SERVICE_STATUS_HANDLE WINAPI
851 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName
, LPHANDLER_FUNCTION lpfHandler
)
853 LPWSTR lpServiceNameW
;
854 SERVICE_STATUS_HANDLE ret
;
856 lpServiceNameW
= SERV_dup(lpServiceName
);
857 ret
= RegisterServiceCtrlHandlerW( lpServiceNameW
, lpfHandler
);
858 SERV_free(lpServiceNameW
);
862 /******************************************************************************
863 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
869 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName
,
870 LPHANDLER_FUNCTION lpfHandler
)
872 service_data
*service
;
874 EnterCriticalSection( &service_cs
);
875 for(service
= service_list
; service
; service
= service
->next
)
876 if(!strcmpW(lpServiceName
, service
->name
))
879 service
->handler
= lpfHandler
;
880 LeaveCriticalSection( &service_cs
);
882 return (SERVICE_STATUS_HANDLE
)service
;
885 /******************************************************************************
886 * SetServiceStatus [ADVAPI32.@]
893 SetServiceStatus( SERVICE_STATUS_HANDLE hService
, LPSERVICE_STATUS lpStatus
)
895 service_data
*service
;
898 TRACE("%p %lx %lx %lx %lx %lx %lx %lx\n", hService
,
899 lpStatus
->dwServiceType
, lpStatus
->dwCurrentState
,
900 lpStatus
->dwControlsAccepted
, lpStatus
->dwWin32ExitCode
,
901 lpStatus
->dwServiceSpecificExitCode
, lpStatus
->dwCheckPoint
,
902 lpStatus
->dwWaitHint
);
904 EnterCriticalSection( &service_cs
);
905 for (service
= service_list
; service
; service
= service
->next
)
906 if(service
== (service_data
*)hService
)
910 memcpy( &service
->status
, lpStatus
, sizeof(SERVICE_STATUS
) );
911 TRACE("Set service status to %ld\n",service
->status
.dwCurrentState
);
915 LeaveCriticalSection( &service_cs
);
921 /******************************************************************************
922 * OpenSCManagerA [ADVAPI32.@]
924 * Establish a connection to the service control manager and open its database.
927 * lpMachineName [I] Pointer to machine name string
928 * lpDatabaseName [I] Pointer to database name string
929 * dwDesiredAccess [I] Type of access
932 * Success: A Handle to the service control manager database
935 SC_HANDLE WINAPI
OpenSCManagerA( LPCSTR lpMachineName
, LPCSTR lpDatabaseName
,
936 DWORD dwDesiredAccess
)
938 LPWSTR lpMachineNameW
, lpDatabaseNameW
;
941 lpMachineNameW
= SERV_dup(lpMachineName
);
942 lpDatabaseNameW
= SERV_dup(lpDatabaseName
);
943 ret
= OpenSCManagerW(lpMachineNameW
, lpDatabaseNameW
, dwDesiredAccess
);
944 SERV_free(lpDatabaseNameW
);
945 SERV_free(lpMachineNameW
);
949 /******************************************************************************
950 * OpenSCManagerW [ADVAPI32.@]
952 * See OpenSCManagerA.
954 SC_HANDLE WINAPI
OpenSCManagerW( LPCWSTR lpMachineName
, LPCWSTR lpDatabaseName
,
955 DWORD dwDesiredAccess
)
957 struct sc_manager
*manager
;
961 TRACE("(%s,%s,0x%08lx)\n", debugstr_w(lpMachineName
),
962 debugstr_w(lpDatabaseName
), dwDesiredAccess
);
964 if( lpDatabaseName
&& lpDatabaseName
[0] )
966 if( strcmpiW( lpDatabaseName
, SERVICES_ACTIVE_DATABASEW
) == 0 )
968 /* noop, all right */
970 else if( strcmpiW( lpDatabaseName
, SERVICES_FAILED_DATABASEW
) == 0 )
972 SetLastError( ERROR_DATABASE_DOES_NOT_EXIST
);
977 SetLastError( ERROR_INVALID_NAME
);
982 manager
= sc_handle_alloc( SC_HTYPE_MANAGER
, sizeof (struct sc_manager
),
983 sc_handle_destroy_manager
);
987 r
= RegConnectRegistryW(lpMachineName
,HKEY_LOCAL_MACHINE
,&hReg
);
988 if (r
!=ERROR_SUCCESS
)
991 r
= RegOpenKeyExW(hReg
, szServiceManagerKey
,
992 0, KEY_ALL_ACCESS
, &manager
->hkey
);
994 if (r
!=ERROR_SUCCESS
)
997 TRACE("returning %p\n", manager
);
999 return (SC_HANDLE
) &manager
->hdr
;
1002 sc_handle_free( &manager
->hdr
);
1007 /******************************************************************************
1008 * ControlService [ADVAPI32.@]
1010 * Send a control code to a service.
1013 * hService [I] Handle of the service control manager database
1014 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
1015 * lpServiceStatus [O] Destination for the status of the service, if available
1022 * Unlike M$' implementation, control requests are not serialized and may be
1023 * processed asynchronously.
1025 BOOL WINAPI
ControlService( SC_HANDLE hService
, DWORD dwControl
,
1026 LPSERVICE_STATUS lpServiceStatus
)
1028 struct sc_service
*hsvc
;
1032 TRACE("%p %ld %p\n", hService
, dwControl
, lpServiceStatus
);
1034 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1037 SetLastError( ERROR_INVALID_HANDLE
);
1041 ret
= QueryServiceStatus(hService
, lpServiceStatus
);
1044 ERR("failed to query service status\n");
1045 SetLastError(ERROR_SERVICE_NOT_ACTIVE
);
1049 switch (lpServiceStatus
->dwCurrentState
)
1051 case SERVICE_STOPPED
:
1052 SetLastError(ERROR_SERVICE_NOT_ACTIVE
);
1054 case SERVICE_START_PENDING
:
1055 if (dwControl
==SERVICE_CONTROL_STOP
)
1058 case SERVICE_STOP_PENDING
:
1059 SetLastError(ERROR_SERVICE_CANNOT_ACCEPT_CTRL
);
1063 handle
= service_open_pipe(hsvc
->name
);
1064 if (handle
!=INVALID_HANDLE_VALUE
)
1066 DWORD result
= ERROR_SUCCESS
;
1067 ret
= service_send_control(handle
, dwControl
, &result
);
1068 CloseHandle(handle
);
1069 if (result
!=ERROR_SUCCESS
)
1071 SetLastError(result
);
1079 /******************************************************************************
1080 * CloseServiceHandle [ADVAPI32.@]
1082 * Close a handle to a service or the service control manager database.
1085 * hSCObject [I] Handle to service or service control manager database
1092 CloseServiceHandle( SC_HANDLE hSCObject
)
1094 TRACE("%p\n", hSCObject
);
1096 sc_handle_free( (struct sc_handle
*) hSCObject
);
1102 /******************************************************************************
1103 * OpenServiceA [ADVAPI32.@]
1105 * Open a handle to a service.
1108 * hSCManager [I] Handle of the service control manager database
1109 * lpServiceName [I] Name of the service to open
1110 * dwDesiredAccess [I] Access required to the service
1113 * Success: Handle to the service
1116 SC_HANDLE WINAPI
OpenServiceA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
1117 DWORD dwDesiredAccess
)
1119 LPWSTR lpServiceNameW
;
1122 TRACE("%p %s %ld\n", hSCManager
, debugstr_a(lpServiceName
), dwDesiredAccess
);
1124 lpServiceNameW
= SERV_dup(lpServiceName
);
1125 ret
= OpenServiceW( hSCManager
, lpServiceNameW
, dwDesiredAccess
);
1126 SERV_free(lpServiceNameW
);
1131 /******************************************************************************
1132 * OpenServiceW [ADVAPI32.@]
1136 SC_HANDLE WINAPI
OpenServiceW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
1137 DWORD dwDesiredAccess
)
1139 struct sc_manager
*hscm
;
1140 struct sc_service
*hsvc
;
1145 TRACE("%p %s %ld\n", hSCManager
, debugstr_w(lpServiceName
), dwDesiredAccess
);
1149 SetLastError(ERROR_INVALID_ADDRESS
);
1153 hscm
= sc_handle_get_handle_data( hSCManager
, SC_HTYPE_MANAGER
);
1156 SetLastError( ERROR_INVALID_HANDLE
);
1160 r
= RegOpenKeyExW( hscm
->hkey
, lpServiceName
, 0, KEY_ALL_ACCESS
, &hKey
);
1161 if (r
!=ERROR_SUCCESS
)
1163 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST
);
1167 len
= strlenW(lpServiceName
)+1;
1168 hsvc
= sc_handle_alloc( SC_HTYPE_SERVICE
,
1169 sizeof (struct sc_service
) + len
*sizeof(WCHAR
),
1170 sc_handle_destroy_service
);
1173 strcpyW( hsvc
->name
, lpServiceName
);
1176 /* add reference to SCM handle */
1177 hscm
->hdr
.ref_count
++;
1180 TRACE("returning %p\n",hsvc
);
1182 return (SC_HANDLE
) &hsvc
->hdr
;
1185 /******************************************************************************
1186 * CreateServiceW [ADVAPI32.@]
1189 CreateServiceW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
1190 LPCWSTR lpDisplayName
, DWORD dwDesiredAccess
,
1191 DWORD dwServiceType
, DWORD dwStartType
,
1192 DWORD dwErrorControl
, LPCWSTR lpBinaryPathName
,
1193 LPCWSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
,
1194 LPCWSTR lpDependencies
, LPCWSTR lpServiceStartName
,
1195 LPCWSTR lpPassword
)
1197 struct sc_manager
*hscm
;
1198 struct sc_service
*hsvc
= NULL
;
1202 struct reg_value val
[10];
1205 TRACE("%p %s %s\n", hSCManager
,
1206 debugstr_w(lpServiceName
), debugstr_w(lpDisplayName
));
1208 hscm
= sc_handle_get_handle_data( hSCManager
, SC_HTYPE_MANAGER
);
1211 SetLastError( ERROR_INVALID_HANDLE
);
1215 r
= RegCreateKeyExW(hscm
->hkey
, lpServiceName
, 0, NULL
,
1216 REG_OPTION_NON_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &hKey
, &dp
);
1217 if (r
!=ERROR_SUCCESS
)
1220 if (dp
!= REG_CREATED_NEW_KEY
)
1222 SetLastError(ERROR_SERVICE_EXISTS
);
1227 service_set_string( &val
[n
++], szDisplayName
, lpDisplayName
);
1229 service_set_dword( &val
[n
++], szType
, &dwServiceType
);
1230 service_set_dword( &val
[n
++], szStart
, &dwStartType
);
1231 service_set_dword( &val
[n
++], szError
, &dwErrorControl
);
1233 if( lpBinaryPathName
)
1234 service_set_string( &val
[n
++], szImagePath
, lpBinaryPathName
);
1236 if( lpLoadOrderGroup
)
1237 service_set_string( &val
[n
++], szGroup
, lpLoadOrderGroup
);
1239 if( lpDependencies
)
1240 service_set_multi_string( &val
[n
++], szDependencies
, lpDependencies
);
1243 FIXME("Don't know how to add a Password for a service.\n");
1245 if( lpServiceStartName
)
1246 service_set_string( &val
[n
++], szDependOnService
, lpServiceStartName
);
1248 r
= service_write_values( hKey
, val
, n
);
1249 if( r
!= ERROR_SUCCESS
)
1252 len
= strlenW(lpServiceName
)+1;
1253 len
= sizeof (struct sc_service
) + len
*sizeof(WCHAR
);
1254 hsvc
= sc_handle_alloc( SC_HTYPE_SERVICE
, len
, sc_handle_destroy_service
);
1257 lstrcpyW( hsvc
->name
, lpServiceName
);
1260 hscm
->hdr
.ref_count
++;
1262 return (SC_HANDLE
) &hsvc
->hdr
;
1265 RegCloseKey( hKey
);
1270 /******************************************************************************
1271 * CreateServiceA [ADVAPI32.@]
1274 CreateServiceA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
1275 LPCSTR lpDisplayName
, DWORD dwDesiredAccess
,
1276 DWORD dwServiceType
, DWORD dwStartType
,
1277 DWORD dwErrorControl
, LPCSTR lpBinaryPathName
,
1278 LPCSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
,
1279 LPCSTR lpDependencies
, LPCSTR lpServiceStartName
,
1282 LPWSTR lpServiceNameW
, lpDisplayNameW
, lpBinaryPathNameW
,
1283 lpLoadOrderGroupW
, lpDependenciesW
, lpServiceStartNameW
, lpPasswordW
;
1286 TRACE("%p %s %s\n", hSCManager
,
1287 debugstr_a(lpServiceName
), debugstr_a(lpDisplayName
));
1289 lpServiceNameW
= SERV_dup( lpServiceName
);
1290 lpDisplayNameW
= SERV_dup( lpDisplayName
);
1291 lpBinaryPathNameW
= SERV_dup( lpBinaryPathName
);
1292 lpLoadOrderGroupW
= SERV_dup( lpLoadOrderGroup
);
1293 lpDependenciesW
= SERV_dupmulti( lpDependencies
);
1294 lpServiceStartNameW
= SERV_dup( lpServiceStartName
);
1295 lpPasswordW
= SERV_dup( lpPassword
);
1297 r
= CreateServiceW( hSCManager
, lpServiceNameW
, lpDisplayNameW
,
1298 dwDesiredAccess
, dwServiceType
, dwStartType
, dwErrorControl
,
1299 lpBinaryPathNameW
, lpLoadOrderGroupW
, lpdwTagId
,
1300 lpDependenciesW
, lpServiceStartNameW
, lpPasswordW
);
1302 SERV_free( lpServiceNameW
);
1303 SERV_free( lpDisplayNameW
);
1304 SERV_free( lpBinaryPathNameW
);
1305 SERV_free( lpLoadOrderGroupW
);
1306 SERV_free( lpDependenciesW
);
1307 SERV_free( lpServiceStartNameW
);
1308 SERV_free( lpPasswordW
);
1314 /******************************************************************************
1315 * DeleteService [ADVAPI32.@]
1317 * Delete a service from the service control manager database.
1320 * hService [I] Handle of the service to delete
1326 BOOL WINAPI
DeleteService( SC_HANDLE hService
)
1328 struct sc_service
*hsvc
;
1330 WCHAR valname
[MAX_PATH
+1];
1335 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1338 SetLastError( ERROR_INVALID_HANDLE
);
1344 /* Clean out the values */
1345 rc
= RegEnumValueW(hKey
, index
, valname
,&size
,0,0,0,0);
1346 while (rc
== ERROR_SUCCESS
)
1348 RegDeleteValueW(hKey
,valname
);
1351 rc
= RegEnumValueW(hKey
, index
, valname
, &size
,0,0,0,0);
1357 /* delete the key */
1358 RegDeleteKeyW(hsvc
->scm
->hkey
, hsvc
->name
);
1364 /******************************************************************************
1365 * StartServiceA [ADVAPI32.@]
1370 * hService [I] Handle of service
1371 * dwNumServiceArgs [I] Number of arguments
1372 * lpServiceArgVectors [I] Address of array of argument strings
1375 * - NT implements this function using an obscure RPC call.
1376 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1377 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1378 * - This will only work for shared address space. How should the service
1379 * args be transferred when address spaces are separated?
1380 * - Can only start one service at a time.
1381 * - Has no concept of privilege.
1387 BOOL WINAPI
StartServiceA( SC_HANDLE hService
, DWORD dwNumServiceArgs
,
1388 LPCSTR
*lpServiceArgVectors
)
1390 LPWSTR
*lpwstr
=NULL
;
1394 TRACE("(%p,%ld,%p)\n",hService
,dwNumServiceArgs
,lpServiceArgVectors
);
1396 if (dwNumServiceArgs
)
1397 lpwstr
= HeapAlloc( GetProcessHeap(), 0,
1398 dwNumServiceArgs
*sizeof(LPWSTR
) );
1400 for(i
=0; i
<dwNumServiceArgs
; i
++)
1401 lpwstr
[i
]=SERV_dup(lpServiceArgVectors
[i
]);
1403 r
= StartServiceW(hService
, dwNumServiceArgs
, (LPCWSTR
*)lpwstr
);
1405 if (dwNumServiceArgs
)
1407 for(i
=0; i
<dwNumServiceArgs
; i
++)
1408 SERV_free(lpwstr
[i
]);
1409 HeapFree(GetProcessHeap(), 0, lpwstr
);
1415 /******************************************************************************
1416 * service_start_process [INTERNAL]
1418 static DWORD
service_start_process(struct sc_service
*hsvc
)
1420 static const WCHAR _ImagePathW
[] = {'I','m','a','g','e','P','a','t','h',0};
1421 PROCESS_INFORMATION pi
;
1423 LPWSTR path
= NULL
, str
;
1424 DWORD type
, size
, ret
;
1428 /* read the executable path from memory */
1430 ret
= RegQueryValueExW(hsvc
->hkey
, _ImagePathW
, NULL
, &type
, NULL
, &size
);
1431 if (ret
!=ERROR_SUCCESS
)
1433 str
= HeapAlloc(GetProcessHeap(),0,size
);
1434 ret
= RegQueryValueExW(hsvc
->hkey
, _ImagePathW
, NULL
, &type
, (LPBYTE
)str
, &size
);
1435 if (ret
==ERROR_SUCCESS
)
1437 size
= ExpandEnvironmentStringsW(str
,NULL
,0);
1438 path
= HeapAlloc(GetProcessHeap(),0,size
*sizeof(WCHAR
));
1439 ExpandEnvironmentStringsW(str
,path
,size
);
1441 HeapFree(GetProcessHeap(),0,str
);
1445 /* wait for the process to start and set an event or terminate */
1446 handles
[0] = service_get_event_handle( hsvc
->name
);
1447 ZeroMemory(&si
, sizeof(STARTUPINFOW
));
1448 si
.cb
= sizeof(STARTUPINFOW
);
1449 r
= CreateProcessW(NULL
, path
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
1452 handles
[1] = pi
.hProcess
;
1453 ret
= WaitForMultipleObjectsEx(2, handles
, FALSE
, 30000, FALSE
);
1454 if(ret
!= WAIT_OBJECT_0
)
1456 SetLastError(ERROR_IO_PENDING
);
1460 CloseHandle( pi
.hThread
);
1461 CloseHandle( pi
.hProcess
);
1463 CloseHandle( handles
[0] );
1464 HeapFree(GetProcessHeap(),0,path
);
1468 static BOOL
service_wait_for_startup(SC_HANDLE hService
)
1471 SERVICE_STATUS status
;
1474 TRACE("%p\n", hService
);
1476 for (i
=0; i
<30; i
++)
1478 status
.dwCurrentState
= 0;
1479 r
= QueryServiceStatus(hService
, &status
);
1482 if (status
.dwCurrentState
== SERVICE_RUNNING
)
1484 TRACE("Service started successfully\n");
1493 /******************************************************************************
1494 * StartServiceW [ADVAPI32.@]
1496 * See StartServiceA.
1498 BOOL WINAPI
StartServiceW(SC_HANDLE hService
, DWORD dwNumServiceArgs
,
1499 LPCWSTR
*lpServiceArgVectors
)
1501 struct sc_service
*hsvc
;
1504 HANDLE handle
= INVALID_HANDLE_VALUE
;
1506 TRACE("%p %ld %p\n", hService
, dwNumServiceArgs
, lpServiceArgVectors
);
1508 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1511 SetLastError(ERROR_INVALID_HANDLE
);
1515 hLock
= LockServiceDatabase((SC_HANDLE
)hsvc
->scm
);
1519 handle
= service_open_pipe(hsvc
->name
);
1520 if (handle
==INVALID_HANDLE_VALUE
)
1522 /* start the service process */
1523 if (service_start_process(hsvc
))
1524 handle
= service_open_pipe(hsvc
->name
);
1527 if (handle
!= INVALID_HANDLE_VALUE
)
1529 service_send_start_message(handle
, lpServiceArgVectors
, dwNumServiceArgs
);
1530 CloseHandle(handle
);
1534 UnlockServiceDatabase( hLock
);
1536 TRACE("returning %d\n", r
);
1538 service_wait_for_startup(hService
);
1543 /******************************************************************************
1544 * QueryServiceStatus [ADVAPI32.@]
1548 * lpservicestatus []
1551 BOOL WINAPI
QueryServiceStatus(SC_HANDLE hService
,
1552 LPSERVICE_STATUS lpservicestatus
)
1554 struct sc_service
*hsvc
;
1555 DWORD size
, type
, val
;
1559 TRACE("%p %p\n", hService
, lpservicestatus
);
1561 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1564 SetLastError( ERROR_INVALID_HANDLE
);
1568 pipe
= service_open_pipe(hsvc
->name
);
1569 if (pipe
!= INVALID_HANDLE_VALUE
)
1571 r
= service_get_status(pipe
, lpservicestatus
);
1577 TRACE("Failed to read service status\n");
1579 /* read the service type from the registry */
1581 r
= RegQueryValueExA(hsvc
->hkey
, "Type", NULL
, &type
, (LPBYTE
)&val
, &size
);
1582 if(r
!=ERROR_SUCCESS
|| type
!=REG_DWORD
)
1585 lpservicestatus
->dwServiceType
= val
;
1586 lpservicestatus
->dwCurrentState
= SERVICE_STOPPED
; /* stopped */
1587 lpservicestatus
->dwControlsAccepted
= 0;
1588 lpservicestatus
->dwWin32ExitCode
= ERROR_SERVICE_NEVER_STARTED
;
1589 lpservicestatus
->dwServiceSpecificExitCode
= 0;
1590 lpservicestatus
->dwCheckPoint
= 0;
1591 lpservicestatus
->dwWaitHint
= 0;
1596 /******************************************************************************
1597 * QueryServiceStatusEx [ADVAPI32.@]
1599 * Get information about a service.
1602 * hService [I] Handle to service to get information about
1603 * InfoLevel [I] Level of information to get
1604 * lpBuffer [O] Destination for requested information
1605 * cbBufSize [I] Size of lpBuffer in bytes
1606 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1612 BOOL WINAPI
QueryServiceStatusEx(SC_HANDLE hService
, SC_STATUS_TYPE InfoLevel
,
1613 LPBYTE lpBuffer
, DWORD cbBufSize
,
1614 LPDWORD pcbBytesNeeded
)
1617 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1621 /******************************************************************************
1622 * QueryServiceConfigA [ADVAPI32.@]
1625 QueryServiceConfigA( SC_HANDLE hService
,
1626 LPQUERY_SERVICE_CONFIGA lpServiceConfig
,
1627 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
1629 static const CHAR szDisplayName
[] = "DisplayName";
1630 static const CHAR szType
[] = "Type";
1631 static const CHAR szStart
[] = "Start";
1632 static const CHAR szError
[] = "ErrorControl";
1633 static const CHAR szImagePath
[] = "ImagePath";
1634 static const CHAR szGroup
[] = "Group";
1635 static const CHAR szDependencies
[] = "Dependencies";
1636 struct sc_service
*hsvc
;
1638 CHAR str_buffer
[ MAX_PATH
];
1640 DWORD type
, val
, sz
, total
, n
;
1643 TRACE("%p %p %ld %p\n", hService
, lpServiceConfig
,
1644 cbBufSize
, pcbBytesNeeded
);
1646 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1649 SetLastError( ERROR_INVALID_HANDLE
);
1654 /* calculate the size required first */
1655 total
= sizeof (QUERY_SERVICE_CONFIGA
);
1657 sz
= sizeof(str_buffer
);
1658 r
= RegQueryValueExA( hKey
, szImagePath
, 0, &type
, (LPBYTE
)str_buffer
, &sz
);
1659 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
|| type
== REG_EXPAND_SZ
) )
1661 sz
= ExpandEnvironmentStringsA(str_buffer
,NULL
,0);
1662 if( 0 == sz
) return FALSE
;
1668 /* FIXME: set last error */
1673 r
= RegQueryValueExA( hKey
, szGroup
, 0, &type
, NULL
, &sz
);
1674 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1678 r
= RegQueryValueExA( hKey
, szDependencies
, 0, &type
, NULL
, &sz
);
1679 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_MULTI_SZ
) )
1683 r
= RegQueryValueExA( hKey
, szStart
, 0, &type
, NULL
, &sz
);
1684 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1688 r
= RegQueryValueExA( hKey
, szDisplayName
, 0, &type
, NULL
, &sz
);
1689 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1692 *pcbBytesNeeded
= total
;
1694 /* if there's not enough memory, return an error */
1695 if( total
> cbBufSize
)
1697 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1701 ZeroMemory( lpServiceConfig
, total
);
1704 r
= RegQueryValueExA( hKey
, szType
, 0, &type
, (LPBYTE
)&val
, &sz
);
1705 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_DWORD
) )
1706 lpServiceConfig
->dwServiceType
= val
;
1709 r
= RegQueryValueExA( hKey
, szStart
, 0, &type
, (LPBYTE
)&val
, &sz
);
1710 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_DWORD
) )
1711 lpServiceConfig
->dwStartType
= val
;
1714 r
= RegQueryValueExA( hKey
, szError
, 0, &type
, (LPBYTE
)&val
, &sz
);
1715 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_DWORD
) )
1716 lpServiceConfig
->dwErrorControl
= val
;
1718 /* now do the strings */
1719 p
= (LPSTR
) &lpServiceConfig
[1];
1720 n
= total
- sizeof (QUERY_SERVICE_CONFIGA
);
1722 sz
= sizeof(str_buffer
);
1723 r
= RegQueryValueExA( hKey
, szImagePath
, 0, &type
, (LPBYTE
)str_buffer
, &sz
);
1724 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
|| type
== REG_EXPAND_SZ
) )
1726 sz
= ExpandEnvironmentStringsA(str_buffer
, p
, n
);
1727 if( 0 == sz
|| sz
> n
) return FALSE
;
1729 lpServiceConfig
->lpBinaryPathName
= p
;
1735 /* FIXME: set last error */
1740 r
= RegQueryValueExA( hKey
, szGroup
, 0, &type
, (LPBYTE
)p
, &sz
);
1741 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_SZ
) )
1743 lpServiceConfig
->lpLoadOrderGroup
= p
;
1749 r
= RegQueryValueExA( hKey
, szDependencies
, 0, &type
, (LPBYTE
)p
, &sz
);
1750 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_SZ
) )
1752 lpServiceConfig
->lpDependencies
= p
;
1758 ERR("Buffer overflow!\n");
1760 TRACE("Image path = %s\n", lpServiceConfig
->lpBinaryPathName
);
1761 TRACE("Group = %s\n", lpServiceConfig
->lpLoadOrderGroup
);
1766 /******************************************************************************
1767 * QueryServiceConfigW [ADVAPI32.@]
1770 QueryServiceConfigW( SC_HANDLE hService
,
1771 LPQUERY_SERVICE_CONFIGW lpServiceConfig
,
1772 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
1774 WCHAR str_buffer
[ MAX_PATH
];
1776 DWORD type
, val
, sz
, total
, n
;
1779 struct sc_service
*hsvc
;
1781 TRACE("%p %p %ld %p\n", hService
, lpServiceConfig
,
1782 cbBufSize
, pcbBytesNeeded
);
1784 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1787 SetLastError( ERROR_INVALID_HANDLE
);
1792 /* calculate the size required first */
1793 total
= sizeof (QUERY_SERVICE_CONFIGW
);
1795 sz
= sizeof(str_buffer
);
1796 r
= RegQueryValueExW( hKey
, szImagePath
, 0, &type
, (LPBYTE
) str_buffer
, &sz
);
1797 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
|| type
== REG_EXPAND_SZ
) )
1799 sz
= ExpandEnvironmentStringsW(str_buffer
,NULL
,0);
1800 if( 0 == sz
) return FALSE
;
1802 total
+= sizeof(WCHAR
) * sz
;
1806 /* FIXME: set last error */
1811 r
= RegQueryValueExW( hKey
, szGroup
, 0, &type
, NULL
, &sz
);
1812 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1816 r
= RegQueryValueExW( hKey
, szDependencies
, 0, &type
, NULL
, &sz
);
1817 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_MULTI_SZ
) )
1820 total
+= sizeof(WCHAR
);
1823 r
= RegQueryValueExW( hKey
, szStart
, 0, &type
, NULL
, &sz
);
1824 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1828 r
= RegQueryValueExW( hKey
, szDisplayName
, 0, &type
, NULL
, &sz
);
1829 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1832 *pcbBytesNeeded
= total
;
1834 /* if there's not enough memory, return an error */
1835 if( total
> cbBufSize
)
1837 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1841 ZeroMemory( lpServiceConfig
, total
);
1844 r
= RegQueryValueExW( hKey
, szType
, 0, &type
, (LPBYTE
)&val
, &sz
);
1845 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_DWORD
) )
1846 lpServiceConfig
->dwServiceType
= val
;
1849 r
= RegQueryValueExW( hKey
, szStart
, 0, &type
, (LPBYTE
)&val
, &sz
);
1850 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_DWORD
) )
1851 lpServiceConfig
->dwStartType
= val
;
1854 r
= RegQueryValueExW( hKey
, szError
, 0, &type
, (LPBYTE
)&val
, &sz
);
1855 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_DWORD
) )
1856 lpServiceConfig
->dwErrorControl
= val
;
1858 /* now do the strings */
1859 p
= (LPBYTE
) &lpServiceConfig
[1];
1860 n
= total
- sizeof (QUERY_SERVICE_CONFIGW
);
1862 sz
= sizeof(str_buffer
);
1863 r
= RegQueryValueExW( hKey
, szImagePath
, 0, &type
, (LPBYTE
) str_buffer
, &sz
);
1864 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
|| type
== REG_EXPAND_SZ
) )
1866 sz
= ExpandEnvironmentStringsW(str_buffer
, (LPWSTR
) p
, n
);
1867 sz
*= sizeof(WCHAR
);
1868 if( 0 == sz
|| sz
> n
) return FALSE
;
1870 lpServiceConfig
->lpBinaryPathName
= (LPWSTR
) p
;
1876 /* FIXME: set last error */
1881 r
= RegQueryValueExW( hKey
, szGroup
, 0, &type
, p
, &sz
);
1882 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_SZ
) )
1884 lpServiceConfig
->lpLoadOrderGroup
= (LPWSTR
) p
;
1890 r
= RegQueryValueExW( hKey
, szDependencies
, 0, &type
, p
, &sz
);
1891 lpServiceConfig
->lpDependencies
= (LPWSTR
) p
;
1892 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_SZ
) )
1905 ERR("Buffer overflow!\n");
1907 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig
->lpBinaryPathName
) );
1908 TRACE("Group = %s\n", debugstr_w(lpServiceConfig
->lpLoadOrderGroup
) );
1913 /******************************************************************************
1914 * EnumServicesStatusA [ADVAPI32.@]
1917 EnumServicesStatusA( SC_HANDLE hSCManager
, DWORD dwServiceType
,
1918 DWORD dwServiceState
, LPENUM_SERVICE_STATUSA lpServices
,
1919 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
1920 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
)
1922 FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager
,
1923 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
1924 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
);
1925 SetLastError (ERROR_ACCESS_DENIED
);
1929 /******************************************************************************
1930 * EnumServicesStatusW [ADVAPI32.@]
1933 EnumServicesStatusW( SC_HANDLE hSCManager
, DWORD dwServiceType
,
1934 DWORD dwServiceState
, LPENUM_SERVICE_STATUSW lpServices
,
1935 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
1936 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
)
1938 FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager
,
1939 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
1940 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
);
1941 SetLastError (ERROR_ACCESS_DENIED
);
1945 /******************************************************************************
1946 * GetServiceKeyNameA [ADVAPI32.@]
1948 BOOL WINAPI
GetServiceKeyNameA( SC_HANDLE hSCManager
, LPCSTR lpDisplayName
,
1949 LPSTR lpServiceName
, LPDWORD lpcchBuffer
)
1951 FIXME("%p %s %p %p\n", hSCManager
, debugstr_a(lpDisplayName
), lpServiceName
, lpcchBuffer
);
1955 /******************************************************************************
1956 * GetServiceKeyNameW [ADVAPI32.@]
1958 BOOL WINAPI
GetServiceKeyNameW( SC_HANDLE hSCManager
, LPCWSTR lpDisplayName
,
1959 LPWSTR lpServiceName
, LPDWORD lpcchBuffer
)
1961 FIXME("%p %s %p %p\n", hSCManager
, debugstr_w(lpDisplayName
), lpServiceName
, lpcchBuffer
);
1965 /******************************************************************************
1966 * QueryServiceLockStatusA [ADVAPI32.@]
1968 BOOL WINAPI
QueryServiceLockStatusA( SC_HANDLE hSCManager
,
1969 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus
,
1970 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
1972 FIXME("%p %p %08lx %p\n", hSCManager
, lpLockStatus
, cbBufSize
, pcbBytesNeeded
);
1977 /******************************************************************************
1978 * QueryServiceLockStatusW [ADVAPI32.@]
1980 BOOL WINAPI
QueryServiceLockStatusW( SC_HANDLE hSCManager
,
1981 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus
,
1982 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
1984 FIXME("%p %p %08lx %p\n", hSCManager
, lpLockStatus
, cbBufSize
, pcbBytesNeeded
);
1989 /******************************************************************************
1990 * GetServiceDisplayNameA [ADVAPI32.@]
1992 BOOL WINAPI
GetServiceDisplayNameA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
1993 LPSTR lpDisplayName
, LPDWORD lpcchBuffer
)
1995 FIXME("%p %s %p %p\n", hSCManager
,
1996 debugstr_a(lpServiceName
), lpDisplayName
, lpcchBuffer
);
2000 /******************************************************************************
2001 * GetServiceDisplayNameW [ADVAPI32.@]
2003 BOOL WINAPI
GetServiceDisplayNameW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
2004 LPWSTR lpDisplayName
, LPDWORD lpcchBuffer
)
2006 FIXME("%p %s %p %p\n", hSCManager
,
2007 debugstr_w(lpServiceName
), lpDisplayName
, lpcchBuffer
);
2011 /******************************************************************************
2012 * ChangeServiceConfigW [ADVAPI32.@]
2014 BOOL WINAPI
ChangeServiceConfigW( SC_HANDLE hService
, DWORD dwServiceType
,
2015 DWORD dwStartType
, DWORD dwErrorControl
, LPCWSTR lpBinaryPathName
,
2016 LPCWSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
, LPCWSTR lpDependencies
,
2017 LPCWSTR lpServiceStartName
, LPCWSTR lpPassword
, LPCWSTR lpDisplayName
)
2019 struct reg_value val
[10];
2020 struct sc_service
*hsvc
;
2021 DWORD r
= ERROR_SUCCESS
;
2025 TRACE("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
2026 hService
, dwServiceType
, dwStartType
, dwErrorControl
,
2027 debugstr_w(lpBinaryPathName
), debugstr_w(lpLoadOrderGroup
),
2028 lpdwTagId
, lpDependencies
, debugstr_w(lpServiceStartName
),
2029 debugstr_w(lpPassword
), debugstr_w(lpDisplayName
) );
2031 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
2034 SetLastError( ERROR_INVALID_HANDLE
);
2039 if( dwServiceType
!= SERVICE_NO_CHANGE
)
2040 service_set_dword( &val
[n
++], szType
, &dwServiceType
);
2042 if( dwStartType
!= SERVICE_NO_CHANGE
)
2043 service_set_dword( &val
[n
++], szStart
, &dwStartType
);
2045 if( dwErrorControl
!= SERVICE_NO_CHANGE
)
2046 service_set_dword( &val
[n
++], szError
, &dwErrorControl
);
2048 if( lpBinaryPathName
)
2049 service_set_string( &val
[n
++], szImagePath
, lpBinaryPathName
);
2051 if( lpLoadOrderGroup
)
2052 service_set_string( &val
[n
++], szGroup
, lpLoadOrderGroup
);
2054 if( lpDependencies
)
2055 service_set_multi_string( &val
[n
++], szDependencies
, lpDependencies
);
2058 FIXME("ignoring password\n");
2060 if( lpServiceStartName
)
2061 service_set_string( &val
[n
++], szDependOnService
, lpServiceStartName
);
2063 r
= service_write_values( hsvc
->hkey
, val
, n
);
2065 return (r
== ERROR_SUCCESS
) ? TRUE
: FALSE
;
2068 /******************************************************************************
2069 * ChangeServiceConfigA [ADVAPI32.@]
2071 BOOL WINAPI
ChangeServiceConfigA( SC_HANDLE hService
, DWORD dwServiceType
,
2072 DWORD dwStartType
, DWORD dwErrorControl
, LPCSTR lpBinaryPathName
,
2073 LPCSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
, LPCSTR lpDependencies
,
2074 LPCSTR lpServiceStartName
, LPCSTR lpPassword
, LPCSTR lpDisplayName
)
2076 LPWSTR wBinaryPathName
, wLoadOrderGroup
, wDependencies
;
2077 LPWSTR wServiceStartName
, wPassword
, wDisplayName
;
2080 TRACE("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
2081 hService
, dwServiceType
, dwStartType
, dwErrorControl
,
2082 debugstr_a(lpBinaryPathName
), debugstr_a(lpLoadOrderGroup
),
2083 lpdwTagId
, lpDependencies
, debugstr_a(lpServiceStartName
),
2084 debugstr_a(lpPassword
), debugstr_a(lpDisplayName
) );
2086 wBinaryPathName
= SERV_dup( lpBinaryPathName
);
2087 wLoadOrderGroup
= SERV_dup( lpLoadOrderGroup
);
2088 wDependencies
= SERV_dupmulti( lpDependencies
);
2089 wServiceStartName
= SERV_dup( lpServiceStartName
);
2090 wPassword
= SERV_dup( lpPassword
);
2091 wDisplayName
= SERV_dup( lpDisplayName
);
2093 r
= ChangeServiceConfigW( hService
, dwServiceType
,
2094 dwStartType
, dwErrorControl
, wBinaryPathName
,
2095 wLoadOrderGroup
, lpdwTagId
, wDependencies
,
2096 wServiceStartName
, wPassword
, wDisplayName
);
2098 SERV_free( wBinaryPathName
);
2099 SERV_free( wLoadOrderGroup
);
2100 SERV_free( wDependencies
);
2101 SERV_free( wServiceStartName
);
2102 SERV_free( wPassword
);
2103 SERV_free( wDisplayName
);
2108 /******************************************************************************
2109 * ChangeServiceConfig2A [ADVAPI32.@]
2111 BOOL WINAPI
ChangeServiceConfig2A( SC_HANDLE hService
, DWORD dwInfoLevel
,
2116 TRACE("%p %ld %p\n",hService
, dwInfoLevel
, lpInfo
);
2118 if (dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
2120 LPSERVICE_DESCRIPTIONA sd
= (LPSERVICE_DESCRIPTIONA
) lpInfo
;
2121 SERVICE_DESCRIPTIONW sdw
;
2123 sdw
.lpDescription
= SERV_dup( sd
->lpDescription
);
2125 r
= ChangeServiceConfig2W( hService
, dwInfoLevel
, &sdw
);
2127 SERV_free( sdw
.lpDescription
);
2129 else if (dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
2131 LPSERVICE_FAILURE_ACTIONSA fa
= (LPSERVICE_FAILURE_ACTIONSA
) lpInfo
;
2132 SERVICE_FAILURE_ACTIONSW faw
;
2134 faw
.dwResetPeriod
= fa
->dwResetPeriod
;
2135 faw
.lpRebootMsg
= SERV_dup( fa
->lpRebootMsg
);
2136 faw
.lpCommand
= SERV_dup( fa
->lpCommand
);
2137 faw
.cActions
= fa
->cActions
;
2138 faw
.lpsaActions
= fa
->lpsaActions
;
2140 r
= ChangeServiceConfig2W( hService
, dwInfoLevel
, &faw
);
2142 SERV_free( faw
.lpRebootMsg
);
2143 SERV_free( faw
.lpCommand
);
2146 SetLastError( ERROR_INVALID_PARAMETER
);
2151 /******************************************************************************
2152 * ChangeServiceConfig2W [ADVAPI32.@]
2154 BOOL WINAPI
ChangeServiceConfig2W( SC_HANDLE hService
, DWORD dwInfoLevel
,
2158 struct sc_service
*hsvc
;
2160 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
2163 SetLastError( ERROR_INVALID_HANDLE
);
2168 if (dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
2170 static const WCHAR szDescription
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2171 LPSERVICE_DESCRIPTIONW sd
= (LPSERVICE_DESCRIPTIONW
)lpInfo
;
2172 if (sd
->lpDescription
)
2174 TRACE("Setting Description to %s\n",debugstr_w(sd
->lpDescription
));
2175 if (sd
->lpDescription
[0] == 0)
2176 RegDeleteValueW(hKey
,szDescription
);
2178 RegSetValueExW(hKey
, szDescription
, 0, REG_SZ
,
2179 (LPVOID
)sd
->lpDescription
,
2180 sizeof(WCHAR
)*(strlenW(sd
->lpDescription
)+1));
2184 FIXME("STUB: %p %ld %p\n",hService
, dwInfoLevel
, lpInfo
);
2188 /******************************************************************************
2189 * QueryServiceObjectSecurity [ADVAPI32.@]
2191 BOOL WINAPI
QueryServiceObjectSecurity(SC_HANDLE hService
,
2192 SECURITY_INFORMATION dwSecurityInformation
,
2193 PSECURITY_DESCRIPTOR lpSecurityDescriptor
,
2194 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
2198 FIXME("%p %ld %p %lu %p\n", hService
, dwSecurityInformation
,
2199 lpSecurityDescriptor
, cbBufSize
, pcbBytesNeeded
);
2201 InitializeSecurityDescriptor(lpSecurityDescriptor
, SECURITY_DESCRIPTOR_REVISION
);
2203 pACL
= HeapAlloc( GetProcessHeap(), 0, sizeof(ACL
) );
2204 InitializeAcl(pACL
, sizeof(ACL
), ACL_REVISION
);
2205 SetSecurityDescriptorDacl(lpSecurityDescriptor
, TRUE
, pACL
, TRUE
);
2209 /******************************************************************************
2210 * SetServiceObjectSecurity [ADVAPI32.@]
2212 BOOL WINAPI
SetServiceObjectSecurity(SC_HANDLE hService
,
2213 SECURITY_INFORMATION dwSecurityInformation
,
2214 PSECURITY_DESCRIPTOR lpSecurityDescriptor
)
2216 FIXME("%p %ld %p\n", hService
, dwSecurityInformation
, lpSecurityDescriptor
);
2220 /******************************************************************************
2221 * SetServiceBits [ADVAPI32.@]
2223 BOOL WINAPI
SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus
,
2224 DWORD dwServiceBits
,
2226 BOOL bUpdateImmediately
)
2228 FIXME("%p %08lx %x %x\n", hServiceStatus
, dwServiceBits
,
2229 bSetBitsOn
, bUpdateImmediately
);
2233 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerExA( LPCSTR lpServiceName
,
2234 LPHANDLER_FUNCTION_EX lpHandlerProc
, LPVOID lpContext
)
2236 FIXME("%s %p %p\n", debugstr_a(lpServiceName
), lpHandlerProc
, lpContext
);
2240 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName
,
2241 LPHANDLER_FUNCTION_EX lpHandlerProc
, LPVOID lpContext
)
2243 FIXME("%s %p %p\n", debugstr_w(lpServiceName
), lpHandlerProc
, lpContext
);