Start only first service in the service table.
[wine/multimedia.git] / dlls / advapi32 / service.c
blobddbbf65ae18c8d2ee9088f72d11b08bf39f79566
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 * open_seb_shmem
223 * helper function for StartServiceCtrlDispatcherA/W
225 static struct SEB* open_seb_shmem( LPWSTR service_name, HANDLE* hServiceShmem )
227 WCHAR object_name[ MAX_PATH ];
228 HANDLE hmem;
229 struct SEB *ret;
231 snprintfW( object_name, MAX_PATH, szServiceShmemNameFmtW, service_name );
232 hmem = OpenFileMappingW( FILE_MAP_ALL_ACCESS, FALSE, object_name );
233 if( NULL == hmem )
234 return NULL;
236 ret = MapViewOfFile( hmem, FILE_MAP_ALL_ACCESS, 0, 0, 0 );
237 if( NULL == ret )
238 CloseHandle( hmem );
239 else
240 *hServiceShmem = hmem;
241 return ret;
244 /******************************************************************************
245 * build_arg_vectors
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 )
255 LPWSTR *ret;
256 LPWSTR argptr;
257 DWORD i;
259 ret = HeapAlloc( GetProcessHeap(), 0, (1 + seb->argc) * sizeof(LPWSTR) );
260 if( NULL == ret )
261 return NULL;
263 argptr = (LPWSTR) &seb[1];
264 for( i = 0; i < seb->argc; i++ )
266 ret[ 1 + i ] = argptr;
267 argptr += 1 + strlenW( argptr );
269 return ret;
272 /******************************************************************************
273 * StartServiceCtrlDispatcherA [ADVAPI32.@]
275 BOOL WINAPI
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;
285 unsigned int i;
286 BOOL ret = FALSE;
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 );
299 return TRUE;
302 seb = open_seb_shmem( service_name, &hServiceShmem );
303 if( NULL == seb )
304 return FALSE;
306 lpArgVecW = build_arg_vectors( seb );
307 if( NULL == lpArgVecW )
308 goto done;
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);
326 done:
327 if(dwNumServiceArgs)
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 );
338 return ret;
341 /******************************************************************************
342 * StartServiceCtrlDispatcherW [ADVAPI32.@]
344 * PARAMS
345 * servent []
347 BOOL WINAPI
348 StartServiceCtrlDispatcherW( LPSERVICE_TABLE_ENTRYW servent )
350 LPSERVICE_MAIN_FUNCTIONW fpMain;
351 WCHAR service_name[ MAX_SERVICE_NAME ];
352 HANDLE hServiceShmem = NULL;
353 struct SEB *seb;
354 DWORD dwNumServiceArgs ;
355 LPWSTR *lpServiceArgVectors ;
357 TRACE("(%p)\n", servent);
359 if( ! read_scm_lock_data( service_name ) )
360 return FALSE;
362 seb = open_seb_shmem( service_name, &hServiceShmem );
363 if( NULL == seb )
364 return FALSE;
366 lpServiceArgVectors = build_arg_vectors( seb );
367 if( NULL == lpServiceArgVectors )
369 UnmapViewOfFile( seb );
370 CloseHandle( hServiceShmem );
371 return FALSE;
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 );
386 return TRUE;
389 /******************************************************************************
390 * LockServiceDatabase [ADVAPI32.@]
392 LPVOID WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
394 HANDLE ret;
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 )
402 CloseHandle( ret );
403 ret = NULL;
404 SetLastError( ERROR_SERVICE_DATABASE_LOCKED );
407 TRACE("returning %p\n", ret);
409 return 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);
429 return 0xcacacafe;
432 /******************************************************************************
433 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
435 * PARAMS
436 * lpServiceName []
437 * lpfHandler []
439 SERVICE_STATUS_HANDLE WINAPI
440 RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName,
441 LPHANDLER_FUNCTION lpfHandler )
442 { FIXME("%s %p\n", debugstr_w(lpServiceName), lpfHandler);
443 return 0xcacacafe;
446 /******************************************************************************
447 * SetServiceStatus [ADVAPI32.@]
449 * PARAMS
450 * hService []
451 * lpStatus []
453 BOOL WINAPI
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);
463 return TRUE;
466 /******************************************************************************
467 * OpenSCManagerA [ADVAPI32.@]
469 * Establish a connection to the service control manager and open its database.
471 * PARAMS
472 * lpMachineName [I] Pointer to machine name string
473 * lpDatabaseName [I] Pointer to database name string
474 * dwDesiredAccess [I] Type of access
476 * RETURNS
477 * Success: A Handle to the service control manager database
478 * Failure: NULL
480 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
481 DWORD dwDesiredAccess )
483 UNICODE_STRING lpMachineNameW;
484 UNICODE_STRING lpDatabaseNameW;
485 SC_HANDLE ret;
487 RtlCreateUnicodeStringFromAsciiz (&lpMachineNameW,lpMachineName);
488 RtlCreateUnicodeStringFromAsciiz (&lpDatabaseNameW,lpDatabaseName);
489 ret = OpenSCManagerW(lpMachineNameW.Buffer,lpDatabaseNameW.Buffer, dwDesiredAccess);
490 RtlFreeUnicodeString(&lpDatabaseNameW);
491 RtlFreeUnicodeString(&lpMachineNameW);
492 return ret;
495 /******************************************************************************
496 * OpenSCManagerW [ADVAPI32.@]
498 * See OpenSCManagerA.
500 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
501 DWORD dwDesiredAccess )
503 struct sc_handle *retval;
504 HKEY hReg;
505 LONG r;
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)
523 goto error;
525 r = RegOpenKeyExW(hReg, szServiceManagerKey,
526 0, KEY_ALL_ACCESS, &retval->u.manager.hkey_scm_db);
527 RegCloseKey( hReg );
528 if (r!=ERROR_SUCCESS)
529 goto error;
531 TRACE("returning %p\n", retval);
533 return (SC_HANDLE) retval;
535 error:
536 free_sc_handle( retval );
537 return NULL;
541 /******************************************************************************
542 * AllocateLocallyUniqueId [ADVAPI32.@]
544 * PARAMS
545 * lpluid []
547 BOOL WINAPI
548 AllocateLocallyUniqueId( PLUID lpluid )
550 lpluid->LowPart = time(NULL);
551 lpluid->HighPart = 0;
552 return TRUE;
556 /******************************************************************************
557 * ControlService [ADVAPI32.@]
559 * Send a control code to a service.
561 * PARAMS
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
566 * RETURNS
567 * Success: TRUE.
568 * Failure: FALSE.
570 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
571 LPSERVICE_STATUS lpServiceStatus )
573 FIXME("(%p,%ld,%p): stub\n",hService,dwControl,lpServiceStatus);
574 return TRUE;
578 /******************************************************************************
579 * CloseServiceHandle [ADVAPI32.@]
581 * Close a handle to a service or the service control manager database.
583 * PARAMS
584 * hSCObject [I] Handle to service or service control manager database
586 * RETURNS
587 * Success: TRUE
588 * Failure: FALSE
590 BOOL WINAPI
591 CloseServiceHandle( SC_HANDLE hSCObject )
593 TRACE("(%p)\n", hSCObject);
595 free_sc_handle( (struct sc_handle*) hSCObject );
597 return TRUE;
601 /******************************************************************************
602 * OpenServiceA [ADVAPI32.@]
604 * Open a handle to a service.
606 * PARAMS
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
611 * RETURNS
612 * Success: Handle to the service
613 * Failure: NULL
615 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
616 DWORD dwDesiredAccess )
618 UNICODE_STRING lpServiceNameW;
619 SC_HANDLE ret;
620 RtlCreateUnicodeStringFromAsciiz (&lpServiceNameW,lpServiceName);
621 if(lpServiceName)
622 TRACE("Request for service %s\n",lpServiceName);
623 else
624 return FALSE;
625 ret = OpenServiceW( hSCManager, lpServiceNameW.Buffer, dwDesiredAccess);
626 RtlFreeUnicodeString(&lpServiceNameW);
627 return ret;
631 /******************************************************************************
632 * OpenServiceW [ADVAPI32.@]
634 * See OpenServiceA.
636 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
637 DWORD dwDesiredAccess)
639 struct sc_handle *hscm = hSCManager;
640 struct sc_handle *retval;
641 HKEY hKey;
642 long r;
644 TRACE("(%p,%p,%ld)\n",hSCManager, lpServiceName,
645 dwDesiredAccess);
647 retval = alloc_sc_handle( SC_HTYPE_SERVICE );
648 if( NULL == retval )
649 return NULL;
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 );
657 return NULL;
660 init_service_handle( retval, hscm, hKey, lpServiceName );
662 TRACE("returning %p\n",retval);
664 return (SC_HANDLE) retval;
667 /******************************************************************************
668 * CreateServiceW [ADVAPI32.@]
670 SC_HANDLE WINAPI
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,
677 LPCWSTR lpPassword )
679 struct sc_handle *hscm = hSCManager;
680 struct sc_handle *retval;
681 HKEY hKey;
682 LONG r;
683 DWORD dp;
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 );
696 if( NULL == retval )
697 return NULL;
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)
702 goto error;
704 init_service_handle( retval, hscm, hKey, lpServiceName );
706 if (dp != REG_CREATED_NEW_KEY)
707 goto error;
709 if(lpDisplayName)
711 r = RegSetValueExW(hKey, szDisplayName, 0, REG_SZ, (LPBYTE)lpDisplayName,
712 (strlenW(lpDisplayName)+1)*sizeof(WCHAR) );
713 if (r!=ERROR_SUCCESS)
714 goto error;
717 r = RegSetValueExW(hKey, szType, 0, REG_DWORD, (LPVOID)&dwServiceType, sizeof (DWORD) );
718 if (r!=ERROR_SUCCESS)
719 goto error;
721 r = RegSetValueExW(hKey, szStart, 0, REG_DWORD, (LPVOID)&dwStartType, sizeof (DWORD) );
722 if (r!=ERROR_SUCCESS)
723 goto error;
725 r = RegSetValueExW(hKey, szError, 0, REG_DWORD,
726 (LPVOID)&dwErrorControl, sizeof (DWORD) );
727 if (r!=ERROR_SUCCESS)
728 goto error;
730 if(lpBinaryPathName)
732 r = RegSetValueExW(hKey, szImagePath, 0, REG_SZ, (LPBYTE)lpBinaryPathName,
733 (strlenW(lpBinaryPathName)+1)*sizeof(WCHAR) );
734 if (r!=ERROR_SUCCESS)
735 goto error;
738 if(lpLoadOrderGroup)
740 r = RegSetValueExW(hKey, szGroup, 0, REG_SZ, (LPBYTE)lpLoadOrderGroup,
741 (strlenW(lpLoadOrderGroup)+1)*sizeof(WCHAR) );
742 if (r!=ERROR_SUCCESS)
743 goto error;
746 if(lpDependencies)
748 DWORD len = 0;
750 /* determine the length of a double null terminated multi string */
751 do {
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)
758 goto error;
761 if(lpPassword)
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;
773 error:
774 free_sc_handle( retval );
775 return NULL;
779 static inline LPWSTR SERV_dup( LPCSTR str )
781 UINT len;
782 LPWSTR wstr;
784 if( !str )
785 return NULL;
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 );
789 return wstr;
792 static inline LPWSTR SERV_dupmulti( LPCSTR str )
794 UINT len = 0, n = 0;
795 LPWSTR wstr;
797 if( !str )
798 return NULL;
799 do {
800 len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
801 n += (strlen( &str[n] ) + 1);
802 } while (str[n]);
803 len++;
804 n++;
806 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
807 MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
808 return wstr;
811 static inline VOID SERV_free( LPWSTR wstr )
813 HeapFree( GetProcessHeap(), 0, wstr );
816 /******************************************************************************
817 * CreateServiceA [ADVAPI32.@]
819 SC_HANDLE WINAPI
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,
826 LPCSTR lpPassword )
828 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
829 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
830 SC_HANDLE r;
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 );
856 return r;
860 /******************************************************************************
861 * DeleteService [ADVAPI32.@]
863 * Delete a service from the service control manager database.
865 * PARAMS
866 * hService [I] Handle of the service to delete
868 * RETURNS
869 * Success: TRUE
870 * Failure: FALSE
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];
877 INT index = 0;
878 LONG rc;
879 DWORD size;
881 size = 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);
887 index++;
888 size = MAX_PATH+1;
889 rc = RegEnumValueW(hKey, index, valname, &size,0,0,0,0);
892 RegCloseKey(hKey);
893 hsvc->u.service.hkey = NULL;
895 /* delete the key */
896 RegDeleteKeyW(hsvc->u.service.sc_manager->u.manager.hkey_scm_db,
897 hsvc->u.service.name);
899 return TRUE;
903 /******************************************************************************
904 * StartServiceA [ADVAPI32.@]
906 * Start a service
908 * PARAMS
909 * hService [I] Handle of service
910 * dwNumServiceArgs [I] Number of arguments
911 * lpServiceArgVectors [I] Address of array of argument strings
913 * NOTES
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.
922 * RETURNS
923 * Success: TRUE.
924 * Failure: FALSE
926 BOOL WINAPI
927 StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
928 LPCSTR *lpServiceArgVectors )
930 LPWSTR *lpwstr=NULL;
931 UNICODE_STRING usBuffer;
932 unsigned int i;
934 TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
936 if(dwNumServiceArgs)
937 lpwstr = (LPWSTR*) HeapAlloc( GetProcessHeap(), 0,
938 dwNumServiceArgs*sizeof(LPWSTR) );
939 else
940 lpwstr = NULL;
942 for(i=0; i<dwNumServiceArgs; i++)
944 RtlCreateUnicodeStringFromAsciiz (&usBuffer,lpServiceArgVectors[i]);
945 lpwstr[i]=usBuffer.Buffer;
948 StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
950 if(dwNumServiceArgs)
952 for(i=0; i<dwNumServiceArgs; i++)
953 HeapFree(GetProcessHeap(), 0, lpwstr[i]);
954 HeapFree(GetProcessHeap(), 0, lpwstr);
957 return TRUE;
961 /******************************************************************************
962 * StartServiceW [ADVAPI32.@]
964 * See StartServiceA.
966 BOOL WINAPI
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];
977 DWORD type,size;
978 DWORD i;
979 long r;
980 HANDLE hLock;
981 HANDLE hServiceShmem = NULL;
982 HANDLE wait = NULL;
983 LPWSTR shmem_lock = NULL;
984 struct SEB *seb = NULL;
985 LPWSTR argptr;
986 PROCESS_INFORMATION procinfo;
987 STARTUPINFOW startupinfo;
988 BOOL ret = FALSE;
990 TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,
991 lpServiceArgVectors);
993 size = sizeof(str);
994 r = RegQueryValueExW(hsvc->u.service.hkey, _ImagePathW, NULL, &type, (LPVOID)str, &size);
995 if (r!=ERROR_SUCCESS)
996 return FALSE;
997 ExpandEnvironmentStringsW(str,path,sizeof(path));
999 TRACE("Starting service %s\n", debugstr_w(path) );
1001 hLock = LockServiceDatabase( hsvc->u.service.sc_manager );
1002 if( NULL == hLock )
1003 return FALSE;
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");
1015 goto done;
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");
1030 goto done;
1032 if( GetLastError() == ERROR_ALREADY_EXISTS )
1034 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
1035 goto done;
1037 seb = MapViewOfFile( hServiceShmem, FILE_MAP_ALL_ACCESS, 0, 0, 0 );
1038 if( NULL == seb )
1040 ERR("Couldn't map shared memory\n");
1041 goto done;
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);
1054 if (!wait)
1056 ERR("Couldn't create wait semaphore\n");
1057 goto done;
1060 ZeroMemory(&startupinfo,sizeof(STARTUPINFOW));
1061 startupinfo.cb = sizeof(STARTUPINFOW);
1063 r = CreateProcessW(NULL,
1064 path,
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 */
1074 if(r == FALSE)
1076 ERR("Couldn't start process\n");
1077 goto done;
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 );
1086 goto done;
1089 /* allright */
1090 CloseHandle( procinfo.hProcess );
1091 ret = TRUE;
1093 done:
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 );
1099 return ret;
1102 /******************************************************************************
1103 * QueryServiceStatus [ADVAPI32.@]
1105 * PARAMS
1106 * hService []
1107 * lpservicestatus []
1110 BOOL WINAPI
1111 QueryServiceStatus( SC_HANDLE hService, LPSERVICE_STATUS lpservicestatus )
1113 struct sc_handle *hsvc = hService;
1114 LONG r;
1115 DWORD type, val, size;
1117 FIXME("(%p,%p) partial\n",hService,lpservicestatus);
1119 /* read the service type from the registry */
1120 size = sizeof(val);
1121 r = RegQueryValueExA(hsvc->u.service.hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1122 if(type!=REG_DWORD)
1124 ERR("invalid Type\n");
1125 return FALSE;
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;
1137 return TRUE;
1140 /******************************************************************************
1141 * QueryServiceStatusEx [ADVAPI32.@]
1143 * Get information about a service.
1145 * PARAMS
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
1152 * RETURNS
1153 * Success: TRUE
1154 * FAILURE: FALSE
1156 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1157 LPBYTE lpBuffer, DWORD cbBufSize,
1158 LPDWORD pcbBytesNeeded)
1160 FIXME("stub\n");
1161 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1162 return FALSE;
1165 /******************************************************************************
1166 * QueryServiceConfigA [ADVAPI32.@]
1168 BOOL WINAPI
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 ];
1182 LONG r;
1183 DWORD type, val, sz, total, n;
1184 LPBYTE p;
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;
1199 total += sz;
1201 else
1203 /* FIXME: set last error */
1204 return FALSE;
1207 sz = 0;
1208 r = RegQueryValueExA( hKey, szGroup, 0, &type, NULL, &sz );
1209 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1210 total += sz;
1212 sz = 0;
1213 r = RegQueryValueExA( hKey, szDependencies, 0, &type, NULL, &sz );
1214 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1215 total += sz;
1217 sz = 0;
1218 r = RegQueryValueExA( hKey, szStart, 0, &type, NULL, &sz );
1219 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1220 total += sz;
1222 sz = 0;
1223 r = RegQueryValueExA( hKey, szDisplayName, 0, &type, NULL, &sz );
1224 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1225 total += sz;
1227 /* if there's not enough memory, return an error */
1228 if( total > *pcbBytesNeeded )
1230 *pcbBytesNeeded = total;
1231 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1232 return FALSE;
1235 *pcbBytesNeeded = total;
1236 ZeroMemory( lpServiceConfig, total );
1238 sz = sizeof val;
1239 r = RegQueryValueExA( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1240 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1241 lpServiceConfig->dwServiceType = val;
1243 sz = sizeof val;
1244 r = RegQueryValueExA( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1245 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1246 lpServiceConfig->dwStartType = val;
1248 sz = sizeof 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;
1265 p += sz;
1266 n -= sz;
1268 else
1270 /* FIXME: set last error */
1271 return FALSE;
1274 sz = n;
1275 r = RegQueryValueExA( hKey, szGroup, 0, &type, p, &sz );
1276 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1278 lpServiceConfig->lpLoadOrderGroup = (LPSTR) p;
1279 p += sz;
1280 n -= sz;
1283 sz = n;
1284 r = RegQueryValueExA( hKey, szDependencies, 0, &type, p, &sz );
1285 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1287 lpServiceConfig->lpDependencies = (LPSTR) p;
1288 p += sz;
1289 n -= sz;
1292 if( n < 0 )
1293 ERR("Buffer overflow!\n");
1295 TRACE("Image path = %s\n", lpServiceConfig->lpBinaryPathName );
1296 TRACE("Group = %s\n", lpServiceConfig->lpLoadOrderGroup );
1298 return TRUE;
1301 /******************************************************************************
1302 * QueryServiceConfigW [ADVAPI32.@]
1304 BOOL WINAPI
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 ];
1321 LONG r;
1322 DWORD type, val, sz, total, n;
1323 LPBYTE p;
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;
1340 else
1342 /* FIXME: set last error */
1343 return FALSE;
1346 sz = 0;
1347 r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1348 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1349 total += sz;
1351 sz = 0;
1352 r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1353 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1354 total += sz;
1356 sz = 0;
1357 r = RegQueryValueExW( hKey, szStart, 0, &type, NULL, &sz );
1358 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1359 total += sz;
1361 sz = 0;
1362 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1363 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1364 total += sz;
1366 /* if there's not enough memory, return an error */
1367 if( total > *pcbBytesNeeded )
1369 *pcbBytesNeeded = total;
1370 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1371 return FALSE;
1374 *pcbBytesNeeded = total;
1375 ZeroMemory( lpServiceConfig, total );
1377 sz = sizeof val;
1378 r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1379 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1380 lpServiceConfig->dwServiceType = val;
1382 sz = sizeof val;
1383 r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1384 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1385 lpServiceConfig->dwStartType = val;
1387 sz = sizeof 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;
1405 p += sz;
1406 n -= sz;
1408 else
1410 /* FIXME: set last error */
1411 return FALSE;
1414 sz = n;
1415 r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
1416 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1418 lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
1419 p += sz;
1420 n -= sz;
1423 sz = n;
1424 r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
1425 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1427 lpServiceConfig->lpDependencies = (LPWSTR) p;
1428 p += sz;
1429 n -= sz;
1432 if( n < 0 )
1433 ERR("Buffer overflow!\n");
1435 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1436 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1438 return TRUE;
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) );
1454 return TRUE;
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) );
1470 return TRUE;
1473 /******************************************************************************
1474 * ChangeServiceConfig2A [ADVAPI32.@]
1476 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
1477 LPVOID lpInfo)
1479 FIXME("STUB: %p %ld %p\n",hService, dwInfoLevel, lpInfo);
1480 return TRUE;
1483 /******************************************************************************
1484 * ChangeServiceConfig2W [ADVAPI32.@]
1486 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
1487 LPVOID lpInfo)
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);
1500 else
1501 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
1502 (LPVOID)sd->lpDescription,
1503 sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
1506 else
1507 FIXME("STUB: %p %ld %p\n",hService, dwInfoLevel, lpInfo);
1508 return TRUE;
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;