Proper finalization in StartServiceW.
[wine.git] / dlls / advapi32 / service.c
blob80af1f65497ec0ee0300bbcfdf1943f8f1de732f
1 /*
2 * Win32 advapi functions
4 * Copyright 1995 Sven Verdoolaege
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include <stdarg.h>
22 #include <string.h>
23 #include <time.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winsvc.h"
28 #include "winerror.h"
29 #include "winreg.h"
30 #include "wine/unicode.h"
31 #include "heap.h"
32 #include "wine/debug.h"
33 #include "winternl.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(advapi);
37 static DWORD start_dwNumServiceArgs;
38 static LPWSTR *start_lpServiceArgVectors;
40 static const WCHAR _ServiceStartDataW[] = {'A','D','V','A','P','I','_','S',
41 'e','r','v','i','c','e','S','t',
42 'a','r','t','D','a','t','a',0};
43 static const WCHAR szServiceManagerKey[] = { 'S','y','s','t','e','m','\\',
44 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
45 'S','e','r','v','i','c','e','s','\\',0 };
46 static const WCHAR szSCMLock[] = {'A','D','V','A','P','I','_','S','C','M',
47 'L','O','C','K',0};
49 /******************************************************************************
50 * SC_HANDLEs
53 #define MAX_SERVICE_NAME 256
55 typedef enum { SC_HTYPE_MANAGER, SC_HTYPE_SERVICE } SC_HANDLE_TYPE;
57 struct sc_handle;
59 struct sc_manager /* SCM handle */
61 HKEY hkey_scm_db; /* handle to services database in the registry */
62 LONG ref_count; /* handle must remain alive until any related service */
63 /* handle exists because DeleteService requires it */
66 struct sc_service /* service handle */
68 HKEY hkey; /* handle to service entry in the registry (under hkey_scm_db) */
69 struct sc_handle *sc_manager; /* pointer to SCM handle */
70 WCHAR name[ MAX_SERVICE_NAME ];
73 struct sc_handle
75 SC_HANDLE_TYPE htype;
76 union
78 struct sc_manager manager;
79 struct sc_service service;
80 } u;
83 static struct sc_handle* alloc_sc_handle( SC_HANDLE_TYPE htype )
85 struct sc_handle *retval;
87 retval = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct sc_handle) );
88 if( retval != NULL )
90 retval->htype = htype;
92 TRACE("SC_HANDLE type=%d -> %p\n",htype,retval);
93 return retval;
96 static void free_sc_handle( struct sc_handle* handle )
98 if( NULL == handle )
99 return;
101 switch( handle->htype )
103 case SC_HTYPE_MANAGER:
105 if( InterlockedDecrement( &handle->u.manager.ref_count ) )
106 /* there are references to this handle */
107 return;
109 if( handle->u.manager.hkey_scm_db )
110 RegCloseKey( handle->u.manager.hkey_scm_db );
111 break;
114 case SC_HTYPE_SERVICE:
116 struct sc_handle *h = handle->u.service.sc_manager;
118 if( h )
120 /* release SCM handle */
121 if( 0 == InterlockedDecrement( &h->u.manager.ref_count ) )
123 /* it's time to destroy SCM handle */
124 if( h->u.manager.hkey_scm_db )
125 RegCloseKey( h->u.manager.hkey_scm_db );
127 TRACE("SC_HANDLE (SCM) %p type=%d\n",h,h->htype);
129 HeapFree( GetProcessHeap(), 0, h );
132 if( handle->u.service.hkey )
133 RegCloseKey( handle->u.service.hkey );
134 break;
138 TRACE("SC_HANDLE %p type=%d\n",handle,handle->htype);
140 HeapFree( GetProcessHeap(), 0, handle );
143 static void init_service_handle( struct sc_handle* handle,
144 struct sc_handle* sc_manager,
145 HKEY hKey, LPCWSTR lpServiceName )
147 /* init sc_service structure */
148 handle->u.service.hkey = hKey;
149 lstrcpynW( handle->u.service.name, lpServiceName, MAX_SERVICE_NAME );
151 /* add reference to SCM handle */
152 InterlockedIncrement( &sc_manager->u.manager.ref_count );
153 handle->u.service.sc_manager = sc_manager;
156 /******************************************************************************
157 * EnumServicesStatusA [ADVAPI32.@]
159 BOOL WINAPI
160 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
161 DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
162 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
163 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
164 { FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
165 dwServiceType, dwServiceState, lpServices, cbBufSize,
166 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
167 SetLastError (ERROR_ACCESS_DENIED);
168 return FALSE;
171 /******************************************************************************
172 * EnumServicesStatusW [ADVAPI32.@]
174 BOOL WINAPI
175 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
176 DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
177 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
178 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
179 { FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
180 dwServiceType, dwServiceState, lpServices, cbBufSize,
181 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
182 SetLastError (ERROR_ACCESS_DENIED);
183 return FALSE;
186 /******************************************************************************
187 * StartServiceCtrlDispatcherA [ADVAPI32.@]
189 BOOL WINAPI
190 StartServiceCtrlDispatcherA( LPSERVICE_TABLE_ENTRYA servent )
192 LPSERVICE_MAIN_FUNCTIONA fpMain;
193 HANDLE wait;
194 DWORD dwNumServiceArgs ;
195 LPWSTR *lpArgVecW;
196 LPSTR *lpArgVecA;
197 unsigned int i;
199 TRACE("(%p)\n", servent);
200 wait = CreateSemaphoreW(NULL,1,1,_ServiceStartDataW);
201 if (!wait)
203 ERR("Couldn't create data semaphore\n");
204 return FALSE;
207 dwNumServiceArgs = start_dwNumServiceArgs;
208 lpArgVecW = start_lpServiceArgVectors;
210 ReleaseSemaphore(wait, 1, NULL);
212 /* Convert the Unicode arg vectors back to ASCII */
213 if(dwNumServiceArgs)
214 lpArgVecA = (LPSTR*) HeapAlloc( GetProcessHeap(), 0,
215 dwNumServiceArgs*sizeof(LPSTR) );
216 else
217 lpArgVecA = NULL;
219 for(i=0; i<dwNumServiceArgs; i++)
220 lpArgVecA[i]=HEAP_strdupWtoA(GetProcessHeap(), 0, lpArgVecW[i]);
222 /* FIXME: should we blindly start all services? */
223 while (servent->lpServiceName) {
224 TRACE("%s at %p)\n", debugstr_a(servent->lpServiceName),servent);
225 fpMain = servent->lpServiceProc;
227 /* try to start the service */
228 fpMain( dwNumServiceArgs, lpArgVecA);
230 servent++;
233 if(dwNumServiceArgs)
235 /* free arg strings */
236 for(i=0; i<dwNumServiceArgs; i++)
237 HeapFree(GetProcessHeap(), 0, lpArgVecA[i]);
238 HeapFree(GetProcessHeap(), 0, lpArgVecA);
241 return TRUE;
244 /******************************************************************************
245 * StartServiceCtrlDispatcherW [ADVAPI32.@]
247 * PARAMS
248 * servent []
250 BOOL WINAPI
251 StartServiceCtrlDispatcherW( LPSERVICE_TABLE_ENTRYW servent )
253 LPSERVICE_MAIN_FUNCTIONW fpMain;
254 HANDLE wait;
255 DWORD dwNumServiceArgs ;
256 LPWSTR *lpServiceArgVectors ;
258 TRACE("(%p)\n", servent);
259 wait = OpenSemaphoreW(SEMAPHORE_ALL_ACCESS, FALSE, _ServiceStartDataW);
260 if(wait == 0)
262 ERR("Couldn't find wait semaphore\n");
263 ERR("perhaps you need to start services using StartService\n");
264 return FALSE;
267 dwNumServiceArgs = start_dwNumServiceArgs;
268 lpServiceArgVectors = start_lpServiceArgVectors;
270 ReleaseSemaphore(wait, 1, NULL);
272 /* FIXME: should we blindly start all services? */
273 while (servent->lpServiceName) {
274 TRACE("%s at %p)\n", debugstr_w(servent->lpServiceName),servent);
275 fpMain = servent->lpServiceProc;
277 /* try to start the service */
278 fpMain( dwNumServiceArgs, lpServiceArgVectors);
280 servent++;
283 return TRUE;
286 /******************************************************************************
287 * LockServiceDatabase [ADVAPI32.@]
289 LPVOID WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
291 HANDLE ret;
293 TRACE("%p\n",hSCManager);
295 ret = CreateFileMappingW( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
296 0, MAX_SERVICE_NAME * sizeof(WCHAR), szSCMLock );
297 if( ret && GetLastError() == ERROR_ALREADY_EXISTS )
299 CloseHandle( ret );
300 ret = NULL;
301 SetLastError( ERROR_SERVICE_DATABASE_LOCKED );
304 TRACE("returning %p\n", ret);
306 return ret;
309 /******************************************************************************
310 * UnlockServiceDatabase [ADVAPI32.@]
312 BOOL WINAPI UnlockServiceDatabase (LPVOID ScLock)
314 TRACE("%p\n",ScLock);
316 return CloseHandle( (HANDLE) ScLock );
319 /******************************************************************************
320 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
322 SERVICE_STATUS_HANDLE WINAPI
323 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName,
324 LPHANDLER_FUNCTION lpfHandler )
325 { FIXME("%s %p\n", lpServiceName, lpfHandler);
326 return 0xcacacafe;
329 /******************************************************************************
330 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
332 * PARAMS
333 * lpServiceName []
334 * lpfHandler []
336 SERVICE_STATUS_HANDLE WINAPI
337 RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName,
338 LPHANDLER_FUNCTION lpfHandler )
339 { FIXME("%s %p\n", debugstr_w(lpServiceName), lpfHandler);
340 return 0xcacacafe;
343 /******************************************************************************
344 * SetServiceStatus [ADVAPI32.@]
346 * PARAMS
347 * hService []
348 * lpStatus []
350 BOOL WINAPI
351 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
352 { FIXME("0x%lx %p\n",hService, lpStatus);
353 TRACE("\tType:%lx\n",lpStatus->dwServiceType);
354 TRACE("\tState:%lx\n",lpStatus->dwCurrentState);
355 TRACE("\tControlAccepted:%lx\n",lpStatus->dwControlsAccepted);
356 TRACE("\tExitCode:%lx\n",lpStatus->dwWin32ExitCode);
357 TRACE("\tServiceExitCode:%lx\n",lpStatus->dwServiceSpecificExitCode);
358 TRACE("\tCheckPoint:%lx\n",lpStatus->dwCheckPoint);
359 TRACE("\tWaitHint:%lx\n",lpStatus->dwWaitHint);
360 return TRUE;
363 /******************************************************************************
364 * OpenSCManagerA [ADVAPI32.@]
366 * Establish a connection to the service control manager and open its database.
368 * PARAMS
369 * lpMachineName [I] Pointer to machine name string
370 * lpDatabaseName [I] Pointer to database name string
371 * dwDesiredAccess [I] Type of access
373 * RETURNS
374 * Success: A Handle to the service control manager database
375 * Failure: NULL
377 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
378 DWORD dwDesiredAccess )
380 UNICODE_STRING lpMachineNameW;
381 UNICODE_STRING lpDatabaseNameW;
382 SC_HANDLE ret;
384 RtlCreateUnicodeStringFromAsciiz (&lpMachineNameW,lpMachineName);
385 RtlCreateUnicodeStringFromAsciiz (&lpDatabaseNameW,lpDatabaseName);
386 ret = OpenSCManagerW(lpMachineNameW.Buffer,lpDatabaseNameW.Buffer, dwDesiredAccess);
387 RtlFreeUnicodeString(&lpDatabaseNameW);
388 RtlFreeUnicodeString(&lpMachineNameW);
389 return ret;
392 /******************************************************************************
393 * OpenSCManagerW [ADVAPI32.@]
395 * See OpenSCManagerA.
397 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
398 DWORD dwDesiredAccess )
400 struct sc_handle *retval;
401 HKEY hReg;
402 LONG r;
404 TRACE("(%s,%s,0x%08lx)\n", debugstr_w(lpMachineName),
405 debugstr_w(lpDatabaseName), dwDesiredAccess);
408 * FIXME: what is lpDatabaseName?
409 * It should be set to "SERVICES_ACTIVE_DATABASE" according to
410 * docs, but what if it isn't?
413 retval = alloc_sc_handle( SC_HTYPE_MANAGER );
414 if( NULL == retval ) return NULL;
416 retval->u.manager.ref_count = 1;
418 r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
419 if (r!=ERROR_SUCCESS)
420 goto error;
422 r = RegOpenKeyExW(hReg, szServiceManagerKey,
423 0, KEY_ALL_ACCESS, &retval->u.manager.hkey_scm_db);
424 RegCloseKey( hReg );
425 if (r!=ERROR_SUCCESS)
426 goto error;
428 TRACE("returning %p\n", retval);
430 return (SC_HANDLE) retval;
432 error:
433 free_sc_handle( retval );
434 return NULL;
438 /******************************************************************************
439 * AllocateLocallyUniqueId [ADVAPI32.@]
441 * PARAMS
442 * lpluid []
444 BOOL WINAPI
445 AllocateLocallyUniqueId( PLUID lpluid )
447 lpluid->LowPart = time(NULL);
448 lpluid->HighPart = 0;
449 return TRUE;
453 /******************************************************************************
454 * ControlService [ADVAPI32.@]
456 * Send a control code to a service.
458 * PARAMS
459 * hService [I] Handle of the service control manager database
460 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
461 * lpServiceStatus [O] Destination for the status of the service, if available
463 * RETURNS
464 * Success: TRUE.
465 * Failure: FALSE.
467 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
468 LPSERVICE_STATUS lpServiceStatus )
470 FIXME("(%p,%ld,%p): stub\n",hService,dwControl,lpServiceStatus);
471 return TRUE;
475 /******************************************************************************
476 * CloseServiceHandle [ADVAPI32.@]
478 * Close a handle to a service or the service control manager database.
480 * PARAMS
481 * hSCObject [I] Handle to service or service control manager database
483 * RETURNS
484 * Success: TRUE
485 * Failure: FALSE
487 BOOL WINAPI
488 CloseServiceHandle( SC_HANDLE hSCObject )
490 TRACE("(%p)\n", hSCObject);
492 free_sc_handle( (struct sc_handle*) hSCObject );
494 return TRUE;
498 /******************************************************************************
499 * OpenServiceA [ADVAPI32.@]
501 * Open a handle to a service.
503 * PARAMS
504 * hSCManager [I] Handle of the service control manager database
505 * lpServiceName [I] Name of the service to open
506 * dwDesiredAccess [I] Access required to the service
508 * RETURNS
509 * Success: Handle to the service
510 * Failure: NULL
512 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
513 DWORD dwDesiredAccess )
515 UNICODE_STRING lpServiceNameW;
516 SC_HANDLE ret;
517 RtlCreateUnicodeStringFromAsciiz (&lpServiceNameW,lpServiceName);
518 if(lpServiceName)
519 TRACE("Request for service %s\n",lpServiceName);
520 else
521 return FALSE;
522 ret = OpenServiceW( hSCManager, lpServiceNameW.Buffer, dwDesiredAccess);
523 RtlFreeUnicodeString(&lpServiceNameW);
524 return ret;
528 /******************************************************************************
529 * OpenServiceW [ADVAPI32.@]
531 * See OpenServiceA.
533 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
534 DWORD dwDesiredAccess)
536 struct sc_handle *hscm = hSCManager;
537 struct sc_handle *retval;
538 HKEY hKey;
539 long r;
541 TRACE("(%p,%p,%ld)\n",hSCManager, lpServiceName,
542 dwDesiredAccess);
544 retval = alloc_sc_handle( SC_HTYPE_SERVICE );
545 if( NULL == retval )
546 return NULL;
548 r = RegOpenKeyExW( hscm->u.manager.hkey_scm_db,
549 lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
550 if (r!=ERROR_SUCCESS)
552 free_sc_handle( retval );
553 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
554 return NULL;
557 init_service_handle( retval, hscm, hKey, lpServiceName );
559 TRACE("returning %p\n",retval);
561 return (SC_HANDLE) retval;
564 /******************************************************************************
565 * CreateServiceW [ADVAPI32.@]
567 SC_HANDLE WINAPI
568 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
569 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
570 DWORD dwServiceType, DWORD dwStartType,
571 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
572 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
573 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
574 LPCWSTR lpPassword )
576 struct sc_handle *hscm = hSCManager;
577 struct sc_handle *retval;
578 HKEY hKey;
579 LONG r;
580 DWORD dp;
581 static const WCHAR szDisplayName[] = { 'D','i','s','p','l','a','y','N','a','m','e', 0 };
582 static const WCHAR szType[] = {'T','y','p','e',0};
583 static const WCHAR szStart[] = {'S','t','a','r','t',0};
584 static const WCHAR szError[] = {'E','r','r','o','r','C','o','n','t','r','o','l', 0};
585 static const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
586 static const WCHAR szGroup[] = {'G','r','o','u','p',0};
587 static const WCHAR szDependencies[] = { 'D','e','p','e','n','d','e','n','c','i','e','s',0};
589 FIXME("%p %s %s\n", hSCManager,
590 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
592 retval = alloc_sc_handle( SC_HTYPE_SERVICE );
593 if( NULL == retval )
594 return NULL;
596 r = RegCreateKeyExW(hscm->u.manager.hkey_scm_db, lpServiceName, 0, NULL,
597 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
598 if (r!=ERROR_SUCCESS)
599 goto error;
601 init_service_handle( retval, hscm, hKey, lpServiceName );
603 if (dp != REG_CREATED_NEW_KEY)
604 goto error;
606 if(lpDisplayName)
608 r = RegSetValueExW(hKey, szDisplayName, 0, REG_SZ, (LPBYTE)lpDisplayName,
609 (strlenW(lpDisplayName)+1)*sizeof(WCHAR) );
610 if (r!=ERROR_SUCCESS)
611 goto error;
614 r = RegSetValueExW(hKey, szType, 0, REG_DWORD, (LPVOID)&dwServiceType, sizeof (DWORD) );
615 if (r!=ERROR_SUCCESS)
616 goto error;
618 r = RegSetValueExW(hKey, szStart, 0, REG_DWORD, (LPVOID)&dwStartType, sizeof (DWORD) );
619 if (r!=ERROR_SUCCESS)
620 goto error;
622 r = RegSetValueExW(hKey, szError, 0, REG_DWORD,
623 (LPVOID)&dwErrorControl, sizeof (DWORD) );
624 if (r!=ERROR_SUCCESS)
625 goto error;
627 if(lpBinaryPathName)
629 r = RegSetValueExW(hKey, szImagePath, 0, REG_SZ, (LPBYTE)lpBinaryPathName,
630 (strlenW(lpBinaryPathName)+1)*sizeof(WCHAR) );
631 if (r!=ERROR_SUCCESS)
632 goto error;
635 if(lpLoadOrderGroup)
637 r = RegSetValueExW(hKey, szGroup, 0, REG_SZ, (LPBYTE)lpLoadOrderGroup,
638 (strlenW(lpLoadOrderGroup)+1)*sizeof(WCHAR) );
639 if (r!=ERROR_SUCCESS)
640 goto error;
643 if(lpDependencies)
645 DWORD len = 0;
647 /* determine the length of a double null terminated multi string */
648 do {
649 len += (strlenW(&lpDependencies[len])+1);
650 } while (lpDependencies[len++]);
652 r = RegSetValueExW(hKey, szDependencies, 0, REG_MULTI_SZ,
653 (LPBYTE)lpDependencies, len );
654 if (r!=ERROR_SUCCESS)
655 goto error;
658 if(lpPassword)
660 FIXME("Don't know how to add a Password for a service.\n");
663 if(lpServiceStartName)
665 FIXME("Don't know how to add a ServiceStartName for a service.\n");
668 return (SC_HANDLE) retval;
670 error:
671 free_sc_handle( retval );
672 return NULL;
676 static inline LPWSTR SERV_dup( LPCSTR str )
678 UINT len;
679 LPWSTR wstr;
681 if( !str )
682 return NULL;
683 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
684 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
685 MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
686 return wstr;
689 static inline LPWSTR SERV_dupmulti( LPCSTR str )
691 UINT len = 0, n = 0;
692 LPWSTR wstr;
694 if( !str )
695 return NULL;
696 do {
697 len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
698 n += (strlen( &str[n] ) + 1);
699 } while (str[n]);
700 len++;
701 n++;
703 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
704 MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
705 return wstr;
708 static inline VOID SERV_free( LPWSTR wstr )
710 HeapFree( GetProcessHeap(), 0, wstr );
713 /******************************************************************************
714 * CreateServiceA [ADVAPI32.@]
716 SC_HANDLE WINAPI
717 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
718 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
719 DWORD dwServiceType, DWORD dwStartType,
720 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
721 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
722 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
723 LPCSTR lpPassword )
725 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
726 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
727 SC_HANDLE r;
729 TRACE("%p %s %s\n", hSCManager,
730 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
732 lpServiceNameW = SERV_dup( lpServiceName );
733 lpDisplayNameW = SERV_dup( lpDisplayName );
734 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
735 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
736 lpDependenciesW = SERV_dupmulti( lpDependencies );
737 lpServiceStartNameW = SERV_dup( lpServiceStartName );
738 lpPasswordW = SERV_dup( lpPassword );
740 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
741 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
742 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
743 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
745 SERV_free( lpServiceNameW );
746 SERV_free( lpDisplayNameW );
747 SERV_free( lpBinaryPathNameW );
748 SERV_free( lpLoadOrderGroupW );
749 SERV_free( lpDependenciesW );
750 SERV_free( lpServiceStartNameW );
751 SERV_free( lpPasswordW );
753 return r;
757 /******************************************************************************
758 * DeleteService [ADVAPI32.@]
760 * Delete a service from the service control manager database.
762 * PARAMS
763 * hService [I] Handle of the service to delete
765 * RETURNS
766 * Success: TRUE
767 * Failure: FALSE
769 BOOL WINAPI DeleteService( SC_HANDLE hService )
771 struct sc_handle *hsvc = hService;
772 HKEY hKey = hsvc->u.service.hkey;
773 WCHAR valname[MAX_PATH+1];
774 INT index = 0;
775 LONG rc;
776 DWORD size;
778 size = MAX_PATH+1;
779 /* Clean out the values */
780 rc = RegEnumValueW(hKey, index, valname,&size,0,0,0,0);
781 while (rc == ERROR_SUCCESS)
783 RegDeleteValueW(hKey,valname);
784 index++;
785 size = MAX_PATH+1;
786 rc = RegEnumValueW(hKey, index, valname, &size,0,0,0,0);
789 RegCloseKey(hKey);
790 hsvc->u.service.hkey = NULL;
792 /* delete the key */
793 RegDeleteKeyW(hsvc->u.service.sc_manager->u.manager.hkey_scm_db,
794 hsvc->u.service.name);
796 return TRUE;
800 /******************************************************************************
801 * StartServiceA [ADVAPI32.@]
803 * Start a service
805 * PARAMS
806 * hService [I] Handle of service
807 * dwNumServiceArgs [I] Number of arguments
808 * lpServiceArgVectors [I] Address of array of argument strings
810 * NOTES
811 * - NT implements this function using an obscure RPC call.
812 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
813 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
814 * - This will only work for shared address space. How should the service
815 * args be transferred when address spaces are separated?
816 * - Can only start one service at a time.
817 * - Has no concept of privilege.
819 * RETURNS
820 * Success: TRUE.
821 * Failure: FALSE
823 BOOL WINAPI
824 StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
825 LPCSTR *lpServiceArgVectors )
827 LPWSTR *lpwstr=NULL;
828 UNICODE_STRING usBuffer;
829 unsigned int i;
831 TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
833 if(dwNumServiceArgs)
834 lpwstr = (LPWSTR*) HeapAlloc( GetProcessHeap(), 0,
835 dwNumServiceArgs*sizeof(LPWSTR) );
836 else
837 lpwstr = NULL;
839 for(i=0; i<dwNumServiceArgs; i++)
841 RtlCreateUnicodeStringFromAsciiz (&usBuffer,lpServiceArgVectors[i]);
842 lpwstr[i]=usBuffer.Buffer;
845 StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
847 if(dwNumServiceArgs)
849 for(i=0; i<dwNumServiceArgs; i++)
850 HeapFree(GetProcessHeap(), 0, lpwstr[i]);
851 HeapFree(GetProcessHeap(), 0, lpwstr);
854 return TRUE;
858 /******************************************************************************
859 * StartServiceW [ADVAPI32.@]
861 * See StartServiceA.
863 BOOL WINAPI
864 StartServiceW( SC_HANDLE hService, DWORD dwNumServiceArgs,
865 LPCWSTR *lpServiceArgVectors )
867 static const WCHAR _WaitServiceStartW[] = {'A','D','V','A','P','I','_','W',
868 'a','i','t','S','e','r','v','i',
869 'c','e','S','t','a','r','t',0};
870 static const WCHAR _ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0};
872 struct sc_handle *hsvc = hService;
873 WCHAR path[MAX_PATH],str[MAX_PATH];
874 DWORD type,size;
875 long r;
876 HANDLE data,wait;
877 PROCESS_INFORMATION procinfo;
878 STARTUPINFOW startupinfo;
879 BOOL ret = FALSE;
881 TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,
882 lpServiceArgVectors);
884 size = sizeof(str);
885 r = RegQueryValueExW(hsvc->u.service.hkey, _ImagePathW, NULL, &type, (LPVOID)str, &size);
886 if (r!=ERROR_SUCCESS)
887 return FALSE;
888 ExpandEnvironmentStringsW(str,path,sizeof(path));
890 TRACE("Starting service %s\n", debugstr_w(path) );
892 data = CreateSemaphoreW(NULL,1,1,_ServiceStartDataW);
893 if (!data)
895 ERR("Couldn't create data semaphore\n");
896 return FALSE;
898 wait = CreateSemaphoreW(NULL,0,1,_WaitServiceStartW);
899 if (!wait)
901 ERR("Couldn't create wait semaphore\n");
902 return FALSE;
906 * FIXME: lpServiceArgsVectors need to be stored and returned to
907 * the service when it calls StartServiceCtrlDispatcher
909 * Chuck these in a global (yuk) so we can pass them to
910 * another process - address space separation will break this.
913 r = WaitForSingleObject(data,INFINITE);
915 if( r == WAIT_FAILED)
916 return FALSE;
918 FIXME("problematic because of address space separation.\n");
919 start_dwNumServiceArgs = dwNumServiceArgs;
920 start_lpServiceArgVectors = (LPWSTR *)lpServiceArgVectors;
922 ZeroMemory(&startupinfo,sizeof(STARTUPINFOW));
923 startupinfo.cb = sizeof(STARTUPINFOW);
925 r = CreateProcessW(NULL,
926 path,
927 NULL, /* process security attribs */
928 NULL, /* thread security attribs */
929 FALSE, /* inherit handles */
930 0, /* creation flags */
931 NULL, /* environment */
932 NULL, /* current directory */
933 &startupinfo, /* startup info */
934 &procinfo); /* process info */
936 if(r == FALSE)
938 ERR("Couldn't start process\n");
939 goto done;
941 CloseHandle( procinfo.hThread );
943 /* docs for StartServiceCtrlDispatcher say this should be 30 sec */
944 r = WaitForSingleObject(wait,30000);
945 if( WAIT_FAILED == r )
947 CloseHandle( procinfo.hProcess );
948 goto done;
951 /* allright */
952 CloseHandle( procinfo.hProcess );
953 ret = TRUE;
955 done:
956 CloseHandle( wait );
957 ReleaseSemaphore(data, 1, NULL);
958 CloseHandle( data );
959 return ret;
962 /******************************************************************************
963 * QueryServiceStatus [ADVAPI32.@]
965 * PARAMS
966 * hService []
967 * lpservicestatus []
970 BOOL WINAPI
971 QueryServiceStatus( SC_HANDLE hService, LPSERVICE_STATUS lpservicestatus )
973 struct sc_handle *hsvc = hService;
974 LONG r;
975 DWORD type, val, size;
977 FIXME("(%p,%p) partial\n",hService,lpservicestatus);
979 /* read the service type from the registry */
980 size = sizeof(val);
981 r = RegQueryValueExA(hsvc->u.service.hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
982 if(type!=REG_DWORD)
984 ERR("invalid Type\n");
985 return FALSE;
987 lpservicestatus->dwServiceType = val;
988 /* FIXME: how are these determined or read from the registry? */
989 /* SERVICE: unavailable=0, stopped=1, starting=2, running=3? */;
990 lpservicestatus->dwCurrentState = 1;
991 lpservicestatus->dwControlsAccepted = 0;
992 lpservicestatus->dwWin32ExitCode = NO_ERROR;
993 lpservicestatus->dwServiceSpecificExitCode = 0;
994 lpservicestatus->dwCheckPoint = 0;
995 lpservicestatus->dwWaitHint = 0;
997 return TRUE;
1000 /******************************************************************************
1001 * QueryServiceStatusEx [ADVAPI32.@]
1003 * Get information about a service.
1005 * PARAMS
1006 * hService [I] Handle to service to get information about
1007 * InfoLevel [I] Level of information to get
1008 * lpBuffer [O] Destination for requested information
1009 * cbBufSize [I] Size of lpBuffer in bytes
1010 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1012 * RETURNS
1013 * Success: TRUE
1014 * FAILURE: FALSE
1016 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1017 LPBYTE lpBuffer, DWORD cbBufSize,
1018 LPDWORD pcbBytesNeeded)
1020 FIXME("stub\n");
1021 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1022 return FALSE;
1025 /******************************************************************************
1026 * QueryServiceConfigA [ADVAPI32.@]
1028 BOOL WINAPI
1029 QueryServiceConfigA( SC_HANDLE hService,
1030 LPQUERY_SERVICE_CONFIGA lpServiceConfig,
1031 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1033 static const CHAR szDisplayName[] = "DisplayName";
1034 static const CHAR szType[] = "Type";
1035 static const CHAR szStart[] = "Start";
1036 static const CHAR szError[] = "ErrorControl";
1037 static const CHAR szImagePath[] = "ImagePath";
1038 static const CHAR szGroup[] = "Group";
1039 static const CHAR szDependencies[] = "Dependencies";
1040 HKEY hKey = ((struct sc_handle*) hService)->u.service.hkey;
1041 CHAR str_buffer[ MAX_PATH ];
1042 LONG r;
1043 DWORD type, val, sz, total, n;
1044 LPBYTE p;
1046 TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
1047 cbBufSize, pcbBytesNeeded);
1049 /* calculate the size required first */
1050 total = sizeof (QUERY_SERVICE_CONFIGA);
1052 sz = sizeof(str_buffer);
1053 r = RegQueryValueExA( hKey, szImagePath, 0, &type, str_buffer, &sz );
1054 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1056 sz = ExpandEnvironmentStringsA(str_buffer,NULL,0);
1057 if( 0 == sz ) return FALSE;
1059 total += sz;
1061 else
1063 /* FIXME: set last error */
1064 return FALSE;
1067 sz = 0;
1068 r = RegQueryValueExA( hKey, szGroup, 0, &type, NULL, &sz );
1069 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1070 total += sz;
1072 sz = 0;
1073 r = RegQueryValueExA( hKey, szDependencies, 0, &type, NULL, &sz );
1074 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1075 total += sz;
1077 sz = 0;
1078 r = RegQueryValueExA( hKey, szStart, 0, &type, NULL, &sz );
1079 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1080 total += sz;
1082 sz = 0;
1083 r = RegQueryValueExA( hKey, szDisplayName, 0, &type, NULL, &sz );
1084 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1085 total += sz;
1087 /* if there's not enough memory, return an error */
1088 if( total > *pcbBytesNeeded )
1090 *pcbBytesNeeded = total;
1091 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1092 return FALSE;
1095 *pcbBytesNeeded = total;
1096 ZeroMemory( lpServiceConfig, total );
1098 sz = sizeof val;
1099 r = RegQueryValueExA( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1100 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1101 lpServiceConfig->dwServiceType = val;
1103 sz = sizeof val;
1104 r = RegQueryValueExA( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1105 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1106 lpServiceConfig->dwStartType = val;
1108 sz = sizeof val;
1109 r = RegQueryValueExA( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1110 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1111 lpServiceConfig->dwErrorControl = val;
1113 /* now do the strings */
1114 p = (LPBYTE) &lpServiceConfig[1];
1115 n = total - sizeof (QUERY_SERVICE_CONFIGA);
1117 sz = sizeof(str_buffer);
1118 r = RegQueryValueExA( hKey, szImagePath, 0, &type, str_buffer, &sz );
1119 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1121 sz = ExpandEnvironmentStringsA(str_buffer, p, n);
1122 if( 0 == sz || sz > n ) return FALSE;
1124 lpServiceConfig->lpBinaryPathName = (LPSTR) p;
1125 p += sz;
1126 n -= sz;
1128 else
1130 /* FIXME: set last error */
1131 return FALSE;
1134 sz = n;
1135 r = RegQueryValueExA( hKey, szGroup, 0, &type, p, &sz );
1136 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1138 lpServiceConfig->lpLoadOrderGroup = (LPSTR) p;
1139 p += sz;
1140 n -= sz;
1143 sz = n;
1144 r = RegQueryValueExA( hKey, szDependencies, 0, &type, p, &sz );
1145 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1147 lpServiceConfig->lpDependencies = (LPSTR) p;
1148 p += sz;
1149 n -= sz;
1152 if( n < 0 )
1153 ERR("Buffer overflow!\n");
1155 TRACE("Image path = %s\n", lpServiceConfig->lpBinaryPathName );
1156 TRACE("Group = %s\n", lpServiceConfig->lpLoadOrderGroup );
1158 return TRUE;
1161 /******************************************************************************
1162 * QueryServiceConfigW [ADVAPI32.@]
1164 BOOL WINAPI
1165 QueryServiceConfigW( SC_HANDLE hService,
1166 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1167 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1169 static const WCHAR szDisplayName[] = {
1170 'D','i','s','p','l','a','y','N','a','m','e', 0 };
1171 static const WCHAR szType[] = {'T','y','p','e',0};
1172 static const WCHAR szStart[] = {'S','t','a','r','t',0};
1173 static const WCHAR szError[] = {
1174 'E','r','r','o','r','C','o','n','t','r','o','l', 0};
1175 static const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
1176 static const WCHAR szGroup[] = {'G','r','o','u','p',0};
1177 static const WCHAR szDependencies[] = {
1178 'D','e','p','e','n','d','e','n','c','i','e','s',0};
1179 HKEY hKey = ((struct sc_handle*) hService)->u.service.hkey;
1180 WCHAR str_buffer[ MAX_PATH ];
1181 LONG r;
1182 DWORD type, val, sz, total, n;
1183 LPBYTE p;
1185 TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
1186 cbBufSize, pcbBytesNeeded);
1188 /* calculate the size required first */
1189 total = sizeof (QUERY_SERVICE_CONFIGW);
1191 sz = sizeof(str_buffer);
1192 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1193 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1195 sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1196 if( 0 == sz ) return FALSE;
1198 total += sizeof(WCHAR) * sz;
1200 else
1202 /* FIXME: set last error */
1203 return FALSE;
1206 sz = 0;
1207 r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1208 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1209 total += sz;
1211 sz = 0;
1212 r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1213 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1214 total += sz;
1216 sz = 0;
1217 r = RegQueryValueExW( hKey, szStart, 0, &type, NULL, &sz );
1218 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1219 total += sz;
1221 sz = 0;
1222 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1223 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1224 total += sz;
1226 /* if there's not enough memory, return an error */
1227 if( total > *pcbBytesNeeded )
1229 *pcbBytesNeeded = total;
1230 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1231 return FALSE;
1234 *pcbBytesNeeded = total;
1235 ZeroMemory( lpServiceConfig, total );
1237 sz = sizeof val;
1238 r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1239 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1240 lpServiceConfig->dwServiceType = val;
1242 sz = sizeof val;
1243 r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1244 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1245 lpServiceConfig->dwStartType = val;
1247 sz = sizeof val;
1248 r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1249 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1250 lpServiceConfig->dwErrorControl = val;
1252 /* now do the strings */
1253 p = (LPBYTE) &lpServiceConfig[1];
1254 n = total - sizeof (QUERY_SERVICE_CONFIGW);
1256 sz = sizeof(str_buffer);
1257 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1258 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1260 sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
1261 sz *= sizeof(WCHAR);
1262 if( 0 == sz || sz > n ) return FALSE;
1264 lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
1265 p += sz;
1266 n -= sz;
1268 else
1270 /* FIXME: set last error */
1271 return FALSE;
1274 sz = n;
1275 r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
1276 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1278 lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
1279 p += sz;
1280 n -= sz;
1283 sz = n;
1284 r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
1285 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1287 lpServiceConfig->lpDependencies = (LPWSTR) p;
1288 p += sz;
1289 n -= sz;
1292 if( n < 0 )
1293 ERR("Buffer overflow!\n");
1295 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1296 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1298 return TRUE;
1301 /******************************************************************************
1302 * ChangeServiceConfigW [ADVAPI32.@]
1304 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
1305 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1306 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
1307 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
1309 FIXME("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
1310 hService, dwServiceType, dwStartType, dwErrorControl,
1311 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
1312 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
1313 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
1314 return TRUE;
1317 /******************************************************************************
1318 * ChangeServiceConfigA [ADVAPI32.@]
1320 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
1321 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1322 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
1323 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
1325 FIXME("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
1326 hService, dwServiceType, dwStartType, dwErrorControl,
1327 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
1328 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
1329 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
1330 return TRUE;
1333 /******************************************************************************
1334 * ChangeServiceConfig2A [ADVAPI32.@]
1336 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
1337 LPVOID lpInfo)
1339 FIXME("STUB: %p %ld %p\n",hService, dwInfoLevel, lpInfo);
1340 return TRUE;
1343 /******************************************************************************
1344 * ChangeServiceConfig2W [ADVAPI32.@]
1346 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
1347 LPVOID lpInfo)
1349 HKEY hKey = ((struct sc_handle*) hService)->u.service.hkey;
1351 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
1353 static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
1354 LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
1355 if (sd->lpDescription)
1357 TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
1358 if (sd->lpDescription[0] == 0)
1359 RegDeleteValueW(hKey,szDescription);
1360 else
1361 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
1362 (LPVOID)sd->lpDescription,
1363 sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
1366 else
1367 FIXME("STUB: %p %ld %p\n",hService, dwInfoLevel, lpInfo);
1368 return TRUE;
1371 /******************************************************************************
1372 * QueryServiceObjectSecurity [ADVAPI32.@]
1374 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
1375 SECURITY_INFORMATION dwSecurityInformation,
1376 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
1377 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1379 FIXME("%p %ld %p %lu %p\n", hService, dwSecurityInformation,
1380 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
1381 return ERROR_CALL_NOT_IMPLEMENTED;