wine-wine/dlls/advapi32/service.c

427 lines
14 KiB
C

/*
* Win32 advapi functions
*
* Copyright 1995 Sven Verdoolaege
* Copyright 2005 Mike McCormack
* Copyright 2007 Rolf Kalbermatter
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <stdarg.h>
#include "windef.h"
#include "winbase.h"
#include "winsvc.h"
#include "wine/unicode.h"
#include "wine/debug.h"
#include "advapi32_misc.h"
WINE_DEFAULT_DEBUG_CHANNEL(service);
/******************************************************************************
* LockServiceDatabase [ADVAPI32.@]
*/
SC_LOCK WINAPI LockServiceDatabase( SC_HANDLE manager )
{
/* this function is a no-op in Vista and above */
TRACE("%p\n", manager);
return (SC_LOCK)0xdeadbeef;
}
/******************************************************************************
* UnlockServiceDatabase [ADVAPI32.@]
*/
BOOL WINAPI UnlockServiceDatabase( SC_LOCK lock )
{
/* this function is a no-op in Vista and above */
TRACE("%p\n", lock);
return TRUE;
}
/******************************************************************************
* EnumServicesStatusA [ADVAPI32.@]
*/
BOOL WINAPI
EnumServicesStatusA( SC_HANDLE hmngr, DWORD type, DWORD state, LPENUM_SERVICE_STATUSA
services, DWORD size, LPDWORD needed, LPDWORD returned,
LPDWORD resume_handle )
{
BOOL ret;
unsigned int i;
ENUM_SERVICE_STATUSW *servicesW = NULL;
DWORD sz, n;
char *p;
TRACE("%p 0x%x 0x%x %p %u %p %p %p\n", hmngr, type, state, services, size, needed,
returned, resume_handle);
if (!hmngr)
{
SetLastError( ERROR_INVALID_HANDLE );
return FALSE;
}
if (!needed || !returned)
{
SetLastError( ERROR_INVALID_ADDRESS );
return FALSE;
}
sz = max( 2 * size, sizeof(*servicesW) );
if (!(servicesW = heap_alloc( sz )))
{
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
return FALSE;
}
ret = EnumServicesStatusW( hmngr, type, state, servicesW, sz, needed, returned, resume_handle );
if (!ret) goto done;
p = (char *)services + *returned * sizeof(ENUM_SERVICE_STATUSA);
n = size - (p - (char *)services);
ret = FALSE;
for (i = 0; i < *returned; i++)
{
sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpServiceName, -1, p, n, NULL, NULL );
if (!sz) goto done;
services[i].lpServiceName = p;
p += sz;
n -= sz;
if (servicesW[i].lpDisplayName)
{
sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpDisplayName, -1, p, n, NULL, NULL );
if (!sz) goto done;
services[i].lpDisplayName = p;
p += sz;
n -= sz;
}
else services[i].lpDisplayName = NULL;
services[i].ServiceStatus = servicesW[i].ServiceStatus;
}
ret = TRUE;
done:
heap_free( servicesW );
return ret;
}
/******************************************************************************
* EnumServicesStatusW [ADVAPI32.@]
*/
BOOL WINAPI
EnumServicesStatusW( SC_HANDLE manager, DWORD type, DWORD state, ENUM_SERVICE_STATUSW *status,
DWORD size, DWORD *ret_size, DWORD *ret_count, DWORD *resume_handle )
{
ENUM_SERVICE_STATUS_PROCESSW *status_ex;
DWORD alloc_size, count, i;
WCHAR *p;
TRACE("%p 0x%x 0x%x %p %u %p %p %p\n", manager, type, state, status, size,
ret_size, ret_count, resume_handle);
if (!manager)
{
SetLastError( ERROR_INVALID_HANDLE );
return FALSE;
}
if (!ret_size || !ret_count)
{
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
*ret_size = 0;
*ret_count = 0;
if (!EnumServicesStatusExW( manager, SC_ENUM_PROCESS_INFO, type, state,
NULL, 0, &alloc_size, &count, resume_handle, NULL )
&& GetLastError() != ERROR_MORE_DATA)
return FALSE;
if (!(status_ex = heap_alloc( alloc_size )))
{
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
return FALSE;
}
if (!EnumServicesStatusExW( manager, SC_ENUM_PROCESS_INFO, type, state, (BYTE *)status_ex,
alloc_size, &alloc_size, &count, resume_handle, NULL )
&& GetLastError() != ERROR_MORE_DATA)
{
heap_free( status_ex );
return FALSE;
}
for (i = 0; i < count; i++)
{
*ret_size += sizeof(ENUM_SERVICE_STATUSW);
*ret_size += (strlenW( status_ex[i].lpServiceName ) + 1) * sizeof(WCHAR);
if (status_ex[i].lpDisplayName)
*ret_size += (strlenW( status_ex[i].lpDisplayName ) + 1) * sizeof(WCHAR);
if (*ret_size <= size)
++*ret_count;
}
p = (WCHAR *)(status + *ret_count);
for (i = 0; i < *ret_count; i++)
{
strcpyW( p, status_ex[i].lpServiceName );
status[i].lpServiceName = (WCHAR *)p;
p += strlenW( p ) + 1;
if (status_ex[i].lpDisplayName)
{
strcpyW( p, status_ex[i].lpDisplayName );
status[i].lpDisplayName = (WCHAR *)p;
p += strlenW( p ) + 1;
}
else status[i].lpDisplayName = NULL;
status[i].ServiceStatus.dwServiceType = status_ex[i].ServiceStatusProcess.dwServiceType;
status[i].ServiceStatus.dwCurrentState = status_ex[i].ServiceStatusProcess.dwCurrentState;
status[i].ServiceStatus.dwControlsAccepted = status_ex[i].ServiceStatusProcess.dwControlsAccepted;
status[i].ServiceStatus.dwWin32ExitCode = status_ex[i].ServiceStatusProcess.dwWin32ExitCode;
status[i].ServiceStatus.dwServiceSpecificExitCode = status_ex[i].ServiceStatusProcess.dwServiceSpecificExitCode;
status[i].ServiceStatus.dwCheckPoint = status_ex[i].ServiceStatusProcess.dwCheckPoint;
status[i].ServiceStatus.dwWaitHint = status_ex[i].ServiceStatusProcess.dwWaitHint;
}
heap_free( status_ex );
if (*ret_size > size)
{
SetLastError( ERROR_MORE_DATA );
return FALSE;
}
*ret_size = 0;
return TRUE;
}
/******************************************************************************
* EnumServicesStatusExA [ADVAPI32.@]
*/
BOOL WINAPI
EnumServicesStatusExA( SC_HANDLE hmngr, SC_ENUM_TYPE level, DWORD type, DWORD state,
LPBYTE buffer, DWORD size, LPDWORD needed, LPDWORD returned,
LPDWORD resume_handle, LPCSTR group )
{
BOOL ret;
unsigned int i;
ENUM_SERVICE_STATUS_PROCESSA *services = (ENUM_SERVICE_STATUS_PROCESSA *)buffer;
ENUM_SERVICE_STATUS_PROCESSW *servicesW = NULL;
WCHAR *groupW = NULL;
DWORD sz, n;
char *p;
TRACE("%p %u 0x%x 0x%x %p %u %p %p %p %s\n", hmngr, level, type, state, buffer,
size, needed, returned, resume_handle, debugstr_a(group));
sz = max( 2 * size, sizeof(*servicesW) );
if (!(servicesW = heap_alloc( sz )))
{
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
return FALSE;
}
if (group)
{
int len = MultiByteToWideChar( CP_ACP, 0, group, -1, NULL, 0 );
if (!(groupW = heap_alloc( len * sizeof(WCHAR) )))
{
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
heap_free( servicesW );
return FALSE;
}
MultiByteToWideChar( CP_ACP, 0, group, -1, groupW, len * sizeof(WCHAR) );
}
ret = EnumServicesStatusExW( hmngr, level, type, state, (BYTE *)servicesW, sz,
needed, returned, resume_handle, groupW );
if (!ret) goto done;
p = (char *)services + *returned * sizeof(ENUM_SERVICE_STATUS_PROCESSA);
n = size - (p - (char *)services);
ret = FALSE;
for (i = 0; i < *returned; i++)
{
sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpServiceName, -1, p, n, NULL, NULL );
if (!sz) goto done;
services[i].lpServiceName = p;
p += sz;
n -= sz;
if (servicesW[i].lpDisplayName)
{
sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpDisplayName, -1, p, n, NULL, NULL );
if (!sz) goto done;
services[i].lpDisplayName = p;
p += sz;
n -= sz;
}
else services[i].lpDisplayName = NULL;
services[i].ServiceStatusProcess = servicesW[i].ServiceStatusProcess;
}
ret = TRUE;
done:
heap_free( servicesW );
heap_free( groupW );
return ret;
}
/******************************************************************************
* GetServiceKeyNameA [ADVAPI32.@]
*/
BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
LPSTR lpServiceName, LPDWORD lpcchBuffer )
{
LPWSTR lpDisplayNameW, lpServiceNameW;
DWORD sizeW;
BOOL ret = FALSE;
TRACE("%p %s %p %p\n", hSCManager,
debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
lpDisplayNameW = strdupAW(lpDisplayName);
if (lpServiceName)
lpServiceNameW = heap_alloc(*lpcchBuffer * sizeof(WCHAR));
else
lpServiceNameW = NULL;
sizeW = *lpcchBuffer;
if (!GetServiceKeyNameW(hSCManager, lpDisplayNameW, lpServiceNameW, &sizeW))
{
if (lpServiceName && *lpcchBuffer)
lpServiceName[0] = 0;
*lpcchBuffer = sizeW*2; /* we can only provide an upper estimation of string length */
goto cleanup;
}
if (!WideCharToMultiByte(CP_ACP, 0, lpServiceNameW, (sizeW + 1), lpServiceName,
*lpcchBuffer, NULL, NULL ))
{
if (*lpcchBuffer && lpServiceName)
lpServiceName[0] = 0;
*lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpServiceNameW, -1, NULL, 0, NULL, NULL);
goto cleanup;
}
/* lpcchBuffer not updated - same as in GetServiceDisplayNameA */
ret = TRUE;
cleanup:
heap_free(lpServiceNameW);
heap_free(lpDisplayNameW);
return ret;
}
/******************************************************************************
* QueryServiceLockStatusA [ADVAPI32.@]
*/
BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
DWORD cbBufSize, LPDWORD pcbBytesNeeded)
{
FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
return FALSE;
}
/******************************************************************************
* QueryServiceLockStatusW [ADVAPI32.@]
*/
BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
DWORD cbBufSize, LPDWORD pcbBytesNeeded)
{
FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
return FALSE;
}
/******************************************************************************
* GetServiceDisplayNameA [ADVAPI32.@]
*/
BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
LPSTR lpDisplayName, LPDWORD lpcchBuffer)
{
LPWSTR lpServiceNameW, lpDisplayNameW;
DWORD sizeW;
BOOL ret = FALSE;
TRACE("%p %s %p %p\n", hSCManager,
debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
lpServiceNameW = strdupAW(lpServiceName);
if (lpDisplayName)
lpDisplayNameW = heap_alloc(*lpcchBuffer * sizeof(WCHAR));
else
lpDisplayNameW = NULL;
sizeW = *lpcchBuffer;
if (!GetServiceDisplayNameW(hSCManager, lpServiceNameW, lpDisplayNameW, &sizeW))
{
if (lpDisplayName && *lpcchBuffer)
lpDisplayName[0] = 0;
*lpcchBuffer = sizeW*2; /* we can only provide an upper estimation of string length */
goto cleanup;
}
if (!WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, (sizeW + 1), lpDisplayName,
*lpcchBuffer, NULL, NULL ))
{
if (*lpcchBuffer && lpDisplayName)
lpDisplayName[0] = 0;
*lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, -1, NULL, 0, NULL, NULL);
goto cleanup;
}
/* probably due to a bug GetServiceDisplayNameA doesn't modify lpcchBuffer on success.
* (but if the function succeeded it means that is a good upper estimation of the size) */
ret = TRUE;
cleanup:
heap_free(lpDisplayNameW);
heap_free(lpServiceNameW);
return ret;
}
/******************************************************************************
* SetServiceBits [ADVAPI32.@]
*/
BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
DWORD dwServiceBits,
BOOL bSetBitsOn,
BOOL bUpdateImmediately)
{
FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
bSetBitsOn, bUpdateImmediately);
return TRUE;
}
/******************************************************************************
* EnumDependentServicesA [ADVAPI32.@]
*/
BOOL WINAPI EnumDependentServicesA( SC_HANDLE hService, DWORD dwServiceState,
LPENUM_SERVICE_STATUSA lpServices, DWORD cbBufSize,
LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
{
FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
*lpServicesReturned = 0;
return TRUE;
}