advapi32: Launch winedevice.exe when asked to start a kernel driver service.
[wine/wine-gecko.git] / dlls / advapi32 / service.c
blobe9a116088c445e8c2a948059aeb5dae83d643ab4
1 /*
2 * Win32 advapi functions
4 * Copyright 1995 Sven Verdoolaege
5 * Copyright 2005 Mike McCormack
6 * Copyright 2007 Rolf Kalbermatter
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include <stdarg.h>
24 #include <string.h>
25 #include <time.h>
26 #include <assert.h>
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winsvc.h"
31 #include "winerror.h"
32 #include "winreg.h"
33 #include "wine/unicode.h"
34 #include "wine/debug.h"
35 #include "winternl.h"
36 #include "lmcons.h"
37 #include "lmserver.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(advapi);
41 static const WCHAR szServiceManagerKey[] = { 'S','y','s','t','e','m','\\',
42 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
43 'S','e','r','v','i','c','e','s',0 };
44 static const WCHAR szSCMLock[] = {'A','D','V','A','P','I','_','S','C','M',
45 'L','O','C','K',0};
47 typedef struct service_start_info_t
49 DWORD cmd;
50 DWORD size;
51 WCHAR str[1];
52 } service_start_info;
54 #define WINESERV_STARTINFO 1
55 #define WINESERV_GETSTATUS 2
56 #define WINESERV_SENDCONTROL 3
57 #define WINESERV_SETPID 4
59 typedef struct service_data_t
61 struct service_data_t *next;
62 union {
63 LPHANDLER_FUNCTION handler;
64 LPHANDLER_FUNCTION_EX handler_ex;
65 } handler;
66 LPVOID context;
67 SERVICE_STATUS_PROCESS status;
68 HANDLE thread;
69 BOOL unicode : 1;
70 BOOL extended : 1; /* uses handler_ex instead of handler? */
71 union {
72 LPSERVICE_MAIN_FUNCTIONA a;
73 LPSERVICE_MAIN_FUNCTIONW w;
74 } proc;
75 LPWSTR args;
76 WCHAR name[1];
77 } service_data;
79 static CRITICAL_SECTION service_cs;
80 static CRITICAL_SECTION_DEBUG service_cs_debug =
82 0, 0, &service_cs,
83 { &service_cs_debug.ProcessLocksList,
84 &service_cs_debug.ProcessLocksList },
85 0, 0, { (DWORD_PTR)(__FILE__ ": service_cs") }
87 static CRITICAL_SECTION service_cs = { &service_cs_debug, -1, 0, 0, 0, 0 };
89 static service_data *service_list;
91 /******************************************************************************
92 * SC_HANDLEs
95 #define MAX_SERVICE_NAME 256
97 typedef enum { SC_HTYPE_MANAGER, SC_HTYPE_SERVICE } SC_HANDLE_TYPE;
99 struct sc_handle;
100 typedef VOID (*sc_handle_destructor)(struct sc_handle *);
102 struct sc_handle
104 SC_HANDLE_TYPE htype;
105 DWORD ref_count;
106 sc_handle_destructor destroy;
109 struct sc_manager /* service control manager handle */
111 struct sc_handle hdr;
112 HKEY hkey; /* handle to services database in the registry */
113 DWORD dwAccess;
116 struct sc_service /* service handle */
118 struct sc_handle hdr;
119 HKEY hkey; /* handle to service entry in the registry (under hkey) */
120 DWORD dwAccess;
121 struct sc_manager *scm; /* pointer to SCM handle */
122 WCHAR name[1];
125 static void *sc_handle_alloc(SC_HANDLE_TYPE htype, DWORD size,
126 sc_handle_destructor destroy)
128 struct sc_handle *hdr;
130 hdr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
131 if (hdr)
133 hdr->htype = htype;
134 hdr->ref_count = 1;
135 hdr->destroy = destroy;
137 TRACE("sc_handle type=%d -> %p\n", htype, hdr);
138 return hdr;
141 static void *sc_handle_get_handle_data(SC_HANDLE handle, DWORD htype)
143 struct sc_handle *hdr = (struct sc_handle *) handle;
145 if (!hdr)
146 return NULL;
147 if (hdr->htype != htype)
148 return NULL;
149 return hdr;
152 static void sc_handle_free(struct sc_handle* hdr)
154 if (!hdr)
155 return;
156 if (--hdr->ref_count)
157 return;
158 hdr->destroy(hdr);
159 HeapFree(GetProcessHeap(), 0, hdr);
162 static void sc_handle_destroy_manager(struct sc_handle *handle)
164 struct sc_manager *mgr = (struct sc_manager*) handle;
166 TRACE("destroying SC Manager %p\n", mgr);
167 if (mgr->hkey)
168 RegCloseKey(mgr->hkey);
171 static void sc_handle_destroy_service(struct sc_handle *handle)
173 struct sc_service *svc = (struct sc_service*) handle;
175 TRACE("destroying service %p\n", svc);
176 if (svc->hkey)
177 RegCloseKey(svc->hkey);
178 svc->hkey = NULL;
179 sc_handle_free(&svc->scm->hdr);
180 svc->scm = NULL;
183 /******************************************************************************
184 * String management functions
186 static inline LPWSTR SERV_dup( LPCSTR str )
188 UINT len;
189 LPWSTR wstr;
191 if( !str )
192 return NULL;
193 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
194 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
195 MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
196 return wstr;
199 static inline LPWSTR SERV_dupmulti(LPCSTR str)
201 UINT len = 0, n = 0;
202 LPWSTR wstr;
204 if( !str )
205 return NULL;
206 do {
207 len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
208 n += (strlen( &str[n] ) + 1);
209 } while (str[n]);
210 len++;
211 n++;
213 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
214 MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
215 return wstr;
218 static inline VOID SERV_free( LPWSTR wstr )
220 HeapFree( GetProcessHeap(), 0, wstr );
223 /******************************************************************************
224 * registry access functions and data
226 static const WCHAR szDisplayName[] = {
227 'D','i','s','p','l','a','y','N','a','m','e', 0 };
228 static const WCHAR szType[] = {'T','y','p','e',0};
229 static const WCHAR szStart[] = {'S','t','a','r','t',0};
230 static const WCHAR szError[] = {
231 'E','r','r','o','r','C','o','n','t','r','o','l', 0};
232 static const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
233 static const WCHAR szGroup[] = {'G','r','o','u','p',0};
234 static const WCHAR szDependencies[] = {
235 'D','e','p','e','n','d','e','n','c','i','e','s',0};
236 static const WCHAR szDependOnService[] = {
237 'D','e','p','e','n','d','O','n','S','e','r','v','i','c','e',0};
239 struct reg_value {
240 DWORD type;
241 DWORD size;
242 LPCWSTR name;
243 LPCVOID data;
246 static inline void service_set_value( struct reg_value *val,
247 DWORD type, LPCWSTR name, LPCVOID data, DWORD size )
249 val->name = name;
250 val->type = type;
251 val->data = data;
252 val->size = size;
255 static inline void service_set_dword( struct reg_value *val,
256 LPCWSTR name, const DWORD *data )
258 service_set_value( val, REG_DWORD, name, data, sizeof (DWORD));
261 static inline void service_set_string( struct reg_value *val,
262 LPCWSTR name, LPCWSTR string )
264 DWORD len = (lstrlenW(string)+1) * sizeof (WCHAR);
265 service_set_value( val, REG_SZ, name, string, len );
268 static inline void service_set_multi_string( struct reg_value *val,
269 LPCWSTR name, LPCWSTR string )
271 DWORD len = 0;
273 /* determine the length of a double null terminated multi string */
274 do {
275 len += (lstrlenW( &string[ len ] )+1);
276 } while ( string[ len++ ] );
278 len *= sizeof (WCHAR);
279 service_set_value( val, REG_MULTI_SZ, name, string, len );
282 static inline LONG service_write_values( HKEY hKey,
283 const struct reg_value *val, int n )
285 LONG r = ERROR_SUCCESS;
286 int i;
288 for( i=0; i<n; i++ )
290 r = RegSetValueExW(hKey, val[i].name, 0, val[i].type,
291 (const BYTE*)val[i].data, val[i].size );
292 if( r != ERROR_SUCCESS )
293 break;
295 return r;
298 /******************************************************************************
299 * Service IPC functions
301 static LPWSTR service_get_pipe_name(LPCWSTR service)
303 static const WCHAR prefix[] = { '\\','\\','.','\\','p','i','p','e','\\',
304 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
305 LPWSTR name;
306 DWORD len;
308 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
309 name = HeapAlloc(GetProcessHeap(), 0, len);
310 strcpyW(name, prefix);
311 strcatW(name, service);
312 return name;
315 static HANDLE service_open_pipe(LPCWSTR service)
317 LPWSTR szPipe = service_get_pipe_name( service );
318 HANDLE handle = INVALID_HANDLE_VALUE;
320 do {
321 handle = CreateFileW(szPipe, GENERIC_READ|GENERIC_WRITE,
322 0, NULL, OPEN_ALWAYS, 0, NULL);
323 if (handle != INVALID_HANDLE_VALUE)
324 break;
325 if (GetLastError() != ERROR_PIPE_BUSY)
326 break;
327 } while (WaitNamedPipeW(szPipe, NMPWAIT_WAIT_FOREVER));
328 SERV_free(szPipe);
330 return handle;
333 /******************************************************************************
334 * service_get_event_handle
336 static HANDLE service_get_event_handle(LPCWSTR service)
338 static const WCHAR prefix[] = {
339 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
340 LPWSTR name;
341 DWORD len;
342 HANDLE handle;
344 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
345 name = HeapAlloc(GetProcessHeap(), 0, len);
346 strcpyW(name, prefix);
347 strcatW(name, service);
348 handle = CreateEventW(NULL, TRUE, FALSE, name);
349 SERV_free(name);
350 return handle;
353 /******************************************************************************
354 * service_thread
356 * Call into the main service routine provided by StartServiceCtrlDispatcher.
358 static DWORD WINAPI service_thread(LPVOID arg)
360 service_data *info = arg;
361 LPWSTR str = info->args;
362 DWORD argc = 0, len = 0;
364 TRACE("%p\n", arg);
366 while (str[len])
368 len += strlenW(&str[len]) + 1;
369 argc++;
372 if (!argc)
374 if (info->unicode)
375 info->proc.w(0, NULL);
376 else
377 info->proc.a(0, NULL);
378 return 0;
381 if (info->unicode)
383 LPWSTR *argv, p;
385 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPWSTR));
386 for (argc=0, p=str; *p; p += strlenW(p) + 1)
387 argv[argc++] = p;
388 argv[argc] = NULL;
390 info->proc.w(argc, argv);
391 HeapFree(GetProcessHeap(), 0, argv);
393 else
395 LPSTR strA, *argv, p;
396 DWORD lenA;
398 lenA = WideCharToMultiByte(CP_ACP,0, str, len, NULL, 0, NULL, NULL);
399 strA = HeapAlloc(GetProcessHeap(), 0, lenA);
400 WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL);
402 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPSTR));
403 for (argc=0, p=strA; *p; p += strlen(p) + 1)
404 argv[argc++] = p;
405 argv[argc] = NULL;
407 info->proc.a(argc, argv);
408 HeapFree(GetProcessHeap(), 0, argv);
409 HeapFree(GetProcessHeap(), 0, strA);
411 return 0;
414 /******************************************************************************
415 * service_handle_start
417 static BOOL service_handle_start(HANDLE pipe, service_data *service, DWORD count)
419 DWORD read = 0, result = 0;
420 LPWSTR args;
421 BOOL r;
423 TRACE("%p %p %d\n", pipe, service, count);
425 args = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
426 r = ReadFile(pipe, args, count*sizeof(WCHAR), &read, NULL);
427 if (!r || count!=read/sizeof(WCHAR) || args[count-1])
429 ERR("pipe read failed r = %d count = %d read = %d args[n-1]=%s\n",
430 r, count, read, debugstr_wn(args, count));
431 goto end;
434 if (service->thread)
436 ERR("service is not stopped\n");
437 goto end;
440 SERV_free(service->args);
441 service->args = args;
442 args = NULL;
443 service->thread = CreateThread( NULL, 0, service_thread,
444 service, 0, NULL );
446 end:
447 HeapFree(GetProcessHeap(), 0, args);
448 WriteFile( pipe, &result, sizeof result, &read, NULL );
450 return TRUE;
453 /******************************************************************************
454 * service_send_start_message
456 static BOOL service_send_start_message(HANDLE pipe, LPCWSTR *argv, DWORD argc)
458 DWORD i, len, count, result;
459 service_start_info *ssi;
460 LPWSTR p;
461 BOOL r;
463 TRACE("%p %p %d\n", pipe, argv, argc);
465 /* calculate how much space do we need to send the startup info */
466 len = 1;
467 for (i=0; i<argc; i++)
468 len += strlenW(argv[i])+1;
470 ssi = HeapAlloc(GetProcessHeap(),0,sizeof *ssi + (len-1)*sizeof(WCHAR));
471 ssi->cmd = WINESERV_STARTINFO;
472 ssi->size = len;
474 /* copy service args into a single buffer*/
475 p = &ssi->str[0];
476 for (i=0; i<argc; i++)
478 strcpyW(p, argv[i]);
479 p += strlenW(p) + 1;
481 *p=0;
483 r = WriteFile(pipe, ssi, sizeof *ssi + len*sizeof(WCHAR), &count, NULL);
484 if (r)
485 r = ReadFile(pipe, &result, sizeof result, &count, NULL);
487 HeapFree(GetProcessHeap(),0,ssi);
489 return r;
492 /******************************************************************************
493 * service_handle_get_status
495 static BOOL service_handle_get_status(HANDLE pipe, const service_data *service)
497 DWORD count = 0;
498 TRACE("\n");
499 return WriteFile(pipe, &service->status,
500 sizeof service->status, &count, NULL);
503 /******************************************************************************
504 * service_get_status
506 static BOOL service_get_status(HANDLE pipe, LPSERVICE_STATUS_PROCESS status)
508 DWORD cmd[2], count = 0;
509 BOOL r;
511 cmd[0] = WINESERV_GETSTATUS;
512 cmd[1] = 0;
513 r = WriteFile( pipe, cmd, sizeof cmd, &count, NULL );
514 if (!r || count != sizeof cmd)
516 ERR("service protocol error - failed to write pipe!\n");
517 return r;
519 r = ReadFile( pipe, status, sizeof *status, &count, NULL );
520 if (!r || count != sizeof *status)
521 ERR("service protocol error - failed to read pipe "
522 "r = %d count = %d!\n", r, count);
523 return r;
526 /******************************************************************************
527 * service_handle_set_processID
529 static BOOL service_handle_set_processID(HANDLE pipe, service_data *service, DWORD dwProcessId)
531 DWORD count, ret = ERROR_SUCCESS;
533 TRACE("received control %d\n", dwProcessId);
534 service->status.dwProcessId = dwProcessId;
535 return WriteFile(pipe, &ret, sizeof ret , &count, NULL);
538 /******************************************************************************
539 * service_set_processID
541 static BOOL service_set_processID(HANDLE pipe, DWORD dwprocessId, LPDWORD dwResult)
543 DWORD cmd[2], count = 0;
544 BOOL r;
546 cmd[0] = WINESERV_SETPID;
547 cmd[1] = dwprocessId;
548 r = WriteFile( pipe, cmd, sizeof cmd, &count, NULL );
549 if (!r || count != sizeof cmd)
551 ERR("service protocol error - failed to write pipe!\n");
552 return r;
554 r = ReadFile( pipe, dwResult, sizeof *dwResult, &count, NULL );
555 if (!r || count != sizeof *dwResult)
556 ERR("service protocol error - failed to read pipe "
557 "r = %d count = %d!\n", r, count);
558 return r;
561 /******************************************************************************
562 * service_send_control
564 static BOOL service_send_control(HANDLE pipe, DWORD dwControl, DWORD *result)
566 DWORD cmd[2], count = 0;
567 BOOL r;
569 cmd[0] = WINESERV_SENDCONTROL;
570 cmd[1] = dwControl;
571 r = WriteFile(pipe, cmd, sizeof cmd, &count, NULL);
572 if (!r || count != sizeof cmd)
574 ERR("service protocol error - failed to write pipe!\n");
575 return r;
577 r = ReadFile(pipe, result, sizeof *result, &count, NULL);
578 if (!r || count != sizeof *result)
579 ERR("service protocol error - failed to read pipe "
580 "r = %d count = %d!\n", r, count);
581 return r;
584 /******************************************************************************
585 * service_accepts_control
587 static BOOL service_accepts_control(const service_data *service, DWORD dwControl)
589 DWORD a = service->status.dwControlsAccepted;
591 switch (dwControl)
593 case SERVICE_CONTROL_INTERROGATE:
594 return TRUE;
595 case SERVICE_CONTROL_STOP:
596 if (a&SERVICE_ACCEPT_STOP)
597 return TRUE;
598 break;
599 case SERVICE_CONTROL_SHUTDOWN:
600 if (a&SERVICE_ACCEPT_SHUTDOWN)
601 return TRUE;
602 break;
603 case SERVICE_CONTROL_PAUSE:
604 case SERVICE_CONTROL_CONTINUE:
605 if (a&SERVICE_ACCEPT_PAUSE_CONTINUE)
606 return TRUE;
607 break;
608 case SERVICE_CONTROL_PARAMCHANGE:
609 if (a&SERVICE_ACCEPT_PARAMCHANGE)
610 return TRUE;
611 break;
612 case SERVICE_CONTROL_NETBINDADD:
613 case SERVICE_CONTROL_NETBINDREMOVE:
614 case SERVICE_CONTROL_NETBINDENABLE:
615 case SERVICE_CONTROL_NETBINDDISABLE:
616 if (a&SERVICE_ACCEPT_NETBINDCHANGE)
617 return TRUE;
619 if (!service->extended)
620 return FALSE;
621 switch (dwControl)
623 case SERVICE_CONTROL_HARDWAREPROFILECHANGE:
624 if (a&SERVICE_ACCEPT_HARDWAREPROFILECHANGE)
625 return TRUE;
626 break;
627 case SERVICE_CONTROL_POWEREVENT:
628 if (a&SERVICE_ACCEPT_POWEREVENT)
629 return TRUE;
630 break;
631 case SERVICE_CONTROL_SESSIONCHANGE:
632 if (a&SERVICE_ACCEPT_SESSIONCHANGE)
633 return TRUE;
634 break;
636 return FALSE;
639 /******************************************************************************
640 * service_handle_control
642 static BOOL service_handle_control(HANDLE pipe, service_data *service,
643 DWORD dwControl)
645 DWORD count, ret = ERROR_INVALID_SERVICE_CONTROL;
647 TRACE("received control %d\n", dwControl);
649 if (service_accepts_control(service, dwControl))
651 if (service->extended && service->handler.handler_ex)
653 service->handler.handler_ex(dwControl, 0, NULL, service->context);
654 ret = ERROR_SUCCESS;
656 else if (service->handler.handler)
658 service->handler.handler(dwControl);
659 ret = ERROR_SUCCESS;
662 return WriteFile(pipe, &ret, sizeof ret, &count, NULL);
665 /******************************************************************************
666 * service_reap_thread
668 static DWORD service_reap_thread(service_data *service)
670 DWORD exitcode = 0;
672 if (!service->thread)
673 return 0;
674 GetExitCodeThread(service->thread, &exitcode);
675 if (exitcode!=STILL_ACTIVE)
677 CloseHandle(service->thread);
678 service->thread = 0;
680 return exitcode;
683 /******************************************************************************
684 * service_control_dispatcher
686 static DWORD WINAPI service_control_dispatcher(LPVOID arg)
688 service_data *service = arg;
689 LPWSTR name;
690 HANDLE pipe, event;
692 TRACE("%p %s\n", service, debugstr_w(service->name));
694 /* create a pipe to talk to the rest of the world with */
695 name = service_get_pipe_name(service->name);
696 pipe = CreateNamedPipeW(name, PIPE_ACCESS_DUPLEX,
697 PIPE_TYPE_BYTE|PIPE_WAIT, 1, 256, 256, 10000, NULL );
698 SERV_free(name);
700 /* let the process who started us know we've tried to create a pipe */
701 event = service_get_event_handle(service->name);
702 SetEvent(event);
703 CloseHandle(event);
705 if (pipe==INVALID_HANDLE_VALUE)
707 ERR("failed to create pipe for %s, error = %d\n",
708 debugstr_w(service->name), GetLastError());
709 return 0;
712 /* dispatcher loop */
713 while (1)
715 BOOL r;
716 DWORD count, req[2] = {0,0};
718 r = ConnectNamedPipe(pipe, NULL);
719 if (!r && GetLastError() != ERROR_PIPE_CONNECTED)
721 ERR("pipe connect failed\n");
722 break;
725 r = ReadFile( pipe, &req, sizeof req, &count, NULL );
726 if (!r || count!=sizeof req)
728 ERR("pipe read failed\n");
729 break;
732 service_reap_thread(service);
734 /* handle the request */
735 switch (req[0])
737 case WINESERV_STARTINFO:
738 service_handle_start(pipe, service, req[1]);
739 break;
740 case WINESERV_GETSTATUS:
741 service_handle_get_status(pipe, service);
742 break;
743 case WINESERV_SENDCONTROL:
744 service_handle_control(pipe, service, req[1]);
745 break;
746 case WINESERV_SETPID:
747 service_handle_set_processID(pipe, service, req[1]);
748 break;
749 default:
750 ERR("received invalid command %d length %d\n", req[0], req[1]);
753 FlushFileBuffers(pipe);
754 DisconnectNamedPipe(pipe);
757 CloseHandle(pipe);
758 return 1;
761 /******************************************************************************
762 * service_run_threads
764 static BOOL service_run_threads(void)
766 service_data *service;
767 DWORD count = 0, n = 0;
768 HANDLE *handles;
770 EnterCriticalSection( &service_cs );
772 /* count how many services there are */
773 for (service = service_list; service; service = service->next)
774 count++;
776 TRACE("starting %d pipe listener threads\n", count);
778 handles = HeapAlloc(GetProcessHeap(), 0, sizeof(HANDLE)*count);
780 for (n=0, service = service_list; service; service = service->next, n++)
781 handles[n] = CreateThread( NULL, 0, service_control_dispatcher,
782 service, 0, NULL );
783 assert(n==count);
785 LeaveCriticalSection( &service_cs );
787 /* wait for all the threads to pack up and exit */
788 WaitForMultipleObjectsEx(count, handles, TRUE, INFINITE, FALSE);
790 HeapFree(GetProcessHeap(), 0, handles);
792 return TRUE;
795 /******************************************************************************
796 * StartServiceCtrlDispatcherA [ADVAPI32.@]
798 * See StartServiceCtrlDispatcherW.
800 BOOL WINAPI StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *servent )
802 service_data *info;
803 DWORD sz, len;
804 BOOL ret = TRUE;
806 TRACE("%p\n", servent);
808 EnterCriticalSection( &service_cs );
809 while (servent->lpServiceName)
811 LPSTR name = servent->lpServiceName;
813 len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0);
814 sz = len*sizeof(WCHAR) + sizeof *info;
815 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
816 MultiByteToWideChar(CP_ACP, 0, name, -1, info->name, len);
817 info->proc.a = servent->lpServiceProc;
818 info->unicode = FALSE;
820 /* insert into the list */
821 info->next = service_list;
822 service_list = info;
824 servent++;
826 LeaveCriticalSection( &service_cs );
828 service_run_threads();
830 return ret;
833 /******************************************************************************
834 * StartServiceCtrlDispatcherW [ADVAPI32.@]
836 * Connects a process containing one or more services to the service control
837 * manager.
839 * PARAMS
840 * servent [I] A list of the service names and service procedures
842 * RETURNS
843 * Success: TRUE.
844 * Failure: FALSE.
846 BOOL WINAPI StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW *servent )
848 service_data *info;
849 DWORD sz, len;
850 BOOL ret = TRUE;
852 TRACE("%p\n", servent);
854 EnterCriticalSection( &service_cs );
855 while (servent->lpServiceName)
857 LPWSTR name = servent->lpServiceName;
859 len = strlenW(name);
860 sz = len*sizeof(WCHAR) + sizeof *info;
861 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
862 strcpyW(info->name, name);
863 info->proc.w = servent->lpServiceProc;
864 info->unicode = TRUE;
866 /* insert into the list */
867 info->next = service_list;
868 service_list = info;
870 servent++;
872 LeaveCriticalSection( &service_cs );
874 service_run_threads();
876 return ret;
879 /******************************************************************************
880 * LockServiceDatabase [ADVAPI32.@]
882 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
884 HANDLE ret;
886 TRACE("%p\n",hSCManager);
888 ret = CreateSemaphoreW( NULL, 1, 1, szSCMLock );
889 if( ret && GetLastError() == ERROR_ALREADY_EXISTS )
891 CloseHandle( ret );
892 ret = NULL;
893 SetLastError( ERROR_SERVICE_DATABASE_LOCKED );
896 TRACE("returning %p\n", ret);
898 return ret;
901 /******************************************************************************
902 * UnlockServiceDatabase [ADVAPI32.@]
904 BOOL WINAPI UnlockServiceDatabase (SC_LOCK ScLock)
906 TRACE("%p\n",ScLock);
908 return CloseHandle( ScLock );
911 /******************************************************************************
912 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
914 SERVICE_STATUS_HANDLE WINAPI
915 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName, LPHANDLER_FUNCTION lpfHandler )
917 LPWSTR lpServiceNameW;
918 SERVICE_STATUS_HANDLE ret;
920 lpServiceNameW = SERV_dup(lpServiceName);
921 ret = RegisterServiceCtrlHandlerW( lpServiceNameW, lpfHandler );
922 SERV_free(lpServiceNameW);
923 return ret;
926 /******************************************************************************
927 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
929 * PARAMS
930 * lpServiceName []
931 * lpfHandler []
933 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName,
934 LPHANDLER_FUNCTION lpfHandler )
936 service_data *service;
938 EnterCriticalSection( &service_cs );
939 for(service = service_list; service; service = service->next)
940 if(!strcmpW(lpServiceName, service->name))
941 break;
942 if (service)
943 service->handler.handler = lpfHandler;
944 LeaveCriticalSection( &service_cs );
946 return (SERVICE_STATUS_HANDLE)service;
949 /******************************************************************************
950 * SetServiceStatus [ADVAPI32.@]
952 * PARAMS
953 * hService []
954 * lpStatus []
956 BOOL WINAPI
957 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
959 service_data *service;
960 BOOL r = TRUE;
962 TRACE("%p %x %x %x %x %x %x %x\n", hService,
963 lpStatus->dwServiceType, lpStatus->dwCurrentState,
964 lpStatus->dwControlsAccepted, lpStatus->dwWin32ExitCode,
965 lpStatus->dwServiceSpecificExitCode, lpStatus->dwCheckPoint,
966 lpStatus->dwWaitHint);
968 EnterCriticalSection( &service_cs );
969 for (service = service_list; service; service = service->next)
970 if(service == (service_data*)hService)
971 break;
972 if (service)
974 memcpy( &service->status, lpStatus, sizeof(SERVICE_STATUS) );
975 TRACE("Set service status to %d\n",service->status.dwCurrentState);
977 else
978 r = FALSE;
979 LeaveCriticalSection( &service_cs );
981 return r;
985 /******************************************************************************
986 * OpenSCManagerA [ADVAPI32.@]
988 * Establish a connection to the service control manager and open its database.
990 * PARAMS
991 * lpMachineName [I] Pointer to machine name string
992 * lpDatabaseName [I] Pointer to database name string
993 * dwDesiredAccess [I] Type of access
995 * RETURNS
996 * Success: A Handle to the service control manager database
997 * Failure: NULL
999 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
1000 DWORD dwDesiredAccess )
1002 LPWSTR lpMachineNameW, lpDatabaseNameW;
1003 SC_HANDLE ret;
1005 lpMachineNameW = SERV_dup(lpMachineName);
1006 lpDatabaseNameW = SERV_dup(lpDatabaseName);
1007 ret = OpenSCManagerW(lpMachineNameW, lpDatabaseNameW, dwDesiredAccess);
1008 SERV_free(lpDatabaseNameW);
1009 SERV_free(lpMachineNameW);
1010 return ret;
1013 /******************************************************************************
1014 * OpenSCManagerW [ADVAPI32.@]
1016 * See OpenSCManagerA.
1018 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
1019 DWORD dwDesiredAccess )
1021 struct sc_manager *manager;
1022 HKEY hReg;
1023 LONG r;
1025 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName),
1026 debugstr_w(lpDatabaseName), dwDesiredAccess);
1028 if( lpDatabaseName && lpDatabaseName[0] )
1030 if( strcmpiW( lpDatabaseName, SERVICES_ACTIVE_DATABASEW ) == 0 )
1032 /* noop, all right */
1034 else if( strcmpiW( lpDatabaseName, SERVICES_FAILED_DATABASEW ) == 0 )
1036 SetLastError( ERROR_DATABASE_DOES_NOT_EXIST );
1037 return NULL;
1039 else
1041 SetLastError( ERROR_INVALID_NAME );
1042 return NULL;
1046 manager = sc_handle_alloc( SC_HTYPE_MANAGER, sizeof (struct sc_manager),
1047 sc_handle_destroy_manager );
1048 if (!manager)
1049 return NULL;
1051 r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
1052 if (r!=ERROR_SUCCESS)
1053 goto error;
1055 r = RegCreateKeyW(hReg, szServiceManagerKey, &manager->hkey);
1056 RegCloseKey( hReg );
1057 if (r!=ERROR_SUCCESS)
1058 goto error;
1060 manager->dwAccess = dwDesiredAccess;
1061 TRACE("returning %p\n", manager);
1063 return (SC_HANDLE) &manager->hdr;
1065 error:
1066 sc_handle_free( &manager->hdr );
1067 SetLastError( r);
1068 return NULL;
1071 /******************************************************************************
1072 * ControlService [ADVAPI32.@]
1074 * Send a control code to a service.
1076 * PARAMS
1077 * hService [I] Handle of the service control manager database
1078 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
1079 * lpServiceStatus [O] Destination for the status of the service, if available
1081 * RETURNS
1082 * Success: TRUE.
1083 * Failure: FALSE.
1085 * BUGS
1086 * Unlike M$' implementation, control requests are not serialized and may be
1087 * processed asynchronously.
1089 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
1090 LPSERVICE_STATUS lpServiceStatus )
1092 struct sc_service *hsvc;
1093 BOOL ret = FALSE;
1094 HANDLE handle;
1096 TRACE("%p %d %p\n", hService, dwControl, lpServiceStatus);
1098 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1099 if (!hsvc)
1101 SetLastError( ERROR_INVALID_HANDLE );
1102 return FALSE;
1105 ret = QueryServiceStatus(hService, lpServiceStatus);
1106 if (!ret)
1108 ERR("failed to query service status\n");
1109 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1110 return FALSE;
1113 switch (lpServiceStatus->dwCurrentState)
1115 case SERVICE_STOPPED:
1116 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1117 return FALSE;
1118 case SERVICE_START_PENDING:
1119 if (dwControl==SERVICE_CONTROL_STOP)
1120 break;
1121 /* fall thru */
1122 case SERVICE_STOP_PENDING:
1123 SetLastError(ERROR_SERVICE_CANNOT_ACCEPT_CTRL);
1124 return FALSE;
1127 handle = service_open_pipe(hsvc->name);
1128 if (handle!=INVALID_HANDLE_VALUE)
1130 DWORD result = ERROR_SUCCESS;
1131 ret = service_send_control(handle, dwControl, &result);
1132 CloseHandle(handle);
1133 if (result!=ERROR_SUCCESS)
1135 SetLastError(result);
1136 ret = FALSE;
1140 return ret;
1143 /******************************************************************************
1144 * CloseServiceHandle [ADVAPI32.@]
1146 * Close a handle to a service or the service control manager database.
1148 * PARAMS
1149 * hSCObject [I] Handle to service or service control manager database
1151 * RETURNS
1152 * Success: TRUE
1153 * Failure: FALSE
1155 BOOL WINAPI
1156 CloseServiceHandle( SC_HANDLE hSCObject )
1158 TRACE("%p\n", hSCObject);
1160 sc_handle_free( (struct sc_handle*) hSCObject );
1162 return TRUE;
1166 /******************************************************************************
1167 * OpenServiceA [ADVAPI32.@]
1169 * Open a handle to a service.
1171 * PARAMS
1172 * hSCManager [I] Handle of the service control manager database
1173 * lpServiceName [I] Name of the service to open
1174 * dwDesiredAccess [I] Access required to the service
1176 * RETURNS
1177 * Success: Handle to the service
1178 * Failure: NULL
1180 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1181 DWORD dwDesiredAccess )
1183 LPWSTR lpServiceNameW;
1184 SC_HANDLE ret;
1186 TRACE("%p %s %d\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
1188 lpServiceNameW = SERV_dup(lpServiceName);
1189 ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
1190 SERV_free(lpServiceNameW);
1191 return ret;
1195 /******************************************************************************
1196 * OpenServiceW [ADVAPI32.@]
1198 * See OpenServiceA.
1200 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1201 DWORD dwDesiredAccess)
1203 struct sc_manager *hscm;
1204 struct sc_service *hsvc;
1205 HKEY hKey;
1206 long r;
1207 DWORD len;
1209 TRACE("%p %s %d\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
1211 if (!lpServiceName)
1213 SetLastError(ERROR_INVALID_ADDRESS);
1214 return NULL;
1217 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1218 if (!hscm)
1220 SetLastError( ERROR_INVALID_HANDLE );
1221 return FALSE;
1224 r = RegOpenKeyExW( hscm->hkey, lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
1225 if (r!=ERROR_SUCCESS)
1227 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
1228 return NULL;
1231 len = strlenW(lpServiceName)+1;
1232 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE,
1233 sizeof (struct sc_service) + len*sizeof(WCHAR),
1234 sc_handle_destroy_service );
1235 if (!hsvc)
1236 return NULL;
1237 strcpyW( hsvc->name, lpServiceName );
1238 hsvc->hkey = hKey;
1239 hsvc->dwAccess = dwDesiredAccess;
1241 /* add reference to SCM handle */
1242 hscm->hdr.ref_count++;
1243 hsvc->scm = hscm;
1245 TRACE("returning %p\n",hsvc);
1247 return (SC_HANDLE) &hsvc->hdr;
1250 /******************************************************************************
1251 * CreateServiceW [ADVAPI32.@]
1253 SC_HANDLE WINAPI
1254 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1255 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
1256 DWORD dwServiceType, DWORD dwStartType,
1257 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1258 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1259 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
1260 LPCWSTR lpPassword )
1262 struct sc_manager *hscm;
1263 struct sc_service *hsvc = NULL;
1264 HKEY hKey;
1265 LONG r;
1266 DWORD dp, len;
1267 struct reg_value val[10];
1268 int n = 0;
1270 TRACE("%p %s %s\n", hSCManager,
1271 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
1273 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1274 if (!hscm)
1276 SetLastError( ERROR_INVALID_HANDLE );
1277 return NULL;
1280 r = RegCreateKeyExW(hscm->hkey, lpServiceName, 0, NULL,
1281 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
1282 if (r!=ERROR_SUCCESS)
1283 return NULL;
1285 if (dp != REG_CREATED_NEW_KEY)
1287 SetLastError(ERROR_SERVICE_EXISTS);
1288 goto error;
1291 if( lpDisplayName )
1292 service_set_string( &val[n++], szDisplayName, lpDisplayName );
1294 service_set_dword( &val[n++], szType, &dwServiceType );
1295 service_set_dword( &val[n++], szStart, &dwStartType );
1296 service_set_dword( &val[n++], szError, &dwErrorControl );
1298 if( lpBinaryPathName )
1299 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
1301 if( lpLoadOrderGroup )
1302 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
1304 if( lpDependencies )
1305 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
1307 if( lpPassword )
1308 FIXME("Don't know how to add a Password for a service.\n");
1310 if( lpServiceStartName )
1311 service_set_string( &val[n++], szDependOnService, lpServiceStartName );
1313 r = service_write_values( hKey, val, n );
1314 if( r != ERROR_SUCCESS )
1315 goto error;
1317 len = strlenW(lpServiceName)+1;
1318 len = sizeof (struct sc_service) + len*sizeof(WCHAR);
1319 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE, len, sc_handle_destroy_service );
1320 if( !hsvc )
1321 goto error;
1322 lstrcpyW( hsvc->name, lpServiceName );
1323 hsvc->hkey = hKey;
1324 hsvc->scm = hscm;
1325 hscm->hdr.ref_count++;
1327 return (SC_HANDLE) &hsvc->hdr;
1329 error:
1330 RegCloseKey( hKey );
1331 return NULL;
1335 /******************************************************************************
1336 * CreateServiceA [ADVAPI32.@]
1338 SC_HANDLE WINAPI
1339 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1340 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1341 DWORD dwServiceType, DWORD dwStartType,
1342 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1343 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1344 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1345 LPCSTR lpPassword )
1347 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1348 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1349 SC_HANDLE r;
1351 TRACE("%p %s %s\n", hSCManager,
1352 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1354 lpServiceNameW = SERV_dup( lpServiceName );
1355 lpDisplayNameW = SERV_dup( lpDisplayName );
1356 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1357 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1358 lpDependenciesW = SERV_dupmulti( lpDependencies );
1359 lpServiceStartNameW = SERV_dup( lpServiceStartName );
1360 lpPasswordW = SERV_dup( lpPassword );
1362 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1363 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1364 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1365 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1367 SERV_free( lpServiceNameW );
1368 SERV_free( lpDisplayNameW );
1369 SERV_free( lpBinaryPathNameW );
1370 SERV_free( lpLoadOrderGroupW );
1371 SERV_free( lpDependenciesW );
1372 SERV_free( lpServiceStartNameW );
1373 SERV_free( lpPasswordW );
1375 return r;
1379 /******************************************************************************
1380 * DeleteService [ADVAPI32.@]
1382 * Delete a service from the service control manager database.
1384 * PARAMS
1385 * hService [I] Handle of the service to delete
1387 * RETURNS
1388 * Success: TRUE
1389 * Failure: FALSE
1391 BOOL WINAPI DeleteService( SC_HANDLE hService )
1393 struct sc_service *hsvc;
1394 HKEY hKey;
1395 WCHAR valname[MAX_PATH+1];
1396 INT index = 0;
1397 LONG rc;
1398 DWORD size;
1400 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1401 if (!hsvc)
1403 SetLastError( ERROR_INVALID_HANDLE );
1404 return FALSE;
1406 hKey = hsvc->hkey;
1408 size = MAX_PATH+1;
1409 /* Clean out the values */
1410 rc = RegEnumValueW(hKey, index, valname,&size,0,0,0,0);
1411 while (rc == ERROR_SUCCESS)
1413 RegDeleteValueW(hKey,valname);
1414 index++;
1415 size = MAX_PATH+1;
1416 rc = RegEnumValueW(hKey, index, valname, &size,0,0,0,0);
1419 RegCloseKey(hKey);
1420 hsvc->hkey = NULL;
1422 /* delete the key */
1423 RegDeleteKeyW(hsvc->scm->hkey, hsvc->name);
1425 return TRUE;
1429 /******************************************************************************
1430 * StartServiceA [ADVAPI32.@]
1432 * Start a service
1434 * PARAMS
1435 * hService [I] Handle of service
1436 * dwNumServiceArgs [I] Number of arguments
1437 * lpServiceArgVectors [I] Address of array of argument strings
1439 * NOTES
1440 * - NT implements this function using an obscure RPC call.
1441 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1442 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1443 * - This will only work for shared address space. How should the service
1444 * args be transferred when address spaces are separated?
1445 * - Can only start one service at a time.
1446 * - Has no concept of privilege.
1448 * RETURNS
1449 * Success: TRUE.
1450 * Failure: FALSE
1452 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1453 LPCSTR *lpServiceArgVectors )
1455 LPWSTR *lpwstr=NULL;
1456 unsigned int i;
1457 BOOL r;
1459 TRACE("(%p,%d,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1461 if (dwNumServiceArgs)
1462 lpwstr = HeapAlloc( GetProcessHeap(), 0,
1463 dwNumServiceArgs*sizeof(LPWSTR) );
1465 for(i=0; i<dwNumServiceArgs; i++)
1466 lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1468 r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1470 if (dwNumServiceArgs)
1472 for(i=0; i<dwNumServiceArgs; i++)
1473 SERV_free(lpwstr[i]);
1474 HeapFree(GetProcessHeap(), 0, lpwstr);
1477 return r;
1480 /******************************************************************************
1481 * service_start_process [INTERNAL]
1483 static DWORD service_start_process(struct sc_service *hsvc, LPDWORD ppid)
1485 static const WCHAR _ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0};
1486 PROCESS_INFORMATION pi;
1487 STARTUPINFOW si;
1488 LPWSTR path = NULL, str;
1489 DWORD type, size, ret, svc_type;
1490 HANDLE handles[2];
1491 BOOL r;
1493 size = sizeof(svc_type);
1494 if (RegQueryValueExW(hsvc->hkey, szType, NULL, &type, (LPBYTE)&svc_type, &size) || type != REG_DWORD)
1495 svc_type = 0;
1497 if (svc_type == SERVICE_KERNEL_DRIVER)
1499 static const WCHAR winedeviceW[] = {'\\','w','i','n','e','d','e','v','i','c','e','.','e','x','e',' ',0};
1500 DWORD len = GetSystemDirectoryW( NULL, 0 ) + sizeof(winedeviceW)/sizeof(WCHAR) + strlenW(hsvc->name);
1502 if (!(path = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return FALSE;
1503 GetSystemDirectoryW( path, len );
1504 lstrcatW( path, winedeviceW );
1505 lstrcatW( path, hsvc->name );
1507 else
1509 /* read the executable path from the registry */
1510 size = 0;
1511 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, NULL, &size);
1512 if (ret!=ERROR_SUCCESS)
1513 return FALSE;
1514 str = HeapAlloc(GetProcessHeap(),0,size);
1515 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, (LPBYTE)str, &size);
1516 if (ret==ERROR_SUCCESS)
1518 size = ExpandEnvironmentStringsW(str,NULL,0);
1519 path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
1520 ExpandEnvironmentStringsW(str,path,size);
1522 HeapFree(GetProcessHeap(),0,str);
1523 if (!path)
1524 return FALSE;
1527 /* wait for the process to start and set an event or terminate */
1528 handles[0] = service_get_event_handle( hsvc->name );
1529 ZeroMemory(&si, sizeof(STARTUPINFOW));
1530 si.cb = sizeof(STARTUPINFOW);
1531 r = CreateProcessW(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1532 if (r)
1534 if (ppid) *ppid = pi.dwProcessId;
1536 handles[1] = pi.hProcess;
1537 ret = WaitForMultipleObjectsEx(2, handles, FALSE, 30000, FALSE);
1538 if(ret != WAIT_OBJECT_0)
1540 SetLastError(ERROR_IO_PENDING);
1541 r = FALSE;
1544 CloseHandle( pi.hThread );
1545 CloseHandle( pi.hProcess );
1547 CloseHandle( handles[0] );
1548 HeapFree(GetProcessHeap(),0,path);
1549 return r;
1552 static BOOL service_wait_for_startup(SC_HANDLE hService)
1554 DWORD i;
1555 SERVICE_STATUS status;
1556 BOOL r = FALSE;
1558 TRACE("%p\n", hService);
1560 for (i=0; i<30; i++)
1562 status.dwCurrentState = 0;
1563 r = QueryServiceStatus(hService, &status);
1564 if (!r)
1565 break;
1566 if (status.dwCurrentState == SERVICE_RUNNING)
1568 TRACE("Service started successfully\n");
1569 break;
1571 r = FALSE;
1572 Sleep(1000);
1574 return r;
1577 /******************************************************************************
1578 * StartServiceW [ADVAPI32.@]
1580 * See StartServiceA.
1582 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1583 LPCWSTR *lpServiceArgVectors)
1585 struct sc_service *hsvc;
1586 BOOL r = FALSE;
1587 DWORD dwResult, dwProcessId = 0;
1588 SC_LOCK hLock;
1589 HANDLE handle = INVALID_HANDLE_VALUE;
1591 TRACE("%p %d %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1593 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1594 if (!hsvc)
1596 SetLastError(ERROR_INVALID_HANDLE);
1597 return r;
1600 hLock = LockServiceDatabase((SC_HANDLE)hsvc->scm);
1601 if (!hLock)
1602 return r;
1604 handle = service_open_pipe(hsvc->name);
1605 if (handle==INVALID_HANDLE_VALUE)
1607 /* start the service process */
1608 if (service_start_process(hsvc, &dwProcessId))
1609 handle = service_open_pipe(hsvc->name);
1612 if (handle != INVALID_HANDLE_VALUE)
1614 r = service_send_start_message(handle, lpServiceArgVectors, dwNumServiceArgs);
1615 CloseHandle(handle);
1618 handle = service_open_pipe(hsvc->name);
1619 if (handle != INVALID_HANDLE_VALUE)
1621 service_set_processID(handle, dwProcessId, &dwResult);
1622 CloseHandle(handle);
1625 UnlockServiceDatabase( hLock );
1627 TRACE("returning %d\n", r);
1629 if (r)
1630 service_wait_for_startup(hService);
1632 return r;
1635 /******************************************************************************
1636 * QueryServiceStatus [ADVAPI32.@]
1638 * PARAMS
1639 * hService [I] Handle to service to get information about
1640 * lpservicestatus [O] buffer to receive the status information for the service
1643 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1644 LPSERVICE_STATUS lpservicestatus)
1646 SERVICE_STATUS_PROCESS SvcStatusData;
1647 BOOL ret;
1649 TRACE("%p %p\n", hService, lpservicestatus);
1651 ret = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&SvcStatusData,
1652 sizeof(SERVICE_STATUS_PROCESS), NULL);
1653 if (ret) memcpy(lpservicestatus, &SvcStatusData, sizeof(SERVICE_STATUS)) ;
1654 return ret;
1658 /******************************************************************************
1659 * QueryServiceStatusEx [ADVAPI32.@]
1661 * Get information about a service.
1663 * PARAMS
1664 * hService [I] Handle to service to get information about
1665 * InfoLevel [I] Level of information to get
1666 * lpBuffer [O] Destination for requested information
1667 * cbBufSize [I] Size of lpBuffer in bytes
1668 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1670 * RETURNS
1671 * Success: TRUE
1672 * FAILURE: FALSE
1674 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1675 LPBYTE lpBuffer, DWORD cbBufSize,
1676 LPDWORD pcbBytesNeeded)
1678 struct sc_service *hsvc;
1679 DWORD size, type, val;
1680 HANDLE pipe;
1681 LONG r;
1682 LPSERVICE_STATUS_PROCESS pSvcStatusData;
1684 TRACE("%p %d %p %d %p\n", hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1686 if (InfoLevel != SC_STATUS_PROCESS_INFO)
1688 SetLastError( ERROR_INVALID_LEVEL);
1689 return FALSE;
1692 pSvcStatusData = (LPSERVICE_STATUS_PROCESS) lpBuffer;
1693 if (pSvcStatusData == NULL)
1695 SetLastError( ERROR_INVALID_PARAMETER);
1696 return FALSE;
1699 if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
1701 if( pcbBytesNeeded != NULL)
1702 *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
1704 SetLastError( ERROR_INSUFFICIENT_BUFFER);
1705 return FALSE;
1708 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1709 if (!hsvc)
1711 SetLastError( ERROR_INVALID_HANDLE );
1712 return FALSE;
1715 pipe = service_open_pipe(hsvc->name);
1716 if (pipe != INVALID_HANDLE_VALUE)
1718 r = service_get_status(pipe, pSvcStatusData);
1719 CloseHandle(pipe);
1720 if (r)
1721 return TRUE;
1724 TRACE("Failed to read service status\n");
1726 /* read the service type from the registry */
1727 size = sizeof(val);
1728 r = RegQueryValueExA(hsvc->hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1729 if (r != ERROR_SUCCESS || type != REG_DWORD)
1730 val = 0;
1732 pSvcStatusData->dwServiceType = val;
1733 pSvcStatusData->dwCurrentState = SERVICE_STOPPED; /* stopped */
1734 pSvcStatusData->dwControlsAccepted = 0;
1735 pSvcStatusData->dwWin32ExitCode = ERROR_SERVICE_NEVER_STARTED;
1736 pSvcStatusData->dwServiceSpecificExitCode = 0;
1737 pSvcStatusData->dwCheckPoint = 0;
1738 pSvcStatusData->dwWaitHint = 0;
1740 return TRUE;
1743 /******************************************************************************
1744 * QueryServiceConfigA [ADVAPI32.@]
1746 BOOL WINAPI QueryServiceConfigA( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGA config,
1747 DWORD size, LPDWORD needed )
1749 DWORD n;
1750 LPSTR p, buffer;
1751 BOOL ret;
1752 QUERY_SERVICE_CONFIGW *configW;
1754 TRACE("%p %p %d %p\n", hService, config, size, needed);
1756 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, 2 * size )))
1758 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1759 return FALSE;
1761 configW = (QUERY_SERVICE_CONFIGW *)buffer;
1762 ret = QueryServiceConfigW( hService, configW, 2 * size, needed );
1763 if (!ret) goto done;
1765 config->dwServiceType = configW->dwServiceType;
1766 config->dwStartType = configW->dwStartType;
1767 config->dwErrorControl = configW->dwErrorControl;
1768 config->lpBinaryPathName = NULL;
1769 config->lpLoadOrderGroup = NULL;
1770 config->dwTagId = configW->dwTagId;
1771 config->lpDependencies = NULL;
1772 config->lpServiceStartName = NULL;
1773 config->lpDisplayName = NULL;
1775 p = (LPSTR)(config + 1);
1776 n = size - sizeof(*config);
1777 ret = FALSE;
1779 #define MAP_STR(str) \
1780 do { \
1781 if (configW->str) \
1783 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1784 if (!sz) goto done; \
1785 config->str = p; \
1786 p += sz; \
1787 n -= sz; \
1789 } while (0)
1791 MAP_STR( lpBinaryPathName );
1792 MAP_STR( lpLoadOrderGroup );
1793 MAP_STR( lpDependencies );
1794 MAP_STR( lpServiceStartName );
1795 MAP_STR( lpDisplayName );
1796 #undef MAP_STR
1798 *needed = p - buffer;
1799 ret = TRUE;
1801 done:
1802 HeapFree( GetProcessHeap(), 0, buffer );
1803 return ret;
1806 /******************************************************************************
1807 * QueryServiceConfigW [ADVAPI32.@]
1809 BOOL WINAPI
1810 QueryServiceConfigW( SC_HANDLE hService,
1811 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1812 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1814 WCHAR str_buffer[ MAX_PATH ];
1815 LONG r;
1816 DWORD type, val, sz, total, n;
1817 LPBYTE p;
1818 HKEY hKey;
1819 struct sc_service *hsvc;
1821 TRACE("%p %p %d %p\n", hService, lpServiceConfig,
1822 cbBufSize, pcbBytesNeeded);
1824 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1825 if (!hsvc)
1827 SetLastError( ERROR_INVALID_HANDLE );
1828 return FALSE;
1830 hKey = hsvc->hkey;
1832 /* calculate the size required first */
1833 total = sizeof (QUERY_SERVICE_CONFIGW);
1835 sz = sizeof(str_buffer);
1836 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1837 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1839 sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1840 if( 0 == sz ) return FALSE;
1842 total += sizeof(WCHAR) * sz;
1844 else
1846 /* FIXME: set last error */
1847 return FALSE;
1850 sz = 0;
1851 r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1852 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1853 total += sz;
1855 sz = 0;
1856 r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1857 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1858 total += sz;
1859 else
1860 total += sizeof(WCHAR);
1862 sz = 0;
1863 r = RegQueryValueExW( hKey, szStart, 0, &type, NULL, &sz );
1864 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1865 total += sz;
1867 sz = 0;
1868 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1869 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1870 total += sz;
1872 *pcbBytesNeeded = total;
1874 /* if there's not enough memory, return an error */
1875 if( total > cbBufSize )
1877 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1878 return FALSE;
1881 ZeroMemory( lpServiceConfig, total );
1883 sz = sizeof val;
1884 r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1885 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1886 lpServiceConfig->dwServiceType = val;
1888 sz = sizeof val;
1889 r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1890 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1891 lpServiceConfig->dwStartType = val;
1893 sz = sizeof val;
1894 r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1895 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1896 lpServiceConfig->dwErrorControl = val;
1898 /* now do the strings */
1899 p = (LPBYTE) &lpServiceConfig[1];
1900 n = total - sizeof (QUERY_SERVICE_CONFIGW);
1902 sz = sizeof(str_buffer);
1903 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1904 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1906 sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
1907 sz *= sizeof(WCHAR);
1908 if( 0 == sz || sz > n ) return FALSE;
1910 lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
1911 p += sz;
1912 n -= sz;
1914 else
1916 /* FIXME: set last error */
1917 return FALSE;
1920 sz = n;
1921 r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
1922 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1924 lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
1925 p += sz;
1926 n -= sz;
1929 sz = n;
1930 r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
1931 lpServiceConfig->lpDependencies = (LPWSTR) p;
1932 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1934 p += sz;
1935 n -= sz;
1937 else
1939 *(WCHAR *) p = 0;
1940 p += sizeof(WCHAR);
1941 n -= sizeof(WCHAR);
1944 if( n < 0 )
1945 ERR("Buffer overflow!\n");
1947 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1948 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1950 return TRUE;
1953 /******************************************************************************
1954 * EnumServicesStatusA [ADVAPI32.@]
1956 BOOL WINAPI
1957 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
1958 DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
1959 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1960 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1962 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
1963 dwServiceType, dwServiceState, lpServices, cbBufSize,
1964 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
1965 SetLastError (ERROR_ACCESS_DENIED);
1966 return FALSE;
1969 /******************************************************************************
1970 * EnumServicesStatusW [ADVAPI32.@]
1972 BOOL WINAPI
1973 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
1974 DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
1975 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1976 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1978 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
1979 dwServiceType, dwServiceState, lpServices, cbBufSize,
1980 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
1981 SetLastError (ERROR_ACCESS_DENIED);
1982 return FALSE;
1985 /******************************************************************************
1986 * EnumServicesStatusExA [ADVAPI32.@]
1988 BOOL WINAPI
1989 EnumServicesStatusExA(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
1990 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1991 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCSTR pszGroupName)
1993 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
1994 dwServiceType, dwServiceState, lpServices, cbBufSize,
1995 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_a(pszGroupName));
1996 SetLastError (ERROR_ACCESS_DENIED);
1997 return FALSE;
2000 /******************************************************************************
2001 * EnumServicesStatusExW [ADVAPI32.@]
2003 BOOL WINAPI
2004 EnumServicesStatusExW(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
2005 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2006 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCWSTR pszGroupName)
2008 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
2009 dwServiceType, dwServiceState, lpServices, cbBufSize,
2010 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_w(pszGroupName));
2011 SetLastError (ERROR_ACCESS_DENIED);
2012 return FALSE;
2015 /******************************************************************************
2016 * GetServiceKeyNameA [ADVAPI32.@]
2018 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
2019 LPSTR lpServiceName, LPDWORD lpcchBuffer )
2021 FIXME("%p %s %p %p\n", hSCManager, debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
2022 return FALSE;
2025 /******************************************************************************
2026 * GetServiceKeyNameW [ADVAPI32.@]
2028 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
2029 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
2031 FIXME("%p %s %p %p\n", hSCManager, debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
2032 return FALSE;
2035 /******************************************************************************
2036 * QueryServiceLockStatusA [ADVAPI32.@]
2038 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
2039 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
2040 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2042 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2044 return FALSE;
2047 /******************************************************************************
2048 * QueryServiceLockStatusW [ADVAPI32.@]
2050 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
2051 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2052 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2054 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2056 return FALSE;
2059 /******************************************************************************
2060 * GetServiceDisplayNameA [ADVAPI32.@]
2062 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
2063 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
2065 struct sc_manager *hscm;
2066 DWORD type, size;
2067 LONG ret;
2069 TRACE("%p %s %p %p\n", hSCManager,
2070 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
2072 hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
2073 if (!hscm)
2075 SetLastError(ERROR_INVALID_HANDLE);
2076 return FALSE;
2079 size = *lpcchBuffer;
2080 ret = RegGetValueA(hscm->hkey, lpServiceName, "DisplayName", RRF_RT_REG_SZ, &type, lpDisplayName, &size);
2081 if (ret)
2083 if (lpDisplayName && *lpcchBuffer) *lpDisplayName = 0;
2085 if (ret == ERROR_MORE_DATA)
2087 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2088 *lpcchBuffer = size - 1;
2090 else
2091 SetLastError(ret);
2092 return FALSE;
2094 return TRUE;
2097 /******************************************************************************
2098 * GetServiceDisplayNameW [ADVAPI32.@]
2100 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
2101 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
2103 struct sc_manager *hscm;
2104 DWORD type, size;
2105 LONG ret;
2107 TRACE("%p %s %p %p\n", hSCManager,
2108 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
2110 hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
2111 if (!hscm)
2113 SetLastError(ERROR_INVALID_HANDLE);
2114 return FALSE;
2117 size = *lpcchBuffer * sizeof(WCHAR);
2118 ret = RegGetValueW(hscm->hkey, lpServiceName, szDisplayName, RRF_RT_REG_SZ, &type, lpDisplayName, &size);
2119 if (ret)
2121 if (lpDisplayName && *lpcchBuffer) *lpDisplayName = 0;
2123 if (ret == ERROR_MORE_DATA)
2125 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2126 *lpcchBuffer = (size / sizeof(WCHAR)) - 1;
2128 else
2129 SetLastError(ret);
2130 return FALSE;
2132 return TRUE;
2135 /******************************************************************************
2136 * ChangeServiceConfigW [ADVAPI32.@]
2138 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
2139 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
2140 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
2141 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
2143 struct reg_value val[10];
2144 struct sc_service *hsvc;
2145 DWORD r = ERROR_SUCCESS;
2146 HKEY hKey;
2147 int n = 0;
2149 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2150 hService, dwServiceType, dwStartType, dwErrorControl,
2151 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2152 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2153 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2155 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2156 if (!hsvc)
2158 SetLastError( ERROR_INVALID_HANDLE );
2159 return FALSE;
2161 hKey = hsvc->hkey;
2163 if( dwServiceType != SERVICE_NO_CHANGE )
2164 service_set_dword( &val[n++], szType, &dwServiceType );
2166 if( dwStartType != SERVICE_NO_CHANGE )
2167 service_set_dword( &val[n++], szStart, &dwStartType );
2169 if( dwErrorControl != SERVICE_NO_CHANGE )
2170 service_set_dword( &val[n++], szError, &dwErrorControl );
2172 if( lpBinaryPathName )
2173 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
2175 if( lpLoadOrderGroup )
2176 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
2178 if( lpDependencies )
2179 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
2181 if( lpPassword )
2182 FIXME("ignoring password\n");
2184 if( lpServiceStartName )
2185 service_set_string( &val[n++], szDependOnService, lpServiceStartName );
2187 r = service_write_values( hsvc->hkey, val, n );
2189 return (r == ERROR_SUCCESS) ? TRUE : FALSE ;
2192 /******************************************************************************
2193 * ChangeServiceConfigA [ADVAPI32.@]
2195 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2196 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2197 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2198 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2200 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2201 LPWSTR wServiceStartName, wPassword, wDisplayName;
2202 BOOL r;
2204 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2205 hService, dwServiceType, dwStartType, dwErrorControl,
2206 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2207 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2208 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2210 wBinaryPathName = SERV_dup( lpBinaryPathName );
2211 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2212 wDependencies = SERV_dupmulti( lpDependencies );
2213 wServiceStartName = SERV_dup( lpServiceStartName );
2214 wPassword = SERV_dup( lpPassword );
2215 wDisplayName = SERV_dup( lpDisplayName );
2217 r = ChangeServiceConfigW( hService, dwServiceType,
2218 dwStartType, dwErrorControl, wBinaryPathName,
2219 wLoadOrderGroup, lpdwTagId, wDependencies,
2220 wServiceStartName, wPassword, wDisplayName);
2222 SERV_free( wBinaryPathName );
2223 SERV_free( wLoadOrderGroup );
2224 SERV_free( wDependencies );
2225 SERV_free( wServiceStartName );
2226 SERV_free( wPassword );
2227 SERV_free( wDisplayName );
2229 return r;
2232 /******************************************************************************
2233 * ChangeServiceConfig2A [ADVAPI32.@]
2235 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2236 LPVOID lpInfo)
2238 BOOL r = FALSE;
2240 TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo);
2242 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2244 LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
2245 SERVICE_DESCRIPTIONW sdw;
2247 sdw.lpDescription = SERV_dup( sd->lpDescription );
2249 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2251 SERV_free( sdw.lpDescription );
2253 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2255 LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
2256 SERVICE_FAILURE_ACTIONSW faw;
2258 faw.dwResetPeriod = fa->dwResetPeriod;
2259 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2260 faw.lpCommand = SERV_dup( fa->lpCommand );
2261 faw.cActions = fa->cActions;
2262 faw.lpsaActions = fa->lpsaActions;
2264 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2266 SERV_free( faw.lpRebootMsg );
2267 SERV_free( faw.lpCommand );
2269 else
2270 SetLastError( ERROR_INVALID_PARAMETER );
2272 return r;
2275 /******************************************************************************
2276 * ChangeServiceConfig2W [ADVAPI32.@]
2278 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2279 LPVOID lpInfo)
2281 HKEY hKey;
2282 struct sc_service *hsvc;
2284 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2285 if (!hsvc)
2287 SetLastError( ERROR_INVALID_HANDLE );
2288 return FALSE;
2290 hKey = hsvc->hkey;
2292 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2294 static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2295 LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
2296 if (sd->lpDescription)
2298 TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
2299 if (sd->lpDescription[0] == 0)
2300 RegDeleteValueW(hKey,szDescription);
2301 else
2302 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2303 (LPVOID)sd->lpDescription,
2304 sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2307 else
2308 FIXME("STUB: %p %d %p\n",hService, dwInfoLevel, lpInfo);
2309 return TRUE;
2312 /******************************************************************************
2313 * QueryServiceObjectSecurity [ADVAPI32.@]
2315 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2316 SECURITY_INFORMATION dwSecurityInformation,
2317 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2318 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2320 PACL pACL = NULL;
2322 FIXME("%p %d %p %u %p\n", hService, dwSecurityInformation,
2323 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2325 InitializeSecurityDescriptor(lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
2327 pACL = HeapAlloc( GetProcessHeap(), 0, sizeof(ACL) );
2328 InitializeAcl(pACL, sizeof(ACL), ACL_REVISION);
2329 SetSecurityDescriptorDacl(lpSecurityDescriptor, TRUE, pACL, TRUE);
2330 return TRUE;
2333 /******************************************************************************
2334 * SetServiceObjectSecurity [ADVAPI32.@]
2336 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2337 SECURITY_INFORMATION dwSecurityInformation,
2338 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2340 FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2341 return TRUE;
2344 /******************************************************************************
2345 * SetServiceBits [ADVAPI32.@]
2347 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2348 DWORD dwServiceBits,
2349 BOOL bSetBitsOn,
2350 BOOL bUpdateImmediately)
2352 FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2353 bSetBitsOn, bUpdateImmediately);
2354 return TRUE;
2357 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR lpServiceName,
2358 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2360 FIXME("%s %p %p\n", debugstr_a(lpServiceName), lpHandlerProc, lpContext);
2361 return 0;
2364 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2365 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2367 service_data *service;
2369 TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2371 EnterCriticalSection( &service_cs );
2372 for(service = service_list; service; service = service->next)
2373 if(!strcmpW(lpServiceName, service->name))
2374 break;
2375 if (service)
2377 service->handler.handler_ex = lpHandlerProc;
2378 service->context = lpContext;
2379 service->extended = TRUE;
2381 LeaveCriticalSection( &service_cs );
2383 return (SERVICE_STATUS_HANDLE)service;