Pass arguments to the service program.
[wine/multimedia.git] / dlls / advapi32 / service.c
blob80889e6fafcbed2d90f2f214fc54753ec412ab7b
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 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',
41 'L','O','C','K',0};
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 */
47 DWORD argc;
48 /* variable part of SEB contains service arguments */
51 /******************************************************************************
52 * SC_HANDLEs
55 #define MAX_SERVICE_NAME 256
57 typedef enum { SC_HTYPE_MANAGER, SC_HTYPE_SERVICE } SC_HANDLE_TYPE;
59 struct sc_handle;
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 ];
75 struct sc_handle
77 SC_HANDLE_TYPE htype;
78 union
80 struct sc_manager manager;
81 struct sc_service service;
82 } u;
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) );
90 if( retval != NULL )
92 retval->htype = htype;
94 TRACE("SC_HANDLE type=%d -> %p\n",htype,retval);
95 return retval;
98 static void free_sc_handle( struct sc_handle* handle )
100 if( NULL == handle )
101 return;
103 switch( handle->htype )
105 case SC_HTYPE_MANAGER:
107 if( InterlockedDecrement( &handle->u.manager.ref_count ) )
108 /* there are references to this handle */
109 return;
111 if( handle->u.manager.hkey_scm_db )
112 RegCloseKey( handle->u.manager.hkey_scm_db );
113 break;
116 case SC_HTYPE_SERVICE:
118 struct sc_handle *h = handle->u.service.sc_manager;
120 if( h )
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 );
136 break;
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.@]
161 BOOL WINAPI
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);
170 return FALSE;
173 /******************************************************************************
174 * EnumServicesStatusW [ADVAPI32.@]
176 BOOL WINAPI
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);
185 return FALSE;
188 /******************************************************************************
189 * read_scm_lock_data
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 )
198 HANDLE hLock;
199 LPWSTR argptr;
201 hLock = OpenFileMappingW( FILE_MAP_ALL_ACCESS, FALSE, szSCMLock );
202 if( NULL == hLock )
204 SetLastError( ERROR_FAILED_SERVICE_CONTROLLER_CONNECT );
205 return FALSE;
207 argptr = MapViewOfFile( hLock, FILE_MAP_ALL_ACCESS,
208 0, 0, MAX_SERVICE_NAME * sizeof(WCHAR) );
209 if( NULL == argptr )
211 CloseHandle( hLock );
212 return FALSE;
214 strcpyW( buffer, argptr );
215 UnmapViewOfFile( argptr );
216 CloseHandle( hLock );
217 return TRUE;
220 /******************************************************************************
221 * build_arg_vectors
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 )
231 LPWSTR *ret;
232 LPWSTR argptr;
233 DWORD i;
235 ret = HeapAlloc( GetProcessHeap(), 0, (1 + seb->argc) * sizeof(LPWSTR) );
236 if( NULL == ret )
237 return NULL;
239 argptr = (LPWSTR) &seb[1];
240 for( i = 0; i < seb->argc; i++ )
242 ret[ 1 + i ] = argptr;
243 argptr += 1 + strlenW( argptr );
245 return ret;
248 /******************************************************************************
249 * StartServiceCtrlDispatcherA [ADVAPI32.@]
251 BOOL WINAPI
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;
261 LPSTR *lpArgVecA;
262 unsigned int i;
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;
275 lpArgVecA = NULL;
276 goto run_service;
279 snprintfW( object_name, MAX_PATH, szServiceShmemNameFmtW, service_name );
280 hServiceShmem = OpenFileMappingW( FILE_MAP_ALL_ACCESS, FALSE, object_name );
281 if( NULL == hServiceShmem )
282 return FALSE;
284 seb = MapViewOfFile( hServiceShmem, FILE_MAP_ALL_ACCESS, 0, 0, 0 );
285 if( NULL == seb )
287 CloseHandle( hServiceShmem );
288 return FALSE;
291 lpArgVecW = build_arg_vectors( seb );
292 if( NULL == lpArgVecW )
294 UnmapViewOfFile( seb );
295 CloseHandle( hServiceShmem );
296 return FALSE;
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]);
307 run_service:
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);
316 servent++;
319 if(dwNumServiceArgs)
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 );
330 return TRUE;
333 /******************************************************************************
334 * StartServiceCtrlDispatcherW [ADVAPI32.@]
336 * PARAMS
337 * servent []
339 BOOL WINAPI
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;
346 struct SEB *seb;
347 DWORD dwNumServiceArgs ;
348 LPWSTR *lpServiceArgVectors ;
350 TRACE("(%p)\n", servent);
352 if( ! read_scm_lock_data( service_name ) )
353 return FALSE;
355 snprintfW( object_name, MAX_PATH, szServiceShmemNameFmtW, service_name );
356 hServiceShmem = OpenFileMappingW( FILE_MAP_ALL_ACCESS, FALSE, object_name );
357 if( NULL == hServiceShmem )
358 return FALSE;
360 seb = MapViewOfFile( hServiceShmem, FILE_MAP_ALL_ACCESS, 0, 0, 0 );
361 if( NULL == seb )
363 CloseHandle( hServiceShmem );
364 return FALSE;
367 lpServiceArgVectors = build_arg_vectors( seb );
368 if( NULL == lpServiceArgVectors )
370 UnmapViewOfFile( seb );
371 CloseHandle( hServiceShmem );
372 return FALSE;
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);
385 servent++;
388 HeapFree( GetProcessHeap(), 0, lpServiceArgVectors );
389 UnmapViewOfFile( seb );
390 CloseHandle( hServiceShmem );
391 return TRUE;
394 /******************************************************************************
395 * LockServiceDatabase [ADVAPI32.@]
397 LPVOID WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
399 HANDLE ret;
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 )
407 CloseHandle( ret );
408 ret = NULL;
409 SetLastError( ERROR_SERVICE_DATABASE_LOCKED );
412 TRACE("returning %p\n", ret);
414 return 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);
434 return 0xcacacafe;
437 /******************************************************************************
438 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
440 * PARAMS
441 * lpServiceName []
442 * lpfHandler []
444 SERVICE_STATUS_HANDLE WINAPI
445 RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName,
446 LPHANDLER_FUNCTION lpfHandler )
447 { FIXME("%s %p\n", debugstr_w(lpServiceName), lpfHandler);
448 return 0xcacacafe;
451 /******************************************************************************
452 * SetServiceStatus [ADVAPI32.@]
454 * PARAMS
455 * hService []
456 * lpStatus []
458 BOOL WINAPI
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);
468 return TRUE;
471 /******************************************************************************
472 * OpenSCManagerA [ADVAPI32.@]
474 * Establish a connection to the service control manager and open its database.
476 * PARAMS
477 * lpMachineName [I] Pointer to machine name string
478 * lpDatabaseName [I] Pointer to database name string
479 * dwDesiredAccess [I] Type of access
481 * RETURNS
482 * Success: A Handle to the service control manager database
483 * Failure: NULL
485 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
486 DWORD dwDesiredAccess )
488 UNICODE_STRING lpMachineNameW;
489 UNICODE_STRING lpDatabaseNameW;
490 SC_HANDLE ret;
492 RtlCreateUnicodeStringFromAsciiz (&lpMachineNameW,lpMachineName);
493 RtlCreateUnicodeStringFromAsciiz (&lpDatabaseNameW,lpDatabaseName);
494 ret = OpenSCManagerW(lpMachineNameW.Buffer,lpDatabaseNameW.Buffer, dwDesiredAccess);
495 RtlFreeUnicodeString(&lpDatabaseNameW);
496 RtlFreeUnicodeString(&lpMachineNameW);
497 return ret;
500 /******************************************************************************
501 * OpenSCManagerW [ADVAPI32.@]
503 * See OpenSCManagerA.
505 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
506 DWORD dwDesiredAccess )
508 struct sc_handle *retval;
509 HKEY hReg;
510 LONG r;
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)
528 goto error;
530 r = RegOpenKeyExW(hReg, szServiceManagerKey,
531 0, KEY_ALL_ACCESS, &retval->u.manager.hkey_scm_db);
532 RegCloseKey( hReg );
533 if (r!=ERROR_SUCCESS)
534 goto error;
536 TRACE("returning %p\n", retval);
538 return (SC_HANDLE) retval;
540 error:
541 free_sc_handle( retval );
542 return NULL;
546 /******************************************************************************
547 * AllocateLocallyUniqueId [ADVAPI32.@]
549 * PARAMS
550 * lpluid []
552 BOOL WINAPI
553 AllocateLocallyUniqueId( PLUID lpluid )
555 lpluid->LowPart = time(NULL);
556 lpluid->HighPart = 0;
557 return TRUE;
561 /******************************************************************************
562 * ControlService [ADVAPI32.@]
564 * Send a control code to a service.
566 * PARAMS
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
571 * RETURNS
572 * Success: TRUE.
573 * Failure: FALSE.
575 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
576 LPSERVICE_STATUS lpServiceStatus )
578 FIXME("(%p,%ld,%p): stub\n",hService,dwControl,lpServiceStatus);
579 return TRUE;
583 /******************************************************************************
584 * CloseServiceHandle [ADVAPI32.@]
586 * Close a handle to a service or the service control manager database.
588 * PARAMS
589 * hSCObject [I] Handle to service or service control manager database
591 * RETURNS
592 * Success: TRUE
593 * Failure: FALSE
595 BOOL WINAPI
596 CloseServiceHandle( SC_HANDLE hSCObject )
598 TRACE("(%p)\n", hSCObject);
600 free_sc_handle( (struct sc_handle*) hSCObject );
602 return TRUE;
606 /******************************************************************************
607 * OpenServiceA [ADVAPI32.@]
609 * Open a handle to a service.
611 * PARAMS
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
616 * RETURNS
617 * Success: Handle to the service
618 * Failure: NULL
620 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
621 DWORD dwDesiredAccess )
623 UNICODE_STRING lpServiceNameW;
624 SC_HANDLE ret;
625 RtlCreateUnicodeStringFromAsciiz (&lpServiceNameW,lpServiceName);
626 if(lpServiceName)
627 TRACE("Request for service %s\n",lpServiceName);
628 else
629 return FALSE;
630 ret = OpenServiceW( hSCManager, lpServiceNameW.Buffer, dwDesiredAccess);
631 RtlFreeUnicodeString(&lpServiceNameW);
632 return ret;
636 /******************************************************************************
637 * OpenServiceW [ADVAPI32.@]
639 * See OpenServiceA.
641 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
642 DWORD dwDesiredAccess)
644 struct sc_handle *hscm = hSCManager;
645 struct sc_handle *retval;
646 HKEY hKey;
647 long r;
649 TRACE("(%p,%p,%ld)\n",hSCManager, lpServiceName,
650 dwDesiredAccess);
652 retval = alloc_sc_handle( SC_HTYPE_SERVICE );
653 if( NULL == retval )
654 return NULL;
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 );
662 return NULL;
665 init_service_handle( retval, hscm, hKey, lpServiceName );
667 TRACE("returning %p\n",retval);
669 return (SC_HANDLE) retval;
672 /******************************************************************************
673 * CreateServiceW [ADVAPI32.@]
675 SC_HANDLE WINAPI
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,
682 LPCWSTR lpPassword )
684 struct sc_handle *hscm = hSCManager;
685 struct sc_handle *retval;
686 HKEY hKey;
687 LONG r;
688 DWORD dp;
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 );
701 if( NULL == retval )
702 return NULL;
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)
707 goto error;
709 init_service_handle( retval, hscm, hKey, lpServiceName );
711 if (dp != REG_CREATED_NEW_KEY)
712 goto error;
714 if(lpDisplayName)
716 r = RegSetValueExW(hKey, szDisplayName, 0, REG_SZ, (LPBYTE)lpDisplayName,
717 (strlenW(lpDisplayName)+1)*sizeof(WCHAR) );
718 if (r!=ERROR_SUCCESS)
719 goto error;
722 r = RegSetValueExW(hKey, szType, 0, REG_DWORD, (LPVOID)&dwServiceType, sizeof (DWORD) );
723 if (r!=ERROR_SUCCESS)
724 goto error;
726 r = RegSetValueExW(hKey, szStart, 0, REG_DWORD, (LPVOID)&dwStartType, sizeof (DWORD) );
727 if (r!=ERROR_SUCCESS)
728 goto error;
730 r = RegSetValueExW(hKey, szError, 0, REG_DWORD,
731 (LPVOID)&dwErrorControl, sizeof (DWORD) );
732 if (r!=ERROR_SUCCESS)
733 goto error;
735 if(lpBinaryPathName)
737 r = RegSetValueExW(hKey, szImagePath, 0, REG_SZ, (LPBYTE)lpBinaryPathName,
738 (strlenW(lpBinaryPathName)+1)*sizeof(WCHAR) );
739 if (r!=ERROR_SUCCESS)
740 goto error;
743 if(lpLoadOrderGroup)
745 r = RegSetValueExW(hKey, szGroup, 0, REG_SZ, (LPBYTE)lpLoadOrderGroup,
746 (strlenW(lpLoadOrderGroup)+1)*sizeof(WCHAR) );
747 if (r!=ERROR_SUCCESS)
748 goto error;
751 if(lpDependencies)
753 DWORD len = 0;
755 /* determine the length of a double null terminated multi string */
756 do {
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)
763 goto error;
766 if(lpPassword)
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;
778 error:
779 free_sc_handle( retval );
780 return NULL;
784 static inline LPWSTR SERV_dup( LPCSTR str )
786 UINT len;
787 LPWSTR wstr;
789 if( !str )
790 return NULL;
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 );
794 return wstr;
797 static inline LPWSTR SERV_dupmulti( LPCSTR str )
799 UINT len = 0, n = 0;
800 LPWSTR wstr;
802 if( !str )
803 return NULL;
804 do {
805 len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
806 n += (strlen( &str[n] ) + 1);
807 } while (str[n]);
808 len++;
809 n++;
811 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
812 MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
813 return wstr;
816 static inline VOID SERV_free( LPWSTR wstr )
818 HeapFree( GetProcessHeap(), 0, wstr );
821 /******************************************************************************
822 * CreateServiceA [ADVAPI32.@]
824 SC_HANDLE WINAPI
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,
831 LPCSTR lpPassword )
833 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
834 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
835 SC_HANDLE r;
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 );
861 return r;
865 /******************************************************************************
866 * DeleteService [ADVAPI32.@]
868 * Delete a service from the service control manager database.
870 * PARAMS
871 * hService [I] Handle of the service to delete
873 * RETURNS
874 * Success: TRUE
875 * Failure: FALSE
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];
882 INT index = 0;
883 LONG rc;
884 DWORD size;
886 size = 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);
892 index++;
893 size = MAX_PATH+1;
894 rc = RegEnumValueW(hKey, index, valname, &size,0,0,0,0);
897 RegCloseKey(hKey);
898 hsvc->u.service.hkey = NULL;
900 /* delete the key */
901 RegDeleteKeyW(hsvc->u.service.sc_manager->u.manager.hkey_scm_db,
902 hsvc->u.service.name);
904 return TRUE;
908 /******************************************************************************
909 * StartServiceA [ADVAPI32.@]
911 * Start a service
913 * PARAMS
914 * hService [I] Handle of service
915 * dwNumServiceArgs [I] Number of arguments
916 * lpServiceArgVectors [I] Address of array of argument strings
918 * NOTES
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.
927 * RETURNS
928 * Success: TRUE.
929 * Failure: FALSE
931 BOOL WINAPI
932 StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
933 LPCSTR *lpServiceArgVectors )
935 LPWSTR *lpwstr=NULL;
936 UNICODE_STRING usBuffer;
937 unsigned int i;
939 TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
941 if(dwNumServiceArgs)
942 lpwstr = (LPWSTR*) HeapAlloc( GetProcessHeap(), 0,
943 dwNumServiceArgs*sizeof(LPWSTR) );
944 else
945 lpwstr = NULL;
947 for(i=0; i<dwNumServiceArgs; i++)
949 RtlCreateUnicodeStringFromAsciiz (&usBuffer,lpServiceArgVectors[i]);
950 lpwstr[i]=usBuffer.Buffer;
953 StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
955 if(dwNumServiceArgs)
957 for(i=0; i<dwNumServiceArgs; i++)
958 HeapFree(GetProcessHeap(), 0, lpwstr[i]);
959 HeapFree(GetProcessHeap(), 0, lpwstr);
962 return TRUE;
966 /******************************************************************************
967 * StartServiceW [ADVAPI32.@]
969 * See StartServiceA.
971 BOOL WINAPI
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];
982 DWORD type,size;
983 DWORD i;
984 long r;
985 HANDLE hLock;
986 HANDLE hServiceShmem = NULL;
987 HANDLE wait = NULL;
988 LPWSTR shmem_lock = NULL;
989 struct SEB *seb = NULL;
990 LPWSTR argptr;
991 PROCESS_INFORMATION procinfo;
992 STARTUPINFOW startupinfo;
993 BOOL ret = FALSE;
995 TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,
996 lpServiceArgVectors);
998 size = sizeof(str);
999 r = RegQueryValueExW(hsvc->u.service.hkey, _ImagePathW, NULL, &type, (LPVOID)str, &size);
1000 if (r!=ERROR_SUCCESS)
1001 return FALSE;
1002 ExpandEnvironmentStringsW(str,path,sizeof(path));
1004 TRACE("Starting service %s\n", debugstr_w(path) );
1006 hLock = LockServiceDatabase( hsvc->u.service.sc_manager );
1007 if( NULL == hLock )
1008 return FALSE;
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");
1020 goto done;
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");
1035 goto done;
1037 if( GetLastError() == ERROR_ALREADY_EXISTS )
1039 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
1040 goto done;
1042 seb = MapViewOfFile( hServiceShmem, FILE_MAP_ALL_ACCESS, 0, 0, 0 );
1043 if( NULL == seb )
1045 ERR("Couldn't map shared memory\n");
1046 goto done;
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);
1059 if (!wait)
1061 ERR("Couldn't create wait semaphore\n");
1062 goto done;
1065 ZeroMemory(&startupinfo,sizeof(STARTUPINFOW));
1066 startupinfo.cb = sizeof(STARTUPINFOW);
1068 r = CreateProcessW(NULL,
1069 path,
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 */
1079 if(r == FALSE)
1081 ERR("Couldn't start process\n");
1082 goto done;
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 );
1091 goto done;
1094 /* allright */
1095 CloseHandle( procinfo.hProcess );
1096 ret = TRUE;
1098 done:
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 );
1104 return ret;
1107 /******************************************************************************
1108 * QueryServiceStatus [ADVAPI32.@]
1110 * PARAMS
1111 * hService []
1112 * lpservicestatus []
1115 BOOL WINAPI
1116 QueryServiceStatus( SC_HANDLE hService, LPSERVICE_STATUS lpservicestatus )
1118 struct sc_handle *hsvc = hService;
1119 LONG r;
1120 DWORD type, val, size;
1122 FIXME("(%p,%p) partial\n",hService,lpservicestatus);
1124 /* read the service type from the registry */
1125 size = sizeof(val);
1126 r = RegQueryValueExA(hsvc->u.service.hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1127 if(type!=REG_DWORD)
1129 ERR("invalid Type\n");
1130 return FALSE;
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;
1142 return TRUE;
1145 /******************************************************************************
1146 * QueryServiceStatusEx [ADVAPI32.@]
1148 * Get information about a service.
1150 * PARAMS
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
1157 * RETURNS
1158 * Success: TRUE
1159 * FAILURE: FALSE
1161 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1162 LPBYTE lpBuffer, DWORD cbBufSize,
1163 LPDWORD pcbBytesNeeded)
1165 FIXME("stub\n");
1166 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1167 return FALSE;
1170 /******************************************************************************
1171 * QueryServiceConfigA [ADVAPI32.@]
1173 BOOL WINAPI
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 ];
1187 LONG r;
1188 DWORD type, val, sz, total, n;
1189 LPBYTE p;
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;
1204 total += sz;
1206 else
1208 /* FIXME: set last error */
1209 return FALSE;
1212 sz = 0;
1213 r = RegQueryValueExA( hKey, szGroup, 0, &type, NULL, &sz );
1214 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1215 total += sz;
1217 sz = 0;
1218 r = RegQueryValueExA( hKey, szDependencies, 0, &type, NULL, &sz );
1219 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1220 total += sz;
1222 sz = 0;
1223 r = RegQueryValueExA( hKey, szStart, 0, &type, NULL, &sz );
1224 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1225 total += sz;
1227 sz = 0;
1228 r = RegQueryValueExA( hKey, szDisplayName, 0, &type, NULL, &sz );
1229 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1230 total += sz;
1232 /* if there's not enough memory, return an error */
1233 if( total > *pcbBytesNeeded )
1235 *pcbBytesNeeded = total;
1236 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1237 return FALSE;
1240 *pcbBytesNeeded = total;
1241 ZeroMemory( lpServiceConfig, total );
1243 sz = sizeof val;
1244 r = RegQueryValueExA( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1245 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1246 lpServiceConfig->dwServiceType = val;
1248 sz = sizeof val;
1249 r = RegQueryValueExA( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1250 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1251 lpServiceConfig->dwStartType = val;
1253 sz = sizeof 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;
1270 p += sz;
1271 n -= sz;
1273 else
1275 /* FIXME: set last error */
1276 return FALSE;
1279 sz = n;
1280 r = RegQueryValueExA( hKey, szGroup, 0, &type, p, &sz );
1281 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1283 lpServiceConfig->lpLoadOrderGroup = (LPSTR) p;
1284 p += sz;
1285 n -= sz;
1288 sz = n;
1289 r = RegQueryValueExA( hKey, szDependencies, 0, &type, p, &sz );
1290 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1292 lpServiceConfig->lpDependencies = (LPSTR) p;
1293 p += sz;
1294 n -= sz;
1297 if( n < 0 )
1298 ERR("Buffer overflow!\n");
1300 TRACE("Image path = %s\n", lpServiceConfig->lpBinaryPathName );
1301 TRACE("Group = %s\n", lpServiceConfig->lpLoadOrderGroup );
1303 return TRUE;
1306 /******************************************************************************
1307 * QueryServiceConfigW [ADVAPI32.@]
1309 BOOL WINAPI
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 ];
1326 LONG r;
1327 DWORD type, val, sz, total, n;
1328 LPBYTE p;
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;
1345 else
1347 /* FIXME: set last error */
1348 return FALSE;
1351 sz = 0;
1352 r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1353 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1354 total += sz;
1356 sz = 0;
1357 r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1358 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1359 total += sz;
1361 sz = 0;
1362 r = RegQueryValueExW( hKey, szStart, 0, &type, NULL, &sz );
1363 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1364 total += sz;
1366 sz = 0;
1367 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1368 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1369 total += sz;
1371 /* if there's not enough memory, return an error */
1372 if( total > *pcbBytesNeeded )
1374 *pcbBytesNeeded = total;
1375 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1376 return FALSE;
1379 *pcbBytesNeeded = total;
1380 ZeroMemory( lpServiceConfig, total );
1382 sz = sizeof val;
1383 r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1384 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1385 lpServiceConfig->dwServiceType = val;
1387 sz = sizeof val;
1388 r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1389 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1390 lpServiceConfig->dwStartType = val;
1392 sz = sizeof 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;
1410 p += sz;
1411 n -= sz;
1413 else
1415 /* FIXME: set last error */
1416 return FALSE;
1419 sz = n;
1420 r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
1421 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1423 lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
1424 p += sz;
1425 n -= sz;
1428 sz = n;
1429 r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
1430 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1432 lpServiceConfig->lpDependencies = (LPWSTR) p;
1433 p += sz;
1434 n -= sz;
1437 if( n < 0 )
1438 ERR("Buffer overflow!\n");
1440 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1441 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1443 return TRUE;
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) );
1459 return TRUE;
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) );
1475 return TRUE;
1478 /******************************************************************************
1479 * ChangeServiceConfig2A [ADVAPI32.@]
1481 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
1482 LPVOID lpInfo)
1484 FIXME("STUB: %p %ld %p\n",hService, dwInfoLevel, lpInfo);
1485 return TRUE;
1488 /******************************************************************************
1489 * ChangeServiceConfig2W [ADVAPI32.@]
1491 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
1492 LPVOID lpInfo)
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);
1505 else
1506 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
1507 (LPVOID)sd->lpDescription,
1508 sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
1511 else
1512 FIXME("STUB: %p %ld %p\n",hService, dwInfoLevel, lpInfo);
1513 return TRUE;
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;