Correct incorrect use of arguments to QueryServiceConfigW.
[wine/multimedia.git] / dlls / advapi32 / service.c
blob75521c2360cb6a38423f65d10c92d3fb96506bdd
1 /*
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
22 #include <stdarg.h>
23 #include <string.h>
24 #include <time.h>
25 #include <assert.h>
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winsvc.h"
30 #include "winerror.h"
31 #include "winreg.h"
32 #include "wine/unicode.h"
33 #include "wine/debug.h"
34 #include "winternl.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',
42 'L','O','C','K',0};
44 typedef struct service_start_info_t
46 DWORD cmd;
47 DWORD size;
48 WCHAR str[1];
49 } service_start_info;
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;
60 HANDLE thread;
61 BOOL unicode;
62 union {
63 LPSERVICE_MAIN_FUNCTIONA a;
64 LPSERVICE_MAIN_FUNCTIONW w;
65 } proc;
66 LPWSTR args;
67 WCHAR name[1];
68 } service_data;
70 static CRITICAL_SECTION service_cs;
71 static CRITICAL_SECTION_DEBUG service_cs_debug =
73 0, 0, &service_cs,
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 /******************************************************************************
83 * SC_HANDLEs
86 #define MAX_SERVICE_NAME 256
88 typedef enum { SC_HTYPE_MANAGER, SC_HTYPE_SERVICE } SC_HANDLE_TYPE;
90 struct sc_handle;
91 typedef VOID (*sc_handle_destructor)(struct sc_handle *);
93 struct sc_handle
95 SC_HANDLE_TYPE htype;
96 DWORD ref_count;
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 */
111 WCHAR name[1];
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 );
120 if (hdr)
122 hdr->htype = htype;
123 hdr->ref_count = 1;
124 hdr->destroy = destroy;
126 TRACE("sc_handle type=%d -> %p\n", htype, hdr);
127 return hdr;
130 static void *sc_handle_get_handle_data(SC_HANDLE handle, DWORD htype)
132 struct sc_handle *hdr = (struct sc_handle *) handle;
134 if (!hdr)
135 return NULL;
136 if (hdr->htype != htype)
137 return NULL;
138 return hdr;
141 static void sc_handle_free(struct sc_handle* hdr)
143 if (!hdr)
144 return;
145 if (--hdr->ref_count)
146 return;
147 hdr->destroy(hdr);
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);
156 if (mgr->hkey)
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);
165 if (svc->hkey)
166 RegCloseKey(svc->hkey);
167 svc->hkey = NULL;
168 sc_handle_free(&svc->scm->hdr);
169 svc->scm = NULL;
172 /******************************************************************************
173 * String management functions
175 static inline LPWSTR SERV_dup( LPCSTR str )
177 UINT len;
178 LPWSTR wstr;
180 if( !str )
181 return NULL;
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 );
185 return wstr;
188 static inline LPWSTR SERV_dupmulti(LPCSTR str)
190 UINT len = 0, n = 0;
191 LPWSTR wstr;
193 if( !str )
194 return NULL;
195 do {
196 len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
197 n += (strlen( &str[n] ) + 1);
198 } while (str[n]);
199 len++;
200 n++;
202 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
203 MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
204 return wstr;
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};
220 LPWSTR name;
221 DWORD len;
223 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
224 name = HeapAlloc(GetProcessHeap(), 0, len);
225 strcpyW(name, prefix);
226 strcatW(name, service);
227 return name;
230 static HANDLE service_open_pipe(LPWSTR service)
232 LPWSTR szPipe = service_get_pipe_name( service );
233 HANDLE handle = INVALID_HANDLE_VALUE;
235 do {
236 handle = CreateFileW(szPipe, GENERIC_READ|GENERIC_WRITE,
237 0, NULL, OPEN_ALWAYS, 0, NULL);
238 if (handle != INVALID_HANDLE_VALUE)
239 break;
240 if (GetLastError() != ERROR_PIPE_BUSY)
241 break;
242 } while (WaitNamedPipeW(szPipe, NMPWAIT_WAIT_FOREVER));
243 SERV_free(szPipe);
245 return handle;
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};
255 LPWSTR name;
256 DWORD len;
257 HANDLE handle;
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);
264 SERV_free(name);
265 return handle;
268 /******************************************************************************
269 * service_thread
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;
279 TRACE("%p\n", arg);
281 while (str[len])
283 len += strlenW(&str[len]) + 1;
284 argc++;
287 if (info->unicode)
289 LPWSTR *argv, p;
291 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPWSTR));
292 for (argc=0, p=str; *p; p += strlenW(p) + 1)
293 argv[argc++] = p;
294 argv[argc] = NULL;
296 info->proc.w(argc, argv);
297 HeapFree(GetProcessHeap(), 0, argv);
299 else
301 LPSTR strA, *argv, p;
302 DWORD lenA;
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)
310 argv[argc++] = p;
311 argv[argc] = NULL;
313 info->proc.a(argc, argv);
314 HeapFree(GetProcessHeap(), 0, argv);
315 HeapFree(GetProcessHeap(), 0, strA);
317 return 0;
320 /******************************************************************************
321 * service_handle_start
323 static BOOL service_handle_start(HANDLE pipe, service_data *service, DWORD count)
325 DWORD read = 0, result = 0;
326 LPWSTR args;
327 BOOL r;
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));
337 goto end;
340 if (service->thread)
342 ERR("service is not stopped\n");
343 goto end;
346 if (service->args)
347 SERV_free(service->args);
348 service->args = args;
349 args = NULL;
350 service->thread = CreateThread( NULL, 0, service_thread,
351 service, 0, NULL );
353 end:
354 HeapFree(GetProcessHeap(), 0, args);
355 WriteFile( pipe, &result, sizeof result, &read, NULL );
357 return TRUE;
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;
367 LPWSTR p;
368 BOOL r;
370 TRACE("%p %p %ld\n", pipe, argv, argc);
372 /* calculate how much space do we need to send the startup info */
373 len = 1;
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;
379 ssi->size = len;
381 /* copy service args into a single buffer*/
382 p = &ssi->str[0];
383 for (i=0; i<argc; i++)
385 strcpyW(p, argv[i]);
386 p += strlenW(p) + 1;
388 *p=0;
390 r = WriteFile(pipe, ssi, sizeof *ssi + len*sizeof(WCHAR), &count, NULL);
391 if (r)
392 r = ReadFile(pipe, &result, sizeof result, &count, NULL);
394 HeapFree(GetProcessHeap(),0,ssi);
396 return r;
399 /******************************************************************************
400 * service_handle_get_status
402 static BOOL service_handle_get_status(HANDLE pipe, service_data *service)
404 DWORD count = 0;
405 TRACE("\n");
406 return WriteFile(pipe, &service->status,
407 sizeof service->status, &count, NULL);
410 /******************************************************************************
411 * service_get_status
413 static BOOL service_get_status(HANDLE pipe, LPSERVICE_STATUS status)
415 DWORD cmd[2], count = 0;
416 BOOL r;
418 cmd[0] = WINESERV_GETSTATUS;
419 cmd[1] = 0;
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");
424 return r;
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);
430 return r;
433 /******************************************************************************
434 * service_send_control
436 static BOOL service_send_control(HANDLE pipe, DWORD dwControl, DWORD *result)
438 DWORD cmd[2], count = 0;
439 BOOL r;
441 cmd[0] = WINESERV_SENDCONTROL;
442 cmd[1] = dwControl;
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");
447 return r;
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);
453 return r;
456 /******************************************************************************
457 * service_accepts_control
459 static BOOL service_accepts_control(service_data *service, DWORD dwControl)
461 DWORD a = service->status.dwControlsAccepted;
463 switch (dwControl)
465 case SERVICE_CONTROL_INTERROGATE:
466 return TRUE;
467 case SERVICE_CONTROL_STOP:
468 if (a&SERVICE_ACCEPT_STOP)
469 return TRUE;
470 break;
471 case SERVICE_CONTROL_SHUTDOWN:
472 if (a&SERVICE_ACCEPT_SHUTDOWN)
473 return TRUE;
474 break;
475 case SERVICE_CONTROL_PAUSE:
476 case SERVICE_CONTROL_CONTINUE:
477 if (a&SERVICE_ACCEPT_PAUSE_CONTINUE)
478 return TRUE;
479 break;
480 case SERVICE_CONTROL_PARAMCHANGE:
481 if (a&SERVICE_ACCEPT_PARAMCHANGE)
482 return TRUE;
483 break;
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)
489 return TRUE;
491 if (1) /* (!service->handlerex) */
492 return FALSE;
493 switch (dwControl)
495 case SERVICE_CONTROL_HARDWAREPROFILECHANGE:
496 if (a&SERVICE_ACCEPT_HARDWAREPROFILECHANGE)
497 return TRUE;
498 break;
499 case SERVICE_CONTROL_POWEREVENT:
500 if (a&SERVICE_ACCEPT_POWEREVENT)
501 return TRUE;
502 break;
503 case SERVICE_CONTROL_SESSIONCHANGE:
504 if (a&SERVICE_ACCEPT_SESSIONCHANGE)
505 return TRUE;
506 break;
508 return FALSE;
511 /******************************************************************************
512 * service_handle_control
514 static BOOL service_handle_control(HANDLE pipe, service_data *service,
515 DWORD dwControl)
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);
524 ret = ERROR_SUCCESS;
526 return WriteFile(pipe, &ret, sizeof ret, &count, NULL);
529 /******************************************************************************
530 * service_reap_thread
532 static DWORD service_reap_thread(service_data *service)
534 DWORD exitcode = 0;
536 if (!service->thread)
537 return 0;
538 GetExitCodeThread(service->thread, &exitcode);
539 if (exitcode!=STILL_ACTIVE)
541 CloseHandle(service->thread);
542 service->thread = 0;
544 return exitcode;
547 /******************************************************************************
548 * service_control_dispatcher
550 static DWORD WINAPI service_control_dispatcher(LPVOID arg)
552 service_data *service = arg;
553 LPWSTR name;
554 HANDLE pipe, event;
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 );
562 SERV_free(name);
564 /* let the process who started us know we've tried to create a pipe */
565 event = service_get_event_handle(service->name);
566 SetEvent(event);
567 CloseHandle(event);
569 if (pipe==INVALID_HANDLE_VALUE)
571 ERR("failed to create pipe, error = %ld\n", GetLastError());
572 return 0;
575 /* dispatcher loop */
576 while (1)
578 BOOL r;
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");
585 break;
588 r = ReadFile( pipe, &req, sizeof req, &count, NULL );
589 if (!r || count!=sizeof req)
591 ERR("pipe read failed\n");
592 break;
595 service_reap_thread(service);
597 /* handle the request */
598 switch (req[0])
600 case WINESERV_STARTINFO:
601 service_handle_start(pipe, service, req[1]);
602 break;
603 case WINESERV_GETSTATUS:
604 service_handle_get_status(pipe, service);
605 break;
606 case WINESERV_SENDCONTROL:
607 service_handle_control(pipe, service, req[1]);
608 break;
609 default:
610 ERR("received invalid command %ld length %ld\n", req[0], req[1]);
613 FlushFileBuffers(pipe);
614 DisconnectNamedPipe(pipe);
617 CloseHandle(pipe);
618 return 1;
621 /******************************************************************************
622 * service_run_threads
624 static BOOL service_run_threads(void)
626 service_data *service;
627 DWORD count = 0, n = 0;
628 HANDLE *handles;
630 EnterCriticalSection( &service_cs );
632 /* count how many services there are */
633 for (service = service_list; service; service = service->next)
634 count++;
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,
642 service, 0, NULL );
643 assert(n==count);
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);
652 return TRUE;
655 /******************************************************************************
656 * StartServiceCtrlDispatcherA [ADVAPI32.@]
658 * Connects a process containing one or more services to the service control
659 * manager.
661 * PARAMS
662 * servent [I] A list of the service names and service procedures
664 BOOL WINAPI StartServiceCtrlDispatcherA( LPSERVICE_TABLE_ENTRYA servent )
666 service_data *info;
667 DWORD sz, len;
668 BOOL ret = TRUE;
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;
686 service_list = info;
688 servent++;
690 LeaveCriticalSection( &service_cs );
692 service_run_threads();
694 return ret;
697 /******************************************************************************
698 * StartServiceCtrlDispatcherW [ADVAPI32.@]
700 * Connects a process containing one or more services to the service control
701 * manager.
703 * PARAMS
704 * servent [I] A list of the service names and service procedures
706 BOOL WINAPI StartServiceCtrlDispatcherW( LPSERVICE_TABLE_ENTRYW servent )
708 service_data *info;
709 DWORD sz, len;
710 BOOL ret = TRUE;
712 TRACE("%p\n", servent);
714 EnterCriticalSection( &service_cs );
715 while (servent->lpServiceName)
717 LPWSTR name = servent->lpServiceName;
719 len = strlenW(name);
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;
728 service_list = info;
730 servent++;
732 LeaveCriticalSection( &service_cs );
734 service_run_threads();
736 return ret;
739 /******************************************************************************
740 * LockServiceDatabase [ADVAPI32.@]
742 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
744 HANDLE ret;
746 TRACE("%p\n",hSCManager);
748 ret = CreateSemaphoreW( NULL, 1, 1, szSCMLock );
749 if( ret && GetLastError() == ERROR_ALREADY_EXISTS )
751 CloseHandle( ret );
752 ret = NULL;
753 SetLastError( ERROR_SERVICE_DATABASE_LOCKED );
756 TRACE("returning %p\n", ret);
758 return 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);
783 return ret;
786 /******************************************************************************
787 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
789 * PARAMS
790 * lpServiceName []
791 * lpfHandler []
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))
801 break;
802 if (service)
803 service->handler = lpfHandler;
804 LeaveCriticalSection( &service_cs );
806 return (SERVICE_STATUS_HANDLE)service;
809 /******************************************************************************
810 * SetServiceStatus [ADVAPI32.@]
812 * PARAMS
813 * hService []
814 * lpStatus []
816 BOOL WINAPI
817 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
819 service_data *service;
820 BOOL r = TRUE;
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)
831 break;
832 if (service)
834 memcpy( &service->status, lpStatus, sizeof(SERVICE_STATUS) );
835 TRACE("Set service status to %ld\n",service->status.dwCurrentState);
837 else
838 r = FALSE;
839 LeaveCriticalSection( &service_cs );
841 return r;
845 /******************************************************************************
846 * OpenSCManagerA [ADVAPI32.@]
848 * Establish a connection to the service control manager and open its database.
850 * PARAMS
851 * lpMachineName [I] Pointer to machine name string
852 * lpDatabaseName [I] Pointer to database name string
853 * dwDesiredAccess [I] Type of access
855 * RETURNS
856 * Success: A Handle to the service control manager database
857 * Failure: NULL
859 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
860 DWORD dwDesiredAccess )
862 LPWSTR lpMachineNameW, lpDatabaseNameW;
863 SC_HANDLE ret;
865 lpMachineNameW = SERV_dup(lpMachineName);
866 lpDatabaseNameW = SERV_dup(lpDatabaseName);
867 ret = OpenSCManagerW(lpMachineNameW, lpDatabaseNameW, dwDesiredAccess);
868 SERV_free(lpDatabaseNameW);
869 SERV_free(lpMachineNameW);
870 return ret;
873 /******************************************************************************
874 * OpenSCManagerW [ADVAPI32.@]
876 * See OpenSCManagerA.
878 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
879 DWORD dwDesiredAccess )
881 struct sc_manager *manager;
882 HKEY hReg;
883 LONG r;
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 );
897 return NULL;
899 else
901 SetLastError( ERROR_INVALID_NAME );
902 return NULL;
906 manager = sc_handle_alloc( SC_HTYPE_MANAGER, sizeof (struct sc_manager),
907 sc_handle_destroy_manager );
908 if (!manager)
909 return NULL;
911 r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
912 if (r!=ERROR_SUCCESS)
913 goto error;
915 r = RegOpenKeyExW(hReg, szServiceManagerKey,
916 0, KEY_ALL_ACCESS, &manager->hkey);
917 RegCloseKey( hReg );
918 if (r!=ERROR_SUCCESS)
919 goto error;
921 TRACE("returning %p\n", manager);
923 return (SC_HANDLE) &manager->hdr;
925 error:
926 sc_handle_free( &manager->hdr );
927 return NULL;
930 /******************************************************************************
931 * ControlService [ADVAPI32.@]
933 * Send a control code to a service.
935 * PARAMS
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
940 * RETURNS
941 * Success: TRUE.
942 * Failure: FALSE.
944 * BUGS
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;
952 BOOL ret = FALSE;
953 HANDLE handle;
955 TRACE("%p %ld %p\n", hService, dwControl, lpServiceStatus);
957 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
958 if (!hsvc)
960 SetLastError( ERROR_INVALID_HANDLE );
961 return FALSE;
964 ret = QueryServiceStatus(hService, lpServiceStatus);
965 if (ret)
967 ERR("failed to query service status\n");
968 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
969 return FALSE;
972 switch (lpServiceStatus->dwCurrentState)
974 case SERVICE_STOPPED:
975 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
976 return FALSE;
977 case SERVICE_START_PENDING:
978 if (dwControl==SERVICE_CONTROL_STOP)
979 break;
980 /* fall thru */
981 case SERVICE_STOP_PENDING:
982 SetLastError(ERROR_SERVICE_CANNOT_ACCEPT_CTRL);
983 return FALSE;
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);
991 CloseHandle(handle);
992 if (result!=ERROR_SUCCESS)
994 SetLastError(result);
995 ret = FALSE;
999 return ret;
1002 /******************************************************************************
1003 * CloseServiceHandle [ADVAPI32.@]
1005 * Close a handle to a service or the service control manager database.
1007 * PARAMS
1008 * hSCObject [I] Handle to service or service control manager database
1010 * RETURNS
1011 * Success: TRUE
1012 * Failure: FALSE
1014 BOOL WINAPI
1015 CloseServiceHandle( SC_HANDLE hSCObject )
1017 TRACE("%p\n", hSCObject);
1019 sc_handle_free( (struct sc_handle*) hSCObject );
1021 return TRUE;
1025 /******************************************************************************
1026 * OpenServiceA [ADVAPI32.@]
1028 * Open a handle to a service.
1030 * PARAMS
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
1035 * RETURNS
1036 * Success: Handle to the service
1037 * Failure: NULL
1039 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1040 DWORD dwDesiredAccess )
1042 LPWSTR lpServiceNameW;
1043 SC_HANDLE ret;
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);
1050 return ret;
1054 /******************************************************************************
1055 * OpenServiceW [ADVAPI32.@]
1057 * See OpenServiceA.
1059 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1060 DWORD dwDesiredAccess)
1062 struct sc_manager *hscm;
1063 struct sc_service *hsvc;
1064 HKEY hKey;
1065 long r;
1066 DWORD len;
1068 TRACE("%p %s %ld\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
1070 if (!lpServiceName)
1072 SetLastError(ERROR_INVALID_ADDRESS);
1073 return NULL;
1076 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1077 if (!hscm)
1079 SetLastError( ERROR_INVALID_HANDLE );
1080 return FALSE;
1083 r = RegOpenKeyExW( hscm->hkey, lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
1084 if (r!=ERROR_SUCCESS)
1086 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
1087 return NULL;
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 );
1094 if (!hsvc)
1095 return NULL;
1096 strcpyW( hsvc->name, lpServiceName );
1097 hsvc->hkey = hKey;
1099 /* add reference to SCM handle */
1100 hscm->hdr.ref_count++;
1101 hsvc->scm = hscm;
1103 TRACE("returning %p\n",hsvc);
1105 return (SC_HANDLE) &hsvc->hdr;
1108 /******************************************************************************
1109 * CreateServiceW [ADVAPI32.@]
1111 SC_HANDLE WINAPI
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;
1122 HKEY hKey;
1123 LONG r;
1124 DWORD dp, len;
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 );
1137 if (!hscm)
1139 SetLastError( ERROR_INVALID_HANDLE );
1140 return NULL;
1143 r = RegCreateKeyExW(hscm->hkey, lpServiceName, 0, NULL,
1144 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
1145 if (r!=ERROR_SUCCESS)
1146 goto error;
1148 if (dp != REG_CREATED_NEW_KEY)
1150 SetLastError(ERROR_SERVICE_EXISTS);
1151 goto error;
1154 if(lpDisplayName)
1156 r = RegSetValueExW(hKey, szDisplayName, 0, REG_SZ, (const BYTE*)lpDisplayName,
1157 (strlenW(lpDisplayName)+1)*sizeof(WCHAR) );
1158 if (r!=ERROR_SUCCESS)
1159 goto error;
1162 r = RegSetValueExW(hKey, szType, 0, REG_DWORD, (LPVOID)&dwServiceType, sizeof (DWORD) );
1163 if (r!=ERROR_SUCCESS)
1164 goto error;
1166 r = RegSetValueExW(hKey, szStart, 0, REG_DWORD, (LPVOID)&dwStartType, sizeof (DWORD) );
1167 if (r!=ERROR_SUCCESS)
1168 goto error;
1170 r = RegSetValueExW(hKey, szError, 0, REG_DWORD,
1171 (LPVOID)&dwErrorControl, sizeof (DWORD) );
1172 if (r!=ERROR_SUCCESS)
1173 goto error;
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)
1180 goto error;
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)
1188 goto error;
1191 if(lpDependencies)
1193 DWORD len = 0;
1195 /* determine the length of a double null terminated multi string */
1196 do {
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)
1203 goto error;
1206 if(lpPassword)
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 );
1220 if (!hsvc)
1221 return NULL;
1222 strcpyW( hsvc->name, lpServiceName );
1223 hsvc->hkey = hKey;
1224 hsvc->scm = hscm;
1225 hscm->hdr.ref_count++;
1227 return (SC_HANDLE) &hsvc->hdr;
1229 error:
1230 if (hsvc)
1231 sc_handle_free( &hsvc->hdr );
1232 return NULL;
1236 /******************************************************************************
1237 * CreateServiceA [ADVAPI32.@]
1239 SC_HANDLE WINAPI
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,
1246 LPCSTR lpPassword )
1248 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1249 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1250 SC_HANDLE r;
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 );
1276 return r;
1280 /******************************************************************************
1281 * DeleteService [ADVAPI32.@]
1283 * Delete a service from the service control manager database.
1285 * PARAMS
1286 * hService [I] Handle of the service to delete
1288 * RETURNS
1289 * Success: TRUE
1290 * Failure: FALSE
1292 BOOL WINAPI DeleteService( SC_HANDLE hService )
1294 struct sc_service *hsvc;
1295 HKEY hKey;
1296 WCHAR valname[MAX_PATH+1];
1297 INT index = 0;
1298 LONG rc;
1299 DWORD size;
1301 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1302 if (!hsvc)
1304 SetLastError( ERROR_INVALID_HANDLE );
1305 return FALSE;
1307 hKey = hsvc->hkey;
1309 size = MAX_PATH+1;
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);
1315 index++;
1316 size = MAX_PATH+1;
1317 rc = RegEnumValueW(hKey, index, valname, &size,0,0,0,0);
1320 RegCloseKey(hKey);
1321 hsvc->hkey = NULL;
1323 /* delete the key */
1324 RegDeleteKeyW(hsvc->scm->hkey, hsvc->name);
1326 return TRUE;
1330 /******************************************************************************
1331 * StartServiceA [ADVAPI32.@]
1333 * Start a service
1335 * PARAMS
1336 * hService [I] Handle of service
1337 * dwNumServiceArgs [I] Number of arguments
1338 * lpServiceArgVectors [I] Address of array of argument strings
1340 * NOTES
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.
1349 * RETURNS
1350 * Success: TRUE.
1351 * Failure: FALSE
1353 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1354 LPCSTR *lpServiceArgVectors )
1356 LPWSTR *lpwstr=NULL;
1357 unsigned int i;
1358 BOOL r;
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);
1378 return r;
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;
1388 STARTUPINFOW si;
1389 LPWSTR path = NULL, str;
1390 DWORD type, size, ret;
1391 HANDLE handles[2];
1392 BOOL r;
1394 /* read the executable path from memory */
1395 size = 0;
1396 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, NULL, &size);
1397 if (ret!=ERROR_SUCCESS)
1398 return FALSE;
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);
1408 if (!path)
1409 return FALSE;
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);
1416 if (r)
1418 handles[1] = pi.hProcess;
1419 ret = WaitForMultipleObjectsEx(2, handles, FALSE, 30000, FALSE);
1420 if(ret != WAIT_OBJECT_0)
1422 SetLastError(ERROR_IO_PENDING);
1423 r = FALSE;
1426 CloseHandle( pi.hThread );
1427 CloseHandle( pi.hProcess );
1429 CloseHandle( handles[0] );
1430 HeapFree(GetProcessHeap(),0,path);
1431 return r;
1434 static BOOL service_wait_for_startup(SC_HANDLE hService)
1436 DWORD i;
1437 SERVICE_STATUS status;
1438 BOOL r = FALSE;
1440 TRACE("%p\n", hService);
1442 for (i=0; i<30; i++)
1444 status.dwCurrentState = 0;
1445 r = QueryServiceStatus(hService, &status);
1446 if (!r)
1447 break;
1448 if (status.dwCurrentState == SERVICE_RUNNING)
1450 TRACE("Service started successfully\n");
1451 break;
1453 r = FALSE;
1454 Sleep(1000);
1456 return r;
1459 /******************************************************************************
1460 * StartServiceW [ADVAPI32.@]
1462 * See StartServiceA.
1464 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1465 LPCWSTR *lpServiceArgVectors)
1467 struct sc_service *hsvc;
1468 BOOL r = FALSE;
1469 SC_LOCK hLock;
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);
1475 if (!hsvc)
1477 SetLastError(ERROR_INVALID_HANDLE);
1478 return r;
1481 hLock = LockServiceDatabase(hsvc->scm);
1482 if (!hLock)
1483 return r;
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);
1497 r = TRUE;
1500 UnlockServiceDatabase( hLock );
1502 TRACE("returning %d\n", r);
1504 service_wait_for_startup(hService);
1506 return r;
1509 /******************************************************************************
1510 * QueryServiceStatus [ADVAPI32.@]
1512 * PARAMS
1513 * hService []
1514 * lpservicestatus []
1517 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1518 LPSERVICE_STATUS lpservicestatus)
1520 struct sc_service *hsvc;
1521 DWORD size, type, val;
1522 HANDLE pipe;
1523 LONG r;
1525 TRACE("%p %p\n", hService, lpservicestatus);
1527 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1528 if (!hsvc)
1530 SetLastError( ERROR_INVALID_HANDLE );
1531 return FALSE;
1534 pipe = service_open_pipe(hsvc->name);
1535 if (pipe != INVALID_HANDLE_VALUE)
1537 r = service_get_status(pipe, lpservicestatus);
1538 CloseHandle(pipe);
1539 if (r)
1540 return TRUE;
1543 TRACE("Failed to read service status\n");
1545 /* read the service type from the registry */
1546 size = sizeof(val);
1547 r = RegQueryValueExA(hsvc->hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1548 if(r!=ERROR_SUCCESS || type!=REG_DWORD)
1549 val = 0;
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;
1559 return TRUE;
1562 /******************************************************************************
1563 * QueryServiceStatusEx [ADVAPI32.@]
1565 * Get information about a service.
1567 * PARAMS
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
1574 * RETURNS
1575 * Success: TRUE
1576 * FAILURE: FALSE
1578 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1579 LPBYTE lpBuffer, DWORD cbBufSize,
1580 LPDWORD pcbBytesNeeded)
1582 FIXME("stub\n");
1583 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1584 return FALSE;
1587 /******************************************************************************
1588 * QueryServiceConfigA [ADVAPI32.@]
1590 BOOL WINAPI
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;
1603 HKEY hKey;
1604 CHAR str_buffer[ MAX_PATH ];
1605 LONG r;
1606 DWORD type, val, sz, total, n;
1607 LPBYTE p;
1609 TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
1610 cbBufSize, pcbBytesNeeded);
1612 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1613 if (!hsvc)
1615 SetLastError( ERROR_INVALID_HANDLE );
1616 return FALSE;
1618 hKey = hsvc->hkey;
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;
1630 total += sz;
1632 else
1634 /* FIXME: set last error */
1635 return FALSE;
1638 sz = 0;
1639 r = RegQueryValueExA( hKey, szGroup, 0, &type, NULL, &sz );
1640 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1641 total += sz;
1643 sz = 0;
1644 r = RegQueryValueExA( hKey, szDependencies, 0, &type, NULL, &sz );
1645 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1646 total += sz;
1648 sz = 0;
1649 r = RegQueryValueExA( hKey, szStart, 0, &type, NULL, &sz );
1650 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1651 total += sz;
1653 sz = 0;
1654 r = RegQueryValueExA( hKey, szDisplayName, 0, &type, NULL, &sz );
1655 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1656 total += sz;
1658 /* if there's not enough memory, return an error */
1659 if( total > *pcbBytesNeeded )
1661 *pcbBytesNeeded = total;
1662 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1663 return FALSE;
1666 *pcbBytesNeeded = total;
1667 ZeroMemory( lpServiceConfig, total );
1669 sz = sizeof val;
1670 r = RegQueryValueExA( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1671 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1672 lpServiceConfig->dwServiceType = val;
1674 sz = sizeof val;
1675 r = RegQueryValueExA( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1676 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1677 lpServiceConfig->dwStartType = val;
1679 sz = sizeof 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;
1696 p += sz;
1697 n -= sz;
1699 else
1701 /* FIXME: set last error */
1702 return FALSE;
1705 sz = n;
1706 r = RegQueryValueExA( hKey, szGroup, 0, &type, p, &sz );
1707 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1709 lpServiceConfig->lpLoadOrderGroup = (LPSTR) p;
1710 p += sz;
1711 n -= sz;
1714 sz = n;
1715 r = RegQueryValueExA( hKey, szDependencies, 0, &type, p, &sz );
1716 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1718 lpServiceConfig->lpDependencies = (LPSTR) p;
1719 p += sz;
1720 n -= sz;
1723 if( n < 0 )
1724 ERR("Buffer overflow!\n");
1726 TRACE("Image path = %s\n", lpServiceConfig->lpBinaryPathName );
1727 TRACE("Group = %s\n", lpServiceConfig->lpLoadOrderGroup );
1729 return TRUE;
1732 /******************************************************************************
1733 * QueryServiceConfigW [ADVAPI32.@]
1735 BOOL WINAPI
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 ];
1751 LONG r;
1752 DWORD type, val, sz, total, n;
1753 LPBYTE p;
1754 HKEY hKey;
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);
1761 if (!hsvc)
1763 SetLastError( ERROR_INVALID_HANDLE );
1764 return FALSE;
1766 hKey = hsvc->hkey;
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;
1780 else
1782 /* FIXME: set last error */
1783 return FALSE;
1786 sz = 0;
1787 r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1788 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1789 total += sz;
1791 sz = 0;
1792 r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1793 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1794 total += sz;
1796 sz = 0;
1797 r = RegQueryValueExW( hKey, szStart, 0, &type, NULL, &sz );
1798 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1799 total += sz;
1801 sz = 0;
1802 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1803 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1804 total += sz;
1806 *pcbBytesNeeded = total;
1808 /* if there's not enough memory, return an error */
1809 if( total > cbBufSize )
1811 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1812 return FALSE;
1815 ZeroMemory( lpServiceConfig, total );
1817 sz = sizeof val;
1818 r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1819 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1820 lpServiceConfig->dwServiceType = val;
1822 sz = sizeof val;
1823 r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1824 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1825 lpServiceConfig->dwStartType = val;
1827 sz = sizeof 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;
1845 p += sz;
1846 n -= sz;
1848 else
1850 /* FIXME: set last error */
1851 return FALSE;
1854 sz = n;
1855 r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
1856 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1858 lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
1859 p += sz;
1860 n -= sz;
1863 sz = n;
1864 r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
1865 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1867 lpServiceConfig->lpDependencies = (LPWSTR) p;
1868 p += sz;
1869 n -= sz;
1872 if( n < 0 )
1873 ERR("Buffer overflow!\n");
1875 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1876 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1878 return TRUE;
1881 /******************************************************************************
1882 * EnumServicesStatusA [ADVAPI32.@]
1884 BOOL WINAPI
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);
1894 return FALSE;
1897 /******************************************************************************
1898 * EnumServicesStatusW [ADVAPI32.@]
1900 BOOL WINAPI
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);
1910 return FALSE;
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);
1920 return FALSE;
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);
1930 return FALSE;
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);
1942 return FALSE;
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);
1954 return FALSE;
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);
1965 return FALSE;
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);
1976 return FALSE;
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) );
1992 return TRUE;
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;
2005 BOOL r;
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 );
2032 return r;
2035 /******************************************************************************
2036 * ChangeServiceConfig2A [ADVAPI32.@]
2038 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2039 LPVOID lpInfo)
2041 BOOL r = FALSE;
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 );
2072 else
2073 SetLastError( ERROR_INVALID_PARAMETER );
2075 return r;
2078 /******************************************************************************
2079 * ChangeServiceConfig2W [ADVAPI32.@]
2081 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2082 LPVOID lpInfo)
2084 HKEY hKey;
2085 struct sc_service *hsvc;
2087 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2088 if (!hsvc)
2090 SetLastError( ERROR_INVALID_HANDLE );
2091 return FALSE;
2093 hKey = hsvc->hkey;
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);
2104 else
2105 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2106 (LPVOID)sd->lpDescription,
2107 sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2110 else
2111 FIXME("STUB: %p %ld %p\n",hService, dwInfoLevel, lpInfo);
2112 return TRUE;
2115 /******************************************************************************
2116 * QueryServiceObjectSecurity [ADVAPI32.@]
2118 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2119 SECURITY_INFORMATION dwSecurityInformation,
2120 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2121 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2123 PACL pACL = NULL;
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);
2133 return 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);
2144 return TRUE;
2147 /******************************************************************************
2148 * SetServiceBits [ADVAPI32.@]
2150 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2151 DWORD dwServiceBits,
2152 BOOL bSetBitsOn,
2153 BOOL bUpdateImmediately)
2155 FIXME("%08lx %08lx %x %x\n", hServiceStatus, dwServiceBits,
2156 bSetBitsOn, bUpdateImmediately);
2157 return TRUE;