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"
36 WINE_DEFAULT_DEBUG_CHANNEL(advapi
);
38 static const WCHAR szServiceManagerKey
[] = { 'S','y','s','t','e','m','\\',
39 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
40 'S','e','r','v','i','c','e','s','\\',0 };
41 static const WCHAR szSCMLock
[] = {'A','D','V','A','P','I','_','S','C','M',
44 typedef struct service_start_info_t
51 #define WINESERV_STARTINFO 1
52 #define WINESERV_GETSTATUS 2
53 #define WINESERV_SENDCONTROL 3
55 typedef struct service_data_t
57 struct service_data_t
*next
;
58 LPHANDLER_FUNCTION handler
;
59 SERVICE_STATUS status
;
63 LPSERVICE_MAIN_FUNCTIONA a
;
64 LPSERVICE_MAIN_FUNCTIONW w
;
70 static CRITICAL_SECTION service_cs
;
71 static CRITICAL_SECTION_DEBUG service_cs_debug
=
74 { &service_cs_debug
.ProcessLocksList
,
75 &service_cs_debug
.ProcessLocksList
},
76 0, 0, { 0, (DWORD
)(__FILE__
": service_cs") }
78 static CRITICAL_SECTION service_cs
= { &service_cs_debug
, -1, 0, 0, 0, 0 };
80 service_data
*service_list
;
82 /******************************************************************************
86 #define MAX_SERVICE_NAME 256
88 typedef enum { SC_HTYPE_MANAGER
, SC_HTYPE_SERVICE
} SC_HANDLE_TYPE
;
91 typedef VOID (*sc_handle_destructor
)(struct sc_handle
*);
97 sc_handle_destructor destroy
;
100 struct sc_manager
/* service control manager handle */
102 struct sc_handle hdr
;
103 HKEY hkey
; /* handle to services database in the registry */
106 struct sc_service
/* service handle */
108 struct sc_handle hdr
;
109 HKEY hkey
; /* handle to service entry in the registry (under hkey) */
110 struct sc_manager
*scm
; /* pointer to SCM handle */
114 static void *sc_handle_alloc(SC_HANDLE_TYPE htype
, DWORD size
,
115 sc_handle_destructor destroy
)
117 struct sc_handle
*hdr
;
119 hdr
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
124 hdr
->destroy
= destroy
;
126 TRACE("sc_handle type=%d -> %p\n", htype
, hdr
);
130 static void *sc_handle_get_handle_data(SC_HANDLE handle
, DWORD htype
)
132 struct sc_handle
*hdr
= (struct sc_handle
*) handle
;
136 if (hdr
->htype
!= htype
)
141 static void sc_handle_free(struct sc_handle
* hdr
)
145 if (--hdr
->ref_count
)
148 HeapFree(GetProcessHeap(), 0, hdr
);
151 static void sc_handle_destroy_manager(struct sc_handle
*handle
)
153 struct sc_manager
*mgr
= (struct sc_manager
*) handle
;
155 TRACE("destroying SC Manager %p\n", mgr
);
157 RegCloseKey(mgr
->hkey
);
160 static void sc_handle_destroy_service(struct sc_handle
*handle
)
162 struct sc_service
*svc
= (struct sc_service
*) handle
;
164 TRACE("destroying service %p\n", svc
);
166 RegCloseKey(svc
->hkey
);
168 sc_handle_free(&svc
->scm
->hdr
);
172 /******************************************************************************
173 * String management functions
175 static inline LPWSTR
SERV_dup( LPCSTR str
)
182 len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
183 wstr
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof (WCHAR
) );
184 MultiByteToWideChar( CP_ACP
, 0, str
, -1, wstr
, len
);
188 static inline LPWSTR
SERV_dupmulti(LPCSTR str
)
196 len
+= MultiByteToWideChar( CP_ACP
, 0, &str
[n
], -1, NULL
, 0 );
197 n
+= (strlen( &str
[n
] ) + 1);
202 wstr
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof (WCHAR
) );
203 MultiByteToWideChar( CP_ACP
, 0, str
, n
, wstr
, len
);
207 static inline VOID
SERV_free( LPWSTR wstr
)
209 HeapFree( GetProcessHeap(), 0, wstr
);
212 /******************************************************************************
213 * registry access functions and data
215 static const WCHAR szDisplayName
[] = {
216 'D','i','s','p','l','a','y','N','a','m','e', 0 };
217 static const WCHAR szType
[] = {'T','y','p','e',0};
218 static const WCHAR szStart
[] = {'S','t','a','r','t',0};
219 static const WCHAR szError
[] = {
220 'E','r','r','o','r','C','o','n','t','r','o','l', 0};
221 static const WCHAR szImagePath
[] = {'I','m','a','g','e','P','a','t','h',0};
222 static const WCHAR szGroup
[] = {'G','r','o','u','p',0};
223 static const WCHAR szDependencies
[] = {
224 'D','e','p','e','n','d','e','n','c','i','e','s',0};
225 static const WCHAR szDependOnService
[] = {
226 'D','e','p','e','n','d','O','n','S','e','r','v','i','c','e',0};
235 static inline void service_set_value( struct reg_value
*val
,
236 DWORD type
, LPCWSTR name
, LPCVOID data
, DWORD size
)
244 static inline void service_set_dword( struct reg_value
*val
,
245 LPCWSTR name
, DWORD
*data
)
247 service_set_value( val
, REG_DWORD
, name
, data
, sizeof (DWORD
));
250 static inline void service_set_string( struct reg_value
*val
,
251 LPCWSTR name
, LPCWSTR string
)
253 DWORD len
= (lstrlenW(string
)+1) * sizeof (WCHAR
);
254 service_set_value( val
, REG_SZ
, name
, string
, len
);
257 static inline void service_set_multi_string( struct reg_value
*val
,
258 LPCWSTR name
, LPCWSTR string
)
262 /* determine the length of a double null terminated multi string */
264 len
+= (lstrlenW( &string
[ len
] )+1);
265 } while ( string
[ len
++ ] );
267 len
*= sizeof (WCHAR
);
268 service_set_value( val
, REG_MULTI_SZ
, name
, string
, len
);
271 static inline LONG
service_write_values( HKEY hKey
,
272 struct reg_value
*val
, int n
)
274 LONG r
= ERROR_SUCCESS
;
279 r
= RegSetValueExW(hKey
, val
[i
].name
, 0, val
[i
].type
,
280 (const BYTE
*)val
[i
].data
, val
[i
].size
);
281 if( r
!= ERROR_SUCCESS
)
287 /******************************************************************************
288 * Service IPC functions
290 static LPWSTR
service_get_pipe_name(LPWSTR service
)
292 static const WCHAR prefix
[] = { '\\','\\','.','\\','p','i','p','e','\\',
293 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
297 len
= sizeof prefix
+ strlenW(service
)*sizeof(WCHAR
);
298 name
= HeapAlloc(GetProcessHeap(), 0, len
);
299 strcpyW(name
, prefix
);
300 strcatW(name
, service
);
304 static HANDLE
service_open_pipe(LPWSTR service
)
306 LPWSTR szPipe
= service_get_pipe_name( service
);
307 HANDLE handle
= INVALID_HANDLE_VALUE
;
310 handle
= CreateFileW(szPipe
, GENERIC_READ
|GENERIC_WRITE
,
311 0, NULL
, OPEN_ALWAYS
, 0, NULL
);
312 if (handle
!= INVALID_HANDLE_VALUE
)
314 if (GetLastError() != ERROR_PIPE_BUSY
)
316 } while (WaitNamedPipeW(szPipe
, NMPWAIT_WAIT_FOREVER
));
322 /******************************************************************************
323 * service_get_event_handle
325 static HANDLE
service_get_event_handle(LPWSTR service
)
327 static const WCHAR prefix
[] = {
328 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
333 len
= sizeof prefix
+ strlenW(service
)*sizeof(WCHAR
);
334 name
= HeapAlloc(GetProcessHeap(), 0, len
);
335 strcpyW(name
, prefix
);
336 strcatW(name
, service
);
337 handle
= CreateEventW(NULL
, TRUE
, FALSE
, name
);
342 /******************************************************************************
345 * Call into the main service routine provided by StartServiceCtrlDispatcher.
347 static DWORD WINAPI
service_thread(LPVOID arg
)
349 service_data
*info
= arg
;
350 LPWSTR str
= info
->args
;
351 DWORD argc
= 0, len
= 0;
357 len
+= strlenW(&str
[len
]) + 1;
365 argv
= HeapAlloc(GetProcessHeap(), 0, (argc
+1)*sizeof(LPWSTR
));
366 for (argc
=0, p
=str
; *p
; p
+= strlenW(p
) + 1)
370 info
->proc
.w(argc
, argv
);
371 HeapFree(GetProcessHeap(), 0, argv
);
375 LPSTR strA
, *argv
, p
;
378 lenA
= WideCharToMultiByte(CP_ACP
,0, str
, len
, NULL
, 0, NULL
, NULL
);
379 strA
= HeapAlloc(GetProcessHeap(), 0, lenA
);
380 WideCharToMultiByte(CP_ACP
,0, str
, len
, strA
, lenA
, NULL
, NULL
);
382 argv
= HeapAlloc(GetProcessHeap(), 0, (argc
+1)*sizeof(LPSTR
));
383 for (argc
=0, p
=strA
; *p
; p
+= strlen(p
) + 1)
387 info
->proc
.a(argc
, argv
);
388 HeapFree(GetProcessHeap(), 0, argv
);
389 HeapFree(GetProcessHeap(), 0, strA
);
394 /******************************************************************************
395 * service_handle_start
397 static BOOL
service_handle_start(HANDLE pipe
, service_data
*service
, DWORD count
)
399 DWORD read
= 0, result
= 0;
403 TRACE("%p %p %ld\n", pipe
, service
, count
);
405 args
= HeapAlloc(GetProcessHeap(), 0, count
*sizeof(WCHAR
));
406 r
= ReadFile(pipe
, args
, count
*sizeof(WCHAR
), &read
, NULL
);
407 if (!r
|| count
!=read
/sizeof(WCHAR
) || args
[count
-1])
409 ERR("pipe read failed r = %d count = %ld/%ld args[n-1]=%s\n",
410 r
, count
, read
/sizeof(WCHAR
), debugstr_wn(args
, count
));
416 ERR("service is not stopped\n");
421 SERV_free(service
->args
);
422 service
->args
= args
;
424 service
->thread
= CreateThread( NULL
, 0, service_thread
,
428 HeapFree(GetProcessHeap(), 0, args
);
429 WriteFile( pipe
, &result
, sizeof result
, &read
, NULL
);
434 /******************************************************************************
435 * service_send_start_message
437 static BOOL
service_send_start_message(HANDLE pipe
, LPCWSTR
*argv
, DWORD argc
)
439 DWORD i
, len
, count
, result
;
440 service_start_info
*ssi
;
444 TRACE("%p %p %ld\n", pipe
, argv
, argc
);
446 /* calculate how much space do we need to send the startup info */
448 for (i
=0; i
<argc
; i
++)
449 len
+= strlenW(argv
[i
])+1;
451 ssi
= HeapAlloc(GetProcessHeap(),0,sizeof *ssi
+ (len
-1)*sizeof(WCHAR
));
452 ssi
->cmd
= WINESERV_STARTINFO
;
455 /* copy service args into a single buffer*/
457 for (i
=0; i
<argc
; i
++)
464 r
= WriteFile(pipe
, ssi
, sizeof *ssi
+ len
*sizeof(WCHAR
), &count
, NULL
);
466 r
= ReadFile(pipe
, &result
, sizeof result
, &count
, NULL
);
468 HeapFree(GetProcessHeap(),0,ssi
);
473 /******************************************************************************
474 * service_handle_get_status
476 static BOOL
service_handle_get_status(HANDLE pipe
, service_data
*service
)
480 return WriteFile(pipe
, &service
->status
,
481 sizeof service
->status
, &count
, NULL
);
484 /******************************************************************************
487 static BOOL
service_get_status(HANDLE pipe
, LPSERVICE_STATUS status
)
489 DWORD cmd
[2], count
= 0;
492 cmd
[0] = WINESERV_GETSTATUS
;
494 r
= WriteFile( pipe
, cmd
, sizeof cmd
, &count
, NULL
);
495 if (!r
|| count
!= sizeof cmd
)
497 ERR("service protocol error - failed to write pipe!\n");
500 r
= ReadFile( pipe
, status
, sizeof *status
, &count
, NULL
);
501 if (!r
|| count
!= sizeof *status
)
502 ERR("service protocol error - failed to read pipe "
503 "r = %d count = %ld/%d!\n", r
, count
, sizeof *status
);
507 /******************************************************************************
508 * service_send_control
510 static BOOL
service_send_control(HANDLE pipe
, DWORD dwControl
, DWORD
*result
)
512 DWORD cmd
[2], count
= 0;
515 cmd
[0] = WINESERV_SENDCONTROL
;
517 r
= WriteFile(pipe
, cmd
, sizeof cmd
, &count
, NULL
);
518 if (!r
|| count
!= sizeof cmd
)
520 ERR("service protocol error - failed to write pipe!\n");
523 r
= ReadFile(pipe
, result
, sizeof *result
, &count
, NULL
);
524 if (!r
|| count
!= sizeof *result
)
525 ERR("service protocol error - failed to read pipe "
526 "r = %d count = %ld/%d!\n", r
, count
, sizeof *result
);
530 /******************************************************************************
531 * service_accepts_control
533 static BOOL
service_accepts_control(service_data
*service
, DWORD dwControl
)
535 DWORD a
= service
->status
.dwControlsAccepted
;
539 case SERVICE_CONTROL_INTERROGATE
:
541 case SERVICE_CONTROL_STOP
:
542 if (a
&SERVICE_ACCEPT_STOP
)
545 case SERVICE_CONTROL_SHUTDOWN
:
546 if (a
&SERVICE_ACCEPT_SHUTDOWN
)
549 case SERVICE_CONTROL_PAUSE
:
550 case SERVICE_CONTROL_CONTINUE
:
551 if (a
&SERVICE_ACCEPT_PAUSE_CONTINUE
)
554 case SERVICE_CONTROL_PARAMCHANGE
:
555 if (a
&SERVICE_ACCEPT_PARAMCHANGE
)
558 case SERVICE_CONTROL_NETBINDADD
:
559 case SERVICE_CONTROL_NETBINDREMOVE
:
560 case SERVICE_CONTROL_NETBINDENABLE
:
561 case SERVICE_CONTROL_NETBINDDISABLE
:
562 if (a
&SERVICE_ACCEPT_NETBINDCHANGE
)
565 if (1) /* (!service->handlerex) */
569 case SERVICE_CONTROL_HARDWAREPROFILECHANGE
:
570 if (a
&SERVICE_ACCEPT_HARDWAREPROFILECHANGE
)
573 case SERVICE_CONTROL_POWEREVENT
:
574 if (a
&SERVICE_ACCEPT_POWEREVENT
)
577 case SERVICE_CONTROL_SESSIONCHANGE
:
578 if (a
&SERVICE_ACCEPT_SESSIONCHANGE
)
585 /******************************************************************************
586 * service_handle_control
588 static BOOL
service_handle_control(HANDLE pipe
, service_data
*service
,
591 DWORD count
, ret
= ERROR_INVALID_SERVICE_CONTROL
;
593 TRACE("received control %ld\n", dwControl
);
595 if (service_accepts_control(service
, dwControl
) && service
->handler
)
597 service
->handler(dwControl
);
600 return WriteFile(pipe
, &ret
, sizeof ret
, &count
, NULL
);
603 /******************************************************************************
604 * service_reap_thread
606 static DWORD
service_reap_thread(service_data
*service
)
610 if (!service
->thread
)
612 GetExitCodeThread(service
->thread
, &exitcode
);
613 if (exitcode
!=STILL_ACTIVE
)
615 CloseHandle(service
->thread
);
621 /******************************************************************************
622 * service_control_dispatcher
624 static DWORD WINAPI
service_control_dispatcher(LPVOID arg
)
626 service_data
*service
= arg
;
630 TRACE("%p %s\n", service
, debugstr_w(service
->name
));
632 /* create a pipe to talk to the rest of the world with */
633 name
= service_get_pipe_name(service
->name
);
634 pipe
= CreateNamedPipeW(name
, PIPE_ACCESS_DUPLEX
,
635 PIPE_TYPE_BYTE
|PIPE_WAIT
, 1, 256, 256, 10000, NULL
);
638 /* let the process who started us know we've tried to create a pipe */
639 event
= service_get_event_handle(service
->name
);
643 if (pipe
==INVALID_HANDLE_VALUE
)
645 ERR("failed to create pipe, error = %ld\n", GetLastError());
649 /* dispatcher loop */
653 DWORD count
, req
[2] = {0,0};
655 r
= ConnectNamedPipe(pipe
, NULL
);
656 if (!r
&& GetLastError() != ERROR_PIPE_CONNECTED
)
658 ERR("pipe connect failed\n");
662 r
= ReadFile( pipe
, &req
, sizeof req
, &count
, NULL
);
663 if (!r
|| count
!=sizeof req
)
665 ERR("pipe read failed\n");
669 service_reap_thread(service
);
671 /* handle the request */
674 case WINESERV_STARTINFO
:
675 service_handle_start(pipe
, service
, req
[1]);
677 case WINESERV_GETSTATUS
:
678 service_handle_get_status(pipe
, service
);
680 case WINESERV_SENDCONTROL
:
681 service_handle_control(pipe
, service
, req
[1]);
684 ERR("received invalid command %ld length %ld\n", req
[0], req
[1]);
687 FlushFileBuffers(pipe
);
688 DisconnectNamedPipe(pipe
);
695 /******************************************************************************
696 * service_run_threads
698 static BOOL
service_run_threads(void)
700 service_data
*service
;
701 DWORD count
= 0, n
= 0;
704 EnterCriticalSection( &service_cs
);
706 /* count how many services there are */
707 for (service
= service_list
; service
; service
= service
->next
)
710 TRACE("starting %ld pipe listener threads\n", count
);
712 handles
= HeapAlloc(GetProcessHeap(), 0, sizeof(HANDLE
)*count
);
714 for (n
=0, service
= service_list
; service
; service
= service
->next
, n
++)
715 handles
[n
] = CreateThread( NULL
, 0, service_control_dispatcher
,
719 LeaveCriticalSection( &service_cs
);
721 /* wait for all the threads to pack up and exit */
722 WaitForMultipleObjectsEx(count
, handles
, TRUE
, INFINITE
, FALSE
);
724 HeapFree(GetProcessHeap(), 0, handles
);
729 /******************************************************************************
730 * StartServiceCtrlDispatcherA [ADVAPI32.@]
732 * Connects a process containing one or more services to the service control
736 * servent [I] A list of the service names and service procedures
738 BOOL WINAPI
StartServiceCtrlDispatcherA( LPSERVICE_TABLE_ENTRYA servent
)
744 TRACE("%p\n", servent
);
746 EnterCriticalSection( &service_cs
);
747 while (servent
->lpServiceName
)
749 LPSTR name
= servent
->lpServiceName
;
751 len
= MultiByteToWideChar(CP_ACP
, 0, name
, -1, NULL
, 0);
752 sz
= len
*sizeof(WCHAR
) + sizeof *info
;
753 info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sz
);
754 MultiByteToWideChar(CP_ACP
, 0, name
, -1, info
->name
, len
);
755 info
->proc
.a
= servent
->lpServiceProc
;
756 info
->unicode
= FALSE
;
758 /* insert into the list */
759 info
->next
= service_list
;
764 LeaveCriticalSection( &service_cs
);
766 service_run_threads();
771 /******************************************************************************
772 * StartServiceCtrlDispatcherW [ADVAPI32.@]
774 * Connects a process containing one or more services to the service control
778 * servent [I] A list of the service names and service procedures
780 BOOL WINAPI
StartServiceCtrlDispatcherW( LPSERVICE_TABLE_ENTRYW servent
)
786 TRACE("%p\n", servent
);
788 EnterCriticalSection( &service_cs
);
789 while (servent
->lpServiceName
)
791 LPWSTR name
= servent
->lpServiceName
;
794 sz
= len
*sizeof(WCHAR
) + sizeof *info
;
795 info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sz
);
796 strcpyW(info
->name
, name
);
797 info
->proc
.w
= servent
->lpServiceProc
;
798 info
->unicode
= TRUE
;
800 /* insert into the list */
801 info
->next
= service_list
;
806 LeaveCriticalSection( &service_cs
);
808 service_run_threads();
813 /******************************************************************************
814 * LockServiceDatabase [ADVAPI32.@]
816 SC_LOCK WINAPI
LockServiceDatabase (SC_HANDLE hSCManager
)
820 TRACE("%p\n",hSCManager
);
822 ret
= CreateSemaphoreW( NULL
, 1, 1, szSCMLock
);
823 if( ret
&& GetLastError() == ERROR_ALREADY_EXISTS
)
827 SetLastError( ERROR_SERVICE_DATABASE_LOCKED
);
830 TRACE("returning %p\n", ret
);
835 /******************************************************************************
836 * UnlockServiceDatabase [ADVAPI32.@]
838 BOOL WINAPI
UnlockServiceDatabase (SC_LOCK ScLock
)
840 TRACE("%p\n",ScLock
);
842 return CloseHandle( ScLock
);
845 /******************************************************************************
846 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
848 SERVICE_STATUS_HANDLE WINAPI
849 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName
, LPHANDLER_FUNCTION lpfHandler
)
851 LPWSTR lpServiceNameW
;
852 SERVICE_STATUS_HANDLE ret
;
854 lpServiceNameW
= SERV_dup(lpServiceName
);
855 ret
= RegisterServiceCtrlHandlerW( lpServiceNameW
, lpfHandler
);
856 SERV_free(lpServiceNameW
);
860 /******************************************************************************
861 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
867 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName
,
868 LPHANDLER_FUNCTION lpfHandler
)
870 service_data
*service
;
872 EnterCriticalSection( &service_cs
);
873 for(service
= service_list
; service
; service
= service
->next
)
874 if(!strcmpW(lpServiceName
, service
->name
))
877 service
->handler
= lpfHandler
;
878 LeaveCriticalSection( &service_cs
);
880 return (SERVICE_STATUS_HANDLE
)service
;
883 /******************************************************************************
884 * SetServiceStatus [ADVAPI32.@]
891 SetServiceStatus( SERVICE_STATUS_HANDLE hService
, LPSERVICE_STATUS lpStatus
)
893 service_data
*service
;
896 TRACE("%lx %lx %lx %lx %lx %lx %lx %lx\n", hService
,
897 lpStatus
->dwServiceType
, lpStatus
->dwCurrentState
,
898 lpStatus
->dwControlsAccepted
, lpStatus
->dwWin32ExitCode
,
899 lpStatus
->dwServiceSpecificExitCode
, lpStatus
->dwCheckPoint
,
900 lpStatus
->dwWaitHint
);
902 EnterCriticalSection( &service_cs
);
903 for (service
= service_list
; service
; service
= service
->next
)
904 if(service
== (service_data
*)hService
)
908 memcpy( &service
->status
, lpStatus
, sizeof(SERVICE_STATUS
) );
909 TRACE("Set service status to %ld\n",service
->status
.dwCurrentState
);
913 LeaveCriticalSection( &service_cs
);
919 /******************************************************************************
920 * OpenSCManagerA [ADVAPI32.@]
922 * Establish a connection to the service control manager and open its database.
925 * lpMachineName [I] Pointer to machine name string
926 * lpDatabaseName [I] Pointer to database name string
927 * dwDesiredAccess [I] Type of access
930 * Success: A Handle to the service control manager database
933 SC_HANDLE WINAPI
OpenSCManagerA( LPCSTR lpMachineName
, LPCSTR lpDatabaseName
,
934 DWORD dwDesiredAccess
)
936 LPWSTR lpMachineNameW
, lpDatabaseNameW
;
939 lpMachineNameW
= SERV_dup(lpMachineName
);
940 lpDatabaseNameW
= SERV_dup(lpDatabaseName
);
941 ret
= OpenSCManagerW(lpMachineNameW
, lpDatabaseNameW
, dwDesiredAccess
);
942 SERV_free(lpDatabaseNameW
);
943 SERV_free(lpMachineNameW
);
947 /******************************************************************************
948 * OpenSCManagerW [ADVAPI32.@]
950 * See OpenSCManagerA.
952 SC_HANDLE WINAPI
OpenSCManagerW( LPCWSTR lpMachineName
, LPCWSTR lpDatabaseName
,
953 DWORD dwDesiredAccess
)
955 struct sc_manager
*manager
;
959 TRACE("(%s,%s,0x%08lx)\n", debugstr_w(lpMachineName
),
960 debugstr_w(lpDatabaseName
), dwDesiredAccess
);
962 if( lpDatabaseName
&& lpDatabaseName
[0] )
964 if( strcmpiW( lpDatabaseName
, SERVICES_ACTIVE_DATABASEW
) == 0 )
966 /* noop, all right */
968 else if( strcmpiW( lpDatabaseName
, SERVICES_FAILED_DATABASEW
) == 0 )
970 SetLastError( ERROR_DATABASE_DOES_NOT_EXIST
);
975 SetLastError( ERROR_INVALID_NAME
);
980 manager
= sc_handle_alloc( SC_HTYPE_MANAGER
, sizeof (struct sc_manager
),
981 sc_handle_destroy_manager
);
985 r
= RegConnectRegistryW(lpMachineName
,HKEY_LOCAL_MACHINE
,&hReg
);
986 if (r
!=ERROR_SUCCESS
)
989 r
= RegOpenKeyExW(hReg
, szServiceManagerKey
,
990 0, KEY_ALL_ACCESS
, &manager
->hkey
);
992 if (r
!=ERROR_SUCCESS
)
995 TRACE("returning %p\n", manager
);
997 return (SC_HANDLE
) &manager
->hdr
;
1000 sc_handle_free( &manager
->hdr
);
1004 /******************************************************************************
1005 * ControlService [ADVAPI32.@]
1007 * Send a control code to a service.
1010 * hService [I] Handle of the service control manager database
1011 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
1012 * lpServiceStatus [O] Destination for the status of the service, if available
1019 * Unlike M$' implementation, control requests are not serialized and may be
1020 * processed asynchronously.
1022 BOOL WINAPI
ControlService( SC_HANDLE hService
, DWORD dwControl
,
1023 LPSERVICE_STATUS lpServiceStatus
)
1025 struct sc_service
*hsvc
;
1029 TRACE("%p %ld %p\n", hService
, dwControl
, lpServiceStatus
);
1031 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1034 SetLastError( ERROR_INVALID_HANDLE
);
1038 ret
= QueryServiceStatus(hService
, lpServiceStatus
);
1041 ERR("failed to query service status\n");
1042 SetLastError(ERROR_SERVICE_NOT_ACTIVE
);
1046 switch (lpServiceStatus
->dwCurrentState
)
1048 case SERVICE_STOPPED
:
1049 SetLastError(ERROR_SERVICE_NOT_ACTIVE
);
1051 case SERVICE_START_PENDING
:
1052 if (dwControl
==SERVICE_CONTROL_STOP
)
1055 case SERVICE_STOP_PENDING
:
1056 SetLastError(ERROR_SERVICE_CANNOT_ACCEPT_CTRL
);
1060 handle
= service_open_pipe(hsvc
->name
);
1061 if (handle
!=INVALID_HANDLE_VALUE
)
1063 DWORD result
= ERROR_SUCCESS
;
1064 ret
= service_send_control(handle
, dwControl
, &result
);
1065 CloseHandle(handle
);
1066 if (result
!=ERROR_SUCCESS
)
1068 SetLastError(result
);
1076 /******************************************************************************
1077 * CloseServiceHandle [ADVAPI32.@]
1079 * Close a handle to a service or the service control manager database.
1082 * hSCObject [I] Handle to service or service control manager database
1089 CloseServiceHandle( SC_HANDLE hSCObject
)
1091 TRACE("%p\n", hSCObject
);
1093 sc_handle_free( (struct sc_handle
*) hSCObject
);
1099 /******************************************************************************
1100 * OpenServiceA [ADVAPI32.@]
1102 * Open a handle to a service.
1105 * hSCManager [I] Handle of the service control manager database
1106 * lpServiceName [I] Name of the service to open
1107 * dwDesiredAccess [I] Access required to the service
1110 * Success: Handle to the service
1113 SC_HANDLE WINAPI
OpenServiceA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
1114 DWORD dwDesiredAccess
)
1116 LPWSTR lpServiceNameW
;
1119 TRACE("%p %s %ld\n", hSCManager
, debugstr_a(lpServiceName
), dwDesiredAccess
);
1121 lpServiceNameW
= SERV_dup(lpServiceName
);
1122 ret
= OpenServiceW( hSCManager
, lpServiceNameW
, dwDesiredAccess
);
1123 SERV_free(lpServiceNameW
);
1128 /******************************************************************************
1129 * OpenServiceW [ADVAPI32.@]
1133 SC_HANDLE WINAPI
OpenServiceW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
1134 DWORD dwDesiredAccess
)
1136 struct sc_manager
*hscm
;
1137 struct sc_service
*hsvc
;
1142 TRACE("%p %s %ld\n", hSCManager
, debugstr_w(lpServiceName
), dwDesiredAccess
);
1146 SetLastError(ERROR_INVALID_ADDRESS
);
1150 hscm
= sc_handle_get_handle_data( hSCManager
, SC_HTYPE_MANAGER
);
1153 SetLastError( ERROR_INVALID_HANDLE
);
1157 r
= RegOpenKeyExW( hscm
->hkey
, lpServiceName
, 0, KEY_ALL_ACCESS
, &hKey
);
1158 if (r
!=ERROR_SUCCESS
)
1160 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST
);
1164 len
= strlenW(lpServiceName
)+1;
1165 hsvc
= sc_handle_alloc( SC_HTYPE_SERVICE
,
1166 sizeof (struct sc_service
) + len
*sizeof(WCHAR
),
1167 sc_handle_destroy_service
);
1170 strcpyW( hsvc
->name
, lpServiceName
);
1173 /* add reference to SCM handle */
1174 hscm
->hdr
.ref_count
++;
1177 TRACE("returning %p\n",hsvc
);
1179 return (SC_HANDLE
) &hsvc
->hdr
;
1182 /******************************************************************************
1183 * CreateServiceW [ADVAPI32.@]
1186 CreateServiceW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
1187 LPCWSTR lpDisplayName
, DWORD dwDesiredAccess
,
1188 DWORD dwServiceType
, DWORD dwStartType
,
1189 DWORD dwErrorControl
, LPCWSTR lpBinaryPathName
,
1190 LPCWSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
,
1191 LPCWSTR lpDependencies
, LPCWSTR lpServiceStartName
,
1192 LPCWSTR lpPassword
)
1194 struct sc_manager
*hscm
;
1195 struct sc_service
*hsvc
= NULL
;
1199 struct reg_value val
[10];
1202 TRACE("%p %s %s\n", hSCManager
,
1203 debugstr_w(lpServiceName
), debugstr_w(lpDisplayName
));
1205 hscm
= sc_handle_get_handle_data( hSCManager
, SC_HTYPE_MANAGER
);
1208 SetLastError( ERROR_INVALID_HANDLE
);
1212 r
= RegCreateKeyExW(hscm
->hkey
, lpServiceName
, 0, NULL
,
1213 REG_OPTION_NON_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &hKey
, &dp
);
1214 if (r
!=ERROR_SUCCESS
)
1217 if (dp
!= REG_CREATED_NEW_KEY
)
1219 SetLastError(ERROR_SERVICE_EXISTS
);
1224 service_set_string( &val
[n
++], szDisplayName
, lpDisplayName
);
1226 service_set_dword( &val
[n
++], szType
, &dwServiceType
);
1227 service_set_dword( &val
[n
++], szStart
, &dwStartType
);
1228 service_set_dword( &val
[n
++], szError
, &dwErrorControl
);
1230 if( lpBinaryPathName
)
1231 service_set_string( &val
[n
++], szImagePath
, lpBinaryPathName
);
1233 if( lpLoadOrderGroup
)
1234 service_set_string( &val
[n
++], szGroup
, lpLoadOrderGroup
);
1236 if( lpDependencies
)
1237 service_set_multi_string( &val
[n
++], szDependencies
, lpDependencies
);
1240 FIXME("Don't know how to add a Password for a service.\n");
1242 if( lpServiceStartName
)
1243 service_set_string( &val
[n
++], szDependOnService
, lpServiceStartName
);
1245 r
= service_write_values( hKey
, val
, n
);
1246 if( r
!= ERROR_SUCCESS
)
1249 len
= strlenW(lpServiceName
)+1;
1250 len
= sizeof (struct sc_service
) + len
*sizeof(WCHAR
);
1251 hsvc
= sc_handle_alloc( SC_HTYPE_SERVICE
, len
, sc_handle_destroy_service
);
1254 lstrcpyW( hsvc
->name
, lpServiceName
);
1257 hscm
->hdr
.ref_count
++;
1259 return (SC_HANDLE
) &hsvc
->hdr
;
1262 RegCloseKey( hKey
);
1267 /******************************************************************************
1268 * CreateServiceA [ADVAPI32.@]
1271 CreateServiceA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
1272 LPCSTR lpDisplayName
, DWORD dwDesiredAccess
,
1273 DWORD dwServiceType
, DWORD dwStartType
,
1274 DWORD dwErrorControl
, LPCSTR lpBinaryPathName
,
1275 LPCSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
,
1276 LPCSTR lpDependencies
, LPCSTR lpServiceStartName
,
1279 LPWSTR lpServiceNameW
, lpDisplayNameW
, lpBinaryPathNameW
,
1280 lpLoadOrderGroupW
, lpDependenciesW
, lpServiceStartNameW
, lpPasswordW
;
1283 TRACE("%p %s %s\n", hSCManager
,
1284 debugstr_a(lpServiceName
), debugstr_a(lpDisplayName
));
1286 lpServiceNameW
= SERV_dup( lpServiceName
);
1287 lpDisplayNameW
= SERV_dup( lpDisplayName
);
1288 lpBinaryPathNameW
= SERV_dup( lpBinaryPathName
);
1289 lpLoadOrderGroupW
= SERV_dup( lpLoadOrderGroup
);
1290 lpDependenciesW
= SERV_dupmulti( lpDependencies
);
1291 lpServiceStartNameW
= SERV_dup( lpServiceStartName
);
1292 lpPasswordW
= SERV_dup( lpPassword
);
1294 r
= CreateServiceW( hSCManager
, lpServiceNameW
, lpDisplayNameW
,
1295 dwDesiredAccess
, dwServiceType
, dwStartType
, dwErrorControl
,
1296 lpBinaryPathNameW
, lpLoadOrderGroupW
, lpdwTagId
,
1297 lpDependenciesW
, lpServiceStartNameW
, lpPasswordW
);
1299 SERV_free( lpServiceNameW
);
1300 SERV_free( lpDisplayNameW
);
1301 SERV_free( lpBinaryPathNameW
);
1302 SERV_free( lpLoadOrderGroupW
);
1303 SERV_free( lpDependenciesW
);
1304 SERV_free( lpServiceStartNameW
);
1305 SERV_free( lpPasswordW
);
1311 /******************************************************************************
1312 * DeleteService [ADVAPI32.@]
1314 * Delete a service from the service control manager database.
1317 * hService [I] Handle of the service to delete
1323 BOOL WINAPI
DeleteService( SC_HANDLE hService
)
1325 struct sc_service
*hsvc
;
1327 WCHAR valname
[MAX_PATH
+1];
1332 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1335 SetLastError( ERROR_INVALID_HANDLE
);
1341 /* Clean out the values */
1342 rc
= RegEnumValueW(hKey
, index
, valname
,&size
,0,0,0,0);
1343 while (rc
== ERROR_SUCCESS
)
1345 RegDeleteValueW(hKey
,valname
);
1348 rc
= RegEnumValueW(hKey
, index
, valname
, &size
,0,0,0,0);
1354 /* delete the key */
1355 RegDeleteKeyW(hsvc
->scm
->hkey
, hsvc
->name
);
1361 /******************************************************************************
1362 * StartServiceA [ADVAPI32.@]
1367 * hService [I] Handle of service
1368 * dwNumServiceArgs [I] Number of arguments
1369 * lpServiceArgVectors [I] Address of array of argument strings
1372 * - NT implements this function using an obscure RPC call.
1373 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1374 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1375 * - This will only work for shared address space. How should the service
1376 * args be transferred when address spaces are separated?
1377 * - Can only start one service at a time.
1378 * - Has no concept of privilege.
1384 BOOL WINAPI
StartServiceA( SC_HANDLE hService
, DWORD dwNumServiceArgs
,
1385 LPCSTR
*lpServiceArgVectors
)
1387 LPWSTR
*lpwstr
=NULL
;
1391 TRACE("(%p,%ld,%p)\n",hService
,dwNumServiceArgs
,lpServiceArgVectors
);
1393 if (dwNumServiceArgs
)
1394 lpwstr
= HeapAlloc( GetProcessHeap(), 0,
1395 dwNumServiceArgs
*sizeof(LPWSTR
) );
1397 for(i
=0; i
<dwNumServiceArgs
; i
++)
1398 lpwstr
[i
]=SERV_dup(lpServiceArgVectors
[i
]);
1400 r
= StartServiceW(hService
, dwNumServiceArgs
, (LPCWSTR
*)lpwstr
);
1402 if (dwNumServiceArgs
)
1404 for(i
=0; i
<dwNumServiceArgs
; i
++)
1405 SERV_free(lpwstr
[i
]);
1406 HeapFree(GetProcessHeap(), 0, lpwstr
);
1412 /******************************************************************************
1413 * service_start_process [INTERNAL]
1415 static DWORD
service_start_process(struct sc_service
*hsvc
)
1417 static const WCHAR _ImagePathW
[] = {'I','m','a','g','e','P','a','t','h',0};
1418 PROCESS_INFORMATION pi
;
1420 LPWSTR path
= NULL
, str
;
1421 DWORD type
, size
, ret
;
1425 /* read the executable path from memory */
1427 ret
= RegQueryValueExW(hsvc
->hkey
, _ImagePathW
, NULL
, &type
, NULL
, &size
);
1428 if (ret
!=ERROR_SUCCESS
)
1430 str
= HeapAlloc(GetProcessHeap(),0,size
);
1431 ret
= RegQueryValueExW(hsvc
->hkey
, _ImagePathW
, NULL
, &type
, (LPBYTE
)str
, &size
);
1432 if (ret
==ERROR_SUCCESS
)
1434 size
= ExpandEnvironmentStringsW(str
,NULL
,0);
1435 path
= HeapAlloc(GetProcessHeap(),0,size
*sizeof(WCHAR
));
1436 ExpandEnvironmentStringsW(str
,path
,size
);
1438 HeapFree(GetProcessHeap(),0,str
);
1442 /* wait for the process to start and set an event or terminate */
1443 handles
[0] = service_get_event_handle( hsvc
->name
);
1444 ZeroMemory(&si
, sizeof(STARTUPINFOW
));
1445 si
.cb
= sizeof(STARTUPINFOW
);
1446 r
= CreateProcessW(NULL
, path
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
1449 handles
[1] = pi
.hProcess
;
1450 ret
= WaitForMultipleObjectsEx(2, handles
, FALSE
, 30000, FALSE
);
1451 if(ret
!= WAIT_OBJECT_0
)
1453 SetLastError(ERROR_IO_PENDING
);
1457 CloseHandle( pi
.hThread
);
1458 CloseHandle( pi
.hProcess
);
1460 CloseHandle( handles
[0] );
1461 HeapFree(GetProcessHeap(),0,path
);
1465 static BOOL
service_wait_for_startup(SC_HANDLE hService
)
1468 SERVICE_STATUS status
;
1471 TRACE("%p\n", hService
);
1473 for (i
=0; i
<30; i
++)
1475 status
.dwCurrentState
= 0;
1476 r
= QueryServiceStatus(hService
, &status
);
1479 if (status
.dwCurrentState
== SERVICE_RUNNING
)
1481 TRACE("Service started successfully\n");
1490 /******************************************************************************
1491 * StartServiceW [ADVAPI32.@]
1493 * See StartServiceA.
1495 BOOL WINAPI
StartServiceW(SC_HANDLE hService
, DWORD dwNumServiceArgs
,
1496 LPCWSTR
*lpServiceArgVectors
)
1498 struct sc_service
*hsvc
;
1501 HANDLE handle
= INVALID_HANDLE_VALUE
;
1503 TRACE("%p %ld %p\n", hService
, dwNumServiceArgs
, lpServiceArgVectors
);
1505 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1508 SetLastError(ERROR_INVALID_HANDLE
);
1512 hLock
= LockServiceDatabase(hsvc
->scm
);
1516 handle
= service_open_pipe(hsvc
->name
);
1517 if (handle
==INVALID_HANDLE_VALUE
)
1519 /* start the service process */
1520 if (service_start_process(hsvc
))
1521 handle
= service_open_pipe(hsvc
->name
);
1524 if (handle
!= INVALID_HANDLE_VALUE
)
1526 service_send_start_message(handle
, lpServiceArgVectors
, dwNumServiceArgs
);
1527 CloseHandle(handle
);
1531 UnlockServiceDatabase( hLock
);
1533 TRACE("returning %d\n", r
);
1535 service_wait_for_startup(hService
);
1540 /******************************************************************************
1541 * QueryServiceStatus [ADVAPI32.@]
1545 * lpservicestatus []
1548 BOOL WINAPI
QueryServiceStatus(SC_HANDLE hService
,
1549 LPSERVICE_STATUS lpservicestatus
)
1551 struct sc_service
*hsvc
;
1552 DWORD size
, type
, val
;
1556 TRACE("%p %p\n", hService
, lpservicestatus
);
1558 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1561 SetLastError( ERROR_INVALID_HANDLE
);
1565 pipe
= service_open_pipe(hsvc
->name
);
1566 if (pipe
!= INVALID_HANDLE_VALUE
)
1568 r
= service_get_status(pipe
, lpservicestatus
);
1574 TRACE("Failed to read service status\n");
1576 /* read the service type from the registry */
1578 r
= RegQueryValueExA(hsvc
->hkey
, "Type", NULL
, &type
, (LPBYTE
)&val
, &size
);
1579 if(r
!=ERROR_SUCCESS
|| type
!=REG_DWORD
)
1582 lpservicestatus
->dwServiceType
= val
;
1583 lpservicestatus
->dwCurrentState
= SERVICE_STOPPED
; /* stopped */
1584 lpservicestatus
->dwControlsAccepted
= 0;
1585 lpservicestatus
->dwWin32ExitCode
= ERROR_SERVICE_NEVER_STARTED
;
1586 lpservicestatus
->dwServiceSpecificExitCode
= 0;
1587 lpservicestatus
->dwCheckPoint
= 0;
1588 lpservicestatus
->dwWaitHint
= 0;
1593 /******************************************************************************
1594 * QueryServiceStatusEx [ADVAPI32.@]
1596 * Get information about a service.
1599 * hService [I] Handle to service to get information about
1600 * InfoLevel [I] Level of information to get
1601 * lpBuffer [O] Destination for requested information
1602 * cbBufSize [I] Size of lpBuffer in bytes
1603 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1609 BOOL WINAPI
QueryServiceStatusEx(SC_HANDLE hService
, SC_STATUS_TYPE InfoLevel
,
1610 LPBYTE lpBuffer
, DWORD cbBufSize
,
1611 LPDWORD pcbBytesNeeded
)
1614 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1618 /******************************************************************************
1619 * QueryServiceConfigA [ADVAPI32.@]
1622 QueryServiceConfigA( SC_HANDLE hService
,
1623 LPQUERY_SERVICE_CONFIGA lpServiceConfig
,
1624 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
1626 static const CHAR szDisplayName
[] = "DisplayName";
1627 static const CHAR szType
[] = "Type";
1628 static const CHAR szStart
[] = "Start";
1629 static const CHAR szError
[] = "ErrorControl";
1630 static const CHAR szImagePath
[] = "ImagePath";
1631 static const CHAR szGroup
[] = "Group";
1632 static const CHAR szDependencies
[] = "Dependencies";
1633 struct sc_service
*hsvc
;
1635 CHAR str_buffer
[ MAX_PATH
];
1637 DWORD type
, val
, sz
, total
, n
;
1640 TRACE("%p %p %ld %p\n", hService
, lpServiceConfig
,
1641 cbBufSize
, pcbBytesNeeded
);
1643 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1646 SetLastError( ERROR_INVALID_HANDLE
);
1651 /* calculate the size required first */
1652 total
= sizeof (QUERY_SERVICE_CONFIGA
);
1654 sz
= sizeof(str_buffer
);
1655 r
= RegQueryValueExA( hKey
, szImagePath
, 0, &type
, str_buffer
, &sz
);
1656 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
|| type
== REG_EXPAND_SZ
) )
1658 sz
= ExpandEnvironmentStringsA(str_buffer
,NULL
,0);
1659 if( 0 == sz
) return FALSE
;
1665 /* FIXME: set last error */
1670 r
= RegQueryValueExA( hKey
, szGroup
, 0, &type
, NULL
, &sz
);
1671 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1675 r
= RegQueryValueExA( hKey
, szDependencies
, 0, &type
, NULL
, &sz
);
1676 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_MULTI_SZ
) )
1680 r
= RegQueryValueExA( hKey
, szStart
, 0, &type
, NULL
, &sz
);
1681 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1685 r
= RegQueryValueExA( hKey
, szDisplayName
, 0, &type
, NULL
, &sz
);
1686 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1689 *pcbBytesNeeded
= total
;
1691 /* if there's not enough memory, return an error */
1692 if( total
> cbBufSize
)
1694 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1698 ZeroMemory( lpServiceConfig
, total
);
1701 r
= RegQueryValueExA( hKey
, szType
, 0, &type
, (LPBYTE
)&val
, &sz
);
1702 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_DWORD
) )
1703 lpServiceConfig
->dwServiceType
= val
;
1706 r
= RegQueryValueExA( hKey
, szStart
, 0, &type
, (LPBYTE
)&val
, &sz
);
1707 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_DWORD
) )
1708 lpServiceConfig
->dwStartType
= val
;
1711 r
= RegQueryValueExA( hKey
, szError
, 0, &type
, (LPBYTE
)&val
, &sz
);
1712 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_DWORD
) )
1713 lpServiceConfig
->dwErrorControl
= val
;
1715 /* now do the strings */
1716 p
= (LPBYTE
) &lpServiceConfig
[1];
1717 n
= total
- sizeof (QUERY_SERVICE_CONFIGA
);
1719 sz
= sizeof(str_buffer
);
1720 r
= RegQueryValueExA( hKey
, szImagePath
, 0, &type
, str_buffer
, &sz
);
1721 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
|| type
== REG_EXPAND_SZ
) )
1723 sz
= ExpandEnvironmentStringsA(str_buffer
, p
, n
);
1724 if( 0 == sz
|| sz
> n
) return FALSE
;
1726 lpServiceConfig
->lpBinaryPathName
= (LPSTR
) p
;
1732 /* FIXME: set last error */
1737 r
= RegQueryValueExA( hKey
, szGroup
, 0, &type
, p
, &sz
);
1738 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_SZ
) )
1740 lpServiceConfig
->lpLoadOrderGroup
= (LPSTR
) p
;
1746 r
= RegQueryValueExA( hKey
, szDependencies
, 0, &type
, p
, &sz
);
1747 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_SZ
) )
1749 lpServiceConfig
->lpDependencies
= (LPSTR
) p
;
1755 ERR("Buffer overflow!\n");
1757 TRACE("Image path = %s\n", lpServiceConfig
->lpBinaryPathName
);
1758 TRACE("Group = %s\n", lpServiceConfig
->lpLoadOrderGroup
);
1763 /******************************************************************************
1764 * QueryServiceConfigW [ADVAPI32.@]
1767 QueryServiceConfigW( SC_HANDLE hService
,
1768 LPQUERY_SERVICE_CONFIGW lpServiceConfig
,
1769 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
1771 WCHAR str_buffer
[ MAX_PATH
];
1773 DWORD type
, val
, sz
, total
, n
;
1776 struct sc_service
*hsvc
;
1778 TRACE("%p %p %ld %p\n", hService
, lpServiceConfig
,
1779 cbBufSize
, pcbBytesNeeded
);
1781 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1784 SetLastError( ERROR_INVALID_HANDLE
);
1789 /* calculate the size required first */
1790 total
= sizeof (QUERY_SERVICE_CONFIGW
);
1792 sz
= sizeof(str_buffer
);
1793 r
= RegQueryValueExW( hKey
, szImagePath
, 0, &type
, (LPBYTE
) str_buffer
, &sz
);
1794 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
|| type
== REG_EXPAND_SZ
) )
1796 sz
= ExpandEnvironmentStringsW(str_buffer
,NULL
,0);
1797 if( 0 == sz
) return FALSE
;
1799 total
+= sizeof(WCHAR
) * sz
;
1803 /* FIXME: set last error */
1808 r
= RegQueryValueExW( hKey
, szGroup
, 0, &type
, NULL
, &sz
);
1809 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1813 r
= RegQueryValueExW( hKey
, szDependencies
, 0, &type
, NULL
, &sz
);
1814 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_MULTI_SZ
) )
1817 total
+= sizeof(WCHAR
);
1820 r
= RegQueryValueExW( hKey
, szStart
, 0, &type
, NULL
, &sz
);
1821 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1825 r
= RegQueryValueExW( hKey
, szDisplayName
, 0, &type
, NULL
, &sz
);
1826 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1829 *pcbBytesNeeded
= total
;
1831 /* if there's not enough memory, return an error */
1832 if( total
> cbBufSize
)
1834 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1838 ZeroMemory( lpServiceConfig
, total
);
1841 r
= RegQueryValueExW( hKey
, szType
, 0, &type
, (LPBYTE
)&val
, &sz
);
1842 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_DWORD
) )
1843 lpServiceConfig
->dwServiceType
= val
;
1846 r
= RegQueryValueExW( hKey
, szStart
, 0, &type
, (LPBYTE
)&val
, &sz
);
1847 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_DWORD
) )
1848 lpServiceConfig
->dwStartType
= val
;
1851 r
= RegQueryValueExW( hKey
, szError
, 0, &type
, (LPBYTE
)&val
, &sz
);
1852 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_DWORD
) )
1853 lpServiceConfig
->dwErrorControl
= val
;
1855 /* now do the strings */
1856 p
= (LPBYTE
) &lpServiceConfig
[1];
1857 n
= 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
, (LPWSTR
) p
, n
);
1864 sz
*= sizeof(WCHAR
);
1865 if( 0 == sz
|| sz
> n
) return FALSE
;
1867 lpServiceConfig
->lpBinaryPathName
= (LPWSTR
) p
;
1873 /* FIXME: set last error */
1878 r
= RegQueryValueExW( hKey
, szGroup
, 0, &type
, p
, &sz
);
1879 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_SZ
) )
1881 lpServiceConfig
->lpLoadOrderGroup
= (LPWSTR
) p
;
1887 r
= RegQueryValueExW( hKey
, szDependencies
, 0, &type
, p
, &sz
);
1888 lpServiceConfig
->lpDependencies
= (LPWSTR
) p
;
1889 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_SZ
) )
1902 ERR("Buffer overflow!\n");
1904 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig
->lpBinaryPathName
) );
1905 TRACE("Group = %s\n", debugstr_w(lpServiceConfig
->lpLoadOrderGroup
) );
1910 /******************************************************************************
1911 * EnumServicesStatusA [ADVAPI32.@]
1914 EnumServicesStatusA( SC_HANDLE hSCManager
, DWORD dwServiceType
,
1915 DWORD dwServiceState
, LPENUM_SERVICE_STATUSA lpServices
,
1916 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
1917 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
)
1919 FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager
,
1920 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
1921 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
);
1922 SetLastError (ERROR_ACCESS_DENIED
);
1926 /******************************************************************************
1927 * EnumServicesStatusW [ADVAPI32.@]
1930 EnumServicesStatusW( SC_HANDLE hSCManager
, DWORD dwServiceType
,
1931 DWORD dwServiceState
, LPENUM_SERVICE_STATUSW lpServices
,
1932 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
1933 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
)
1935 FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager
,
1936 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
1937 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
);
1938 SetLastError (ERROR_ACCESS_DENIED
);
1942 /******************************************************************************
1943 * GetServiceKeyNameA [ADVAPI32.@]
1945 BOOL WINAPI
GetServiceKeyNameA( SC_HANDLE hSCManager
, LPCSTR lpDisplayName
,
1946 LPSTR lpServiceName
, LPDWORD lpcchBuffer
)
1948 FIXME("%p %s %p %p\n", hSCManager
, debugstr_a(lpDisplayName
), lpServiceName
, lpcchBuffer
);
1952 /******************************************************************************
1953 * GetServiceKeyNameW [ADVAPI32.@]
1955 BOOL WINAPI
GetServiceKeyNameW( SC_HANDLE hSCManager
, LPCWSTR lpDisplayName
,
1956 LPWSTR lpServiceName
, LPDWORD lpcchBuffer
)
1958 FIXME("%p %s %p %p\n", hSCManager
, debugstr_w(lpDisplayName
), lpServiceName
, lpcchBuffer
);
1962 /******************************************************************************
1963 * QueryServiceLockStatusA [ADVAPI32.@]
1965 BOOL WINAPI
QueryServiceLockStatusA( SC_HANDLE hSCManager
,
1966 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus
,
1967 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
1969 FIXME("%p %p %08lx %p\n", hSCManager
, lpLockStatus
, cbBufSize
, pcbBytesNeeded
);
1974 /******************************************************************************
1975 * QueryServiceLockStatusW [ADVAPI32.@]
1977 BOOL WINAPI
QueryServiceLockStatusW( SC_HANDLE hSCManager
,
1978 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus
,
1979 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
1981 FIXME("%p %p %08lx %p\n", hSCManager
, lpLockStatus
, cbBufSize
, pcbBytesNeeded
);
1986 /******************************************************************************
1987 * GetServiceDisplayNameA [ADVAPI32.@]
1989 BOOL WINAPI
GetServiceDisplayNameA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
1990 LPSTR lpDisplayName
, LPDWORD lpcchBuffer
)
1992 FIXME("%p %s %p %p\n", hSCManager
,
1993 debugstr_a(lpServiceName
), lpDisplayName
, lpcchBuffer
);
1997 /******************************************************************************
1998 * GetServiceDisplayNameW [ADVAPI32.@]
2000 BOOL WINAPI
GetServiceDisplayNameW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
2001 LPWSTR lpDisplayName
, LPDWORD lpcchBuffer
)
2003 FIXME("%p %s %p %p\n", hSCManager
,
2004 debugstr_w(lpServiceName
), lpDisplayName
, lpcchBuffer
);
2008 /******************************************************************************
2009 * ChangeServiceConfigW [ADVAPI32.@]
2011 BOOL WINAPI
ChangeServiceConfigW( SC_HANDLE hService
, DWORD dwServiceType
,
2012 DWORD dwStartType
, DWORD dwErrorControl
, LPCWSTR lpBinaryPathName
,
2013 LPCWSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
, LPCWSTR lpDependencies
,
2014 LPCWSTR lpServiceStartName
, LPCWSTR lpPassword
, LPCWSTR lpDisplayName
)
2016 struct reg_value val
[10];
2017 struct sc_service
*hsvc
;
2018 DWORD r
= ERROR_SUCCESS
;
2022 TRACE("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
2023 hService
, dwServiceType
, dwStartType
, dwErrorControl
,
2024 debugstr_w(lpBinaryPathName
), debugstr_w(lpLoadOrderGroup
),
2025 lpdwTagId
, lpDependencies
, debugstr_w(lpServiceStartName
),
2026 debugstr_w(lpPassword
), debugstr_w(lpDisplayName
) );
2028 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
2031 SetLastError( ERROR_INVALID_HANDLE
);
2036 if( dwServiceType
!= SERVICE_NO_CHANGE
)
2037 service_set_dword( &val
[n
++], szType
, &dwServiceType
);
2039 if( dwStartType
!= SERVICE_NO_CHANGE
)
2040 service_set_dword( &val
[n
++], szStart
, &dwStartType
);
2042 if( dwErrorControl
!= SERVICE_NO_CHANGE
)
2043 service_set_dword( &val
[n
++], szError
, &dwErrorControl
);
2045 if( lpBinaryPathName
)
2046 service_set_string( &val
[n
++], szImagePath
, lpBinaryPathName
);
2048 if( lpLoadOrderGroup
)
2049 service_set_string( &val
[n
++], szGroup
, lpLoadOrderGroup
);
2051 if( lpDependencies
)
2052 service_set_multi_string( &val
[n
++], szDependencies
, lpDependencies
);
2055 FIXME("ignoring password\n");
2057 if( lpServiceStartName
)
2058 service_set_string( &val
[n
++], szDependOnService
, lpServiceStartName
);
2060 r
= service_write_values( hsvc
->hkey
, val
, n
);
2062 return (r
== ERROR_SUCCESS
) ? TRUE
: FALSE
;
2065 /******************************************************************************
2066 * ChangeServiceConfigA [ADVAPI32.@]
2068 BOOL WINAPI
ChangeServiceConfigA( SC_HANDLE hService
, DWORD dwServiceType
,
2069 DWORD dwStartType
, DWORD dwErrorControl
, LPCSTR lpBinaryPathName
,
2070 LPCSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
, LPCSTR lpDependencies
,
2071 LPCSTR lpServiceStartName
, LPCSTR lpPassword
, LPCSTR lpDisplayName
)
2073 LPWSTR wBinaryPathName
, wLoadOrderGroup
, wDependencies
;
2074 LPWSTR wServiceStartName
, wPassword
, wDisplayName
;
2077 TRACE("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
2078 hService
, dwServiceType
, dwStartType
, dwErrorControl
,
2079 debugstr_a(lpBinaryPathName
), debugstr_a(lpLoadOrderGroup
),
2080 lpdwTagId
, lpDependencies
, debugstr_a(lpServiceStartName
),
2081 debugstr_a(lpPassword
), debugstr_a(lpDisplayName
) );
2083 wBinaryPathName
= SERV_dup( lpBinaryPathName
);
2084 wLoadOrderGroup
= SERV_dup( lpLoadOrderGroup
);
2085 wDependencies
= SERV_dupmulti( lpDependencies
);
2086 wServiceStartName
= SERV_dup( lpServiceStartName
);
2087 wPassword
= SERV_dup( lpPassword
);
2088 wDisplayName
= SERV_dup( lpDisplayName
);
2090 r
= ChangeServiceConfigW( hService
, dwServiceType
,
2091 dwStartType
, dwErrorControl
, wBinaryPathName
,
2092 wLoadOrderGroup
, lpdwTagId
, wDependencies
,
2093 wServiceStartName
, wPassword
, wDisplayName
);
2095 SERV_free( wBinaryPathName
);
2096 SERV_free( wLoadOrderGroup
);
2097 SERV_free( wDependencies
);
2098 SERV_free( wServiceStartName
);
2099 SERV_free( wPassword
);
2100 SERV_free( wDisplayName
);
2105 /******************************************************************************
2106 * ChangeServiceConfig2A [ADVAPI32.@]
2108 BOOL WINAPI
ChangeServiceConfig2A( SC_HANDLE hService
, DWORD dwInfoLevel
,
2113 TRACE("%p %ld %p\n",hService
, dwInfoLevel
, lpInfo
);
2115 if (dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
2117 LPSERVICE_DESCRIPTIONA sd
= (LPSERVICE_DESCRIPTIONA
) lpInfo
;
2118 SERVICE_DESCRIPTIONW sdw
;
2120 sdw
.lpDescription
= SERV_dup( sd
->lpDescription
);
2122 r
= ChangeServiceConfig2W( hService
, dwInfoLevel
, &sdw
);
2124 SERV_free( sdw
.lpDescription
);
2126 else if (dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
2128 LPSERVICE_FAILURE_ACTIONSA fa
= (LPSERVICE_FAILURE_ACTIONSA
) lpInfo
;
2129 SERVICE_FAILURE_ACTIONSW faw
;
2131 faw
.dwResetPeriod
= fa
->dwResetPeriod
;
2132 faw
.lpRebootMsg
= SERV_dup( fa
->lpRebootMsg
);
2133 faw
.lpCommand
= SERV_dup( fa
->lpCommand
);
2134 faw
.cActions
= fa
->cActions
;
2135 faw
.lpsaActions
= fa
->lpsaActions
;
2137 r
= ChangeServiceConfig2W( hService
, dwInfoLevel
, &faw
);
2139 SERV_free( faw
.lpRebootMsg
);
2140 SERV_free( faw
.lpCommand
);
2143 SetLastError( ERROR_INVALID_PARAMETER
);
2148 /******************************************************************************
2149 * ChangeServiceConfig2W [ADVAPI32.@]
2151 BOOL WINAPI
ChangeServiceConfig2W( SC_HANDLE hService
, DWORD dwInfoLevel
,
2155 struct sc_service
*hsvc
;
2157 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
2160 SetLastError( ERROR_INVALID_HANDLE
);
2165 if (dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
2167 static const WCHAR szDescription
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2168 LPSERVICE_DESCRIPTIONW sd
= (LPSERVICE_DESCRIPTIONW
)lpInfo
;
2169 if (sd
->lpDescription
)
2171 TRACE("Setting Description to %s\n",debugstr_w(sd
->lpDescription
));
2172 if (sd
->lpDescription
[0] == 0)
2173 RegDeleteValueW(hKey
,szDescription
);
2175 RegSetValueExW(hKey
, szDescription
, 0, REG_SZ
,
2176 (LPVOID
)sd
->lpDescription
,
2177 sizeof(WCHAR
)*(strlenW(sd
->lpDescription
)+1));
2181 FIXME("STUB: %p %ld %p\n",hService
, dwInfoLevel
, lpInfo
);
2185 /******************************************************************************
2186 * QueryServiceObjectSecurity [ADVAPI32.@]
2188 BOOL WINAPI
QueryServiceObjectSecurity(SC_HANDLE hService
,
2189 SECURITY_INFORMATION dwSecurityInformation
,
2190 PSECURITY_DESCRIPTOR lpSecurityDescriptor
,
2191 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
2195 FIXME("%p %ld %p %lu %p\n", hService
, dwSecurityInformation
,
2196 lpSecurityDescriptor
, cbBufSize
, pcbBytesNeeded
);
2198 InitializeSecurityDescriptor(lpSecurityDescriptor
, SECURITY_DESCRIPTOR_REVISION
);
2200 pACL
= HeapAlloc( GetProcessHeap(), 0, sizeof(ACL
) );
2201 InitializeAcl(pACL
, sizeof(ACL
), ACL_REVISION
);
2202 SetSecurityDescriptorDacl(lpSecurityDescriptor
, TRUE
, pACL
, TRUE
);
2206 /******************************************************************************
2207 * SetServiceObjectSecurity [ADVAPI32.@]
2209 BOOL WINAPI
SetServiceObjectSecurity(SC_HANDLE hService
,
2210 SECURITY_INFORMATION dwSecurityInformation
,
2211 PSECURITY_DESCRIPTOR lpSecurityDescriptor
)
2213 FIXME("%p %ld %p\n", hService
, dwSecurityInformation
, lpSecurityDescriptor
);
2217 /******************************************************************************
2218 * SetServiceBits [ADVAPI32.@]
2220 BOOL WINAPI
SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus
,
2221 DWORD dwServiceBits
,
2223 BOOL bUpdateImmediately
)
2225 FIXME("%08lx %08lx %x %x\n", hServiceStatus
, dwServiceBits
,
2226 bSetBitsOn
, bUpdateImmediately
);