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
30 #include "wine/unicode.h"
32 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(advapi
);
37 static const WCHAR szServiceManagerKey
[] = { 'S','y','s','t','e','m','\\',
38 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
39 'S','e','r','v','i','c','e','s','\\',0 };
40 static const WCHAR szSCMLock
[] = {'A','D','V','A','P','I','_','S','C','M',
42 static const WCHAR szServiceShmemNameFmtW
[] = {'A','D','V','A','P','I','_',
43 'S','E','B','_','%','s',0};
45 struct SEB
/* service environment block */
46 { /* resides in service's shared memory object */
48 /* variable part of SEB contains service arguments */
51 /******************************************************************************
55 #define MAX_SERVICE_NAME 256
57 typedef enum { SC_HTYPE_MANAGER
, SC_HTYPE_SERVICE
} SC_HANDLE_TYPE
;
61 struct sc_manager
/* SCM handle */
63 HKEY hkey_scm_db
; /* handle to services database in the registry */
64 LONG ref_count
; /* handle must remain alive until any related service */
65 /* handle exists because DeleteService requires it */
68 struct sc_service
/* service handle */
70 HKEY hkey
; /* handle to service entry in the registry (under hkey_scm_db) */
71 struct sc_handle
*sc_manager
; /* pointer to SCM handle */
72 WCHAR name
[ MAX_SERVICE_NAME
];
80 struct sc_manager manager
;
81 struct sc_service service
;
85 static struct sc_handle
* alloc_sc_handle( SC_HANDLE_TYPE htype
)
87 struct sc_handle
*retval
;
89 retval
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(struct sc_handle
) );
92 retval
->htype
= htype
;
94 TRACE("SC_HANDLE type=%d -> %p\n",htype
,retval
);
98 static void free_sc_handle( struct sc_handle
* handle
)
103 switch( handle
->htype
)
105 case SC_HTYPE_MANAGER
:
107 if( InterlockedDecrement( &handle
->u
.manager
.ref_count
) )
108 /* there are references to this handle */
111 if( handle
->u
.manager
.hkey_scm_db
)
112 RegCloseKey( handle
->u
.manager
.hkey_scm_db
);
116 case SC_HTYPE_SERVICE
:
118 struct sc_handle
*h
= handle
->u
.service
.sc_manager
;
122 /* release SCM handle */
123 if( 0 == InterlockedDecrement( &h
->u
.manager
.ref_count
) )
125 /* it's time to destroy SCM handle */
126 if( h
->u
.manager
.hkey_scm_db
)
127 RegCloseKey( h
->u
.manager
.hkey_scm_db
);
129 TRACE("SC_HANDLE (SCM) %p type=%d\n",h
,h
->htype
);
131 HeapFree( GetProcessHeap(), 0, h
);
134 if( handle
->u
.service
.hkey
)
135 RegCloseKey( handle
->u
.service
.hkey
);
140 TRACE("SC_HANDLE %p type=%d\n",handle
,handle
->htype
);
142 HeapFree( GetProcessHeap(), 0, handle
);
145 static void init_service_handle( struct sc_handle
* handle
,
146 struct sc_handle
* sc_manager
,
147 HKEY hKey
, LPCWSTR lpServiceName
)
149 /* init sc_service structure */
150 handle
->u
.service
.hkey
= hKey
;
151 lstrcpynW( handle
->u
.service
.name
, lpServiceName
, MAX_SERVICE_NAME
);
153 /* add reference to SCM handle */
154 InterlockedIncrement( &sc_manager
->u
.manager
.ref_count
);
155 handle
->u
.service
.sc_manager
= sc_manager
;
158 /******************************************************************************
159 * EnumServicesStatusA [ADVAPI32.@]
162 EnumServicesStatusA( SC_HANDLE hSCManager
, DWORD dwServiceType
,
163 DWORD dwServiceState
, LPENUM_SERVICE_STATUSA lpServices
,
164 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
165 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
)
166 { FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager
,
167 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
168 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
);
169 SetLastError (ERROR_ACCESS_DENIED
);
173 /******************************************************************************
174 * EnumServicesStatusW [ADVAPI32.@]
177 EnumServicesStatusW( SC_HANDLE hSCManager
, DWORD dwServiceType
,
178 DWORD dwServiceState
, LPENUM_SERVICE_STATUSW lpServices
,
179 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
180 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
)
181 { FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager
,
182 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
183 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
);
184 SetLastError (ERROR_ACCESS_DENIED
);
188 /******************************************************************************
191 * helper function for StartServiceCtrlDispatcherA/W
193 * SCM database is locked by StartService;
194 * open global SCM lock object and read service name
196 static BOOL
read_scm_lock_data( LPWSTR buffer
)
201 hLock
= OpenFileMappingW( FILE_MAP_ALL_ACCESS
, FALSE
, szSCMLock
);
204 SetLastError( ERROR_FAILED_SERVICE_CONTROLLER_CONNECT
);
207 argptr
= MapViewOfFile( hLock
, FILE_MAP_ALL_ACCESS
,
208 0, 0, MAX_SERVICE_NAME
* sizeof(WCHAR
) );
211 CloseHandle( hLock
);
214 strcpyW( buffer
, argptr
);
215 UnmapViewOfFile( argptr
);
216 CloseHandle( hLock
);
220 /******************************************************************************
223 * helper function for StartServiceCtrlDispatcherA/W
225 * Allocate and initialize array of LPWSTRs to arguments in variable part
226 * of service environment block.
227 * First entry in the array is reserved for service name and not initialized.
229 static LPWSTR
* build_arg_vectors( struct SEB
* seb
)
235 ret
= HeapAlloc( GetProcessHeap(), 0, (1 + seb
->argc
) * sizeof(LPWSTR
) );
239 argptr
= (LPWSTR
) &seb
[1];
240 for( i
= 0; i
< seb
->argc
; i
++ )
242 ret
[ 1 + i
] = argptr
;
243 argptr
+= 1 + strlenW( argptr
);
248 /******************************************************************************
249 * StartServiceCtrlDispatcherA [ADVAPI32.@]
252 StartServiceCtrlDispatcherA( LPSERVICE_TABLE_ENTRYA servent
)
254 LPSERVICE_MAIN_FUNCTIONA fpMain
;
255 WCHAR service_name
[ MAX_SERVICE_NAME
];
256 WCHAR object_name
[ MAX_PATH
];
257 HANDLE hServiceShmem
= NULL
;
258 struct SEB
*seb
= NULL
;
259 DWORD dwNumServiceArgs
;
260 LPWSTR
*lpArgVecW
= NULL
;
264 TRACE("(%p)\n", servent
);
266 if( ! read_scm_lock_data( service_name
) )
268 /* FIXME: Instead of exiting we fall through and allow
269 service to be executed as ordinary program.
270 This behaviour was specially introduced in the patch
271 submitted against revision 1.45 and so preserved here.
273 FIXME("should fail with ERROR_FAILED_SERVICE_CONTROLLER_CONNECT\n");
274 dwNumServiceArgs
= 0;
279 snprintfW( object_name
, MAX_PATH
, szServiceShmemNameFmtW
, service_name
);
280 hServiceShmem
= OpenFileMappingW( FILE_MAP_ALL_ACCESS
, FALSE
, object_name
);
281 if( NULL
== hServiceShmem
)
284 seb
= MapViewOfFile( hServiceShmem
, FILE_MAP_ALL_ACCESS
, 0, 0, 0 );
287 CloseHandle( hServiceShmem
);
291 lpArgVecW
= build_arg_vectors( seb
);
292 if( NULL
== lpArgVecW
)
294 UnmapViewOfFile( seb
);
295 CloseHandle( hServiceShmem
);
298 lpArgVecW
[0] = service_name
;
299 dwNumServiceArgs
= seb
->argc
+ 1;
301 /* Convert the Unicode arg vectors back to ASCII */
302 lpArgVecA
= (LPSTR
*) HeapAlloc( GetProcessHeap(), 0,
303 dwNumServiceArgs
*sizeof(LPSTR
) );
304 for(i
=0; i
<dwNumServiceArgs
; i
++)
305 lpArgVecA
[i
]=HEAP_strdupWtoA(GetProcessHeap(), 0, lpArgVecW
[i
]);
308 /* FIXME: should we blindly start all services? */
309 while (servent
->lpServiceName
) {
310 TRACE("%s at %p)\n", debugstr_a(servent
->lpServiceName
),servent
);
311 fpMain
= servent
->lpServiceProc
;
313 /* try to start the service */
314 fpMain( dwNumServiceArgs
, lpArgVecA
);
321 /* free arg strings */
322 for(i
=0; i
<dwNumServiceArgs
; i
++)
323 HeapFree(GetProcessHeap(), 0, lpArgVecA
[i
]);
324 HeapFree(GetProcessHeap(), 0, lpArgVecA
);
327 if( lpArgVecW
) HeapFree( GetProcessHeap(), 0, lpArgVecW
);
328 if( seb
) UnmapViewOfFile( seb
);
329 if( hServiceShmem
) CloseHandle( hServiceShmem
);
333 /******************************************************************************
334 * StartServiceCtrlDispatcherW [ADVAPI32.@]
340 StartServiceCtrlDispatcherW( LPSERVICE_TABLE_ENTRYW servent
)
342 LPSERVICE_MAIN_FUNCTIONW fpMain
;
343 WCHAR service_name
[ MAX_SERVICE_NAME
];
344 WCHAR object_name
[ MAX_PATH
];
345 HANDLE hServiceShmem
;
347 DWORD dwNumServiceArgs
;
348 LPWSTR
*lpServiceArgVectors
;
350 TRACE("(%p)\n", servent
);
352 if( ! read_scm_lock_data( service_name
) )
355 snprintfW( object_name
, MAX_PATH
, szServiceShmemNameFmtW
, service_name
);
356 hServiceShmem
= OpenFileMappingW( FILE_MAP_ALL_ACCESS
, FALSE
, object_name
);
357 if( NULL
== hServiceShmem
)
360 seb
= MapViewOfFile( hServiceShmem
, FILE_MAP_ALL_ACCESS
, 0, 0, 0 );
363 CloseHandle( hServiceShmem
);
367 lpServiceArgVectors
= build_arg_vectors( seb
);
368 if( NULL
== lpServiceArgVectors
)
370 UnmapViewOfFile( seb
);
371 CloseHandle( hServiceShmem
);
374 lpServiceArgVectors
[0] = service_name
;
375 dwNumServiceArgs
= seb
->argc
+ 1;
377 /* FIXME: should we blindly start all services? */
378 while (servent
->lpServiceName
) {
379 TRACE("%s at %p)\n", debugstr_w(servent
->lpServiceName
),servent
);
380 fpMain
= servent
->lpServiceProc
;
382 /* try to start the service */
383 fpMain( dwNumServiceArgs
, lpServiceArgVectors
);
388 HeapFree( GetProcessHeap(), 0, lpServiceArgVectors
);
389 UnmapViewOfFile( seb
);
390 CloseHandle( hServiceShmem
);
394 /******************************************************************************
395 * LockServiceDatabase [ADVAPI32.@]
397 LPVOID WINAPI
LockServiceDatabase (SC_HANDLE hSCManager
)
401 TRACE("%p\n",hSCManager
);
403 ret
= CreateFileMappingW( INVALID_HANDLE_VALUE
, NULL
, PAGE_READWRITE
,
404 0, MAX_SERVICE_NAME
* sizeof(WCHAR
), szSCMLock
);
405 if( ret
&& GetLastError() == ERROR_ALREADY_EXISTS
)
409 SetLastError( ERROR_SERVICE_DATABASE_LOCKED
);
412 TRACE("returning %p\n", ret
);
417 /******************************************************************************
418 * UnlockServiceDatabase [ADVAPI32.@]
420 BOOL WINAPI
UnlockServiceDatabase (LPVOID ScLock
)
422 TRACE("%p\n",ScLock
);
424 return CloseHandle( (HANDLE
) ScLock
);
427 /******************************************************************************
428 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
430 SERVICE_STATUS_HANDLE WINAPI
431 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName
,
432 LPHANDLER_FUNCTION lpfHandler
)
433 { FIXME("%s %p\n", lpServiceName
, lpfHandler
);
437 /******************************************************************************
438 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
444 SERVICE_STATUS_HANDLE WINAPI
445 RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName
,
446 LPHANDLER_FUNCTION lpfHandler
)
447 { FIXME("%s %p\n", debugstr_w(lpServiceName
), lpfHandler
);
451 /******************************************************************************
452 * SetServiceStatus [ADVAPI32.@]
459 SetServiceStatus( SERVICE_STATUS_HANDLE hService
, LPSERVICE_STATUS lpStatus
)
460 { FIXME("0x%lx %p\n",hService
, lpStatus
);
461 TRACE("\tType:%lx\n",lpStatus
->dwServiceType
);
462 TRACE("\tState:%lx\n",lpStatus
->dwCurrentState
);
463 TRACE("\tControlAccepted:%lx\n",lpStatus
->dwControlsAccepted
);
464 TRACE("\tExitCode:%lx\n",lpStatus
->dwWin32ExitCode
);
465 TRACE("\tServiceExitCode:%lx\n",lpStatus
->dwServiceSpecificExitCode
);
466 TRACE("\tCheckPoint:%lx\n",lpStatus
->dwCheckPoint
);
467 TRACE("\tWaitHint:%lx\n",lpStatus
->dwWaitHint
);
471 /******************************************************************************
472 * OpenSCManagerA [ADVAPI32.@]
474 * Establish a connection to the service control manager and open its database.
477 * lpMachineName [I] Pointer to machine name string
478 * lpDatabaseName [I] Pointer to database name string
479 * dwDesiredAccess [I] Type of access
482 * Success: A Handle to the service control manager database
485 SC_HANDLE WINAPI
OpenSCManagerA( LPCSTR lpMachineName
, LPCSTR lpDatabaseName
,
486 DWORD dwDesiredAccess
)
488 UNICODE_STRING lpMachineNameW
;
489 UNICODE_STRING lpDatabaseNameW
;
492 RtlCreateUnicodeStringFromAsciiz (&lpMachineNameW
,lpMachineName
);
493 RtlCreateUnicodeStringFromAsciiz (&lpDatabaseNameW
,lpDatabaseName
);
494 ret
= OpenSCManagerW(lpMachineNameW
.Buffer
,lpDatabaseNameW
.Buffer
, dwDesiredAccess
);
495 RtlFreeUnicodeString(&lpDatabaseNameW
);
496 RtlFreeUnicodeString(&lpMachineNameW
);
500 /******************************************************************************
501 * OpenSCManagerW [ADVAPI32.@]
503 * See OpenSCManagerA.
505 SC_HANDLE WINAPI
OpenSCManagerW( LPCWSTR lpMachineName
, LPCWSTR lpDatabaseName
,
506 DWORD dwDesiredAccess
)
508 struct sc_handle
*retval
;
512 TRACE("(%s,%s,0x%08lx)\n", debugstr_w(lpMachineName
),
513 debugstr_w(lpDatabaseName
), dwDesiredAccess
);
516 * FIXME: what is lpDatabaseName?
517 * It should be set to "SERVICES_ACTIVE_DATABASE" according to
518 * docs, but what if it isn't?
521 retval
= alloc_sc_handle( SC_HTYPE_MANAGER
);
522 if( NULL
== retval
) return NULL
;
524 retval
->u
.manager
.ref_count
= 1;
526 r
= RegConnectRegistryW(lpMachineName
,HKEY_LOCAL_MACHINE
,&hReg
);
527 if (r
!=ERROR_SUCCESS
)
530 r
= RegOpenKeyExW(hReg
, szServiceManagerKey
,
531 0, KEY_ALL_ACCESS
, &retval
->u
.manager
.hkey_scm_db
);
533 if (r
!=ERROR_SUCCESS
)
536 TRACE("returning %p\n", retval
);
538 return (SC_HANDLE
) retval
;
541 free_sc_handle( retval
);
546 /******************************************************************************
547 * AllocateLocallyUniqueId [ADVAPI32.@]
553 AllocateLocallyUniqueId( PLUID lpluid
)
555 lpluid
->LowPart
= time(NULL
);
556 lpluid
->HighPart
= 0;
561 /******************************************************************************
562 * ControlService [ADVAPI32.@]
564 * Send a control code to a service.
567 * hService [I] Handle of the service control manager database
568 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
569 * lpServiceStatus [O] Destination for the status of the service, if available
575 BOOL WINAPI
ControlService( SC_HANDLE hService
, DWORD dwControl
,
576 LPSERVICE_STATUS lpServiceStatus
)
578 FIXME("(%p,%ld,%p): stub\n",hService
,dwControl
,lpServiceStatus
);
583 /******************************************************************************
584 * CloseServiceHandle [ADVAPI32.@]
586 * Close a handle to a service or the service control manager database.
589 * hSCObject [I] Handle to service or service control manager database
596 CloseServiceHandle( SC_HANDLE hSCObject
)
598 TRACE("(%p)\n", hSCObject
);
600 free_sc_handle( (struct sc_handle
*) hSCObject
);
606 /******************************************************************************
607 * OpenServiceA [ADVAPI32.@]
609 * Open a handle to a service.
612 * hSCManager [I] Handle of the service control manager database
613 * lpServiceName [I] Name of the service to open
614 * dwDesiredAccess [I] Access required to the service
617 * Success: Handle to the service
620 SC_HANDLE WINAPI
OpenServiceA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
621 DWORD dwDesiredAccess
)
623 UNICODE_STRING lpServiceNameW
;
625 RtlCreateUnicodeStringFromAsciiz (&lpServiceNameW
,lpServiceName
);
627 TRACE("Request for service %s\n",lpServiceName
);
630 ret
= OpenServiceW( hSCManager
, lpServiceNameW
.Buffer
, dwDesiredAccess
);
631 RtlFreeUnicodeString(&lpServiceNameW
);
636 /******************************************************************************
637 * OpenServiceW [ADVAPI32.@]
641 SC_HANDLE WINAPI
OpenServiceW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
642 DWORD dwDesiredAccess
)
644 struct sc_handle
*hscm
= hSCManager
;
645 struct sc_handle
*retval
;
649 TRACE("(%p,%p,%ld)\n",hSCManager
, lpServiceName
,
652 retval
= alloc_sc_handle( SC_HTYPE_SERVICE
);
656 r
= RegOpenKeyExW( hscm
->u
.manager
.hkey_scm_db
,
657 lpServiceName
, 0, KEY_ALL_ACCESS
, &hKey
);
658 if (r
!=ERROR_SUCCESS
)
660 free_sc_handle( retval
);
661 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST
);
665 init_service_handle( retval
, hscm
, hKey
, lpServiceName
);
667 TRACE("returning %p\n",retval
);
669 return (SC_HANDLE
) retval
;
672 /******************************************************************************
673 * CreateServiceW [ADVAPI32.@]
676 CreateServiceW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
677 LPCWSTR lpDisplayName
, DWORD dwDesiredAccess
,
678 DWORD dwServiceType
, DWORD dwStartType
,
679 DWORD dwErrorControl
, LPCWSTR lpBinaryPathName
,
680 LPCWSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
,
681 LPCWSTR lpDependencies
, LPCWSTR lpServiceStartName
,
684 struct sc_handle
*hscm
= hSCManager
;
685 struct sc_handle
*retval
;
689 static const WCHAR szDisplayName
[] = { 'D','i','s','p','l','a','y','N','a','m','e', 0 };
690 static const WCHAR szType
[] = {'T','y','p','e',0};
691 static const WCHAR szStart
[] = {'S','t','a','r','t',0};
692 static const WCHAR szError
[] = {'E','r','r','o','r','C','o','n','t','r','o','l', 0};
693 static const WCHAR szImagePath
[] = {'I','m','a','g','e','P','a','t','h',0};
694 static const WCHAR szGroup
[] = {'G','r','o','u','p',0};
695 static const WCHAR szDependencies
[] = { 'D','e','p','e','n','d','e','n','c','i','e','s',0};
697 FIXME("%p %s %s\n", hSCManager
,
698 debugstr_w(lpServiceName
), debugstr_w(lpDisplayName
));
700 retval
= alloc_sc_handle( SC_HTYPE_SERVICE
);
704 r
= RegCreateKeyExW(hscm
->u
.manager
.hkey_scm_db
, lpServiceName
, 0, NULL
,
705 REG_OPTION_NON_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &hKey
, &dp
);
706 if (r
!=ERROR_SUCCESS
)
709 init_service_handle( retval
, hscm
, hKey
, lpServiceName
);
711 if (dp
!= REG_CREATED_NEW_KEY
)
716 r
= RegSetValueExW(hKey
, szDisplayName
, 0, REG_SZ
, (LPBYTE
)lpDisplayName
,
717 (strlenW(lpDisplayName
)+1)*sizeof(WCHAR
) );
718 if (r
!=ERROR_SUCCESS
)
722 r
= RegSetValueExW(hKey
, szType
, 0, REG_DWORD
, (LPVOID
)&dwServiceType
, sizeof (DWORD
) );
723 if (r
!=ERROR_SUCCESS
)
726 r
= RegSetValueExW(hKey
, szStart
, 0, REG_DWORD
, (LPVOID
)&dwStartType
, sizeof (DWORD
) );
727 if (r
!=ERROR_SUCCESS
)
730 r
= RegSetValueExW(hKey
, szError
, 0, REG_DWORD
,
731 (LPVOID
)&dwErrorControl
, sizeof (DWORD
) );
732 if (r
!=ERROR_SUCCESS
)
737 r
= RegSetValueExW(hKey
, szImagePath
, 0, REG_SZ
, (LPBYTE
)lpBinaryPathName
,
738 (strlenW(lpBinaryPathName
)+1)*sizeof(WCHAR
) );
739 if (r
!=ERROR_SUCCESS
)
745 r
= RegSetValueExW(hKey
, szGroup
, 0, REG_SZ
, (LPBYTE
)lpLoadOrderGroup
,
746 (strlenW(lpLoadOrderGroup
)+1)*sizeof(WCHAR
) );
747 if (r
!=ERROR_SUCCESS
)
755 /* determine the length of a double null terminated multi string */
757 len
+= (strlenW(&lpDependencies
[len
])+1);
758 } while (lpDependencies
[len
++]);
760 r
= RegSetValueExW(hKey
, szDependencies
, 0, REG_MULTI_SZ
,
761 (LPBYTE
)lpDependencies
, len
);
762 if (r
!=ERROR_SUCCESS
)
768 FIXME("Don't know how to add a Password for a service.\n");
771 if(lpServiceStartName
)
773 FIXME("Don't know how to add a ServiceStartName for a service.\n");
776 return (SC_HANDLE
) retval
;
779 free_sc_handle( retval
);
784 static inline LPWSTR
SERV_dup( LPCSTR str
)
791 len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
792 wstr
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof (WCHAR
) );
793 MultiByteToWideChar( CP_ACP
, 0, str
, -1, wstr
, len
);
797 static inline LPWSTR
SERV_dupmulti( LPCSTR str
)
805 len
+= MultiByteToWideChar( CP_ACP
, 0, &str
[n
], -1, NULL
, 0 );
806 n
+= (strlen( &str
[n
] ) + 1);
811 wstr
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof (WCHAR
) );
812 MultiByteToWideChar( CP_ACP
, 0, str
, n
, wstr
, len
);
816 static inline VOID
SERV_free( LPWSTR wstr
)
818 HeapFree( GetProcessHeap(), 0, wstr
);
821 /******************************************************************************
822 * CreateServiceA [ADVAPI32.@]
825 CreateServiceA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
826 LPCSTR lpDisplayName
, DWORD dwDesiredAccess
,
827 DWORD dwServiceType
, DWORD dwStartType
,
828 DWORD dwErrorControl
, LPCSTR lpBinaryPathName
,
829 LPCSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
,
830 LPCSTR lpDependencies
, LPCSTR lpServiceStartName
,
833 LPWSTR lpServiceNameW
, lpDisplayNameW
, lpBinaryPathNameW
,
834 lpLoadOrderGroupW
, lpDependenciesW
, lpServiceStartNameW
, lpPasswordW
;
837 TRACE("%p %s %s\n", hSCManager
,
838 debugstr_a(lpServiceName
), debugstr_a(lpDisplayName
));
840 lpServiceNameW
= SERV_dup( lpServiceName
);
841 lpDisplayNameW
= SERV_dup( lpDisplayName
);
842 lpBinaryPathNameW
= SERV_dup( lpBinaryPathName
);
843 lpLoadOrderGroupW
= SERV_dup( lpLoadOrderGroup
);
844 lpDependenciesW
= SERV_dupmulti( lpDependencies
);
845 lpServiceStartNameW
= SERV_dup( lpServiceStartName
);
846 lpPasswordW
= SERV_dup( lpPassword
);
848 r
= CreateServiceW( hSCManager
, lpServiceNameW
, lpDisplayNameW
,
849 dwDesiredAccess
, dwServiceType
, dwStartType
, dwErrorControl
,
850 lpBinaryPathNameW
, lpLoadOrderGroupW
, lpdwTagId
,
851 lpDependenciesW
, lpServiceStartNameW
, lpPasswordW
);
853 SERV_free( lpServiceNameW
);
854 SERV_free( lpDisplayNameW
);
855 SERV_free( lpBinaryPathNameW
);
856 SERV_free( lpLoadOrderGroupW
);
857 SERV_free( lpDependenciesW
);
858 SERV_free( lpServiceStartNameW
);
859 SERV_free( lpPasswordW
);
865 /******************************************************************************
866 * DeleteService [ADVAPI32.@]
868 * Delete a service from the service control manager database.
871 * hService [I] Handle of the service to delete
877 BOOL WINAPI
DeleteService( SC_HANDLE hService
)
879 struct sc_handle
*hsvc
= hService
;
880 HKEY hKey
= hsvc
->u
.service
.hkey
;
881 WCHAR valname
[MAX_PATH
+1];
887 /* Clean out the values */
888 rc
= RegEnumValueW(hKey
, index
, valname
,&size
,0,0,0,0);
889 while (rc
== ERROR_SUCCESS
)
891 RegDeleteValueW(hKey
,valname
);
894 rc
= RegEnumValueW(hKey
, index
, valname
, &size
,0,0,0,0);
898 hsvc
->u
.service
.hkey
= NULL
;
901 RegDeleteKeyW(hsvc
->u
.service
.sc_manager
->u
.manager
.hkey_scm_db
,
902 hsvc
->u
.service
.name
);
908 /******************************************************************************
909 * StartServiceA [ADVAPI32.@]
914 * hService [I] Handle of service
915 * dwNumServiceArgs [I] Number of arguments
916 * lpServiceArgVectors [I] Address of array of argument strings
919 * - NT implements this function using an obscure RPC call.
920 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
921 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
922 * - This will only work for shared address space. How should the service
923 * args be transferred when address spaces are separated?
924 * - Can only start one service at a time.
925 * - Has no concept of privilege.
932 StartServiceA( SC_HANDLE hService
, DWORD dwNumServiceArgs
,
933 LPCSTR
*lpServiceArgVectors
)
936 UNICODE_STRING usBuffer
;
939 TRACE("(%p,%ld,%p)\n",hService
,dwNumServiceArgs
,lpServiceArgVectors
);
942 lpwstr
= (LPWSTR
*) HeapAlloc( GetProcessHeap(), 0,
943 dwNumServiceArgs
*sizeof(LPWSTR
) );
947 for(i
=0; i
<dwNumServiceArgs
; i
++)
949 RtlCreateUnicodeStringFromAsciiz (&usBuffer
,lpServiceArgVectors
[i
]);
950 lpwstr
[i
]=usBuffer
.Buffer
;
953 StartServiceW(hService
, dwNumServiceArgs
, (LPCWSTR
*)lpwstr
);
957 for(i
=0; i
<dwNumServiceArgs
; i
++)
958 HeapFree(GetProcessHeap(), 0, lpwstr
[i
]);
959 HeapFree(GetProcessHeap(), 0, lpwstr
);
966 /******************************************************************************
967 * StartServiceW [ADVAPI32.@]
972 StartServiceW( SC_HANDLE hService
, DWORD dwNumServiceArgs
,
973 LPCWSTR
*lpServiceArgVectors
)
975 static const WCHAR _WaitServiceStartW
[] = {'A','D','V','A','P','I','_','W',
976 'a','i','t','S','e','r','v','i',
977 'c','e','S','t','a','r','t',0};
978 static const WCHAR _ImagePathW
[] = {'I','m','a','g','e','P','a','t','h',0};
980 struct sc_handle
*hsvc
= hService
;
981 WCHAR path
[MAX_PATH
],str
[MAX_PATH
];
986 HANDLE hServiceShmem
= NULL
;
988 LPWSTR shmem_lock
= NULL
;
989 struct SEB
*seb
= NULL
;
991 PROCESS_INFORMATION procinfo
;
992 STARTUPINFOW startupinfo
;
995 TRACE("(%p,%ld,%p)\n",hService
,dwNumServiceArgs
,
996 lpServiceArgVectors
);
999 r
= RegQueryValueExW(hsvc
->u
.service
.hkey
, _ImagePathW
, NULL
, &type
, (LPVOID
)str
, &size
);
1000 if (r
!=ERROR_SUCCESS
)
1002 ExpandEnvironmentStringsW(str
,path
,sizeof(path
));
1004 TRACE("Starting service %s\n", debugstr_w(path
) );
1006 hLock
= LockServiceDatabase( hsvc
->u
.service
.sc_manager
);
1011 * FIXME: start dependent services
1014 /* pass argv[0] (service name) to the service via global SCM lock object */
1015 shmem_lock
= MapViewOfFile( hLock
, FILE_MAP_ALL_ACCESS
,
1016 0, 0, MAX_SERVICE_NAME
* sizeof(WCHAR
) );
1017 if( NULL
== shmem_lock
)
1019 ERR("Couldn't map shared memory\n");
1022 strcpyW( shmem_lock
, hsvc
->u
.service
.name
);
1024 /* create service environment block */
1025 size
= sizeof(struct SEB
);
1026 for( i
= 0; i
< dwNumServiceArgs
; i
++ )
1027 size
+= sizeof(WCHAR
) * (1 + strlenW( lpServiceArgVectors
[ i
] ));
1029 snprintfW( str
, MAX_PATH
, szServiceShmemNameFmtW
, hsvc
->u
.service
.name
);
1030 hServiceShmem
= CreateFileMappingW( INVALID_HANDLE_VALUE
,
1031 NULL
, PAGE_READWRITE
, 0, size
, str
);
1032 if( NULL
== hServiceShmem
)
1034 ERR("Couldn't create shared memory object\n");
1037 if( GetLastError() == ERROR_ALREADY_EXISTS
)
1039 SetLastError( ERROR_SERVICE_ALREADY_RUNNING
);
1042 seb
= MapViewOfFile( hServiceShmem
, FILE_MAP_ALL_ACCESS
, 0, 0, 0 );
1045 ERR("Couldn't map shared memory\n");
1049 /* copy service args to SEB */
1050 seb
->argc
= dwNumServiceArgs
;
1051 argptr
= (LPWSTR
) &seb
[1];
1052 for( i
= 0; i
< dwNumServiceArgs
; i
++ )
1054 strcpyW( argptr
, lpServiceArgVectors
[ i
] );
1055 argptr
+= 1 + strlenW( argptr
);
1058 wait
= CreateSemaphoreW(NULL
,0,1,_WaitServiceStartW
);
1061 ERR("Couldn't create wait semaphore\n");
1065 ZeroMemory(&startupinfo
,sizeof(STARTUPINFOW
));
1066 startupinfo
.cb
= sizeof(STARTUPINFOW
);
1068 r
= CreateProcessW(NULL
,
1070 NULL
, /* process security attribs */
1071 NULL
, /* thread security attribs */
1072 FALSE
, /* inherit handles */
1073 0, /* creation flags */
1074 NULL
, /* environment */
1075 NULL
, /* current directory */
1076 &startupinfo
, /* startup info */
1077 &procinfo
); /* process info */
1081 ERR("Couldn't start process\n");
1084 CloseHandle( procinfo
.hThread
);
1086 /* docs for StartServiceCtrlDispatcher say this should be 30 sec */
1087 r
= WaitForSingleObject(wait
,30000);
1088 if( WAIT_FAILED
== r
)
1090 CloseHandle( procinfo
.hProcess
);
1095 CloseHandle( procinfo
.hProcess
);
1099 if( wait
) CloseHandle( wait
);
1100 if( seb
!= NULL
) UnmapViewOfFile( seb
);
1101 if( hServiceShmem
!= NULL
) CloseHandle( hServiceShmem
);
1102 if( shmem_lock
!= NULL
) UnmapViewOfFile( shmem_lock
);
1103 UnlockServiceDatabase( hLock
);
1107 /******************************************************************************
1108 * QueryServiceStatus [ADVAPI32.@]
1112 * lpservicestatus []
1116 QueryServiceStatus( SC_HANDLE hService
, LPSERVICE_STATUS lpservicestatus
)
1118 struct sc_handle
*hsvc
= hService
;
1120 DWORD type
, val
, size
;
1122 FIXME("(%p,%p) partial\n",hService
,lpservicestatus
);
1124 /* read the service type from the registry */
1126 r
= RegQueryValueExA(hsvc
->u
.service
.hkey
, "Type", NULL
, &type
, (LPBYTE
)&val
, &size
);
1129 ERR("invalid Type\n");
1132 lpservicestatus
->dwServiceType
= val
;
1133 /* FIXME: how are these determined or read from the registry? */
1134 /* SERVICE: unavailable=0, stopped=1, starting=2, running=3? */;
1135 lpservicestatus
->dwCurrentState
= 1;
1136 lpservicestatus
->dwControlsAccepted
= 0;
1137 lpservicestatus
->dwWin32ExitCode
= NO_ERROR
;
1138 lpservicestatus
->dwServiceSpecificExitCode
= 0;
1139 lpservicestatus
->dwCheckPoint
= 0;
1140 lpservicestatus
->dwWaitHint
= 0;
1145 /******************************************************************************
1146 * QueryServiceStatusEx [ADVAPI32.@]
1148 * Get information about a service.
1151 * hService [I] Handle to service to get information about
1152 * InfoLevel [I] Level of information to get
1153 * lpBuffer [O] Destination for requested information
1154 * cbBufSize [I] Size of lpBuffer in bytes
1155 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1161 BOOL WINAPI
QueryServiceStatusEx(SC_HANDLE hService
, SC_STATUS_TYPE InfoLevel
,
1162 LPBYTE lpBuffer
, DWORD cbBufSize
,
1163 LPDWORD pcbBytesNeeded
)
1166 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1170 /******************************************************************************
1171 * QueryServiceConfigA [ADVAPI32.@]
1174 QueryServiceConfigA( SC_HANDLE hService
,
1175 LPQUERY_SERVICE_CONFIGA lpServiceConfig
,
1176 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
1178 static const CHAR szDisplayName
[] = "DisplayName";
1179 static const CHAR szType
[] = "Type";
1180 static const CHAR szStart
[] = "Start";
1181 static const CHAR szError
[] = "ErrorControl";
1182 static const CHAR szImagePath
[] = "ImagePath";
1183 static const CHAR szGroup
[] = "Group";
1184 static const CHAR szDependencies
[] = "Dependencies";
1185 HKEY hKey
= ((struct sc_handle
*) hService
)->u
.service
.hkey
;
1186 CHAR str_buffer
[ MAX_PATH
];
1188 DWORD type
, val
, sz
, total
, n
;
1191 TRACE("%p %p %ld %p\n", hService
, lpServiceConfig
,
1192 cbBufSize
, pcbBytesNeeded
);
1194 /* calculate the size required first */
1195 total
= sizeof (QUERY_SERVICE_CONFIGA
);
1197 sz
= sizeof(str_buffer
);
1198 r
= RegQueryValueExA( hKey
, szImagePath
, 0, &type
, str_buffer
, &sz
);
1199 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
|| type
== REG_EXPAND_SZ
) )
1201 sz
= ExpandEnvironmentStringsA(str_buffer
,NULL
,0);
1202 if( 0 == sz
) return FALSE
;
1208 /* FIXME: set last error */
1213 r
= RegQueryValueExA( hKey
, szGroup
, 0, &type
, NULL
, &sz
);
1214 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1218 r
= RegQueryValueExA( hKey
, szDependencies
, 0, &type
, NULL
, &sz
);
1219 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_MULTI_SZ
) )
1223 r
= RegQueryValueExA( hKey
, szStart
, 0, &type
, NULL
, &sz
);
1224 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1228 r
= RegQueryValueExA( hKey
, szDisplayName
, 0, &type
, NULL
, &sz
);
1229 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1232 /* if there's not enough memory, return an error */
1233 if( total
> *pcbBytesNeeded
)
1235 *pcbBytesNeeded
= total
;
1236 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1240 *pcbBytesNeeded
= total
;
1241 ZeroMemory( lpServiceConfig
, total
);
1244 r
= RegQueryValueExA( hKey
, szType
, 0, &type
, (LPBYTE
)&val
, &sz
);
1245 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_DWORD
) )
1246 lpServiceConfig
->dwServiceType
= val
;
1249 r
= RegQueryValueExA( hKey
, szStart
, 0, &type
, (LPBYTE
)&val
, &sz
);
1250 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_DWORD
) )
1251 lpServiceConfig
->dwStartType
= val
;
1254 r
= RegQueryValueExA( hKey
, szError
, 0, &type
, (LPBYTE
)&val
, &sz
);
1255 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_DWORD
) )
1256 lpServiceConfig
->dwErrorControl
= val
;
1258 /* now do the strings */
1259 p
= (LPBYTE
) &lpServiceConfig
[1];
1260 n
= total
- sizeof (QUERY_SERVICE_CONFIGA
);
1262 sz
= sizeof(str_buffer
);
1263 r
= RegQueryValueExA( hKey
, szImagePath
, 0, &type
, str_buffer
, &sz
);
1264 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
|| type
== REG_EXPAND_SZ
) )
1266 sz
= ExpandEnvironmentStringsA(str_buffer
, p
, n
);
1267 if( 0 == sz
|| sz
> n
) return FALSE
;
1269 lpServiceConfig
->lpBinaryPathName
= (LPSTR
) p
;
1275 /* FIXME: set last error */
1280 r
= RegQueryValueExA( hKey
, szGroup
, 0, &type
, p
, &sz
);
1281 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_SZ
) )
1283 lpServiceConfig
->lpLoadOrderGroup
= (LPSTR
) p
;
1289 r
= RegQueryValueExA( hKey
, szDependencies
, 0, &type
, p
, &sz
);
1290 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_SZ
) )
1292 lpServiceConfig
->lpDependencies
= (LPSTR
) p
;
1298 ERR("Buffer overflow!\n");
1300 TRACE("Image path = %s\n", lpServiceConfig
->lpBinaryPathName
);
1301 TRACE("Group = %s\n", lpServiceConfig
->lpLoadOrderGroup
);
1306 /******************************************************************************
1307 * QueryServiceConfigW [ADVAPI32.@]
1310 QueryServiceConfigW( SC_HANDLE hService
,
1311 LPQUERY_SERVICE_CONFIGW lpServiceConfig
,
1312 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
1314 static const WCHAR szDisplayName
[] = {
1315 'D','i','s','p','l','a','y','N','a','m','e', 0 };
1316 static const WCHAR szType
[] = {'T','y','p','e',0};
1317 static const WCHAR szStart
[] = {'S','t','a','r','t',0};
1318 static const WCHAR szError
[] = {
1319 'E','r','r','o','r','C','o','n','t','r','o','l', 0};
1320 static const WCHAR szImagePath
[] = {'I','m','a','g','e','P','a','t','h',0};
1321 static const WCHAR szGroup
[] = {'G','r','o','u','p',0};
1322 static const WCHAR szDependencies
[] = {
1323 'D','e','p','e','n','d','e','n','c','i','e','s',0};
1324 HKEY hKey
= ((struct sc_handle
*) hService
)->u
.service
.hkey
;
1325 WCHAR str_buffer
[ MAX_PATH
];
1327 DWORD type
, val
, sz
, total
, n
;
1330 TRACE("%p %p %ld %p\n", hService
, lpServiceConfig
,
1331 cbBufSize
, pcbBytesNeeded
);
1333 /* calculate the size required first */
1334 total
= sizeof (QUERY_SERVICE_CONFIGW
);
1336 sz
= sizeof(str_buffer
);
1337 r
= RegQueryValueExW( hKey
, szImagePath
, 0, &type
, (LPBYTE
) str_buffer
, &sz
);
1338 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
|| type
== REG_EXPAND_SZ
) )
1340 sz
= ExpandEnvironmentStringsW(str_buffer
,NULL
,0);
1341 if( 0 == sz
) return FALSE
;
1343 total
+= sizeof(WCHAR
) * sz
;
1347 /* FIXME: set last error */
1352 r
= RegQueryValueExW( hKey
, szGroup
, 0, &type
, NULL
, &sz
);
1353 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1357 r
= RegQueryValueExW( hKey
, szDependencies
, 0, &type
, NULL
, &sz
);
1358 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_MULTI_SZ
) )
1362 r
= RegQueryValueExW( hKey
, szStart
, 0, &type
, NULL
, &sz
);
1363 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1367 r
= RegQueryValueExW( hKey
, szDisplayName
, 0, &type
, NULL
, &sz
);
1368 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1371 /* if there's not enough memory, return an error */
1372 if( total
> *pcbBytesNeeded
)
1374 *pcbBytesNeeded
= total
;
1375 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1379 *pcbBytesNeeded
= total
;
1380 ZeroMemory( lpServiceConfig
, total
);
1383 r
= RegQueryValueExW( hKey
, szType
, 0, &type
, (LPBYTE
)&val
, &sz
);
1384 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_DWORD
) )
1385 lpServiceConfig
->dwServiceType
= val
;
1388 r
= RegQueryValueExW( hKey
, szStart
, 0, &type
, (LPBYTE
)&val
, &sz
);
1389 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_DWORD
) )
1390 lpServiceConfig
->dwStartType
= val
;
1393 r
= RegQueryValueExW( hKey
, szError
, 0, &type
, (LPBYTE
)&val
, &sz
);
1394 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_DWORD
) )
1395 lpServiceConfig
->dwErrorControl
= val
;
1397 /* now do the strings */
1398 p
= (LPBYTE
) &lpServiceConfig
[1];
1399 n
= total
- sizeof (QUERY_SERVICE_CONFIGW
);
1401 sz
= sizeof(str_buffer
);
1402 r
= RegQueryValueExW( hKey
, szImagePath
, 0, &type
, (LPBYTE
) str_buffer
, &sz
);
1403 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
|| type
== REG_EXPAND_SZ
) )
1405 sz
= ExpandEnvironmentStringsW(str_buffer
, (LPWSTR
) p
, n
);
1406 sz
*= sizeof(WCHAR
);
1407 if( 0 == sz
|| sz
> n
) return FALSE
;
1409 lpServiceConfig
->lpBinaryPathName
= (LPWSTR
) p
;
1415 /* FIXME: set last error */
1420 r
= RegQueryValueExW( hKey
, szGroup
, 0, &type
, p
, &sz
);
1421 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_SZ
) )
1423 lpServiceConfig
->lpLoadOrderGroup
= (LPWSTR
) p
;
1429 r
= RegQueryValueExW( hKey
, szDependencies
, 0, &type
, p
, &sz
);
1430 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_SZ
) )
1432 lpServiceConfig
->lpDependencies
= (LPWSTR
) p
;
1438 ERR("Buffer overflow!\n");
1440 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig
->lpBinaryPathName
) );
1441 TRACE("Group = %s\n", debugstr_w(lpServiceConfig
->lpLoadOrderGroup
) );
1446 /******************************************************************************
1447 * ChangeServiceConfigW [ADVAPI32.@]
1449 BOOL WINAPI
ChangeServiceConfigW( SC_HANDLE hService
, DWORD dwServiceType
,
1450 DWORD dwStartType
, DWORD dwErrorControl
, LPCWSTR lpBinaryPathName
,
1451 LPCWSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
, LPCWSTR lpDependencies
,
1452 LPCWSTR lpServiceStartName
, LPCWSTR lpPassword
, LPCWSTR lpDisplayName
)
1454 FIXME("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
1455 hService
, dwServiceType
, dwStartType
, dwErrorControl
,
1456 debugstr_w(lpBinaryPathName
), debugstr_w(lpLoadOrderGroup
),
1457 lpdwTagId
, lpDependencies
, debugstr_w(lpServiceStartName
),
1458 debugstr_w(lpPassword
), debugstr_w(lpDisplayName
) );
1462 /******************************************************************************
1463 * ChangeServiceConfigA [ADVAPI32.@]
1465 BOOL WINAPI
ChangeServiceConfigA( SC_HANDLE hService
, DWORD dwServiceType
,
1466 DWORD dwStartType
, DWORD dwErrorControl
, LPCSTR lpBinaryPathName
,
1467 LPCSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
, LPCSTR lpDependencies
,
1468 LPCSTR lpServiceStartName
, LPCSTR lpPassword
, LPCSTR lpDisplayName
)
1470 FIXME("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
1471 hService
, dwServiceType
, dwStartType
, dwErrorControl
,
1472 debugstr_a(lpBinaryPathName
), debugstr_a(lpLoadOrderGroup
),
1473 lpdwTagId
, lpDependencies
, debugstr_a(lpServiceStartName
),
1474 debugstr_a(lpPassword
), debugstr_a(lpDisplayName
) );
1478 /******************************************************************************
1479 * ChangeServiceConfig2A [ADVAPI32.@]
1481 BOOL WINAPI
ChangeServiceConfig2A( SC_HANDLE hService
, DWORD dwInfoLevel
,
1484 FIXME("STUB: %p %ld %p\n",hService
, dwInfoLevel
, lpInfo
);
1488 /******************************************************************************
1489 * ChangeServiceConfig2W [ADVAPI32.@]
1491 BOOL WINAPI
ChangeServiceConfig2W( SC_HANDLE hService
, DWORD dwInfoLevel
,
1494 HKEY hKey
= ((struct sc_handle
*) hService
)->u
.service
.hkey
;
1496 if (dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
1498 static const WCHAR szDescription
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
1499 LPSERVICE_DESCRIPTIONW sd
= (LPSERVICE_DESCRIPTIONW
)lpInfo
;
1500 if (sd
->lpDescription
)
1502 TRACE("Setting Description to %s\n",debugstr_w(sd
->lpDescription
));
1503 if (sd
->lpDescription
[0] == 0)
1504 RegDeleteValueW(hKey
,szDescription
);
1506 RegSetValueExW(hKey
, szDescription
, 0, REG_SZ
,
1507 (LPVOID
)sd
->lpDescription
,
1508 sizeof(WCHAR
)*(strlenW(sd
->lpDescription
)+1));
1512 FIXME("STUB: %p %ld %p\n",hService
, dwInfoLevel
, lpInfo
);
1516 /******************************************************************************
1517 * QueryServiceObjectSecurity [ADVAPI32.@]
1519 BOOL WINAPI
QueryServiceObjectSecurity(SC_HANDLE hService
,
1520 SECURITY_INFORMATION dwSecurityInformation
,
1521 PSECURITY_DESCRIPTOR lpSecurityDescriptor
,
1522 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
1524 FIXME("%p %ld %p %lu %p\n", hService
, dwSecurityInformation
,
1525 lpSecurityDescriptor
, cbBufSize
, pcbBytesNeeded
);
1526 return ERROR_CALL_NOT_IMPLEMENTED
;