2 * Win32 advapi functions
4 * Copyright 1995 Sven Verdoolaege
5 * Copyright 2005 Mike McCormack
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32 #include "wine/unicode.h"
33 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(advapi
);
38 static const WCHAR szServiceManagerKey
[] = { 'S','y','s','t','e','m','\\',
39 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
40 'S','e','r','v','i','c','e','s','\\',0 };
41 static const WCHAR szSCMLock
[] = {'A','D','V','A','P','I','_','S','C','M',
44 typedef struct service_start_info_t
51 #define WINESERV_STARTINFO 1
52 #define WINESERV_GETSTATUS 2
53 #define WINESERV_SENDCONTROL 3
55 typedef struct service_data_t
57 struct service_data_t
*next
;
58 LPHANDLER_FUNCTION handler
;
59 SERVICE_STATUS status
;
63 LPSERVICE_MAIN_FUNCTIONA a
;
64 LPSERVICE_MAIN_FUNCTIONW w
;
70 static CRITICAL_SECTION service_cs
;
71 static CRITICAL_SECTION_DEBUG service_cs_debug
=
74 { &service_cs_debug
.ProcessLocksList
,
75 &service_cs_debug
.ProcessLocksList
},
76 0, 0, { 0, (DWORD
)(__FILE__
": service_cs") }
78 static CRITICAL_SECTION service_cs
= { &service_cs_debug
, -1, 0, 0, 0, 0 };
80 service_data
*service_list
;
82 /******************************************************************************
86 #define MAX_SERVICE_NAME 256
88 typedef enum { SC_HTYPE_MANAGER
, SC_HTYPE_SERVICE
} SC_HANDLE_TYPE
;
91 typedef VOID (*sc_handle_destructor
)(struct sc_handle
*);
97 sc_handle_destructor destroy
;
100 struct sc_manager
/* service control manager handle */
102 struct sc_handle hdr
;
103 HKEY hkey
; /* handle to services database in the registry */
106 struct sc_service
/* service handle */
108 struct sc_handle hdr
;
109 HKEY hkey
; /* handle to service entry in the registry (under hkey) */
110 struct sc_manager
*scm
; /* pointer to SCM handle */
114 static void *sc_handle_alloc(SC_HANDLE_TYPE htype
, DWORD size
,
115 sc_handle_destructor destroy
)
117 struct sc_handle
*hdr
;
119 hdr
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
124 hdr
->destroy
= destroy
;
126 TRACE("sc_handle type=%d -> %p\n", htype
, hdr
);
130 static void *sc_handle_get_handle_data(SC_HANDLE handle
, DWORD htype
)
132 struct sc_handle
*hdr
= (struct sc_handle
*) handle
;
136 if (hdr
->htype
!= htype
)
141 static void sc_handle_free(struct sc_handle
* hdr
)
145 if (--hdr
->ref_count
)
148 HeapFree(GetProcessHeap(), 0, hdr
);
151 static void sc_handle_destroy_manager(struct sc_handle
*handle
)
153 struct sc_manager
*mgr
= (struct sc_manager
*) handle
;
155 TRACE("destroying SC Manager %p\n", mgr
);
157 RegCloseKey(mgr
->hkey
);
160 static void sc_handle_destroy_service(struct sc_handle
*handle
)
162 struct sc_service
*svc
= (struct sc_service
*) handle
;
164 TRACE("destroying service %p\n", svc
);
166 RegCloseKey(svc
->hkey
);
168 sc_handle_free(&svc
->scm
->hdr
);
172 /******************************************************************************
173 * String management functions
175 static inline LPWSTR
SERV_dup( LPCSTR str
)
182 len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
183 wstr
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof (WCHAR
) );
184 MultiByteToWideChar( CP_ACP
, 0, str
, -1, wstr
, len
);
188 static inline LPWSTR
SERV_dupmulti(LPCSTR str
)
196 len
+= MultiByteToWideChar( CP_ACP
, 0, &str
[n
], -1, NULL
, 0 );
197 n
+= (strlen( &str
[n
] ) + 1);
202 wstr
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof (WCHAR
) );
203 MultiByteToWideChar( CP_ACP
, 0, str
, n
, wstr
, len
);
207 static inline VOID
SERV_free( LPWSTR wstr
)
209 HeapFree( GetProcessHeap(), 0, wstr
);
213 /******************************************************************************
214 * Service IPC functions
216 static LPWSTR
service_get_pipe_name(LPWSTR service
)
218 static const WCHAR prefix
[] = { '\\','\\','.','\\','p','i','p','e','\\',
219 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
223 len
= sizeof prefix
+ strlenW(service
)*sizeof(WCHAR
);
224 name
= HeapAlloc(GetProcessHeap(), 0, len
);
225 strcpyW(name
, prefix
);
226 strcatW(name
, service
);
230 static HANDLE
service_open_pipe(LPWSTR service
)
232 LPWSTR szPipe
= service_get_pipe_name( service
);
233 HANDLE handle
= INVALID_HANDLE_VALUE
;
236 handle
= CreateFileW(szPipe
, GENERIC_READ
|GENERIC_WRITE
,
237 0, NULL
, OPEN_ALWAYS
, 0, NULL
);
238 if (handle
!= INVALID_HANDLE_VALUE
)
240 if (GetLastError() != ERROR_PIPE_BUSY
)
242 } while (WaitNamedPipeW(szPipe
, NMPWAIT_WAIT_FOREVER
));
248 /******************************************************************************
249 * service_get_event_handle
251 static HANDLE
service_get_event_handle(LPWSTR service
)
253 static const WCHAR prefix
[] = {
254 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
259 len
= sizeof prefix
+ strlenW(service
)*sizeof(WCHAR
);
260 name
= HeapAlloc(GetProcessHeap(), 0, len
);
261 strcpyW(name
, prefix
);
262 strcatW(name
, service
);
263 handle
= CreateEventW(NULL
, TRUE
, FALSE
, name
);
268 /******************************************************************************
271 * Call into the main service routine provided by StartServiceCtrlDispatcher.
273 static DWORD WINAPI
service_thread(LPVOID arg
)
275 service_data
*info
= arg
;
276 LPWSTR str
= info
->args
;
277 DWORD argc
= 0, len
= 0;
283 len
+= strlenW(&str
[len
]) + 1;
291 argv
= HeapAlloc(GetProcessHeap(), 0, (argc
+1)*sizeof(LPWSTR
));
292 for (argc
=0, p
=str
; *p
; p
+= strlenW(p
) + 1)
296 info
->proc
.w(argc
, argv
);
297 HeapFree(GetProcessHeap(), 0, argv
);
301 LPSTR strA
, *argv
, p
;
304 lenA
= WideCharToMultiByte(CP_ACP
,0, str
, len
, NULL
, 0, NULL
, NULL
);
305 strA
= HeapAlloc(GetProcessHeap(), 0, lenA
);
306 WideCharToMultiByte(CP_ACP
,0, str
, len
, strA
, lenA
, NULL
, NULL
);
308 argv
= HeapAlloc(GetProcessHeap(), 0, (argc
+1)*sizeof(LPSTR
));
309 for (argc
=0, p
=strA
; *p
; p
+= strlen(p
) + 1)
313 info
->proc
.a(argc
, argv
);
314 HeapFree(GetProcessHeap(), 0, argv
);
315 HeapFree(GetProcessHeap(), 0, strA
);
320 /******************************************************************************
321 * service_handle_start
323 static BOOL
service_handle_start(HANDLE pipe
, service_data
*service
, DWORD count
)
325 DWORD read
= 0, result
= 0;
329 TRACE("%p %p %ld\n", pipe
, service
, count
);
331 args
= HeapAlloc(GetProcessHeap(), 0, count
*sizeof(WCHAR
));
332 r
= ReadFile(pipe
, args
, count
*sizeof(WCHAR
), &read
, NULL
);
333 if (!r
|| count
!=read
/sizeof(WCHAR
) || args
[count
-1])
335 ERR("pipe read failed r = %d count = %ld/%ld args[n-1]=%s\n",
336 r
, count
, read
/sizeof(WCHAR
), debugstr_wn(args
, count
));
342 ERR("service is not stopped\n");
347 SERV_free(service
->args
);
348 service
->args
= args
;
350 service
->thread
= CreateThread( NULL
, 0, service_thread
,
354 HeapFree(GetProcessHeap(), 0, args
);
355 WriteFile( pipe
, &result
, sizeof result
, &read
, NULL
);
360 /******************************************************************************
361 * service_send_start_message
363 static BOOL
service_send_start_message(HANDLE pipe
, LPCWSTR
*argv
, DWORD argc
)
365 DWORD i
, len
, count
, result
;
366 service_start_info
*ssi
;
370 TRACE("%p %p %ld\n", pipe
, argv
, argc
);
372 /* calculate how much space do we need to send the startup info */
374 for (i
=0; i
<argc
; i
++)
375 len
+= strlenW(argv
[i
])+1;
377 ssi
= HeapAlloc(GetProcessHeap(),0,sizeof *ssi
+ (len
-1)*sizeof(WCHAR
));
378 ssi
->cmd
= WINESERV_STARTINFO
;
381 /* copy service args into a single buffer*/
383 for (i
=0; i
<argc
; i
++)
390 r
= WriteFile(pipe
, ssi
, sizeof *ssi
+ len
*sizeof(WCHAR
), &count
, NULL
);
392 r
= ReadFile(pipe
, &result
, sizeof result
, &count
, NULL
);
394 HeapFree(GetProcessHeap(),0,ssi
);
399 /******************************************************************************
400 * service_handle_get_status
402 static BOOL
service_handle_get_status(HANDLE pipe
, service_data
*service
)
406 return WriteFile(pipe
, &service
->status
,
407 sizeof service
->status
, &count
, NULL
);
410 /******************************************************************************
413 static BOOL
service_get_status(HANDLE pipe
, LPSERVICE_STATUS status
)
415 DWORD cmd
[2], count
= 0;
418 cmd
[0] = WINESERV_GETSTATUS
;
420 r
= WriteFile( pipe
, cmd
, sizeof cmd
, &count
, NULL
);
421 if (!r
|| count
!= sizeof cmd
)
423 ERR("service protocol error - failed to write pipe!\n");
426 r
= ReadFile( pipe
, status
, sizeof *status
, &count
, NULL
);
427 if (!r
|| count
!= sizeof *status
)
428 ERR("service protocol error - failed to read pipe "
429 "r = %d count = %ld/%d!\n", r
, count
, sizeof *status
);
433 /******************************************************************************
434 * service_send_control
436 static BOOL
service_send_control(HANDLE pipe
, DWORD dwControl
, DWORD
*result
)
438 DWORD cmd
[2], count
= 0;
441 cmd
[0] = WINESERV_SENDCONTROL
;
443 r
= WriteFile(pipe
, cmd
, sizeof cmd
, &count
, NULL
);
444 if (!r
|| count
!= sizeof cmd
)
446 ERR("service protocol error - failed to write pipe!\n");
449 r
= ReadFile(pipe
, result
, sizeof *result
, &count
, NULL
);
450 if (!r
|| count
!= sizeof *result
)
451 ERR("service protocol error - failed to read pipe "
452 "r = %d count = %ld/%d!\n", r
, count
, sizeof *result
);
456 /******************************************************************************
457 * service_accepts_control
459 static BOOL
service_accepts_control(service_data
*service
, DWORD dwControl
)
461 DWORD a
= service
->status
.dwControlsAccepted
;
465 case SERVICE_CONTROL_INTERROGATE
:
467 case SERVICE_CONTROL_STOP
:
468 if (a
&SERVICE_ACCEPT_STOP
)
471 case SERVICE_CONTROL_SHUTDOWN
:
472 if (a
&SERVICE_ACCEPT_SHUTDOWN
)
475 case SERVICE_CONTROL_PAUSE
:
476 case SERVICE_CONTROL_CONTINUE
:
477 if (a
&SERVICE_ACCEPT_PAUSE_CONTINUE
)
480 case SERVICE_CONTROL_PARAMCHANGE
:
481 if (a
&SERVICE_ACCEPT_PARAMCHANGE
)
484 case SERVICE_CONTROL_NETBINDADD
:
485 case SERVICE_CONTROL_NETBINDREMOVE
:
486 case SERVICE_CONTROL_NETBINDENABLE
:
487 case SERVICE_CONTROL_NETBINDDISABLE
:
488 if (a
&SERVICE_ACCEPT_NETBINDCHANGE
)
491 if (1) /* (!service->handlerex) */
495 case SERVICE_CONTROL_HARDWAREPROFILECHANGE
:
496 if (a
&SERVICE_ACCEPT_HARDWAREPROFILECHANGE
)
499 case SERVICE_CONTROL_POWEREVENT
:
500 if (a
&SERVICE_ACCEPT_POWEREVENT
)
503 case SERVICE_CONTROL_SESSIONCHANGE
:
504 if (a
&SERVICE_ACCEPT_SESSIONCHANGE
)
511 /******************************************************************************
512 * service_handle_control
514 static BOOL
service_handle_control(HANDLE pipe
, service_data
*service
,
517 DWORD count
, ret
= ERROR_INVALID_SERVICE_CONTROL
;
519 TRACE("received control %ld\n", dwControl
);
521 if (service_accepts_control(service
, dwControl
) && service
->handler
)
523 service
->handler(dwControl
);
526 return WriteFile(pipe
, &ret
, sizeof ret
, &count
, NULL
);
529 /******************************************************************************
530 * service_reap_thread
532 static DWORD
service_reap_thread(service_data
*service
)
536 if (!service
->thread
)
538 GetExitCodeThread(service
->thread
, &exitcode
);
539 if (exitcode
!=STILL_ACTIVE
)
541 CloseHandle(service
->thread
);
547 /******************************************************************************
548 * service_control_dispatcher
550 static DWORD WINAPI
service_control_dispatcher(LPVOID arg
)
552 service_data
*service
= arg
;
556 TRACE("%p %s\n", service
, debugstr_w(service
->name
));
558 /* create a pipe to talk to the rest of the world with */
559 name
= service_get_pipe_name(service
->name
);
560 pipe
= CreateNamedPipeW(name
, PIPE_ACCESS_DUPLEX
,
561 PIPE_TYPE_BYTE
|PIPE_WAIT
, 1, 256, 256, 10000, NULL
);
564 /* let the process who started us know we've tried to create a pipe */
565 event
= service_get_event_handle(service
->name
);
569 if (pipe
==INVALID_HANDLE_VALUE
)
571 ERR("failed to create pipe, error = %ld\n", GetLastError());
575 /* dispatcher loop */
579 DWORD count
, req
[2] = {0,0};
581 r
= ConnectNamedPipe(pipe
, NULL
);
582 if (!r
&& GetLastError() != ERROR_PIPE_CONNECTED
)
584 ERR("pipe connect failed\n");
588 r
= ReadFile( pipe
, &req
, sizeof req
, &count
, NULL
);
589 if (!r
|| count
!=sizeof req
)
591 ERR("pipe read failed\n");
595 service_reap_thread(service
);
597 /* handle the request */
600 case WINESERV_STARTINFO
:
601 service_handle_start(pipe
, service
, req
[1]);
603 case WINESERV_GETSTATUS
:
604 service_handle_get_status(pipe
, service
);
606 case WINESERV_SENDCONTROL
:
607 service_handle_control(pipe
, service
, req
[1]);
610 ERR("received invalid command %ld length %ld\n", req
[0], req
[1]);
613 FlushFileBuffers(pipe
);
614 DisconnectNamedPipe(pipe
);
621 /******************************************************************************
622 * service_run_threads
624 static BOOL
service_run_threads(void)
626 service_data
*service
;
627 DWORD count
= 0, n
= 0;
630 EnterCriticalSection( &service_cs
);
632 /* count how many services there are */
633 for (service
= service_list
; service
; service
= service
->next
)
636 TRACE("starting %ld pipe listener threads\n", count
);
638 handles
= HeapAlloc(GetProcessHeap(), 0, sizeof(HANDLE
)*count
);
640 for (n
=0, service
= service_list
; service
; service
= service
->next
, n
++)
641 handles
[n
] = CreateThread( NULL
, 0, service_control_dispatcher
,
645 LeaveCriticalSection( &service_cs
);
647 /* wait for all the threads to pack up and exit */
648 WaitForMultipleObjectsEx(count
, handles
, TRUE
, INFINITE
, FALSE
);
650 HeapFree(GetProcessHeap(), 0, handles
);
655 /******************************************************************************
656 * StartServiceCtrlDispatcherA [ADVAPI32.@]
658 * Connects a process containing one or more services to the service control
662 * servent [I] A list of the service names and service procedures
664 BOOL WINAPI
StartServiceCtrlDispatcherA( LPSERVICE_TABLE_ENTRYA servent
)
670 TRACE("%p\n", servent
);
672 EnterCriticalSection( &service_cs
);
673 while (servent
->lpServiceName
)
675 LPSTR name
= servent
->lpServiceName
;
677 len
= MultiByteToWideChar(CP_ACP
, 0, name
, -1, NULL
, 0);
678 sz
= len
*sizeof(WCHAR
) + sizeof *info
;
679 info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sz
);
680 MultiByteToWideChar(CP_ACP
, 0, name
, -1, info
->name
, len
);
681 info
->proc
.a
= servent
->lpServiceProc
;
682 info
->unicode
= FALSE
;
684 /* insert into the list */
685 info
->next
= service_list
;
690 LeaveCriticalSection( &service_cs
);
692 service_run_threads();
697 /******************************************************************************
698 * StartServiceCtrlDispatcherW [ADVAPI32.@]
700 * Connects a process containing one or more services to the service control
704 * servent [I] A list of the service names and service procedures
706 BOOL WINAPI
StartServiceCtrlDispatcherW( LPSERVICE_TABLE_ENTRYW servent
)
712 TRACE("%p\n", servent
);
714 EnterCriticalSection( &service_cs
);
715 while (servent
->lpServiceName
)
717 LPWSTR name
= servent
->lpServiceName
;
720 sz
= len
*sizeof(WCHAR
) + sizeof *info
;
721 info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sz
);
722 strcpyW(info
->name
, name
);
723 info
->proc
.w
= servent
->lpServiceProc
;
724 info
->unicode
= TRUE
;
726 /* insert into the list */
727 info
->next
= service_list
;
732 LeaveCriticalSection( &service_cs
);
734 service_run_threads();
739 /******************************************************************************
740 * LockServiceDatabase [ADVAPI32.@]
742 SC_LOCK WINAPI
LockServiceDatabase (SC_HANDLE hSCManager
)
746 TRACE("%p\n",hSCManager
);
748 ret
= CreateSemaphoreW( NULL
, 1, 1, szSCMLock
);
749 if( ret
&& GetLastError() == ERROR_ALREADY_EXISTS
)
753 SetLastError( ERROR_SERVICE_DATABASE_LOCKED
);
756 TRACE("returning %p\n", ret
);
761 /******************************************************************************
762 * UnlockServiceDatabase [ADVAPI32.@]
764 BOOL WINAPI
UnlockServiceDatabase (SC_LOCK ScLock
)
766 TRACE("%p\n",ScLock
);
768 return CloseHandle( ScLock
);
771 /******************************************************************************
772 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
774 SERVICE_STATUS_HANDLE WINAPI
775 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName
, LPHANDLER_FUNCTION lpfHandler
)
777 LPWSTR lpServiceNameW
;
778 SERVICE_STATUS_HANDLE ret
;
780 lpServiceNameW
= SERV_dup(lpServiceName
);
781 ret
= RegisterServiceCtrlHandlerW( lpServiceNameW
, lpfHandler
);
782 SERV_free(lpServiceNameW
);
786 /******************************************************************************
787 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
793 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName
,
794 LPHANDLER_FUNCTION lpfHandler
)
796 service_data
*service
;
798 EnterCriticalSection( &service_cs
);
799 for(service
= service_list
; service
; service
= service
->next
)
800 if(!strcmpW(lpServiceName
, service
->name
))
803 service
->handler
= lpfHandler
;
804 LeaveCriticalSection( &service_cs
);
806 return (SERVICE_STATUS_HANDLE
)service
;
809 /******************************************************************************
810 * SetServiceStatus [ADVAPI32.@]
817 SetServiceStatus( SERVICE_STATUS_HANDLE hService
, LPSERVICE_STATUS lpStatus
)
819 service_data
*service
;
822 TRACE("%lx %lx %lx %lx %lx %lx %lx %lx\n", hService
,
823 lpStatus
->dwServiceType
, lpStatus
->dwCurrentState
,
824 lpStatus
->dwControlsAccepted
, lpStatus
->dwWin32ExitCode
,
825 lpStatus
->dwServiceSpecificExitCode
, lpStatus
->dwCheckPoint
,
826 lpStatus
->dwWaitHint
);
828 EnterCriticalSection( &service_cs
);
829 for (service
= service_list
; service
; service
= service
->next
)
830 if(service
== (service_data
*)hService
)
834 memcpy( &service
->status
, lpStatus
, sizeof(SERVICE_STATUS
) );
835 TRACE("Set service status to %ld\n",service
->status
.dwCurrentState
);
839 LeaveCriticalSection( &service_cs
);
845 /******************************************************************************
846 * OpenSCManagerA [ADVAPI32.@]
848 * Establish a connection to the service control manager and open its database.
851 * lpMachineName [I] Pointer to machine name string
852 * lpDatabaseName [I] Pointer to database name string
853 * dwDesiredAccess [I] Type of access
856 * Success: A Handle to the service control manager database
859 SC_HANDLE WINAPI
OpenSCManagerA( LPCSTR lpMachineName
, LPCSTR lpDatabaseName
,
860 DWORD dwDesiredAccess
)
862 LPWSTR lpMachineNameW
, lpDatabaseNameW
;
865 lpMachineNameW
= SERV_dup(lpMachineName
);
866 lpDatabaseNameW
= SERV_dup(lpDatabaseName
);
867 ret
= OpenSCManagerW(lpMachineNameW
, lpDatabaseNameW
, dwDesiredAccess
);
868 SERV_free(lpDatabaseNameW
);
869 SERV_free(lpMachineNameW
);
873 /******************************************************************************
874 * OpenSCManagerW [ADVAPI32.@]
876 * See OpenSCManagerA.
878 SC_HANDLE WINAPI
OpenSCManagerW( LPCWSTR lpMachineName
, LPCWSTR lpDatabaseName
,
879 DWORD dwDesiredAccess
)
881 struct sc_manager
*manager
;
885 TRACE("(%s,%s,0x%08lx)\n", debugstr_w(lpMachineName
),
886 debugstr_w(lpDatabaseName
), dwDesiredAccess
);
888 if( lpDatabaseName
&& lpDatabaseName
[0] )
890 if( strcmpiW( lpDatabaseName
, SERVICES_ACTIVE_DATABASEW
) == 0 )
892 /* noop, all right */
894 else if( strcmpiW( lpDatabaseName
, SERVICES_FAILED_DATABASEW
) == 0 )
896 SetLastError( ERROR_DATABASE_DOES_NOT_EXIST
);
901 SetLastError( ERROR_INVALID_NAME
);
906 manager
= sc_handle_alloc( SC_HTYPE_MANAGER
, sizeof (struct sc_manager
),
907 sc_handle_destroy_manager
);
911 r
= RegConnectRegistryW(lpMachineName
,HKEY_LOCAL_MACHINE
,&hReg
);
912 if (r
!=ERROR_SUCCESS
)
915 r
= RegOpenKeyExW(hReg
, szServiceManagerKey
,
916 0, KEY_ALL_ACCESS
, &manager
->hkey
);
918 if (r
!=ERROR_SUCCESS
)
921 TRACE("returning %p\n", manager
);
923 return (SC_HANDLE
) &manager
->hdr
;
926 sc_handle_free( &manager
->hdr
);
930 /******************************************************************************
931 * ControlService [ADVAPI32.@]
933 * Send a control code to a service.
936 * hService [I] Handle of the service control manager database
937 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
938 * lpServiceStatus [O] Destination for the status of the service, if available
945 * Unlike M$' implementation, control requests are not serialized and may be
946 * processed asynchronously.
948 BOOL WINAPI
ControlService( SC_HANDLE hService
, DWORD dwControl
,
949 LPSERVICE_STATUS lpServiceStatus
)
951 struct sc_service
*hsvc
;
955 TRACE("%p %ld %p\n", hService
, dwControl
, lpServiceStatus
);
957 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
960 SetLastError( ERROR_INVALID_HANDLE
);
964 ret
= QueryServiceStatus(hService
, lpServiceStatus
);
967 ERR("failed to query service status\n");
968 SetLastError(ERROR_SERVICE_NOT_ACTIVE
);
972 switch (lpServiceStatus
->dwCurrentState
)
974 case SERVICE_STOPPED
:
975 SetLastError(ERROR_SERVICE_NOT_ACTIVE
);
977 case SERVICE_START_PENDING
:
978 if (dwControl
==SERVICE_CONTROL_STOP
)
981 case SERVICE_STOP_PENDING
:
982 SetLastError(ERROR_SERVICE_CANNOT_ACCEPT_CTRL
);
986 handle
= service_open_pipe(hsvc
->name
);
987 if (handle
!=INVALID_HANDLE_VALUE
)
989 DWORD result
= ERROR_SUCCESS
;
990 ret
= service_send_control(handle
, dwControl
, &result
);
992 if (result
!=ERROR_SUCCESS
)
994 SetLastError(result
);
1002 /******************************************************************************
1003 * CloseServiceHandle [ADVAPI32.@]
1005 * Close a handle to a service or the service control manager database.
1008 * hSCObject [I] Handle to service or service control manager database
1015 CloseServiceHandle( SC_HANDLE hSCObject
)
1017 TRACE("%p\n", hSCObject
);
1019 sc_handle_free( (struct sc_handle
*) hSCObject
);
1025 /******************************************************************************
1026 * OpenServiceA [ADVAPI32.@]
1028 * Open a handle to a service.
1031 * hSCManager [I] Handle of the service control manager database
1032 * lpServiceName [I] Name of the service to open
1033 * dwDesiredAccess [I] Access required to the service
1036 * Success: Handle to the service
1039 SC_HANDLE WINAPI
OpenServiceA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
1040 DWORD dwDesiredAccess
)
1042 LPWSTR lpServiceNameW
;
1045 TRACE("%p %s %ld\n", hSCManager
, debugstr_a(lpServiceName
), dwDesiredAccess
);
1047 lpServiceNameW
= SERV_dup(lpServiceName
);
1048 ret
= OpenServiceW( hSCManager
, lpServiceNameW
, dwDesiredAccess
);
1049 SERV_free(lpServiceNameW
);
1054 /******************************************************************************
1055 * OpenServiceW [ADVAPI32.@]
1059 SC_HANDLE WINAPI
OpenServiceW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
1060 DWORD dwDesiredAccess
)
1062 struct sc_manager
*hscm
;
1063 struct sc_service
*hsvc
;
1068 TRACE("%p %s %ld\n", hSCManager
, debugstr_w(lpServiceName
), dwDesiredAccess
);
1072 SetLastError(ERROR_INVALID_ADDRESS
);
1076 hscm
= sc_handle_get_handle_data( hSCManager
, SC_HTYPE_MANAGER
);
1079 SetLastError( ERROR_INVALID_HANDLE
);
1083 r
= RegOpenKeyExW( hscm
->hkey
, lpServiceName
, 0, KEY_ALL_ACCESS
, &hKey
);
1084 if (r
!=ERROR_SUCCESS
)
1086 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST
);
1090 len
= strlenW(lpServiceName
)+1;
1091 hsvc
= sc_handle_alloc( SC_HTYPE_SERVICE
,
1092 sizeof (struct sc_service
) + len
*sizeof(WCHAR
),
1093 sc_handle_destroy_service
);
1096 strcpyW( hsvc
->name
, lpServiceName
);
1099 /* add reference to SCM handle */
1100 hscm
->hdr
.ref_count
++;
1103 TRACE("returning %p\n",hsvc
);
1105 return (SC_HANDLE
) &hsvc
->hdr
;
1108 /******************************************************************************
1109 * CreateServiceW [ADVAPI32.@]
1112 CreateServiceW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
1113 LPCWSTR lpDisplayName
, DWORD dwDesiredAccess
,
1114 DWORD dwServiceType
, DWORD dwStartType
,
1115 DWORD dwErrorControl
, LPCWSTR lpBinaryPathName
,
1116 LPCWSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
,
1117 LPCWSTR lpDependencies
, LPCWSTR lpServiceStartName
,
1118 LPCWSTR lpPassword
)
1120 struct sc_manager
*hscm
;
1121 struct sc_service
*hsvc
= NULL
;
1125 static const WCHAR szDisplayName
[] = { 'D','i','s','p','l','a','y','N','a','m','e', 0 };
1126 static const WCHAR szType
[] = {'T','y','p','e',0};
1127 static const WCHAR szStart
[] = {'S','t','a','r','t',0};
1128 static const WCHAR szError
[] = {'E','r','r','o','r','C','o','n','t','r','o','l', 0};
1129 static const WCHAR szImagePath
[] = {'I','m','a','g','e','P','a','t','h',0};
1130 static const WCHAR szGroup
[] = {'G','r','o','u','p',0};
1131 static const WCHAR szDependencies
[] = { 'D','e','p','e','n','d','e','n','c','i','e','s',0};
1133 FIXME("%p %s %s\n", hSCManager
,
1134 debugstr_w(lpServiceName
), debugstr_w(lpDisplayName
));
1136 hscm
= sc_handle_get_handle_data( hSCManager
, SC_HTYPE_MANAGER
);
1139 SetLastError( ERROR_INVALID_HANDLE
);
1143 r
= RegCreateKeyExW(hscm
->hkey
, lpServiceName
, 0, NULL
,
1144 REG_OPTION_NON_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &hKey
, &dp
);
1145 if (r
!=ERROR_SUCCESS
)
1148 if (dp
!= REG_CREATED_NEW_KEY
)
1150 SetLastError(ERROR_SERVICE_EXISTS
);
1156 r
= RegSetValueExW(hKey
, szDisplayName
, 0, REG_SZ
, (const BYTE
*)lpDisplayName
,
1157 (strlenW(lpDisplayName
)+1)*sizeof(WCHAR
) );
1158 if (r
!=ERROR_SUCCESS
)
1162 r
= RegSetValueExW(hKey
, szType
, 0, REG_DWORD
, (LPVOID
)&dwServiceType
, sizeof (DWORD
) );
1163 if (r
!=ERROR_SUCCESS
)
1166 r
= RegSetValueExW(hKey
, szStart
, 0, REG_DWORD
, (LPVOID
)&dwStartType
, sizeof (DWORD
) );
1167 if (r
!=ERROR_SUCCESS
)
1170 r
= RegSetValueExW(hKey
, szError
, 0, REG_DWORD
,
1171 (LPVOID
)&dwErrorControl
, sizeof (DWORD
) );
1172 if (r
!=ERROR_SUCCESS
)
1175 if(lpBinaryPathName
)
1177 r
= RegSetValueExW(hKey
, szImagePath
, 0, REG_SZ
, (const BYTE
*)lpBinaryPathName
,
1178 (strlenW(lpBinaryPathName
)+1)*sizeof(WCHAR
) );
1179 if (r
!=ERROR_SUCCESS
)
1183 if(lpLoadOrderGroup
)
1185 r
= RegSetValueExW(hKey
, szGroup
, 0, REG_SZ
, (const BYTE
*)lpLoadOrderGroup
,
1186 (strlenW(lpLoadOrderGroup
)+1)*sizeof(WCHAR
) );
1187 if (r
!=ERROR_SUCCESS
)
1195 /* determine the length of a double null terminated multi string */
1197 len
+= (strlenW(&lpDependencies
[len
])+1);
1198 } while (lpDependencies
[len
++]);
1200 r
= RegSetValueExW(hKey
, szDependencies
, 0, REG_MULTI_SZ
,
1201 (const BYTE
*)lpDependencies
, len
);
1202 if (r
!=ERROR_SUCCESS
)
1208 FIXME("Don't know how to add a Password for a service.\n");
1211 if(lpServiceStartName
)
1213 FIXME("Don't know how to add a ServiceStartName for a service.\n");
1216 len
= strlenW(lpServiceName
)+1;
1217 hsvc
= sc_handle_alloc( SC_HTYPE_SERVICE
,
1218 sizeof (struct sc_service
) + len
*sizeof(WCHAR
),
1219 sc_handle_destroy_service
);
1222 strcpyW( hsvc
->name
, lpServiceName
);
1225 hscm
->hdr
.ref_count
++;
1227 return (SC_HANDLE
) &hsvc
->hdr
;
1231 sc_handle_free( &hsvc
->hdr
);
1236 /******************************************************************************
1237 * CreateServiceA [ADVAPI32.@]
1240 CreateServiceA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
1241 LPCSTR lpDisplayName
, DWORD dwDesiredAccess
,
1242 DWORD dwServiceType
, DWORD dwStartType
,
1243 DWORD dwErrorControl
, LPCSTR lpBinaryPathName
,
1244 LPCSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
,
1245 LPCSTR lpDependencies
, LPCSTR lpServiceStartName
,
1248 LPWSTR lpServiceNameW
, lpDisplayNameW
, lpBinaryPathNameW
,
1249 lpLoadOrderGroupW
, lpDependenciesW
, lpServiceStartNameW
, lpPasswordW
;
1252 TRACE("%p %s %s\n", hSCManager
,
1253 debugstr_a(lpServiceName
), debugstr_a(lpDisplayName
));
1255 lpServiceNameW
= SERV_dup( lpServiceName
);
1256 lpDisplayNameW
= SERV_dup( lpDisplayName
);
1257 lpBinaryPathNameW
= SERV_dup( lpBinaryPathName
);
1258 lpLoadOrderGroupW
= SERV_dup( lpLoadOrderGroup
);
1259 lpDependenciesW
= SERV_dupmulti( lpDependencies
);
1260 lpServiceStartNameW
= SERV_dup( lpServiceStartName
);
1261 lpPasswordW
= SERV_dup( lpPassword
);
1263 r
= CreateServiceW( hSCManager
, lpServiceNameW
, lpDisplayNameW
,
1264 dwDesiredAccess
, dwServiceType
, dwStartType
, dwErrorControl
,
1265 lpBinaryPathNameW
, lpLoadOrderGroupW
, lpdwTagId
,
1266 lpDependenciesW
, lpServiceStartNameW
, lpPasswordW
);
1268 SERV_free( lpServiceNameW
);
1269 SERV_free( lpDisplayNameW
);
1270 SERV_free( lpBinaryPathNameW
);
1271 SERV_free( lpLoadOrderGroupW
);
1272 SERV_free( lpDependenciesW
);
1273 SERV_free( lpServiceStartNameW
);
1274 SERV_free( lpPasswordW
);
1280 /******************************************************************************
1281 * DeleteService [ADVAPI32.@]
1283 * Delete a service from the service control manager database.
1286 * hService [I] Handle of the service to delete
1292 BOOL WINAPI
DeleteService( SC_HANDLE hService
)
1294 struct sc_service
*hsvc
;
1296 WCHAR valname
[MAX_PATH
+1];
1301 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1304 SetLastError( ERROR_INVALID_HANDLE
);
1310 /* Clean out the values */
1311 rc
= RegEnumValueW(hKey
, index
, valname
,&size
,0,0,0,0);
1312 while (rc
== ERROR_SUCCESS
)
1314 RegDeleteValueW(hKey
,valname
);
1317 rc
= RegEnumValueW(hKey
, index
, valname
, &size
,0,0,0,0);
1323 /* delete the key */
1324 RegDeleteKeyW(hsvc
->scm
->hkey
, hsvc
->name
);
1330 /******************************************************************************
1331 * StartServiceA [ADVAPI32.@]
1336 * hService [I] Handle of service
1337 * dwNumServiceArgs [I] Number of arguments
1338 * lpServiceArgVectors [I] Address of array of argument strings
1341 * - NT implements this function using an obscure RPC call.
1342 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1343 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1344 * - This will only work for shared address space. How should the service
1345 * args be transferred when address spaces are separated?
1346 * - Can only start one service at a time.
1347 * - Has no concept of privilege.
1353 BOOL WINAPI
StartServiceA( SC_HANDLE hService
, DWORD dwNumServiceArgs
,
1354 LPCSTR
*lpServiceArgVectors
)
1356 LPWSTR
*lpwstr
=NULL
;
1360 TRACE("(%p,%ld,%p)\n",hService
,dwNumServiceArgs
,lpServiceArgVectors
);
1362 if (dwNumServiceArgs
)
1363 lpwstr
= HeapAlloc( GetProcessHeap(), 0,
1364 dwNumServiceArgs
*sizeof(LPWSTR
) );
1366 for(i
=0; i
<dwNumServiceArgs
; i
++)
1367 lpwstr
[i
]=SERV_dup(lpServiceArgVectors
[i
]);
1369 r
= StartServiceW(hService
, dwNumServiceArgs
, (LPCWSTR
*)lpwstr
);
1371 if (dwNumServiceArgs
)
1373 for(i
=0; i
<dwNumServiceArgs
; i
++)
1374 SERV_free(lpwstr
[i
]);
1375 HeapFree(GetProcessHeap(), 0, lpwstr
);
1381 /******************************************************************************
1382 * service_start_process [INTERNAL]
1384 static DWORD
service_start_process(struct sc_service
*hsvc
)
1386 static const WCHAR _ImagePathW
[] = {'I','m','a','g','e','P','a','t','h',0};
1387 PROCESS_INFORMATION pi
;
1389 LPWSTR path
= NULL
, str
;
1390 DWORD type
, size
, ret
;
1394 /* read the executable path from memory */
1396 ret
= RegQueryValueExW(hsvc
->hkey
, _ImagePathW
, NULL
, &type
, NULL
, &size
);
1397 if (ret
!=ERROR_SUCCESS
)
1399 str
= HeapAlloc(GetProcessHeap(),0,size
);
1400 ret
= RegQueryValueExW(hsvc
->hkey
, _ImagePathW
, NULL
, &type
, (LPBYTE
)str
, &size
);
1401 if (ret
==ERROR_SUCCESS
)
1403 size
= ExpandEnvironmentStringsW(str
,NULL
,0);
1404 path
= HeapAlloc(GetProcessHeap(),0,size
*sizeof(WCHAR
));
1405 ExpandEnvironmentStringsW(str
,path
,size
);
1407 HeapFree(GetProcessHeap(),0,str
);
1411 /* wait for the process to start and set an event or terminate */
1412 handles
[0] = service_get_event_handle( hsvc
->name
);
1413 ZeroMemory(&si
, sizeof(STARTUPINFOW
));
1414 si
.cb
= sizeof(STARTUPINFOW
);
1415 r
= CreateProcessW(NULL
, path
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
1418 handles
[1] = pi
.hProcess
;
1419 ret
= WaitForMultipleObjectsEx(2, handles
, FALSE
, 30000, FALSE
);
1420 if(ret
!= WAIT_OBJECT_0
)
1422 SetLastError(ERROR_IO_PENDING
);
1426 CloseHandle( pi
.hThread
);
1427 CloseHandle( pi
.hProcess
);
1429 CloseHandle( handles
[0] );
1430 HeapFree(GetProcessHeap(),0,path
);
1434 static BOOL
service_wait_for_startup(SC_HANDLE hService
)
1437 SERVICE_STATUS status
;
1440 TRACE("%p\n", hService
);
1442 for (i
=0; i
<30; i
++)
1444 status
.dwCurrentState
= 0;
1445 r
= QueryServiceStatus(hService
, &status
);
1448 if (status
.dwCurrentState
== SERVICE_RUNNING
)
1450 TRACE("Service started successfully\n");
1459 /******************************************************************************
1460 * StartServiceW [ADVAPI32.@]
1462 * See StartServiceA.
1464 BOOL WINAPI
StartServiceW(SC_HANDLE hService
, DWORD dwNumServiceArgs
,
1465 LPCWSTR
*lpServiceArgVectors
)
1467 struct sc_service
*hsvc
;
1470 HANDLE handle
= INVALID_HANDLE_VALUE
;
1472 TRACE("%p %ld %p\n", hService
, dwNumServiceArgs
, lpServiceArgVectors
);
1474 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1477 SetLastError(ERROR_INVALID_HANDLE
);
1481 hLock
= LockServiceDatabase(hsvc
->scm
);
1485 handle
= service_open_pipe(hsvc
->name
);
1486 if (handle
==INVALID_HANDLE_VALUE
)
1488 /* start the service process */
1489 if (service_start_process(hsvc
))
1490 handle
= service_open_pipe(hsvc
->name
);
1493 if (handle
!= INVALID_HANDLE_VALUE
)
1495 service_send_start_message(handle
, lpServiceArgVectors
, dwNumServiceArgs
);
1496 CloseHandle(handle
);
1500 UnlockServiceDatabase( hLock
);
1502 TRACE("returning %d\n", r
);
1504 service_wait_for_startup(hService
);
1509 /******************************************************************************
1510 * QueryServiceStatus [ADVAPI32.@]
1514 * lpservicestatus []
1517 BOOL WINAPI
QueryServiceStatus(SC_HANDLE hService
,
1518 LPSERVICE_STATUS lpservicestatus
)
1520 struct sc_service
*hsvc
;
1521 DWORD size
, type
, val
;
1525 TRACE("%p %p\n", hService
, lpservicestatus
);
1527 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1530 SetLastError( ERROR_INVALID_HANDLE
);
1534 pipe
= service_open_pipe(hsvc
->name
);
1535 if (pipe
!= INVALID_HANDLE_VALUE
)
1537 r
= service_get_status(pipe
, lpservicestatus
);
1543 TRACE("Failed to read service status\n");
1545 /* read the service type from the registry */
1547 r
= RegQueryValueExA(hsvc
->hkey
, "Type", NULL
, &type
, (LPBYTE
)&val
, &size
);
1548 if(r
!=ERROR_SUCCESS
|| type
!=REG_DWORD
)
1551 lpservicestatus
->dwServiceType
= val
;
1552 lpservicestatus
->dwCurrentState
= SERVICE_STOPPED
; /* stopped */
1553 lpservicestatus
->dwControlsAccepted
= 0;
1554 lpservicestatus
->dwWin32ExitCode
= ERROR_SERVICE_NEVER_STARTED
;
1555 lpservicestatus
->dwServiceSpecificExitCode
= 0;
1556 lpservicestatus
->dwCheckPoint
= 0;
1557 lpservicestatus
->dwWaitHint
= 0;
1562 /******************************************************************************
1563 * QueryServiceStatusEx [ADVAPI32.@]
1565 * Get information about a service.
1568 * hService [I] Handle to service to get information about
1569 * InfoLevel [I] Level of information to get
1570 * lpBuffer [O] Destination for requested information
1571 * cbBufSize [I] Size of lpBuffer in bytes
1572 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1578 BOOL WINAPI
QueryServiceStatusEx(SC_HANDLE hService
, SC_STATUS_TYPE InfoLevel
,
1579 LPBYTE lpBuffer
, DWORD cbBufSize
,
1580 LPDWORD pcbBytesNeeded
)
1583 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1587 /******************************************************************************
1588 * QueryServiceConfigA [ADVAPI32.@]
1591 QueryServiceConfigA( SC_HANDLE hService
,
1592 LPQUERY_SERVICE_CONFIGA lpServiceConfig
,
1593 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
1595 static const CHAR szDisplayName
[] = "DisplayName";
1596 static const CHAR szType
[] = "Type";
1597 static const CHAR szStart
[] = "Start";
1598 static const CHAR szError
[] = "ErrorControl";
1599 static const CHAR szImagePath
[] = "ImagePath";
1600 static const CHAR szGroup
[] = "Group";
1601 static const CHAR szDependencies
[] = "Dependencies";
1602 struct sc_service
*hsvc
;
1604 CHAR str_buffer
[ MAX_PATH
];
1606 DWORD type
, val
, sz
, total
, n
;
1609 TRACE("%p %p %ld %p\n", hService
, lpServiceConfig
,
1610 cbBufSize
, pcbBytesNeeded
);
1612 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1615 SetLastError( ERROR_INVALID_HANDLE
);
1620 /* calculate the size required first */
1621 total
= sizeof (QUERY_SERVICE_CONFIGA
);
1623 sz
= sizeof(str_buffer
);
1624 r
= RegQueryValueExA( hKey
, szImagePath
, 0, &type
, str_buffer
, &sz
);
1625 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
|| type
== REG_EXPAND_SZ
) )
1627 sz
= ExpandEnvironmentStringsA(str_buffer
,NULL
,0);
1628 if( 0 == sz
) return FALSE
;
1634 /* FIXME: set last error */
1639 r
= RegQueryValueExA( hKey
, szGroup
, 0, &type
, NULL
, &sz
);
1640 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1644 r
= RegQueryValueExA( hKey
, szDependencies
, 0, &type
, NULL
, &sz
);
1645 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_MULTI_SZ
) )
1649 r
= RegQueryValueExA( hKey
, szStart
, 0, &type
, NULL
, &sz
);
1650 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1654 r
= RegQueryValueExA( hKey
, szDisplayName
, 0, &type
, NULL
, &sz
);
1655 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1658 /* if there's not enough memory, return an error */
1659 if( total
> *pcbBytesNeeded
)
1661 *pcbBytesNeeded
= total
;
1662 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1666 *pcbBytesNeeded
= total
;
1667 ZeroMemory( lpServiceConfig
, total
);
1670 r
= RegQueryValueExA( hKey
, szType
, 0, &type
, (LPBYTE
)&val
, &sz
);
1671 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_DWORD
) )
1672 lpServiceConfig
->dwServiceType
= val
;
1675 r
= RegQueryValueExA( hKey
, szStart
, 0, &type
, (LPBYTE
)&val
, &sz
);
1676 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_DWORD
) )
1677 lpServiceConfig
->dwStartType
= val
;
1680 r
= RegQueryValueExA( hKey
, szError
, 0, &type
, (LPBYTE
)&val
, &sz
);
1681 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_DWORD
) )
1682 lpServiceConfig
->dwErrorControl
= val
;
1684 /* now do the strings */
1685 p
= (LPBYTE
) &lpServiceConfig
[1];
1686 n
= total
- sizeof (QUERY_SERVICE_CONFIGA
);
1688 sz
= sizeof(str_buffer
);
1689 r
= RegQueryValueExA( hKey
, szImagePath
, 0, &type
, str_buffer
, &sz
);
1690 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
|| type
== REG_EXPAND_SZ
) )
1692 sz
= ExpandEnvironmentStringsA(str_buffer
, p
, n
);
1693 if( 0 == sz
|| sz
> n
) return FALSE
;
1695 lpServiceConfig
->lpBinaryPathName
= (LPSTR
) p
;
1701 /* FIXME: set last error */
1706 r
= RegQueryValueExA( hKey
, szGroup
, 0, &type
, p
, &sz
);
1707 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_SZ
) )
1709 lpServiceConfig
->lpLoadOrderGroup
= (LPSTR
) p
;
1715 r
= RegQueryValueExA( hKey
, szDependencies
, 0, &type
, p
, &sz
);
1716 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_SZ
) )
1718 lpServiceConfig
->lpDependencies
= (LPSTR
) p
;
1724 ERR("Buffer overflow!\n");
1726 TRACE("Image path = %s\n", lpServiceConfig
->lpBinaryPathName
);
1727 TRACE("Group = %s\n", lpServiceConfig
->lpLoadOrderGroup
);
1732 /******************************************************************************
1733 * QueryServiceConfigW [ADVAPI32.@]
1736 QueryServiceConfigW( SC_HANDLE hService
,
1737 LPQUERY_SERVICE_CONFIGW lpServiceConfig
,
1738 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
1740 static const WCHAR szDisplayName
[] = {
1741 'D','i','s','p','l','a','y','N','a','m','e', 0 };
1742 static const WCHAR szType
[] = {'T','y','p','e',0};
1743 static const WCHAR szStart
[] = {'S','t','a','r','t',0};
1744 static const WCHAR szError
[] = {
1745 'E','r','r','o','r','C','o','n','t','r','o','l', 0};
1746 static const WCHAR szImagePath
[] = {'I','m','a','g','e','P','a','t','h',0};
1747 static const WCHAR szGroup
[] = {'G','r','o','u','p',0};
1748 static const WCHAR szDependencies
[] = {
1749 'D','e','p','e','n','d','e','n','c','i','e','s',0};
1750 WCHAR str_buffer
[ MAX_PATH
];
1752 DWORD type
, val
, sz
, total
, n
;
1755 struct sc_service
*hsvc
;
1757 TRACE("%p %p %ld %p\n", hService
, lpServiceConfig
,
1758 cbBufSize
, pcbBytesNeeded
);
1760 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1763 SetLastError( ERROR_INVALID_HANDLE
);
1768 /* calculate the size required first */
1769 total
= sizeof (QUERY_SERVICE_CONFIGW
);
1771 sz
= sizeof(str_buffer
);
1772 r
= RegQueryValueExW( hKey
, szImagePath
, 0, &type
, (LPBYTE
) str_buffer
, &sz
);
1773 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
|| type
== REG_EXPAND_SZ
) )
1775 sz
= ExpandEnvironmentStringsW(str_buffer
,NULL
,0);
1776 if( 0 == sz
) return FALSE
;
1778 total
+= sizeof(WCHAR
) * sz
;
1782 /* FIXME: set last error */
1787 r
= RegQueryValueExW( hKey
, szGroup
, 0, &type
, NULL
, &sz
);
1788 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1792 r
= RegQueryValueExW( hKey
, szDependencies
, 0, &type
, NULL
, &sz
);
1793 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_MULTI_SZ
) )
1797 r
= RegQueryValueExW( hKey
, szStart
, 0, &type
, NULL
, &sz
);
1798 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1802 r
= RegQueryValueExW( hKey
, szDisplayName
, 0, &type
, NULL
, &sz
);
1803 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1806 *pcbBytesNeeded
= total
;
1808 /* if there's not enough memory, return an error */
1809 if( total
> cbBufSize
)
1811 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1815 ZeroMemory( lpServiceConfig
, total
);
1818 r
= RegQueryValueExW( hKey
, szType
, 0, &type
, (LPBYTE
)&val
, &sz
);
1819 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_DWORD
) )
1820 lpServiceConfig
->dwServiceType
= val
;
1823 r
= RegQueryValueExW( hKey
, szStart
, 0, &type
, (LPBYTE
)&val
, &sz
);
1824 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_DWORD
) )
1825 lpServiceConfig
->dwStartType
= val
;
1828 r
= RegQueryValueExW( hKey
, szError
, 0, &type
, (LPBYTE
)&val
, &sz
);
1829 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_DWORD
) )
1830 lpServiceConfig
->dwErrorControl
= val
;
1832 /* now do the strings */
1833 p
= (LPBYTE
) &lpServiceConfig
[1];
1834 n
= total
- sizeof (QUERY_SERVICE_CONFIGW
);
1836 sz
= sizeof(str_buffer
);
1837 r
= RegQueryValueExW( hKey
, szImagePath
, 0, &type
, (LPBYTE
) str_buffer
, &sz
);
1838 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
|| type
== REG_EXPAND_SZ
) )
1840 sz
= ExpandEnvironmentStringsW(str_buffer
, (LPWSTR
) p
, n
);
1841 sz
*= sizeof(WCHAR
);
1842 if( 0 == sz
|| sz
> n
) return FALSE
;
1844 lpServiceConfig
->lpBinaryPathName
= (LPWSTR
) p
;
1850 /* FIXME: set last error */
1855 r
= RegQueryValueExW( hKey
, szGroup
, 0, &type
, p
, &sz
);
1856 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_SZ
) )
1858 lpServiceConfig
->lpLoadOrderGroup
= (LPWSTR
) p
;
1864 r
= RegQueryValueExW( hKey
, szDependencies
, 0, &type
, p
, &sz
);
1865 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_SZ
) )
1867 lpServiceConfig
->lpDependencies
= (LPWSTR
) p
;
1873 ERR("Buffer overflow!\n");
1875 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig
->lpBinaryPathName
) );
1876 TRACE("Group = %s\n", debugstr_w(lpServiceConfig
->lpLoadOrderGroup
) );
1881 /******************************************************************************
1882 * EnumServicesStatusA [ADVAPI32.@]
1885 EnumServicesStatusA( SC_HANDLE hSCManager
, DWORD dwServiceType
,
1886 DWORD dwServiceState
, LPENUM_SERVICE_STATUSA lpServices
,
1887 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
1888 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
)
1890 FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager
,
1891 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
1892 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
);
1893 SetLastError (ERROR_ACCESS_DENIED
);
1897 /******************************************************************************
1898 * EnumServicesStatusW [ADVAPI32.@]
1901 EnumServicesStatusW( SC_HANDLE hSCManager
, DWORD dwServiceType
,
1902 DWORD dwServiceState
, LPENUM_SERVICE_STATUSW lpServices
,
1903 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
1904 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
)
1906 FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager
,
1907 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
1908 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
);
1909 SetLastError (ERROR_ACCESS_DENIED
);
1913 /******************************************************************************
1914 * GetServiceKeyNameA [ADVAPI32.@]
1916 BOOL WINAPI
GetServiceKeyNameA( SC_HANDLE hSCManager
, LPCSTR lpDisplayName
,
1917 LPSTR lpServiceName
, LPDWORD lpcchBuffer
)
1919 FIXME("%p %s %p %p\n", hSCManager
, debugstr_a(lpDisplayName
), lpServiceName
, lpcchBuffer
);
1923 /******************************************************************************
1924 * GetServiceKeyNameW [ADVAPI32.@]
1926 BOOL WINAPI
GetServiceKeyNameW( SC_HANDLE hSCManager
, LPCWSTR lpDisplayName
,
1927 LPWSTR lpServiceName
, LPDWORD lpcchBuffer
)
1929 FIXME("%p %s %p %p\n", hSCManager
, debugstr_w(lpDisplayName
), lpServiceName
, lpcchBuffer
);
1933 /******************************************************************************
1934 * QueryServiceLockStatusA [ADVAPI32.@]
1936 BOOL WINAPI
QueryServiceLockStatusA( SC_HANDLE hSCManager
,
1937 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus
,
1938 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
1940 FIXME("%p %p %08lx %p\n", hSCManager
, lpLockStatus
, cbBufSize
, pcbBytesNeeded
);
1945 /******************************************************************************
1946 * QueryServiceLockStatusW [ADVAPI32.@]
1948 BOOL WINAPI
QueryServiceLockStatusW( SC_HANDLE hSCManager
,
1949 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus
,
1950 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
1952 FIXME("%p %p %08lx %p\n", hSCManager
, lpLockStatus
, cbBufSize
, pcbBytesNeeded
);
1957 /******************************************************************************
1958 * GetServiceDisplayNameA [ADVAPI32.@]
1960 BOOL WINAPI
GetServiceDisplayNameA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
1961 LPSTR lpDisplayName
, LPDWORD lpcchBuffer
)
1963 FIXME("%p %s %p %p\n", hSCManager
,
1964 debugstr_a(lpServiceName
), lpDisplayName
, lpcchBuffer
);
1968 /******************************************************************************
1969 * GetServiceDisplayNameW [ADVAPI32.@]
1971 BOOL WINAPI
GetServiceDisplayNameW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
1972 LPWSTR lpDisplayName
, LPDWORD lpcchBuffer
)
1974 FIXME("%p %s %p %p\n", hSCManager
,
1975 debugstr_w(lpServiceName
), lpDisplayName
, lpcchBuffer
);
1979 /******************************************************************************
1980 * ChangeServiceConfigW [ADVAPI32.@]
1982 BOOL WINAPI
ChangeServiceConfigW( SC_HANDLE hService
, DWORD dwServiceType
,
1983 DWORD dwStartType
, DWORD dwErrorControl
, LPCWSTR lpBinaryPathName
,
1984 LPCWSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
, LPCWSTR lpDependencies
,
1985 LPCWSTR lpServiceStartName
, LPCWSTR lpPassword
, LPCWSTR lpDisplayName
)
1987 FIXME("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
1988 hService
, dwServiceType
, dwStartType
, dwErrorControl
,
1989 debugstr_w(lpBinaryPathName
), debugstr_w(lpLoadOrderGroup
),
1990 lpdwTagId
, lpDependencies
, debugstr_w(lpServiceStartName
),
1991 debugstr_w(lpPassword
), debugstr_w(lpDisplayName
) );
1995 /******************************************************************************
1996 * ChangeServiceConfigA [ADVAPI32.@]
1998 BOOL WINAPI
ChangeServiceConfigA( SC_HANDLE hService
, DWORD dwServiceType
,
1999 DWORD dwStartType
, DWORD dwErrorControl
, LPCSTR lpBinaryPathName
,
2000 LPCSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
, LPCSTR lpDependencies
,
2001 LPCSTR lpServiceStartName
, LPCSTR lpPassword
, LPCSTR lpDisplayName
)
2003 LPWSTR wBinaryPathName
, wLoadOrderGroup
, wDependencies
;
2004 LPWSTR wServiceStartName
, wPassword
, wDisplayName
;
2007 TRACE("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
2008 hService
, dwServiceType
, dwStartType
, dwErrorControl
,
2009 debugstr_a(lpBinaryPathName
), debugstr_a(lpLoadOrderGroup
),
2010 lpdwTagId
, lpDependencies
, debugstr_a(lpServiceStartName
),
2011 debugstr_a(lpPassword
), debugstr_a(lpDisplayName
) );
2013 wBinaryPathName
= SERV_dup( lpBinaryPathName
);
2014 wLoadOrderGroup
= SERV_dup( lpLoadOrderGroup
);
2015 wDependencies
= SERV_dupmulti( lpDependencies
);
2016 wServiceStartName
= SERV_dup( lpServiceStartName
);
2017 wPassword
= SERV_dup( lpPassword
);
2018 wDisplayName
= SERV_dup( lpDisplayName
);
2020 r
= ChangeServiceConfigW( hService
, dwServiceType
,
2021 dwStartType
, dwErrorControl
, wBinaryPathName
,
2022 wLoadOrderGroup
, lpdwTagId
, wDependencies
,
2023 wServiceStartName
, wPassword
, wDisplayName
);
2025 SERV_free( wBinaryPathName
);
2026 SERV_free( wLoadOrderGroup
);
2027 SERV_free( wDependencies
);
2028 SERV_free( wServiceStartName
);
2029 SERV_free( wPassword
);
2030 SERV_free( wDisplayName
);
2035 /******************************************************************************
2036 * ChangeServiceConfig2A [ADVAPI32.@]
2038 BOOL WINAPI
ChangeServiceConfig2A( SC_HANDLE hService
, DWORD dwInfoLevel
,
2043 TRACE("%p %ld %p\n",hService
, dwInfoLevel
, lpInfo
);
2045 if (dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
2047 LPSERVICE_DESCRIPTIONA sd
= (LPSERVICE_DESCRIPTIONA
) lpInfo
;
2048 SERVICE_DESCRIPTIONW sdw
;
2050 sdw
.lpDescription
= SERV_dup( sd
->lpDescription
);
2052 r
= ChangeServiceConfig2W( hService
, dwInfoLevel
, &sdw
);
2054 SERV_free( sdw
.lpDescription
);
2056 else if (dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
2058 LPSERVICE_FAILURE_ACTIONSA fa
= (LPSERVICE_FAILURE_ACTIONSA
) lpInfo
;
2059 SERVICE_FAILURE_ACTIONSW faw
;
2061 faw
.dwResetPeriod
= fa
->dwResetPeriod
;
2062 faw
.lpRebootMsg
= SERV_dup( fa
->lpRebootMsg
);
2063 faw
.lpCommand
= SERV_dup( fa
->lpCommand
);
2064 faw
.cActions
= fa
->cActions
;
2065 faw
.lpsaActions
= fa
->lpsaActions
;
2067 r
= ChangeServiceConfig2W( hService
, dwInfoLevel
, &faw
);
2069 SERV_free( faw
.lpRebootMsg
);
2070 SERV_free( faw
.lpCommand
);
2073 SetLastError( ERROR_INVALID_PARAMETER
);
2078 /******************************************************************************
2079 * ChangeServiceConfig2W [ADVAPI32.@]
2081 BOOL WINAPI
ChangeServiceConfig2W( SC_HANDLE hService
, DWORD dwInfoLevel
,
2085 struct sc_service
*hsvc
;
2087 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
2090 SetLastError( ERROR_INVALID_HANDLE
);
2095 if (dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
2097 static const WCHAR szDescription
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2098 LPSERVICE_DESCRIPTIONW sd
= (LPSERVICE_DESCRIPTIONW
)lpInfo
;
2099 if (sd
->lpDescription
)
2101 TRACE("Setting Description to %s\n",debugstr_w(sd
->lpDescription
));
2102 if (sd
->lpDescription
[0] == 0)
2103 RegDeleteValueW(hKey
,szDescription
);
2105 RegSetValueExW(hKey
, szDescription
, 0, REG_SZ
,
2106 (LPVOID
)sd
->lpDescription
,
2107 sizeof(WCHAR
)*(strlenW(sd
->lpDescription
)+1));
2111 FIXME("STUB: %p %ld %p\n",hService
, dwInfoLevel
, lpInfo
);
2115 /******************************************************************************
2116 * QueryServiceObjectSecurity [ADVAPI32.@]
2118 BOOL WINAPI
QueryServiceObjectSecurity(SC_HANDLE hService
,
2119 SECURITY_INFORMATION dwSecurityInformation
,
2120 PSECURITY_DESCRIPTOR lpSecurityDescriptor
,
2121 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
2125 FIXME("%p %ld %p %lu %p\n", hService
, dwSecurityInformation
,
2126 lpSecurityDescriptor
, cbBufSize
, pcbBytesNeeded
);
2128 InitializeSecurityDescriptor(lpSecurityDescriptor
, SECURITY_DESCRIPTOR_REVISION
);
2130 pACL
= HeapAlloc( GetProcessHeap(), 0, sizeof(ACL
) );
2131 InitializeAcl(pACL
, sizeof(ACL
), ACL_REVISION
);
2132 SetSecurityDescriptorDacl(lpSecurityDescriptor
, TRUE
, pACL
, TRUE
);
2136 /******************************************************************************
2137 * SetServiceObjectSecurity [ADVAPI32.@]
2139 BOOL WINAPI
SetServiceObjectSecurity(SC_HANDLE hService
,
2140 SECURITY_INFORMATION dwSecurityInformation
,
2141 PSECURITY_DESCRIPTOR lpSecurityDescriptor
)
2143 FIXME("%p %ld %p\n", hService
, dwSecurityInformation
, lpSecurityDescriptor
);
2147 /******************************************************************************
2148 * SetServiceBits [ADVAPI32.@]
2150 BOOL WINAPI
SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus
,
2151 DWORD dwServiceBits
,
2153 BOOL bUpdateImmediately
)
2155 FIXME("%08lx %08lx %x %x\n", hServiceStatus
, dwServiceBits
,
2156 bSetBitsOn
, bUpdateImmediately
);