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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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
;
61 LPHANDLER_FUNCTION handler
;
62 LPHANDLER_FUNCTION_EX handler_ex
;
65 SERVICE_STATUS status
;
68 BOOL extended
: 1; /* uses handler_ex instead of handler? */
70 LPSERVICE_MAIN_FUNCTIONA a
;
71 LPSERVICE_MAIN_FUNCTIONW w
;
77 static CRITICAL_SECTION service_cs
;
78 static CRITICAL_SECTION_DEBUG service_cs_debug
=
81 { &service_cs_debug
.ProcessLocksList
,
82 &service_cs_debug
.ProcessLocksList
},
83 0, 0, { (DWORD_PTR
)(__FILE__
": service_cs") }
85 static CRITICAL_SECTION service_cs
= { &service_cs_debug
, -1, 0, 0, 0, 0 };
87 static service_data
*service_list
;
89 /******************************************************************************
93 #define MAX_SERVICE_NAME 256
95 typedef enum { SC_HTYPE_MANAGER
, SC_HTYPE_SERVICE
} SC_HANDLE_TYPE
;
98 typedef VOID (*sc_handle_destructor
)(struct sc_handle
*);
102 SC_HANDLE_TYPE htype
;
104 sc_handle_destructor destroy
;
107 struct sc_manager
/* service control manager handle */
109 struct sc_handle hdr
;
110 HKEY hkey
; /* handle to services database in the registry */
113 struct sc_service
/* service handle */
115 struct sc_handle hdr
;
116 HKEY hkey
; /* handle to service entry in the registry (under hkey) */
117 struct sc_manager
*scm
; /* pointer to SCM handle */
121 static void *sc_handle_alloc(SC_HANDLE_TYPE htype
, DWORD size
,
122 sc_handle_destructor destroy
)
124 struct sc_handle
*hdr
;
126 hdr
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
131 hdr
->destroy
= destroy
;
133 TRACE("sc_handle type=%d -> %p\n", htype
, hdr
);
137 static void *sc_handle_get_handle_data(SC_HANDLE handle
, DWORD htype
)
139 struct sc_handle
*hdr
= (struct sc_handle
*) handle
;
143 if (hdr
->htype
!= htype
)
148 static void sc_handle_free(struct sc_handle
* hdr
)
152 if (--hdr
->ref_count
)
155 HeapFree(GetProcessHeap(), 0, hdr
);
158 static void sc_handle_destroy_manager(struct sc_handle
*handle
)
160 struct sc_manager
*mgr
= (struct sc_manager
*) handle
;
162 TRACE("destroying SC Manager %p\n", mgr
);
164 RegCloseKey(mgr
->hkey
);
167 static void sc_handle_destroy_service(struct sc_handle
*handle
)
169 struct sc_service
*svc
= (struct sc_service
*) handle
;
171 TRACE("destroying service %p\n", svc
);
173 RegCloseKey(svc
->hkey
);
175 sc_handle_free(&svc
->scm
->hdr
);
179 /******************************************************************************
180 * String management functions
182 static inline LPWSTR
SERV_dup( LPCSTR str
)
189 len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
190 wstr
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof (WCHAR
) );
191 MultiByteToWideChar( CP_ACP
, 0, str
, -1, wstr
, len
);
195 static inline LPWSTR
SERV_dupmulti(LPCSTR str
)
203 len
+= MultiByteToWideChar( CP_ACP
, 0, &str
[n
], -1, NULL
, 0 );
204 n
+= (strlen( &str
[n
] ) + 1);
209 wstr
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof (WCHAR
) );
210 MultiByteToWideChar( CP_ACP
, 0, str
, n
, wstr
, len
);
214 static inline VOID
SERV_free( LPWSTR wstr
)
216 HeapFree( GetProcessHeap(), 0, wstr
);
219 /******************************************************************************
220 * registry access functions and data
222 static const WCHAR szDisplayName
[] = {
223 'D','i','s','p','l','a','y','N','a','m','e', 0 };
224 static const WCHAR szType
[] = {'T','y','p','e',0};
225 static const WCHAR szStart
[] = {'S','t','a','r','t',0};
226 static const WCHAR szError
[] = {
227 'E','r','r','o','r','C','o','n','t','r','o','l', 0};
228 static const WCHAR szImagePath
[] = {'I','m','a','g','e','P','a','t','h',0};
229 static const WCHAR szGroup
[] = {'G','r','o','u','p',0};
230 static const WCHAR szDependencies
[] = {
231 'D','e','p','e','n','d','e','n','c','i','e','s',0};
232 static const WCHAR szDependOnService
[] = {
233 'D','e','p','e','n','d','O','n','S','e','r','v','i','c','e',0};
242 static inline void service_set_value( struct reg_value
*val
,
243 DWORD type
, LPCWSTR name
, LPCVOID data
, DWORD size
)
251 static inline void service_set_dword( struct reg_value
*val
,
252 LPCWSTR name
, DWORD
*data
)
254 service_set_value( val
, REG_DWORD
, name
, data
, sizeof (DWORD
));
257 static inline void service_set_string( struct reg_value
*val
,
258 LPCWSTR name
, LPCWSTR string
)
260 DWORD len
= (lstrlenW(string
)+1) * sizeof (WCHAR
);
261 service_set_value( val
, REG_SZ
, name
, string
, len
);
264 static inline void service_set_multi_string( struct reg_value
*val
,
265 LPCWSTR name
, LPCWSTR string
)
269 /* determine the length of a double null terminated multi string */
271 len
+= (lstrlenW( &string
[ len
] )+1);
272 } while ( string
[ len
++ ] );
274 len
*= sizeof (WCHAR
);
275 service_set_value( val
, REG_MULTI_SZ
, name
, string
, len
);
278 static inline LONG
service_write_values( HKEY hKey
,
279 struct reg_value
*val
, int n
)
281 LONG r
= ERROR_SUCCESS
;
286 r
= RegSetValueExW(hKey
, val
[i
].name
, 0, val
[i
].type
,
287 (const BYTE
*)val
[i
].data
, val
[i
].size
);
288 if( r
!= ERROR_SUCCESS
)
294 /******************************************************************************
295 * Service IPC functions
297 static LPWSTR
service_get_pipe_name(LPWSTR service
)
299 static const WCHAR prefix
[] = { '\\','\\','.','\\','p','i','p','e','\\',
300 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
304 len
= sizeof prefix
+ strlenW(service
)*sizeof(WCHAR
);
305 name
= HeapAlloc(GetProcessHeap(), 0, len
);
306 strcpyW(name
, prefix
);
307 strcatW(name
, service
);
311 static HANDLE
service_open_pipe(LPWSTR service
)
313 LPWSTR szPipe
= service_get_pipe_name( service
);
314 HANDLE handle
= INVALID_HANDLE_VALUE
;
317 handle
= CreateFileW(szPipe
, GENERIC_READ
|GENERIC_WRITE
,
318 0, NULL
, OPEN_ALWAYS
, 0, NULL
);
319 if (handle
!= INVALID_HANDLE_VALUE
)
321 if (GetLastError() != ERROR_PIPE_BUSY
)
323 } while (WaitNamedPipeW(szPipe
, NMPWAIT_WAIT_FOREVER
));
329 /******************************************************************************
330 * service_get_event_handle
332 static HANDLE
service_get_event_handle(LPWSTR service
)
334 static const WCHAR prefix
[] = {
335 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
340 len
= sizeof prefix
+ strlenW(service
)*sizeof(WCHAR
);
341 name
= HeapAlloc(GetProcessHeap(), 0, len
);
342 strcpyW(name
, prefix
);
343 strcatW(name
, service
);
344 handle
= CreateEventW(NULL
, TRUE
, FALSE
, name
);
349 /******************************************************************************
352 * Call into the main service routine provided by StartServiceCtrlDispatcher.
354 static DWORD WINAPI
service_thread(LPVOID arg
)
356 service_data
*info
= arg
;
357 LPWSTR str
= info
->args
;
358 DWORD argc
= 0, len
= 0;
364 len
+= strlenW(&str
[len
]) + 1;
371 info
->proc
.w(0, NULL
);
373 info
->proc
.a(0, NULL
);
381 argv
= HeapAlloc(GetProcessHeap(), 0, (argc
+1)*sizeof(LPWSTR
));
382 for (argc
=0, p
=str
; *p
; p
+= strlenW(p
) + 1)
386 info
->proc
.w(argc
, argv
);
387 HeapFree(GetProcessHeap(), 0, argv
);
391 LPSTR strA
, *argv
, p
;
394 lenA
= WideCharToMultiByte(CP_ACP
,0, str
, len
, NULL
, 0, NULL
, NULL
);
395 strA
= HeapAlloc(GetProcessHeap(), 0, lenA
);
396 WideCharToMultiByte(CP_ACP
,0, str
, len
, strA
, lenA
, NULL
, NULL
);
398 argv
= HeapAlloc(GetProcessHeap(), 0, (argc
+1)*sizeof(LPSTR
));
399 for (argc
=0, p
=strA
; *p
; p
+= strlen(p
) + 1)
403 info
->proc
.a(argc
, argv
);
404 HeapFree(GetProcessHeap(), 0, argv
);
405 HeapFree(GetProcessHeap(), 0, strA
);
410 /******************************************************************************
411 * service_handle_start
413 static BOOL
service_handle_start(HANDLE pipe
, service_data
*service
, DWORD count
)
415 DWORD read
= 0, result
= 0;
419 TRACE("%p %p %d\n", pipe
, service
, count
);
421 args
= HeapAlloc(GetProcessHeap(), 0, count
*sizeof(WCHAR
));
422 r
= ReadFile(pipe
, args
, count
*sizeof(WCHAR
), &read
, NULL
);
423 if (!r
|| count
!=read
/sizeof(WCHAR
) || args
[count
-1])
425 ERR("pipe read failed r = %d count = %d read = %d args[n-1]=%s\n",
426 r
, count
, read
, debugstr_wn(args
, count
));
432 ERR("service is not stopped\n");
436 SERV_free(service
->args
);
437 service
->args
= args
;
439 service
->thread
= CreateThread( NULL
, 0, service_thread
,
443 HeapFree(GetProcessHeap(), 0, args
);
444 WriteFile( pipe
, &result
, sizeof result
, &read
, NULL
);
449 /******************************************************************************
450 * service_send_start_message
452 static BOOL
service_send_start_message(HANDLE pipe
, LPCWSTR
*argv
, DWORD argc
)
454 DWORD i
, len
, count
, result
;
455 service_start_info
*ssi
;
459 TRACE("%p %p %d\n", pipe
, argv
, argc
);
461 /* calculate how much space do we need to send the startup info */
463 for (i
=0; i
<argc
; i
++)
464 len
+= strlenW(argv
[i
])+1;
466 ssi
= HeapAlloc(GetProcessHeap(),0,sizeof *ssi
+ (len
-1)*sizeof(WCHAR
));
467 ssi
->cmd
= WINESERV_STARTINFO
;
470 /* copy service args into a single buffer*/
472 for (i
=0; i
<argc
; i
++)
479 r
= WriteFile(pipe
, ssi
, sizeof *ssi
+ len
*sizeof(WCHAR
), &count
, NULL
);
481 r
= ReadFile(pipe
, &result
, sizeof result
, &count
, NULL
);
483 HeapFree(GetProcessHeap(),0,ssi
);
488 /******************************************************************************
489 * service_handle_get_status
491 static BOOL
service_handle_get_status(HANDLE pipe
, service_data
*service
)
495 return WriteFile(pipe
, &service
->status
,
496 sizeof service
->status
, &count
, NULL
);
499 /******************************************************************************
502 static BOOL
service_get_status(HANDLE pipe
, LPSERVICE_STATUS status
)
504 DWORD cmd
[2], count
= 0;
507 cmd
[0] = WINESERV_GETSTATUS
;
509 r
= WriteFile( pipe
, cmd
, sizeof cmd
, &count
, NULL
);
510 if (!r
|| count
!= sizeof cmd
)
512 ERR("service protocol error - failed to write pipe!\n");
515 r
= ReadFile( pipe
, status
, sizeof *status
, &count
, NULL
);
516 if (!r
|| count
!= sizeof *status
)
517 ERR("service protocol error - failed to read pipe "
518 "r = %d count = %d!\n", r
, count
);
522 /******************************************************************************
523 * service_send_control
525 static BOOL
service_send_control(HANDLE pipe
, DWORD dwControl
, DWORD
*result
)
527 DWORD cmd
[2], count
= 0;
530 cmd
[0] = WINESERV_SENDCONTROL
;
532 r
= WriteFile(pipe
, cmd
, sizeof cmd
, &count
, NULL
);
533 if (!r
|| count
!= sizeof cmd
)
535 ERR("service protocol error - failed to write pipe!\n");
538 r
= ReadFile(pipe
, result
, sizeof *result
, &count
, NULL
);
539 if (!r
|| count
!= sizeof *result
)
540 ERR("service protocol error - failed to read pipe "
541 "r = %d count = %d!\n", r
, count
);
545 /******************************************************************************
546 * service_accepts_control
548 static BOOL
service_accepts_control(service_data
*service
, DWORD dwControl
)
550 DWORD a
= service
->status
.dwControlsAccepted
;
554 case SERVICE_CONTROL_INTERROGATE
:
556 case SERVICE_CONTROL_STOP
:
557 if (a
&SERVICE_ACCEPT_STOP
)
560 case SERVICE_CONTROL_SHUTDOWN
:
561 if (a
&SERVICE_ACCEPT_SHUTDOWN
)
564 case SERVICE_CONTROL_PAUSE
:
565 case SERVICE_CONTROL_CONTINUE
:
566 if (a
&SERVICE_ACCEPT_PAUSE_CONTINUE
)
569 case SERVICE_CONTROL_PARAMCHANGE
:
570 if (a
&SERVICE_ACCEPT_PARAMCHANGE
)
573 case SERVICE_CONTROL_NETBINDADD
:
574 case SERVICE_CONTROL_NETBINDREMOVE
:
575 case SERVICE_CONTROL_NETBINDENABLE
:
576 case SERVICE_CONTROL_NETBINDDISABLE
:
577 if (a
&SERVICE_ACCEPT_NETBINDCHANGE
)
580 if (!service
->extended
)
584 case SERVICE_CONTROL_HARDWAREPROFILECHANGE
:
585 if (a
&SERVICE_ACCEPT_HARDWAREPROFILECHANGE
)
588 case SERVICE_CONTROL_POWEREVENT
:
589 if (a
&SERVICE_ACCEPT_POWEREVENT
)
592 case SERVICE_CONTROL_SESSIONCHANGE
:
593 if (a
&SERVICE_ACCEPT_SESSIONCHANGE
)
600 /******************************************************************************
601 * service_handle_control
603 static BOOL
service_handle_control(HANDLE pipe
, service_data
*service
,
606 DWORD count
, ret
= ERROR_INVALID_SERVICE_CONTROL
;
608 TRACE("received control %d\n", dwControl
);
610 if (service_accepts_control(service
, dwControl
))
612 if (service
->extended
&& service
->handler
.handler_ex
)
614 service
->handler
.handler_ex(dwControl
, 0, NULL
, service
->context
);
617 else if (service
->handler
.handler
)
619 service
->handler
.handler(dwControl
);
623 return WriteFile(pipe
, &ret
, sizeof ret
, &count
, NULL
);
626 /******************************************************************************
627 * service_reap_thread
629 static DWORD
service_reap_thread(service_data
*service
)
633 if (!service
->thread
)
635 GetExitCodeThread(service
->thread
, &exitcode
);
636 if (exitcode
!=STILL_ACTIVE
)
638 CloseHandle(service
->thread
);
644 /******************************************************************************
645 * service_control_dispatcher
647 static DWORD WINAPI
service_control_dispatcher(LPVOID arg
)
649 service_data
*service
= arg
;
653 TRACE("%p %s\n", service
, debugstr_w(service
->name
));
655 /* create a pipe to talk to the rest of the world with */
656 name
= service_get_pipe_name(service
->name
);
657 pipe
= CreateNamedPipeW(name
, PIPE_ACCESS_DUPLEX
,
658 PIPE_TYPE_BYTE
|PIPE_WAIT
, 1, 256, 256, 10000, NULL
);
661 /* let the process who started us know we've tried to create a pipe */
662 event
= service_get_event_handle(service
->name
);
666 if (pipe
==INVALID_HANDLE_VALUE
)
668 ERR("failed to create pipe for %s, error = %d\n",
669 debugstr_w(service
->name
), GetLastError());
673 /* dispatcher loop */
677 DWORD count
, req
[2] = {0,0};
679 r
= ConnectNamedPipe(pipe
, NULL
);
680 if (!r
&& GetLastError() != ERROR_PIPE_CONNECTED
)
682 ERR("pipe connect failed\n");
686 r
= ReadFile( pipe
, &req
, sizeof req
, &count
, NULL
);
687 if (!r
|| count
!=sizeof req
)
689 ERR("pipe read failed\n");
693 service_reap_thread(service
);
695 /* handle the request */
698 case WINESERV_STARTINFO
:
699 service_handle_start(pipe
, service
, req
[1]);
701 case WINESERV_GETSTATUS
:
702 service_handle_get_status(pipe
, service
);
704 case WINESERV_SENDCONTROL
:
705 service_handle_control(pipe
, service
, req
[1]);
708 ERR("received invalid command %d length %d\n", req
[0], req
[1]);
711 FlushFileBuffers(pipe
);
712 DisconnectNamedPipe(pipe
);
719 /******************************************************************************
720 * service_run_threads
722 static BOOL
service_run_threads(void)
724 service_data
*service
;
725 DWORD count
= 0, n
= 0;
728 EnterCriticalSection( &service_cs
);
730 /* count how many services there are */
731 for (service
= service_list
; service
; service
= service
->next
)
734 TRACE("starting %d pipe listener threads\n", count
);
736 handles
= HeapAlloc(GetProcessHeap(), 0, sizeof(HANDLE
)*count
);
738 for (n
=0, service
= service_list
; service
; service
= service
->next
, n
++)
739 handles
[n
] = CreateThread( NULL
, 0, service_control_dispatcher
,
743 LeaveCriticalSection( &service_cs
);
745 /* wait for all the threads to pack up and exit */
746 WaitForMultipleObjectsEx(count
, handles
, TRUE
, INFINITE
, FALSE
);
748 HeapFree(GetProcessHeap(), 0, handles
);
753 /******************************************************************************
754 * StartServiceCtrlDispatcherA [ADVAPI32.@]
756 * See StartServiceCtrlDispatcherW.
758 BOOL WINAPI
StartServiceCtrlDispatcherA( LPSERVICE_TABLE_ENTRYA servent
)
764 TRACE("%p\n", servent
);
766 EnterCriticalSection( &service_cs
);
767 while (servent
->lpServiceName
)
769 LPSTR name
= servent
->lpServiceName
;
771 len
= MultiByteToWideChar(CP_ACP
, 0, name
, -1, NULL
, 0);
772 sz
= len
*sizeof(WCHAR
) + sizeof *info
;
773 info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sz
);
774 MultiByteToWideChar(CP_ACP
, 0, name
, -1, info
->name
, len
);
775 info
->proc
.a
= servent
->lpServiceProc
;
776 info
->unicode
= FALSE
;
778 /* insert into the list */
779 info
->next
= service_list
;
784 LeaveCriticalSection( &service_cs
);
786 service_run_threads();
791 /******************************************************************************
792 * StartServiceCtrlDispatcherW [ADVAPI32.@]
794 * Connects a process containing one or more services to the service control
798 * servent [I] A list of the service names and service procedures
804 BOOL WINAPI
StartServiceCtrlDispatcherW( LPSERVICE_TABLE_ENTRYW servent
)
810 TRACE("%p\n", servent
);
812 EnterCriticalSection( &service_cs
);
813 while (servent
->lpServiceName
)
815 LPWSTR name
= servent
->lpServiceName
;
818 sz
= len
*sizeof(WCHAR
) + sizeof *info
;
819 info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sz
);
820 strcpyW(info
->name
, name
);
821 info
->proc
.w
= servent
->lpServiceProc
;
822 info
->unicode
= TRUE
;
824 /* insert into the list */
825 info
->next
= service_list
;
830 LeaveCriticalSection( &service_cs
);
832 service_run_threads();
837 /******************************************************************************
838 * LockServiceDatabase [ADVAPI32.@]
840 SC_LOCK WINAPI
LockServiceDatabase (SC_HANDLE hSCManager
)
844 TRACE("%p\n",hSCManager
);
846 ret
= CreateSemaphoreW( NULL
, 1, 1, szSCMLock
);
847 if( ret
&& GetLastError() == ERROR_ALREADY_EXISTS
)
851 SetLastError( ERROR_SERVICE_DATABASE_LOCKED
);
854 TRACE("returning %p\n", ret
);
859 /******************************************************************************
860 * UnlockServiceDatabase [ADVAPI32.@]
862 BOOL WINAPI
UnlockServiceDatabase (SC_LOCK ScLock
)
864 TRACE("%p\n",ScLock
);
866 return CloseHandle( ScLock
);
869 /******************************************************************************
870 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
872 SERVICE_STATUS_HANDLE WINAPI
873 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName
, LPHANDLER_FUNCTION lpfHandler
)
875 LPWSTR lpServiceNameW
;
876 SERVICE_STATUS_HANDLE ret
;
878 lpServiceNameW
= SERV_dup(lpServiceName
);
879 ret
= RegisterServiceCtrlHandlerW( lpServiceNameW
, lpfHandler
);
880 SERV_free(lpServiceNameW
);
884 /******************************************************************************
885 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
891 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName
,
892 LPHANDLER_FUNCTION lpfHandler
)
894 service_data
*service
;
896 EnterCriticalSection( &service_cs
);
897 for(service
= service_list
; service
; service
= service
->next
)
898 if(!strcmpW(lpServiceName
, service
->name
))
901 service
->handler
.handler
= lpfHandler
;
902 LeaveCriticalSection( &service_cs
);
904 return (SERVICE_STATUS_HANDLE
)service
;
907 /******************************************************************************
908 * SetServiceStatus [ADVAPI32.@]
915 SetServiceStatus( SERVICE_STATUS_HANDLE hService
, LPSERVICE_STATUS lpStatus
)
917 service_data
*service
;
920 TRACE("%p %x %x %x %x %x %x %x\n", hService
,
921 lpStatus
->dwServiceType
, lpStatus
->dwCurrentState
,
922 lpStatus
->dwControlsAccepted
, lpStatus
->dwWin32ExitCode
,
923 lpStatus
->dwServiceSpecificExitCode
, lpStatus
->dwCheckPoint
,
924 lpStatus
->dwWaitHint
);
926 EnterCriticalSection( &service_cs
);
927 for (service
= service_list
; service
; service
= service
->next
)
928 if(service
== (service_data
*)hService
)
932 memcpy( &service
->status
, lpStatus
, sizeof(SERVICE_STATUS
) );
933 TRACE("Set service status to %d\n",service
->status
.dwCurrentState
);
937 LeaveCriticalSection( &service_cs
);
943 /******************************************************************************
944 * OpenSCManagerA [ADVAPI32.@]
946 * Establish a connection to the service control manager and open its database.
949 * lpMachineName [I] Pointer to machine name string
950 * lpDatabaseName [I] Pointer to database name string
951 * dwDesiredAccess [I] Type of access
954 * Success: A Handle to the service control manager database
957 SC_HANDLE WINAPI
OpenSCManagerA( LPCSTR lpMachineName
, LPCSTR lpDatabaseName
,
958 DWORD dwDesiredAccess
)
960 LPWSTR lpMachineNameW
, lpDatabaseNameW
;
963 lpMachineNameW
= SERV_dup(lpMachineName
);
964 lpDatabaseNameW
= SERV_dup(lpDatabaseName
);
965 ret
= OpenSCManagerW(lpMachineNameW
, lpDatabaseNameW
, dwDesiredAccess
);
966 SERV_free(lpDatabaseNameW
);
967 SERV_free(lpMachineNameW
);
971 /******************************************************************************
972 * OpenSCManagerW [ADVAPI32.@]
974 * See OpenSCManagerA.
976 SC_HANDLE WINAPI
OpenSCManagerW( LPCWSTR lpMachineName
, LPCWSTR lpDatabaseName
,
977 DWORD dwDesiredAccess
)
979 struct sc_manager
*manager
;
983 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName
),
984 debugstr_w(lpDatabaseName
), dwDesiredAccess
);
986 if( lpDatabaseName
&& lpDatabaseName
[0] )
988 if( strcmpiW( lpDatabaseName
, SERVICES_ACTIVE_DATABASEW
) == 0 )
990 /* noop, all right */
992 else if( strcmpiW( lpDatabaseName
, SERVICES_FAILED_DATABASEW
) == 0 )
994 SetLastError( ERROR_DATABASE_DOES_NOT_EXIST
);
999 SetLastError( ERROR_INVALID_NAME
);
1004 manager
= sc_handle_alloc( SC_HTYPE_MANAGER
, sizeof (struct sc_manager
),
1005 sc_handle_destroy_manager
);
1009 r
= RegConnectRegistryW(lpMachineName
,HKEY_LOCAL_MACHINE
,&hReg
);
1010 if (r
!=ERROR_SUCCESS
)
1013 r
= RegOpenKeyExW(hReg
, szServiceManagerKey
,
1014 0, KEY_ALL_ACCESS
, &manager
->hkey
);
1015 RegCloseKey( hReg
);
1016 if (r
!=ERROR_SUCCESS
)
1019 TRACE("returning %p\n", manager
);
1021 return (SC_HANDLE
) &manager
->hdr
;
1024 sc_handle_free( &manager
->hdr
);
1029 /******************************************************************************
1030 * ControlService [ADVAPI32.@]
1032 * Send a control code to a service.
1035 * hService [I] Handle of the service control manager database
1036 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
1037 * lpServiceStatus [O] Destination for the status of the service, if available
1044 * Unlike M$' implementation, control requests are not serialized and may be
1045 * processed asynchronously.
1047 BOOL WINAPI
ControlService( SC_HANDLE hService
, DWORD dwControl
,
1048 LPSERVICE_STATUS lpServiceStatus
)
1050 struct sc_service
*hsvc
;
1054 TRACE("%p %d %p\n", hService
, dwControl
, lpServiceStatus
);
1056 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1059 SetLastError( ERROR_INVALID_HANDLE
);
1063 ret
= QueryServiceStatus(hService
, lpServiceStatus
);
1066 ERR("failed to query service status\n");
1067 SetLastError(ERROR_SERVICE_NOT_ACTIVE
);
1071 switch (lpServiceStatus
->dwCurrentState
)
1073 case SERVICE_STOPPED
:
1074 SetLastError(ERROR_SERVICE_NOT_ACTIVE
);
1076 case SERVICE_START_PENDING
:
1077 if (dwControl
==SERVICE_CONTROL_STOP
)
1080 case SERVICE_STOP_PENDING
:
1081 SetLastError(ERROR_SERVICE_CANNOT_ACCEPT_CTRL
);
1085 handle
= service_open_pipe(hsvc
->name
);
1086 if (handle
!=INVALID_HANDLE_VALUE
)
1088 DWORD result
= ERROR_SUCCESS
;
1089 ret
= service_send_control(handle
, dwControl
, &result
);
1090 CloseHandle(handle
);
1091 if (result
!=ERROR_SUCCESS
)
1093 SetLastError(result
);
1101 /******************************************************************************
1102 * CloseServiceHandle [ADVAPI32.@]
1104 * Close a handle to a service or the service control manager database.
1107 * hSCObject [I] Handle to service or service control manager database
1114 CloseServiceHandle( SC_HANDLE hSCObject
)
1116 TRACE("%p\n", hSCObject
);
1118 sc_handle_free( (struct sc_handle
*) hSCObject
);
1124 /******************************************************************************
1125 * OpenServiceA [ADVAPI32.@]
1127 * Open a handle to a service.
1130 * hSCManager [I] Handle of the service control manager database
1131 * lpServiceName [I] Name of the service to open
1132 * dwDesiredAccess [I] Access required to the service
1135 * Success: Handle to the service
1138 SC_HANDLE WINAPI
OpenServiceA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
1139 DWORD dwDesiredAccess
)
1141 LPWSTR lpServiceNameW
;
1144 TRACE("%p %s %d\n", hSCManager
, debugstr_a(lpServiceName
), dwDesiredAccess
);
1146 lpServiceNameW
= SERV_dup(lpServiceName
);
1147 ret
= OpenServiceW( hSCManager
, lpServiceNameW
, dwDesiredAccess
);
1148 SERV_free(lpServiceNameW
);
1153 /******************************************************************************
1154 * OpenServiceW [ADVAPI32.@]
1158 SC_HANDLE WINAPI
OpenServiceW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
1159 DWORD dwDesiredAccess
)
1161 struct sc_manager
*hscm
;
1162 struct sc_service
*hsvc
;
1167 TRACE("%p %s %d\n", hSCManager
, debugstr_w(lpServiceName
), dwDesiredAccess
);
1171 SetLastError(ERROR_INVALID_ADDRESS
);
1175 hscm
= sc_handle_get_handle_data( hSCManager
, SC_HTYPE_MANAGER
);
1178 SetLastError( ERROR_INVALID_HANDLE
);
1182 r
= RegOpenKeyExW( hscm
->hkey
, lpServiceName
, 0, KEY_ALL_ACCESS
, &hKey
);
1183 if (r
!=ERROR_SUCCESS
)
1185 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST
);
1189 len
= strlenW(lpServiceName
)+1;
1190 hsvc
= sc_handle_alloc( SC_HTYPE_SERVICE
,
1191 sizeof (struct sc_service
) + len
*sizeof(WCHAR
),
1192 sc_handle_destroy_service
);
1195 strcpyW( hsvc
->name
, lpServiceName
);
1198 /* add reference to SCM handle */
1199 hscm
->hdr
.ref_count
++;
1202 TRACE("returning %p\n",hsvc
);
1204 return (SC_HANDLE
) &hsvc
->hdr
;
1207 /******************************************************************************
1208 * CreateServiceW [ADVAPI32.@]
1211 CreateServiceW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
1212 LPCWSTR lpDisplayName
, DWORD dwDesiredAccess
,
1213 DWORD dwServiceType
, DWORD dwStartType
,
1214 DWORD dwErrorControl
, LPCWSTR lpBinaryPathName
,
1215 LPCWSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
,
1216 LPCWSTR lpDependencies
, LPCWSTR lpServiceStartName
,
1217 LPCWSTR lpPassword
)
1219 struct sc_manager
*hscm
;
1220 struct sc_service
*hsvc
= NULL
;
1224 struct reg_value val
[10];
1227 TRACE("%p %s %s\n", hSCManager
,
1228 debugstr_w(lpServiceName
), debugstr_w(lpDisplayName
));
1230 hscm
= sc_handle_get_handle_data( hSCManager
, SC_HTYPE_MANAGER
);
1233 SetLastError( ERROR_INVALID_HANDLE
);
1237 r
= RegCreateKeyExW(hscm
->hkey
, lpServiceName
, 0, NULL
,
1238 REG_OPTION_NON_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &hKey
, &dp
);
1239 if (r
!=ERROR_SUCCESS
)
1242 if (dp
!= REG_CREATED_NEW_KEY
)
1244 SetLastError(ERROR_SERVICE_EXISTS
);
1249 service_set_string( &val
[n
++], szDisplayName
, lpDisplayName
);
1251 service_set_dword( &val
[n
++], szType
, &dwServiceType
);
1252 service_set_dword( &val
[n
++], szStart
, &dwStartType
);
1253 service_set_dword( &val
[n
++], szError
, &dwErrorControl
);
1255 if( lpBinaryPathName
)
1256 service_set_string( &val
[n
++], szImagePath
, lpBinaryPathName
);
1258 if( lpLoadOrderGroup
)
1259 service_set_string( &val
[n
++], szGroup
, lpLoadOrderGroup
);
1261 if( lpDependencies
)
1262 service_set_multi_string( &val
[n
++], szDependencies
, lpDependencies
);
1265 FIXME("Don't know how to add a Password for a service.\n");
1267 if( lpServiceStartName
)
1268 service_set_string( &val
[n
++], szDependOnService
, lpServiceStartName
);
1270 r
= service_write_values( hKey
, val
, n
);
1271 if( r
!= ERROR_SUCCESS
)
1274 len
= strlenW(lpServiceName
)+1;
1275 len
= sizeof (struct sc_service
) + len
*sizeof(WCHAR
);
1276 hsvc
= sc_handle_alloc( SC_HTYPE_SERVICE
, len
, sc_handle_destroy_service
);
1279 lstrcpyW( hsvc
->name
, lpServiceName
);
1282 hscm
->hdr
.ref_count
++;
1284 return (SC_HANDLE
) &hsvc
->hdr
;
1287 RegCloseKey( hKey
);
1292 /******************************************************************************
1293 * CreateServiceA [ADVAPI32.@]
1296 CreateServiceA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
1297 LPCSTR lpDisplayName
, DWORD dwDesiredAccess
,
1298 DWORD dwServiceType
, DWORD dwStartType
,
1299 DWORD dwErrorControl
, LPCSTR lpBinaryPathName
,
1300 LPCSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
,
1301 LPCSTR lpDependencies
, LPCSTR lpServiceStartName
,
1304 LPWSTR lpServiceNameW
, lpDisplayNameW
, lpBinaryPathNameW
,
1305 lpLoadOrderGroupW
, lpDependenciesW
, lpServiceStartNameW
, lpPasswordW
;
1308 TRACE("%p %s %s\n", hSCManager
,
1309 debugstr_a(lpServiceName
), debugstr_a(lpDisplayName
));
1311 lpServiceNameW
= SERV_dup( lpServiceName
);
1312 lpDisplayNameW
= SERV_dup( lpDisplayName
);
1313 lpBinaryPathNameW
= SERV_dup( lpBinaryPathName
);
1314 lpLoadOrderGroupW
= SERV_dup( lpLoadOrderGroup
);
1315 lpDependenciesW
= SERV_dupmulti( lpDependencies
);
1316 lpServiceStartNameW
= SERV_dup( lpServiceStartName
);
1317 lpPasswordW
= SERV_dup( lpPassword
);
1319 r
= CreateServiceW( hSCManager
, lpServiceNameW
, lpDisplayNameW
,
1320 dwDesiredAccess
, dwServiceType
, dwStartType
, dwErrorControl
,
1321 lpBinaryPathNameW
, lpLoadOrderGroupW
, lpdwTagId
,
1322 lpDependenciesW
, lpServiceStartNameW
, lpPasswordW
);
1324 SERV_free( lpServiceNameW
);
1325 SERV_free( lpDisplayNameW
);
1326 SERV_free( lpBinaryPathNameW
);
1327 SERV_free( lpLoadOrderGroupW
);
1328 SERV_free( lpDependenciesW
);
1329 SERV_free( lpServiceStartNameW
);
1330 SERV_free( lpPasswordW
);
1336 /******************************************************************************
1337 * DeleteService [ADVAPI32.@]
1339 * Delete a service from the service control manager database.
1342 * hService [I] Handle of the service to delete
1348 BOOL WINAPI
DeleteService( SC_HANDLE hService
)
1350 struct sc_service
*hsvc
;
1352 WCHAR valname
[MAX_PATH
+1];
1357 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1360 SetLastError( ERROR_INVALID_HANDLE
);
1366 /* Clean out the values */
1367 rc
= RegEnumValueW(hKey
, index
, valname
,&size
,0,0,0,0);
1368 while (rc
== ERROR_SUCCESS
)
1370 RegDeleteValueW(hKey
,valname
);
1373 rc
= RegEnumValueW(hKey
, index
, valname
, &size
,0,0,0,0);
1379 /* delete the key */
1380 RegDeleteKeyW(hsvc
->scm
->hkey
, hsvc
->name
);
1386 /******************************************************************************
1387 * StartServiceA [ADVAPI32.@]
1392 * hService [I] Handle of service
1393 * dwNumServiceArgs [I] Number of arguments
1394 * lpServiceArgVectors [I] Address of array of argument strings
1397 * - NT implements this function using an obscure RPC call.
1398 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1399 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1400 * - This will only work for shared address space. How should the service
1401 * args be transferred when address spaces are separated?
1402 * - Can only start one service at a time.
1403 * - Has no concept of privilege.
1409 BOOL WINAPI
StartServiceA( SC_HANDLE hService
, DWORD dwNumServiceArgs
,
1410 LPCSTR
*lpServiceArgVectors
)
1412 LPWSTR
*lpwstr
=NULL
;
1416 TRACE("(%p,%d,%p)\n",hService
,dwNumServiceArgs
,lpServiceArgVectors
);
1418 if (dwNumServiceArgs
)
1419 lpwstr
= HeapAlloc( GetProcessHeap(), 0,
1420 dwNumServiceArgs
*sizeof(LPWSTR
) );
1422 for(i
=0; i
<dwNumServiceArgs
; i
++)
1423 lpwstr
[i
]=SERV_dup(lpServiceArgVectors
[i
]);
1425 r
= StartServiceW(hService
, dwNumServiceArgs
, (LPCWSTR
*)lpwstr
);
1427 if (dwNumServiceArgs
)
1429 for(i
=0; i
<dwNumServiceArgs
; i
++)
1430 SERV_free(lpwstr
[i
]);
1431 HeapFree(GetProcessHeap(), 0, lpwstr
);
1437 /******************************************************************************
1438 * service_start_process [INTERNAL]
1440 static DWORD
service_start_process(struct sc_service
*hsvc
)
1442 static const WCHAR _ImagePathW
[] = {'I','m','a','g','e','P','a','t','h',0};
1443 PROCESS_INFORMATION pi
;
1445 LPWSTR path
= NULL
, str
;
1446 DWORD type
, size
, ret
;
1450 /* read the executable path from memory */
1452 ret
= RegQueryValueExW(hsvc
->hkey
, _ImagePathW
, NULL
, &type
, NULL
, &size
);
1453 if (ret
!=ERROR_SUCCESS
)
1455 str
= HeapAlloc(GetProcessHeap(),0,size
);
1456 ret
= RegQueryValueExW(hsvc
->hkey
, _ImagePathW
, NULL
, &type
, (LPBYTE
)str
, &size
);
1457 if (ret
==ERROR_SUCCESS
)
1459 size
= ExpandEnvironmentStringsW(str
,NULL
,0);
1460 path
= HeapAlloc(GetProcessHeap(),0,size
*sizeof(WCHAR
));
1461 ExpandEnvironmentStringsW(str
,path
,size
);
1463 HeapFree(GetProcessHeap(),0,str
);
1467 /* wait for the process to start and set an event or terminate */
1468 handles
[0] = service_get_event_handle( hsvc
->name
);
1469 ZeroMemory(&si
, sizeof(STARTUPINFOW
));
1470 si
.cb
= sizeof(STARTUPINFOW
);
1471 r
= CreateProcessW(NULL
, path
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
1474 handles
[1] = pi
.hProcess
;
1475 ret
= WaitForMultipleObjectsEx(2, handles
, FALSE
, 30000, FALSE
);
1476 if(ret
!= WAIT_OBJECT_0
)
1478 SetLastError(ERROR_IO_PENDING
);
1482 CloseHandle( pi
.hThread
);
1483 CloseHandle( pi
.hProcess
);
1485 CloseHandle( handles
[0] );
1486 HeapFree(GetProcessHeap(),0,path
);
1490 static BOOL
service_wait_for_startup(SC_HANDLE hService
)
1493 SERVICE_STATUS status
;
1496 TRACE("%p\n", hService
);
1498 for (i
=0; i
<30; i
++)
1500 status
.dwCurrentState
= 0;
1501 r
= QueryServiceStatus(hService
, &status
);
1504 if (status
.dwCurrentState
== SERVICE_RUNNING
)
1506 TRACE("Service started successfully\n");
1515 /******************************************************************************
1516 * StartServiceW [ADVAPI32.@]
1518 * See StartServiceA.
1520 BOOL WINAPI
StartServiceW(SC_HANDLE hService
, DWORD dwNumServiceArgs
,
1521 LPCWSTR
*lpServiceArgVectors
)
1523 struct sc_service
*hsvc
;
1526 HANDLE handle
= INVALID_HANDLE_VALUE
;
1528 TRACE("%p %d %p\n", hService
, dwNumServiceArgs
, lpServiceArgVectors
);
1530 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1533 SetLastError(ERROR_INVALID_HANDLE
);
1537 hLock
= LockServiceDatabase((SC_HANDLE
)hsvc
->scm
);
1541 handle
= service_open_pipe(hsvc
->name
);
1542 if (handle
==INVALID_HANDLE_VALUE
)
1544 /* start the service process */
1545 if (service_start_process(hsvc
))
1546 handle
= service_open_pipe(hsvc
->name
);
1549 if (handle
!= INVALID_HANDLE_VALUE
)
1551 service_send_start_message(handle
, lpServiceArgVectors
, dwNumServiceArgs
);
1552 CloseHandle(handle
);
1556 UnlockServiceDatabase( hLock
);
1558 TRACE("returning %d\n", r
);
1561 service_wait_for_startup(hService
);
1566 /******************************************************************************
1567 * QueryServiceStatus [ADVAPI32.@]
1571 * lpservicestatus []
1574 BOOL WINAPI
QueryServiceStatus(SC_HANDLE hService
,
1575 LPSERVICE_STATUS lpservicestatus
)
1577 struct sc_service
*hsvc
;
1578 DWORD size
, type
, val
;
1582 TRACE("%p %p\n", hService
, lpservicestatus
);
1584 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1587 SetLastError( ERROR_INVALID_HANDLE
);
1591 pipe
= service_open_pipe(hsvc
->name
);
1592 if (pipe
!= INVALID_HANDLE_VALUE
)
1594 r
= service_get_status(pipe
, lpservicestatus
);
1600 TRACE("Failed to read service status\n");
1602 /* read the service type from the registry */
1604 r
= RegQueryValueExA(hsvc
->hkey
, "Type", NULL
, &type
, (LPBYTE
)&val
, &size
);
1605 if(r
!=ERROR_SUCCESS
|| type
!=REG_DWORD
)
1608 lpservicestatus
->dwServiceType
= val
;
1609 lpservicestatus
->dwCurrentState
= SERVICE_STOPPED
; /* stopped */
1610 lpservicestatus
->dwControlsAccepted
= 0;
1611 lpservicestatus
->dwWin32ExitCode
= ERROR_SERVICE_NEVER_STARTED
;
1612 lpservicestatus
->dwServiceSpecificExitCode
= 0;
1613 lpservicestatus
->dwCheckPoint
= 0;
1614 lpservicestatus
->dwWaitHint
= 0;
1619 /******************************************************************************
1620 * QueryServiceStatusEx [ADVAPI32.@]
1622 * Get information about a service.
1625 * hService [I] Handle to service to get information about
1626 * InfoLevel [I] Level of information to get
1627 * lpBuffer [O] Destination for requested information
1628 * cbBufSize [I] Size of lpBuffer in bytes
1629 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1635 BOOL WINAPI
QueryServiceStatusEx(SC_HANDLE hService
, SC_STATUS_TYPE InfoLevel
,
1636 LPBYTE lpBuffer
, DWORD cbBufSize
,
1637 LPDWORD pcbBytesNeeded
)
1640 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1644 /******************************************************************************
1645 * QueryServiceConfigA [ADVAPI32.@]
1648 QueryServiceConfigA( SC_HANDLE hService
,
1649 LPQUERY_SERVICE_CONFIGA lpServiceConfig
,
1650 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
1652 static const CHAR szDisplayName
[] = "DisplayName";
1653 static const CHAR szType
[] = "Type";
1654 static const CHAR szStart
[] = "Start";
1655 static const CHAR szError
[] = "ErrorControl";
1656 static const CHAR szImagePath
[] = "ImagePath";
1657 static const CHAR szGroup
[] = "Group";
1658 static const CHAR szDependencies
[] = "Dependencies";
1659 struct sc_service
*hsvc
;
1661 CHAR str_buffer
[ MAX_PATH
];
1663 DWORD type
, val
, sz
, total
, n
;
1666 TRACE("%p %p %d %p\n", hService
, lpServiceConfig
,
1667 cbBufSize
, pcbBytesNeeded
);
1669 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1672 SetLastError( ERROR_INVALID_HANDLE
);
1677 /* calculate the size required first */
1678 total
= sizeof (QUERY_SERVICE_CONFIGA
);
1680 sz
= sizeof(str_buffer
);
1681 r
= RegQueryValueExA( hKey
, szImagePath
, 0, &type
, (LPBYTE
)str_buffer
, &sz
);
1682 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
|| type
== REG_EXPAND_SZ
) )
1684 sz
= ExpandEnvironmentStringsA(str_buffer
,NULL
,0);
1685 if( 0 == sz
) return FALSE
;
1691 /* FIXME: set last error */
1696 r
= RegQueryValueExA( hKey
, szGroup
, 0, &type
, NULL
, &sz
);
1697 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1701 r
= RegQueryValueExA( hKey
, szDependencies
, 0, &type
, NULL
, &sz
);
1702 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_MULTI_SZ
) )
1706 r
= RegQueryValueExA( hKey
, szStart
, 0, &type
, NULL
, &sz
);
1707 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1711 r
= RegQueryValueExA( hKey
, szDisplayName
, 0, &type
, NULL
, &sz
);
1712 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1715 *pcbBytesNeeded
= total
;
1717 /* if there's not enough memory, return an error */
1718 if( total
> cbBufSize
)
1720 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1724 ZeroMemory( lpServiceConfig
, total
);
1727 r
= RegQueryValueExA( hKey
, szType
, 0, &type
, (LPBYTE
)&val
, &sz
);
1728 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_DWORD
) )
1729 lpServiceConfig
->dwServiceType
= val
;
1732 r
= RegQueryValueExA( hKey
, szStart
, 0, &type
, (LPBYTE
)&val
, &sz
);
1733 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_DWORD
) )
1734 lpServiceConfig
->dwStartType
= val
;
1737 r
= RegQueryValueExA( hKey
, szError
, 0, &type
, (LPBYTE
)&val
, &sz
);
1738 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_DWORD
) )
1739 lpServiceConfig
->dwErrorControl
= val
;
1741 /* now do the strings */
1742 p
= (LPSTR
) &lpServiceConfig
[1];
1743 n
= total
- sizeof (QUERY_SERVICE_CONFIGA
);
1745 sz
= sizeof(str_buffer
);
1746 r
= RegQueryValueExA( hKey
, szImagePath
, 0, &type
, (LPBYTE
)str_buffer
, &sz
);
1747 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
|| type
== REG_EXPAND_SZ
) )
1749 sz
= ExpandEnvironmentStringsA(str_buffer
, p
, n
);
1750 if( 0 == sz
|| sz
> n
) return FALSE
;
1752 lpServiceConfig
->lpBinaryPathName
= p
;
1758 /* FIXME: set last error */
1763 r
= RegQueryValueExA( hKey
, szGroup
, 0, &type
, (LPBYTE
)p
, &sz
);
1764 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_SZ
) )
1766 lpServiceConfig
->lpLoadOrderGroup
= p
;
1772 r
= RegQueryValueExA( hKey
, szDependencies
, 0, &type
, (LPBYTE
)p
, &sz
);
1773 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_SZ
) )
1775 lpServiceConfig
->lpDependencies
= p
;
1781 ERR("Buffer overflow!\n");
1783 TRACE("Image path = %s\n", lpServiceConfig
->lpBinaryPathName
);
1784 TRACE("Group = %s\n", lpServiceConfig
->lpLoadOrderGroup
);
1789 /******************************************************************************
1790 * QueryServiceConfigW [ADVAPI32.@]
1793 QueryServiceConfigW( SC_HANDLE hService
,
1794 LPQUERY_SERVICE_CONFIGW lpServiceConfig
,
1795 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
1797 WCHAR str_buffer
[ MAX_PATH
];
1799 DWORD type
, val
, sz
, total
, n
;
1802 struct sc_service
*hsvc
;
1804 TRACE("%p %p %d %p\n", hService
, lpServiceConfig
,
1805 cbBufSize
, pcbBytesNeeded
);
1807 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1810 SetLastError( ERROR_INVALID_HANDLE
);
1815 /* calculate the size required first */
1816 total
= sizeof (QUERY_SERVICE_CONFIGW
);
1818 sz
= sizeof(str_buffer
);
1819 r
= RegQueryValueExW( hKey
, szImagePath
, 0, &type
, (LPBYTE
) str_buffer
, &sz
);
1820 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
|| type
== REG_EXPAND_SZ
) )
1822 sz
= ExpandEnvironmentStringsW(str_buffer
,NULL
,0);
1823 if( 0 == sz
) return FALSE
;
1825 total
+= sizeof(WCHAR
) * sz
;
1829 /* FIXME: set last error */
1834 r
= RegQueryValueExW( hKey
, szGroup
, 0, &type
, NULL
, &sz
);
1835 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1839 r
= RegQueryValueExW( hKey
, szDependencies
, 0, &type
, NULL
, &sz
);
1840 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_MULTI_SZ
) )
1843 total
+= sizeof(WCHAR
);
1846 r
= RegQueryValueExW( hKey
, szStart
, 0, &type
, NULL
, &sz
);
1847 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1851 r
= RegQueryValueExW( hKey
, szDisplayName
, 0, &type
, NULL
, &sz
);
1852 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1855 *pcbBytesNeeded
= total
;
1857 /* if there's not enough memory, return an error */
1858 if( total
> cbBufSize
)
1860 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1864 ZeroMemory( lpServiceConfig
, total
);
1867 r
= RegQueryValueExW( hKey
, szType
, 0, &type
, (LPBYTE
)&val
, &sz
);
1868 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_DWORD
) )
1869 lpServiceConfig
->dwServiceType
= val
;
1872 r
= RegQueryValueExW( hKey
, szStart
, 0, &type
, (LPBYTE
)&val
, &sz
);
1873 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_DWORD
) )
1874 lpServiceConfig
->dwStartType
= val
;
1877 r
= RegQueryValueExW( hKey
, szError
, 0, &type
, (LPBYTE
)&val
, &sz
);
1878 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_DWORD
) )
1879 lpServiceConfig
->dwErrorControl
= val
;
1881 /* now do the strings */
1882 p
= (LPBYTE
) &lpServiceConfig
[1];
1883 n
= total
- sizeof (QUERY_SERVICE_CONFIGW
);
1885 sz
= sizeof(str_buffer
);
1886 r
= RegQueryValueExW( hKey
, szImagePath
, 0, &type
, (LPBYTE
) str_buffer
, &sz
);
1887 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
|| type
== REG_EXPAND_SZ
) )
1889 sz
= ExpandEnvironmentStringsW(str_buffer
, (LPWSTR
) p
, n
);
1890 sz
*= sizeof(WCHAR
);
1891 if( 0 == sz
|| sz
> n
) return FALSE
;
1893 lpServiceConfig
->lpBinaryPathName
= (LPWSTR
) p
;
1899 /* FIXME: set last error */
1904 r
= RegQueryValueExW( hKey
, szGroup
, 0, &type
, p
, &sz
);
1905 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_SZ
) )
1907 lpServiceConfig
->lpLoadOrderGroup
= (LPWSTR
) p
;
1913 r
= RegQueryValueExW( hKey
, szDependencies
, 0, &type
, p
, &sz
);
1914 lpServiceConfig
->lpDependencies
= (LPWSTR
) p
;
1915 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_SZ
) )
1928 ERR("Buffer overflow!\n");
1930 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig
->lpBinaryPathName
) );
1931 TRACE("Group = %s\n", debugstr_w(lpServiceConfig
->lpLoadOrderGroup
) );
1936 /******************************************************************************
1937 * EnumServicesStatusA [ADVAPI32.@]
1940 EnumServicesStatusA( SC_HANDLE hSCManager
, DWORD dwServiceType
,
1941 DWORD dwServiceState
, LPENUM_SERVICE_STATUSA lpServices
,
1942 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
1943 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
)
1945 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager
,
1946 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
1947 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
);
1948 SetLastError (ERROR_ACCESS_DENIED
);
1952 /******************************************************************************
1953 * EnumServicesStatusW [ADVAPI32.@]
1956 EnumServicesStatusW( SC_HANDLE hSCManager
, DWORD dwServiceType
,
1957 DWORD dwServiceState
, LPENUM_SERVICE_STATUSW lpServices
,
1958 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
1959 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
)
1961 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager
,
1962 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
1963 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
);
1964 SetLastError (ERROR_ACCESS_DENIED
);
1968 /******************************************************************************
1969 * GetServiceKeyNameA [ADVAPI32.@]
1971 BOOL WINAPI
GetServiceKeyNameA( SC_HANDLE hSCManager
, LPCSTR lpDisplayName
,
1972 LPSTR lpServiceName
, LPDWORD lpcchBuffer
)
1974 FIXME("%p %s %p %p\n", hSCManager
, debugstr_a(lpDisplayName
), lpServiceName
, lpcchBuffer
);
1978 /******************************************************************************
1979 * GetServiceKeyNameW [ADVAPI32.@]
1981 BOOL WINAPI
GetServiceKeyNameW( SC_HANDLE hSCManager
, LPCWSTR lpDisplayName
,
1982 LPWSTR lpServiceName
, LPDWORD lpcchBuffer
)
1984 FIXME("%p %s %p %p\n", hSCManager
, debugstr_w(lpDisplayName
), lpServiceName
, lpcchBuffer
);
1988 /******************************************************************************
1989 * QueryServiceLockStatusA [ADVAPI32.@]
1991 BOOL WINAPI
QueryServiceLockStatusA( SC_HANDLE hSCManager
,
1992 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus
,
1993 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
1995 FIXME("%p %p %08x %p\n", hSCManager
, lpLockStatus
, cbBufSize
, pcbBytesNeeded
);
2000 /******************************************************************************
2001 * QueryServiceLockStatusW [ADVAPI32.@]
2003 BOOL WINAPI
QueryServiceLockStatusW( SC_HANDLE hSCManager
,
2004 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus
,
2005 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
2007 FIXME("%p %p %08x %p\n", hSCManager
, lpLockStatus
, cbBufSize
, pcbBytesNeeded
);
2012 /******************************************************************************
2013 * GetServiceDisplayNameA [ADVAPI32.@]
2015 BOOL WINAPI
GetServiceDisplayNameA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
2016 LPSTR lpDisplayName
, LPDWORD lpcchBuffer
)
2018 FIXME("%p %s %p %p\n", hSCManager
,
2019 debugstr_a(lpServiceName
), lpDisplayName
, lpcchBuffer
);
2023 /******************************************************************************
2024 * GetServiceDisplayNameW [ADVAPI32.@]
2026 BOOL WINAPI
GetServiceDisplayNameW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
2027 LPWSTR lpDisplayName
, LPDWORD lpcchBuffer
)
2029 FIXME("%p %s %p %p\n", hSCManager
,
2030 debugstr_w(lpServiceName
), lpDisplayName
, lpcchBuffer
);
2034 /******************************************************************************
2035 * ChangeServiceConfigW [ADVAPI32.@]
2037 BOOL WINAPI
ChangeServiceConfigW( SC_HANDLE hService
, DWORD dwServiceType
,
2038 DWORD dwStartType
, DWORD dwErrorControl
, LPCWSTR lpBinaryPathName
,
2039 LPCWSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
, LPCWSTR lpDependencies
,
2040 LPCWSTR lpServiceStartName
, LPCWSTR lpPassword
, LPCWSTR lpDisplayName
)
2042 struct reg_value val
[10];
2043 struct sc_service
*hsvc
;
2044 DWORD r
= ERROR_SUCCESS
;
2048 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2049 hService
, dwServiceType
, dwStartType
, dwErrorControl
,
2050 debugstr_w(lpBinaryPathName
), debugstr_w(lpLoadOrderGroup
),
2051 lpdwTagId
, lpDependencies
, debugstr_w(lpServiceStartName
),
2052 debugstr_w(lpPassword
), debugstr_w(lpDisplayName
) );
2054 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
2057 SetLastError( ERROR_INVALID_HANDLE
);
2062 if( dwServiceType
!= SERVICE_NO_CHANGE
)
2063 service_set_dword( &val
[n
++], szType
, &dwServiceType
);
2065 if( dwStartType
!= SERVICE_NO_CHANGE
)
2066 service_set_dword( &val
[n
++], szStart
, &dwStartType
);
2068 if( dwErrorControl
!= SERVICE_NO_CHANGE
)
2069 service_set_dword( &val
[n
++], szError
, &dwErrorControl
);
2071 if( lpBinaryPathName
)
2072 service_set_string( &val
[n
++], szImagePath
, lpBinaryPathName
);
2074 if( lpLoadOrderGroup
)
2075 service_set_string( &val
[n
++], szGroup
, lpLoadOrderGroup
);
2077 if( lpDependencies
)
2078 service_set_multi_string( &val
[n
++], szDependencies
, lpDependencies
);
2081 FIXME("ignoring password\n");
2083 if( lpServiceStartName
)
2084 service_set_string( &val
[n
++], szDependOnService
, lpServiceStartName
);
2086 r
= service_write_values( hsvc
->hkey
, val
, n
);
2088 return (r
== ERROR_SUCCESS
) ? TRUE
: FALSE
;
2091 /******************************************************************************
2092 * ChangeServiceConfigA [ADVAPI32.@]
2094 BOOL WINAPI
ChangeServiceConfigA( SC_HANDLE hService
, DWORD dwServiceType
,
2095 DWORD dwStartType
, DWORD dwErrorControl
, LPCSTR lpBinaryPathName
,
2096 LPCSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
, LPCSTR lpDependencies
,
2097 LPCSTR lpServiceStartName
, LPCSTR lpPassword
, LPCSTR lpDisplayName
)
2099 LPWSTR wBinaryPathName
, wLoadOrderGroup
, wDependencies
;
2100 LPWSTR wServiceStartName
, wPassword
, wDisplayName
;
2103 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2104 hService
, dwServiceType
, dwStartType
, dwErrorControl
,
2105 debugstr_a(lpBinaryPathName
), debugstr_a(lpLoadOrderGroup
),
2106 lpdwTagId
, lpDependencies
, debugstr_a(lpServiceStartName
),
2107 debugstr_a(lpPassword
), debugstr_a(lpDisplayName
) );
2109 wBinaryPathName
= SERV_dup( lpBinaryPathName
);
2110 wLoadOrderGroup
= SERV_dup( lpLoadOrderGroup
);
2111 wDependencies
= SERV_dupmulti( lpDependencies
);
2112 wServiceStartName
= SERV_dup( lpServiceStartName
);
2113 wPassword
= SERV_dup( lpPassword
);
2114 wDisplayName
= SERV_dup( lpDisplayName
);
2116 r
= ChangeServiceConfigW( hService
, dwServiceType
,
2117 dwStartType
, dwErrorControl
, wBinaryPathName
,
2118 wLoadOrderGroup
, lpdwTagId
, wDependencies
,
2119 wServiceStartName
, wPassword
, wDisplayName
);
2121 SERV_free( wBinaryPathName
);
2122 SERV_free( wLoadOrderGroup
);
2123 SERV_free( wDependencies
);
2124 SERV_free( wServiceStartName
);
2125 SERV_free( wPassword
);
2126 SERV_free( wDisplayName
);
2131 /******************************************************************************
2132 * ChangeServiceConfig2A [ADVAPI32.@]
2134 BOOL WINAPI
ChangeServiceConfig2A( SC_HANDLE hService
, DWORD dwInfoLevel
,
2139 TRACE("%p %d %p\n",hService
, dwInfoLevel
, lpInfo
);
2141 if (dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
2143 LPSERVICE_DESCRIPTIONA sd
= (LPSERVICE_DESCRIPTIONA
) lpInfo
;
2144 SERVICE_DESCRIPTIONW sdw
;
2146 sdw
.lpDescription
= SERV_dup( sd
->lpDescription
);
2148 r
= ChangeServiceConfig2W( hService
, dwInfoLevel
, &sdw
);
2150 SERV_free( sdw
.lpDescription
);
2152 else if (dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
2154 LPSERVICE_FAILURE_ACTIONSA fa
= (LPSERVICE_FAILURE_ACTIONSA
) lpInfo
;
2155 SERVICE_FAILURE_ACTIONSW faw
;
2157 faw
.dwResetPeriod
= fa
->dwResetPeriod
;
2158 faw
.lpRebootMsg
= SERV_dup( fa
->lpRebootMsg
);
2159 faw
.lpCommand
= SERV_dup( fa
->lpCommand
);
2160 faw
.cActions
= fa
->cActions
;
2161 faw
.lpsaActions
= fa
->lpsaActions
;
2163 r
= ChangeServiceConfig2W( hService
, dwInfoLevel
, &faw
);
2165 SERV_free( faw
.lpRebootMsg
);
2166 SERV_free( faw
.lpCommand
);
2169 SetLastError( ERROR_INVALID_PARAMETER
);
2174 /******************************************************************************
2175 * ChangeServiceConfig2W [ADVAPI32.@]
2177 BOOL WINAPI
ChangeServiceConfig2W( SC_HANDLE hService
, DWORD dwInfoLevel
,
2181 struct sc_service
*hsvc
;
2183 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
2186 SetLastError( ERROR_INVALID_HANDLE
);
2191 if (dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
2193 static const WCHAR szDescription
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2194 LPSERVICE_DESCRIPTIONW sd
= (LPSERVICE_DESCRIPTIONW
)lpInfo
;
2195 if (sd
->lpDescription
)
2197 TRACE("Setting Description to %s\n",debugstr_w(sd
->lpDescription
));
2198 if (sd
->lpDescription
[0] == 0)
2199 RegDeleteValueW(hKey
,szDescription
);
2201 RegSetValueExW(hKey
, szDescription
, 0, REG_SZ
,
2202 (LPVOID
)sd
->lpDescription
,
2203 sizeof(WCHAR
)*(strlenW(sd
->lpDescription
)+1));
2207 FIXME("STUB: %p %d %p\n",hService
, dwInfoLevel
, lpInfo
);
2211 /******************************************************************************
2212 * QueryServiceObjectSecurity [ADVAPI32.@]
2214 BOOL WINAPI
QueryServiceObjectSecurity(SC_HANDLE hService
,
2215 SECURITY_INFORMATION dwSecurityInformation
,
2216 PSECURITY_DESCRIPTOR lpSecurityDescriptor
,
2217 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
2221 FIXME("%p %d %p %u %p\n", hService
, dwSecurityInformation
,
2222 lpSecurityDescriptor
, cbBufSize
, pcbBytesNeeded
);
2224 InitializeSecurityDescriptor(lpSecurityDescriptor
, SECURITY_DESCRIPTOR_REVISION
);
2226 pACL
= HeapAlloc( GetProcessHeap(), 0, sizeof(ACL
) );
2227 InitializeAcl(pACL
, sizeof(ACL
), ACL_REVISION
);
2228 SetSecurityDescriptorDacl(lpSecurityDescriptor
, TRUE
, pACL
, TRUE
);
2232 /******************************************************************************
2233 * SetServiceObjectSecurity [ADVAPI32.@]
2235 BOOL WINAPI
SetServiceObjectSecurity(SC_HANDLE hService
,
2236 SECURITY_INFORMATION dwSecurityInformation
,
2237 PSECURITY_DESCRIPTOR lpSecurityDescriptor
)
2239 FIXME("%p %d %p\n", hService
, dwSecurityInformation
, lpSecurityDescriptor
);
2243 /******************************************************************************
2244 * SetServiceBits [ADVAPI32.@]
2246 BOOL WINAPI
SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus
,
2247 DWORD dwServiceBits
,
2249 BOOL bUpdateImmediately
)
2251 FIXME("%p %08x %x %x\n", hServiceStatus
, dwServiceBits
,
2252 bSetBitsOn
, bUpdateImmediately
);
2256 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerExA( LPCSTR lpServiceName
,
2257 LPHANDLER_FUNCTION_EX lpHandlerProc
, LPVOID lpContext
)
2259 FIXME("%s %p %p\n", debugstr_a(lpServiceName
), lpHandlerProc
, lpContext
);
2263 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName
,
2264 LPHANDLER_FUNCTION_EX lpHandlerProc
, LPVOID lpContext
)
2266 service_data
*service
;
2268 TRACE("%s %p %p\n", debugstr_w(lpServiceName
), lpHandlerProc
, lpContext
);
2270 EnterCriticalSection( &service_cs
);
2271 for(service
= service_list
; service
; service
= service
->next
)
2272 if(!strcmpW(lpServiceName
, service
->name
))
2276 service
->handler
.handler_ex
= lpHandlerProc
;
2277 service
->context
= lpContext
;
2278 service
->extended
= TRUE
;
2280 LeaveCriticalSection( &service_cs
);
2282 return (SERVICE_STATUS_HANDLE
)service
;