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
28 #include "wine/unicode.h"
30 #include "wine/debug.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(advapi
);
34 static DWORD start_dwNumServiceArgs
;
35 static LPWSTR
*start_lpServiceArgVectors
;
37 /******************************************************************************
38 * EnumServicesStatusA [ADVAPI32.@]
41 EnumServicesStatusA( SC_HANDLE hSCManager
, DWORD dwServiceType
,
42 DWORD dwServiceState
, LPENUM_SERVICE_STATUSA lpServices
,
43 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
44 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
)
45 { FIXME("%x type=%lx state=%lx %p %lx %p %p %p\n", hSCManager
,
46 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
47 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
);
48 SetLastError (ERROR_ACCESS_DENIED
);
52 /******************************************************************************
53 * EnumServicesStatusW [ADVAPI32.@]
56 EnumServicesStatusW( SC_HANDLE hSCManager
, DWORD dwServiceType
,
57 DWORD dwServiceState
, LPENUM_SERVICE_STATUSW lpServices
,
58 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
59 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
)
60 { FIXME("%x type=%lx state=%lx %p %lx %p %p %p\n", hSCManager
,
61 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
62 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
);
63 SetLastError (ERROR_ACCESS_DENIED
);
67 /******************************************************************************
68 * StartServiceCtrlDispatcherA [ADVAPI32.@]
71 StartServiceCtrlDispatcherA( LPSERVICE_TABLE_ENTRYA servent
)
73 LPSERVICE_MAIN_FUNCTIONA fpMain
;
75 DWORD dwNumServiceArgs
;
80 TRACE("(%p)\n", servent
);
81 wait
= OpenSemaphoreA(SEMAPHORE_ALL_ACCESS
, FALSE
, "ADVAPI32_ServiceStartData");
84 ERR("Couldn't find wait semaphore\n");
85 ERR("perhaps you need to start services using StartService\n");
89 dwNumServiceArgs
= start_dwNumServiceArgs
;
90 lpArgVecW
= start_lpServiceArgVectors
;
92 ReleaseSemaphore(wait
, 1, NULL
);
94 /* Convert the Unicode arg vectors back to ASCII */
96 lpArgVecA
= (LPSTR
*) HeapAlloc( GetProcessHeap(), 0,
97 dwNumServiceArgs
*sizeof(LPSTR
) );
101 for(i
=0; i
<dwNumServiceArgs
; i
++)
102 lpArgVecA
[i
]=HEAP_strdupWtoA(GetProcessHeap(), 0, lpArgVecW
[i
]);
104 /* FIXME: should we blindly start all services? */
105 while (servent
->lpServiceName
) {
106 TRACE("%s at %p)\n", debugstr_a(servent
->lpServiceName
),servent
);
107 fpMain
= servent
->lpServiceProc
;
109 /* try to start the service */
110 fpMain( dwNumServiceArgs
, lpArgVecA
);
117 /* free arg strings */
118 for(i
=0; i
<dwNumServiceArgs
; i
++)
119 HeapFree(GetProcessHeap(), 0, lpArgVecA
[i
]);
120 HeapFree(GetProcessHeap(), 0, lpArgVecA
);
126 /******************************************************************************
127 * StartServiceCtrlDispatcherW [ADVAPI32.@]
133 StartServiceCtrlDispatcherW( LPSERVICE_TABLE_ENTRYW servent
)
135 LPSERVICE_MAIN_FUNCTIONW fpMain
;
137 DWORD dwNumServiceArgs
;
138 LPWSTR
*lpServiceArgVectors
;
140 TRACE("(%p)\n", servent
);
141 wait
= OpenSemaphoreA(SEMAPHORE_ALL_ACCESS
, FALSE
, "ADVAPI32_ServiceStartData");
144 ERR("Couldn't find wait semaphore\n");
145 ERR("perhaps you need to start services using StartService\n");
149 dwNumServiceArgs
= start_dwNumServiceArgs
;
150 lpServiceArgVectors
= start_lpServiceArgVectors
;
152 ReleaseSemaphore(wait
, 1, NULL
);
154 /* FIXME: should we blindly start all services? */
155 while (servent
->lpServiceName
) {
156 TRACE("%s at %p)\n", debugstr_w(servent
->lpServiceName
),servent
);
157 fpMain
= servent
->lpServiceProc
;
159 /* try to start the service */
160 fpMain( dwNumServiceArgs
, lpServiceArgVectors
);
168 /******************************************************************************
169 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
171 SERVICE_STATUS_HANDLE WINAPI
172 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName
,
173 LPHANDLER_FUNCTION lpfHandler
)
174 { FIXME("%s %p\n", lpServiceName
, lpfHandler
);
178 /******************************************************************************
179 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
185 SERVICE_STATUS_HANDLE WINAPI
186 RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName
,
187 LPHANDLER_FUNCTION lpfHandler
)
188 { FIXME("%s %p\n", debugstr_w(lpServiceName
), lpfHandler
);
192 /******************************************************************************
193 * SetServiceStatus [ADVAPI32.@]
200 SetServiceStatus( SERVICE_STATUS_HANDLE hService
, LPSERVICE_STATUS lpStatus
)
201 { FIXME("0x%lx %p\n",hService
, lpStatus
);
202 TRACE("\tType:%lx\n",lpStatus
->dwServiceType
);
203 TRACE("\tState:%lx\n",lpStatus
->dwCurrentState
);
204 TRACE("\tControlAccepted:%lx\n",lpStatus
->dwControlsAccepted
);
205 TRACE("\tExitCode:%lx\n",lpStatus
->dwWin32ExitCode
);
206 TRACE("\tServiceExitCode:%lx\n",lpStatus
->dwServiceSpecificExitCode
);
207 TRACE("\tCheckPoint:%lx\n",lpStatus
->dwCheckPoint
);
208 TRACE("\tWaitHint:%lx\n",lpStatus
->dwWaitHint
);
212 /******************************************************************************
213 * OpenSCManagerA [ADVAPI32.@]
216 OpenSCManagerA( LPCSTR lpMachineName
, LPCSTR lpDatabaseName
,
217 DWORD dwDesiredAccess
)
219 LPWSTR lpMachineNameW
= HEAP_strdupAtoW(GetProcessHeap(),0,lpMachineName
);
220 LPWSTR lpDatabaseNameW
= HEAP_strdupAtoW(GetProcessHeap(),0,lpDatabaseName
);
221 SC_HANDLE ret
= OpenSCManagerW(lpMachineNameW
,lpDatabaseNameW
,
223 HeapFree(GetProcessHeap(),0,lpDatabaseNameW
);
224 HeapFree(GetProcessHeap(),0,lpMachineNameW
);
228 /******************************************************************************
229 * OpenSCManagerW [ADVAPI32.@]
230 * Establishes a connection to the service control manager and opens database
233 * This should return a SC_HANDLE
236 * lpMachineName [I] Pointer to machine name string
237 * lpDatabaseName [I] Pointer to database name string
238 * dwDesiredAccess [I] Type of access
241 * Success: Handle to service control manager database
245 OpenSCManagerW( LPCWSTR lpMachineName
, LPCWSTR lpDatabaseName
,
246 DWORD dwDesiredAccess
)
251 TRACE("(%s,%s,0x%08lx)\n", debugstr_w(lpMachineName
),
252 debugstr_w(lpDatabaseName
), dwDesiredAccess
);
255 * FIXME: what is lpDatabaseName?
256 * It should be set to "SERVICES_ACTIVE_DATABASE" according to
257 * docs, but what if it isn't?
260 r
= RegConnectRegistryW(lpMachineName
,HKEY_LOCAL_MACHINE
,&hKey
);
261 if (r
!=ERROR_SUCCESS
)
264 TRACE("returning %x\n",hKey
);
270 /******************************************************************************
271 * AllocateLocallyUniqueId [ADVAPI32.@]
277 AllocateLocallyUniqueId( PLUID lpluid
)
279 lpluid
->LowPart
= time(NULL
);
280 lpluid
->HighPart
= 0;
285 /******************************************************************************
286 * ControlService [ADVAPI32.@]
287 * Sends a control code to a Win32-based service.
297 ControlService( SC_HANDLE hService
, DWORD dwControl
,
298 LPSERVICE_STATUS lpServiceStatus
)
300 FIXME("(%d,%ld,%p): stub\n",hService
,dwControl
,lpServiceStatus
);
305 /******************************************************************************
306 * CloseServiceHandle [ADVAPI32.@]
307 * Close handle to service or service control manager
310 * hSCObject [I] Handle to service or service control manager database
315 CloseServiceHandle( SC_HANDLE hSCObject
)
317 TRACE("(%x)\n", hSCObject
);
319 RegCloseKey(hSCObject
);
325 /******************************************************************************
326 * OpenServiceA [ADVAPI32.@]
329 OpenServiceA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
330 DWORD dwDesiredAccess
)
332 LPWSTR lpServiceNameW
= HEAP_strdupAtoW(GetProcessHeap(),0,lpServiceName
);
336 TRACE("Request for service %s\n",lpServiceName
);
339 ret
= OpenServiceW( hSCManager
, lpServiceNameW
, dwDesiredAccess
);
340 HeapFree(GetProcessHeap(),0,lpServiceNameW
);
345 /******************************************************************************
346 * OpenServiceW [ADVAPI32.@]
347 * Opens a handle to an existing service
355 * Success: Handle to the service
359 OpenServiceW(SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
360 DWORD dwDesiredAccess
)
362 const char *str
= "System\\CurrentControlSet\\Services\\";
363 WCHAR lpServiceKey
[80]; /* FIXME: this should be dynamically allocated */
367 TRACE("(%d,%p,%ld)\n",hSCManager
, lpServiceName
,
370 MultiByteToWideChar( CP_ACP
, 0, str
, -1, lpServiceKey
, sizeof(lpServiceKey
)/sizeof(WCHAR
) );
371 strcatW(lpServiceKey
,lpServiceName
);
373 TRACE("Opening reg key %s\n", debugstr_w(lpServiceKey
));
375 /* FIXME: dwDesiredAccess may need some processing */
376 r
= RegOpenKeyExW(hSCManager
, lpServiceKey
, 0, dwDesiredAccess
, &hKey
);
377 if (r
!=ERROR_SUCCESS
)
380 TRACE("returning %x\n",hKey
);
385 /******************************************************************************
386 * CreateServiceW [ADVAPI32.@]
389 CreateServiceW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
390 LPCWSTR lpDisplayName
, DWORD dwDesiredAccess
,
391 DWORD dwServiceType
, DWORD dwStartType
,
392 DWORD dwErrorControl
, LPCWSTR lpBinaryPathName
,
393 LPCWSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
,
394 LPCWSTR lpDependencies
, LPCWSTR lpServiceStartName
,
397 FIXME("(%u,%s,%s,...)\n", hSCManager
, debugstr_w(lpServiceName
), debugstr_w(lpDisplayName
));
402 /******************************************************************************
403 * CreateServiceA [ADVAPI32.@]
406 CreateServiceA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
407 LPCSTR lpDisplayName
, DWORD dwDesiredAccess
,
408 DWORD dwServiceType
, DWORD dwStartType
,
409 DWORD dwErrorControl
, LPCSTR lpBinaryPathName
,
410 LPCSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
,
411 LPCSTR lpDependencies
, LPCSTR lpServiceStartName
,
418 TRACE("(%u,%s,%s,...)\n", hSCManager
, debugstr_a(lpServiceName
), debugstr_a(lpDisplayName
));
420 r
= RegCreateKeyExA(hSCManager
, lpServiceName
, 0, NULL
,
421 REG_OPTION_NON_VOLATILE
, dwDesiredAccess
, NULL
, &hKey
, &dp
);
422 if (r
!=ERROR_SUCCESS
)
424 if (dp
!= REG_CREATED_NEW_KEY
)
429 r
= RegSetValueExA(hKey
, "DisplayName", 0, REG_SZ
, lpDisplayName
, strlen(lpDisplayName
) );
430 if (r
!=ERROR_SUCCESS
)
434 r
= RegSetValueExA(hKey
, "Type", 0, REG_DWORD
, (LPVOID
)&dwServiceType
, sizeof (DWORD
) );
435 if (r
!=ERROR_SUCCESS
)
438 r
= RegSetValueExA(hKey
, "Start", 0, REG_DWORD
, (LPVOID
)&dwStartType
, sizeof (DWORD
) );
439 if (r
!=ERROR_SUCCESS
)
442 r
= RegSetValueExA(hKey
, "ErrorControl", 0, REG_DWORD
,
443 (LPVOID
)&dwErrorControl
, sizeof (DWORD
) );
444 if (r
!=ERROR_SUCCESS
)
449 r
= RegSetValueExA(hKey
, "ImagePath", 0, REG_SZ
,
450 lpBinaryPathName
,strlen(lpBinaryPathName
)+1 );
451 if (r
!=ERROR_SUCCESS
)
457 r
= RegSetValueExA(hKey
, "Group", 0, REG_SZ
,
458 lpLoadOrderGroup
, strlen(lpLoadOrderGroup
)+1 );
459 if (r
!=ERROR_SUCCESS
)
463 r
= RegSetValueExA(hKey
, "ErrorControl", 0, REG_DWORD
,
464 (LPVOID
)&dwErrorControl
, sizeof (DWORD
) );
465 if (r
!=ERROR_SUCCESS
)
472 /* determine the length of a double null terminated multi string */
474 len
+= (strlen(&lpDependencies
[len
])+1);
475 } while (lpDependencies
[len
++]);
477 /* FIXME: this should be unicode */
478 r
= RegSetValueExA(hKey
, "Dependencies", 0, REG_MULTI_SZ
,
479 lpDependencies
, len
);
480 if (r
!=ERROR_SUCCESS
)
486 FIXME("Don't know how to add a Password for a service.\n");
489 if(lpServiceStartName
)
491 FIXME("Don't know how to add a ServiceStartName for a service.\n");
498 /******************************************************************************
499 * DeleteService [ADVAPI32.@]
502 * hService [I] Handle to service
508 DeleteService( SC_HANDLE hService
)
510 FIXME("(%d): stub\n",hService
);
515 /******************************************************************************
516 * StartServiceA [ADVAPI32.@]
520 StartServiceA( SC_HANDLE hService
, DWORD dwNumServiceArgs
,
521 LPCSTR
*lpServiceArgVectors
)
526 TRACE("(%d,%ld,%p)\n",hService
,dwNumServiceArgs
,lpServiceArgVectors
);
529 lpwstr
= (LPWSTR
*) HeapAlloc( GetProcessHeap(), 0,
530 dwNumServiceArgs
*sizeof(LPWSTR
) );
534 for(i
=0; i
<dwNumServiceArgs
; i
++)
535 lpwstr
[i
]=HEAP_strdupAtoW(GetProcessHeap(), 0, lpServiceArgVectors
[i
]);
537 StartServiceW(hService
, dwNumServiceArgs
, (LPCWSTR
*)lpwstr
);
541 for(i
=0; i
<dwNumServiceArgs
; i
++)
542 HeapFree(GetProcessHeap(), 0, lpwstr
[i
]);
543 HeapFree(GetProcessHeap(), 0, lpwstr
);
550 /******************************************************************************
551 * StartServiceW [ADVAPI32.@]
555 * hService [I] Handle of service
556 * dwNumServiceArgs [I] Number of arguments
557 * lpServiceArgVectors [I] Address of array of argument string pointers
561 * NT implements this function using an obscure RPC call...
563 * Might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
564 * to get things like %SystemRoot%\\System32\\service.exe to load.
566 * Will only work for shared address space. How should the service
567 * args be transferred when address spaces are separated?
569 * Can only start one service at a time.
571 * Has no concept of privilege.
577 StartServiceW( SC_HANDLE hService
, DWORD dwNumServiceArgs
,
578 LPCWSTR
*lpServiceArgVectors
)
580 CHAR path
[MAX_PATH
],str
[MAX_PATH
];
584 PROCESS_INFORMATION procinfo
;
585 STARTUPINFOA startupinfo
;
587 TRACE("(%d,%ld,%p)\n",hService
,dwNumServiceArgs
,
588 lpServiceArgVectors
);
591 r
= RegQueryValueExA(hService
, "ImagePath", NULL
, &type
, (LPVOID
)str
, &size
);
592 if (r
!=ERROR_SUCCESS
)
594 ExpandEnvironmentStringsA(str
,path
,sizeof path
);
596 TRACE("Starting service %s\n", debugstr_a(path
) );
598 data
= CreateSemaphoreA(NULL
,1,1,"ADVAPI32_ServiceStartData");
599 if(data
== ERROR_INVALID_HANDLE
)
601 data
= OpenSemaphoreA(SEMAPHORE_ALL_ACCESS
, FALSE
, "ADVAPI32_ServiceStartData");
604 ERR("Couldn't create data semaphore\n");
608 wait
= CreateSemaphoreA(NULL
,0,1,"ADVAPI32_WaitServiceStart");
610 wait
= OpenSemaphoreA(SEMAPHORE_ALL_ACCESS
, FALSE
, "ADVAPI32_ServiceStartData");
613 ERR("Couldn't create wait semaphore\n");
619 * FIXME: lpServiceArgsVectors need to be stored and returned to
620 * the service when it calls StartServiceCtrlDispatcher
622 * Chuck these in a global (yuk) so we can pass them to
623 * another process - address space separation will break this.
626 r
= WaitForSingleObject(data
,INFINITE
);
628 if( r
== WAIT_FAILED
)
631 FIXME("problematic because of address space separation.\n");
632 start_dwNumServiceArgs
= dwNumServiceArgs
;
633 start_lpServiceArgVectors
= (LPWSTR
*)lpServiceArgVectors
;
635 ZeroMemory(&startupinfo
,sizeof(STARTUPINFOA
));
636 startupinfo
.cb
= sizeof(STARTUPINFOA
);
638 r
= CreateProcessA(path
,
640 NULL
, /* process security attribs */
641 NULL
, /* thread security attribs */
642 FALSE
, /* inherit handles */
643 0, /* creation flags */
644 NULL
, /* environment */
645 NULL
, /* current directory */
646 &startupinfo
, /* startup info */
647 &procinfo
); /* process info */
651 ERR("Couldn't start process\n");
652 /* ReleaseSemaphore(data, 1, NULL);
656 /* docs for StartServiceCtrlDispatcher say this should be 30 sec */
657 r
= WaitForSingleObject(wait
,30000);
659 ReleaseSemaphore(data
, 1, NULL
);
661 if( r
== WAIT_FAILED
)
667 /******************************************************************************
668 * QueryServiceStatus [ADVAPI32.@]
676 QueryServiceStatus( SC_HANDLE hService
, LPSERVICE_STATUS lpservicestatus
)
679 DWORD type
, val
, size
;
681 FIXME("(%x,%p) partial\n",hService
,lpservicestatus
);
683 /* read the service type from the registry */
685 r
= RegQueryValueExA(hService
, "Type", NULL
, &type
, (LPBYTE
)&val
, &size
);
688 ERR("invalid Type\n");
691 lpservicestatus
->dwServiceType
= val
;
692 /* FIXME: how are these determined or read from the registry? */
693 /* SERVICE: unavailable=0, stopped=1, starting=2, running=3? */;
694 lpservicestatus
->dwCurrentState
= 1;
695 lpservicestatus
->dwControlsAccepted
= 0;
696 lpservicestatus
->dwWin32ExitCode
= NO_ERROR
;
697 lpservicestatus
->dwServiceSpecificExitCode
= 0;
698 lpservicestatus
->dwCheckPoint
= 0;
699 lpservicestatus
->dwWaitHint
= 0;