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 static struct SEB
* open_seb_shmem( LPWSTR service_name
, HANDLE
* hServiceShmem
)
227 WCHAR object_name
[ MAX_PATH
];
231 snprintfW( object_name
, MAX_PATH
, szServiceShmemNameFmtW
, service_name
);
232 hmem
= OpenFileMappingW( FILE_MAP_ALL_ACCESS
, FALSE
, object_name
);
236 ret
= MapViewOfFile( hmem
, FILE_MAP_ALL_ACCESS
, 0, 0, 0 );
240 *hServiceShmem
= hmem
;
244 /******************************************************************************
247 * helper function for StartServiceCtrlDispatcherA/W
249 * Allocate and initialize array of LPWSTRs to arguments in variable part
250 * of service environment block.
251 * First entry in the array is reserved for service name and not initialized.
253 static LPWSTR
* build_arg_vectors( struct SEB
* seb
)
259 ret
= HeapAlloc( GetProcessHeap(), 0, (1 + seb
->argc
) * sizeof(LPWSTR
) );
263 argptr
= (LPWSTR
) &seb
[1];
264 for( i
= 0; i
< seb
->argc
; i
++ )
266 ret
[ 1 + i
] = argptr
;
267 argptr
+= 1 + strlenW( argptr
);
272 /******************************************************************************
273 * StartServiceCtrlDispatcherA [ADVAPI32.@]
276 StartServiceCtrlDispatcherA( LPSERVICE_TABLE_ENTRYA servent
)
278 LPSERVICE_MAIN_FUNCTIONA fpMain
;
279 WCHAR service_name
[ MAX_SERVICE_NAME
];
280 HANDLE hServiceShmem
= NULL
;
281 struct SEB
*seb
= NULL
;
282 DWORD dwNumServiceArgs
= 0;
283 LPWSTR
*lpArgVecW
= NULL
;
284 LPSTR
*lpArgVecA
= NULL
;
288 TRACE("(%p)\n", servent
);
290 if( ! read_scm_lock_data( service_name
) )
292 /* FIXME: Instead of exiting we allow
293 service to be executed as ordinary program.
294 This behaviour was specially introduced in the patch
295 submitted against revision 1.45 and so preserved here.
297 FIXME("should fail with ERROR_FAILED_SERVICE_CONTROLLER_CONNECT\n");
298 servent
->lpServiceProc( 0, NULL
);
302 seb
= open_seb_shmem( service_name
, &hServiceShmem
);
306 lpArgVecW
= build_arg_vectors( seb
);
307 if( NULL
== lpArgVecW
)
310 lpArgVecW
[0] = service_name
;
311 dwNumServiceArgs
= seb
->argc
+ 1;
313 /* Convert the Unicode arg vectors back to ASCII */
314 lpArgVecA
= (LPSTR
*) HeapAlloc( GetProcessHeap(), 0,
315 dwNumServiceArgs
*sizeof(LPSTR
) );
316 for(i
=0; i
<dwNumServiceArgs
; i
++)
317 lpArgVecA
[i
]=HEAP_strdupWtoA(GetProcessHeap(), 0, lpArgVecW
[i
]);
319 /* FIXME: find service entry by name if SERVICE_WIN32_SHARE_PROCESS */
320 TRACE("%s at %p)\n", debugstr_a(servent
->lpServiceName
),servent
);
321 fpMain
= servent
->lpServiceProc
;
323 /* try to start the service */
324 fpMain( dwNumServiceArgs
, lpArgVecA
);
329 /* free arg strings */
330 for(i
=0; i
<dwNumServiceArgs
; i
++)
331 HeapFree(GetProcessHeap(), 0, lpArgVecA
[i
]);
332 HeapFree(GetProcessHeap(), 0, lpArgVecA
);
335 if( lpArgVecW
) HeapFree( GetProcessHeap(), 0, lpArgVecW
);
336 if( seb
) UnmapViewOfFile( seb
);
337 if( hServiceShmem
) CloseHandle( hServiceShmem
);
341 /******************************************************************************
342 * StartServiceCtrlDispatcherW [ADVAPI32.@]
348 StartServiceCtrlDispatcherW( LPSERVICE_TABLE_ENTRYW servent
)
350 LPSERVICE_MAIN_FUNCTIONW fpMain
;
351 WCHAR service_name
[ MAX_SERVICE_NAME
];
352 HANDLE hServiceShmem
= NULL
;
354 DWORD dwNumServiceArgs
;
355 LPWSTR
*lpServiceArgVectors
;
357 TRACE("(%p)\n", servent
);
359 if( ! read_scm_lock_data( service_name
) )
362 seb
= open_seb_shmem( service_name
, &hServiceShmem
);
366 lpServiceArgVectors
= build_arg_vectors( seb
);
367 if( NULL
== lpServiceArgVectors
)
369 UnmapViewOfFile( seb
);
370 CloseHandle( hServiceShmem
);
373 lpServiceArgVectors
[0] = service_name
;
374 dwNumServiceArgs
= seb
->argc
+ 1;
376 /* FIXME: find service entry by name if SERVICE_WIN32_SHARE_PROCESS */
377 TRACE("%s at %p)\n", debugstr_w(servent
->lpServiceName
),servent
);
378 fpMain
= servent
->lpServiceProc
;
380 /* try to start the service */
381 fpMain( dwNumServiceArgs
, lpServiceArgVectors
);
383 HeapFree( GetProcessHeap(), 0, lpServiceArgVectors
);
384 UnmapViewOfFile( seb
);
385 CloseHandle( hServiceShmem
);
389 /******************************************************************************
390 * LockServiceDatabase [ADVAPI32.@]
392 LPVOID WINAPI
LockServiceDatabase (SC_HANDLE hSCManager
)
396 TRACE("%p\n",hSCManager
);
398 ret
= CreateFileMappingW( INVALID_HANDLE_VALUE
, NULL
, PAGE_READWRITE
,
399 0, MAX_SERVICE_NAME
* sizeof(WCHAR
), szSCMLock
);
400 if( ret
&& GetLastError() == ERROR_ALREADY_EXISTS
)
404 SetLastError( ERROR_SERVICE_DATABASE_LOCKED
);
407 TRACE("returning %p\n", ret
);
412 /******************************************************************************
413 * UnlockServiceDatabase [ADVAPI32.@]
415 BOOL WINAPI
UnlockServiceDatabase (LPVOID ScLock
)
417 TRACE("%p\n",ScLock
);
419 return CloseHandle( (HANDLE
) ScLock
);
422 /******************************************************************************
423 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
425 SERVICE_STATUS_HANDLE WINAPI
426 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName
,
427 LPHANDLER_FUNCTION lpfHandler
)
428 { FIXME("%s %p\n", lpServiceName
, lpfHandler
);
432 /******************************************************************************
433 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
439 SERVICE_STATUS_HANDLE WINAPI
440 RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName
,
441 LPHANDLER_FUNCTION lpfHandler
)
442 { FIXME("%s %p\n", debugstr_w(lpServiceName
), lpfHandler
);
446 /******************************************************************************
447 * SetServiceStatus [ADVAPI32.@]
454 SetServiceStatus( SERVICE_STATUS_HANDLE hService
, LPSERVICE_STATUS lpStatus
)
455 { FIXME("0x%lx %p\n",hService
, lpStatus
);
456 TRACE("\tType:%lx\n",lpStatus
->dwServiceType
);
457 TRACE("\tState:%lx\n",lpStatus
->dwCurrentState
);
458 TRACE("\tControlAccepted:%lx\n",lpStatus
->dwControlsAccepted
);
459 TRACE("\tExitCode:%lx\n",lpStatus
->dwWin32ExitCode
);
460 TRACE("\tServiceExitCode:%lx\n",lpStatus
->dwServiceSpecificExitCode
);
461 TRACE("\tCheckPoint:%lx\n",lpStatus
->dwCheckPoint
);
462 TRACE("\tWaitHint:%lx\n",lpStatus
->dwWaitHint
);
466 /******************************************************************************
467 * OpenSCManagerA [ADVAPI32.@]
469 * Establish a connection to the service control manager and open its database.
472 * lpMachineName [I] Pointer to machine name string
473 * lpDatabaseName [I] Pointer to database name string
474 * dwDesiredAccess [I] Type of access
477 * Success: A Handle to the service control manager database
480 SC_HANDLE WINAPI
OpenSCManagerA( LPCSTR lpMachineName
, LPCSTR lpDatabaseName
,
481 DWORD dwDesiredAccess
)
483 UNICODE_STRING lpMachineNameW
;
484 UNICODE_STRING lpDatabaseNameW
;
487 RtlCreateUnicodeStringFromAsciiz (&lpMachineNameW
,lpMachineName
);
488 RtlCreateUnicodeStringFromAsciiz (&lpDatabaseNameW
,lpDatabaseName
);
489 ret
= OpenSCManagerW(lpMachineNameW
.Buffer
,lpDatabaseNameW
.Buffer
, dwDesiredAccess
);
490 RtlFreeUnicodeString(&lpDatabaseNameW
);
491 RtlFreeUnicodeString(&lpMachineNameW
);
495 /******************************************************************************
496 * OpenSCManagerW [ADVAPI32.@]
498 * See OpenSCManagerA.
500 SC_HANDLE WINAPI
OpenSCManagerW( LPCWSTR lpMachineName
, LPCWSTR lpDatabaseName
,
501 DWORD dwDesiredAccess
)
503 struct sc_handle
*retval
;
507 TRACE("(%s,%s,0x%08lx)\n", debugstr_w(lpMachineName
),
508 debugstr_w(lpDatabaseName
), dwDesiredAccess
);
511 * FIXME: what is lpDatabaseName?
512 * It should be set to "SERVICES_ACTIVE_DATABASE" according to
513 * docs, but what if it isn't?
516 retval
= alloc_sc_handle( SC_HTYPE_MANAGER
);
517 if( NULL
== retval
) return NULL
;
519 retval
->u
.manager
.ref_count
= 1;
521 r
= RegConnectRegistryW(lpMachineName
,HKEY_LOCAL_MACHINE
,&hReg
);
522 if (r
!=ERROR_SUCCESS
)
525 r
= RegOpenKeyExW(hReg
, szServiceManagerKey
,
526 0, KEY_ALL_ACCESS
, &retval
->u
.manager
.hkey_scm_db
);
528 if (r
!=ERROR_SUCCESS
)
531 TRACE("returning %p\n", retval
);
533 return (SC_HANDLE
) retval
;
536 free_sc_handle( retval
);
541 /******************************************************************************
542 * AllocateLocallyUniqueId [ADVAPI32.@]
548 AllocateLocallyUniqueId( PLUID lpluid
)
550 lpluid
->LowPart
= time(NULL
);
551 lpluid
->HighPart
= 0;
556 /******************************************************************************
557 * ControlService [ADVAPI32.@]
559 * Send a control code to a service.
562 * hService [I] Handle of the service control manager database
563 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
564 * lpServiceStatus [O] Destination for the status of the service, if available
570 BOOL WINAPI
ControlService( SC_HANDLE hService
, DWORD dwControl
,
571 LPSERVICE_STATUS lpServiceStatus
)
573 FIXME("(%p,%ld,%p): stub\n",hService
,dwControl
,lpServiceStatus
);
578 /******************************************************************************
579 * CloseServiceHandle [ADVAPI32.@]
581 * Close a handle to a service or the service control manager database.
584 * hSCObject [I] Handle to service or service control manager database
591 CloseServiceHandle( SC_HANDLE hSCObject
)
593 TRACE("(%p)\n", hSCObject
);
595 free_sc_handle( (struct sc_handle
*) hSCObject
);
601 /******************************************************************************
602 * OpenServiceA [ADVAPI32.@]
604 * Open a handle to a service.
607 * hSCManager [I] Handle of the service control manager database
608 * lpServiceName [I] Name of the service to open
609 * dwDesiredAccess [I] Access required to the service
612 * Success: Handle to the service
615 SC_HANDLE WINAPI
OpenServiceA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
616 DWORD dwDesiredAccess
)
618 UNICODE_STRING lpServiceNameW
;
620 RtlCreateUnicodeStringFromAsciiz (&lpServiceNameW
,lpServiceName
);
622 TRACE("Request for service %s\n",lpServiceName
);
625 ret
= OpenServiceW( hSCManager
, lpServiceNameW
.Buffer
, dwDesiredAccess
);
626 RtlFreeUnicodeString(&lpServiceNameW
);
631 /******************************************************************************
632 * OpenServiceW [ADVAPI32.@]
636 SC_HANDLE WINAPI
OpenServiceW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
637 DWORD dwDesiredAccess
)
639 struct sc_handle
*hscm
= hSCManager
;
640 struct sc_handle
*retval
;
644 TRACE("(%p,%p,%ld)\n",hSCManager
, lpServiceName
,
647 retval
= alloc_sc_handle( SC_HTYPE_SERVICE
);
651 r
= RegOpenKeyExW( hscm
->u
.manager
.hkey_scm_db
,
652 lpServiceName
, 0, KEY_ALL_ACCESS
, &hKey
);
653 if (r
!=ERROR_SUCCESS
)
655 free_sc_handle( retval
);
656 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST
);
660 init_service_handle( retval
, hscm
, hKey
, lpServiceName
);
662 TRACE("returning %p\n",retval
);
664 return (SC_HANDLE
) retval
;
667 /******************************************************************************
668 * CreateServiceW [ADVAPI32.@]
671 CreateServiceW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
672 LPCWSTR lpDisplayName
, DWORD dwDesiredAccess
,
673 DWORD dwServiceType
, DWORD dwStartType
,
674 DWORD dwErrorControl
, LPCWSTR lpBinaryPathName
,
675 LPCWSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
,
676 LPCWSTR lpDependencies
, LPCWSTR lpServiceStartName
,
679 struct sc_handle
*hscm
= hSCManager
;
680 struct sc_handle
*retval
;
684 static const WCHAR szDisplayName
[] = { 'D','i','s','p','l','a','y','N','a','m','e', 0 };
685 static const WCHAR szType
[] = {'T','y','p','e',0};
686 static const WCHAR szStart
[] = {'S','t','a','r','t',0};
687 static const WCHAR szError
[] = {'E','r','r','o','r','C','o','n','t','r','o','l', 0};
688 static const WCHAR szImagePath
[] = {'I','m','a','g','e','P','a','t','h',0};
689 static const WCHAR szGroup
[] = {'G','r','o','u','p',0};
690 static const WCHAR szDependencies
[] = { 'D','e','p','e','n','d','e','n','c','i','e','s',0};
692 FIXME("%p %s %s\n", hSCManager
,
693 debugstr_w(lpServiceName
), debugstr_w(lpDisplayName
));
695 retval
= alloc_sc_handle( SC_HTYPE_SERVICE
);
699 r
= RegCreateKeyExW(hscm
->u
.manager
.hkey_scm_db
, lpServiceName
, 0, NULL
,
700 REG_OPTION_NON_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &hKey
, &dp
);
701 if (r
!=ERROR_SUCCESS
)
704 init_service_handle( retval
, hscm
, hKey
, lpServiceName
);
706 if (dp
!= REG_CREATED_NEW_KEY
)
711 r
= RegSetValueExW(hKey
, szDisplayName
, 0, REG_SZ
, (LPBYTE
)lpDisplayName
,
712 (strlenW(lpDisplayName
)+1)*sizeof(WCHAR
) );
713 if (r
!=ERROR_SUCCESS
)
717 r
= RegSetValueExW(hKey
, szType
, 0, REG_DWORD
, (LPVOID
)&dwServiceType
, sizeof (DWORD
) );
718 if (r
!=ERROR_SUCCESS
)
721 r
= RegSetValueExW(hKey
, szStart
, 0, REG_DWORD
, (LPVOID
)&dwStartType
, sizeof (DWORD
) );
722 if (r
!=ERROR_SUCCESS
)
725 r
= RegSetValueExW(hKey
, szError
, 0, REG_DWORD
,
726 (LPVOID
)&dwErrorControl
, sizeof (DWORD
) );
727 if (r
!=ERROR_SUCCESS
)
732 r
= RegSetValueExW(hKey
, szImagePath
, 0, REG_SZ
, (LPBYTE
)lpBinaryPathName
,
733 (strlenW(lpBinaryPathName
)+1)*sizeof(WCHAR
) );
734 if (r
!=ERROR_SUCCESS
)
740 r
= RegSetValueExW(hKey
, szGroup
, 0, REG_SZ
, (LPBYTE
)lpLoadOrderGroup
,
741 (strlenW(lpLoadOrderGroup
)+1)*sizeof(WCHAR
) );
742 if (r
!=ERROR_SUCCESS
)
750 /* determine the length of a double null terminated multi string */
752 len
+= (strlenW(&lpDependencies
[len
])+1);
753 } while (lpDependencies
[len
++]);
755 r
= RegSetValueExW(hKey
, szDependencies
, 0, REG_MULTI_SZ
,
756 (LPBYTE
)lpDependencies
, len
);
757 if (r
!=ERROR_SUCCESS
)
763 FIXME("Don't know how to add a Password for a service.\n");
766 if(lpServiceStartName
)
768 FIXME("Don't know how to add a ServiceStartName for a service.\n");
771 return (SC_HANDLE
) retval
;
774 free_sc_handle( retval
);
779 static inline LPWSTR
SERV_dup( LPCSTR str
)
786 len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
787 wstr
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof (WCHAR
) );
788 MultiByteToWideChar( CP_ACP
, 0, str
, -1, wstr
, len
);
792 static inline LPWSTR
SERV_dupmulti( LPCSTR str
)
800 len
+= MultiByteToWideChar( CP_ACP
, 0, &str
[n
], -1, NULL
, 0 );
801 n
+= (strlen( &str
[n
] ) + 1);
806 wstr
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof (WCHAR
) );
807 MultiByteToWideChar( CP_ACP
, 0, str
, n
, wstr
, len
);
811 static inline VOID
SERV_free( LPWSTR wstr
)
813 HeapFree( GetProcessHeap(), 0, wstr
);
816 /******************************************************************************
817 * CreateServiceA [ADVAPI32.@]
820 CreateServiceA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
821 LPCSTR lpDisplayName
, DWORD dwDesiredAccess
,
822 DWORD dwServiceType
, DWORD dwStartType
,
823 DWORD dwErrorControl
, LPCSTR lpBinaryPathName
,
824 LPCSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
,
825 LPCSTR lpDependencies
, LPCSTR lpServiceStartName
,
828 LPWSTR lpServiceNameW
, lpDisplayNameW
, lpBinaryPathNameW
,
829 lpLoadOrderGroupW
, lpDependenciesW
, lpServiceStartNameW
, lpPasswordW
;
832 TRACE("%p %s %s\n", hSCManager
,
833 debugstr_a(lpServiceName
), debugstr_a(lpDisplayName
));
835 lpServiceNameW
= SERV_dup( lpServiceName
);
836 lpDisplayNameW
= SERV_dup( lpDisplayName
);
837 lpBinaryPathNameW
= SERV_dup( lpBinaryPathName
);
838 lpLoadOrderGroupW
= SERV_dup( lpLoadOrderGroup
);
839 lpDependenciesW
= SERV_dupmulti( lpDependencies
);
840 lpServiceStartNameW
= SERV_dup( lpServiceStartName
);
841 lpPasswordW
= SERV_dup( lpPassword
);
843 r
= CreateServiceW( hSCManager
, lpServiceNameW
, lpDisplayNameW
,
844 dwDesiredAccess
, dwServiceType
, dwStartType
, dwErrorControl
,
845 lpBinaryPathNameW
, lpLoadOrderGroupW
, lpdwTagId
,
846 lpDependenciesW
, lpServiceStartNameW
, lpPasswordW
);
848 SERV_free( lpServiceNameW
);
849 SERV_free( lpDisplayNameW
);
850 SERV_free( lpBinaryPathNameW
);
851 SERV_free( lpLoadOrderGroupW
);
852 SERV_free( lpDependenciesW
);
853 SERV_free( lpServiceStartNameW
);
854 SERV_free( lpPasswordW
);
860 /******************************************************************************
861 * DeleteService [ADVAPI32.@]
863 * Delete a service from the service control manager database.
866 * hService [I] Handle of the service to delete
872 BOOL WINAPI
DeleteService( SC_HANDLE hService
)
874 struct sc_handle
*hsvc
= hService
;
875 HKEY hKey
= hsvc
->u
.service
.hkey
;
876 WCHAR valname
[MAX_PATH
+1];
882 /* Clean out the values */
883 rc
= RegEnumValueW(hKey
, index
, valname
,&size
,0,0,0,0);
884 while (rc
== ERROR_SUCCESS
)
886 RegDeleteValueW(hKey
,valname
);
889 rc
= RegEnumValueW(hKey
, index
, valname
, &size
,0,0,0,0);
893 hsvc
->u
.service
.hkey
= NULL
;
896 RegDeleteKeyW(hsvc
->u
.service
.sc_manager
->u
.manager
.hkey_scm_db
,
897 hsvc
->u
.service
.name
);
903 /******************************************************************************
904 * StartServiceA [ADVAPI32.@]
909 * hService [I] Handle of service
910 * dwNumServiceArgs [I] Number of arguments
911 * lpServiceArgVectors [I] Address of array of argument strings
914 * - NT implements this function using an obscure RPC call.
915 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
916 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
917 * - This will only work for shared address space. How should the service
918 * args be transferred when address spaces are separated?
919 * - Can only start one service at a time.
920 * - Has no concept of privilege.
927 StartServiceA( SC_HANDLE hService
, DWORD dwNumServiceArgs
,
928 LPCSTR
*lpServiceArgVectors
)
931 UNICODE_STRING usBuffer
;
934 TRACE("(%p,%ld,%p)\n",hService
,dwNumServiceArgs
,lpServiceArgVectors
);
937 lpwstr
= (LPWSTR
*) HeapAlloc( GetProcessHeap(), 0,
938 dwNumServiceArgs
*sizeof(LPWSTR
) );
942 for(i
=0; i
<dwNumServiceArgs
; i
++)
944 RtlCreateUnicodeStringFromAsciiz (&usBuffer
,lpServiceArgVectors
[i
]);
945 lpwstr
[i
]=usBuffer
.Buffer
;
948 StartServiceW(hService
, dwNumServiceArgs
, (LPCWSTR
*)lpwstr
);
952 for(i
=0; i
<dwNumServiceArgs
; i
++)
953 HeapFree(GetProcessHeap(), 0, lpwstr
[i
]);
954 HeapFree(GetProcessHeap(), 0, lpwstr
);
961 /******************************************************************************
962 * StartServiceW [ADVAPI32.@]
967 StartServiceW( SC_HANDLE hService
, DWORD dwNumServiceArgs
,
968 LPCWSTR
*lpServiceArgVectors
)
970 static const WCHAR _WaitServiceStartW
[] = {'A','D','V','A','P','I','_','W',
971 'a','i','t','S','e','r','v','i',
972 'c','e','S','t','a','r','t',0};
973 static const WCHAR _ImagePathW
[] = {'I','m','a','g','e','P','a','t','h',0};
975 struct sc_handle
*hsvc
= hService
;
976 WCHAR path
[MAX_PATH
],str
[MAX_PATH
];
981 HANDLE hServiceShmem
= NULL
;
983 LPWSTR shmem_lock
= NULL
;
984 struct SEB
*seb
= NULL
;
986 PROCESS_INFORMATION procinfo
;
987 STARTUPINFOW startupinfo
;
990 TRACE("(%p,%ld,%p)\n",hService
,dwNumServiceArgs
,
991 lpServiceArgVectors
);
994 r
= RegQueryValueExW(hsvc
->u
.service
.hkey
, _ImagePathW
, NULL
, &type
, (LPVOID
)str
, &size
);
995 if (r
!=ERROR_SUCCESS
)
997 ExpandEnvironmentStringsW(str
,path
,sizeof(path
));
999 TRACE("Starting service %s\n", debugstr_w(path
) );
1001 hLock
= LockServiceDatabase( hsvc
->u
.service
.sc_manager
);
1006 * FIXME: start dependent services
1009 /* pass argv[0] (service name) to the service via global SCM lock object */
1010 shmem_lock
= MapViewOfFile( hLock
, FILE_MAP_ALL_ACCESS
,
1011 0, 0, MAX_SERVICE_NAME
* sizeof(WCHAR
) );
1012 if( NULL
== shmem_lock
)
1014 ERR("Couldn't map shared memory\n");
1017 strcpyW( shmem_lock
, hsvc
->u
.service
.name
);
1019 /* create service environment block */
1020 size
= sizeof(struct SEB
);
1021 for( i
= 0; i
< dwNumServiceArgs
; i
++ )
1022 size
+= sizeof(WCHAR
) * (1 + strlenW( lpServiceArgVectors
[ i
] ));
1024 snprintfW( str
, MAX_PATH
, szServiceShmemNameFmtW
, hsvc
->u
.service
.name
);
1025 hServiceShmem
= CreateFileMappingW( INVALID_HANDLE_VALUE
,
1026 NULL
, PAGE_READWRITE
, 0, size
, str
);
1027 if( NULL
== hServiceShmem
)
1029 ERR("Couldn't create shared memory object\n");
1032 if( GetLastError() == ERROR_ALREADY_EXISTS
)
1034 SetLastError( ERROR_SERVICE_ALREADY_RUNNING
);
1037 seb
= MapViewOfFile( hServiceShmem
, FILE_MAP_ALL_ACCESS
, 0, 0, 0 );
1040 ERR("Couldn't map shared memory\n");
1044 /* copy service args to SEB */
1045 seb
->argc
= dwNumServiceArgs
;
1046 argptr
= (LPWSTR
) &seb
[1];
1047 for( i
= 0; i
< dwNumServiceArgs
; i
++ )
1049 strcpyW( argptr
, lpServiceArgVectors
[ i
] );
1050 argptr
+= 1 + strlenW( argptr
);
1053 wait
= CreateSemaphoreW(NULL
,0,1,_WaitServiceStartW
);
1056 ERR("Couldn't create wait semaphore\n");
1060 ZeroMemory(&startupinfo
,sizeof(STARTUPINFOW
));
1061 startupinfo
.cb
= sizeof(STARTUPINFOW
);
1063 r
= CreateProcessW(NULL
,
1065 NULL
, /* process security attribs */
1066 NULL
, /* thread security attribs */
1067 FALSE
, /* inherit handles */
1068 0, /* creation flags */
1069 NULL
, /* environment */
1070 NULL
, /* current directory */
1071 &startupinfo
, /* startup info */
1072 &procinfo
); /* process info */
1076 ERR("Couldn't start process\n");
1079 CloseHandle( procinfo
.hThread
);
1081 /* docs for StartServiceCtrlDispatcher say this should be 30 sec */
1082 r
= WaitForSingleObject(wait
,30000);
1083 if( WAIT_FAILED
== r
)
1085 CloseHandle( procinfo
.hProcess
);
1090 CloseHandle( procinfo
.hProcess
);
1094 if( wait
) CloseHandle( wait
);
1095 if( seb
!= NULL
) UnmapViewOfFile( seb
);
1096 if( hServiceShmem
!= NULL
) CloseHandle( hServiceShmem
);
1097 if( shmem_lock
!= NULL
) UnmapViewOfFile( shmem_lock
);
1098 UnlockServiceDatabase( hLock
);
1102 /******************************************************************************
1103 * QueryServiceStatus [ADVAPI32.@]
1107 * lpservicestatus []
1111 QueryServiceStatus( SC_HANDLE hService
, LPSERVICE_STATUS lpservicestatus
)
1113 struct sc_handle
*hsvc
= hService
;
1115 DWORD type
, val
, size
;
1117 FIXME("(%p,%p) partial\n",hService
,lpservicestatus
);
1119 /* read the service type from the registry */
1121 r
= RegQueryValueExA(hsvc
->u
.service
.hkey
, "Type", NULL
, &type
, (LPBYTE
)&val
, &size
);
1124 ERR("invalid Type\n");
1127 lpservicestatus
->dwServiceType
= val
;
1128 /* FIXME: how are these determined or read from the registry? */
1129 /* SERVICE: unavailable=0, stopped=1, starting=2, running=3? */;
1130 lpservicestatus
->dwCurrentState
= 1;
1131 lpservicestatus
->dwControlsAccepted
= 0;
1132 lpservicestatus
->dwWin32ExitCode
= NO_ERROR
;
1133 lpservicestatus
->dwServiceSpecificExitCode
= 0;
1134 lpservicestatus
->dwCheckPoint
= 0;
1135 lpservicestatus
->dwWaitHint
= 0;
1140 /******************************************************************************
1141 * QueryServiceStatusEx [ADVAPI32.@]
1143 * Get information about a service.
1146 * hService [I] Handle to service to get information about
1147 * InfoLevel [I] Level of information to get
1148 * lpBuffer [O] Destination for requested information
1149 * cbBufSize [I] Size of lpBuffer in bytes
1150 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1156 BOOL WINAPI
QueryServiceStatusEx(SC_HANDLE hService
, SC_STATUS_TYPE InfoLevel
,
1157 LPBYTE lpBuffer
, DWORD cbBufSize
,
1158 LPDWORD pcbBytesNeeded
)
1161 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1165 /******************************************************************************
1166 * QueryServiceConfigA [ADVAPI32.@]
1169 QueryServiceConfigA( SC_HANDLE hService
,
1170 LPQUERY_SERVICE_CONFIGA lpServiceConfig
,
1171 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
1173 static const CHAR szDisplayName
[] = "DisplayName";
1174 static const CHAR szType
[] = "Type";
1175 static const CHAR szStart
[] = "Start";
1176 static const CHAR szError
[] = "ErrorControl";
1177 static const CHAR szImagePath
[] = "ImagePath";
1178 static const CHAR szGroup
[] = "Group";
1179 static const CHAR szDependencies
[] = "Dependencies";
1180 HKEY hKey
= ((struct sc_handle
*) hService
)->u
.service
.hkey
;
1181 CHAR str_buffer
[ MAX_PATH
];
1183 DWORD type
, val
, sz
, total
, n
;
1186 TRACE("%p %p %ld %p\n", hService
, lpServiceConfig
,
1187 cbBufSize
, pcbBytesNeeded
);
1189 /* calculate the size required first */
1190 total
= sizeof (QUERY_SERVICE_CONFIGA
);
1192 sz
= sizeof(str_buffer
);
1193 r
= RegQueryValueExA( hKey
, szImagePath
, 0, &type
, str_buffer
, &sz
);
1194 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
|| type
== REG_EXPAND_SZ
) )
1196 sz
= ExpandEnvironmentStringsA(str_buffer
,NULL
,0);
1197 if( 0 == sz
) return FALSE
;
1203 /* FIXME: set last error */
1208 r
= RegQueryValueExA( hKey
, szGroup
, 0, &type
, NULL
, &sz
);
1209 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1213 r
= RegQueryValueExA( hKey
, szDependencies
, 0, &type
, NULL
, &sz
);
1214 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_MULTI_SZ
) )
1218 r
= RegQueryValueExA( hKey
, szStart
, 0, &type
, NULL
, &sz
);
1219 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1223 r
= RegQueryValueExA( hKey
, szDisplayName
, 0, &type
, NULL
, &sz
);
1224 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1227 /* if there's not enough memory, return an error */
1228 if( total
> *pcbBytesNeeded
)
1230 *pcbBytesNeeded
= total
;
1231 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1235 *pcbBytesNeeded
= total
;
1236 ZeroMemory( lpServiceConfig
, total
);
1239 r
= RegQueryValueExA( hKey
, szType
, 0, &type
, (LPBYTE
)&val
, &sz
);
1240 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_DWORD
) )
1241 lpServiceConfig
->dwServiceType
= val
;
1244 r
= RegQueryValueExA( hKey
, szStart
, 0, &type
, (LPBYTE
)&val
, &sz
);
1245 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_DWORD
) )
1246 lpServiceConfig
->dwStartType
= val
;
1249 r
= RegQueryValueExA( hKey
, szError
, 0, &type
, (LPBYTE
)&val
, &sz
);
1250 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_DWORD
) )
1251 lpServiceConfig
->dwErrorControl
= val
;
1253 /* now do the strings */
1254 p
= (LPBYTE
) &lpServiceConfig
[1];
1255 n
= total
- sizeof (QUERY_SERVICE_CONFIGA
);
1257 sz
= sizeof(str_buffer
);
1258 r
= RegQueryValueExA( hKey
, szImagePath
, 0, &type
, str_buffer
, &sz
);
1259 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
|| type
== REG_EXPAND_SZ
) )
1261 sz
= ExpandEnvironmentStringsA(str_buffer
, p
, n
);
1262 if( 0 == sz
|| sz
> n
) return FALSE
;
1264 lpServiceConfig
->lpBinaryPathName
= (LPSTR
) p
;
1270 /* FIXME: set last error */
1275 r
= RegQueryValueExA( hKey
, szGroup
, 0, &type
, p
, &sz
);
1276 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_SZ
) )
1278 lpServiceConfig
->lpLoadOrderGroup
= (LPSTR
) p
;
1284 r
= RegQueryValueExA( hKey
, szDependencies
, 0, &type
, p
, &sz
);
1285 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_SZ
) )
1287 lpServiceConfig
->lpDependencies
= (LPSTR
) p
;
1293 ERR("Buffer overflow!\n");
1295 TRACE("Image path = %s\n", lpServiceConfig
->lpBinaryPathName
);
1296 TRACE("Group = %s\n", lpServiceConfig
->lpLoadOrderGroup
);
1301 /******************************************************************************
1302 * QueryServiceConfigW [ADVAPI32.@]
1305 QueryServiceConfigW( SC_HANDLE hService
,
1306 LPQUERY_SERVICE_CONFIGW lpServiceConfig
,
1307 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
1309 static const WCHAR szDisplayName
[] = {
1310 'D','i','s','p','l','a','y','N','a','m','e', 0 };
1311 static const WCHAR szType
[] = {'T','y','p','e',0};
1312 static const WCHAR szStart
[] = {'S','t','a','r','t',0};
1313 static const WCHAR szError
[] = {
1314 'E','r','r','o','r','C','o','n','t','r','o','l', 0};
1315 static const WCHAR szImagePath
[] = {'I','m','a','g','e','P','a','t','h',0};
1316 static const WCHAR szGroup
[] = {'G','r','o','u','p',0};
1317 static const WCHAR szDependencies
[] = {
1318 'D','e','p','e','n','d','e','n','c','i','e','s',0};
1319 HKEY hKey
= ((struct sc_handle
*) hService
)->u
.service
.hkey
;
1320 WCHAR str_buffer
[ MAX_PATH
];
1322 DWORD type
, val
, sz
, total
, n
;
1325 TRACE("%p %p %ld %p\n", hService
, lpServiceConfig
,
1326 cbBufSize
, pcbBytesNeeded
);
1328 /* calculate the size required first */
1329 total
= sizeof (QUERY_SERVICE_CONFIGW
);
1331 sz
= sizeof(str_buffer
);
1332 r
= RegQueryValueExW( hKey
, szImagePath
, 0, &type
, (LPBYTE
) str_buffer
, &sz
);
1333 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
|| type
== REG_EXPAND_SZ
) )
1335 sz
= ExpandEnvironmentStringsW(str_buffer
,NULL
,0);
1336 if( 0 == sz
) return FALSE
;
1338 total
+= sizeof(WCHAR
) * sz
;
1342 /* FIXME: set last error */
1347 r
= RegQueryValueExW( hKey
, szGroup
, 0, &type
, NULL
, &sz
);
1348 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1352 r
= RegQueryValueExW( hKey
, szDependencies
, 0, &type
, NULL
, &sz
);
1353 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_MULTI_SZ
) )
1357 r
= RegQueryValueExW( hKey
, szStart
, 0, &type
, NULL
, &sz
);
1358 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1362 r
= RegQueryValueExW( hKey
, szDisplayName
, 0, &type
, NULL
, &sz
);
1363 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1366 /* if there's not enough memory, return an error */
1367 if( total
> *pcbBytesNeeded
)
1369 *pcbBytesNeeded
= total
;
1370 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1374 *pcbBytesNeeded
= total
;
1375 ZeroMemory( lpServiceConfig
, total
);
1378 r
= RegQueryValueExW( hKey
, szType
, 0, &type
, (LPBYTE
)&val
, &sz
);
1379 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_DWORD
) )
1380 lpServiceConfig
->dwServiceType
= val
;
1383 r
= RegQueryValueExW( hKey
, szStart
, 0, &type
, (LPBYTE
)&val
, &sz
);
1384 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_DWORD
) )
1385 lpServiceConfig
->dwStartType
= val
;
1388 r
= RegQueryValueExW( hKey
, szError
, 0, &type
, (LPBYTE
)&val
, &sz
);
1389 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_DWORD
) )
1390 lpServiceConfig
->dwErrorControl
= val
;
1392 /* now do the strings */
1393 p
= (LPBYTE
) &lpServiceConfig
[1];
1394 n
= total
- sizeof (QUERY_SERVICE_CONFIGW
);
1396 sz
= sizeof(str_buffer
);
1397 r
= RegQueryValueExW( hKey
, szImagePath
, 0, &type
, (LPBYTE
) str_buffer
, &sz
);
1398 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
|| type
== REG_EXPAND_SZ
) )
1400 sz
= ExpandEnvironmentStringsW(str_buffer
, (LPWSTR
) p
, n
);
1401 sz
*= sizeof(WCHAR
);
1402 if( 0 == sz
|| sz
> n
) return FALSE
;
1404 lpServiceConfig
->lpBinaryPathName
= (LPWSTR
) p
;
1410 /* FIXME: set last error */
1415 r
= RegQueryValueExW( hKey
, szGroup
, 0, &type
, p
, &sz
);
1416 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_SZ
) )
1418 lpServiceConfig
->lpLoadOrderGroup
= (LPWSTR
) p
;
1424 r
= RegQueryValueExW( hKey
, szDependencies
, 0, &type
, p
, &sz
);
1425 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_SZ
) )
1427 lpServiceConfig
->lpDependencies
= (LPWSTR
) p
;
1433 ERR("Buffer overflow!\n");
1435 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig
->lpBinaryPathName
) );
1436 TRACE("Group = %s\n", debugstr_w(lpServiceConfig
->lpLoadOrderGroup
) );
1441 /******************************************************************************
1442 * ChangeServiceConfigW [ADVAPI32.@]
1444 BOOL WINAPI
ChangeServiceConfigW( SC_HANDLE hService
, DWORD dwServiceType
,
1445 DWORD dwStartType
, DWORD dwErrorControl
, LPCWSTR lpBinaryPathName
,
1446 LPCWSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
, LPCWSTR lpDependencies
,
1447 LPCWSTR lpServiceStartName
, LPCWSTR lpPassword
, LPCWSTR lpDisplayName
)
1449 FIXME("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
1450 hService
, dwServiceType
, dwStartType
, dwErrorControl
,
1451 debugstr_w(lpBinaryPathName
), debugstr_w(lpLoadOrderGroup
),
1452 lpdwTagId
, lpDependencies
, debugstr_w(lpServiceStartName
),
1453 debugstr_w(lpPassword
), debugstr_w(lpDisplayName
) );
1457 /******************************************************************************
1458 * ChangeServiceConfigA [ADVAPI32.@]
1460 BOOL WINAPI
ChangeServiceConfigA( SC_HANDLE hService
, DWORD dwServiceType
,
1461 DWORD dwStartType
, DWORD dwErrorControl
, LPCSTR lpBinaryPathName
,
1462 LPCSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
, LPCSTR lpDependencies
,
1463 LPCSTR lpServiceStartName
, LPCSTR lpPassword
, LPCSTR lpDisplayName
)
1465 FIXME("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
1466 hService
, dwServiceType
, dwStartType
, dwErrorControl
,
1467 debugstr_a(lpBinaryPathName
), debugstr_a(lpLoadOrderGroup
),
1468 lpdwTagId
, lpDependencies
, debugstr_a(lpServiceStartName
),
1469 debugstr_a(lpPassword
), debugstr_a(lpDisplayName
) );
1473 /******************************************************************************
1474 * ChangeServiceConfig2A [ADVAPI32.@]
1476 BOOL WINAPI
ChangeServiceConfig2A( SC_HANDLE hService
, DWORD dwInfoLevel
,
1479 FIXME("STUB: %p %ld %p\n",hService
, dwInfoLevel
, lpInfo
);
1483 /******************************************************************************
1484 * ChangeServiceConfig2W [ADVAPI32.@]
1486 BOOL WINAPI
ChangeServiceConfig2W( SC_HANDLE hService
, DWORD dwInfoLevel
,
1489 HKEY hKey
= ((struct sc_handle
*) hService
)->u
.service
.hkey
;
1491 if (dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
1493 static const WCHAR szDescription
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
1494 LPSERVICE_DESCRIPTIONW sd
= (LPSERVICE_DESCRIPTIONW
)lpInfo
;
1495 if (sd
->lpDescription
)
1497 TRACE("Setting Description to %s\n",debugstr_w(sd
->lpDescription
));
1498 if (sd
->lpDescription
[0] == 0)
1499 RegDeleteValueW(hKey
,szDescription
);
1501 RegSetValueExW(hKey
, szDescription
, 0, REG_SZ
,
1502 (LPVOID
)sd
->lpDescription
,
1503 sizeof(WCHAR
)*(strlenW(sd
->lpDescription
)+1));
1507 FIXME("STUB: %p %ld %p\n",hService
, dwInfoLevel
, lpInfo
);
1511 /******************************************************************************
1512 * QueryServiceObjectSecurity [ADVAPI32.@]
1514 BOOL WINAPI
QueryServiceObjectSecurity(SC_HANDLE hService
,
1515 SECURITY_INFORMATION dwSecurityInformation
,
1516 PSECURITY_DESCRIPTOR lpSecurityDescriptor
,
1517 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
1519 FIXME("%p %ld %p %lu %p\n", hService
, dwSecurityInformation
,
1520 lpSecurityDescriptor
, cbBufSize
, pcbBytesNeeded
);
1521 return ERROR_CALL_NOT_IMPLEMENTED
;