2 * Win32 advapi functions
4 * Copyright 1995 Sven Verdoolaege
5 * Copyright 2005 Mike McCormack
6 * Copyright 2007 Rolf Kalbermatter
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
33 #include "wine/unicode.h"
34 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(advapi
);
41 static const WCHAR szServiceManagerKey
[] = { 'S','y','s','t','e','m','\\',
42 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
43 'S','e','r','v','i','c','e','s',0 };
44 static const WCHAR szSCMLock
[] = {'A','D','V','A','P','I','_','S','C','M',
47 typedef struct service_start_info_t
54 #define WINESERV_STARTINFO 1
55 #define WINESERV_GETSTATUS 2
56 #define WINESERV_SENDCONTROL 3
57 #define WINESERV_SETPID 4
59 typedef struct service_data_t
61 struct service_data_t
*next
;
63 LPHANDLER_FUNCTION handler
;
64 LPHANDLER_FUNCTION_EX handler_ex
;
67 SERVICE_STATUS_PROCESS status
;
70 BOOL extended
: 1; /* uses handler_ex instead of handler? */
72 LPSERVICE_MAIN_FUNCTIONA a
;
73 LPSERVICE_MAIN_FUNCTIONW w
;
79 static CRITICAL_SECTION service_cs
;
80 static CRITICAL_SECTION_DEBUG service_cs_debug
=
83 { &service_cs_debug
.ProcessLocksList
,
84 &service_cs_debug
.ProcessLocksList
},
85 0, 0, { (DWORD_PTR
)(__FILE__
": service_cs") }
87 static CRITICAL_SECTION service_cs
= { &service_cs_debug
, -1, 0, 0, 0, 0 };
89 static service_data
*service_list
;
91 /******************************************************************************
95 #define MAX_SERVICE_NAME 256
97 typedef enum { SC_HTYPE_MANAGER
, SC_HTYPE_SERVICE
} SC_HANDLE_TYPE
;
100 typedef VOID (*sc_handle_destructor
)(struct sc_handle
*);
104 SC_HANDLE_TYPE htype
;
106 sc_handle_destructor destroy
;
109 struct sc_manager
/* service control manager handle */
111 struct sc_handle hdr
;
112 HKEY hkey
; /* handle to services database in the registry */
115 struct sc_service
/* service handle */
117 struct sc_handle hdr
;
118 HKEY hkey
; /* handle to service entry in the registry (under hkey) */
119 struct sc_manager
*scm
; /* pointer to SCM handle */
123 static void *sc_handle_alloc(SC_HANDLE_TYPE htype
, DWORD size
,
124 sc_handle_destructor destroy
)
126 struct sc_handle
*hdr
;
128 hdr
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
133 hdr
->destroy
= destroy
;
135 TRACE("sc_handle type=%d -> %p\n", htype
, hdr
);
139 static void *sc_handle_get_handle_data(SC_HANDLE handle
, DWORD htype
)
141 struct sc_handle
*hdr
= (struct sc_handle
*) handle
;
145 if (hdr
->htype
!= htype
)
150 static void sc_handle_free(struct sc_handle
* hdr
)
154 if (--hdr
->ref_count
)
157 HeapFree(GetProcessHeap(), 0, hdr
);
160 static void sc_handle_destroy_manager(struct sc_handle
*handle
)
162 struct sc_manager
*mgr
= (struct sc_manager
*) handle
;
164 TRACE("destroying SC Manager %p\n", mgr
);
166 RegCloseKey(mgr
->hkey
);
169 static void sc_handle_destroy_service(struct sc_handle
*handle
)
171 struct sc_service
*svc
= (struct sc_service
*) handle
;
173 TRACE("destroying service %p\n", svc
);
175 RegCloseKey(svc
->hkey
);
177 sc_handle_free(&svc
->scm
->hdr
);
181 /******************************************************************************
182 * String management functions
184 static inline LPWSTR
SERV_dup( LPCSTR str
)
191 len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
192 wstr
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof (WCHAR
) );
193 MultiByteToWideChar( CP_ACP
, 0, str
, -1, wstr
, len
);
197 static inline LPWSTR
SERV_dupmulti(LPCSTR str
)
205 len
+= MultiByteToWideChar( CP_ACP
, 0, &str
[n
], -1, NULL
, 0 );
206 n
+= (strlen( &str
[n
] ) + 1);
211 wstr
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof (WCHAR
) );
212 MultiByteToWideChar( CP_ACP
, 0, str
, n
, wstr
, len
);
216 static inline VOID
SERV_free( LPWSTR wstr
)
218 HeapFree( GetProcessHeap(), 0, wstr
);
221 /******************************************************************************
222 * registry access functions and data
224 static const WCHAR szDisplayName
[] = {
225 'D','i','s','p','l','a','y','N','a','m','e', 0 };
226 static const WCHAR szType
[] = {'T','y','p','e',0};
227 static const WCHAR szStart
[] = {'S','t','a','r','t',0};
228 static const WCHAR szError
[] = {
229 'E','r','r','o','r','C','o','n','t','r','o','l', 0};
230 static const WCHAR szImagePath
[] = {'I','m','a','g','e','P','a','t','h',0};
231 static const WCHAR szGroup
[] = {'G','r','o','u','p',0};
232 static const WCHAR szDependencies
[] = {
233 'D','e','p','e','n','d','e','n','c','i','e','s',0};
234 static const WCHAR szDependOnService
[] = {
235 'D','e','p','e','n','d','O','n','S','e','r','v','i','c','e',0};
244 static inline void service_set_value( struct reg_value
*val
,
245 DWORD type
, LPCWSTR name
, LPCVOID data
, DWORD size
)
253 static inline void service_set_dword( struct reg_value
*val
,
254 LPCWSTR name
, const DWORD
*data
)
256 service_set_value( val
, REG_DWORD
, name
, data
, sizeof (DWORD
));
259 static inline void service_set_string( struct reg_value
*val
,
260 LPCWSTR name
, LPCWSTR string
)
262 DWORD len
= (lstrlenW(string
)+1) * sizeof (WCHAR
);
263 service_set_value( val
, REG_SZ
, name
, string
, len
);
266 static inline void service_set_multi_string( struct reg_value
*val
,
267 LPCWSTR name
, LPCWSTR string
)
271 /* determine the length of a double null terminated multi string */
273 len
+= (lstrlenW( &string
[ len
] )+1);
274 } while ( string
[ len
++ ] );
276 len
*= sizeof (WCHAR
);
277 service_set_value( val
, REG_MULTI_SZ
, name
, string
, len
);
280 static inline LONG
service_write_values( HKEY hKey
,
281 const struct reg_value
*val
, int n
)
283 LONG r
= ERROR_SUCCESS
;
288 r
= RegSetValueExW(hKey
, val
[i
].name
, 0, val
[i
].type
,
289 (const BYTE
*)val
[i
].data
, val
[i
].size
);
290 if( r
!= ERROR_SUCCESS
)
296 /******************************************************************************
297 * Service IPC functions
299 static LPWSTR
service_get_pipe_name(LPCWSTR service
)
301 static const WCHAR prefix
[] = { '\\','\\','.','\\','p','i','p','e','\\',
302 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
306 len
= sizeof prefix
+ strlenW(service
)*sizeof(WCHAR
);
307 name
= HeapAlloc(GetProcessHeap(), 0, len
);
308 strcpyW(name
, prefix
);
309 strcatW(name
, service
);
313 static HANDLE
service_open_pipe(LPCWSTR service
)
315 LPWSTR szPipe
= service_get_pipe_name( service
);
316 HANDLE handle
= INVALID_HANDLE_VALUE
;
319 handle
= CreateFileW(szPipe
, GENERIC_READ
|GENERIC_WRITE
,
320 0, NULL
, OPEN_ALWAYS
, 0, NULL
);
321 if (handle
!= INVALID_HANDLE_VALUE
)
323 if (GetLastError() != ERROR_PIPE_BUSY
)
325 } while (WaitNamedPipeW(szPipe
, NMPWAIT_WAIT_FOREVER
));
331 /******************************************************************************
332 * service_get_event_handle
334 static HANDLE
service_get_event_handle(LPCWSTR service
)
336 static const WCHAR prefix
[] = {
337 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
342 len
= sizeof prefix
+ strlenW(service
)*sizeof(WCHAR
);
343 name
= HeapAlloc(GetProcessHeap(), 0, len
);
344 strcpyW(name
, prefix
);
345 strcatW(name
, service
);
346 handle
= CreateEventW(NULL
, TRUE
, FALSE
, name
);
351 /******************************************************************************
354 * Call into the main service routine provided by StartServiceCtrlDispatcher.
356 static DWORD WINAPI
service_thread(LPVOID arg
)
358 service_data
*info
= arg
;
359 LPWSTR str
= info
->args
;
360 DWORD argc
= 0, len
= 0;
366 len
+= strlenW(&str
[len
]) + 1;
373 info
->proc
.w(0, NULL
);
375 info
->proc
.a(0, NULL
);
383 argv
= HeapAlloc(GetProcessHeap(), 0, (argc
+1)*sizeof(LPWSTR
));
384 for (argc
=0, p
=str
; *p
; p
+= strlenW(p
) + 1)
388 info
->proc
.w(argc
, argv
);
389 HeapFree(GetProcessHeap(), 0, argv
);
393 LPSTR strA
, *argv
, p
;
396 lenA
= WideCharToMultiByte(CP_ACP
,0, str
, len
, NULL
, 0, NULL
, NULL
);
397 strA
= HeapAlloc(GetProcessHeap(), 0, lenA
);
398 WideCharToMultiByte(CP_ACP
,0, str
, len
, strA
, lenA
, NULL
, NULL
);
400 argv
= HeapAlloc(GetProcessHeap(), 0, (argc
+1)*sizeof(LPSTR
));
401 for (argc
=0, p
=strA
; *p
; p
+= strlen(p
) + 1)
405 info
->proc
.a(argc
, argv
);
406 HeapFree(GetProcessHeap(), 0, argv
);
407 HeapFree(GetProcessHeap(), 0, strA
);
412 /******************************************************************************
413 * service_handle_start
415 static BOOL
service_handle_start(HANDLE pipe
, service_data
*service
, DWORD count
)
417 DWORD read
= 0, result
= 0;
421 TRACE("%p %p %d\n", pipe
, service
, count
);
423 args
= HeapAlloc(GetProcessHeap(), 0, count
*sizeof(WCHAR
));
424 r
= ReadFile(pipe
, args
, count
*sizeof(WCHAR
), &read
, NULL
);
425 if (!r
|| count
!=read
/sizeof(WCHAR
) || args
[count
-1])
427 ERR("pipe read failed r = %d count = %d read = %d args[n-1]=%s\n",
428 r
, count
, read
, debugstr_wn(args
, count
));
434 ERR("service is not stopped\n");
438 SERV_free(service
->args
);
439 service
->args
= args
;
441 service
->thread
= CreateThread( NULL
, 0, service_thread
,
445 HeapFree(GetProcessHeap(), 0, args
);
446 WriteFile( pipe
, &result
, sizeof result
, &read
, NULL
);
451 /******************************************************************************
452 * service_send_start_message
454 static BOOL
service_send_start_message(HANDLE pipe
, LPCWSTR
*argv
, DWORD argc
)
456 DWORD i
, len
, count
, result
;
457 service_start_info
*ssi
;
461 TRACE("%p %p %d\n", pipe
, argv
, argc
);
463 /* calculate how much space do we need to send the startup info */
465 for (i
=0; i
<argc
; i
++)
466 len
+= strlenW(argv
[i
])+1;
468 ssi
= HeapAlloc(GetProcessHeap(),0,sizeof *ssi
+ (len
-1)*sizeof(WCHAR
));
469 ssi
->cmd
= WINESERV_STARTINFO
;
472 /* copy service args into a single buffer*/
474 for (i
=0; i
<argc
; i
++)
481 r
= WriteFile(pipe
, ssi
, sizeof *ssi
+ len
*sizeof(WCHAR
), &count
, NULL
);
483 r
= ReadFile(pipe
, &result
, sizeof result
, &count
, NULL
);
485 HeapFree(GetProcessHeap(),0,ssi
);
490 /******************************************************************************
491 * service_handle_get_status
493 static BOOL
service_handle_get_status(HANDLE pipe
, const service_data
*service
)
497 return WriteFile(pipe
, &service
->status
,
498 sizeof service
->status
, &count
, NULL
);
501 /******************************************************************************
504 static BOOL
service_get_status(HANDLE pipe
, LPSERVICE_STATUS_PROCESS status
)
506 DWORD cmd
[2], count
= 0;
509 cmd
[0] = WINESERV_GETSTATUS
;
511 r
= WriteFile( pipe
, cmd
, sizeof cmd
, &count
, NULL
);
512 if (!r
|| count
!= sizeof cmd
)
514 ERR("service protocol error - failed to write pipe!\n");
517 r
= ReadFile( pipe
, status
, sizeof *status
, &count
, NULL
);
518 if (!r
|| count
!= sizeof *status
)
519 ERR("service protocol error - failed to read pipe "
520 "r = %d count = %d!\n", r
, count
);
524 /******************************************************************************
525 * service_handle_set_processID
527 static BOOL
service_handle_set_processID(HANDLE pipe
, service_data
*service
, DWORD dwProcessId
)
529 DWORD count
, ret
= ERROR_SUCCESS
;
531 TRACE("received control %d\n", dwProcessId
);
532 service
->status
.dwProcessId
= dwProcessId
;
533 return WriteFile(pipe
, &ret
, sizeof ret
, &count
, NULL
);
536 /******************************************************************************
537 * service_set_processID
539 static BOOL
service_set_processID(HANDLE pipe
, DWORD dwprocessId
, LPDWORD dwResult
)
541 DWORD cmd
[2], count
= 0;
544 cmd
[0] = WINESERV_SETPID
;
545 cmd
[1] = dwprocessId
;
546 r
= WriteFile( pipe
, cmd
, sizeof cmd
, &count
, NULL
);
547 if (!r
|| count
!= sizeof cmd
)
549 ERR("service protocol error - failed to write pipe!\n");
552 r
= ReadFile( pipe
, dwResult
, sizeof *dwResult
, &count
, NULL
);
553 if (!r
|| count
!= sizeof *dwResult
)
554 ERR("service protocol error - failed to read pipe "
555 "r = %d count = %d!\n", r
, count
);
559 /******************************************************************************
560 * service_send_control
562 static BOOL
service_send_control(HANDLE pipe
, DWORD dwControl
, DWORD
*result
)
564 DWORD cmd
[2], count
= 0;
567 cmd
[0] = WINESERV_SENDCONTROL
;
569 r
= WriteFile(pipe
, cmd
, sizeof cmd
, &count
, NULL
);
570 if (!r
|| count
!= sizeof cmd
)
572 ERR("service protocol error - failed to write pipe!\n");
575 r
= ReadFile(pipe
, result
, sizeof *result
, &count
, NULL
);
576 if (!r
|| count
!= sizeof *result
)
577 ERR("service protocol error - failed to read pipe "
578 "r = %d count = %d!\n", r
, count
);
582 /******************************************************************************
583 * service_accepts_control
585 static BOOL
service_accepts_control(const service_data
*service
, DWORD dwControl
)
587 DWORD a
= service
->status
.dwControlsAccepted
;
591 case SERVICE_CONTROL_INTERROGATE
:
593 case SERVICE_CONTROL_STOP
:
594 if (a
&SERVICE_ACCEPT_STOP
)
597 case SERVICE_CONTROL_SHUTDOWN
:
598 if (a
&SERVICE_ACCEPT_SHUTDOWN
)
601 case SERVICE_CONTROL_PAUSE
:
602 case SERVICE_CONTROL_CONTINUE
:
603 if (a
&SERVICE_ACCEPT_PAUSE_CONTINUE
)
606 case SERVICE_CONTROL_PARAMCHANGE
:
607 if (a
&SERVICE_ACCEPT_PARAMCHANGE
)
610 case SERVICE_CONTROL_NETBINDADD
:
611 case SERVICE_CONTROL_NETBINDREMOVE
:
612 case SERVICE_CONTROL_NETBINDENABLE
:
613 case SERVICE_CONTROL_NETBINDDISABLE
:
614 if (a
&SERVICE_ACCEPT_NETBINDCHANGE
)
617 if (!service
->extended
)
621 case SERVICE_CONTROL_HARDWAREPROFILECHANGE
:
622 if (a
&SERVICE_ACCEPT_HARDWAREPROFILECHANGE
)
625 case SERVICE_CONTROL_POWEREVENT
:
626 if (a
&SERVICE_ACCEPT_POWEREVENT
)
629 case SERVICE_CONTROL_SESSIONCHANGE
:
630 if (a
&SERVICE_ACCEPT_SESSIONCHANGE
)
637 /******************************************************************************
638 * service_handle_control
640 static BOOL
service_handle_control(HANDLE pipe
, service_data
*service
,
643 DWORD count
, ret
= ERROR_INVALID_SERVICE_CONTROL
;
645 TRACE("received control %d\n", dwControl
);
647 if (service_accepts_control(service
, dwControl
))
649 if (service
->extended
&& service
->handler
.handler_ex
)
651 service
->handler
.handler_ex(dwControl
, 0, NULL
, service
->context
);
654 else if (service
->handler
.handler
)
656 service
->handler
.handler(dwControl
);
660 return WriteFile(pipe
, &ret
, sizeof ret
, &count
, NULL
);
663 /******************************************************************************
664 * service_reap_thread
666 static DWORD
service_reap_thread(service_data
*service
)
670 if (!service
->thread
)
672 GetExitCodeThread(service
->thread
, &exitcode
);
673 if (exitcode
!=STILL_ACTIVE
)
675 CloseHandle(service
->thread
);
681 /******************************************************************************
682 * service_control_dispatcher
684 static DWORD WINAPI
service_control_dispatcher(LPVOID arg
)
686 service_data
*service
= arg
;
690 TRACE("%p %s\n", service
, debugstr_w(service
->name
));
692 /* create a pipe to talk to the rest of the world with */
693 name
= service_get_pipe_name(service
->name
);
694 pipe
= CreateNamedPipeW(name
, PIPE_ACCESS_DUPLEX
,
695 PIPE_TYPE_BYTE
|PIPE_WAIT
, 1, 256, 256, 10000, NULL
);
698 /* let the process who started us know we've tried to create a pipe */
699 event
= service_get_event_handle(service
->name
);
703 if (pipe
==INVALID_HANDLE_VALUE
)
705 ERR("failed to create pipe for %s, error = %d\n",
706 debugstr_w(service
->name
), GetLastError());
710 /* dispatcher loop */
714 DWORD count
, req
[2] = {0,0};
716 r
= ConnectNamedPipe(pipe
, NULL
);
717 if (!r
&& GetLastError() != ERROR_PIPE_CONNECTED
)
719 ERR("pipe connect failed\n");
723 r
= ReadFile( pipe
, &req
, sizeof req
, &count
, NULL
);
724 if (!r
|| count
!=sizeof req
)
726 ERR("pipe read failed\n");
730 service_reap_thread(service
);
732 /* handle the request */
735 case WINESERV_STARTINFO
:
736 service_handle_start(pipe
, service
, req
[1]);
738 case WINESERV_GETSTATUS
:
739 service_handle_get_status(pipe
, service
);
741 case WINESERV_SENDCONTROL
:
742 service_handle_control(pipe
, service
, req
[1]);
744 case WINESERV_SETPID
:
745 service_handle_set_processID(pipe
, service
, req
[1]);
748 ERR("received invalid command %d length %d\n", req
[0], req
[1]);
751 FlushFileBuffers(pipe
);
752 DisconnectNamedPipe(pipe
);
759 /******************************************************************************
760 * service_run_threads
762 static BOOL
service_run_threads(void)
764 service_data
*service
;
765 DWORD count
= 0, n
= 0;
768 EnterCriticalSection( &service_cs
);
770 /* count how many services there are */
771 for (service
= service_list
; service
; service
= service
->next
)
774 TRACE("starting %d pipe listener threads\n", count
);
776 handles
= HeapAlloc(GetProcessHeap(), 0, sizeof(HANDLE
)*count
);
778 for (n
=0, service
= service_list
; service
; service
= service
->next
, n
++)
779 handles
[n
] = CreateThread( NULL
, 0, service_control_dispatcher
,
783 LeaveCriticalSection( &service_cs
);
785 /* wait for all the threads to pack up and exit */
786 WaitForMultipleObjectsEx(count
, handles
, TRUE
, INFINITE
, FALSE
);
788 HeapFree(GetProcessHeap(), 0, handles
);
793 /******************************************************************************
794 * StartServiceCtrlDispatcherA [ADVAPI32.@]
796 * See StartServiceCtrlDispatcherW.
798 BOOL WINAPI
StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA
*servent
)
804 TRACE("%p\n", servent
);
806 EnterCriticalSection( &service_cs
);
807 while (servent
->lpServiceName
)
809 LPSTR name
= servent
->lpServiceName
;
811 len
= MultiByteToWideChar(CP_ACP
, 0, name
, -1, NULL
, 0);
812 sz
= len
*sizeof(WCHAR
) + sizeof *info
;
813 info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sz
);
814 MultiByteToWideChar(CP_ACP
, 0, name
, -1, info
->name
, len
);
815 info
->proc
.a
= servent
->lpServiceProc
;
816 info
->unicode
= FALSE
;
818 /* insert into the list */
819 info
->next
= service_list
;
824 LeaveCriticalSection( &service_cs
);
826 service_run_threads();
831 /******************************************************************************
832 * StartServiceCtrlDispatcherW [ADVAPI32.@]
834 * Connects a process containing one or more services to the service control
838 * servent [I] A list of the service names and service procedures
844 BOOL WINAPI
StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW
*servent
)
850 TRACE("%p\n", servent
);
852 EnterCriticalSection( &service_cs
);
853 while (servent
->lpServiceName
)
855 LPWSTR name
= servent
->lpServiceName
;
858 sz
= len
*sizeof(WCHAR
) + sizeof *info
;
859 info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sz
);
860 strcpyW(info
->name
, name
);
861 info
->proc
.w
= servent
->lpServiceProc
;
862 info
->unicode
= TRUE
;
864 /* insert into the list */
865 info
->next
= service_list
;
870 LeaveCriticalSection( &service_cs
);
872 service_run_threads();
877 /******************************************************************************
878 * LockServiceDatabase [ADVAPI32.@]
880 SC_LOCK WINAPI
LockServiceDatabase (SC_HANDLE hSCManager
)
884 TRACE("%p\n",hSCManager
);
886 ret
= CreateSemaphoreW( NULL
, 1, 1, szSCMLock
);
887 if( ret
&& GetLastError() == ERROR_ALREADY_EXISTS
)
891 SetLastError( ERROR_SERVICE_DATABASE_LOCKED
);
894 TRACE("returning %p\n", ret
);
899 /******************************************************************************
900 * UnlockServiceDatabase [ADVAPI32.@]
902 BOOL WINAPI
UnlockServiceDatabase (SC_LOCK ScLock
)
904 TRACE("%p\n",ScLock
);
906 return CloseHandle( ScLock
);
909 /******************************************************************************
910 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
912 SERVICE_STATUS_HANDLE WINAPI
913 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName
, LPHANDLER_FUNCTION lpfHandler
)
915 LPWSTR lpServiceNameW
;
916 SERVICE_STATUS_HANDLE ret
;
918 lpServiceNameW
= SERV_dup(lpServiceName
);
919 ret
= RegisterServiceCtrlHandlerW( lpServiceNameW
, lpfHandler
);
920 SERV_free(lpServiceNameW
);
924 /******************************************************************************
925 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
931 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName
,
932 LPHANDLER_FUNCTION lpfHandler
)
934 service_data
*service
;
936 EnterCriticalSection( &service_cs
);
937 for(service
= service_list
; service
; service
= service
->next
)
938 if(!strcmpW(lpServiceName
, service
->name
))
941 service
->handler
.handler
= lpfHandler
;
942 LeaveCriticalSection( &service_cs
);
944 return (SERVICE_STATUS_HANDLE
)service
;
947 /******************************************************************************
948 * SetServiceStatus [ADVAPI32.@]
955 SetServiceStatus( SERVICE_STATUS_HANDLE hService
, LPSERVICE_STATUS lpStatus
)
957 service_data
*service
;
960 TRACE("%p %x %x %x %x %x %x %x\n", hService
,
961 lpStatus
->dwServiceType
, lpStatus
->dwCurrentState
,
962 lpStatus
->dwControlsAccepted
, lpStatus
->dwWin32ExitCode
,
963 lpStatus
->dwServiceSpecificExitCode
, lpStatus
->dwCheckPoint
,
964 lpStatus
->dwWaitHint
);
966 EnterCriticalSection( &service_cs
);
967 for (service
= service_list
; service
; service
= service
->next
)
968 if(service
== (service_data
*)hService
)
972 memcpy( &service
->status
, lpStatus
, sizeof(SERVICE_STATUS
) );
973 TRACE("Set service status to %d\n",service
->status
.dwCurrentState
);
977 LeaveCriticalSection( &service_cs
);
983 /******************************************************************************
984 * OpenSCManagerA [ADVAPI32.@]
986 * Establish a connection to the service control manager and open its database.
989 * lpMachineName [I] Pointer to machine name string
990 * lpDatabaseName [I] Pointer to database name string
991 * dwDesiredAccess [I] Type of access
994 * Success: A Handle to the service control manager database
997 SC_HANDLE WINAPI
OpenSCManagerA( LPCSTR lpMachineName
, LPCSTR lpDatabaseName
,
998 DWORD dwDesiredAccess
)
1000 LPWSTR lpMachineNameW
, lpDatabaseNameW
;
1003 lpMachineNameW
= SERV_dup(lpMachineName
);
1004 lpDatabaseNameW
= SERV_dup(lpDatabaseName
);
1005 ret
= OpenSCManagerW(lpMachineNameW
, lpDatabaseNameW
, dwDesiredAccess
);
1006 SERV_free(lpDatabaseNameW
);
1007 SERV_free(lpMachineNameW
);
1011 /******************************************************************************
1012 * OpenSCManagerW [ADVAPI32.@]
1014 * See OpenSCManagerA.
1016 SC_HANDLE WINAPI
OpenSCManagerW( LPCWSTR lpMachineName
, LPCWSTR lpDatabaseName
,
1017 DWORD dwDesiredAccess
)
1019 struct sc_manager
*manager
;
1023 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName
),
1024 debugstr_w(lpDatabaseName
), dwDesiredAccess
);
1026 if( lpDatabaseName
&& lpDatabaseName
[0] )
1028 if( strcmpiW( lpDatabaseName
, SERVICES_ACTIVE_DATABASEW
) == 0 )
1030 /* noop, all right */
1032 else if( strcmpiW( lpDatabaseName
, SERVICES_FAILED_DATABASEW
) == 0 )
1034 SetLastError( ERROR_DATABASE_DOES_NOT_EXIST
);
1039 SetLastError( ERROR_INVALID_NAME
);
1044 manager
= sc_handle_alloc( SC_HTYPE_MANAGER
, sizeof (struct sc_manager
),
1045 sc_handle_destroy_manager
);
1049 r
= RegConnectRegistryW(lpMachineName
,HKEY_LOCAL_MACHINE
,&hReg
);
1050 if (r
!=ERROR_SUCCESS
)
1053 r
= RegCreateKeyW(hReg
, szServiceManagerKey
, &manager
->hkey
);
1054 RegCloseKey( hReg
);
1055 if (r
!=ERROR_SUCCESS
)
1058 TRACE("returning %p\n", manager
);
1060 return (SC_HANDLE
) &manager
->hdr
;
1063 sc_handle_free( &manager
->hdr
);
1068 /******************************************************************************
1069 * ControlService [ADVAPI32.@]
1071 * Send a control code to a service.
1074 * hService [I] Handle of the service control manager database
1075 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
1076 * lpServiceStatus [O] Destination for the status of the service, if available
1083 * Unlike M$' implementation, control requests are not serialized and may be
1084 * processed asynchronously.
1086 BOOL WINAPI
ControlService( SC_HANDLE hService
, DWORD dwControl
,
1087 LPSERVICE_STATUS lpServiceStatus
)
1089 struct sc_service
*hsvc
;
1093 TRACE("%p %d %p\n", hService
, dwControl
, lpServiceStatus
);
1095 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1098 SetLastError( ERROR_INVALID_HANDLE
);
1102 ret
= QueryServiceStatus(hService
, lpServiceStatus
);
1105 ERR("failed to query service status\n");
1106 SetLastError(ERROR_SERVICE_NOT_ACTIVE
);
1110 switch (lpServiceStatus
->dwCurrentState
)
1112 case SERVICE_STOPPED
:
1113 SetLastError(ERROR_SERVICE_NOT_ACTIVE
);
1115 case SERVICE_START_PENDING
:
1116 if (dwControl
==SERVICE_CONTROL_STOP
)
1119 case SERVICE_STOP_PENDING
:
1120 SetLastError(ERROR_SERVICE_CANNOT_ACCEPT_CTRL
);
1124 handle
= service_open_pipe(hsvc
->name
);
1125 if (handle
!=INVALID_HANDLE_VALUE
)
1127 DWORD result
= ERROR_SUCCESS
;
1128 ret
= service_send_control(handle
, dwControl
, &result
);
1129 CloseHandle(handle
);
1130 if (result
!=ERROR_SUCCESS
)
1132 SetLastError(result
);
1140 /******************************************************************************
1141 * CloseServiceHandle [ADVAPI32.@]
1143 * Close a handle to a service or the service control manager database.
1146 * hSCObject [I] Handle to service or service control manager database
1153 CloseServiceHandle( SC_HANDLE hSCObject
)
1155 TRACE("%p\n", hSCObject
);
1157 sc_handle_free( (struct sc_handle
*) hSCObject
);
1163 /******************************************************************************
1164 * OpenServiceA [ADVAPI32.@]
1166 * Open a handle to a service.
1169 * hSCManager [I] Handle of the service control manager database
1170 * lpServiceName [I] Name of the service to open
1171 * dwDesiredAccess [I] Access required to the service
1174 * Success: Handle to the service
1177 SC_HANDLE WINAPI
OpenServiceA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
1178 DWORD dwDesiredAccess
)
1180 LPWSTR lpServiceNameW
;
1183 TRACE("%p %s %d\n", hSCManager
, debugstr_a(lpServiceName
), dwDesiredAccess
);
1185 lpServiceNameW
= SERV_dup(lpServiceName
);
1186 ret
= OpenServiceW( hSCManager
, lpServiceNameW
, dwDesiredAccess
);
1187 SERV_free(lpServiceNameW
);
1192 /******************************************************************************
1193 * OpenServiceW [ADVAPI32.@]
1197 SC_HANDLE WINAPI
OpenServiceW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
1198 DWORD dwDesiredAccess
)
1200 struct sc_manager
*hscm
;
1201 struct sc_service
*hsvc
;
1206 TRACE("%p %s %d\n", hSCManager
, debugstr_w(lpServiceName
), dwDesiredAccess
);
1210 SetLastError(ERROR_INVALID_ADDRESS
);
1214 hscm
= sc_handle_get_handle_data( hSCManager
, SC_HTYPE_MANAGER
);
1217 SetLastError( ERROR_INVALID_HANDLE
);
1221 r
= RegOpenKeyExW( hscm
->hkey
, lpServiceName
, 0, KEY_ALL_ACCESS
, &hKey
);
1222 if (r
!=ERROR_SUCCESS
)
1224 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST
);
1228 len
= strlenW(lpServiceName
)+1;
1229 hsvc
= sc_handle_alloc( SC_HTYPE_SERVICE
,
1230 sizeof (struct sc_service
) + len
*sizeof(WCHAR
),
1231 sc_handle_destroy_service
);
1234 strcpyW( hsvc
->name
, lpServiceName
);
1237 /* add reference to SCM handle */
1238 hscm
->hdr
.ref_count
++;
1241 TRACE("returning %p\n",hsvc
);
1243 return (SC_HANDLE
) &hsvc
->hdr
;
1246 /******************************************************************************
1247 * CreateServiceW [ADVAPI32.@]
1250 CreateServiceW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
1251 LPCWSTR lpDisplayName
, DWORD dwDesiredAccess
,
1252 DWORD dwServiceType
, DWORD dwStartType
,
1253 DWORD dwErrorControl
, LPCWSTR lpBinaryPathName
,
1254 LPCWSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
,
1255 LPCWSTR lpDependencies
, LPCWSTR lpServiceStartName
,
1256 LPCWSTR lpPassword
)
1258 struct sc_manager
*hscm
;
1259 struct sc_service
*hsvc
= NULL
;
1263 struct reg_value val
[10];
1266 TRACE("%p %s %s\n", hSCManager
,
1267 debugstr_w(lpServiceName
), debugstr_w(lpDisplayName
));
1269 hscm
= sc_handle_get_handle_data( hSCManager
, SC_HTYPE_MANAGER
);
1272 SetLastError( ERROR_INVALID_HANDLE
);
1276 r
= RegCreateKeyExW(hscm
->hkey
, lpServiceName
, 0, NULL
,
1277 REG_OPTION_NON_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &hKey
, &dp
);
1278 if (r
!=ERROR_SUCCESS
)
1281 if (dp
!= REG_CREATED_NEW_KEY
)
1283 SetLastError(ERROR_SERVICE_EXISTS
);
1288 service_set_string( &val
[n
++], szDisplayName
, lpDisplayName
);
1290 service_set_dword( &val
[n
++], szType
, &dwServiceType
);
1291 service_set_dword( &val
[n
++], szStart
, &dwStartType
);
1292 service_set_dword( &val
[n
++], szError
, &dwErrorControl
);
1294 if( lpBinaryPathName
)
1295 service_set_string( &val
[n
++], szImagePath
, lpBinaryPathName
);
1297 if( lpLoadOrderGroup
)
1298 service_set_string( &val
[n
++], szGroup
, lpLoadOrderGroup
);
1300 if( lpDependencies
)
1301 service_set_multi_string( &val
[n
++], szDependencies
, lpDependencies
);
1304 FIXME("Don't know how to add a Password for a service.\n");
1306 if( lpServiceStartName
)
1307 service_set_string( &val
[n
++], szDependOnService
, lpServiceStartName
);
1309 r
= service_write_values( hKey
, val
, n
);
1310 if( r
!= ERROR_SUCCESS
)
1313 len
= strlenW(lpServiceName
)+1;
1314 len
= sizeof (struct sc_service
) + len
*sizeof(WCHAR
);
1315 hsvc
= sc_handle_alloc( SC_HTYPE_SERVICE
, len
, sc_handle_destroy_service
);
1318 lstrcpyW( hsvc
->name
, lpServiceName
);
1321 hscm
->hdr
.ref_count
++;
1323 return (SC_HANDLE
) &hsvc
->hdr
;
1326 RegCloseKey( hKey
);
1331 /******************************************************************************
1332 * CreateServiceA [ADVAPI32.@]
1335 CreateServiceA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
1336 LPCSTR lpDisplayName
, DWORD dwDesiredAccess
,
1337 DWORD dwServiceType
, DWORD dwStartType
,
1338 DWORD dwErrorControl
, LPCSTR lpBinaryPathName
,
1339 LPCSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
,
1340 LPCSTR lpDependencies
, LPCSTR lpServiceStartName
,
1343 LPWSTR lpServiceNameW
, lpDisplayNameW
, lpBinaryPathNameW
,
1344 lpLoadOrderGroupW
, lpDependenciesW
, lpServiceStartNameW
, lpPasswordW
;
1347 TRACE("%p %s %s\n", hSCManager
,
1348 debugstr_a(lpServiceName
), debugstr_a(lpDisplayName
));
1350 lpServiceNameW
= SERV_dup( lpServiceName
);
1351 lpDisplayNameW
= SERV_dup( lpDisplayName
);
1352 lpBinaryPathNameW
= SERV_dup( lpBinaryPathName
);
1353 lpLoadOrderGroupW
= SERV_dup( lpLoadOrderGroup
);
1354 lpDependenciesW
= SERV_dupmulti( lpDependencies
);
1355 lpServiceStartNameW
= SERV_dup( lpServiceStartName
);
1356 lpPasswordW
= SERV_dup( lpPassword
);
1358 r
= CreateServiceW( hSCManager
, lpServiceNameW
, lpDisplayNameW
,
1359 dwDesiredAccess
, dwServiceType
, dwStartType
, dwErrorControl
,
1360 lpBinaryPathNameW
, lpLoadOrderGroupW
, lpdwTagId
,
1361 lpDependenciesW
, lpServiceStartNameW
, lpPasswordW
);
1363 SERV_free( lpServiceNameW
);
1364 SERV_free( lpDisplayNameW
);
1365 SERV_free( lpBinaryPathNameW
);
1366 SERV_free( lpLoadOrderGroupW
);
1367 SERV_free( lpDependenciesW
);
1368 SERV_free( lpServiceStartNameW
);
1369 SERV_free( lpPasswordW
);
1375 /******************************************************************************
1376 * DeleteService [ADVAPI32.@]
1378 * Delete a service from the service control manager database.
1381 * hService [I] Handle of the service to delete
1387 BOOL WINAPI
DeleteService( SC_HANDLE hService
)
1389 struct sc_service
*hsvc
;
1391 WCHAR valname
[MAX_PATH
+1];
1396 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1399 SetLastError( ERROR_INVALID_HANDLE
);
1405 /* Clean out the values */
1406 rc
= RegEnumValueW(hKey
, index
, valname
,&size
,0,0,0,0);
1407 while (rc
== ERROR_SUCCESS
)
1409 RegDeleteValueW(hKey
,valname
);
1412 rc
= RegEnumValueW(hKey
, index
, valname
, &size
,0,0,0,0);
1418 /* delete the key */
1419 RegDeleteKeyW(hsvc
->scm
->hkey
, hsvc
->name
);
1425 /******************************************************************************
1426 * StartServiceA [ADVAPI32.@]
1431 * hService [I] Handle of service
1432 * dwNumServiceArgs [I] Number of arguments
1433 * lpServiceArgVectors [I] Address of array of argument strings
1436 * - NT implements this function using an obscure RPC call.
1437 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1438 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1439 * - This will only work for shared address space. How should the service
1440 * args be transferred when address spaces are separated?
1441 * - Can only start one service at a time.
1442 * - Has no concept of privilege.
1448 BOOL WINAPI
StartServiceA( SC_HANDLE hService
, DWORD dwNumServiceArgs
,
1449 LPCSTR
*lpServiceArgVectors
)
1451 LPWSTR
*lpwstr
=NULL
;
1455 TRACE("(%p,%d,%p)\n",hService
,dwNumServiceArgs
,lpServiceArgVectors
);
1457 if (dwNumServiceArgs
)
1458 lpwstr
= HeapAlloc( GetProcessHeap(), 0,
1459 dwNumServiceArgs
*sizeof(LPWSTR
) );
1461 for(i
=0; i
<dwNumServiceArgs
; i
++)
1462 lpwstr
[i
]=SERV_dup(lpServiceArgVectors
[i
]);
1464 r
= StartServiceW(hService
, dwNumServiceArgs
, (LPCWSTR
*)lpwstr
);
1466 if (dwNumServiceArgs
)
1468 for(i
=0; i
<dwNumServiceArgs
; i
++)
1469 SERV_free(lpwstr
[i
]);
1470 HeapFree(GetProcessHeap(), 0, lpwstr
);
1476 /******************************************************************************
1477 * service_start_process [INTERNAL]
1479 static DWORD
service_start_process(struct sc_service
*hsvc
, LPDWORD ppid
)
1481 static const WCHAR _ImagePathW
[] = {'I','m','a','g','e','P','a','t','h',0};
1482 PROCESS_INFORMATION pi
;
1484 LPWSTR path
= NULL
, str
;
1485 DWORD type
, size
, ret
;
1489 /* read the executable path from memory */
1491 ret
= RegQueryValueExW(hsvc
->hkey
, _ImagePathW
, NULL
, &type
, NULL
, &size
);
1492 if (ret
!=ERROR_SUCCESS
)
1494 str
= HeapAlloc(GetProcessHeap(),0,size
);
1495 ret
= RegQueryValueExW(hsvc
->hkey
, _ImagePathW
, NULL
, &type
, (LPBYTE
)str
, &size
);
1496 if (ret
==ERROR_SUCCESS
)
1498 size
= ExpandEnvironmentStringsW(str
,NULL
,0);
1499 path
= HeapAlloc(GetProcessHeap(),0,size
*sizeof(WCHAR
));
1500 ExpandEnvironmentStringsW(str
,path
,size
);
1502 HeapFree(GetProcessHeap(),0,str
);
1506 /* wait for the process to start and set an event or terminate */
1507 handles
[0] = service_get_event_handle( hsvc
->name
);
1508 ZeroMemory(&si
, sizeof(STARTUPINFOW
));
1509 si
.cb
= sizeof(STARTUPINFOW
);
1510 r
= CreateProcessW(NULL
, path
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
1513 if (ppid
) *ppid
= pi
.dwProcessId
;
1515 handles
[1] = pi
.hProcess
;
1516 ret
= WaitForMultipleObjectsEx(2, handles
, FALSE
, 30000, FALSE
);
1517 if(ret
!= WAIT_OBJECT_0
)
1519 SetLastError(ERROR_IO_PENDING
);
1523 CloseHandle( pi
.hThread
);
1524 CloseHandle( pi
.hProcess
);
1526 CloseHandle( handles
[0] );
1527 HeapFree(GetProcessHeap(),0,path
);
1531 static BOOL
service_wait_for_startup(SC_HANDLE hService
)
1534 SERVICE_STATUS status
;
1537 TRACE("%p\n", hService
);
1539 for (i
=0; i
<30; i
++)
1541 status
.dwCurrentState
= 0;
1542 r
= QueryServiceStatus(hService
, &status
);
1545 if (status
.dwCurrentState
== SERVICE_RUNNING
)
1547 TRACE("Service started successfully\n");
1556 /******************************************************************************
1557 * StartServiceW [ADVAPI32.@]
1559 * See StartServiceA.
1561 BOOL WINAPI
StartServiceW(SC_HANDLE hService
, DWORD dwNumServiceArgs
,
1562 LPCWSTR
*lpServiceArgVectors
)
1564 struct sc_service
*hsvc
;
1566 DWORD dwResult
, dwProcessId
= 0;
1568 HANDLE handle
= INVALID_HANDLE_VALUE
;
1570 TRACE("%p %d %p\n", hService
, dwNumServiceArgs
, lpServiceArgVectors
);
1572 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1575 SetLastError(ERROR_INVALID_HANDLE
);
1579 hLock
= LockServiceDatabase((SC_HANDLE
)hsvc
->scm
);
1583 handle
= service_open_pipe(hsvc
->name
);
1584 if (handle
==INVALID_HANDLE_VALUE
)
1586 /* start the service process */
1587 if (service_start_process(hsvc
, &dwProcessId
))
1588 handle
= service_open_pipe(hsvc
->name
);
1591 if (handle
!= INVALID_HANDLE_VALUE
)
1593 r
= service_send_start_message(handle
, lpServiceArgVectors
, dwNumServiceArgs
);
1594 CloseHandle(handle
);
1597 handle
= service_open_pipe(hsvc
->name
);
1598 if (handle
!= INVALID_HANDLE_VALUE
)
1600 service_set_processID(handle
, dwProcessId
, &dwResult
);
1601 CloseHandle(handle
);
1604 UnlockServiceDatabase( hLock
);
1606 TRACE("returning %d\n", r
);
1609 service_wait_for_startup(hService
);
1614 /******************************************************************************
1615 * QueryServiceStatus [ADVAPI32.@]
1618 * hService [I] Handle to service to get information about
1619 * lpservicestatus [O] buffer to receive the status information for the service
1622 BOOL WINAPI
QueryServiceStatus(SC_HANDLE hService
,
1623 LPSERVICE_STATUS lpservicestatus
)
1625 SERVICE_STATUS_PROCESS SvcStatusData
;
1628 TRACE("%p %p\n", hService
, lpservicestatus
);
1630 ret
= QueryServiceStatusEx(hService
, SC_STATUS_PROCESS_INFO
, (LPBYTE
)&SvcStatusData
,
1631 sizeof(SERVICE_STATUS_PROCESS
), NULL
);
1632 if (ret
) memcpy(lpservicestatus
, &SvcStatusData
, sizeof(SERVICE_STATUS
)) ;
1637 /******************************************************************************
1638 * QueryServiceStatusEx [ADVAPI32.@]
1640 * Get information about a service.
1643 * hService [I] Handle to service to get information about
1644 * InfoLevel [I] Level of information to get
1645 * lpBuffer [O] Destination for requested information
1646 * cbBufSize [I] Size of lpBuffer in bytes
1647 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1653 BOOL WINAPI
QueryServiceStatusEx(SC_HANDLE hService
, SC_STATUS_TYPE InfoLevel
,
1654 LPBYTE lpBuffer
, DWORD cbBufSize
,
1655 LPDWORD pcbBytesNeeded
)
1657 struct sc_service
*hsvc
;
1658 DWORD size
, type
, val
;
1661 LPSERVICE_STATUS_PROCESS pSvcStatusData
;
1663 TRACE("%p %d %p %d %p\n", hService
, InfoLevel
, lpBuffer
, cbBufSize
, pcbBytesNeeded
);
1665 if (InfoLevel
!= SC_STATUS_PROCESS_INFO
)
1667 SetLastError( ERROR_INVALID_LEVEL
);
1671 pSvcStatusData
= (LPSERVICE_STATUS_PROCESS
) lpBuffer
;
1672 if (pSvcStatusData
== NULL
)
1674 SetLastError( ERROR_INVALID_PARAMETER
);
1678 if (cbBufSize
< sizeof(SERVICE_STATUS_PROCESS
))
1680 if( pcbBytesNeeded
!= NULL
)
1681 *pcbBytesNeeded
= sizeof(SERVICE_STATUS_PROCESS
);
1683 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1687 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1690 SetLastError( ERROR_INVALID_HANDLE
);
1694 pipe
= service_open_pipe(hsvc
->name
);
1695 if (pipe
!= INVALID_HANDLE_VALUE
)
1697 r
= service_get_status(pipe
, pSvcStatusData
);
1703 TRACE("Failed to read service status\n");
1705 /* read the service type from the registry */
1707 r
= RegQueryValueExA(hsvc
->hkey
, "Type", NULL
, &type
, (LPBYTE
)&val
, &size
);
1708 if (r
!= ERROR_SUCCESS
|| type
!= REG_DWORD
)
1711 pSvcStatusData
->dwServiceType
= val
;
1712 pSvcStatusData
->dwCurrentState
= SERVICE_STOPPED
; /* stopped */
1713 pSvcStatusData
->dwControlsAccepted
= 0;
1714 pSvcStatusData
->dwWin32ExitCode
= ERROR_SERVICE_NEVER_STARTED
;
1715 pSvcStatusData
->dwServiceSpecificExitCode
= 0;
1716 pSvcStatusData
->dwCheckPoint
= 0;
1717 pSvcStatusData
->dwWaitHint
= 0;
1722 /******************************************************************************
1723 * QueryServiceConfigA [ADVAPI32.@]
1725 BOOL WINAPI
QueryServiceConfigA( SC_HANDLE hService
, LPQUERY_SERVICE_CONFIGA config
,
1726 DWORD size
, LPDWORD needed
)
1731 QUERY_SERVICE_CONFIGW
*configW
;
1733 TRACE("%p %p %d %p\n", hService
, config
, size
, needed
);
1735 if (!(buffer
= HeapAlloc( GetProcessHeap(), 0, 2 * size
)))
1737 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1740 configW
= (QUERY_SERVICE_CONFIGW
*)buffer
;
1741 ret
= QueryServiceConfigW( hService
, configW
, 2 * size
, needed
);
1742 if (!ret
) goto done
;
1744 config
->dwServiceType
= configW
->dwServiceType
;
1745 config
->dwStartType
= configW
->dwStartType
;
1746 config
->dwErrorControl
= configW
->dwErrorControl
;
1747 config
->lpBinaryPathName
= NULL
;
1748 config
->lpLoadOrderGroup
= NULL
;
1749 config
->dwTagId
= configW
->dwTagId
;
1750 config
->lpDependencies
= NULL
;
1751 config
->lpServiceStartName
= NULL
;
1752 config
->lpDisplayName
= NULL
;
1754 p
= (LPSTR
)(config
+ 1);
1755 n
= size
- sizeof(*config
);
1758 #define MAP_STR(str) \
1762 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1763 if (!sz) goto done; \
1770 MAP_STR( lpBinaryPathName
);
1771 MAP_STR( lpLoadOrderGroup
);
1772 MAP_STR( lpDependencies
);
1773 MAP_STR( lpServiceStartName
);
1774 MAP_STR( lpDisplayName
);
1777 *needed
= p
- buffer
;
1781 HeapFree( GetProcessHeap(), 0, buffer
);
1785 /******************************************************************************
1786 * QueryServiceConfigW [ADVAPI32.@]
1789 QueryServiceConfigW( SC_HANDLE hService
,
1790 LPQUERY_SERVICE_CONFIGW lpServiceConfig
,
1791 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
1793 WCHAR str_buffer
[ MAX_PATH
];
1795 DWORD type
, val
, sz
, total
, n
;
1798 struct sc_service
*hsvc
;
1800 TRACE("%p %p %d %p\n", hService
, lpServiceConfig
,
1801 cbBufSize
, pcbBytesNeeded
);
1803 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1806 SetLastError( ERROR_INVALID_HANDLE
);
1811 /* calculate the size required first */
1812 total
= sizeof (QUERY_SERVICE_CONFIGW
);
1814 sz
= sizeof(str_buffer
);
1815 r
= RegQueryValueExW( hKey
, szImagePath
, 0, &type
, (LPBYTE
) str_buffer
, &sz
);
1816 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
|| type
== REG_EXPAND_SZ
) )
1818 sz
= ExpandEnvironmentStringsW(str_buffer
,NULL
,0);
1819 if( 0 == sz
) return FALSE
;
1821 total
+= sizeof(WCHAR
) * sz
;
1825 /* FIXME: set last error */
1830 r
= RegQueryValueExW( hKey
, szGroup
, 0, &type
, NULL
, &sz
);
1831 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1835 r
= RegQueryValueExW( hKey
, szDependencies
, 0, &type
, NULL
, &sz
);
1836 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_MULTI_SZ
) )
1839 total
+= sizeof(WCHAR
);
1842 r
= RegQueryValueExW( hKey
, szStart
, 0, &type
, NULL
, &sz
);
1843 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1847 r
= RegQueryValueExW( hKey
, szDisplayName
, 0, &type
, NULL
, &sz
);
1848 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1851 *pcbBytesNeeded
= total
;
1853 /* if there's not enough memory, return an error */
1854 if( total
> cbBufSize
)
1856 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1860 ZeroMemory( lpServiceConfig
, total
);
1863 r
= RegQueryValueExW( hKey
, szType
, 0, &type
, (LPBYTE
)&val
, &sz
);
1864 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_DWORD
) )
1865 lpServiceConfig
->dwServiceType
= val
;
1868 r
= RegQueryValueExW( hKey
, szStart
, 0, &type
, (LPBYTE
)&val
, &sz
);
1869 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_DWORD
) )
1870 lpServiceConfig
->dwStartType
= val
;
1873 r
= RegQueryValueExW( hKey
, szError
, 0, &type
, (LPBYTE
)&val
, &sz
);
1874 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_DWORD
) )
1875 lpServiceConfig
->dwErrorControl
= val
;
1877 /* now do the strings */
1878 p
= (LPBYTE
) &lpServiceConfig
[1];
1879 n
= total
- sizeof (QUERY_SERVICE_CONFIGW
);
1881 sz
= sizeof(str_buffer
);
1882 r
= RegQueryValueExW( hKey
, szImagePath
, 0, &type
, (LPBYTE
) str_buffer
, &sz
);
1883 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
|| type
== REG_EXPAND_SZ
) )
1885 sz
= ExpandEnvironmentStringsW(str_buffer
, (LPWSTR
) p
, n
);
1886 sz
*= sizeof(WCHAR
);
1887 if( 0 == sz
|| sz
> n
) return FALSE
;
1889 lpServiceConfig
->lpBinaryPathName
= (LPWSTR
) p
;
1895 /* FIXME: set last error */
1900 r
= RegQueryValueExW( hKey
, szGroup
, 0, &type
, p
, &sz
);
1901 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_SZ
) )
1903 lpServiceConfig
->lpLoadOrderGroup
= (LPWSTR
) p
;
1909 r
= RegQueryValueExW( hKey
, szDependencies
, 0, &type
, p
, &sz
);
1910 lpServiceConfig
->lpDependencies
= (LPWSTR
) p
;
1911 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_SZ
) )
1924 ERR("Buffer overflow!\n");
1926 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig
->lpBinaryPathName
) );
1927 TRACE("Group = %s\n", debugstr_w(lpServiceConfig
->lpLoadOrderGroup
) );
1932 /******************************************************************************
1933 * EnumServicesStatusA [ADVAPI32.@]
1936 EnumServicesStatusA( SC_HANDLE hSCManager
, DWORD dwServiceType
,
1937 DWORD dwServiceState
, LPENUM_SERVICE_STATUSA lpServices
,
1938 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
1939 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
)
1941 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager
,
1942 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
1943 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
);
1944 SetLastError (ERROR_ACCESS_DENIED
);
1948 /******************************************************************************
1949 * EnumServicesStatusW [ADVAPI32.@]
1952 EnumServicesStatusW( SC_HANDLE hSCManager
, DWORD dwServiceType
,
1953 DWORD dwServiceState
, LPENUM_SERVICE_STATUSW lpServices
,
1954 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
1955 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
)
1957 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager
,
1958 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
1959 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
);
1960 SetLastError (ERROR_ACCESS_DENIED
);
1964 /******************************************************************************
1965 * EnumServicesStatusExA [ADVAPI32.@]
1968 EnumServicesStatusExA(SC_HANDLE hSCManager
, SC_ENUM_TYPE InfoLevel
, DWORD dwServiceType
,
1969 DWORD dwServiceState
, LPBYTE lpServices
, DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
1970 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
, LPCSTR pszGroupName
)
1972 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager
, InfoLevel
,
1973 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
1974 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
, debugstr_a(pszGroupName
));
1975 SetLastError (ERROR_ACCESS_DENIED
);
1979 /******************************************************************************
1980 * EnumServicesStatusExW [ADVAPI32.@]
1983 EnumServicesStatusExW(SC_HANDLE hSCManager
, SC_ENUM_TYPE InfoLevel
, DWORD dwServiceType
,
1984 DWORD dwServiceState
, LPBYTE lpServices
, DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
1985 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
, LPCWSTR pszGroupName
)
1987 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager
, InfoLevel
,
1988 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
1989 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
, debugstr_w(pszGroupName
));
1990 SetLastError (ERROR_ACCESS_DENIED
);
1994 /******************************************************************************
1995 * GetServiceKeyNameA [ADVAPI32.@]
1997 BOOL WINAPI
GetServiceKeyNameA( SC_HANDLE hSCManager
, LPCSTR lpDisplayName
,
1998 LPSTR lpServiceName
, LPDWORD lpcchBuffer
)
2000 FIXME("%p %s %p %p\n", hSCManager
, debugstr_a(lpDisplayName
), lpServiceName
, lpcchBuffer
);
2004 /******************************************************************************
2005 * GetServiceKeyNameW [ADVAPI32.@]
2007 BOOL WINAPI
GetServiceKeyNameW( SC_HANDLE hSCManager
, LPCWSTR lpDisplayName
,
2008 LPWSTR lpServiceName
, LPDWORD lpcchBuffer
)
2010 FIXME("%p %s %p %p\n", hSCManager
, debugstr_w(lpDisplayName
), lpServiceName
, lpcchBuffer
);
2014 /******************************************************************************
2015 * QueryServiceLockStatusA [ADVAPI32.@]
2017 BOOL WINAPI
QueryServiceLockStatusA( SC_HANDLE hSCManager
,
2018 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus
,
2019 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
2021 FIXME("%p %p %08x %p\n", hSCManager
, lpLockStatus
, cbBufSize
, pcbBytesNeeded
);
2026 /******************************************************************************
2027 * QueryServiceLockStatusW [ADVAPI32.@]
2029 BOOL WINAPI
QueryServiceLockStatusW( SC_HANDLE hSCManager
,
2030 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus
,
2031 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
2033 FIXME("%p %p %08x %p\n", hSCManager
, lpLockStatus
, cbBufSize
, pcbBytesNeeded
);
2038 /******************************************************************************
2039 * GetServiceDisplayNameA [ADVAPI32.@]
2041 BOOL WINAPI
GetServiceDisplayNameA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
2042 LPSTR lpDisplayName
, LPDWORD lpcchBuffer
)
2044 struct sc_manager
*hscm
;
2048 TRACE("%p %s %p %p\n", hSCManager
,
2049 debugstr_a(lpServiceName
), lpDisplayName
, lpcchBuffer
);
2051 hscm
= sc_handle_get_handle_data(hSCManager
, SC_HTYPE_MANAGER
);
2054 SetLastError(ERROR_INVALID_HANDLE
);
2058 size
= *lpcchBuffer
;
2059 ret
= RegGetValueA(hscm
->hkey
, lpServiceName
, "DisplayName", RRF_RT_REG_SZ
, &type
, lpDisplayName
, &size
);
2062 if (lpDisplayName
&& *lpcchBuffer
) *lpDisplayName
= 0;
2064 if (ret
== ERROR_MORE_DATA
)
2066 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2067 *lpcchBuffer
= size
- 1;
2076 /******************************************************************************
2077 * GetServiceDisplayNameW [ADVAPI32.@]
2079 BOOL WINAPI
GetServiceDisplayNameW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
2080 LPWSTR lpDisplayName
, LPDWORD lpcchBuffer
)
2082 struct sc_manager
*hscm
;
2086 TRACE("%p %s %p %p\n", hSCManager
,
2087 debugstr_w(lpServiceName
), lpDisplayName
, lpcchBuffer
);
2089 hscm
= sc_handle_get_handle_data(hSCManager
, SC_HTYPE_MANAGER
);
2092 SetLastError(ERROR_INVALID_HANDLE
);
2096 size
= *lpcchBuffer
* sizeof(WCHAR
);
2097 ret
= RegGetValueW(hscm
->hkey
, lpServiceName
, szDisplayName
, RRF_RT_REG_SZ
, &type
, lpDisplayName
, &size
);
2100 if (lpDisplayName
&& *lpcchBuffer
) *lpDisplayName
= 0;
2102 if (ret
== ERROR_MORE_DATA
)
2104 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2105 *lpcchBuffer
= (size
/ sizeof(WCHAR
)) - 1;
2114 /******************************************************************************
2115 * ChangeServiceConfigW [ADVAPI32.@]
2117 BOOL WINAPI
ChangeServiceConfigW( SC_HANDLE hService
, DWORD dwServiceType
,
2118 DWORD dwStartType
, DWORD dwErrorControl
, LPCWSTR lpBinaryPathName
,
2119 LPCWSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
, LPCWSTR lpDependencies
,
2120 LPCWSTR lpServiceStartName
, LPCWSTR lpPassword
, LPCWSTR lpDisplayName
)
2122 struct reg_value val
[10];
2123 struct sc_service
*hsvc
;
2124 DWORD r
= ERROR_SUCCESS
;
2128 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2129 hService
, dwServiceType
, dwStartType
, dwErrorControl
,
2130 debugstr_w(lpBinaryPathName
), debugstr_w(lpLoadOrderGroup
),
2131 lpdwTagId
, lpDependencies
, debugstr_w(lpServiceStartName
),
2132 debugstr_w(lpPassword
), debugstr_w(lpDisplayName
) );
2134 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
2137 SetLastError( ERROR_INVALID_HANDLE
);
2142 if( dwServiceType
!= SERVICE_NO_CHANGE
)
2143 service_set_dword( &val
[n
++], szType
, &dwServiceType
);
2145 if( dwStartType
!= SERVICE_NO_CHANGE
)
2146 service_set_dword( &val
[n
++], szStart
, &dwStartType
);
2148 if( dwErrorControl
!= SERVICE_NO_CHANGE
)
2149 service_set_dword( &val
[n
++], szError
, &dwErrorControl
);
2151 if( lpBinaryPathName
)
2152 service_set_string( &val
[n
++], szImagePath
, lpBinaryPathName
);
2154 if( lpLoadOrderGroup
)
2155 service_set_string( &val
[n
++], szGroup
, lpLoadOrderGroup
);
2157 if( lpDependencies
)
2158 service_set_multi_string( &val
[n
++], szDependencies
, lpDependencies
);
2161 FIXME("ignoring password\n");
2163 if( lpServiceStartName
)
2164 service_set_string( &val
[n
++], szDependOnService
, lpServiceStartName
);
2166 r
= service_write_values( hsvc
->hkey
, val
, n
);
2168 return (r
== ERROR_SUCCESS
) ? TRUE
: FALSE
;
2171 /******************************************************************************
2172 * ChangeServiceConfigA [ADVAPI32.@]
2174 BOOL WINAPI
ChangeServiceConfigA( SC_HANDLE hService
, DWORD dwServiceType
,
2175 DWORD dwStartType
, DWORD dwErrorControl
, LPCSTR lpBinaryPathName
,
2176 LPCSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
, LPCSTR lpDependencies
,
2177 LPCSTR lpServiceStartName
, LPCSTR lpPassword
, LPCSTR lpDisplayName
)
2179 LPWSTR wBinaryPathName
, wLoadOrderGroup
, wDependencies
;
2180 LPWSTR wServiceStartName
, wPassword
, wDisplayName
;
2183 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2184 hService
, dwServiceType
, dwStartType
, dwErrorControl
,
2185 debugstr_a(lpBinaryPathName
), debugstr_a(lpLoadOrderGroup
),
2186 lpdwTagId
, lpDependencies
, debugstr_a(lpServiceStartName
),
2187 debugstr_a(lpPassword
), debugstr_a(lpDisplayName
) );
2189 wBinaryPathName
= SERV_dup( lpBinaryPathName
);
2190 wLoadOrderGroup
= SERV_dup( lpLoadOrderGroup
);
2191 wDependencies
= SERV_dupmulti( lpDependencies
);
2192 wServiceStartName
= SERV_dup( lpServiceStartName
);
2193 wPassword
= SERV_dup( lpPassword
);
2194 wDisplayName
= SERV_dup( lpDisplayName
);
2196 r
= ChangeServiceConfigW( hService
, dwServiceType
,
2197 dwStartType
, dwErrorControl
, wBinaryPathName
,
2198 wLoadOrderGroup
, lpdwTagId
, wDependencies
,
2199 wServiceStartName
, wPassword
, wDisplayName
);
2201 SERV_free( wBinaryPathName
);
2202 SERV_free( wLoadOrderGroup
);
2203 SERV_free( wDependencies
);
2204 SERV_free( wServiceStartName
);
2205 SERV_free( wPassword
);
2206 SERV_free( wDisplayName
);
2211 /******************************************************************************
2212 * ChangeServiceConfig2A [ADVAPI32.@]
2214 BOOL WINAPI
ChangeServiceConfig2A( SC_HANDLE hService
, DWORD dwInfoLevel
,
2219 TRACE("%p %d %p\n",hService
, dwInfoLevel
, lpInfo
);
2221 if (dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
2223 LPSERVICE_DESCRIPTIONA sd
= (LPSERVICE_DESCRIPTIONA
) lpInfo
;
2224 SERVICE_DESCRIPTIONW sdw
;
2226 sdw
.lpDescription
= SERV_dup( sd
->lpDescription
);
2228 r
= ChangeServiceConfig2W( hService
, dwInfoLevel
, &sdw
);
2230 SERV_free( sdw
.lpDescription
);
2232 else if (dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
2234 LPSERVICE_FAILURE_ACTIONSA fa
= (LPSERVICE_FAILURE_ACTIONSA
) lpInfo
;
2235 SERVICE_FAILURE_ACTIONSW faw
;
2237 faw
.dwResetPeriod
= fa
->dwResetPeriod
;
2238 faw
.lpRebootMsg
= SERV_dup( fa
->lpRebootMsg
);
2239 faw
.lpCommand
= SERV_dup( fa
->lpCommand
);
2240 faw
.cActions
= fa
->cActions
;
2241 faw
.lpsaActions
= fa
->lpsaActions
;
2243 r
= ChangeServiceConfig2W( hService
, dwInfoLevel
, &faw
);
2245 SERV_free( faw
.lpRebootMsg
);
2246 SERV_free( faw
.lpCommand
);
2249 SetLastError( ERROR_INVALID_PARAMETER
);
2254 /******************************************************************************
2255 * ChangeServiceConfig2W [ADVAPI32.@]
2257 BOOL WINAPI
ChangeServiceConfig2W( SC_HANDLE hService
, DWORD dwInfoLevel
,
2261 struct sc_service
*hsvc
;
2263 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
2266 SetLastError( ERROR_INVALID_HANDLE
);
2271 if (dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
2273 static const WCHAR szDescription
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2274 LPSERVICE_DESCRIPTIONW sd
= (LPSERVICE_DESCRIPTIONW
)lpInfo
;
2275 if (sd
->lpDescription
)
2277 TRACE("Setting Description to %s\n",debugstr_w(sd
->lpDescription
));
2278 if (sd
->lpDescription
[0] == 0)
2279 RegDeleteValueW(hKey
,szDescription
);
2281 RegSetValueExW(hKey
, szDescription
, 0, REG_SZ
,
2282 (LPVOID
)sd
->lpDescription
,
2283 sizeof(WCHAR
)*(strlenW(sd
->lpDescription
)+1));
2287 FIXME("STUB: %p %d %p\n",hService
, dwInfoLevel
, lpInfo
);
2291 /******************************************************************************
2292 * QueryServiceObjectSecurity [ADVAPI32.@]
2294 BOOL WINAPI
QueryServiceObjectSecurity(SC_HANDLE hService
,
2295 SECURITY_INFORMATION dwSecurityInformation
,
2296 PSECURITY_DESCRIPTOR lpSecurityDescriptor
,
2297 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
2301 FIXME("%p %d %p %u %p\n", hService
, dwSecurityInformation
,
2302 lpSecurityDescriptor
, cbBufSize
, pcbBytesNeeded
);
2304 InitializeSecurityDescriptor(lpSecurityDescriptor
, SECURITY_DESCRIPTOR_REVISION
);
2306 pACL
= HeapAlloc( GetProcessHeap(), 0, sizeof(ACL
) );
2307 InitializeAcl(pACL
, sizeof(ACL
), ACL_REVISION
);
2308 SetSecurityDescriptorDacl(lpSecurityDescriptor
, TRUE
, pACL
, TRUE
);
2312 /******************************************************************************
2313 * SetServiceObjectSecurity [ADVAPI32.@]
2315 BOOL WINAPI
SetServiceObjectSecurity(SC_HANDLE hService
,
2316 SECURITY_INFORMATION dwSecurityInformation
,
2317 PSECURITY_DESCRIPTOR lpSecurityDescriptor
)
2319 FIXME("%p %d %p\n", hService
, dwSecurityInformation
, lpSecurityDescriptor
);
2323 /******************************************************************************
2324 * SetServiceBits [ADVAPI32.@]
2326 BOOL WINAPI
SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus
,
2327 DWORD dwServiceBits
,
2329 BOOL bUpdateImmediately
)
2331 FIXME("%p %08x %x %x\n", hServiceStatus
, dwServiceBits
,
2332 bSetBitsOn
, bUpdateImmediately
);
2336 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerExA( LPCSTR lpServiceName
,
2337 LPHANDLER_FUNCTION_EX lpHandlerProc
, LPVOID lpContext
)
2339 FIXME("%s %p %p\n", debugstr_a(lpServiceName
), lpHandlerProc
, lpContext
);
2343 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName
,
2344 LPHANDLER_FUNCTION_EX lpHandlerProc
, LPVOID lpContext
)
2346 service_data
*service
;
2348 TRACE("%s %p %p\n", debugstr_w(lpServiceName
), lpHandlerProc
, lpContext
);
2350 EnterCriticalSection( &service_cs
);
2351 for(service
= service_list
; service
; service
= service
->next
)
2352 if(!strcmpW(lpServiceName
, service
->name
))
2356 service
->handler
.handler_ex
= lpHandlerProc
;
2357 service
->context
= lpContext
;
2358 service
->extended
= TRUE
;
2360 LeaveCriticalSection( &service_cs
);
2362 return (SERVICE_STATUS_HANDLE
)service
;