2 * Win32 advapi functions
4 * Copyright 1995 Sven Verdoolaege
5 * Copyright 2005 Mike McCormack
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
32 #include "wine/unicode.h"
33 #include "wine/debug.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(advapi);
40 static const WCHAR szServiceManagerKey[] = { 'S','y','s','t','e','m','\\',
41 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
42 'S','e','r','v','i','c','e','s','\\',0 };
43 static const WCHAR szSCMLock[] = {'A','D','V','A','P','I','_','S','C','M',
46 typedef struct service_start_info_t
53 #define WINESERV_STARTINFO 1
54 #define WINESERV_GETSTATUS 2
55 #define WINESERV_SENDCONTROL 3
57 typedef struct service_data_t
59 struct service_data_t *next;
61 LPHANDLER_FUNCTION handler;
62 LPHANDLER_FUNCTION_EX handler_ex;
65 SERVICE_STATUS status;
68 BOOL extended : 1; /* uses handler_ex instead of handler? */
70 LPSERVICE_MAIN_FUNCTIONA a;
71 LPSERVICE_MAIN_FUNCTIONW w;
77 static CRITICAL_SECTION service_cs;
78 static CRITICAL_SECTION_DEBUG service_cs_debug =
81 { &service_cs_debug.ProcessLocksList,
82 &service_cs_debug.ProcessLocksList },
83 0, 0, { (DWORD_PTR)(__FILE__ ": service_cs") }
85 static CRITICAL_SECTION service_cs = { &service_cs_debug, -1, 0, 0, 0, 0 };
87 static service_data *service_list;
89 /******************************************************************************
93 #define MAX_SERVICE_NAME 256
95 typedef enum { SC_HTYPE_MANAGER, SC_HTYPE_SERVICE } SC_HANDLE_TYPE;
98 typedef VOID (*sc_handle_destructor)(struct sc_handle *);
102 SC_HANDLE_TYPE htype;
104 sc_handle_destructor destroy;
107 struct sc_manager /* service control manager handle */
109 struct sc_handle hdr;
110 HKEY hkey; /* handle to services database in the registry */
113 struct sc_service /* service handle */
115 struct sc_handle hdr;
116 HKEY hkey; /* handle to service entry in the registry (under hkey) */
117 struct sc_manager *scm; /* pointer to SCM handle */
121 static void *sc_handle_alloc(SC_HANDLE_TYPE htype, DWORD size,
122 sc_handle_destructor destroy)
124 struct sc_handle *hdr;
126 hdr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
131 hdr->destroy = destroy;
133 TRACE("sc_handle type=%d -> %p\n", htype, hdr);
137 static void *sc_handle_get_handle_data(SC_HANDLE handle, DWORD htype)
139 struct sc_handle *hdr = (struct sc_handle *) handle;
143 if (hdr->htype != htype)
148 static void sc_handle_free(struct sc_handle* hdr)
152 if (--hdr->ref_count)
155 HeapFree(GetProcessHeap(), 0, hdr);
158 static void sc_handle_destroy_manager(struct sc_handle *handle)
160 struct sc_manager *mgr = (struct sc_manager*) handle;
162 TRACE("destroying SC Manager %p\n", mgr);
164 RegCloseKey(mgr->hkey);
167 static void sc_handle_destroy_service(struct sc_handle *handle)
169 struct sc_service *svc = (struct sc_service*) handle;
171 TRACE("destroying service %p\n", svc);
173 RegCloseKey(svc->hkey);
175 sc_handle_free(&svc->scm->hdr);
179 /******************************************************************************
180 * String management functions
182 static inline LPWSTR SERV_dup( LPCSTR str )
189 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
190 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
191 MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
195 static inline LPWSTR SERV_dupmulti(LPCSTR str)
203 len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
204 n += (strlen( &str[n] ) + 1);
209 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
210 MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
214 static inline VOID SERV_free( LPWSTR wstr )
216 HeapFree( GetProcessHeap(), 0, wstr );
219 /******************************************************************************
220 * registry access functions and data
222 static const WCHAR szDisplayName[] = {
223 'D','i','s','p','l','a','y','N','a','m','e', 0 };
224 static const WCHAR szType[] = {'T','y','p','e',0};
225 static const WCHAR szStart[] = {'S','t','a','r','t',0};
226 static const WCHAR szError[] = {
227 'E','r','r','o','r','C','o','n','t','r','o','l', 0};
228 static const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
229 static const WCHAR szGroup[] = {'G','r','o','u','p',0};
230 static const WCHAR szDependencies[] = {
231 'D','e','p','e','n','d','e','n','c','i','e','s',0};
232 static const WCHAR szDependOnService[] = {
233 'D','e','p','e','n','d','O','n','S','e','r','v','i','c','e',0};
242 static inline void service_set_value( struct reg_value *val,
243 DWORD type, LPCWSTR name, LPCVOID data, DWORD size )
251 static inline void service_set_dword( struct reg_value *val,
252 LPCWSTR name, DWORD *data )
254 service_set_value( val, REG_DWORD, name, data, sizeof (DWORD));
257 static inline void service_set_string( struct reg_value *val,
258 LPCWSTR name, LPCWSTR string )
260 DWORD len = (lstrlenW(string)+1) * sizeof (WCHAR);
261 service_set_value( val, REG_SZ, name, string, len );
264 static inline void service_set_multi_string( struct reg_value *val,
265 LPCWSTR name, LPCWSTR string )
269 /* determine the length of a double null terminated multi string */
271 len += (lstrlenW( &string[ len ] )+1);
272 } while ( string[ len++ ] );
274 len *= sizeof (WCHAR);
275 service_set_value( val, REG_MULTI_SZ, name, string, len );
278 static inline LONG service_write_values( HKEY hKey,
279 struct reg_value *val, int n )
281 LONG r = ERROR_SUCCESS;
286 r = RegSetValueExW(hKey, val[i].name, 0, val[i].type,
287 (const BYTE*)val[i].data, val[i].size );
288 if( r != ERROR_SUCCESS )
294 /******************************************************************************
295 * Service IPC functions
297 static LPWSTR service_get_pipe_name(LPWSTR service)
299 static const WCHAR prefix[] = { '\\','\\','.','\\','p','i','p','e','\\',
300 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
304 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
305 name = HeapAlloc(GetProcessHeap(), 0, len);
306 strcpyW(name, prefix);
307 strcatW(name, service);
311 static HANDLE service_open_pipe(LPWSTR service)
313 LPWSTR szPipe = service_get_pipe_name( service );
314 HANDLE handle = INVALID_HANDLE_VALUE;
317 handle = CreateFileW(szPipe, GENERIC_READ|GENERIC_WRITE,
318 0, NULL, OPEN_ALWAYS, 0, NULL);
319 if (handle != INVALID_HANDLE_VALUE)
321 if (GetLastError() != ERROR_PIPE_BUSY)
323 } while (WaitNamedPipeW(szPipe, NMPWAIT_WAIT_FOREVER));
329 /******************************************************************************
330 * service_get_event_handle
332 static HANDLE service_get_event_handle(LPWSTR service)
334 static const WCHAR prefix[] = {
335 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
340 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
341 name = HeapAlloc(GetProcessHeap(), 0, len);
342 strcpyW(name, prefix);
343 strcatW(name, service);
344 handle = CreateEventW(NULL, TRUE, FALSE, name);
349 /******************************************************************************
352 * Call into the main service routine provided by StartServiceCtrlDispatcher.
354 static DWORD WINAPI service_thread(LPVOID arg)
356 service_data *info = arg;
357 LPWSTR str = info->args;
358 DWORD argc = 0, len = 0;
364 len += strlenW(&str[len]) + 1;
371 info->proc.w(0, NULL);
373 info->proc.a(0, NULL);
381 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPWSTR));
382 for (argc=0, p=str; *p; p += strlenW(p) + 1)
386 info->proc.w(argc, argv);
387 HeapFree(GetProcessHeap(), 0, argv);
391 LPSTR strA, *argv, p;
394 lenA = WideCharToMultiByte(CP_ACP,0, str, len, NULL, 0, NULL, NULL);
395 strA = HeapAlloc(GetProcessHeap(), 0, lenA);
396 WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL);
398 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPSTR));
399 for (argc=0, p=strA; *p; p += strlen(p) + 1)
403 info->proc.a(argc, argv);
404 HeapFree(GetProcessHeap(), 0, argv);
405 HeapFree(GetProcessHeap(), 0, strA);
410 /******************************************************************************
411 * service_handle_start
413 static BOOL service_handle_start(HANDLE pipe, service_data *service, DWORD count)
415 DWORD read = 0, result = 0;
419 TRACE("%p %p %ld\n", pipe, service, count);
421 args = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
422 r = ReadFile(pipe, args, count*sizeof(WCHAR), &read, NULL);
423 if (!r || count!=read/sizeof(WCHAR) || args[count-1])
425 ERR("pipe read failed r = %d count = %ld/%ld args[n-1]=%s\n",
426 r, count, read/sizeof(WCHAR), debugstr_wn(args, count));
432 ERR("service is not stopped\n");
437 SERV_free(service->args);
438 service->args = args;
440 service->thread = CreateThread( NULL, 0, service_thread,
444 HeapFree(GetProcessHeap(), 0, args);
445 WriteFile( pipe, &result, sizeof result, &read, NULL );
450 /******************************************************************************
451 * service_send_start_message
453 static BOOL service_send_start_message(HANDLE pipe, LPCWSTR *argv, DWORD argc)
455 DWORD i, len, count, result;
456 service_start_info *ssi;
460 TRACE("%p %p %ld\n", pipe, argv, argc);
462 /* calculate how much space do we need to send the startup info */
464 for (i=0; i<argc; i++)
465 len += strlenW(argv[i])+1;
467 ssi = HeapAlloc(GetProcessHeap(),0,sizeof *ssi + (len-1)*sizeof(WCHAR));
468 ssi->cmd = WINESERV_STARTINFO;
471 /* copy service args into a single buffer*/
473 for (i=0; i<argc; i++)
480 r = WriteFile(pipe, ssi, sizeof *ssi + len*sizeof(WCHAR), &count, NULL);
482 r = ReadFile(pipe, &result, sizeof result, &count, NULL);
484 HeapFree(GetProcessHeap(),0,ssi);
489 /******************************************************************************
490 * service_handle_get_status
492 static BOOL service_handle_get_status(HANDLE pipe, service_data *service)
496 return WriteFile(pipe, &service->status,
497 sizeof service->status, &count, NULL);
500 /******************************************************************************
503 static BOOL service_get_status(HANDLE pipe, LPSERVICE_STATUS status)
505 DWORD cmd[2], count = 0;
508 cmd[0] = WINESERV_GETSTATUS;
510 r = WriteFile( pipe, cmd, sizeof cmd, &count, NULL );
511 if (!r || count != sizeof cmd)
513 ERR("service protocol error - failed to write pipe!\n");
516 r = ReadFile( pipe, status, sizeof *status, &count, NULL );
517 if (!r || count != sizeof *status)
518 ERR("service protocol error - failed to read pipe "
519 "r = %d count = %ld!\n", r, count);
523 /******************************************************************************
524 * service_send_control
526 static BOOL service_send_control(HANDLE pipe, DWORD dwControl, DWORD *result)
528 DWORD cmd[2], count = 0;
531 cmd[0] = WINESERV_SENDCONTROL;
533 r = WriteFile(pipe, cmd, sizeof cmd, &count, NULL);
534 if (!r || count != sizeof cmd)
536 ERR("service protocol error - failed to write pipe!\n");
539 r = ReadFile(pipe, result, sizeof *result, &count, NULL);
540 if (!r || count != sizeof *result)
541 ERR("service protocol error - failed to read pipe "
542 "r = %d count = %ld!\n", r, count);
546 /******************************************************************************
547 * service_accepts_control
549 static BOOL service_accepts_control(service_data *service, DWORD dwControl)
551 DWORD a = service->status.dwControlsAccepted;
555 case SERVICE_CONTROL_INTERROGATE:
557 case SERVICE_CONTROL_STOP:
558 if (a&SERVICE_ACCEPT_STOP)
561 case SERVICE_CONTROL_SHUTDOWN:
562 if (a&SERVICE_ACCEPT_SHUTDOWN)
565 case SERVICE_CONTROL_PAUSE:
566 case SERVICE_CONTROL_CONTINUE:
567 if (a&SERVICE_ACCEPT_PAUSE_CONTINUE)
570 case SERVICE_CONTROL_PARAMCHANGE:
571 if (a&SERVICE_ACCEPT_PARAMCHANGE)
574 case SERVICE_CONTROL_NETBINDADD:
575 case SERVICE_CONTROL_NETBINDREMOVE:
576 case SERVICE_CONTROL_NETBINDENABLE:
577 case SERVICE_CONTROL_NETBINDDISABLE:
578 if (a&SERVICE_ACCEPT_NETBINDCHANGE)
581 if (!service->extended)
585 case SERVICE_CONTROL_HARDWAREPROFILECHANGE:
586 if (a&SERVICE_ACCEPT_HARDWAREPROFILECHANGE)
589 case SERVICE_CONTROL_POWEREVENT:
590 if (a&SERVICE_ACCEPT_POWEREVENT)
593 case SERVICE_CONTROL_SESSIONCHANGE:
594 if (a&SERVICE_ACCEPT_SESSIONCHANGE)
601 /******************************************************************************
602 * service_handle_control
604 static BOOL service_handle_control(HANDLE pipe, service_data *service,
607 DWORD count, ret = ERROR_INVALID_SERVICE_CONTROL;
609 TRACE("received control %ld\n", dwControl);
611 if (service_accepts_control(service, dwControl))
613 if (service->extended && service->handler.handler_ex)
615 service->handler.handler_ex(dwControl, 0, NULL, service->context);
618 else if (service->handler.handler)
620 service->handler.handler(dwControl);
624 return WriteFile(pipe, &ret, sizeof ret, &count, NULL);
627 /******************************************************************************
628 * service_reap_thread
630 static DWORD service_reap_thread(service_data *service)
634 if (!service->thread)
636 GetExitCodeThread(service->thread, &exitcode);
637 if (exitcode!=STILL_ACTIVE)
639 CloseHandle(service->thread);
645 /******************************************************************************
646 * service_control_dispatcher
648 static DWORD WINAPI service_control_dispatcher(LPVOID arg)
650 service_data *service = arg;
654 TRACE("%p %s\n", service, debugstr_w(service->name));
656 /* create a pipe to talk to the rest of the world with */
657 name = service_get_pipe_name(service->name);
658 pipe = CreateNamedPipeW(name, PIPE_ACCESS_DUPLEX,
659 PIPE_TYPE_BYTE|PIPE_WAIT, 1, 256, 256, 10000, NULL );
662 /* let the process who started us know we've tried to create a pipe */
663 event = service_get_event_handle(service->name);
667 if (pipe==INVALID_HANDLE_VALUE)
669 ERR("failed to create pipe for %s, error = %ld\n",
670 debugstr_w(service->name), GetLastError());
674 /* dispatcher loop */
678 DWORD count, req[2] = {0,0};
680 r = ConnectNamedPipe(pipe, NULL);
681 if (!r && GetLastError() != ERROR_PIPE_CONNECTED)
683 ERR("pipe connect failed\n");
687 r = ReadFile( pipe, &req, sizeof req, &count, NULL );
688 if (!r || count!=sizeof req)
690 ERR("pipe read failed\n");
694 service_reap_thread(service);
696 /* handle the request */
699 case WINESERV_STARTINFO:
700 service_handle_start(pipe, service, req[1]);
702 case WINESERV_GETSTATUS:
703 service_handle_get_status(pipe, service);
705 case WINESERV_SENDCONTROL:
706 service_handle_control(pipe, service, req[1]);
709 ERR("received invalid command %ld length %ld\n", req[0], req[1]);
712 FlushFileBuffers(pipe);
713 DisconnectNamedPipe(pipe);
720 /******************************************************************************
721 * service_run_threads
723 static BOOL service_run_threads(void)
725 service_data *service;
726 DWORD count = 0, n = 0;
729 EnterCriticalSection( &service_cs );
731 /* count how many services there are */
732 for (service = service_list; service; service = service->next)
735 TRACE("starting %ld pipe listener threads\n", count);
737 handles = HeapAlloc(GetProcessHeap(), 0, sizeof(HANDLE)*count);
739 for (n=0, service = service_list; service; service = service->next, n++)
740 handles[n] = CreateThread( NULL, 0, service_control_dispatcher,
744 LeaveCriticalSection( &service_cs );
746 /* wait for all the threads to pack up and exit */
747 WaitForMultipleObjectsEx(count, handles, TRUE, INFINITE, FALSE);
749 HeapFree(GetProcessHeap(), 0, handles);
754 /******************************************************************************
755 * StartServiceCtrlDispatcherA [ADVAPI32.@]
757 * See StartServiceCtrlDispatcherW.
759 BOOL WINAPI StartServiceCtrlDispatcherA( LPSERVICE_TABLE_ENTRYA servent )
765 TRACE("%p\n", servent);
767 EnterCriticalSection( &service_cs );
768 while (servent->lpServiceName)
770 LPSTR name = servent->lpServiceName;
772 len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0);
773 sz = len*sizeof(WCHAR) + sizeof *info;
774 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
775 MultiByteToWideChar(CP_ACP, 0, name, -1, info->name, len);
776 info->proc.a = servent->lpServiceProc;
777 info->unicode = FALSE;
779 /* insert into the list */
780 info->next = service_list;
785 LeaveCriticalSection( &service_cs );
787 service_run_threads();
792 /******************************************************************************
793 * StartServiceCtrlDispatcherW [ADVAPI32.@]
795 * Connects a process containing one or more services to the service control
799 * servent [I] A list of the service names and service procedures
805 BOOL WINAPI StartServiceCtrlDispatcherW( LPSERVICE_TABLE_ENTRYW servent )
811 TRACE("%p\n", servent);
813 EnterCriticalSection( &service_cs );
814 while (servent->lpServiceName)
816 LPWSTR name = servent->lpServiceName;
819 sz = len*sizeof(WCHAR) + sizeof *info;
820 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
821 strcpyW(info->name, name);
822 info->proc.w = servent->lpServiceProc;
823 info->unicode = TRUE;
825 /* insert into the list */
826 info->next = service_list;
831 LeaveCriticalSection( &service_cs );
833 service_run_threads();
838 /******************************************************************************
839 * LockServiceDatabase [ADVAPI32.@]
841 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
845 TRACE("%p\n",hSCManager);
847 ret = CreateSemaphoreW( NULL, 1, 1, szSCMLock );
848 if( ret && GetLastError() == ERROR_ALREADY_EXISTS )
852 SetLastError( ERROR_SERVICE_DATABASE_LOCKED );
855 TRACE("returning %p\n", ret);
860 /******************************************************************************
861 * UnlockServiceDatabase [ADVAPI32.@]
863 BOOL WINAPI UnlockServiceDatabase (SC_LOCK ScLock)
865 TRACE("%p\n",ScLock);
867 return CloseHandle( ScLock );
870 /******************************************************************************
871 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
873 SERVICE_STATUS_HANDLE WINAPI
874 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName, LPHANDLER_FUNCTION lpfHandler )
876 LPWSTR lpServiceNameW;
877 SERVICE_STATUS_HANDLE ret;
879 lpServiceNameW = SERV_dup(lpServiceName);
880 ret = RegisterServiceCtrlHandlerW( lpServiceNameW, lpfHandler );
881 SERV_free(lpServiceNameW);
885 /******************************************************************************
886 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
892 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName,
893 LPHANDLER_FUNCTION lpfHandler )
895 service_data *service;
897 EnterCriticalSection( &service_cs );
898 for(service = service_list; service; service = service->next)
899 if(!strcmpW(lpServiceName, service->name))
902 service->handler.handler = lpfHandler;
903 LeaveCriticalSection( &service_cs );
905 return (SERVICE_STATUS_HANDLE)service;
908 /******************************************************************************
909 * SetServiceStatus [ADVAPI32.@]
916 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
918 service_data *service;
921 TRACE("%p %lx %lx %lx %lx %lx %lx %lx\n", hService,
922 lpStatus->dwServiceType, lpStatus->dwCurrentState,
923 lpStatus->dwControlsAccepted, lpStatus->dwWin32ExitCode,
924 lpStatus->dwServiceSpecificExitCode, lpStatus->dwCheckPoint,
925 lpStatus->dwWaitHint);
927 EnterCriticalSection( &service_cs );
928 for (service = service_list; service; service = service->next)
929 if(service == (service_data*)hService)
933 memcpy( &service->status, lpStatus, sizeof(SERVICE_STATUS) );
934 TRACE("Set service status to %ld\n",service->status.dwCurrentState);
938 LeaveCriticalSection( &service_cs );
944 /******************************************************************************
945 * OpenSCManagerA [ADVAPI32.@]
947 * Establish a connection to the service control manager and open its database.
950 * lpMachineName [I] Pointer to machine name string
951 * lpDatabaseName [I] Pointer to database name string
952 * dwDesiredAccess [I] Type of access
955 * Success: A Handle to the service control manager database
958 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
959 DWORD dwDesiredAccess )
961 LPWSTR lpMachineNameW, lpDatabaseNameW;
964 lpMachineNameW = SERV_dup(lpMachineName);
965 lpDatabaseNameW = SERV_dup(lpDatabaseName);
966 ret = OpenSCManagerW(lpMachineNameW, lpDatabaseNameW, dwDesiredAccess);
967 SERV_free(lpDatabaseNameW);
968 SERV_free(lpMachineNameW);
972 /******************************************************************************
973 * OpenSCManagerW [ADVAPI32.@]
975 * See OpenSCManagerA.
977 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
978 DWORD dwDesiredAccess )
980 struct sc_manager *manager;
984 TRACE("(%s,%s,0x%08lx)\n", debugstr_w(lpMachineName),
985 debugstr_w(lpDatabaseName), dwDesiredAccess);
987 if( lpDatabaseName && lpDatabaseName[0] )
989 if( strcmpiW( lpDatabaseName, SERVICES_ACTIVE_DATABASEW ) == 0 )
991 /* noop, all right */
993 else if( strcmpiW( lpDatabaseName, SERVICES_FAILED_DATABASEW ) == 0 )
995 SetLastError( ERROR_DATABASE_DOES_NOT_EXIST );
1000 SetLastError( ERROR_INVALID_NAME );
1005 manager = sc_handle_alloc( SC_HTYPE_MANAGER, sizeof (struct sc_manager),
1006 sc_handle_destroy_manager );
1010 r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
1011 if (r!=ERROR_SUCCESS)
1014 r = RegOpenKeyExW(hReg, szServiceManagerKey,
1015 0, KEY_ALL_ACCESS, &manager->hkey);
1016 RegCloseKey( hReg );
1017 if (r!=ERROR_SUCCESS)
1020 TRACE("returning %p\n", manager);
1022 return (SC_HANDLE) &manager->hdr;
1025 sc_handle_free( &manager->hdr );
1030 /******************************************************************************
1031 * ControlService [ADVAPI32.@]
1033 * Send a control code to a service.
1036 * hService [I] Handle of the service control manager database
1037 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
1038 * lpServiceStatus [O] Destination for the status of the service, if available
1045 * Unlike M$' implementation, control requests are not serialized and may be
1046 * processed asynchronously.
1048 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
1049 LPSERVICE_STATUS lpServiceStatus )
1051 struct sc_service *hsvc;
1055 TRACE("%p %ld %p\n", hService, dwControl, lpServiceStatus);
1057 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1060 SetLastError( ERROR_INVALID_HANDLE );
1064 ret = QueryServiceStatus(hService, lpServiceStatus);
1067 ERR("failed to query service status\n");
1068 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1072 switch (lpServiceStatus->dwCurrentState)
1074 case SERVICE_STOPPED:
1075 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1077 case SERVICE_START_PENDING:
1078 if (dwControl==SERVICE_CONTROL_STOP)
1081 case SERVICE_STOP_PENDING:
1082 SetLastError(ERROR_SERVICE_CANNOT_ACCEPT_CTRL);
1086 handle = service_open_pipe(hsvc->name);
1087 if (handle!=INVALID_HANDLE_VALUE)
1089 DWORD result = ERROR_SUCCESS;
1090 ret = service_send_control(handle, dwControl, &result);
1091 CloseHandle(handle);
1092 if (result!=ERROR_SUCCESS)
1094 SetLastError(result);
1102 /******************************************************************************
1103 * CloseServiceHandle [ADVAPI32.@]
1105 * Close a handle to a service or the service control manager database.
1108 * hSCObject [I] Handle to service or service control manager database
1115 CloseServiceHandle( SC_HANDLE hSCObject )
1117 TRACE("%p\n", hSCObject);
1119 sc_handle_free( (struct sc_handle*) hSCObject );
1125 /******************************************************************************
1126 * OpenServiceA [ADVAPI32.@]
1128 * Open a handle to a service.
1131 * hSCManager [I] Handle of the service control manager database
1132 * lpServiceName [I] Name of the service to open
1133 * dwDesiredAccess [I] Access required to the service
1136 * Success: Handle to the service
1139 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1140 DWORD dwDesiredAccess )
1142 LPWSTR lpServiceNameW;
1145 TRACE("%p %s %ld\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
1147 lpServiceNameW = SERV_dup(lpServiceName);
1148 ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
1149 SERV_free(lpServiceNameW);
1154 /******************************************************************************
1155 * OpenServiceW [ADVAPI32.@]
1159 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1160 DWORD dwDesiredAccess)
1162 struct sc_manager *hscm;
1163 struct sc_service *hsvc;
1168 TRACE("%p %s %ld\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
1172 SetLastError(ERROR_INVALID_ADDRESS);
1176 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1179 SetLastError( ERROR_INVALID_HANDLE );
1183 r = RegOpenKeyExW( hscm->hkey, lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
1184 if (r!=ERROR_SUCCESS)
1186 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
1190 len = strlenW(lpServiceName)+1;
1191 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE,
1192 sizeof (struct sc_service) + len*sizeof(WCHAR),
1193 sc_handle_destroy_service );
1196 strcpyW( hsvc->name, lpServiceName );
1199 /* add reference to SCM handle */
1200 hscm->hdr.ref_count++;
1203 TRACE("returning %p\n",hsvc);
1205 return (SC_HANDLE) &hsvc->hdr;
1208 /******************************************************************************
1209 * CreateServiceW [ADVAPI32.@]
1212 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1213 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
1214 DWORD dwServiceType, DWORD dwStartType,
1215 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1216 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1217 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
1218 LPCWSTR lpPassword )
1220 struct sc_manager *hscm;
1221 struct sc_service *hsvc = NULL;
1225 struct reg_value val[10];
1228 TRACE("%p %s %s\n", hSCManager,
1229 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
1231 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1234 SetLastError( ERROR_INVALID_HANDLE );
1238 r = RegCreateKeyExW(hscm->hkey, lpServiceName, 0, NULL,
1239 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
1240 if (r!=ERROR_SUCCESS)
1243 if (dp != REG_CREATED_NEW_KEY)
1245 SetLastError(ERROR_SERVICE_EXISTS);
1250 service_set_string( &val[n++], szDisplayName, lpDisplayName );
1252 service_set_dword( &val[n++], szType, &dwServiceType );
1253 service_set_dword( &val[n++], szStart, &dwStartType );
1254 service_set_dword( &val[n++], szError, &dwErrorControl );
1256 if( lpBinaryPathName )
1257 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
1259 if( lpLoadOrderGroup )
1260 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
1262 if( lpDependencies )
1263 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
1266 FIXME("Don't know how to add a Password for a service.\n");
1268 if( lpServiceStartName )
1269 service_set_string( &val[n++], szDependOnService, lpServiceStartName );
1271 r = service_write_values( hKey, val, n );
1272 if( r != ERROR_SUCCESS )
1275 len = strlenW(lpServiceName)+1;
1276 len = sizeof (struct sc_service) + len*sizeof(WCHAR);
1277 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE, len, sc_handle_destroy_service );
1280 lstrcpyW( hsvc->name, lpServiceName );
1283 hscm->hdr.ref_count++;
1285 return (SC_HANDLE) &hsvc->hdr;
1288 RegCloseKey( hKey );
1293 /******************************************************************************
1294 * CreateServiceA [ADVAPI32.@]
1297 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1298 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1299 DWORD dwServiceType, DWORD dwStartType,
1300 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1301 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1302 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1305 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1306 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1309 TRACE("%p %s %s\n", hSCManager,
1310 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1312 lpServiceNameW = SERV_dup( lpServiceName );
1313 lpDisplayNameW = SERV_dup( lpDisplayName );
1314 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1315 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1316 lpDependenciesW = SERV_dupmulti( lpDependencies );
1317 lpServiceStartNameW = SERV_dup( lpServiceStartName );
1318 lpPasswordW = SERV_dup( lpPassword );
1320 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1321 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1322 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1323 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1325 SERV_free( lpServiceNameW );
1326 SERV_free( lpDisplayNameW );
1327 SERV_free( lpBinaryPathNameW );
1328 SERV_free( lpLoadOrderGroupW );
1329 SERV_free( lpDependenciesW );
1330 SERV_free( lpServiceStartNameW );
1331 SERV_free( lpPasswordW );
1337 /******************************************************************************
1338 * DeleteService [ADVAPI32.@]
1340 * Delete a service from the service control manager database.
1343 * hService [I] Handle of the service to delete
1349 BOOL WINAPI DeleteService( SC_HANDLE hService )
1351 struct sc_service *hsvc;
1353 WCHAR valname[MAX_PATH+1];
1358 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1361 SetLastError( ERROR_INVALID_HANDLE );
1367 /* Clean out the values */
1368 rc = RegEnumValueW(hKey, index, valname,&size,0,0,0,0);
1369 while (rc == ERROR_SUCCESS)
1371 RegDeleteValueW(hKey,valname);
1374 rc = RegEnumValueW(hKey, index, valname, &size,0,0,0,0);
1380 /* delete the key */
1381 RegDeleteKeyW(hsvc->scm->hkey, hsvc->name);
1387 /******************************************************************************
1388 * StartServiceA [ADVAPI32.@]
1393 * hService [I] Handle of service
1394 * dwNumServiceArgs [I] Number of arguments
1395 * lpServiceArgVectors [I] Address of array of argument strings
1398 * - NT implements this function using an obscure RPC call.
1399 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1400 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1401 * - This will only work for shared address space. How should the service
1402 * args be transferred when address spaces are separated?
1403 * - Can only start one service at a time.
1404 * - Has no concept of privilege.
1410 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1411 LPCSTR *lpServiceArgVectors )
1413 LPWSTR *lpwstr=NULL;
1417 TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1419 if (dwNumServiceArgs)
1420 lpwstr = HeapAlloc( GetProcessHeap(), 0,
1421 dwNumServiceArgs*sizeof(LPWSTR) );
1423 for(i=0; i<dwNumServiceArgs; i++)
1424 lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1426 r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1428 if (dwNumServiceArgs)
1430 for(i=0; i<dwNumServiceArgs; i++)
1431 SERV_free(lpwstr[i]);
1432 HeapFree(GetProcessHeap(), 0, lpwstr);
1438 /******************************************************************************
1439 * service_start_process [INTERNAL]
1441 static DWORD service_start_process(struct sc_service *hsvc)
1443 static const WCHAR _ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0};
1444 PROCESS_INFORMATION pi;
1446 LPWSTR path = NULL, str;
1447 DWORD type, size, ret;
1451 /* read the executable path from memory */
1453 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, NULL, &size);
1454 if (ret!=ERROR_SUCCESS)
1456 str = HeapAlloc(GetProcessHeap(),0,size);
1457 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, (LPBYTE)str, &size);
1458 if (ret==ERROR_SUCCESS)
1460 size = ExpandEnvironmentStringsW(str,NULL,0);
1461 path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
1462 ExpandEnvironmentStringsW(str,path,size);
1464 HeapFree(GetProcessHeap(),0,str);
1468 /* wait for the process to start and set an event or terminate */
1469 handles[0] = service_get_event_handle( hsvc->name );
1470 ZeroMemory(&si, sizeof(STARTUPINFOW));
1471 si.cb = sizeof(STARTUPINFOW);
1472 r = CreateProcessW(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1475 handles[1] = pi.hProcess;
1476 ret = WaitForMultipleObjectsEx(2, handles, FALSE, 30000, FALSE);
1477 if(ret != WAIT_OBJECT_0)
1479 SetLastError(ERROR_IO_PENDING);
1483 CloseHandle( pi.hThread );
1484 CloseHandle( pi.hProcess );
1486 CloseHandle( handles[0] );
1487 HeapFree(GetProcessHeap(),0,path);
1491 static BOOL service_wait_for_startup(SC_HANDLE hService)
1494 SERVICE_STATUS status;
1497 TRACE("%p\n", hService);
1499 for (i=0; i<30; i++)
1501 status.dwCurrentState = 0;
1502 r = QueryServiceStatus(hService, &status);
1505 if (status.dwCurrentState == SERVICE_RUNNING)
1507 TRACE("Service started successfully\n");
1516 /******************************************************************************
1517 * StartServiceW [ADVAPI32.@]
1519 * See StartServiceA.
1521 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1522 LPCWSTR *lpServiceArgVectors)
1524 struct sc_service *hsvc;
1527 HANDLE handle = INVALID_HANDLE_VALUE;
1529 TRACE("%p %ld %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1531 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1534 SetLastError(ERROR_INVALID_HANDLE);
1538 hLock = LockServiceDatabase((SC_HANDLE)hsvc->scm);
1542 handle = service_open_pipe(hsvc->name);
1543 if (handle==INVALID_HANDLE_VALUE)
1545 /* start the service process */
1546 if (service_start_process(hsvc))
1547 handle = service_open_pipe(hsvc->name);
1550 if (handle != INVALID_HANDLE_VALUE)
1552 service_send_start_message(handle, lpServiceArgVectors, dwNumServiceArgs);
1553 CloseHandle(handle);
1557 UnlockServiceDatabase( hLock );
1559 TRACE("returning %d\n", r);
1562 service_wait_for_startup(hService);
1567 /******************************************************************************
1568 * QueryServiceStatus [ADVAPI32.@]
1572 * lpservicestatus []
1575 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1576 LPSERVICE_STATUS lpservicestatus)
1578 struct sc_service *hsvc;
1579 DWORD size, type, val;
1583 TRACE("%p %p\n", hService, lpservicestatus);
1585 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1588 SetLastError( ERROR_INVALID_HANDLE );
1592 pipe = service_open_pipe(hsvc->name);
1593 if (pipe != INVALID_HANDLE_VALUE)
1595 r = service_get_status(pipe, lpservicestatus);
1601 TRACE("Failed to read service status\n");
1603 /* read the service type from the registry */
1605 r = RegQueryValueExA(hsvc->hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1606 if(r!=ERROR_SUCCESS || type!=REG_DWORD)
1609 lpservicestatus->dwServiceType = val;
1610 lpservicestatus->dwCurrentState = SERVICE_STOPPED; /* stopped */
1611 lpservicestatus->dwControlsAccepted = 0;
1612 lpservicestatus->dwWin32ExitCode = ERROR_SERVICE_NEVER_STARTED;
1613 lpservicestatus->dwServiceSpecificExitCode = 0;
1614 lpservicestatus->dwCheckPoint = 0;
1615 lpservicestatus->dwWaitHint = 0;
1620 /******************************************************************************
1621 * QueryServiceStatusEx [ADVAPI32.@]
1623 * Get information about a service.
1626 * hService [I] Handle to service to get information about
1627 * InfoLevel [I] Level of information to get
1628 * lpBuffer [O] Destination for requested information
1629 * cbBufSize [I] Size of lpBuffer in bytes
1630 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1636 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1637 LPBYTE lpBuffer, DWORD cbBufSize,
1638 LPDWORD pcbBytesNeeded)
1641 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1645 /******************************************************************************
1646 * QueryServiceConfigA [ADVAPI32.@]
1649 QueryServiceConfigA( SC_HANDLE hService,
1650 LPQUERY_SERVICE_CONFIGA lpServiceConfig,
1651 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1653 static const CHAR szDisplayName[] = "DisplayName";
1654 static const CHAR szType[] = "Type";
1655 static const CHAR szStart[] = "Start";
1656 static const CHAR szError[] = "ErrorControl";
1657 static const CHAR szImagePath[] = "ImagePath";
1658 static const CHAR szGroup[] = "Group";
1659 static const CHAR szDependencies[] = "Dependencies";
1660 struct sc_service *hsvc;
1662 CHAR str_buffer[ MAX_PATH ];
1664 DWORD type, val, sz, total, n;
1667 TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
1668 cbBufSize, pcbBytesNeeded);
1670 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1673 SetLastError( ERROR_INVALID_HANDLE );
1678 /* calculate the size required first */
1679 total = sizeof (QUERY_SERVICE_CONFIGA);
1681 sz = sizeof(str_buffer);
1682 r = RegQueryValueExA( hKey, szImagePath, 0, &type, (LPBYTE)str_buffer, &sz );
1683 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1685 sz = ExpandEnvironmentStringsA(str_buffer,NULL,0);
1686 if( 0 == sz ) return FALSE;
1692 /* FIXME: set last error */
1697 r = RegQueryValueExA( hKey, szGroup, 0, &type, NULL, &sz );
1698 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1702 r = RegQueryValueExA( hKey, szDependencies, 0, &type, NULL, &sz );
1703 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1707 r = RegQueryValueExA( hKey, szStart, 0, &type, NULL, &sz );
1708 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1712 r = RegQueryValueExA( hKey, szDisplayName, 0, &type, NULL, &sz );
1713 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1716 *pcbBytesNeeded = total;
1718 /* if there's not enough memory, return an error */
1719 if( total > cbBufSize )
1721 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1725 ZeroMemory( lpServiceConfig, total );
1728 r = RegQueryValueExA( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1729 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1730 lpServiceConfig->dwServiceType = val;
1733 r = RegQueryValueExA( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1734 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1735 lpServiceConfig->dwStartType = val;
1738 r = RegQueryValueExA( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1739 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1740 lpServiceConfig->dwErrorControl = val;
1742 /* now do the strings */
1743 p = (LPSTR) &lpServiceConfig[1];
1744 n = total - sizeof (QUERY_SERVICE_CONFIGA);
1746 sz = sizeof(str_buffer);
1747 r = RegQueryValueExA( hKey, szImagePath, 0, &type, (LPBYTE)str_buffer, &sz );
1748 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1750 sz = ExpandEnvironmentStringsA(str_buffer, p, n);
1751 if( 0 == sz || sz > n ) return FALSE;
1753 lpServiceConfig->lpBinaryPathName = p;
1759 /* FIXME: set last error */
1764 r = RegQueryValueExA( hKey, szGroup, 0, &type, (LPBYTE)p, &sz );
1765 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1767 lpServiceConfig->lpLoadOrderGroup = p;
1773 r = RegQueryValueExA( hKey, szDependencies, 0, &type, (LPBYTE)p, &sz );
1774 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1776 lpServiceConfig->lpDependencies = p;
1782 ERR("Buffer overflow!\n");
1784 TRACE("Image path = %s\n", lpServiceConfig->lpBinaryPathName );
1785 TRACE("Group = %s\n", lpServiceConfig->lpLoadOrderGroup );
1790 /******************************************************************************
1791 * QueryServiceConfigW [ADVAPI32.@]
1794 QueryServiceConfigW( SC_HANDLE hService,
1795 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1796 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1798 WCHAR str_buffer[ MAX_PATH ];
1800 DWORD type, val, sz, total, n;
1803 struct sc_service *hsvc;
1805 TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
1806 cbBufSize, pcbBytesNeeded);
1808 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1811 SetLastError( ERROR_INVALID_HANDLE );
1816 /* calculate the size required first */
1817 total = sizeof (QUERY_SERVICE_CONFIGW);
1819 sz = sizeof(str_buffer);
1820 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1821 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1823 sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1824 if( 0 == sz ) return FALSE;
1826 total += sizeof(WCHAR) * sz;
1830 /* FIXME: set last error */
1835 r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1836 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1840 r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1841 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1844 total += sizeof(WCHAR);
1847 r = RegQueryValueExW( hKey, szStart, 0, &type, NULL, &sz );
1848 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1852 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1853 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1856 *pcbBytesNeeded = total;
1858 /* if there's not enough memory, return an error */
1859 if( total > cbBufSize )
1861 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1865 ZeroMemory( lpServiceConfig, total );
1868 r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1869 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1870 lpServiceConfig->dwServiceType = val;
1873 r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1874 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1875 lpServiceConfig->dwStartType = val;
1878 r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1879 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1880 lpServiceConfig->dwErrorControl = val;
1882 /* now do the strings */
1883 p = (LPBYTE) &lpServiceConfig[1];
1884 n = total - sizeof (QUERY_SERVICE_CONFIGW);
1886 sz = sizeof(str_buffer);
1887 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1888 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1890 sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
1891 sz *= sizeof(WCHAR);
1892 if( 0 == sz || sz > n ) return FALSE;
1894 lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
1900 /* FIXME: set last error */
1905 r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
1906 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1908 lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
1914 r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
1915 lpServiceConfig->lpDependencies = (LPWSTR) p;
1916 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1929 ERR("Buffer overflow!\n");
1931 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1932 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1937 /******************************************************************************
1938 * EnumServicesStatusA [ADVAPI32.@]
1941 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
1942 DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
1943 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1944 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1946 FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
1947 dwServiceType, dwServiceState, lpServices, cbBufSize,
1948 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
1949 SetLastError (ERROR_ACCESS_DENIED);
1953 /******************************************************************************
1954 * EnumServicesStatusW [ADVAPI32.@]
1957 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
1958 DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
1959 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1960 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1962 FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
1963 dwServiceType, dwServiceState, lpServices, cbBufSize,
1964 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
1965 SetLastError (ERROR_ACCESS_DENIED);
1969 /******************************************************************************
1970 * GetServiceKeyNameA [ADVAPI32.@]
1972 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
1973 LPSTR lpServiceName, LPDWORD lpcchBuffer )
1975 FIXME("%p %s %p %p\n", hSCManager, debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
1979 /******************************************************************************
1980 * GetServiceKeyNameW [ADVAPI32.@]
1982 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
1983 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
1985 FIXME("%p %s %p %p\n", hSCManager, debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
1989 /******************************************************************************
1990 * QueryServiceLockStatusA [ADVAPI32.@]
1992 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
1993 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
1994 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1996 FIXME("%p %p %08lx %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2001 /******************************************************************************
2002 * QueryServiceLockStatusW [ADVAPI32.@]
2004 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
2005 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2006 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2008 FIXME("%p %p %08lx %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2013 /******************************************************************************
2014 * GetServiceDisplayNameA [ADVAPI32.@]
2016 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
2017 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
2019 FIXME("%p %s %p %p\n", hSCManager,
2020 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
2024 /******************************************************************************
2025 * GetServiceDisplayNameW [ADVAPI32.@]
2027 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
2028 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
2030 FIXME("%p %s %p %p\n", hSCManager,
2031 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
2035 /******************************************************************************
2036 * ChangeServiceConfigW [ADVAPI32.@]
2038 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
2039 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
2040 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
2041 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
2043 struct reg_value val[10];
2044 struct sc_service *hsvc;
2045 DWORD r = ERROR_SUCCESS;
2049 TRACE("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
2050 hService, dwServiceType, dwStartType, dwErrorControl,
2051 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2052 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2053 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2055 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2058 SetLastError( ERROR_INVALID_HANDLE );
2063 if( dwServiceType != SERVICE_NO_CHANGE )
2064 service_set_dword( &val[n++], szType, &dwServiceType );
2066 if( dwStartType != SERVICE_NO_CHANGE )
2067 service_set_dword( &val[n++], szStart, &dwStartType );
2069 if( dwErrorControl != SERVICE_NO_CHANGE )
2070 service_set_dword( &val[n++], szError, &dwErrorControl );
2072 if( lpBinaryPathName )
2073 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
2075 if( lpLoadOrderGroup )
2076 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
2078 if( lpDependencies )
2079 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
2082 FIXME("ignoring password\n");
2084 if( lpServiceStartName )
2085 service_set_string( &val[n++], szDependOnService, lpServiceStartName );
2087 r = service_write_values( hsvc->hkey, val, n );
2089 return (r == ERROR_SUCCESS) ? TRUE : FALSE ;
2092 /******************************************************************************
2093 * ChangeServiceConfigA [ADVAPI32.@]
2095 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2096 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2097 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2098 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2100 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2101 LPWSTR wServiceStartName, wPassword, wDisplayName;
2104 TRACE("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
2105 hService, dwServiceType, dwStartType, dwErrorControl,
2106 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2107 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2108 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2110 wBinaryPathName = SERV_dup( lpBinaryPathName );
2111 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2112 wDependencies = SERV_dupmulti( lpDependencies );
2113 wServiceStartName = SERV_dup( lpServiceStartName );
2114 wPassword = SERV_dup( lpPassword );
2115 wDisplayName = SERV_dup( lpDisplayName );
2117 r = ChangeServiceConfigW( hService, dwServiceType,
2118 dwStartType, dwErrorControl, wBinaryPathName,
2119 wLoadOrderGroup, lpdwTagId, wDependencies,
2120 wServiceStartName, wPassword, wDisplayName);
2122 SERV_free( wBinaryPathName );
2123 SERV_free( wLoadOrderGroup );
2124 SERV_free( wDependencies );
2125 SERV_free( wServiceStartName );
2126 SERV_free( wPassword );
2127 SERV_free( wDisplayName );
2132 /******************************************************************************
2133 * ChangeServiceConfig2A [ADVAPI32.@]
2135 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2140 TRACE("%p %ld %p\n",hService, dwInfoLevel, lpInfo);
2142 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2144 LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
2145 SERVICE_DESCRIPTIONW sdw;
2147 sdw.lpDescription = SERV_dup( sd->lpDescription );
2149 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2151 SERV_free( sdw.lpDescription );
2153 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2155 LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
2156 SERVICE_FAILURE_ACTIONSW faw;
2158 faw.dwResetPeriod = fa->dwResetPeriod;
2159 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2160 faw.lpCommand = SERV_dup( fa->lpCommand );
2161 faw.cActions = fa->cActions;
2162 faw.lpsaActions = fa->lpsaActions;
2164 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2166 SERV_free( faw.lpRebootMsg );
2167 SERV_free( faw.lpCommand );
2170 SetLastError( ERROR_INVALID_PARAMETER );
2175 /******************************************************************************
2176 * ChangeServiceConfig2W [ADVAPI32.@]
2178 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2182 struct sc_service *hsvc;
2184 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2187 SetLastError( ERROR_INVALID_HANDLE );
2192 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2194 static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2195 LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
2196 if (sd->lpDescription)
2198 TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
2199 if (sd->lpDescription[0] == 0)
2200 RegDeleteValueW(hKey,szDescription);
2202 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2203 (LPVOID)sd->lpDescription,
2204 sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2208 FIXME("STUB: %p %ld %p\n",hService, dwInfoLevel, lpInfo);
2212 /******************************************************************************
2213 * QueryServiceObjectSecurity [ADVAPI32.@]
2215 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2216 SECURITY_INFORMATION dwSecurityInformation,
2217 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2218 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2222 FIXME("%p %ld %p %lu %p\n", hService, dwSecurityInformation,
2223 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2225 InitializeSecurityDescriptor(lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
2227 pACL = HeapAlloc( GetProcessHeap(), 0, sizeof(ACL) );
2228 InitializeAcl(pACL, sizeof(ACL), ACL_REVISION);
2229 SetSecurityDescriptorDacl(lpSecurityDescriptor, TRUE, pACL, TRUE);
2233 /******************************************************************************
2234 * SetServiceObjectSecurity [ADVAPI32.@]
2236 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2237 SECURITY_INFORMATION dwSecurityInformation,
2238 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2240 FIXME("%p %ld %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2244 /******************************************************************************
2245 * SetServiceBits [ADVAPI32.@]
2247 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2248 DWORD dwServiceBits,
2250 BOOL bUpdateImmediately)
2252 FIXME("%p %08lx %x %x\n", hServiceStatus, dwServiceBits,
2253 bSetBitsOn, bUpdateImmediately);
2257 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR lpServiceName,
2258 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2260 FIXME("%s %p %p\n", debugstr_a(lpServiceName), lpHandlerProc, lpContext);
2264 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2265 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2267 service_data *service;
2269 TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2271 EnterCriticalSection( &service_cs );
2272 for(service = service_list; service; service = service->next)
2273 if(!strcmpW(lpServiceName, service->name))
2277 service->handler.handler_ex = lpHandlerProc;
2278 service->context = lpContext;
2279 service->extended = TRUE;
2281 LeaveCriticalSection( &service_cs );
2283 return (SERVICE_STATUS_HANDLE)service;