/* * 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 #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; }