[CMAKE]
authorSylvain Petreolle <spetreolle@yahoo.fr>
Fri, 26 Nov 2010 23:33:34 +0000 (23:33 +0000)
committerSylvain Petreolle <spetreolle@yahoo.fr>
Fri, 26 Nov 2010 23:33:34 +0000 (23:33 +0000)
Sync with trunk. (r49792)

svn path=/branches/cmake-bringup/; revision=49803

110 files changed:
1  2 
base/applications/rapps/rapps/7zip.txt
base/applications/rapps/rapps/libreoffice.txt
base/applications/rapps/rapps/mirandaim.txt
base/applications/rapps/rapps/mono2.txt
base/applications/rapps/rapps/openttd.txt
base/system/services/rpcserver.c
boot/CMakeLists.txt
boot/armllb/boot.s
boot/armllb/crtsupp.c
boot/armllb/envir.c
boot/armllb/fw.c
boot/armllb/hw/matrix.c
boot/armllb/hw/omap3-beagle/hwinfo.c
boot/armllb/hw/omap3-beagle/hwinit.c
boot/armllb/hw/omap3-beagle/hwuart.c
boot/armllb/hw/omap3-zoom2/hwinfo.c
boot/armllb/hw/omap3-zoom2/hwinit.c
boot/armllb/hw/omap3-zoom2/hwlcd.c
boot/armllb/hw/omap3-zoom2/hwsynkp.c
boot/armllb/hw/omap3-zoom2/hwtwl40x.c
boot/armllb/hw/omap3-zoom2/hwuart.c
boot/armllb/hw/time.c
boot/armllb/hw/video.c
boot/armllb/inc/envir.h
boot/armllb/inc/keyboard.h
boot/armllb/inc/machtype.h
boot/armllb/inc/omap3.h
boot/armllb/inc/precomp.h
boot/armllb/main.c
boot/armllb/os/loader.c
boot/freeldr/freeldr/arch/arm/boot.s
boot/freeldr/freeldr/arch/arm/macharm.c
boot/freeldr/freeldr/freeldr_arm.lnk
boot/freeldr/freeldr/include/keycodes.h
boot/freeldr/freeldr/mm/mm.c
boot/freeldr/freeldr/rtl/bget.c
boot/freeldr/freeldr/windows/arm/wlmemory.c
boot/freeldr/freeldr/windows/conversion.c
boot/freeldr/freeldr/windows/winldr.c
boot/freeldr/freeldr/windows/wlregistry.c
dll/ntdll/ldr/utils.c
dll/win32/gdi32/objects/coord.c
dll/win32/gdi32/objects/dc.c
dll/win32/kernel32/file/npipe.c
drivers/filesystems/npfs/create.c
drivers/filesystems/npfs/fsctrl.c
drivers/filesystems/npfs/npfs.c
drivers/filesystems/npfs/npfs.h
hal/halarm/omap3/halinit_up.c
hal/halarm/omap3/halup.rbuild
hal/halarm/omap3/halup.rc
include/crt/mingw32/intrin_arm.h
include/crt/setjmp.h
include/crt/stddef.h
include/ddk/wdm.h
include/ndk/arm/ketypes.h
include/ndk/arm/mmtypes.h
include/ndk/umfuncs.h
include/psdk/specstrings.h
include/psdk/windef.h
include/psdk/winnt.h
include/reactos/arm/armddk.h
include/reactos/wine/exception.h
lib/sdk/crt/misc/assert.c
ntoskrnl/fsrtl/dbcsname.c
ntoskrnl/fsrtl/filtrctx.c
ntoskrnl/fsrtl/name.c
ntoskrnl/include/internal/arm/kxarm.h
ntoskrnl/include/internal/arm/mm.h
ntoskrnl/include/internal/fsrtl.h
ntoskrnl/include/internal/i386/mm.h
ntoskrnl/include/internal/io.h
ntoskrnl/include/internal/mm.h
ntoskrnl/include/internal/ntoskrnl.h
ntoskrnl/io/iomgr/controller.c
ntoskrnl/io/iomgr/file.c
ntoskrnl/ke/arm/boot.s
ntoskrnl/ke/arm/cpu.c
ntoskrnl/ke/arm/ctxswtch.s
ntoskrnl/ke/arm/thrdini.c
ntoskrnl/ke/arm/trapc.c
ntoskrnl/mm/ARM3/arm/init.c
ntoskrnl/mm/ARM3/mdlsup.c
ntoskrnl/mm/ARM3/miarm.h
ntoskrnl/mm/ARM3/mminit.c
ntoskrnl/mm/ARM3/pagfault.c
ntoskrnl/mm/ARM3/pool.c
ntoskrnl/mm/ARM3/procsup.c
ntoskrnl/mm/ARM3/section.c
ntoskrnl/mm/ARM3/virtual.c
ntoskrnl/mm/amd64/init.c
ntoskrnl/mm/arm/page.c
ntoskrnl/mm/arm/stubs.c
ntoskrnl/mm/pagefile.c
ntoskrnl/ntoskrnl.spec
ntoskrnl/po/power.c
subsystems/win32/win32k/include/msgqueue.h
subsystems/win32/win32k/include/winpos.h
subsystems/win32/win32k/ntuser/clipboard.c
subsystems/win32/win32k/ntuser/cursoricon.c
subsystems/win32/win32k/ntuser/desktop.c
subsystems/win32/win32k/ntuser/input.c
subsystems/win32/win32k/ntuser/menu.c
subsystems/win32/win32k/ntuser/message.c
subsystems/win32/win32k/ntuser/msgqueue.c
subsystems/win32/win32k/ntuser/ntstubs.c
subsystems/win32/win32k/ntuser/window.c
subsystems/win32/win32k/ntuser/winpos.c
subsystems/win32/win32k/ntuser/winsta.c
subsystems/win32/win32k/pch.h

index 28bce05,0000000..ad3e460
mode 100644,000000..100644
--- /dev/null
@@@ -1,5418 -1,0 +1,5418 @@@
-     if (dwSecurityInformation & (DACL_SECURITY_INFORMATION ||
-                                  GROUP_SECURITY_INFORMATION ||
 +/*
 + * PROJECT:     ReactOS Service Control Manager
 + * LICENSE:     GPL - See COPYING in the top level directory
 + * FILE:        base/system/services/rpcserver.c
 + * PURPOSE:     RPC server interface for the advapi32 calls
 + * COPYRIGHT:   Copyright 2005-2006 Eric Kohl
 + *              Copyright 2006-2007 HervĂ© Poussineau <hpoussin@reactos.org>
 + *              Copyright 2007 Ged Murphy <gedmurphy@reactos.org>
 + */
 +
 +/* INCLUDES ****************************************************************/
 +
 +#include "services.h"
 +#include "svcctl_s.h"
 +
 +#define NDEBUG
 +#include <debug.h>
 +
 +/* GLOBALS *****************************************************************/
 +
 +#define MANAGER_TAG 0x72674D68  /* 'hMgr' */
 +#define SERVICE_TAG 0x63765368  /* 'hSvc' */
 +
 +typedef struct _SCMGR_HANDLE
 +{
 +    DWORD Tag;
 +    DWORD DesiredAccess;
 +} SCMGR_HANDLE;
 +
 +
 +typedef struct _MANAGER_HANDLE
 +{
 +    SCMGR_HANDLE Handle;
 +    WCHAR DatabaseName[1];
 +} MANAGER_HANDLE, *PMANAGER_HANDLE;
 +
 +
 +typedef struct _SERVICE_HANDLE
 +{
 +    SCMGR_HANDLE Handle;
 +    PSERVICE ServiceEntry;
 +} SERVICE_HANDLE, *PSERVICE_HANDLE;
 +
 +
 +#define SC_MANAGER_READ \
 +  (STANDARD_RIGHTS_READ | \
 +   SC_MANAGER_QUERY_LOCK_STATUS | \
 +   SC_MANAGER_ENUMERATE_SERVICE)
 +
 +#define SC_MANAGER_WRITE \
 +  (STANDARD_RIGHTS_WRITE | \
 +   SC_MANAGER_MODIFY_BOOT_CONFIG | \
 +   SC_MANAGER_CREATE_SERVICE)
 +
 +#define SC_MANAGER_EXECUTE \
 +  (STANDARD_RIGHTS_EXECUTE | \
 +   SC_MANAGER_LOCK | \
 +   SC_MANAGER_ENUMERATE_SERVICE | \
 +   SC_MANAGER_CONNECT | \
 +   SC_MANAGER_CREATE_SERVICE)
 +
 +
 +#define SERVICE_READ \
 +  (STANDARD_RIGHTS_READ | \
 +   SERVICE_INTERROGATE | \
 +   SERVICE_ENUMERATE_DEPENDENTS | \
 +   SERVICE_QUERY_STATUS | \
 +   SERVICE_QUERY_CONFIG)
 +
 +#define SERVICE_WRITE \
 +  (STANDARD_RIGHTS_WRITE | \
 +   SERVICE_CHANGE_CONFIG)
 +
 +#define SERVICE_EXECUTE \
 +  (STANDARD_RIGHTS_EXECUTE | \
 +   SERVICE_USER_DEFINED_CONTROL | \
 +   SERVICE_PAUSE_CONTINUE | \
 +   SERVICE_STOP | \
 +   SERVICE_START)
 +
 +
 +/* VARIABLES ***************************************************************/
 +
 +static GENERIC_MAPPING
 +ScmManagerMapping = {SC_MANAGER_READ,
 +                     SC_MANAGER_WRITE,
 +                     SC_MANAGER_EXECUTE,
 +                     SC_MANAGER_ALL_ACCESS};
 +
 +static GENERIC_MAPPING
 +ScmServiceMapping = {SERVICE_READ,
 +                     SERVICE_WRITE,
 +                     SERVICE_EXECUTE,
 +                     SC_MANAGER_ALL_ACCESS};
 +
 +
 +/* FUNCTIONS ***************************************************************/
 +
 +VOID
 +ScmStartRpcServer(VOID)
 +{
 +    RPC_STATUS Status;
 +
 +    DPRINT("ScmStartRpcServer() called\n");
 +
 +    Status = RpcServerUseProtseqEpW(L"ncacn_np",
 +                                    10,
 +                                    L"\\pipe\\ntsvcs",
 +                                    NULL);
 +    if (Status != RPC_S_OK)
 +    {
 +        DPRINT1("RpcServerUseProtseqEpW() failed (Status %lx)\n", Status);
 +        return;
 +    }
 +
 +    Status = RpcServerRegisterIf(svcctl_v2_0_s_ifspec,
 +                                 NULL,
 +                                 NULL);
 +    if (Status != RPC_S_OK)
 +    {
 +        DPRINT1("RpcServerRegisterIf() failed (Status %lx)\n", Status);
 +        return;
 +    }
 +
 +    Status = RpcServerListen(1, 20, TRUE);
 +    if (Status != RPC_S_OK)
 +    {
 +        DPRINT1("RpcServerListen() failed (Status %lx)\n", Status);
 +        return;
 +    }
 +
 +    DPRINT("ScmStartRpcServer() done\n");
 +}
 +
 +
 +static DWORD
 +ScmCreateManagerHandle(LPWSTR lpDatabaseName,
 +                       SC_HANDLE *Handle)
 +{
 +    PMANAGER_HANDLE Ptr;
 +
 +    if (lpDatabaseName == NULL)
 +        lpDatabaseName = SERVICES_ACTIVE_DATABASEW;
 +
 +    if (_wcsicmp(lpDatabaseName, SERVICES_FAILED_DATABASEW) == 0)
 +    {
 +        DPRINT("Database %S, does not exist\n",lpDatabaseName);
 +        return ERROR_DATABASE_DOES_NOT_EXIST;
 +    }
 +    else if (_wcsicmp(lpDatabaseName, SERVICES_ACTIVE_DATABASEW) != 0)
 +    {
 +        DPRINT("Invalid Database name %S.\n",lpDatabaseName);
 +        return ERROR_INVALID_NAME;
 +    }
 +
 +    Ptr = (MANAGER_HANDLE*) HeapAlloc(GetProcessHeap(),
 +                    HEAP_ZERO_MEMORY,
 +                    sizeof(MANAGER_HANDLE) + (wcslen(lpDatabaseName) + 1) * sizeof(WCHAR));
 +    if (Ptr == NULL)
 +        return ERROR_NOT_ENOUGH_MEMORY;
 +
 +    Ptr->Handle.Tag = MANAGER_TAG;
 +
 +    wcscpy(Ptr->DatabaseName, lpDatabaseName);
 +
 +    *Handle = (SC_HANDLE)Ptr;
 +
 +    return ERROR_SUCCESS;
 +}
 +
 +
 +static DWORD
 +ScmCreateServiceHandle(PSERVICE lpServiceEntry,
 +                       SC_HANDLE *Handle)
 +{
 +    PSERVICE_HANDLE Ptr;
 +
 +    Ptr = (SERVICE_HANDLE*) HeapAlloc(GetProcessHeap(),
 +                    HEAP_ZERO_MEMORY,
 +                    sizeof(SERVICE_HANDLE));
 +    if (Ptr == NULL)
 +        return ERROR_NOT_ENOUGH_MEMORY;
 +
 +    Ptr->Handle.Tag = SERVICE_TAG;
 +
 +    Ptr->ServiceEntry = lpServiceEntry;
 +
 +    *Handle = (SC_HANDLE)Ptr;
 +
 +    return ERROR_SUCCESS;
 +}
 +
 +
 +static PMANAGER_HANDLE
 +ScmGetServiceManagerFromHandle(SC_RPC_HANDLE Handle)
 +{
 +    PMANAGER_HANDLE pManager = NULL;
 +
 +    _SEH2_TRY
 +    {
 +        if (((PMANAGER_HANDLE)Handle)->Handle.Tag == MANAGER_TAG)
 +            pManager = (PMANAGER_HANDLE)Handle;
 +    }
 +    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
 +    {
 +        DPRINT1("Exception: Invalid Service Manager handle!\n");
 +    }
 +    _SEH2_END;
 +
 +    return pManager;
 +}
 +
 +
 +static PSERVICE_HANDLE
 +ScmGetServiceFromHandle(SC_RPC_HANDLE Handle)
 +{
 +    PSERVICE_HANDLE pService = NULL;
 +
 +    _SEH2_TRY
 +    {
 +        if (((PSERVICE_HANDLE)Handle)->Handle.Tag == SERVICE_TAG)
 +            pService = (PSERVICE_HANDLE)Handle;
 +    }
 +    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
 +    {
 +        DPRINT1("Exception: Invalid Service handle!\n");
 +    }
 +    _SEH2_END;
 +
 +    return pService;
 +}
 +
 +
 +static DWORD
 +ScmCheckAccess(SC_HANDLE Handle,
 +               DWORD dwDesiredAccess)
 +{
 +    PMANAGER_HANDLE hMgr;
 +
 +    hMgr = (PMANAGER_HANDLE)Handle;
 +    if (hMgr->Handle.Tag == MANAGER_TAG)
 +    {
 +        RtlMapGenericMask(&dwDesiredAccess,
 +                          &ScmManagerMapping);
 +
 +        hMgr->Handle.DesiredAccess = dwDesiredAccess;
 +
 +        return ERROR_SUCCESS;
 +    }
 +    else if (hMgr->Handle.Tag == SERVICE_TAG)
 +    {
 +        RtlMapGenericMask(&dwDesiredAccess,
 +                          &ScmServiceMapping);
 +
 +        hMgr->Handle.DesiredAccess = dwDesiredAccess;
 +
 +        return ERROR_SUCCESS;
 +    }
 +
 +    return ERROR_INVALID_HANDLE;
 +}
 +
 +
 +DWORD
 +ScmAssignNewTag(PSERVICE lpService)
 +{
 +    /* FIXME */
 +    DPRINT("Assigning new tag to service %S\n", lpService->lpServiceName);
 +    lpService->dwTag = 0;
 +    return ERROR_SUCCESS;
 +}
 +
 +
 +/* Internal recursive function */
 +/* Need to search for every dependency on every service */
 +static DWORD
 +Int_EnumDependentServicesW(HKEY hServicesKey,
 +                           PSERVICE lpService,
 +                           DWORD dwServiceState,
 +                           PSERVICE *lpServices,
 +                           LPDWORD pcbBytesNeeded,
 +                           LPDWORD lpServicesReturned)
 +{
 +    DWORD dwError = ERROR_SUCCESS;
 +    WCHAR szNameBuf[MAX_PATH];
 +    WCHAR szValueBuf[MAX_PATH];
 +    WCHAR *lpszNameBuf = szNameBuf;
 +    WCHAR *lpszValueBuf = szValueBuf;
 +    DWORD dwSize;
 +    DWORD dwNumSubKeys;
 +    DWORD dwIteration;
 +    PSERVICE lpCurrentService;
 +    HKEY hServiceEnumKey;
 +    DWORD dwCurrentServiceState = SERVICE_ACTIVE;
 +    DWORD dwDependServiceStrPtr = 0;
 +    DWORD dwRequiredSize = 0;
 +
 +    /* Get the number of service keys */
 +    dwError = RegQueryInfoKeyW(hServicesKey,
 +                               NULL,
 +                               NULL,
 +                               NULL,
 +                               &dwNumSubKeys,
 +                               NULL,
 +                               NULL,
 +                               NULL,
 +                               NULL,
 +                               NULL,
 +                               NULL,
 +                               NULL);
 +    if (dwError != ERROR_SUCCESS)
 +    {
 +        DPRINT("ERROR! Unable to get number of services keys.\n");
 +        return dwError;
 +    }
 +
 +    /* Iterate the service keys to see if another service depends on the this service */
 +    for (dwIteration = 0; dwIteration < dwNumSubKeys; dwIteration++)
 +    {
 +        dwSize = MAX_PATH;
 +        dwError = RegEnumKeyExW(hServicesKey,
 +                                dwIteration,
 +                                lpszNameBuf,
 +                                &dwSize,
 +                                NULL,
 +                                NULL,
 +                                NULL,
 +                                NULL);
 +        if (dwError != ERROR_SUCCESS)
 +            return dwError;
 +
 +        /* Open the Service key */
 +        dwError = RegOpenKeyExW(hServicesKey,
 +                                lpszNameBuf,
 +                                0,
 +                                KEY_READ,
 +                                &hServiceEnumKey);
 +        if (dwError != ERROR_SUCCESS)
 +            return dwError;
 +
 +        dwSize = MAX_PATH;
 +
 +        /* Check for the DependOnService Value */
 +        dwError = RegQueryValueExW(hServiceEnumKey,
 +                                   L"DependOnService",
 +                                   NULL,
 +                                   NULL,
 +                                   (LPBYTE)lpszValueBuf,
 +                                   &dwSize);
 +
 +        /* FIXME: Handle load order. */
 +
 +        /* If the service found has a DependOnService value */
 +        if (dwError == ERROR_SUCCESS)
 +        {
 +            dwDependServiceStrPtr = 0;
 +
 +            /* Can be more than one Dependencies in the DependOnService string */
 +            while (wcslen(lpszValueBuf + dwDependServiceStrPtr) > 0)
 +            {
 +                if (_wcsicmp(lpszValueBuf + dwDependServiceStrPtr, lpService->lpServiceName) == 0)
 +                {
 +                    /* Get the current enumed service pointer */
 +                    lpCurrentService = ScmGetServiceEntryByName(lpszNameBuf);
 +
 +                    /* Check for valid Service */
 +                    if (!lpCurrentService)
 +                    {
 +                        /* This should never happen! */
 +                        DPRINT("This should not happen at this point, report to Developer\n");
 +                        return ERROR_NOT_FOUND;
 +                    }
 +
 +                    /* Determine state the service is in */
 +                    if (lpCurrentService->Status.dwCurrentState == SERVICE_STOPPED)
 +                        dwCurrentServiceState = SERVICE_INACTIVE;
 +
 +                    /* If the ServiceState matches that requested or searching for SERVICE_STATE_ALL */
 +                    if ((dwCurrentServiceState == dwServiceState) ||
 +                        (dwServiceState == SERVICE_STATE_ALL))
 +                    {
 +                        /* Calculate the required size */
 +                        dwRequiredSize += sizeof(SERVICE_STATUS);
 +                        dwRequiredSize += ((wcslen(lpCurrentService->lpServiceName) + 1) * sizeof(WCHAR));
 +                        dwRequiredSize += ((wcslen(lpCurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
 +
 +                        /* Add the size for service name and display name pointers */
 +                        dwRequiredSize += (2 * sizeof(PVOID));
 +
 +                        /* increase the BytesNeeded size */
 +                        *pcbBytesNeeded = *pcbBytesNeeded + dwRequiredSize;
 +
 +                        /* Don't fill callers buffer yet, as MSDN read that the last service with dependency
 +                           comes first */
 +
 +                        /* Recursive call to check for its dependencies */
 +                        Int_EnumDependentServicesW(hServicesKey,
 +                                                   lpCurrentService,
 +                                                   dwServiceState,
 +                                                   lpServices,
 +                                                   pcbBytesNeeded,
 +                                                   lpServicesReturned);
 +
 +                        /* If the lpServices is valid set the service pointer */
 +                        if (lpServices)
 +                            lpServices[*lpServicesReturned] = lpCurrentService;
 +
 +                        *lpServicesReturned = *lpServicesReturned + 1;
 +                    }
 +                }
 +
 +                dwDependServiceStrPtr += (wcslen(lpszValueBuf + dwDependServiceStrPtr) + 1);
 +            }
 +        }
 +        else if (*pcbBytesNeeded)
 +        {
 +            dwError = ERROR_SUCCESS;
 +        }
 +
 +        RegCloseKey(hServiceEnumKey);
 +    }
 +
 +    return dwError;
 +}
 +
 +
 +/* Function 0 */
 +DWORD RCloseServiceHandle(
 +    LPSC_RPC_HANDLE hSCObject)
 +{
 +    PMANAGER_HANDLE hManager;
 +    PSERVICE_HANDLE hService;
 +    PSERVICE lpService;
 +    HKEY hServicesKey;
 +    DWORD dwError;
 +    DWORD pcbBytesNeeded = 0;
 +    DWORD dwServicesReturned = 0;
 +
 +    DPRINT("RCloseServiceHandle() called\n");
 +
 +    DPRINT("hSCObject = %p\n", *hSCObject);
 +
 +    if (*hSCObject == 0)
 +        return ERROR_INVALID_HANDLE;
 +
 +    hManager = ScmGetServiceManagerFromHandle(*hSCObject);
 +    hService = ScmGetServiceFromHandle(*hSCObject);
 +
 +    if (hManager != NULL)
 +    {
 +        DPRINT("Found manager handle\n");
 +
 +        /* FIXME: add handle cleanup code */
 +
 +        HeapFree(GetProcessHeap(), 0, hManager);
 +        hManager = NULL;
 +
 +        DPRINT("RCloseServiceHandle() done\n");
 +        return ERROR_SUCCESS;
 +    }
 +    else if (hService != NULL)
 +    {
 +        DPRINT("Found service handle\n");
 +
 +        /* Get the pointer to the service record */
 +        lpService = hService->ServiceEntry;
 +
 +        /* FIXME: add handle cleanup code */
 +
 +        /* Free the handle */
 +        HeapFree(GetProcessHeap(), 0, hService);
 +        hService = NULL;
 +
 +        ASSERT(lpService->dwRefCount > 0);
 +
 +        lpService->dwRefCount--;
 +        DPRINT("CloseServiceHandle - lpService->dwRefCount %u\n",
 +               lpService->dwRefCount);
 +
 +        if (lpService->dwRefCount == 0)
 +        {
 +            /* If this service has been marked for deletion */
 +            if (lpService->bDeleted)
 +            {
 +                /* Open the Services Reg key */
 +                dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
 +                                        L"System\\CurrentControlSet\\Services",
 +                                        0,
 +                                        KEY_SET_VALUE | KEY_READ,
 +                                        &hServicesKey);
 +                if (dwError != ERROR_SUCCESS)
 +                {
 +                    DPRINT("Failed to open services key\n");
 +                    return dwError;
 +                }
 +
 +                /* Call the internal function with NULL, just to get bytes we need */
 +                Int_EnumDependentServicesW(hServicesKey,
 +                                           lpService,
 +                                           SERVICE_ACTIVE,
 +                                           NULL,
 +                                           &pcbBytesNeeded,
 +                                           &dwServicesReturned);
 +
 +                /* if pcbBytesNeeded returned a value then there are services running that are dependent on this service*/
 +                if (pcbBytesNeeded)
 +                {
 +                    DPRINT("Deletion failed due to running dependencies.\n");
 +                    RegCloseKey(hServicesKey);
 +                    return ERROR_SUCCESS;
 +                }
 +
 +                /* There are no references and no runnning dependencies,
 +                   it is now safe to delete the service */
 +
 +                /* Delete the Service Key */
 +                dwError = RegDeleteKeyW(hServicesKey,
 +                                        lpService->lpServiceName);
 +
 +                RegCloseKey(hServicesKey);
 +
 +                if (dwError != ERROR_SUCCESS)
 +                {
 +                    DPRINT("Failed to Delete the Service Registry key\n");
 +                    return dwError;
 +                }
 +
 +                /* Delete the Service */
 +                ScmDeleteServiceRecord(lpService);
 +            }
 +        }
 +
 +        DPRINT("RCloseServiceHandle() done\n");
 +        return ERROR_SUCCESS;
 +    }
 +
 +    DPRINT("Invalid handle tag (Tag %lx)\n", hManager->Handle.Tag);
 +
 +    return ERROR_INVALID_HANDLE;
 +}
 +
 +
 +/* Function 1 */
 +DWORD RControlService(
 +    SC_RPC_HANDLE hService,
 +    DWORD dwControl,
 +    LPSERVICE_STATUS lpServiceStatus)
 +{
 +    PSERVICE_HANDLE hSvc;
 +    PSERVICE lpService;
 +    ACCESS_MASK DesiredAccess;
 +    DWORD dwError = ERROR_SUCCESS;
 +    DWORD pcbBytesNeeded = 0;
 +    DWORD dwServicesReturned = 0;
 +    DWORD dwControlsAccepted;
 +    DWORD dwCurrentState;
 +    HKEY hServicesKey = NULL;
 +
 +    DPRINT("RControlService() called\n");
 +
 +    if (ScmShutdown)
 +        return ERROR_SHUTDOWN_IN_PROGRESS;
 +
 +    /* Check the service handle */
 +    hSvc = ScmGetServiceFromHandle(hService);
 +    if (hSvc == NULL)
 +    {
 +        DPRINT1("Invalid service handle!\n");
 +        return ERROR_INVALID_HANDLE;
 +    }
 +
 +
 +    /* Check the service entry point */
 +    lpService = hSvc->ServiceEntry;
 +    if (lpService == NULL)
 +    {
 +        DPRINT1("lpService == NULL!\n"); 
 +        return ERROR_INVALID_HANDLE;
 +    }
 +
 +    /* Check access rights */
 +    switch (dwControl)
 +    {
 +        case SERVICE_CONTROL_STOP:
 +            DesiredAccess = SERVICE_STOP;
 +            break;
 +
 +        case SERVICE_CONTROL_PAUSE:
 +        case SERVICE_CONTROL_CONTINUE:
 +            DesiredAccess = SERVICE_PAUSE_CONTINUE;
 +            break;
 +
 +        case SERVICE_INTERROGATE:
 +            DesiredAccess = SERVICE_INTERROGATE;
 +            break;
 +
 +        default:
 +            if (dwControl >= 128 && dwControl <= 255)
 +                DesiredAccess = SERVICE_USER_DEFINED_CONTROL;
 +            else
 +                DesiredAccess = SERVICE_QUERY_CONFIG |
 +                                SERVICE_CHANGE_CONFIG |
 +                                SERVICE_QUERY_STATUS |
 +                                SERVICE_START |
 +                                SERVICE_PAUSE_CONTINUE;
 +            break;
 +    }
 +
 +    if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
 +                                  DesiredAccess))
 +        return ERROR_ACCESS_DENIED;
 +
 +    if (dwControl == SERVICE_CONTROL_STOP)
 +    {
 +        /* Check if the service has dependencies running as windows
 +           doesn't stop a service that does */
 +
 +        /* Open the Services Reg key */
 +        dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
 +                                L"System\\CurrentControlSet\\Services",
 +                                0,
 +                                KEY_READ,
 +                                &hServicesKey);
 +        if (dwError != ERROR_SUCCESS)
 +        {
 +            DPRINT("Failed to open services key\n");
 +            return dwError;
 +        }
 +
 +        /* Call the internal function with NULL, just to get bytes we need */
 +        Int_EnumDependentServicesW(hServicesKey,
 +                                   lpService,
 +                                   SERVICE_ACTIVE,
 +                                   NULL,
 +                                   &pcbBytesNeeded,
 +                                   &dwServicesReturned);
 +
 +        RegCloseKey(hServicesKey);
 +
 +        /* If pcbBytesNeeded is not zero then there are services running that
 +           are dependent on this service */
 +        if (pcbBytesNeeded != 0)
 +        {
 +            DPRINT("Service has running dependencies. Failed to stop service.\n");
 +            return ERROR_DEPENDENT_SERVICES_RUNNING;
 +        }
 +    }
 +
 +    if (lpService->Status.dwServiceType & SERVICE_DRIVER)
 +    {
 +        /* Send control code to the driver */
 +        dwError = ScmControlDriver(lpService,
 +                                   dwControl,
 +                                   lpServiceStatus);
 +    }
 +    else
 +    {
 +        dwControlsAccepted = lpService->Status.dwControlsAccepted;
 +        dwCurrentState = lpService->Status.dwCurrentState;
 +
 +        /* Check the current state before sending a control request */
 +        switch (dwCurrentState)
 +        {
 +            case SERVICE_STOP_PENDING:
 +            case SERVICE_STOPPED:
 +                return ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
 +
 +            case SERVICE_START_PENDING:
 +                switch (dwControl)
 +                {
 +                    case SERVICE_CONTROL_STOP:
 +                        break;
 +
 +                    case SERVICE_CONTROL_INTERROGATE:
 +                        RtlCopyMemory(lpServiceStatus,
 +                                      &lpService->Status,
 +                                      sizeof(SERVICE_STATUS));
 +                        return ERROR_SUCCESS;
 +
 +                    default:
 +                        return ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
 +                }
 +                break;
 +        }
 +
 +        /* Check if the control code is acceptable to the service */
 +        switch (dwControl)
 +        {
 +            case SERVICE_CONTROL_STOP:
 +                if ((dwControlsAccepted & SERVICE_ACCEPT_STOP) == 0)
 +                    return ERROR_INVALID_SERVICE_CONTROL;
 +                break;
 +
 +            case SERVICE_CONTROL_PAUSE:
 +            case SERVICE_CONTROL_CONTINUE:
 +                if ((dwControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE) == 0)
 +                    return ERROR_INVALID_SERVICE_CONTROL;
 +                break;
 +        }
 +
 +        /* Send control code to the service */
 +        dwError = ScmControlService(lpService,
 +                                    dwControl);
 +
 +        /* Return service status information */
 +        RtlCopyMemory(lpServiceStatus,
 +                      &lpService->Status,
 +                      sizeof(SERVICE_STATUS));
 +    }
 +
 +    if ((dwError == ERROR_SUCCESS) && (pcbBytesNeeded))
 +        dwError = ERROR_DEPENDENT_SERVICES_RUNNING;
 +
 +    if (dwError == ERROR_SUCCESS &&
 +        dwControl == SERVICE_CONTROL_STOP && 
 +        lpServiceStatus->dwCurrentState == SERVICE_STOPPED)
 +    {
 +        lpService->ProcessId = 0; /* FIXME */
 +        lpService->ThreadId = 0;
 +    }
 +
 +
 +    return dwError;
 +}
 +
 +
 +/* Function 2 */
 +DWORD RDeleteService(
 +    SC_RPC_HANDLE hService)
 +{
 +    PSERVICE_HANDLE hSvc;
 +    PSERVICE lpService;
 +    DWORD dwError;
 +
 +    DPRINT("RDeleteService() called\n");
 +
 +    if (ScmShutdown)
 +        return ERROR_SHUTDOWN_IN_PROGRESS;
 +
 +    hSvc = ScmGetServiceFromHandle(hService);
 +    if (hSvc == NULL)
 +    {
 +        DPRINT1("Invalid service handle!\n");
 +        return ERROR_INVALID_HANDLE;
 +    }
 +
 +    if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
 +                                  DELETE))
 +        return ERROR_ACCESS_DENIED;
 +
 +    lpService = hSvc->ServiceEntry;
 +    if (lpService == NULL)
 +    {
 +        DPRINT("lpService == NULL!\n");
 +        return ERROR_INVALID_HANDLE;
 +    }
 +
 +    /* FIXME: Acquire service database lock exclusively */
 +
 +    if (lpService->bDeleted)
 +    {
 +        DPRINT("The service has already been marked for delete!\n");
 +        return ERROR_SERVICE_MARKED_FOR_DELETE;
 +    }
 +
 +    /* Mark service for delete */
 +    lpService->bDeleted = TRUE;
 +
 +    dwError = ScmMarkServiceForDelete(lpService);
 +
 +    /* FIXME: Release service database lock */
 +
 +    DPRINT("RDeleteService() done\n");
 +
 +    return dwError;
 +}
 +
 +
 +/* Function 3 */
 +DWORD RLockServiceDatabase(
 +    SC_RPC_HANDLE hSCManager,
 +    LPSC_RPC_LOCK lpLock)
 +{
 +    PMANAGER_HANDLE hMgr;
 +
 +    DPRINT("RLockServiceDatabase() called\n");
 +
 +    *lpLock = 0;
 +
 +    hMgr = ScmGetServiceManagerFromHandle(hSCManager);
 +    if (hMgr == NULL)
 +    {
 +        DPRINT1("Invalid service manager handle!\n");
 +        return ERROR_INVALID_HANDLE;
 +    }
 +
 +    if (!RtlAreAllAccessesGranted(hMgr->Handle.DesiredAccess,
 +                                  SC_MANAGER_LOCK))
 +        return ERROR_ACCESS_DENIED;
 +
 +//    return ScmLockDatabase(0, hMgr->0xC, hLock);
 +
 +    /* FIXME: Lock the database */
 +    *lpLock = (SC_RPC_LOCK)0x12345678; /* Dummy! */
 +
 +    return ERROR_SUCCESS;
 +}
 +
 +
 +/* Function 4 */
 +DWORD RQueryServiceObjectSecurity(
 +    SC_RPC_HANDLE hService,
 +    SECURITY_INFORMATION dwSecurityInformation,
 +    LPBYTE lpSecurityDescriptor,
 +    DWORD cbBufSize,
 +    LPBOUNDED_DWORD_256K pcbBytesNeeded)
 +{
 +    PSERVICE_HANDLE hSvc;
 +    PSERVICE lpService;
 +    ULONG DesiredAccess = 0;
 +    NTSTATUS Status;
 +    DWORD dwBytesNeeded;
 +    DWORD dwError;
 +
 +
 +    SECURITY_DESCRIPTOR ObjectDescriptor;
 +
 +    DPRINT("RQueryServiceObjectSecurity() called\n");
 +
 +    hSvc = ScmGetServiceFromHandle(hService);
 +    if (hSvc == NULL)
 +    {
 +        DPRINT1("Invalid service handle!\n");
 +        return ERROR_INVALID_HANDLE;
 +    }
 +
++    if (dwSecurityInformation & (DACL_SECURITY_INFORMATION |
++                                 GROUP_SECURITY_INFORMATION |
 +                                 OWNER_SECURITY_INFORMATION))
 +        DesiredAccess |= READ_CONTROL;
 +
 +    if (dwSecurityInformation & SACL_SECURITY_INFORMATION)
 +        DesiredAccess |= ACCESS_SYSTEM_SECURITY;
 +
 +    if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
 +                                  DesiredAccess))
 +    {
 +        DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
 +        return ERROR_ACCESS_DENIED;
 +    }
 +
 +    lpService = hSvc->ServiceEntry;
 +    if (lpService == NULL)
 +    {
 +        DPRINT("lpService == NULL!\n");
 +        return ERROR_INVALID_HANDLE;
 +    }
 +
 +    /* FIXME: Lock the service list */
 +
 +    /* hack */
 +    Status = RtlCreateSecurityDescriptor(&ObjectDescriptor, SECURITY_DESCRIPTOR_REVISION);
 +
 +    Status = RtlQuerySecurityObject(&ObjectDescriptor  /* lpService->lpSecurityDescriptor */,
 +                                    dwSecurityInformation,
 +                                    (PSECURITY_DESCRIPTOR)lpSecurityDescriptor,
 +                                    cbBufSize,
 +                                    &dwBytesNeeded);
 +
 +    /* FIXME: Unlock the service list */
 +
 +    if (NT_SUCCESS(Status))
 +    {
 +        *pcbBytesNeeded = dwBytesNeeded;
 +        dwError = STATUS_SUCCESS;
 +    }
 +    else if (Status == STATUS_BUFFER_TOO_SMALL)
 +    {
 +        *pcbBytesNeeded = dwBytesNeeded;
 +        dwError = ERROR_INSUFFICIENT_BUFFER;
 +    }
 +    else if (Status == STATUS_BAD_DESCRIPTOR_FORMAT)
 +    {
 +        dwError = ERROR_GEN_FAILURE;
 +    }
 +    else
 +    {
 +        dwError = RtlNtStatusToDosError(Status);
 +    }
 +
 +    return dwError;
 +}
 +
 +
 +/* Function 5 */
 +DWORD RSetServiceObjectSecurity(
 +    SC_RPC_HANDLE hService,
 +    DWORD dwSecurityInformation,
 +    LPBYTE lpSecurityDescriptor,
 +    DWORD dwSecuityDescriptorSize)
 +{
 +    PSERVICE_HANDLE hSvc;
 +    PSERVICE lpService;
 +    ULONG DesiredAccess = 0;
 +    /* HANDLE hToken = NULL; */
 +    HKEY hServiceKey;
 +    /* NTSTATUS Status; */
 +    DWORD dwError;
 +
 +    DPRINT("RSetServiceObjectSecurity() called\n");
 +
 +    hSvc = ScmGetServiceFromHandle(hService);
 +    if (hSvc == NULL)
 +    {
 +        DPRINT1("Invalid service handle!\n");
 +        return ERROR_INVALID_HANDLE;
 +    }
 +
 +    if (dwSecurityInformation == 0 ||
 +        dwSecurityInformation & ~(OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION
 +        | DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION))
 +        return ERROR_INVALID_PARAMETER;
 +
 +    if (!RtlValidSecurityDescriptor((PSECURITY_DESCRIPTOR)lpSecurityDescriptor))
 +        return ERROR_INVALID_PARAMETER;
 +
 +    if (dwSecurityInformation & SACL_SECURITY_INFORMATION)
 +        DesiredAccess |= ACCESS_SYSTEM_SECURITY;
 +
 +    if (dwSecurityInformation & DACL_SECURITY_INFORMATION)
 +        DesiredAccess |= WRITE_DAC;
 +
 +    if (dwSecurityInformation & (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION))
 +        DesiredAccess |= WRITE_OWNER;
 +
 +    if ((dwSecurityInformation & OWNER_SECURITY_INFORMATION) &&
 +        (((PISECURITY_DESCRIPTOR)lpSecurityDescriptor)->Owner == NULL))
 +        return ERROR_INVALID_PARAMETER;
 +
 +    if ((dwSecurityInformation & GROUP_SECURITY_INFORMATION) &&
 +        (((PISECURITY_DESCRIPTOR)lpSecurityDescriptor)->Group == NULL))
 +        return ERROR_INVALID_PARAMETER;
 +
 +    if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
 +                                  DesiredAccess))
 +    {
 +        DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
 +        return ERROR_ACCESS_DENIED;
 +    }
 +
 +    lpService = hSvc->ServiceEntry;
 +    if (lpService == NULL)
 +    {
 +        DPRINT("lpService == NULL!\n");
 +        return ERROR_INVALID_HANDLE;
 +    }
 +
 +    if (lpService->bDeleted)
 +        return ERROR_SERVICE_MARKED_FOR_DELETE;
 +
 +#if 0
 +    RpcImpersonateClient(NULL);
 +
 +    Status = NtOpenThreadToken(NtCurrentThread(),
 +                               8,
 +                               TRUE,
 +                               &hToken);
 +    if (!NT_SUCCESS(Status))
 +        return RtlNtStatusToDosError(Status); 
 +
 +    RpcRevertToSelf();
 +
 +    /* FIXME: Lock service database */
 +
 +    Status = RtlSetSecurityObject(dwSecurityInformation,
 +                                  (PSECURITY_DESCRIPTOR)lpSecurityDescriptor,
 +                                  &lpService->lpSecurityDescriptor,
 +                                  &ScmServiceMapping,
 +                                  hToken);
 +    if (!NT_SUCCESS(Status))
 +    {
 +        dwError = RtlNtStatusToDosError(Status);
 +        goto Done;
 +    }
 +#endif
 +
 +    dwError = ScmOpenServiceKey(lpService->lpServiceName,
 +                                READ_CONTROL | KEY_CREATE_SUB_KEY | KEY_SET_VALUE,
 +                                &hServiceKey);
 +    if (dwError != ERROR_SUCCESS)
 +        goto Done;
 +
 +    UNIMPLEMENTED;
 +    dwError = ERROR_SUCCESS;
 +//    dwError = ScmWriteSecurityDescriptor(hServiceKey,
 +//                                         lpService->lpSecurityDescriptor);
 +
 +    RegFlushKey(hServiceKey);
 +    RegCloseKey(hServiceKey);
 +
 +Done:
 +
 +#if 0
 +    if (hToken != NULL)
 +        NtClose(hToken);
 +#endif
 +
 +    /* FIXME: Unlock service database */
 +
 +    DPRINT("RSetServiceObjectSecurity() done (Error %lu)\n", dwError);
 +
 +    return dwError;
 +}
 +
 +
 +/* Function 6 */
 +DWORD RQueryServiceStatus(
 +    SC_RPC_HANDLE hService,
 +    LPSERVICE_STATUS lpServiceStatus)
 +{
 +    PSERVICE_HANDLE hSvc;
 +    PSERVICE lpService;
 +
 +    DPRINT("RQueryServiceStatus() called\n");
 +
 +    if (ScmShutdown)
 +        return ERROR_SHUTDOWN_IN_PROGRESS;
 +
 +    hSvc = ScmGetServiceFromHandle(hService);
 +    if (hSvc == NULL)
 +    {
 +        DPRINT1("Invalid service handle!\n");
 +        return ERROR_INVALID_HANDLE;
 +    }
 +
 +    if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
 +                                  SERVICE_QUERY_STATUS))
 +    {
 +        DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
 +        return ERROR_ACCESS_DENIED;
 +    }
 +
 +    lpService = hSvc->ServiceEntry;
 +    if (lpService == NULL)
 +    {
 +        DPRINT("lpService == NULL!\n");
 +        return ERROR_INVALID_HANDLE;
 +    }
 +
 +    ScmLockDatabaseShared();
 +
 +    /* Return service status information */
 +    RtlCopyMemory(lpServiceStatus,
 +                  &lpService->Status,
 +                  sizeof(SERVICE_STATUS));
 +
 +    ScmUnlockDatabase();
 +
 +    return ERROR_SUCCESS;
 +}
 +
 +
 +static BOOL
 +ScmIsValidServiceState(DWORD dwCurrentState)
 +{
 +    switch (dwCurrentState)
 +    {
 +        case SERVICE_STOPPED:
 +        case SERVICE_START_PENDING:
 +        case SERVICE_STOP_PENDING:
 +        case SERVICE_RUNNING:
 +        case SERVICE_CONTINUE_PENDING:
 +        case SERVICE_PAUSE_PENDING:
 +        case SERVICE_PAUSED:
 +            return TRUE;
 +
 +        default:
 +            return FALSE;
 +    }
 +}
 +
 +
 +/* Function 7 */
 +DWORD RSetServiceStatus(
 +    RPC_SERVICE_STATUS_HANDLE hServiceStatus,
 +    LPSERVICE_STATUS lpServiceStatus)
 +{
 +    PSERVICE lpService;
 +
 +    DPRINT("RSetServiceStatus() called\n");
 +    DPRINT("hServiceStatus = %p\n", hServiceStatus);
 +    DPRINT("dwServiceType = %lu\n", lpServiceStatus->dwServiceType);
 +    DPRINT("dwCurrentState = %lu\n", lpServiceStatus->dwCurrentState);
 +    DPRINT("dwControlsAccepted = %lu\n", lpServiceStatus->dwControlsAccepted);
 +    DPRINT("dwWin32ExitCode = %lu\n", lpServiceStatus->dwWin32ExitCode);
 +    DPRINT("dwServiceSpecificExitCode = %lu\n", lpServiceStatus->dwServiceSpecificExitCode);
 +    DPRINT("dwCheckPoint = %lu\n", lpServiceStatus->dwCheckPoint);
 +    DPRINT("dwWaitHint = %lu\n", lpServiceStatus->dwWaitHint);
 +
 +    if (hServiceStatus == 0)
 +    {
 +        DPRINT("hServiceStatus == NULL!\n");
 +        return ERROR_INVALID_HANDLE;
 +    }
 +
 +    lpService = (PSERVICE)hServiceStatus;
 +    if (lpService == NULL)
 +    {
 +        DPRINT("lpService == NULL!\n");
 +        return ERROR_INVALID_HANDLE;
 +    }
 +
 +    /* Check current state */
 +    if (!ScmIsValidServiceState(lpServiceStatus->dwCurrentState))
 +    {
 +        DPRINT("Invalid service state!\n");
 +        return ERROR_INVALID_DATA;
 +    }
 +
 +    /* Check service type */
 +    if (!(lpServiceStatus->dwServiceType & SERVICE_WIN32) &&
 +         (lpServiceStatus->dwServiceType & SERVICE_DRIVER))
 +    {
 +        DPRINT("Invalid service type!\n");
 +        return ERROR_INVALID_DATA;
 +    }
 +
 +    /* Check accepted controls */
 +    if (lpServiceStatus->dwControlsAccepted & ~0xFF)
 +    {
 +        DPRINT("Invalid controls accepted!\n");
 +        return ERROR_INVALID_DATA;
 +    }
 +
 +    ScmLockDatabaseExclusive();
 +
 +    RtlCopyMemory(&lpService->Status,
 +                  lpServiceStatus,
 +                  sizeof(SERVICE_STATUS));
 +
 +    ScmUnlockDatabase();
 +
 +    DPRINT("Set %S to %lu\n", lpService->lpDisplayName, lpService->Status.dwCurrentState);
 +    DPRINT("RSetServiceStatus() done\n");
 +
 +    return ERROR_SUCCESS;
 +}
 +
 +
 +/* Function 8 */
 +DWORD RUnlockServiceDatabase(
 +    LPSC_RPC_LOCK Lock)
 +{
 +    UNIMPLEMENTED;
 +    return ERROR_SUCCESS;
 +}
 +
 +
 +/* Function 9 */
 +DWORD RNotifyBootConfigStatus(
 +    SVCCTL_HANDLEW lpMachineName,
 +    DWORD BootAcceptable)
 +{
 +    UNIMPLEMENTED;
 +    return ERROR_CALL_NOT_IMPLEMENTED;
 +}
 +
 +
 +/* Function 10 */
 +DWORD RI_ScSetServiceBitsW(
 +    RPC_SERVICE_STATUS_HANDLE hServiceStatus,
 +    DWORD dwServiceBits,
 +    int bSetBitsOn,
 +    int bUpdateImmediately,
 +    wchar_t *lpString)
 +{
 +    UNIMPLEMENTED;
 +    return ERROR_CALL_NOT_IMPLEMENTED;
 +}
 +
 +
 +/* Function 11 */
 +DWORD RChangeServiceConfigW(
 +    SC_RPC_HANDLE hService,
 +    DWORD dwServiceType,
 +    DWORD dwStartType,
 +    DWORD dwErrorControl,
 +    LPWSTR lpBinaryPathName,
 +    LPWSTR lpLoadOrderGroup,
 +    LPDWORD lpdwTagId,
 +    LPBYTE lpDependencies,
 +    DWORD dwDependSize,
 +    LPWSTR lpServiceStartName,
 +    LPBYTE lpPassword,
 +    DWORD dwPwSize,
 +    LPWSTR lpDisplayName)
 +{
 +    DWORD dwError = ERROR_SUCCESS;
 +    PSERVICE_HANDLE hSvc;
 +    PSERVICE lpService = NULL;
 +    HKEY hServiceKey = NULL;
 +    LPWSTR lpDisplayNameW = NULL;
 +
 +    DPRINT("RChangeServiceConfigW() called\n");
 +    DPRINT("dwServiceType = %lu\n", dwServiceType);
 +    DPRINT("dwStartType = %lu\n", dwStartType);
 +    DPRINT("dwErrorControl = %lu\n", dwErrorControl);
 +    DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName);
 +    DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup);
 +    DPRINT("lpDisplayName = %S\n", lpDisplayName);
 +
 +    if (ScmShutdown)
 +        return ERROR_SHUTDOWN_IN_PROGRESS;
 +
 +    hSvc = ScmGetServiceFromHandle(hService);
 +    if (hSvc == NULL)
 +    {
 +        DPRINT1("Invalid service handle!\n");
 +        return ERROR_INVALID_HANDLE;
 +    }
 +
 +    if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
 +                                  SERVICE_CHANGE_CONFIG))
 +    {
 +        DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
 +        return ERROR_ACCESS_DENIED;
 +    }
 +
 +    lpService = hSvc->ServiceEntry;
 +    if (lpService == NULL)
 +    {
 +        DPRINT("lpService == NULL!\n");
 +        return ERROR_INVALID_HANDLE;
 +    }
 +
 +    /* FIXME: Lock database exclusively */
 +
 +    if (lpService->bDeleted)
 +    {
 +        /* FIXME: Unlock database */
 +        DPRINT("The service has already been marked for delete!\n");
 +        return ERROR_SERVICE_MARKED_FOR_DELETE;
 +    }
 +
 +    /* Open the service key */
 +    dwError = ScmOpenServiceKey(lpService->szServiceName,
 +                                KEY_SET_VALUE,
 +                                &hServiceKey);
 +    if (dwError != ERROR_SUCCESS)
 +        goto done;
 +
 +    /* Write service data to the registry */
 +    /* Set the display name */
 +    if (lpDisplayName != NULL && *lpDisplayName != 0)
 +    {
 +        RegSetValueExW(hServiceKey,
 +                       L"DisplayName",
 +                       0,
 +                       REG_SZ,
 +                       (LPBYTE)lpDisplayName,
 +                       (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
 +
 +        /* Update the display name */
 +        lpDisplayNameW = (LPWSTR)HeapAlloc(GetProcessHeap(),
 +                                           0,
 +                                           (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
 +        if (lpDisplayNameW == NULL)
 +        {
 +            dwError = ERROR_NOT_ENOUGH_MEMORY;
 +            goto done;
 +        }
 +
 +        if (lpService->lpDisplayName != lpService->lpServiceName)
 +            HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
 +
 +        lpService->lpDisplayName = lpDisplayNameW;
 +    }
 +
 +    if (dwServiceType != SERVICE_NO_CHANGE)
 +    {
 +        /* Set the service type */
 +        dwError = RegSetValueExW(hServiceKey,
 +                                 L"Type",
 +                                 0,
 +                                 REG_DWORD,
 +                                 (LPBYTE)&dwServiceType,
 +                                 sizeof(DWORD));
 +        if (dwError != ERROR_SUCCESS)
 +            goto done;
 +
 +        lpService->Status.dwServiceType = dwServiceType;
 +    }
 +
 +    if (dwStartType != SERVICE_NO_CHANGE)
 +    {
 +        /* Set the start value */
 +        dwError = RegSetValueExW(hServiceKey,
 +                                 L"Start",
 +                                 0,
 +                                 REG_DWORD,
 +                                 (LPBYTE)&dwStartType,
 +                                 sizeof(DWORD));
 +        if (dwError != ERROR_SUCCESS)
 +            goto done;
 +
 +        lpService->dwStartType = dwStartType;
 +    }
 +
 +    if (dwErrorControl != SERVICE_NO_CHANGE)
 +    {
 +        /* Set the error control value */
 +        dwError = RegSetValueExW(hServiceKey,
 +                                 L"ErrorControl",
 +                                 0,
 +                                 REG_DWORD,
 +                                 (LPBYTE)&dwErrorControl,
 +                                 sizeof(DWORD));
 +        if (dwError != ERROR_SUCCESS)
 +            goto done;
 +
 +        lpService->dwErrorControl = dwErrorControl;
 +    }
 +
 +#if 0
 +    /* FIXME: set the new ImagePath value */
 +
 +    /* Set the image path */
 +    if (dwServiceType & SERVICE_WIN32)
 +    {
 +        if (lpBinaryPathName != NULL && *lpBinaryPathName != 0)
 +        {
 +            dwError = RegSetValueExW(hServiceKey,
 +                                     L"ImagePath",
 +                                     0,
 +                                     REG_EXPAND_SZ,
 +                                     (LPBYTE)lpBinaryPathName,
 +                                     (wcslen(lpBinaryPathName) + 1) * sizeof(WCHAR));
 +            if (dwError != ERROR_SUCCESS)
 +                goto done;
 +        }
 +    }
 +    else if (dwServiceType & SERVICE_DRIVER)
 +    {
 +        if (lpImagePath != NULL && *lpImagePath != 0)
 +        {
 +            dwError = RegSetValueExW(hServiceKey,
 +                                     L"ImagePath",
 +                                     0,
 +                                     REG_EXPAND_SZ,
 +                                     (LPBYTE)lpImagePath,
 +                                     (wcslen(lpImagePath) + 1) *sizeof(WCHAR));
 +            if (dwError != ERROR_SUCCESS)
 +                goto done;
 +        }
 +    }
 +#endif
 +
 +    /* Set the group name */
 +    if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
 +    {
 +        dwError = RegSetValueExW(hServiceKey,
 +                                 L"Group",
 +                                 0,
 +                                 REG_SZ,
 +                                 (LPBYTE)lpLoadOrderGroup,
 +                                 (wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR));
 +        if (dwError != ERROR_SUCCESS)
 +            goto done;
 +
 +        dwError = ScmSetServiceGroup(lpService,
 +                                     lpLoadOrderGroup);
 +        if (dwError != ERROR_SUCCESS)
 +            goto done;
 +    }
 +
 +    if (lpdwTagId != NULL)
 +    {
 +        dwError = ScmAssignNewTag(lpService);
 +        if (dwError != ERROR_SUCCESS)
 +            goto done;
 +
 +        dwError = RegSetValueExW(hServiceKey,
 +                                 L"Tag",
 +                                 0,
 +                                 REG_DWORD,
 +                                 (LPBYTE)&lpService->dwTag,
 +                                 sizeof(DWORD));
 +        if (dwError != ERROR_SUCCESS)
 +            goto done;
 +
 +        *lpdwTagId = lpService->dwTag;
 +    }
 +
 +    /* Write dependencies */
 +    if (lpDependencies != NULL && *lpDependencies != 0)
 +    {
 +        dwError = ScmWriteDependencies(hServiceKey,
 +                                       (LPWSTR)lpDependencies,
 +                                       dwDependSize);
 +        if (dwError != ERROR_SUCCESS)
 +            goto done;
 +    }
 +
 +    if (lpPassword != NULL)
 +    {
 +        /* FIXME: Write password */
 +    }
 +
 +    /* FIXME: Unlock database */
 +
 +done:
 +    if (hServiceKey != NULL)
 +        RegCloseKey(hServiceKey);
 +
 +    DPRINT("RChangeServiceConfigW() done (Error %lu)\n", dwError);
 +
 +    return dwError;
 +}
 +
 +
 +/* Create a path suitable for the bootloader out of the full path */
 +DWORD
 +ScmConvertToBootPathName(wchar_t *CanonName, wchar_t **RelativeName)
 +{
 +    DWORD ServiceNameLen, BufferSize, ExpandedLen;
 +    WCHAR Dest;
 +    WCHAR *Expanded;
 +    UNICODE_STRING NtPathName, SystemRoot, LinkTarget;
 +    OBJECT_ATTRIBUTES ObjectAttributes;
 +    NTSTATUS Status;
 +    HANDLE SymbolicLinkHandle;
 +
 +    DPRINT("ScmConvertToBootPathName %S\n", CanonName);
 +
 +    ServiceNameLen = wcslen(CanonName);
 +
 +    /* First check, if it's already good */
 +    if (ServiceNameLen > 12 &&
 +        !_wcsnicmp(L"\\SystemRoot\\", CanonName, 12))
 +    {
 +        *RelativeName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR) + sizeof(WCHAR));
 +        if (*RelativeName == NULL)
 +        {
 +            DPRINT("Error allocating memory for boot driver name!\n");
 +            return ERROR_NOT_ENOUGH_MEMORY;
 +        }
 +
 +        /* Copy it */
 +        wcscpy(*RelativeName, CanonName);
 +
 +        DPRINT("Bootdriver name %S\n", *RelativeName);
 +        return ERROR_SUCCESS;
 +    }
 +
 +    /* If it has %SystemRoot% prefix, substitute it to \System*/
 +    if (ServiceNameLen > 13 &&
 +        !_wcsnicmp(L"%SystemRoot%\\", CanonName, 13))
 +    {
 +        /* There is no +sizeof(wchar_t) because the name is less by 1 wchar */
 +        *RelativeName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR));
 +
 +        if (*RelativeName == NULL)
 +        {
 +            DPRINT("Error allocating memory for boot driver name!\n");
 +            return ERROR_NOT_ENOUGH_MEMORY;
 +        }
 +
 +        /* Copy it */
 +        wcscpy(*RelativeName, L"\\SystemRoot\\");
 +        wcscat(*RelativeName, CanonName + 13);
 +
 +        DPRINT("Bootdriver name %S\n", *RelativeName);
 +        return ERROR_SUCCESS;
 +    }
 +
 +    /* Get buffer size needed for expanding env strings */
 +    BufferSize = ExpandEnvironmentStringsW(L"%SystemRoot%\\", &Dest, 1);
 +
 +    if (BufferSize <= 1)
 +    {
 +        DPRINT("Error during a call to ExpandEnvironmentStringsW()\n");
 +        return ERROR_INVALID_ENVIRONMENT;
 +    }
 +
 +    /* Allocate memory, since the size is known now */
 +    Expanded = LocalAlloc(LMEM_ZEROINIT, BufferSize * sizeof(WCHAR) + sizeof(WCHAR));
 +    if (!Expanded)
 +    {
 +        DPRINT("Error allocating memory for boot driver name!\n");
 +        return ERROR_NOT_ENOUGH_MEMORY;
 +    }
 +
 +    /* Expand it */
 +    if (ExpandEnvironmentStringsW(L"%SystemRoot%\\", Expanded, BufferSize) >
 +        BufferSize)
 +    {
 +        DPRINT("Error during a call to ExpandEnvironmentStringsW()\n");
 +        LocalFree(Expanded);
 +        return ERROR_NOT_ENOUGH_MEMORY;
 +    }
 +
 +    /* Convert to NY-style path */
 +    if (!RtlDosPathNameToNtPathName_U(Expanded, &NtPathName, NULL, NULL))
 +    {
 +        DPRINT("Error during a call to RtlDosPathNameToNtPathName_U()\n");
 +        return ERROR_INVALID_ENVIRONMENT;
 +    }
 +
 +    DPRINT("Converted to NT-style %wZ\n", &NtPathName);
 +
 +    /* No need to keep the dos-path anymore */
 +    LocalFree(Expanded);
 +
 +    /* Copy it to the allocated place */
 +    Expanded = LocalAlloc(LMEM_ZEROINIT, NtPathName.Length + sizeof(WCHAR));
 +    if (!Expanded)
 +    {
 +            DPRINT("Error allocating memory for boot driver name!\n");
 +            return ERROR_NOT_ENOUGH_MEMORY;
 +    }
 +
 +    ExpandedLen = NtPathName.Length / sizeof(WCHAR);
 +    wcsncpy(Expanded, NtPathName.Buffer, ExpandedLen);
 +    Expanded[ExpandedLen] = 0;
 +
 +    if (ServiceNameLen > ExpandedLen &&
 +        !_wcsnicmp(Expanded, CanonName, ExpandedLen))
 +    {
 +        /* Only \SystemRoot\ is missing */
 +        *RelativeName = LocalAlloc(LMEM_ZEROINIT,
 +            (ServiceNameLen - ExpandedLen) * sizeof(WCHAR) + 13*sizeof(WCHAR));
 +        if (*RelativeName == NULL)
 +        {
 +            DPRINT("Error allocating memory for boot driver name!\n");
 +            LocalFree(Expanded);
 +            return ERROR_NOT_ENOUGH_MEMORY;
 +        }
 +
 +        wcscpy(*RelativeName, L"\\SystemRoot\\");
 +        wcscat(*RelativeName, CanonName + ExpandedLen);
 +
 +        RtlFreeUnicodeString(&NtPathName);
 +        return ERROR_SUCCESS;
 +    }
 +
 +    /* The most complex case starts here */
 +    RtlInitUnicodeString(&SystemRoot, L"\\SystemRoot");
 +    InitializeObjectAttributes(&ObjectAttributes,
 +                               &SystemRoot,
 +                               OBJ_CASE_INSENSITIVE,
 +                               NULL,
 +                               NULL);
 +
 +    /* Open this symlink */
 +    Status = NtOpenSymbolicLinkObject(&SymbolicLinkHandle, SYMBOLIC_LINK_QUERY, &ObjectAttributes);
 +
 +    if (NT_SUCCESS(Status))
 +    {
 +        LinkTarget.Length = 0;
 +        LinkTarget.MaximumLength = 0;
 +
 +        DPRINT("Opened symbolic link object\n");
 +
 +        Status = NtQuerySymbolicLinkObject(SymbolicLinkHandle, &LinkTarget, &BufferSize);
 +        if (NT_SUCCESS(Status) || Status == STATUS_BUFFER_TOO_SMALL)
 +        {
 +            /* Check if required buffer size is sane */
 +            if (BufferSize > 0xFFFD)
 +            {
 +                DPRINT("Too large buffer required\n");
 +                *RelativeName = 0;
 +
 +                if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
 +                LocalFree(Expanded);
 +                return ERROR_NOT_ENOUGH_MEMORY;
 +            }
 +
 +            /* Alloc the string */
 +            LinkTarget.Buffer = LocalAlloc(LMEM_ZEROINIT, BufferSize + sizeof(WCHAR));
 +            if (!LinkTarget.Buffer)
 +            {
 +                DPRINT("Unable to alloc buffer\n");
 +                if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
 +                LocalFree(Expanded);
 +                return ERROR_NOT_ENOUGH_MEMORY;
 +            }
 +
 +            /* Do a real query now */
 +            LinkTarget.Length = BufferSize;
 +            LinkTarget.MaximumLength = LinkTarget.Length + sizeof(WCHAR);
 +
 +            Status = NtQuerySymbolicLinkObject(SymbolicLinkHandle, &LinkTarget, &BufferSize);
 +            if (NT_SUCCESS(Status))
 +            {
 +                DPRINT("LinkTarget: %wZ\n", &LinkTarget);
 +
 +                ExpandedLen = LinkTarget.Length / sizeof(WCHAR);
 +                if ((ServiceNameLen > ExpandedLen) &&
 +                    !_wcsnicmp(LinkTarget.Buffer, CanonName, ExpandedLen))
 +                {
 +                    *RelativeName = LocalAlloc(LMEM_ZEROINIT,
 +                       (ServiceNameLen - ExpandedLen) * sizeof(WCHAR) + 13*sizeof(WCHAR));
 +
 +                    if (*RelativeName == NULL)
 +                    {
 +                        DPRINT("Unable to alloc buffer\n");
 +                        if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
 +                        LocalFree(Expanded);
 +                        RtlFreeUnicodeString(&NtPathName);
 +                        return ERROR_NOT_ENOUGH_MEMORY;
 +                    }
 +
 +                    /* Copy it over, substituting the first part
 +                       with SystemRoot */
 +                    wcscpy(*RelativeName, L"\\SystemRoot\\");
 +                    wcscat(*RelativeName, CanonName+ExpandedLen+1);
 +
 +                    /* Cleanup */
 +                    if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
 +                    LocalFree(Expanded);
 +                    RtlFreeUnicodeString(&NtPathName);
 +
 +                    /* Return success */
 +                    return ERROR_SUCCESS;
 +                }
 +                else
 +                {
 +                    if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
 +                    LocalFree(Expanded);
 +                    RtlFreeUnicodeString(&NtPathName);
 +                    return ERROR_INVALID_PARAMETER;
 +                }
 +            }
 +            else
 +            {
 +                DPRINT("Error, Status = %08X\n", Status);
 +                if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
 +                LocalFree(Expanded);
 +                RtlFreeUnicodeString(&NtPathName);
 +                return ERROR_INVALID_PARAMETER;
 +            }
 +        }
 +        else
 +        {
 +            DPRINT("Error, Status = %08X\n", Status);
 +            if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
 +            LocalFree(Expanded);
 +            RtlFreeUnicodeString(&NtPathName);
 +            return ERROR_INVALID_PARAMETER;
 +        }
 +    }
 +    else
 +    {
 +        DPRINT("Error, Status = %08X\n", Status);
 +        LocalFree(Expanded);
 +        return ERROR_INVALID_PARAMETER;
 +    }
 +
 +    /* Failure */
 +    *RelativeName = NULL;
 +    return ERROR_INVALID_PARAMETER;
 +}
 +
 +DWORD
 +ScmCanonDriverImagePath(DWORD dwStartType,
 +                        const wchar_t *lpServiceName,
 +                        wchar_t **lpCanonName)
 +{
 +    DWORD ServiceNameLen, Result;
 +    UNICODE_STRING NtServiceName;
 +    WCHAR *RelativeName;
 +    const WCHAR *SourceName = lpServiceName;
 +
 +    /* Calculate the length of the service's name */
 +    ServiceNameLen = wcslen(lpServiceName);
 +
 +    /* 12 is wcslen(L"\\SystemRoot\\") */
 +    if (ServiceNameLen > 12 &&
 +        !_wcsnicmp(L"\\SystemRoot\\", lpServiceName, 12))
 +    {
 +        /* SystemRoot prefix is already included */
 +
 +        *lpCanonName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR) + sizeof(WCHAR));
 +
 +        if (*lpCanonName == NULL)
 +        {
 +            DPRINT("Error allocating memory for canonized service name!\n");
 +            return ERROR_NOT_ENOUGH_MEMORY;
 +        }
 +
 +        /* If it's a boot-time driver, it must be systemroot relative */
 +        if (dwStartType == SERVICE_BOOT_START)
 +            SourceName += 12;
 +
 +        /* Copy it */
 +        wcscpy(*lpCanonName, SourceName);
 +
 +        DPRINT("Canonicalized name %S\n", *lpCanonName);
 +        return NO_ERROR;
 +    }
 +
 +    /* Check if it has %SystemRoot% (len=13) */
 +    if (ServiceNameLen > 13 &&
 +        !_wcsnicmp(L"%%SystemRoot%%\\", lpServiceName, 13))
 +    {
 +        /* Substitute %SystemRoot% with \\SystemRoot\\ */
 +        *lpCanonName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR) + sizeof(WCHAR));
 +
 +        if (*lpCanonName == NULL)
 +        {
 +            DPRINT("Error allocating memory for canonized service name!\n");
 +            return ERROR_NOT_ENOUGH_MEMORY;
 +        }
 +
 +        /* If it's a boot-time driver, it must be systemroot relative */
 +        if (dwStartType == SERVICE_BOOT_START)
 +            wcscpy(*lpCanonName, L"\\SystemRoot\\");
 +
 +        wcscat(*lpCanonName, lpServiceName + 13);
 +
 +        DPRINT("Canonicalized name %S\n", *lpCanonName);
 +        return NO_ERROR;
 +    }
 +
 +    /* Check if it's a relative path name */
 +    if (lpServiceName[0] != L'\\' && lpServiceName[1] != L':')
 +    {
 +        *lpCanonName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR) + sizeof(WCHAR));
 +
 +        if (*lpCanonName == NULL)
 +        {
 +            DPRINT("Error allocating memory for canonized service name!\n");
 +            return ERROR_NOT_ENOUGH_MEMORY;
 +        }
 +
 +        /* Just copy it over without changing */
 +        wcscpy(*lpCanonName, lpServiceName);
 +
 +        return NO_ERROR;
 +    }
 +
 +    /* It seems to be a DOS path, convert it */
 +    if (!RtlDosPathNameToNtPathName_U(lpServiceName, &NtServiceName, NULL, NULL))
 +    {
 +        DPRINT("RtlDosPathNameToNtPathName_U() failed!\n");
 +        return ERROR_INVALID_PARAMETER;
 +    }
 +
 +    *lpCanonName = LocalAlloc(LMEM_ZEROINIT, NtServiceName.Length + sizeof(WCHAR));
 +
 +    if (*lpCanonName == NULL)
 +    {
 +        DPRINT("Error allocating memory for canonized service name!\n");
 +        RtlFreeUnicodeString(&NtServiceName);
 +        return ERROR_NOT_ENOUGH_MEMORY;
 +    }
 +
 +    /* Copy the string */
 +    wcsncpy(*lpCanonName, NtServiceName.Buffer, NtServiceName.Length / sizeof(WCHAR));
 +
 +    /* The unicode string is not needed anymore */
 +    RtlFreeUnicodeString(&NtServiceName);
 +
 +    if (dwStartType != SERVICE_BOOT_START)
 +    {
 +        DPRINT("Canonicalized name %S\n", *lpCanonName);
 +        return NO_ERROR;
 +    }
 +
 +    /* The service is boot-started, so must be relative */
 +    Result = ScmConvertToBootPathName(*lpCanonName, &RelativeName);
 +    if (Result)
 +    {
 +        /* There is a problem, free name and return */
 +        LocalFree(*lpCanonName);
 +        DPRINT("Error converting named!\n");
 +        return Result;
 +    }
 +
 +    ASSERT(RelativeName);
 +
 +    /* Copy that string */
 +    wcscpy(*lpCanonName, RelativeName + 12);
 +
 +    /* Free the allocated buffer */
 +    LocalFree(RelativeName);
 +
 +    DPRINT("Canonicalized name %S\n", *lpCanonName);
 +
 +    /* Success */
 +    return NO_ERROR;
 +}
 +
 +
 +/* Function 12 */
 +DWORD RCreateServiceW(
 +    SC_RPC_HANDLE hSCManager,
 +    LPCWSTR lpServiceName,
 +    LPCWSTR lpDisplayName,
 +    DWORD dwDesiredAccess,
 +    DWORD dwServiceType,
 +    DWORD dwStartType,
 +    DWORD dwErrorControl,
 +    LPCWSTR lpBinaryPathName,
 +    LPCWSTR lpLoadOrderGroup,
 +    LPDWORD lpdwTagId,
 +    LPBYTE lpDependencies,
 +    DWORD dwDependSize,
 +    LPCWSTR lpServiceStartName,
 +    LPBYTE lpPassword,
 +    DWORD dwPwSize,
 +    LPSC_RPC_HANDLE lpServiceHandle)
 +{
 +    PMANAGER_HANDLE hManager;
 +    DWORD dwError = ERROR_SUCCESS;
 +    PSERVICE lpService = NULL;
 +    SC_HANDLE hServiceHandle = NULL;
 +    LPWSTR lpImagePath = NULL;
 +    HKEY hServiceKey = NULL;
 +    LPWSTR lpObjectName;
 +
 +    DPRINT("RCreateServiceW() called\n");
 +    DPRINT("lpServiceName = %S\n", lpServiceName);
 +    DPRINT("lpDisplayName = %S\n", lpDisplayName);
 +    DPRINT("dwDesiredAccess = %lx\n", dwDesiredAccess);
 +    DPRINT("dwServiceType = %lu\n", dwServiceType);
 +    DPRINT("dwStartType = %lu\n", dwStartType);
 +    DPRINT("dwErrorControl = %lu\n", dwErrorControl);
 +    DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName);
 +    DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup);
 +
 +    if (ScmShutdown)
 +        return ERROR_SHUTDOWN_IN_PROGRESS;
 +
 +    hManager = ScmGetServiceManagerFromHandle(hSCManager);
 +    if (hManager == NULL)
 +    {
 +        DPRINT1("Invalid service manager handle!\n");
 +        return ERROR_INVALID_HANDLE;
 +    }
 +
 +    /* Check access rights */
 +    if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
 +                                  SC_MANAGER_CREATE_SERVICE))
 +    {
 +        DPRINT("Insufficient access rights! 0x%lx\n",
 +               hManager->Handle.DesiredAccess);
 +        return ERROR_ACCESS_DENIED;
 +    }
 +
 +    if (wcslen(lpServiceName) == 0)
 +    {
 +        return ERROR_INVALID_NAME;
 +    }
 +
 +    if (wcslen(lpBinaryPathName) == 0)
 +    {
 +        return ERROR_INVALID_PARAMETER;
 +    }
 +
 +    if ((dwServiceType == (SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS)) &&
 +        (lpServiceStartName))
 +    {
 +        return ERROR_INVALID_PARAMETER;
 +    }
 +
 +    if ((dwServiceType > SERVICE_WIN32_SHARE_PROCESS) &&
 +        (dwServiceType != (SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS)) &&
 +        (dwServiceType != (SERVICE_WIN32_SHARE_PROCESS | SERVICE_INTERACTIVE_PROCESS)))
 +    {
 +        return ERROR_INVALID_PARAMETER;
 +    }
 +
 +    if (dwStartType > SERVICE_DISABLED)
 +    {
 +        return ERROR_INVALID_PARAMETER;
 +    }
 +
 +    lpService = ScmGetServiceEntryByName(lpServiceName);
 +    if (lpService)
 +    {
 +        /* check if it is marked for deletion */
 +        if (lpService->bDeleted)
 +            return ERROR_SERVICE_MARKED_FOR_DELETE;
 +        /* Return Error exist */
 +        return ERROR_SERVICE_EXISTS;
 +    }
 +
 +    if (lpDisplayName != NULL &&
 +        ScmGetServiceEntryByDisplayName(lpDisplayName) != NULL)
 +        return ERROR_DUPLICATE_SERVICE_NAME;
 +
 +    if (dwServiceType & SERVICE_DRIVER)
 +    {
 +        dwError = ScmCanonDriverImagePath(dwStartType,
 +                                          lpBinaryPathName,
 +                                          &lpImagePath);
 +        if (dwError != ERROR_SUCCESS)
 +            goto done;
 +    }
 +    else
 +    {
 +        if (dwStartType == SERVICE_BOOT_START ||
 +            dwStartType == SERVICE_SYSTEM_START)
 +        {
 +            return ERROR_INVALID_PARAMETER;
 +        }
 +    }
 +
 +    /* Allocate a new service entry */
 +    dwError = ScmCreateNewServiceRecord(lpServiceName,
 +                                        &lpService);
 +    if (dwError != ERROR_SUCCESS)
 +        goto done;
 +
 +    /* Fill the new service entry */
 +    lpService->Status.dwServiceType = dwServiceType;
 +    lpService->dwStartType = dwStartType;
 +    lpService->dwErrorControl = dwErrorControl;
 +
 +    /* Fill the display name */
 +    if (lpDisplayName != NULL &&
 +        *lpDisplayName != 0 &&
 +        _wcsicmp(lpService->lpDisplayName, lpDisplayName) != 0)
 +    {
 +        lpService->lpDisplayName = (WCHAR*) HeapAlloc(GetProcessHeap(), 0,
 +                                             (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
 +        if (lpService->lpDisplayName == NULL)
 +        {
 +            dwError = ERROR_NOT_ENOUGH_MEMORY;
 +            goto done;
 +        }
 +        wcscpy(lpService->lpDisplayName, lpDisplayName);
 +    }
 +
 +    /* Assign the service to a group */
 +    if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
 +    {
 +        dwError = ScmSetServiceGroup(lpService,
 +                                     lpLoadOrderGroup);
 +        if (dwError != ERROR_SUCCESS)
 +            goto done;
 +    }
 +
 +    /* Assign a new tag */
 +    if (lpdwTagId != NULL)
 +    {
 +        dwError = ScmAssignNewTag(lpService);
 +        if (dwError != ERROR_SUCCESS)
 +            goto done;
 +    }
 +
 +    /* Write service data to the registry */
 +    /* Create the service key */
 +    dwError = ScmCreateServiceKey(lpServiceName,
 +                                  KEY_WRITE,
 +                                  &hServiceKey);
 +    if (dwError != ERROR_SUCCESS)
 +        goto done;
 +
 +    /* Set the display name */
 +    if (lpDisplayName != NULL && *lpDisplayName != 0)
 +    {
 +        RegSetValueExW(hServiceKey,
 +                       L"DisplayName",
 +                       0,
 +                       REG_SZ,
 +                       (LPBYTE)lpDisplayName,
 +                       (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
 +    }
 +
 +    /* Set the service type */
 +    dwError = RegSetValueExW(hServiceKey,
 +                             L"Type",
 +                             0,
 +                             REG_DWORD,
 +                             (LPBYTE)&dwServiceType,
 +                             sizeof(DWORD));
 +    if (dwError != ERROR_SUCCESS)
 +        goto done;
 +
 +    /* Set the start value */
 +    dwError = RegSetValueExW(hServiceKey,
 +                             L"Start",
 +                             0,
 +                             REG_DWORD,
 +                             (LPBYTE)&dwStartType,
 +                             sizeof(DWORD));
 +    if (dwError != ERROR_SUCCESS)
 +        goto done;
 +
 +    /* Set the error control value */
 +    dwError = RegSetValueExW(hServiceKey,
 +                             L"ErrorControl",
 +                             0,
 +                             REG_DWORD,
 +                             (LPBYTE)&dwErrorControl,
 +                             sizeof(DWORD));
 +    if (dwError != ERROR_SUCCESS)
 +        goto done;
 +
 +    /* Set the image path */
 +    if (dwServiceType & SERVICE_WIN32)
 +    {
 +        dwError = RegSetValueExW(hServiceKey,
 +                                 L"ImagePath",
 +                                 0,
 +                                 REG_EXPAND_SZ,
 +                                 (LPBYTE)lpBinaryPathName,
 +                                 (wcslen(lpBinaryPathName) + 1) * sizeof(WCHAR));
 +        if (dwError != ERROR_SUCCESS)
 +            goto done;
 +    }
 +    else if (dwServiceType & SERVICE_DRIVER)
 +    {
 +        dwError = RegSetValueExW(hServiceKey,
 +                                 L"ImagePath",
 +                                 0,
 +                                 REG_EXPAND_SZ,
 +                                 (LPBYTE)lpImagePath,
 +                                 (wcslen(lpImagePath) + 1) * sizeof(WCHAR));
 +        if (dwError != ERROR_SUCCESS)
 +            goto done;
 +    }
 +
 +    /* Set the group name */
 +    if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
 +    {
 +        dwError = RegSetValueExW(hServiceKey,
 +                                 L"Group",
 +                                 0,
 +                                 REG_SZ,
 +                                 (LPBYTE)lpLoadOrderGroup,
 +                                 (wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR));
 +        if (dwError != ERROR_SUCCESS)
 +            goto done;
 +    }
 +
 +    if (lpdwTagId != NULL)
 +    {
 +        dwError = RegSetValueExW(hServiceKey,
 +                                 L"Tag",
 +                                 0,
 +                                 REG_DWORD,
 +                                 (LPBYTE)&lpService->dwTag,
 +                                 sizeof(DWORD));
 +        if (dwError != ERROR_SUCCESS)
 +            goto done;
 +    }
 +
 +    /* Write dependencies */
 +    if (lpDependencies != NULL && *lpDependencies != 0)
 +    {
 +        dwError = ScmWriteDependencies(hServiceKey,
 +                                       (LPWSTR)lpDependencies,
 +                                       dwDependSize);
 +        if (dwError != ERROR_SUCCESS)
 +            goto done;
 +    }
 +
 +    /* Write service start name */
 +    if (dwServiceType & SERVICE_WIN32)
 +    {
 +        lpObjectName = (lpServiceStartName != NULL) ? (LPWSTR)lpServiceStartName : L"LocalSystem";
 +        dwError = RegSetValueExW(hServiceKey,
 +                                 L"ObjectName",
 +                                 0,
 +                                 REG_SZ,
 +                                 (LPBYTE)lpObjectName,
 +                                 (wcslen(lpObjectName) + 1) * sizeof(WCHAR));
 +        if (dwError != ERROR_SUCCESS)
 +            goto done;
 +    }
 +
 +    if (lpPassword != NULL)
 +    {
 +        /* FIXME: Write password */
 +    }
 +
 +    dwError = ScmCreateServiceHandle(lpService,
 +                                     &hServiceHandle);
 +    if (dwError != ERROR_SUCCESS)
 +        goto done;
 +
 +    dwError = ScmCheckAccess(hServiceHandle,
 +                             dwDesiredAccess);
 +    if (dwError != ERROR_SUCCESS)
 +        goto done;
 +
 +    lpService->dwRefCount = 1;
 +    DPRINT("CreateService - lpService->dwRefCount %u\n", lpService->dwRefCount);
 +
 +done:;
 +    if (hServiceKey != NULL)
 +        RegCloseKey(hServiceKey);
 +
 +    if (dwError == ERROR_SUCCESS)
 +    {
 +        DPRINT("hService %p\n", hServiceHandle);
 +        *lpServiceHandle = (SC_RPC_HANDLE)hServiceHandle;
 +
 +        if (lpdwTagId != NULL)
 +            *lpdwTagId = lpService->dwTag;
 +    }
 +    else
 +    {
 +        /* Release the display name buffer */
 +        if (lpService->lpServiceName != NULL)
 +            HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
 +
 +        if (hServiceHandle)
 +        {
 +            /* Remove the service handle */
 +            HeapFree(GetProcessHeap(), 0, hServiceHandle);
 +        }
 +
 +        if (lpService != NULL)
 +        {
 +            /* FIXME: remove the service entry */
 +        }
 +    }
 +
 +    if (lpImagePath != NULL)
 +        HeapFree(GetProcessHeap(), 0, lpImagePath);
 +
 +    DPRINT("RCreateServiceW() done (Error %lu)\n", dwError);
 +
 +    return dwError;
 +}
 +
 +
 +/* Function 13 */
 +DWORD REnumDependentServicesW(
 +    SC_RPC_HANDLE hService,
 +    DWORD dwServiceState,
 +    LPBYTE lpServices,
 +    DWORD cbBufSize,
 +    LPBOUNDED_DWORD_256K pcbBytesNeeded,
 +    LPBOUNDED_DWORD_256K lpServicesReturned)
 +{
 +    DWORD dwError = ERROR_SUCCESS;
 +    DWORD dwServicesReturned = 0;
 +    DWORD dwServiceCount;
 +    HKEY hServicesKey = NULL;
 +    PSERVICE_HANDLE hSvc;
 +    PSERVICE lpService = NULL;
 +    PSERVICE *lpServicesArray = NULL;
 +    LPENUM_SERVICE_STATUSW lpServicesPtr = NULL;
 +    LPWSTR lpStr;
 +
 +    *pcbBytesNeeded = 0;
 +    *lpServicesReturned = 0;
 +
 +    DPRINT("REnumDependentServicesW() called\n");
 +
 +    hSvc = ScmGetServiceFromHandle(hService);
 +    if (hSvc == NULL)
 +    {
 +        DPRINT1("Invalid service handle!\n");
 +        return ERROR_INVALID_HANDLE;
 +    }
 +
 +    lpService = hSvc->ServiceEntry;
 +
 +    /* Check access rights */
 +    if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
 +                                  SC_MANAGER_ENUMERATE_SERVICE))
 +    {
 +        DPRINT("Insufficient access rights! 0x%lx\n",
 +               hSvc->Handle.DesiredAccess);
 +        return ERROR_ACCESS_DENIED;
 +    }
 +
 +    /* Open the Services Reg key */
 +    dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
 +                            L"System\\CurrentControlSet\\Services",
 +                            0,
 +                            KEY_READ,
 +                            &hServicesKey);
 +    if (dwError != ERROR_SUCCESS)
 +        return dwError;
 +
 +    /* First determine the bytes needed and get the number of dependent services */
 +    dwError = Int_EnumDependentServicesW(hServicesKey,
 +                                         lpService,
 +                                         dwServiceState,
 +                                         NULL,
 +                                         pcbBytesNeeded,
 +                                         &dwServicesReturned);
 +    if (dwError != ERROR_SUCCESS)
 +        goto Done;
 +
 +    /* If buffer size is less than the bytes needed or pointer is null */
 +    if ((!lpServices) || (cbBufSize < *pcbBytesNeeded))
 +    {
 +        dwError = ERROR_MORE_DATA;
 +        goto Done;
 +    }
 +
 +    /* Allocate memory for array of service pointers */
 +    lpServicesArray = HeapAlloc(GetProcessHeap(),
 +                                0,
 +                                (dwServicesReturned + 1) * sizeof(PSERVICE));
 +    if (!lpServicesArray)
 +    {
 +        DPRINT("Could not allocate a buffer!!\n");
 +        dwError = ERROR_NOT_ENOUGH_MEMORY;
 +        goto Done;
 +    }
 +
 +    dwServicesReturned = 0;
 +    *pcbBytesNeeded = 0;
 +
 +    dwError = Int_EnumDependentServicesW(hServicesKey,
 +                                         lpService,
 +                                         dwServiceState,
 +                                         lpServicesArray,
 +                                         pcbBytesNeeded,
 +                                         &dwServicesReturned);
 +    if (dwError != ERROR_SUCCESS)
 +    {
 +        goto Done;
 +    }
 +
 +    lpServicesPtr = (LPENUM_SERVICE_STATUSW) lpServices;
 +    lpStr = (LPWSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSW)));
 +
 +    /* Copy EnumDepenedentService to Buffer */
 +    for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++)
 +    {
 +        lpService = lpServicesArray[dwServiceCount];
 +
 +        /* Copy status info */
 +        memcpy(&lpServicesPtr->ServiceStatus,
 +               &lpService->Status,
 +               sizeof(SERVICE_STATUS));
 +
 +        /* Copy display name */
 +        wcscpy(lpStr, lpService->lpDisplayName);
 +        lpServicesPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
 +        lpStr += (wcslen(lpService->lpDisplayName) + 1);
 +
 +        /* Copy service name */
 +        wcscpy(lpStr, lpService->lpServiceName);
 +        lpServicesPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
 +        lpStr += (wcslen(lpService->lpServiceName) + 1);
 +
 +        lpServicesPtr ++;
 +    }
 +
 +    *lpServicesReturned = dwServicesReturned;
 +
 +Done:
 +    if (lpServicesArray != NULL)
 +        HeapFree(GetProcessHeap(), 0, lpServicesArray);
 +
 +    RegCloseKey(hServicesKey);
 +
 +    DPRINT("REnumDependentServicesW() done (Error %lu)\n", dwError);
 +
 +    return dwError;
 +}
 +
 +
 +/* Function 14 */
 +DWORD REnumServicesStatusW(
 +    SC_RPC_HANDLE hSCManager,
 +    DWORD dwServiceType,
 +    DWORD dwServiceState,
 +    LPBYTE lpBuffer,
 +    DWORD dwBufSize,
 +    LPBOUNDED_DWORD_256K pcbBytesNeeded,
 +    LPBOUNDED_DWORD_256K lpServicesReturned,
 +    LPBOUNDED_DWORD_256K lpResumeHandle)
 +{
 +    PMANAGER_HANDLE hManager;
 +    PSERVICE lpService;
 +    DWORD dwError = ERROR_SUCCESS;
 +    PLIST_ENTRY ServiceEntry;
 +    PSERVICE CurrentService;
 +    DWORD dwState;
 +    DWORD dwRequiredSize;
 +    DWORD dwServiceCount;
 +    DWORD dwSize;
 +    DWORD dwLastResumeCount = 0;
 +    LPENUM_SERVICE_STATUSW lpStatusPtr;
 +    LPWSTR lpStringPtr;
 +
 +    DPRINT("REnumServicesStatusW() called\n");
 +
 +    if (ScmShutdown)
 +        return ERROR_SHUTDOWN_IN_PROGRESS;
 +
 +    hManager = ScmGetServiceManagerFromHandle(hSCManager);
 +    if (hManager == NULL)
 +    {
 +        DPRINT1("Invalid service manager handle!\n");
 +        return ERROR_INVALID_HANDLE;
 +    }
 +
 +
 +    *pcbBytesNeeded = 0;
 +    *lpServicesReturned = 0;
 +
 +    if ((dwServiceType!=SERVICE_DRIVER) && (dwServiceType!=SERVICE_WIN32))
 +    {
 +        DPRINT("Not a valid Service Type!\n");
 +        return ERROR_INVALID_PARAMETER;
 +    }
 +
 +    if ((dwServiceState<SERVICE_ACTIVE) || (dwServiceState>SERVICE_STATE_ALL))
 +    {
 +        DPRINT("Not a valid Service State!\n");
 +        return ERROR_INVALID_PARAMETER;
 +    }
 +
 +    /* Check access rights */
 +    if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
 +                                  SC_MANAGER_ENUMERATE_SERVICE))
 +    {
 +        DPRINT("Insufficient access rights! 0x%lx\n",
 +                hManager->Handle.DesiredAccess);
 +        return ERROR_ACCESS_DENIED;
 +    }
 +
 +    if (lpResumeHandle)
 +        dwLastResumeCount = *lpResumeHandle;
 +
 +    /* FIXME: Lock the service list shared */
 +
 +    lpService = ScmGetServiceEntryByResumeCount(dwLastResumeCount);
 +    if (lpService == NULL)
 +    {
 +        dwError = ERROR_SUCCESS;
 +        goto Done;
 +    }
 +
 +    dwRequiredSize = 0;
 +    dwServiceCount = 0;
 +
 +    for (ServiceEntry = &lpService->ServiceListEntry;
 +         ServiceEntry != &ServiceListHead;
 +         ServiceEntry = ServiceEntry->Flink)
 +    {
 +        CurrentService = CONTAINING_RECORD(ServiceEntry,
 +                                           SERVICE,
 +                                           ServiceListEntry);
 +
 +        if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
 +            continue;
 +
 +        dwState = SERVICE_ACTIVE;
 +        if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
 +            dwState = SERVICE_INACTIVE;
 +
 +        if ((dwState & dwServiceState) == 0)
 +            continue;
 +
 +        dwSize = sizeof(ENUM_SERVICE_STATUSW) +
 +                 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
 +                 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
 +
 +        if (dwRequiredSize + dwSize > dwBufSize)
 +        {
 +            DPRINT("Service name: %S  no fit\n", CurrentService->lpServiceName);
 +            break;
 +        }
 +
 +        DPRINT("Service name: %S  fit\n", CurrentService->lpServiceName);
 +        dwRequiredSize += dwSize;
 +        dwServiceCount++;
 +        dwLastResumeCount = CurrentService->dwResumeCount;
 +    }
 +
 +    DPRINT("dwRequiredSize: %lu\n", dwRequiredSize);
 +    DPRINT("dwServiceCount: %lu\n", dwServiceCount);
 +
 +    for (;
 +         ServiceEntry != &ServiceListHead;
 +         ServiceEntry = ServiceEntry->Flink)
 +    {
 +        CurrentService = CONTAINING_RECORD(ServiceEntry,
 +                                           SERVICE,
 +                                           ServiceListEntry);
 +
 +        if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
 +            continue;
 +
 +        dwState = SERVICE_ACTIVE;
 +        if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
 +            dwState = SERVICE_INACTIVE;
 +
 +        if ((dwState & dwServiceState) == 0)
 +            continue;
 +
 +        dwRequiredSize += (sizeof(ENUM_SERVICE_STATUSW) +
 +                           ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
 +                           ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR)));
 +
 +        dwError = ERROR_MORE_DATA;
 +    }
 +
 +    DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize);
 +
 +    if (lpResumeHandle)
 +        *lpResumeHandle = dwLastResumeCount;
 +
 +    *lpServicesReturned = dwServiceCount;
 +    *pcbBytesNeeded = dwRequiredSize;
 +
 +    lpStatusPtr = (LPENUM_SERVICE_STATUSW)lpBuffer;
 +    lpStringPtr = (LPWSTR)((ULONG_PTR)lpBuffer +
 +                           dwServiceCount * sizeof(ENUM_SERVICE_STATUSW));
 +
 +    dwRequiredSize = 0;
 +    for (ServiceEntry = &lpService->ServiceListEntry;
 +         ServiceEntry != &ServiceListHead;
 +         ServiceEntry = ServiceEntry->Flink)
 +    {
 +        CurrentService = CONTAINING_RECORD(ServiceEntry,
 +                                           SERVICE,
 +                                           ServiceListEntry);
 +
 +        if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
 +            continue;
 +
 +        dwState = SERVICE_ACTIVE;
 +        if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
 +            dwState = SERVICE_INACTIVE;
 +
 +        if ((dwState & dwServiceState) == 0)
 +            continue;
 +
 +        dwSize = sizeof(ENUM_SERVICE_STATUSW) +
 +                 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
 +                 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
 +
 +        if (dwRequiredSize + dwSize > dwBufSize)
 +            break;
 +
 +        /* Copy the service name */
 +        wcscpy(lpStringPtr, CurrentService->lpServiceName);
 +        lpStatusPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
 +        lpStringPtr += (wcslen(CurrentService->lpServiceName) + 1);
 +
 +        /* Copy the display name */
 +        wcscpy(lpStringPtr, CurrentService->lpDisplayName);
 +        lpStatusPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
 +        lpStringPtr += (wcslen(CurrentService->lpDisplayName) + 1);
 +
 +        /* Copy the status information */
 +        memcpy(&lpStatusPtr->ServiceStatus,
 +               &CurrentService->Status,
 +               sizeof(SERVICE_STATUS));
 +
 +        lpStatusPtr++;
 +        dwRequiredSize += dwSize;
 +    }
 +
 +    if (dwError == 0) 
 +    {
 +        *pcbBytesNeeded = 0;
 +        if (lpResumeHandle) *lpResumeHandle = 0;
 +    }
 +
 +Done:;
 +    /* FIXME: Unlock the service list */
 +
 +    DPRINT("REnumServicesStatusW() done (Error %lu)\n", dwError);
 +
 +    return dwError;
 +}
 +
 +
 +/* Function 15 */
 +DWORD ROpenSCManagerW(
 +    LPWSTR lpMachineName,
 +    LPWSTR lpDatabaseName,
 +    DWORD dwDesiredAccess,
 +    LPSC_RPC_HANDLE lpScHandle)
 +{
 +    DWORD dwError;
 +    SC_HANDLE hHandle;
 +
 +    DPRINT("ROpenSCManagerW() called\n");
 +    DPRINT("lpMachineName = %p\n", lpMachineName);
 +    DPRINT("lpMachineName: %S\n", lpMachineName);
 +    DPRINT("lpDataBaseName = %p\n", lpDatabaseName);
 +    DPRINT("lpDataBaseName: %S\n", lpDatabaseName);
 +    DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
 +
 +    if (ScmShutdown)
 +        return ERROR_SHUTDOWN_IN_PROGRESS;
 +
 +    if (!lpScHandle)
 +        return ERROR_INVALID_PARAMETER;
 +
 +    dwError = ScmCreateManagerHandle(lpDatabaseName,
 +                                     &hHandle);
 +    if (dwError != ERROR_SUCCESS)
 +    {
 +        DPRINT("ScmCreateManagerHandle() failed (Error %lu)\n", dwError);
 +        return dwError;
 +    }
 +
 +    /* Check the desired access */
 +    dwError = ScmCheckAccess(hHandle,
 +                             dwDesiredAccess | SC_MANAGER_CONNECT);
 +    if (dwError != ERROR_SUCCESS)
 +    {
 +        DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError);
 +        HeapFree(GetProcessHeap(), 0, hHandle);
 +        return dwError;
 +    }
 +
 +    *lpScHandle = (SC_RPC_HANDLE)hHandle;
 +    DPRINT("*hScm = %p\n", *lpScHandle);
 +
 +    DPRINT("ROpenSCManagerW() done\n");
 +
 +    return ERROR_SUCCESS;
 +}
 +
 +
 +/* Function 16 */
 +DWORD ROpenServiceW(
 +    SC_RPC_HANDLE hSCManager,
 +    LPWSTR lpServiceName,
 +    DWORD dwDesiredAccess,
 +    LPSC_RPC_HANDLE lpServiceHandle)
 +{
 +    PSERVICE lpService;
 +    PMANAGER_HANDLE hManager;
 +    SC_HANDLE hHandle;
 +    DWORD dwError;
 +
 +    DPRINT("ROpenServiceW() called\n");
 +    DPRINT("hSCManager = %p\n", hSCManager);
 +    DPRINT("lpServiceName = %p\n", lpServiceName);
 +    DPRINT("lpServiceName: %S\n", lpServiceName);
 +    DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
 +
 +    if (ScmShutdown)
 +        return ERROR_SHUTDOWN_IN_PROGRESS;
 +
 +    hManager = ScmGetServiceManagerFromHandle(hSCManager);
 +    if (hManager == NULL)
 +    {
 +        DPRINT1("Invalid service manager handle!\n");
 +        return ERROR_INVALID_HANDLE;
 +    }
 +
 +    if (!lpServiceHandle)
 +        return ERROR_INVALID_PARAMETER;
 +
 +    if (!lpServiceName)
 +        return ERROR_INVALID_ADDRESS;
 +
 +    /* FIXME: Lock the service list */
 +
 +    /* Get service database entry */
 +    lpService = ScmGetServiceEntryByName(lpServiceName);
 +    if (lpService == NULL)
 +    {
 +        DPRINT("Could not find a service!\n");
 +        return ERROR_SERVICE_DOES_NOT_EXIST;
 +    }
 +
 +    /* Create a service handle */
 +    dwError = ScmCreateServiceHandle(lpService,
 +                                     &hHandle);
 +    if (dwError != ERROR_SUCCESS)
 +    {
 +        DPRINT("ScmCreateServiceHandle() failed (Error %lu)\n", dwError);
 +        return dwError;
 +    }
 +
 +    /* Check the desired access */
 +    dwError = ScmCheckAccess(hHandle,
 +                             dwDesiredAccess);
 +    if (dwError != ERROR_SUCCESS)
 +    {
 +        DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError);
 +        HeapFree(GetProcessHeap(), 0, hHandle);
 +        return dwError;
 +    }
 +
 +    lpService->dwRefCount++;
 +    DPRINT("OpenService - lpService->dwRefCount %u\n",lpService->dwRefCount);
 +
 +    *lpServiceHandle = (SC_RPC_HANDLE)hHandle;
 +    DPRINT("*hService = %p\n", *lpServiceHandle);
 +
 +    DPRINT("ROpenServiceW() done\n");
 +
 +    return ERROR_SUCCESS;
 +}
 +
 +
 +/* Function 17 */
 +DWORD RQueryServiceConfigW(
 +    SC_RPC_HANDLE hService,
 +    LPQUERY_SERVICE_CONFIGW lpServiceConfig,
 +    DWORD cbBufSize,
 +    LPBOUNDED_DWORD_8K pcbBytesNeeded)
 +{
 +    DWORD dwError = ERROR_SUCCESS;
 +    PSERVICE_HANDLE hSvc;
 +    PSERVICE lpService = NULL;
 +    HKEY hServiceKey = NULL;
 +    LPWSTR lpImagePath = NULL;
 +    LPWSTR lpServiceStartName = NULL;
 +    LPWSTR lpDependencies = NULL;
 +    DWORD dwDependenciesLength = 0;
 +    DWORD dwRequiredSize;
 +    LPQUERY_SERVICE_CONFIGW lpConfig = NULL;
 +    WCHAR lpEmptyString[] = {0,0};
 +    LPWSTR lpStr;
 +
 +    DPRINT("RQueryServiceConfigW() called\n");
 +
 +    if (ScmShutdown)
 +        return ERROR_SHUTDOWN_IN_PROGRESS;
 +
 +    hSvc = ScmGetServiceFromHandle(hService);
 +    if (hSvc == NULL)
 +    {
 +        DPRINT1("Invalid service handle!\n");
 +        return ERROR_INVALID_HANDLE;
 +    }
 +
 +    if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
 +                                  SERVICE_QUERY_CONFIG))
 +    {
 +        DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
 +        return ERROR_ACCESS_DENIED;
 +    }
 +
 +    lpService = hSvc->ServiceEntry;
 +    if (lpService == NULL)
 +    {
 +        DPRINT("lpService == NULL!\n");
 +        return ERROR_INVALID_HANDLE;
 +    }
 +
 +    /* FIXME: Lock the service database shared */
 +
 +    dwError = ScmOpenServiceKey(lpService->lpServiceName,
 +                                KEY_READ,
 +                                &hServiceKey);
 +    if (dwError != ERROR_SUCCESS)
 +        goto Done;
 +
 +    /* Read the image path */
 +    dwError = ScmReadString(hServiceKey,
 +                            L"ImagePath",
 +                            &lpImagePath);
 +    if (dwError != ERROR_SUCCESS)
 +        goto Done;
 +
 +    /* Read the service start name */
 +    ScmReadString(hServiceKey,
 +                  L"ObjectName",
 +                  &lpServiceStartName);
 +
 +    /* Read the dependencies */
 +    ScmReadDependencies(hServiceKey,
 +                        &lpDependencies,
 +                        &dwDependenciesLength);
 +
 +    dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGW);
 +
 +    if (lpImagePath != NULL)
 +        dwRequiredSize += ((wcslen(lpImagePath) + 1) * sizeof(WCHAR));
 +    else
 +        dwRequiredSize += 2 * sizeof(WCHAR);
 +
 +    if (lpService->lpGroup != NULL)
 +        dwRequiredSize += ((wcslen(lpService->lpGroup->lpGroupName) + 1) * sizeof(WCHAR));
 +    else
 +        dwRequiredSize += 2 * sizeof(WCHAR);
 +
 +    if (lpDependencies != NULL)
 +        dwRequiredSize += dwDependenciesLength * sizeof(WCHAR);
 +    else
 +        dwRequiredSize += 2 * sizeof(WCHAR);
 +
 +    if (lpServiceStartName != NULL)
 +        dwRequiredSize += ((wcslen(lpServiceStartName) + 1) * sizeof(WCHAR));
 +    else
 +        dwRequiredSize += 2 * sizeof(WCHAR);
 +
 +    if (lpService->lpDisplayName != NULL)
 +        dwRequiredSize += ((wcslen(lpService->lpDisplayName) + 1) * sizeof(WCHAR));
 +    else
 +        dwRequiredSize += 2 * sizeof(WCHAR);
 +
 +    if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize)
 +    {
 +        dwError = ERROR_INSUFFICIENT_BUFFER;
 +    }
 +    else
 +    {
 +        lpConfig = (LPQUERY_SERVICE_CONFIGW)lpServiceConfig;
 +        lpConfig->dwServiceType = lpService->Status.dwServiceType;
 +        lpConfig->dwStartType = lpService->dwStartType;
 +        lpConfig->dwErrorControl = lpService->dwErrorControl;
 +        lpConfig->dwTagId = lpService->dwTag;
 +
 +        lpStr = (LPWSTR)(lpConfig + 1);
 +
 +        /* Append the image path */
 +        if (lpImagePath != NULL)
 +        {
 +            wcscpy(lpStr, lpImagePath);
 +        }
 +        else
 +        {
 +            wcscpy(lpStr, lpEmptyString);
 +        }
 +
 +        lpConfig->lpBinaryPathName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
 +        lpStr += (wcslen(lpStr) + 1);
 +
 +        /* Append the group name */
 +        if (lpService->lpGroup != NULL)
 +        {
 +            wcscpy(lpStr, lpService->lpGroup->lpGroupName);
 +        }
 +        else
 +        {
 +            wcscpy(lpStr, lpEmptyString);
 +        }
 +
 +        lpConfig->lpLoadOrderGroup = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
 +        lpStr += (wcslen(lpStr) + 1);
 +
 +        /* Append Dependencies */
 +        if (lpDependencies != NULL)
 +        {
 +            memcpy(lpStr,
 +                   lpDependencies,
 +                   dwDependenciesLength * sizeof(WCHAR));
 +        }
 +        else
 +        {
 +            wcscpy(lpStr, lpEmptyString);
 +        }
 +
 +        lpConfig->lpDependencies = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
 +        if (lpDependencies != NULL)
 +            lpStr += dwDependenciesLength * sizeof(WCHAR);
 +        else
 +            lpStr += (wcslen(lpStr) + 1);
 +
 +        /* Append the service start name */
 +        if (lpServiceStartName != NULL)
 +        {
 +            wcscpy(lpStr, lpServiceStartName);
 +        }
 +        else
 +        {
 +            wcscpy(lpStr, lpEmptyString);
 +        }
 +
 +        lpConfig->lpServiceStartName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
 +        lpStr += (wcslen(lpStr) + 1);
 +
 +        /* Append the display name */
 +        if (lpService->lpDisplayName != NULL)
 +        {
 +            wcscpy(lpStr, lpService->lpDisplayName);
 +        }
 +        else
 +        {
 +            wcscpy(lpStr, lpEmptyString);
 +        }
 +
 +        lpConfig->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
 +    }
 +
 +    if (pcbBytesNeeded != NULL)
 +        *pcbBytesNeeded = dwRequiredSize;
 +
 +Done:;
 +    if (lpImagePath != NULL)
 +        HeapFree(GetProcessHeap(), 0, lpImagePath);
 +
 +    if (lpServiceStartName != NULL)
 +        HeapFree(GetProcessHeap(), 0, lpServiceStartName);
 +
 +    if (lpDependencies != NULL)
 +        HeapFree(GetProcessHeap(), 0, lpDependencies);
 +
 +    if (hServiceKey != NULL)
 +        RegCloseKey(hServiceKey);
 +
 +    /* FIXME: Unlock the service database */
 +
 +    DPRINT("RQueryServiceConfigW() done\n");
 +
 +    return dwError;
 +}
 +
 +
 +/* Function 18 */
 +DWORD RQueryServiceLockStatusW(
 +    SC_RPC_HANDLE hSCManager,
 +    LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
 +    DWORD cbBufSize,
 +    LPBOUNDED_DWORD_4K pcbBytesNeeded)
 +{
 +    UNIMPLEMENTED;
 +    return ERROR_CALL_NOT_IMPLEMENTED;
 +}
 +
 +
 +/* Function 19 */
 +DWORD RStartServiceW(
 +    SC_RPC_HANDLE hService,
 +    DWORD argc,
 +    LPSTRING_PTRSW argv)
 +{
 +    DWORD dwError = ERROR_SUCCESS;
 +    PSERVICE_HANDLE hSvc;
 +    PSERVICE lpService = NULL;
 +
 +    DPRINT("RStartServiceW() called\n");
 +
 +    if (ScmShutdown)
 +        return ERROR_SHUTDOWN_IN_PROGRESS;
 +
 +    hSvc = ScmGetServiceFromHandle(hService);
 +    if (hSvc == NULL)
 +    {
 +        DPRINT1("Invalid service handle!\n");
 +        return ERROR_INVALID_HANDLE;
 +    }
 +
 +    if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
 +                                  SERVICE_START))
 +    {
 +        DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
 +        return ERROR_ACCESS_DENIED;
 +    }
 +
 +    lpService = hSvc->ServiceEntry;
 +    if (lpService == NULL)
 +    {
 +        DPRINT("lpService == NULL!\n");
 +        return ERROR_INVALID_HANDLE;
 +    }
 +
 +    if (lpService->dwStartType == SERVICE_DISABLED)
 +        return ERROR_SERVICE_DISABLED;
 +
 +    if (lpService->bDeleted)
 +        return ERROR_SERVICE_MARKED_FOR_DELETE;
 +
 +    if (argv) {
 +        UNIMPLEMENTED;
 +        argv = NULL;
 +    }
 +
 +    /* Start the service */
 +    dwError = ScmStartService(lpService, argc, (LPWSTR *)argv);
 +
 +    return dwError;
 +}
 +
 +
 +/* Function 20 */
 +DWORD RGetServiceDisplayNameW(
 +    SC_RPC_HANDLE hSCManager,
 +    LPCWSTR lpServiceName,
 +    LPWSTR lpDisplayName,
 +    DWORD *lpcchBuffer)
 +{
 +//    PMANAGER_HANDLE hManager;
 +    PSERVICE lpService;
 +    DWORD dwLength;
 +    DWORD dwError;
 +
 +    DPRINT("RGetServiceDisplayNameW() called\n");
 +    DPRINT("hSCManager = %p\n", hSCManager);
 +    DPRINT("lpServiceName: %S\n", lpServiceName);
 +    DPRINT("lpDisplayName: %p\n", lpDisplayName);
 +    DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
 +
 +//    hManager = (PMANAGER_HANDLE)hSCManager;
 +//    if (hManager->Handle.Tag != MANAGER_TAG)
 +//    {
 +//        DPRINT("Invalid manager handle!\n");
 +//        return ERROR_INVALID_HANDLE;
 +//    }
 +
 +    /* Get service database entry */
 +    lpService = ScmGetServiceEntryByName(lpServiceName);
 +    if (lpService == NULL)
 +    {
 +        DPRINT("Could not find a service!\n");
 +
 +        /* If the service could not be found and lpcchBuffer is less than 2, windows
 +           puts null in lpDisplayName and puts 2 in lpcchBuffer */
 +        if (*lpcchBuffer < 2)
 +        {
 +            *lpcchBuffer = 2;
 +            if (lpDisplayName != NULL)
 +            {
 +                *lpDisplayName = '\0';
 +            }
 +        }
 +
 +        return ERROR_SERVICE_DOES_NOT_EXIST;
 +    }
 +
 +    if (!lpService->lpDisplayName)
 +    {
 +        dwLength = wcslen(lpService->lpServiceName);
 +
 +        if (lpDisplayName != NULL &&
 +            *lpcchBuffer > dwLength)
 +        {
 +            wcscpy(lpDisplayName, lpService->lpServiceName);
 +        }
 +    }
 +    else
 +    {
 +        dwLength = wcslen(lpService->lpDisplayName);
 +
 +        if (lpDisplayName != NULL &&
 +            *lpcchBuffer > dwLength)
 +        {
 +            wcscpy(lpDisplayName, lpService->lpDisplayName);
 +        }
 +    }
 +
 +    dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
 +
 +    *lpcchBuffer = dwLength;
 +
 +    return dwError;
 +}
 +
 +
 +/* Function 21 */
 +DWORD RGetServiceKeyNameW(
 +    SC_RPC_HANDLE hSCManager,
 +    LPCWSTR lpDisplayName,
 +    LPWSTR lpServiceName,
 +    DWORD *lpcchBuffer)
 +{
 +//    PMANAGER_HANDLE hManager;
 +    PSERVICE lpService;
 +    DWORD dwLength;
 +    DWORD dwError;
 +
 +    DPRINT("RGetServiceKeyNameW() called\n");
 +    DPRINT("hSCManager = %p\n", hSCManager);
 +    DPRINT("lpDisplayName: %S\n", lpDisplayName);
 +    DPRINT("lpServiceName: %p\n", lpServiceName);
 +    DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
 +
 +//    hManager = (PMANAGER_HANDLE)hSCManager;
 +//    if (hManager->Handle.Tag != MANAGER_TAG)
 +//    {
 +//        DPRINT("Invalid manager handle!\n");
 +//        return ERROR_INVALID_HANDLE;
 +//    }
 +
 +    /* Get service database entry */
 +    lpService = ScmGetServiceEntryByDisplayName(lpDisplayName);
 +    if (lpService == NULL)
 +    {
 +        DPRINT("Could not find a service!\n");
 +
 +        /* If the service could not be found and lpcchBuffer is less than 2, windows
 +           puts null in lpDisplayName and puts 2 in lpcchBuffer */
 +        if (*lpcchBuffer < 2)
 +        {
 +            *lpcchBuffer = 2;
 +            if (lpServiceName != NULL)
 +            {
 +                *lpServiceName = '\0';
 +            }
 +        }
 +
 +        return ERROR_SERVICE_DOES_NOT_EXIST;
 +    }
 +
 +    dwLength = wcslen(lpService->lpServiceName);
 +
 +    if (lpServiceName != NULL &&
 +        *lpcchBuffer > dwLength)
 +    {
 +        wcscpy(lpServiceName, lpService->lpServiceName);
 +        *lpcchBuffer = dwLength;
 +        return ERROR_SUCCESS;
 +    }
 +
 +    dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
 +
 +    *lpcchBuffer = dwLength;
 +
 +    return dwError;
 +}
 +
 +
 +/* Function 22 */
 +DWORD RI_ScSetServiceBitsA(
 +    RPC_SERVICE_STATUS_HANDLE hServiceStatus,
 +    DWORD dwServiceBits,
 +    int bSetBitsOn,
 +    int bUpdateImmediately,
 +    char *lpString)
 +{
 +    UNIMPLEMENTED;
 +    return ERROR_CALL_NOT_IMPLEMENTED;
 +}
 +
 +
 +/* Function 23 */
 +DWORD RChangeServiceConfigA(
 +    SC_RPC_HANDLE hService,
 +    DWORD dwServiceType,
 +    DWORD dwStartType,
 +    DWORD dwErrorControl,
 +    LPSTR lpBinaryPathName,
 +    LPSTR lpLoadOrderGroup,
 +    LPDWORD lpdwTagId,
 +    LPSTR lpDependencies,
 +    DWORD dwDependSize,
 +    LPSTR lpServiceStartName,
 +    LPBYTE lpPassword,
 +    DWORD dwPwSize,
 +    LPSTR lpDisplayName)
 +{
 +    DWORD dwError = ERROR_SUCCESS;
 +    PSERVICE_HANDLE hSvc;
 +    PSERVICE lpService = NULL;
 +    HKEY hServiceKey = NULL;
 +    LPWSTR lpDisplayNameW = NULL;
 +    // LPWSTR lpBinaryPathNameW = NULL;
 +    LPWSTR lpLoadOrderGroupW = NULL;
 +    LPWSTR lpDependenciesW = NULL;
 +    // LPWSTR lpPasswordW = NULL;
 +
 +    DPRINT("RChangeServiceConfigA() called\n");
 +    DPRINT("dwServiceType = %lu\n", dwServiceType);
 +    DPRINT("dwStartType = %lu\n", dwStartType);
 +    DPRINT("dwErrorControl = %lu\n", dwErrorControl);
 +    DPRINT("lpBinaryPathName = %s\n", lpBinaryPathName);
 +    DPRINT("lpLoadOrderGroup = %s\n", lpLoadOrderGroup);
 +    DPRINT("lpDisplayName = %s\n", lpDisplayName);
 +
 +    if (ScmShutdown)
 +        return ERROR_SHUTDOWN_IN_PROGRESS;
 +
 +    hSvc = ScmGetServiceFromHandle(hService);
 +    if (hSvc == NULL)
 +    {
 +        DPRINT1("Invalid service handle!\n");
 +        return ERROR_INVALID_HANDLE;
 +    }
 +
 +    if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
 +                                  SERVICE_CHANGE_CONFIG))
 +    {
 +        DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
 +        return ERROR_ACCESS_DENIED;
 +    }
 +
 +    lpService = hSvc->ServiceEntry;
 +    if (lpService == NULL)
 +    {
 +        DPRINT("lpService == NULL!\n");
 +        return ERROR_INVALID_HANDLE;
 +    }
 +
 +    /* FIXME: Lock database exclusively */
 +
 +    if (lpService->bDeleted)
 +    {
 +        /* FIXME: Unlock database */
 +        DPRINT("The service has already been marked for delete!\n");
 +        return ERROR_SERVICE_MARKED_FOR_DELETE;
 +    }
 +
 +    /* Open the service key */
 +    dwError = ScmOpenServiceKey(lpService->szServiceName,
 +                                KEY_SET_VALUE,
 +                                &hServiceKey);
 +    if (dwError != ERROR_SUCCESS)
 +        goto done;
 +
 +    /* Write service data to the registry */
 +
 +    if (lpDisplayName != NULL && *lpDisplayName != 0)
 +    {
 +        /* Set the display name */
 +        lpDisplayNameW = HeapAlloc(GetProcessHeap(),
 +                                   0,
 +                                   (strlen(lpDisplayName) + 1) * sizeof(WCHAR));
 +        if (lpDisplayNameW == NULL)
 +        {
 +            dwError = ERROR_NOT_ENOUGH_MEMORY;
 +            goto done;
 +        }
 +
 +        MultiByteToWideChar(CP_ACP,
 +                            0,
 +                            lpDisplayName,
 +                            -1,
 +                            lpDisplayNameW,
 +                            strlen(lpDisplayName) + 1);
 +
 +        RegSetValueExW(hServiceKey,
 +                       L"DisplayName",
 +                       0,
 +                       REG_SZ,
 +                       (LPBYTE)lpDisplayNameW,
 +                       (wcslen(lpDisplayNameW) + 1) * sizeof(WCHAR));
 +
 +        /* Update lpService->lpDisplayName */
 +        if (lpService->lpDisplayName)
 +            HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
 +
 +        lpService->lpDisplayName = lpDisplayNameW;
 +    }
 +
 +    if (dwServiceType != SERVICE_NO_CHANGE)
 +    {
 +        /* Set the service type */
 +        dwError = RegSetValueExW(hServiceKey,
 +                                 L"Type",
 +                                 0,
 +                                 REG_DWORD,
 +                                 (LPBYTE)&dwServiceType,
 +                                 sizeof(DWORD));
 +        if (dwError != ERROR_SUCCESS)
 +            goto done;
 +
 +        lpService->Status.dwServiceType = dwServiceType;
 +    }
 +
 +    if (dwStartType != SERVICE_NO_CHANGE)
 +    {
 +        /* Set the start value */
 +        dwError = RegSetValueExW(hServiceKey,
 +                                 L"Start",
 +                                 0,
 +                                 REG_DWORD,
 +                                 (LPBYTE)&dwStartType,
 +                                 sizeof(DWORD));
 +        if (dwError != ERROR_SUCCESS)
 +            goto done;
 +
 +        lpService->dwStartType = dwStartType;
 +    }
 +
 +    if (dwErrorControl != SERVICE_NO_CHANGE)
 +    {
 +        /* Set the error control value */
 +        dwError = RegSetValueExW(hServiceKey,
 +                                 L"ErrorControl",
 +                                 0,
 +                                 REG_DWORD,
 +                                 (LPBYTE)&dwErrorControl,
 +                                 sizeof(DWORD));
 +        if (dwError != ERROR_SUCCESS)
 +            goto done;
 +
 +        lpService->dwErrorControl = dwErrorControl;
 +    }
 +
 +#if 0
 +    /* FIXME: set the new ImagePath value */
 +
 +    /* Set the image path */
 +    if (dwServiceType & SERVICE_WIN32)
 +    {
 +        if (lpBinaryPathName != NULL && *lpBinaryPathName != 0)
 +        {
 +            lpBinaryPathNameW=HeapAlloc(GetProcessHeap(),0, (strlen(lpBinaryPathName)+1) * sizeof(WCHAR));
 +            MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, lpBinaryPathNameW, strlen(lpBinaryPathName)+1);
 +            dwError = RegSetValueExW(hServiceKey,
 +                                     L"ImagePath",
 +                                     0,
 +                                     REG_EXPAND_SZ,
 +                                     (LPBYTE)lpBinaryPathNameW,
 +                                     (wcslen(lpBinaryPathNameW) + 1) * sizeof(WCHAR));
 +            if (dwError != ERROR_SUCCESS)
 +                goto done;
 +        }
 +    }
 +    else if (dwServiceType & SERVICE_DRIVER)
 +    {
 +        if (lpImagePath != NULL && *lpImagePath != 0)
 +        {
 +            dwError = RegSetValueExW(hServiceKey,
 +                                     L"ImagePath",
 +                                     0,
 +                                     REG_EXPAND_SZ,
 +                                     (LPBYTE)lpImagePath,
 +                                     (wcslen(lpImagePath) + 1) *sizeof(WCHAR));
 +            if (dwError != ERROR_SUCCESS)
 +                goto done;
 +        }
 +    }
 +#endif
 +
 +    /* Set the group name */
 +    if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
 +    {
 +        lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(),
 +                                      0,
 +                                      (strlen(lpLoadOrderGroup) + 1) * sizeof(WCHAR));
 +        if (lpLoadOrderGroupW == NULL)
 +        {
 +            dwError = ERROR_NOT_ENOUGH_MEMORY;
 +            goto done;
 +        }
 +
 +        MultiByteToWideChar(CP_ACP,
 +                            0,
 +                            lpLoadOrderGroup,
 +                            -1,
 +                            lpLoadOrderGroupW,
 +                            strlen(lpLoadOrderGroup) + 1);
 +
 +        dwError = RegSetValueExW(hServiceKey,
 +                                 L"Group",
 +                                 0,
 +                                 REG_SZ,
 +                                 (LPBYTE)lpLoadOrderGroupW,
 +                                 (wcslen(lpLoadOrderGroupW) + 1) * sizeof(WCHAR));
 +        if (dwError != ERROR_SUCCESS)
 +        {
 +            HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
 +            goto done;
 +        }
 +
 +        dwError = ScmSetServiceGroup(lpService,
 +                                     lpLoadOrderGroupW);
 +
 +        HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
 +
 +        if (dwError != ERROR_SUCCESS)
 +            goto done;
 +    }
 +
 +    if (lpdwTagId != NULL)
 +    {
 +        dwError = ScmAssignNewTag(lpService);
 +        if (dwError != ERROR_SUCCESS)
 +            goto done;
 +
 +        dwError = RegSetValueExW(hServiceKey,
 +                                 L"Tag",
 +                                 0,
 +                                 REG_DWORD,
 +                                 (LPBYTE)&lpService->dwTag,
 +                                 sizeof(DWORD));
 +        if (dwError != ERROR_SUCCESS)
 +            goto done;
 +
 +        *lpdwTagId = lpService->dwTag;
 +    }
 +
 +    /* Write dependencies */
 +    if (lpDependencies != NULL && *lpDependencies != 0)
 +    {
 +        lpDependenciesW = HeapAlloc(GetProcessHeap(),
 +                                    0,
 +                                    (strlen(lpDependencies) + 1) * sizeof(WCHAR));
 +        if (lpDependenciesW == NULL)
 +        {
 +            dwError = ERROR_NOT_ENOUGH_MEMORY;
 +            goto done;
 +        }
 +
 +        MultiByteToWideChar(CP_ACP,
 +                            0,
 +                            lpDependencies,
 +                            dwDependSize,
 +                            lpDependenciesW,
 +                            strlen(lpDependencies) + 1);
 +
 +        dwError = ScmWriteDependencies(hServiceKey,
 +                                       (LPWSTR)lpDependenciesW,
 +                                       dwDependSize);
 +
 +        HeapFree(GetProcessHeap(), 0, lpDependenciesW);
 +    }
 +
 +    if (lpPassword != NULL)
 +    {
 +        /* FIXME: Write password */
 +    }
 +
 +    /* FIXME: Unlock database */
 +
 +done:
 +    if (hServiceKey != NULL)
 +        RegCloseKey(hServiceKey);
 +
 +    DPRINT("RChangeServiceConfigA() done (Error %lu)\n", dwError);
 +
 +    return dwError;
 +}
 +
 +
 +/* Function 24 */
 +DWORD RCreateServiceA(
 +    SC_RPC_HANDLE hSCManager,
 +    LPSTR lpServiceName,
 +    LPSTR lpDisplayName,
 +    DWORD dwDesiredAccess,
 +    DWORD dwServiceType,
 +    DWORD dwStartType,
 +    DWORD dwErrorControl,
 +    LPSTR lpBinaryPathName,
 +    LPSTR lpLoadOrderGroup,
 +    LPDWORD lpdwTagId,
 +    LPBYTE lpDependencies,
 +    DWORD dwDependSize,
 +    LPSTR lpServiceStartName,
 +    LPBYTE lpPassword,
 +    DWORD dwPwSize,
 +    LPSC_RPC_HANDLE lpServiceHandle)
 +{
 +    DWORD dwError = ERROR_SUCCESS;
 +    LPWSTR lpServiceNameW = NULL;
 +    LPWSTR lpDisplayNameW = NULL;
 +    LPWSTR lpBinaryPathNameW = NULL;
 +    LPWSTR lpLoadOrderGroupW = NULL;
 +    LPWSTR lpDependenciesW = NULL;
 +    LPWSTR lpServiceStartNameW = NULL;
 +    DWORD dwDependenciesLength = 0;
 +    DWORD dwLength;
 +    int len;
 +    LPSTR lpStr;
 +
 +    if (lpServiceName)
 +    {
 +        len = MultiByteToWideChar(CP_ACP, 0, lpServiceName, -1, NULL, 0);
 +        lpServiceNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
 +        if (!lpServiceNameW)
 +        {
 +            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
 +            goto cleanup;
 +        }
 +        MultiByteToWideChar(CP_ACP, 0, lpServiceName, -1, lpServiceNameW, len);
 +    }
 +
 +    if (lpDisplayName)
 +    {
 +        len = MultiByteToWideChar(CP_ACP, 0, lpDisplayName, -1, NULL, 0);
 +        lpDisplayNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
 +        if (!lpDisplayNameW)
 +        {
 +            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
 +            goto cleanup;
 +        }
 +        MultiByteToWideChar(CP_ACP, 0, lpDisplayName, -1, lpDisplayNameW, len);
 +    }
 +
 +    if (lpBinaryPathName)
 +    {
 +        len = MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, NULL, 0);
 +        lpBinaryPathNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
 +        if (!lpBinaryPathNameW)
 +        {
 +            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
 +            goto cleanup;
 +        }
 +        MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, lpBinaryPathNameW, len);
 +    }
 +
 +    if (lpLoadOrderGroup)
 +    {
 +        len = MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, NULL, 0);
 +        lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
 +        if (!lpLoadOrderGroupW)
 +        {
 +            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
 +            goto cleanup;
 +        }
 +        MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, lpLoadOrderGroupW, len);
 +    }
 +
 +    if (lpDependencies)
 +    {
 +        lpStr = (LPSTR)lpDependencies;
 +        while (*lpStr)
 +        {
 +            dwLength = strlen(lpStr) + 1;
 +            dwDependenciesLength += dwLength;
 +            lpStr = lpStr + dwLength;
 +        }
 +        dwDependenciesLength++;
 +
 +        lpDependenciesW = HeapAlloc(GetProcessHeap(), 0, dwDependenciesLength * sizeof(WCHAR));
 +        if (!lpDependenciesW)
 +        {
 +            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
 +            goto cleanup;
 +        }
 +        MultiByteToWideChar(CP_ACP, 0, (LPSTR)lpDependencies, dwDependenciesLength, lpDependenciesW, dwDependenciesLength);
 +    }
 +
 +    if (lpServiceStartName)
 +    {
 +        len = MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, NULL, 0);
 +        lpServiceStartNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
 +        if (!lpServiceStartNameW)
 +        {
 +            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
 +            goto cleanup;
 +        }
 +        MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, lpServiceStartNameW, len);
 +    }
 +
 +    dwError = RCreateServiceW(hSCManager,
 +                              lpServiceNameW,
 +                              lpDisplayNameW,
 +                              dwDesiredAccess,
 +                              dwServiceType,
 +                              dwStartType,
 +                              dwErrorControl,
 +                              lpBinaryPathNameW,
 +                              lpLoadOrderGroupW,
 +                              lpdwTagId,
 +                              (LPBYTE)lpDependenciesW,
 +                              dwDependenciesLength,
 +                              lpServiceStartNameW,
 +                              lpPassword,
 +                              dwPwSize,
 +                              lpServiceHandle);
 +
 +cleanup:
 +    if (lpServiceNameW !=NULL)
 +        HeapFree(GetProcessHeap(), 0, lpServiceNameW);
 +
 +    if (lpDisplayNameW != NULL)
 +        HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
 +
 +    if (lpBinaryPathNameW != NULL)
 +        HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW);
 +
 +    if (lpLoadOrderGroupW != NULL)
 +        HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
 +
 +    if (lpDependenciesW != NULL)
 +        HeapFree(GetProcessHeap(), 0, lpDependenciesW);
 +
 +    if (lpServiceStartNameW != NULL)
 +        HeapFree(GetProcessHeap(), 0, lpServiceStartNameW);
 +
 +    return dwError;
 +}
 +
 +
 +/* Function 25 */
 +DWORD REnumDependentServicesA(
 +    SC_RPC_HANDLE hService,
 +    DWORD dwServiceState,
 +    LPBYTE lpServices,
 +    DWORD cbBufSize,
 +    LPBOUNDED_DWORD_256K pcbBytesNeeded,
 +    LPBOUNDED_DWORD_256K lpServicesReturned)
 +{
 +    DWORD dwError = ERROR_SUCCESS;
 +    DWORD dwServicesReturned = 0;
 +    DWORD dwServiceCount;
 +    HKEY hServicesKey = NULL;
 +    PSERVICE_HANDLE hSvc;
 +    PSERVICE lpService = NULL;
 +    PSERVICE *lpServicesArray = NULL;
 +    LPENUM_SERVICE_STATUSA lpServicesPtr = NULL;
 +    LPSTR lpStr;
 +
 +    *pcbBytesNeeded = 0;
 +    *lpServicesReturned = 0;
 +
 +    DPRINT("REnumDependentServicesA() called\n");
 +
 +    hSvc = ScmGetServiceFromHandle(hService);
 +    if (hSvc == NULL)
 +    {
 +        DPRINT1("Invalid service handle!\n");
 +        return ERROR_INVALID_HANDLE;
 +    }
 +
 +    lpService = hSvc->ServiceEntry;
 +
 +    /* Check access rights */
 +    if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
 +                                  SC_MANAGER_ENUMERATE_SERVICE))
 +    {
 +        DPRINT("Insufficient access rights! 0x%lx\n",
 +               hSvc->Handle.DesiredAccess);
 +        return ERROR_ACCESS_DENIED;
 +    }
 +
 +    /* Open the Services Reg key */
 +    dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
 +                            L"System\\CurrentControlSet\\Services",
 +                            0,
 +                            KEY_READ,
 +                            &hServicesKey);
 +
 +    if (dwError != ERROR_SUCCESS)
 +        return dwError;
 +
 +    /* NOTE: Windows calculates the pcbBytesNeeded based on WCHAR strings for
 +             both EnumDependentServicesA and EnumDependentServicesW. So returned pcbBytesNeeded
 +             are the same for both. Verified in WINXP. */
 +
 +    /* First determine the bytes needed and get the number of dependent services*/
 +    dwError = Int_EnumDependentServicesW(hServicesKey,
 +                                         lpService,
 +                                         dwServiceState,
 +                                         NULL,
 +                                         pcbBytesNeeded,
 +                                         &dwServicesReturned);
 +    if (dwError != ERROR_SUCCESS)
 +        goto Done;
 +
 +    /* If buffer size is less than the bytes needed or pointer is null*/
 +    if ((!lpServices) || (cbBufSize < *pcbBytesNeeded))
 +    {
 +        dwError = ERROR_MORE_DATA;
 +        goto Done;
 +    }
 +
 +    /* Allocate memory for array of service pointers */
 +    lpServicesArray = HeapAlloc(GetProcessHeap(),
 +                                0,
 +                                (dwServicesReturned + 1) * sizeof(PSERVICE));
 +    if (!lpServicesArray)
 +    {
 +        DPRINT("Could not allocate a buffer!!\n");
 +        dwError = ERROR_NOT_ENOUGH_MEMORY;
 +        goto Done;
 +    }
 +
 +    dwServicesReturned = 0;
 +    *pcbBytesNeeded = 0;
 +
 +    dwError = Int_EnumDependentServicesW(hServicesKey,
 +                                         lpService,
 +                                         dwServiceState,
 +                                         lpServicesArray,
 +                                         pcbBytesNeeded,
 +                                         &dwServicesReturned);
 +    if (dwError != ERROR_SUCCESS)
 +    {
 +        goto Done;
 +    }
 +
 +    lpServicesPtr = (LPENUM_SERVICE_STATUSA)lpServices;
 +    lpStr = (LPSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSA)));
 +
 +    /* Copy EnumDepenedentService to Buffer */
 +    for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++)
 +    {
 +        lpService = lpServicesArray[dwServiceCount];
 +
 +        /* Copy the status info */
 +        memcpy(&lpServicesPtr->ServiceStatus,
 +               &lpService->Status,
 +               sizeof(SERVICE_STATUS));
 +
 +        /* Copy display name */
 +        WideCharToMultiByte(CP_ACP,
 +                            0,
 +                            lpService->lpDisplayName,
 +                            -1,
 +                            lpStr,
 +                            wcslen(lpService->lpDisplayName),
 +                            0,
 +                            0);
 +        lpServicesPtr->lpDisplayName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
 +        lpStr += strlen(lpStr) + 1;
 +
 +        /* Copy service name */
 +        WideCharToMultiByte(CP_ACP,
 +                            0,
 +                            lpService->lpServiceName,
 +                            -1,
 +                            lpStr,
 +                            wcslen(lpService->lpServiceName),
 +                            0,
 +                            0);
 +        lpServicesPtr->lpServiceName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
 +        lpStr += strlen(lpStr) + 1;
 +
 +        lpServicesPtr ++;
 +    }
 +
 +    *lpServicesReturned = dwServicesReturned;
 +
 +Done:
 +    if (lpServicesArray)
 +        HeapFree(GetProcessHeap(), 0, lpServicesArray);
 +
 +    RegCloseKey(hServicesKey);
 +
 +    DPRINT("REnumDependentServicesA() done (Error %lu)\n", dwError);
 +
 +    return dwError;
 +}
 +
 +
 +/* Function 26 */
 +DWORD REnumServicesStatusA(
 +    SC_RPC_HANDLE hSCManager,
 +    DWORD dwServiceType,
 +    DWORD dwServiceState,
 +    LPBYTE lpBuffer,
 +    DWORD dwBufSize,
 +    LPBOUNDED_DWORD_256K pcbBytesNeeded,
 +    LPBOUNDED_DWORD_256K lpServicesReturned,
 +    LPBOUNDED_DWORD_256K lpResumeHandle)
 +{
 +    LPENUM_SERVICE_STATUSW lpStatusPtrW = NULL;
 +    LPENUM_SERVICE_STATUSA lpStatusPtrA = NULL;
 +    LPWSTR lpStringPtrW;
 +    LPSTR lpStringPtrA;
 +    DWORD dwError;
 +    DWORD dwServiceCount;
 +
 +    DPRINT("REnumServicesStatusA() called\n");
 +
 +    if ((dwBufSize > 0) && (lpBuffer))
 +    {
 +        lpStatusPtrW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufSize);
 +        if (!lpStatusPtrW)
 +        {
 +            DPRINT("Failed to allocate buffer!\n");
 +            return ERROR_NOT_ENOUGH_MEMORY;
 +        }
 +    }
 +
 +    dwError = REnumServicesStatusW(hSCManager,
 +                                   dwServiceType,
 +                                   dwServiceState,
 +                                   (LPBYTE)lpStatusPtrW,
 +                                   dwBufSize,
 +                                   pcbBytesNeeded,
 +                                   lpServicesReturned,
 +                                   lpResumeHandle);
 +
 +    /* if no services were returned then we are Done */
 +    if (*lpServicesReturned == 0)
 +        goto Done;
 +
 +    lpStatusPtrA = (LPENUM_SERVICE_STATUSA)lpBuffer;
 +    lpStringPtrA = (LPSTR)((ULONG_PTR)lpBuffer +
 +                  *lpServicesReturned * sizeof(ENUM_SERVICE_STATUSA));
 +    lpStringPtrW = (LPWSTR)((ULONG_PTR)lpStatusPtrW + 
 +                  *lpServicesReturned * sizeof(ENUM_SERVICE_STATUSW));
 +
 +    for (dwServiceCount = 0; dwServiceCount < *lpServicesReturned; dwServiceCount++)
 +    {
 +        /* Copy the service name */
 +        WideCharToMultiByte(CP_ACP,
 +                            0,
 +                            lpStringPtrW,
 +                            -1,
 +                            lpStringPtrA,
 +                            wcslen(lpStringPtrW),
 +                            0,
 +                            0);
 +
 +        lpStatusPtrA->lpServiceName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
 +        lpStringPtrA += wcslen(lpStringPtrW) + 1;
 +        lpStringPtrW += wcslen(lpStringPtrW) + 1;
 +
 +        /* Copy the display name */
 +        WideCharToMultiByte(CP_ACP,
 +                            0,
 +                            lpStringPtrW,
 +                            -1,
 +                            lpStringPtrA,
 +                            wcslen(lpStringPtrW),
 +                            0,
 +                            0);
 +
 +        lpStatusPtrA->lpDisplayName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
 +        lpStringPtrA += wcslen(lpStringPtrW) + 1;
 +        lpStringPtrW += wcslen(lpStringPtrW) + 1;
 +
 +        /* Copy the status information */
 +        memcpy(&lpStatusPtrA->ServiceStatus,
 +               &lpStatusPtrW->ServiceStatus,
 +               sizeof(SERVICE_STATUS));
 +
 +        lpStatusPtrA++;
 +    }
 +
 +Done:;
 +    if (lpStatusPtrW)
 +        HeapFree(GetProcessHeap(), 0, lpStatusPtrW);
 +
 +    DPRINT("REnumServicesStatusA() done (Error %lu)\n", dwError);
 +
 +    return dwError;
 +}
 +
 +
 +/* Function 27 */
 +DWORD ROpenSCManagerA(
 +    LPSTR lpMachineName,
 +    LPSTR lpDatabaseName,
 +    DWORD dwDesiredAccess,
 +    LPSC_RPC_HANDLE lpScHandle)
 +{
 +    UNICODE_STRING MachineName;
 +    UNICODE_STRING DatabaseName;
 +    DWORD dwError;
 +
 +    DPRINT("ROpenSCManagerA() called\n");
 +
 +    if (lpMachineName)
 +        RtlCreateUnicodeStringFromAsciiz(&MachineName,
 +                                         lpMachineName);
 +
 +    if (lpDatabaseName)
 +        RtlCreateUnicodeStringFromAsciiz(&DatabaseName,
 +                                         lpDatabaseName);
 +
 +    dwError = ROpenSCManagerW(lpMachineName ? MachineName.Buffer : NULL,
 +                              lpDatabaseName ? DatabaseName.Buffer : NULL,
 +                              dwDesiredAccess,
 +                              lpScHandle);
 +
 +    if (lpMachineName)
 +        RtlFreeUnicodeString(&MachineName);
 +
 +    if (lpDatabaseName)
 +        RtlFreeUnicodeString(&DatabaseName);
 +
 +    return dwError;
 +}
 +
 +
 +/* Function 28 */
 +DWORD ROpenServiceA(
 +    SC_RPC_HANDLE hSCManager,
 +    LPSTR lpServiceName,
 +    DWORD dwDesiredAccess,
 +    LPSC_RPC_HANDLE lpServiceHandle)
 +{
 +    UNICODE_STRING ServiceName;
 +    DWORD dwError;
 +
 +    DPRINT("ROpenServiceA() called\n");
 +
 +    if (lpServiceName)
 +        RtlCreateUnicodeStringFromAsciiz(&ServiceName,
 +                                         lpServiceName);
 +
 +    dwError = ROpenServiceW(hSCManager,
 +                            lpServiceName ? ServiceName.Buffer : NULL,
 +                            dwDesiredAccess,
 +                            lpServiceHandle);
 +
 +    if (lpServiceName)
 +        RtlFreeUnicodeString(&ServiceName);
 +
 +    return dwError;
 +}
 +
 +
 +/* Function 29 */
 +DWORD RQueryServiceConfigA(
 +    SC_RPC_HANDLE hService,
 +    LPQUERY_SERVICE_CONFIGA lpServiceConfig,
 +    DWORD cbBufSize,
 +    LPBOUNDED_DWORD_8K pcbBytesNeeded)
 +{
 +    DWORD dwError = ERROR_SUCCESS;
 +    PSERVICE_HANDLE hSvc;
 +    PSERVICE lpService = NULL;
 +    HKEY hServiceKey = NULL;
 +    LPWSTR lpImagePath = NULL;
 +    LPWSTR lpServiceStartName = NULL;
 +    LPWSTR lpDependencies = NULL;
 +    DWORD dwDependenciesLength = 0;
 +    DWORD dwRequiredSize;
 +    LPQUERY_SERVICE_CONFIGA lpConfig = NULL;
 +    CHAR lpEmptyString[]={0,0};
 +    LPSTR lpStr;
 +
 +    DPRINT("RQueryServiceConfigA() called\n");
 +
 +    if (ScmShutdown)
 +        return ERROR_SHUTDOWN_IN_PROGRESS;
 +
 +    hSvc = ScmGetServiceFromHandle(hService);
 +    if (hSvc == NULL)
 +    {
 +        DPRINT1("Invalid service handle!\n");
 +        return ERROR_INVALID_HANDLE;
 +    }
 +
 +    if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
 +                                  SERVICE_QUERY_CONFIG))
 +    {
 +        DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
 +        return ERROR_ACCESS_DENIED;
 +    }
 +
 +    lpService = hSvc->ServiceEntry;
 +    if (lpService == NULL)
 +    {
 +        DPRINT("lpService == NULL!\n");
 +        return ERROR_INVALID_HANDLE;
 +    }
 +
 +    /* FIXME: Lock the service database shared */
 +
 +    dwError = ScmOpenServiceKey(lpService->lpServiceName,
 +                                KEY_READ,
 +                                &hServiceKey);
 +    if (dwError != ERROR_SUCCESS)
 +        goto Done;
 +
 +    /* Read the image path */
 +    dwError = ScmReadString(hServiceKey,
 +                            L"ImagePath",
 +                            &lpImagePath);
 +    if (dwError != ERROR_SUCCESS)
 +        goto Done;
 +
 +    /* Read the service start name */
 +    ScmReadString(hServiceKey,
 +                  L"ObjectName",
 +                  &lpServiceStartName);
 +
 +    /* Read the dependencies */
 +    ScmReadDependencies(hServiceKey,
 +                        &lpDependencies,
 +                        &dwDependenciesLength);
 +
 +    dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGW);
 +
 +    if (lpImagePath != NULL)
 +        dwRequiredSize += wcslen(lpImagePath) + 1;
 +    else
 +        dwRequiredSize += 2;
 +
 +    if ((lpService->lpGroup != NULL) && (lpService->lpGroup->lpGroupName != NULL))
 +        dwRequiredSize += wcslen(lpService->lpGroup->lpGroupName) + 1;
 +    else
 +        dwRequiredSize += 2;
 +
 +    /* Add Dependencies length */
 +    if (lpDependencies != NULL)
 +        dwRequiredSize += dwDependenciesLength;
 +    else
 +        dwRequiredSize += 2;
 +
 +    if (lpServiceStartName != NULL)
 +        dwRequiredSize += wcslen(lpServiceStartName) + 1;
 +    else
 +        dwRequiredSize += 2;
 +
 +    if (lpService->lpDisplayName != NULL)
 +        dwRequiredSize += wcslen(lpService->lpDisplayName) + 1;
 +    else
 +        dwRequiredSize += 2;
 +
 +    if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize)
 +    {
 +        dwError = ERROR_INSUFFICIENT_BUFFER;
 +    }
 +    else
 +    {
 +        lpConfig = (LPQUERY_SERVICE_CONFIGA)lpServiceConfig;
 +        lpConfig->dwServiceType = lpService->Status.dwServiceType;
 +        lpConfig->dwStartType = lpService->dwStartType;
 +        lpConfig->dwErrorControl = lpService->dwErrorControl;
 +        lpConfig->dwTagId = lpService->dwTag;
 +
 +        lpStr = (LPSTR)(lpServiceConfig + 1);
 +
 +        /* NOTE: Strings that are NULL for QUERY_SERVICE_CONFIG are pointers to empty strings.
 +          Verified in WINXP*/
 +
 +        if (lpImagePath)
 +        {
 +            WideCharToMultiByte(CP_ACP,
 +                                0,
 +                                lpImagePath,
 +                                -1,
 +                                lpStr,
 +                                wcslen(lpImagePath) + 1,
 +                                0,
 +                                0);
 +        }
 +        else
 +        {
 +            strcpy(lpStr, lpEmptyString);
 +        }
 +
 +        lpConfig->lpBinaryPathName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
 +        lpStr += (strlen((LPSTR)lpStr) + 1);
 +
 +        if (lpService->lpGroup && lpService->lpGroup->lpGroupName)
 +        {
 +            WideCharToMultiByte(CP_ACP,
 +                                0,
 +                                lpService->lpGroup->lpGroupName,
 +                                -1,
 +                                lpStr,
 +                                wcslen(lpService->lpGroup->lpGroupName) + 1,
 +                                0,
 +                                0);
 +        }
 +        else
 +        {
 +            strcpy(lpStr, lpEmptyString);
 +        }
 +
 +        lpConfig->lpLoadOrderGroup = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
 +        lpStr += (strlen(lpStr) + 1);
 +
 +        /* Append Dependencies */
 +        if (lpDependencies)
 +        {
 +            WideCharToMultiByte(CP_ACP,
 +                                0,
 +                                lpDependencies,
 +                                dwDependenciesLength,
 +                                lpStr,
 +                                dwDependenciesLength,
 +                                0,
 +                                0);
 +        }
 +        else
 +        {
 +            strcpy(lpStr, lpEmptyString);
 +        }
 +
 +        lpConfig->lpDependencies = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
 +        if (lpDependencies)
 +            lpStr += dwDependenciesLength;
 +        else
 +            lpStr += (strlen(lpStr) + 1);
 +
 +        if (lpServiceStartName)
 +        {
 +            WideCharToMultiByte(CP_ACP,
 +                                0,
 +                                lpServiceStartName,
 +                                -1,
 +                                lpStr,
 +                                wcslen(lpServiceStartName) + 1,
 +                                0,
 +                                0);
 +        }
 +        else
 +        {
 +            strcpy(lpStr, lpEmptyString);
 +        }
 +
 +        lpConfig->lpServiceStartName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
 +        lpStr += (strlen(lpStr) + 1);
 +
 +        if (lpService->lpDisplayName)
 +        {
 +            WideCharToMultiByte(CP_ACP,
 +                                0,
 +                                lpService->lpDisplayName,
 +                                -1,
 +                                lpStr,
 +                                wcslen(lpService->lpDisplayName) + 1,
 +                                0,
 +                                0);
 +        }
 +        else
 +        {
 +            strcpy(lpStr, lpEmptyString);
 +        }
 +
 +        lpConfig->lpDisplayName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
 +    }
 +
 +    if (pcbBytesNeeded != NULL)
 +        *pcbBytesNeeded = dwRequiredSize;
 +
 +Done:;
 +    if (lpImagePath != NULL)
 +        HeapFree(GetProcessHeap(), 0, lpImagePath);
 +
 +    if (lpServiceStartName != NULL)
 +        HeapFree(GetProcessHeap(), 0, lpServiceStartName);
 +
 +    if (lpDependencies != NULL)
 +        HeapFree(GetProcessHeap(), 0, lpDependencies);
 +
 +    if (hServiceKey != NULL)
 +        RegCloseKey(hServiceKey);
 +
 +    /* FIXME: Unlock the service database */
 +
 +    DPRINT("RQueryServiceConfigA() done\n");
 +
 +    return dwError;
 +}
 +
 +
 +/* Function 30 */
 +DWORD RQueryServiceLockStatusA(
 +    SC_RPC_HANDLE hSCManager,
 +    LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
 +    DWORD cbBufSize,
 +    LPBOUNDED_DWORD_4K pcbBytesNeeded)
 +{
 +    UNIMPLEMENTED;
 +    return ERROR_CALL_NOT_IMPLEMENTED;
 +}
 +
 +
 +/* Function 31 */
 +DWORD RStartServiceA(
 +    SC_RPC_HANDLE hService,
 +    DWORD argc,
 +    LPSTRING_PTRSA argv)
 +{
 +    DWORD dwError = ERROR_SUCCESS;
 +    PSERVICE_HANDLE hSvc;
 +    PSERVICE lpService = NULL;
 +
 +    DPRINT("RStartServiceA() called\n");
 +
 +    if (ScmShutdown)
 +        return ERROR_SHUTDOWN_IN_PROGRESS;
 +
 +    hSvc = ScmGetServiceFromHandle(hService);
 +    if (hSvc == NULL)
 +    {
 +        DPRINT1("Invalid service handle!\n");
 +        return ERROR_INVALID_HANDLE;
 +    }
 +
 +    if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
 +                                  SERVICE_START))
 +    {
 +        DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
 +        return ERROR_ACCESS_DENIED;
 +    }
 +
 +    lpService = hSvc->ServiceEntry;
 +    if (lpService == NULL)
 +    {
 +        DPRINT("lpService == NULL!\n");
 +        return ERROR_INVALID_HANDLE;
 +    }
 +
 +    if (lpService->dwStartType == SERVICE_DISABLED)
 +        return ERROR_SERVICE_DISABLED;
 +
 +    if (lpService->bDeleted)
 +        return ERROR_SERVICE_MARKED_FOR_DELETE;
 +
 +    /* FIXME: Convert argument vector to Unicode */
 +
 +    /* Start the service */
 +    dwError = ScmStartService(lpService, 0, NULL);
 +
 +    /* FIXME: Free argument vector */
 +
 +    return dwError;
 +}
 +
 +
 +/* Function 32 */
 +DWORD RGetServiceDisplayNameA(
 +    SC_RPC_HANDLE hSCManager,
 +    LPCSTR lpServiceName,
 +    LPSTR lpDisplayName,
 +    LPBOUNDED_DWORD_4K lpcchBuffer)
 +{
 +//    PMANAGER_HANDLE hManager;
 +    PSERVICE lpService = NULL;
 +    DWORD dwLength;
 +    DWORD dwError;
 +    LPWSTR lpServiceNameW;
 +
 +    DPRINT("RGetServiceDisplayNameA() called\n");
 +    DPRINT("hSCManager = %p\n", hSCManager);
 +    DPRINT("lpServiceName: %s\n", lpServiceName);
 +    DPRINT("lpDisplayName: %p\n", lpDisplayName);
 +    DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
 +
 +//    hManager = (PMANAGER_HANDLE)hSCManager;
 +//    if (hManager->Handle.Tag != MANAGER_TAG)
 +//    {
 +//        DPRINT("Invalid manager handle!\n");
 +//        return ERROR_INVALID_HANDLE;
 +//    }
 +
 +    if (lpServiceName != NULL)
 +    {
 +        dwLength = strlen(lpServiceName) + 1;
 +        lpServiceNameW = HeapAlloc(GetProcessHeap(),
 +                                   HEAP_ZERO_MEMORY,
 +                                   dwLength * sizeof(WCHAR));
 +        if (!lpServiceNameW)
 +            return ERROR_NOT_ENOUGH_MEMORY;
 +
 +        MultiByteToWideChar(CP_ACP,
 +                            0,
 +                            lpServiceName,
 +                            -1,
 +                            lpServiceNameW,
 +                            dwLength);
 +
 +        lpService = ScmGetServiceEntryByName(lpServiceNameW);
 +
 +        HeapFree(GetProcessHeap(), 0, lpServiceNameW);
 +    }
 +
 +    if (lpService == NULL)
 +    {
 +        DPRINT("Could not find a service!\n");
 +
 +        /* If the service could not be found and lpcchBuffer is 0, windows
 +           puts null in lpDisplayName and puts 1 in lpcchBuffer */
 +        if (*lpcchBuffer == 0)
 +        {
 +            *lpcchBuffer = 1;
 +            if (lpDisplayName != NULL)
 +            {
 +                *lpDisplayName = '\0';
 +            }
 +        }
 +        return ERROR_SERVICE_DOES_NOT_EXIST;
 +    }
 +
 +    if (!lpService->lpDisplayName)
 +    {
 +        dwLength = wcslen(lpService->lpServiceName);
 +        if (lpDisplayName != NULL &&
 +            *lpcchBuffer > dwLength)
 +        {
 +            WideCharToMultiByte(CP_ACP,
 +                                0,
 +                                lpService->lpServiceName,
 +                                wcslen(lpService->lpServiceName),
 +                                lpDisplayName,
 +                                dwLength + 1,
 +                                NULL,
 +                                NULL);
 +            return ERROR_SUCCESS;
 +        }
 +    }
 +    else
 +    {
 +        dwLength = wcslen(lpService->lpDisplayName);
 +        if (lpDisplayName != NULL &&
 +            *lpcchBuffer > dwLength)
 +        {
 +            WideCharToMultiByte(CP_ACP,
 +                                0,
 +                                lpService->lpDisplayName,
 +                                wcslen(lpService->lpDisplayName),
 +                                lpDisplayName,
 +                                dwLength + 1,
 +                                NULL,
 +                                NULL);
 +            return ERROR_SUCCESS;
 +        }
 +    }
 +
 +    dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
 +
 +    *lpcchBuffer = dwLength * 2;
 +
 +    return dwError;
 +}
 +
 +
 +/* Function 33 */
 +DWORD RGetServiceKeyNameA(
 +    SC_RPC_HANDLE hSCManager,
 +    LPCSTR lpDisplayName,
 +    LPSTR lpServiceName,
 +    LPBOUNDED_DWORD_4K lpcchBuffer)
 +{
 +    PSERVICE lpService;
 +    DWORD dwLength;
 +    DWORD dwError;
 +    LPWSTR lpDisplayNameW;
 +
 +    DPRINT("RGetServiceKeyNameA() called\n");
 +    DPRINT("hSCManager = %p\n", hSCManager);
 +    DPRINT("lpDisplayName: %s\n", lpDisplayName);
 +    DPRINT("lpServiceName: %p\n", lpServiceName);
 +    DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
 +
 +    dwLength = strlen(lpDisplayName) + 1;
 +    lpDisplayNameW = HeapAlloc(GetProcessHeap(),
 +                               HEAP_ZERO_MEMORY,
 +                               dwLength * sizeof(WCHAR));
 +    if (!lpDisplayNameW)
 +        return ERROR_NOT_ENOUGH_MEMORY;
 +
 +    MultiByteToWideChar(CP_ACP,
 +                        0,
 +                        lpDisplayName,
 +                        -1,
 +                        lpDisplayNameW,
 +                        dwLength);
 +
 +    lpService = ScmGetServiceEntryByDisplayName(lpDisplayNameW);
 +
 +    HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
 +
 +    if (lpService == NULL)
 +    {
 +        DPRINT("Could not find the service!\n");
 +
 +        /* If the service could not be found and lpcchBuffer is 0,
 +           put null in lpDisplayName and puts 1 in lpcchBuffer, verified WINXP. */
 +        if (*lpcchBuffer == 0)
 +        {
 +            *lpcchBuffer = 1;
 +            if (lpServiceName != NULL)
 +            {
 +                *lpServiceName = '\0';
 +            }
 +        }
 +
 +        return ERROR_SERVICE_DOES_NOT_EXIST;
 +    }
 +
 +    dwLength = wcslen(lpService->lpServiceName);
 +    if (lpServiceName != NULL &&
 +        *lpcchBuffer > dwLength)
 +    {
 +        WideCharToMultiByte(CP_ACP,
 +                            0,
 +                            lpService->lpServiceName,
 +                            wcslen(lpService->lpServiceName),
 +                            lpServiceName,
 +                            dwLength + 1,
 +                            NULL,
 +                            NULL);
 +        return ERROR_SUCCESS;
 +    }
 +
 +    dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
 +
 +    *lpcchBuffer = dwLength * 2;
 +
 +    return dwError;
 +}
 +
 +
 +/* Function 34 */
 +DWORD RI_ScGetCurrentGroupStateW(
 +    SC_RPC_HANDLE hSCManager,
 +    LPWSTR lpLoadOrderGroup,
 +    LPDWORD lpState)
 +{
 +    UNIMPLEMENTED;
 +    return ERROR_CALL_NOT_IMPLEMENTED;
 +}
 +
 +
 +/* Function 35 */
 +DWORD REnumServiceGroupW(
 +    SC_RPC_HANDLE hSCManager,
 +    DWORD dwServiceType,
 +    DWORD dwServiceState,
 +    LPBYTE lpBuffer,
 +    DWORD cbBufSize,
 +    LPBOUNDED_DWORD_256K pcbBytesNeeded,
 +    LPBOUNDED_DWORD_256K lpServicesReturned,
 +    LPBOUNDED_DWORD_256K lpResumeIndex,
 +    LPCWSTR pszGroupName)
 +{
 +    UNIMPLEMENTED;
 +    return ERROR_CALL_NOT_IMPLEMENTED;
 +}
 +
 +
 +//
 +// WARNING: This function is untested
 +//
 +/* Function 36 */
 +DWORD RChangeServiceConfig2A(
 +    SC_RPC_HANDLE hService,
 +    SC_RPC_CONFIG_INFOA Info)
 +{
 +    SC_RPC_CONFIG_INFOW InfoW;
 +    DWORD dwRet, dwLength;
 +    PVOID ptr = NULL;
 +
 +    DPRINT("RChangeServiceConfig2A() called\n");
 +    DPRINT("dwInfoLevel = %lu\n", Info.dwInfoLevel);
 +
 +    InfoW.dwInfoLevel = Info.dwInfoLevel;
 +
 +    if (InfoW.dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
 +    {
 +        LPSERVICE_DESCRIPTIONW lpServiceDescriptonW;
 +        LPSERVICE_DESCRIPTIONA lpServiceDescriptonA;
 +
 +        lpServiceDescriptonA = Info.psd;
 +
 +        ///if (lpServiceDescriptonA &&
 +        ///lpServiceDescriptonA->lpDescription)
 +        ///{
 +            dwLength = (strlen(Info.lpDescription) + 1) * sizeof(WCHAR);
 +
 +            lpServiceDescriptonW = HeapAlloc(GetProcessHeap(),
 +                                            0,
 +                                            dwLength + sizeof(SERVICE_DESCRIPTIONW));
 +            if (!lpServiceDescriptonW)
 +            {
 +                return ERROR_NOT_ENOUGH_MEMORY;
 +            }
 +
 +            lpServiceDescriptonW->lpDescription = (LPWSTR)(lpServiceDescriptonW + 1);
 +
 +            MultiByteToWideChar(CP_ACP,
 +                                0,
 +                                Info.lpDescription,
 +                                -1,
 +                                lpServiceDescriptonW->lpDescription,
 +                                dwLength);
 +
 +            ptr = lpServiceDescriptonW;
 +            InfoW.psd = lpServiceDescriptonW;
 +        ///}
 +    }
 +    else if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
 +    {
 +        LPSERVICE_FAILURE_ACTIONSW lpServiceFailureActionsW;
 +        LPSERVICE_FAILURE_ACTIONSA lpServiceFailureActionsA;
 +        DWORD dwRebootLen = 0;
 +        DWORD dwCommandLen = 0;
 +
 +        lpServiceFailureActionsA = Info.psfa;
 +
 +        if (lpServiceFailureActionsA)
 +        {
 +            if (lpServiceFailureActionsA->lpRebootMsg)
 +            {
 +                dwRebootLen = (strlen(lpServiceFailureActionsA->lpRebootMsg) + 1) * sizeof(WCHAR);
 +            }
 +            if (lpServiceFailureActionsA->lpCommand)
 +            {
 +                dwCommandLen = (strlen(lpServiceFailureActionsA->lpCommand) + 1) * sizeof(WCHAR);
 +            }
 +            dwLength = dwRebootLen + dwCommandLen + sizeof(SERVICE_FAILURE_ACTIONSW);
 +
 +            lpServiceFailureActionsW = HeapAlloc(GetProcessHeap(),
 +                                                 0,
 +                                                 dwLength);
 +            if (!lpServiceFailureActionsW)
 +            {
 +                return ERROR_NOT_ENOUGH_MEMORY;
 +            }
 +
 +            lpServiceFailureActionsW->cActions = lpServiceFailureActionsA->cActions;
 +            lpServiceFailureActionsW->dwResetPeriod = lpServiceFailureActionsA->dwResetPeriod;
 +            CopyMemory(lpServiceFailureActionsW->lpsaActions, lpServiceFailureActionsA->lpsaActions, sizeof(SC_ACTION));
 +
 +            if (lpServiceFailureActionsA->lpRebootMsg)
 +            {
 +                MultiByteToWideChar(CP_ACP,
 +                                    0,
 +                                    lpServiceFailureActionsA->lpRebootMsg,
 +                                    -1,
 +                                    lpServiceFailureActionsW->lpRebootMsg,
 +                                    dwRebootLen);
 +            }
 +
 +            if (lpServiceFailureActionsA->lpCommand)
 +            {
 +                MultiByteToWideChar(CP_ACP,
 +                                    0,
 +                                    lpServiceFailureActionsA->lpCommand,
 +                                    -1,
 +                                    lpServiceFailureActionsW->lpCommand,
 +                                    dwCommandLen);
 +            }
 +
 +            ptr = lpServiceFailureActionsW;
 +        }
 +    }
 +
 +    dwRet = RChangeServiceConfig2W(hService, InfoW);
 +
 +    HeapFree(GetProcessHeap(), 0, ptr);
 +
 +    return dwRet;
 +}
 +
 +
 +/* Function 37 */
 +DWORD RChangeServiceConfig2W(
 +    SC_RPC_HANDLE hService,
 +    SC_RPC_CONFIG_INFOW Info)
 +{
 +    DWORD dwError = ERROR_SUCCESS;
 +    PSERVICE_HANDLE hSvc;
 +    PSERVICE lpService = NULL;
 +    HKEY hServiceKey = NULL;
 +
 +    DPRINT("RChangeServiceConfig2W() called\n");
 +    DPRINT("dwInfoLevel = %lu\n", Info.dwInfoLevel);
 +
 +    if (ScmShutdown)
 +        return ERROR_SHUTDOWN_IN_PROGRESS;
 +
 +    hSvc = ScmGetServiceFromHandle(hService);
 +    if (hSvc == NULL)
 +    {
 +        DPRINT1("Invalid service handle!\n");
 +        return ERROR_INVALID_HANDLE;
 +    }
 +
 +    if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
 +                                  SERVICE_CHANGE_CONFIG))
 +    {
 +        DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
 +        return ERROR_ACCESS_DENIED;
 +    }
 +
 +    lpService = hSvc->ServiceEntry;
 +    if (lpService == NULL)
 +    {
 +        DPRINT("lpService == NULL!\n");
 +        return ERROR_INVALID_HANDLE;
 +    }
 +
 +    /* FIXME: Lock database exclusively */
 +
 +    if (lpService->bDeleted)
 +    {
 +        /* FIXME: Unlock database */
 +        DPRINT("The service has already been marked for delete!\n");
 +        return ERROR_SERVICE_MARKED_FOR_DELETE;
 +    }
 +
 +    /* Open the service key */
 +    dwError = ScmOpenServiceKey(lpService->szServiceName,
 +                                KEY_SET_VALUE,
 +                                &hServiceKey);
 +    if (dwError != ERROR_SUCCESS)
 +        goto done;
 +
 +    if (Info.dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
 +    {
 +        LPSERVICE_DESCRIPTIONW lpServiceDescription;
 +
 +        lpServiceDescription = (LPSERVICE_DESCRIPTIONW)Info.psd;
 +        lpServiceDescription->lpDescription = (LPWSTR)((ULONG_PTR)lpServiceDescription + sizeof(LPSERVICE_DESCRIPTIONW));
 +
 +        if (lpServiceDescription != NULL &&
 +            lpServiceDescription->lpDescription != NULL)
 +        {
 +            DPRINT("Setting value %S\n", lpServiceDescription->lpDescription);
 +            RegSetValueExW(hServiceKey,
 +                           L"Description",
 +                           0,
 +                           REG_SZ,
 +                           (LPBYTE)lpServiceDescription->lpDescription,
 +                           (wcslen(lpServiceDescription->lpDescription) + 1) * sizeof(WCHAR));
 +
 +            if (dwError != ERROR_SUCCESS)
 +                goto done;
 +        }
 +    }
 +    else if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
 +    {
 +        UNIMPLEMENTED;
 +        dwError = ERROR_CALL_NOT_IMPLEMENTED;
 +        goto done;
 +    }
 +
 +done:
 +    /* FIXME: Unlock database */
 +    if (hServiceKey != NULL)
 +        RegCloseKey(hServiceKey);
 +
 +    DPRINT("RChangeServiceConfig2W() done (Error %lu)\n", dwError);
 +
 +    return dwError;
 +}
 +
 +
 +/* Function 38 */
 +DWORD RQueryServiceConfig2A(
 +    SC_RPC_HANDLE hService,
 +    DWORD dwInfoLevel,
 +    LPBYTE lpBuffer,
 +    DWORD cbBufSize,
 +    LPBOUNDED_DWORD_8K pcbBytesNeeded)
 +{
 +    DWORD dwError = ERROR_SUCCESS;
 +    PSERVICE_HANDLE hSvc;
 +    PSERVICE lpService = NULL;
 +    HKEY hServiceKey = NULL;
 +    LPWSTR lpDescriptionW = NULL;
 +    LPSTR lpDescription = NULL;
 +
 +    DPRINT("RQueryServiceConfig2A() called hService %p dwInfoLevel %u, lpBuffer %p cbBufSize %u pcbBytesNeeded %p\n",
 +           hService, dwInfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
 +
 +    if (!lpBuffer)
 +        return ERROR_INVALID_ADDRESS;
 +
 +    if (ScmShutdown)
 +        return ERROR_SHUTDOWN_IN_PROGRESS;
 +
 +    hSvc = ScmGetServiceFromHandle(hService);
 +    if (hSvc == NULL)
 +    {
 +        DPRINT1("Invalid service handle!\n");
 +        return ERROR_INVALID_HANDLE;
 +    }
 +
 +    if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
 +                                  SERVICE_QUERY_CONFIG))
 +    {
 +        DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
 +        return ERROR_ACCESS_DENIED;
 +    }
 +
 +    lpService = hSvc->ServiceEntry;
 +    if (lpService == NULL)
 +    {
 +        DPRINT("lpService == NULL!\n");
 +        return ERROR_INVALID_HANDLE;
 +    }
 +
 +    /* FIXME: Lock the service database shared */
 +
 +    dwError = ScmOpenServiceKey(lpService->lpServiceName,
 +                                KEY_READ,
 +                                &hServiceKey);
 +    if (dwError != ERROR_SUCCESS)
 +        goto done;
 +
 +    if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
 +    {
 +        LPSERVICE_DESCRIPTIONA lpServiceDescription = (LPSERVICE_DESCRIPTIONA)lpBuffer;
 +        LPSTR lpStr;
 +
 +        *pcbBytesNeeded = sizeof(SERVICE_DESCRIPTIONA);
 +
 +        dwError = ScmReadString(hServiceKey,
 +                                L"Description",
 +                                &lpDescriptionW);
 +        if (dwError == ERROR_SUCCESS)
 +        {
 +            *pcbBytesNeeded += ((wcslen(lpDescriptionW) + 1) * sizeof(WCHAR));
 +        }
 +
 +        if (cbBufSize >= *pcbBytesNeeded)
 +        {
 +
 +            if (dwError == ERROR_SUCCESS)
 +            {
 +                lpStr = (LPSTR)(lpServiceDescription + 1);
 +
 +                WideCharToMultiByte(CP_ACP,
 +                                    0,
 +                                    lpDescriptionW,
 +                                    -1,
 +                                    lpStr,
 +                                    wcslen(lpDescriptionW),
 +                                    NULL,
 +                                    NULL);
 +                lpServiceDescription->lpDescription = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceDescription);
 +            }
 +            else
 +            {
 +                lpServiceDescription->lpDescription = NULL;
 +                goto done;
 +            }
 +        }
 +        else
 +        {
 +            dwError = ERROR_INSUFFICIENT_BUFFER;
 +            goto done;
 +        }
 +    }
 +    else if (dwInfoLevel & SERVICE_CONFIG_FAILURE_ACTIONS)
 +    {
 +        UNIMPLEMENTED;
 +        dwError = ERROR_CALL_NOT_IMPLEMENTED;
 +        goto done;
 +    }
 +
 +done:
 +    if (lpDescription != NULL)
 +        HeapFree(GetProcessHeap(), 0, lpDescription);
 +
 +    if (hServiceKey != NULL)
 +        RegCloseKey(hServiceKey);
 +
 +    /* FIXME: Unlock database */
 +
 +    DPRINT("RQueryServiceConfig2W() done (Error %lu)\n", dwError);
 +
 +    return dwError;
 +}
 +
 +
 +/* Function 39 */
 +DWORD RQueryServiceConfig2W(
 +    SC_RPC_HANDLE hService,
 +    DWORD dwInfoLevel,
 +    LPBYTE lpBuffer,
 +    DWORD cbBufSize,
 +    LPBOUNDED_DWORD_8K pcbBytesNeeded)
 +{
 +    DWORD dwError = ERROR_SUCCESS;
 +    PSERVICE_HANDLE hSvc;
 +    PSERVICE lpService = NULL;
 +    HKEY hServiceKey = NULL;
 +    DWORD dwRequiredSize;
 +    LPWSTR lpDescription = NULL;
 +    LPWSTR lpFailureCommand = NULL;
 +    LPWSTR lpRebootMessage = NULL;
 +
 +    DPRINT("RQueryServiceConfig2W() called\n");
 +
 +    if (!lpBuffer)
 +        return ERROR_INVALID_ADDRESS;
 +
 +    if (ScmShutdown)
 +        return ERROR_SHUTDOWN_IN_PROGRESS;
 +
 +    hSvc = ScmGetServiceFromHandle(hService);
 +    if (hSvc == NULL)
 +    {
 +        DPRINT1("Invalid service handle!\n");
 +        return ERROR_INVALID_HANDLE;
 +    }
 +
 +    if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
 +                                  SERVICE_QUERY_CONFIG))
 +    {
 +        DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
 +        return ERROR_ACCESS_DENIED;
 +    }
 +
 +    lpService = hSvc->ServiceEntry;
 +    if (lpService == NULL)
 +    {
 +        DPRINT("lpService == NULL!\n");
 +        return ERROR_INVALID_HANDLE;
 +    }
 +
 +    /* FIXME: Lock the service database shared */
 +
 +    dwError = ScmOpenServiceKey(lpService->lpServiceName,
 +                                KEY_READ,
 +                                &hServiceKey);
 +    if (dwError != ERROR_SUCCESS)
 +        goto done;
 +
 +    if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
 +    {
 +        LPSERVICE_DESCRIPTIONW lpServiceDescription = (LPSERVICE_DESCRIPTIONW)lpBuffer;
 +        LPWSTR lpStr;
 +
 +        dwError = ScmReadString(hServiceKey,
 +                                L"Description",
 +                                &lpDescription);
 +        if (dwError != ERROR_SUCCESS)
 +            goto done;
 +
 +        dwRequiredSize = sizeof(SERVICE_DESCRIPTIONW) + ((wcslen(lpDescription) + 1) * sizeof(WCHAR));
 +
 +        if (cbBufSize < dwRequiredSize)
 +        {
 +            *pcbBytesNeeded = dwRequiredSize;
 +            dwError = ERROR_INSUFFICIENT_BUFFER;
 +            goto done;
 +        }
 +
 +        lpStr = (LPWSTR)(lpServiceDescription + 1);
 +        wcscpy(lpStr, lpDescription);
 +        lpServiceDescription->lpDescription = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceDescription);
 +    }
 +    else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
 +    {
 +        LPWSTR lpStr;
 +        LPSERVICE_FAILURE_ACTIONSW lpFailureActions = (LPSERVICE_FAILURE_ACTIONSW)lpBuffer;
 +
 +        UNIMPLEMENTED;
 +
 +        dwError = ScmReadString(hServiceKey,
 +                                L"FailureCommand",
 +                                &lpFailureCommand);
 +
 +        dwError = ScmReadString(hServiceKey,
 +                                L"RebootMessage",
 +                                &lpRebootMessage);
 +
 +        dwRequiredSize = sizeof(SERVICE_FAILURE_ACTIONSW);
 +
 +        if (lpFailureCommand)
 +            dwRequiredSize += (wcslen(lpFailureCommand) + 1) * sizeof(WCHAR);
 +
 +        if (lpRebootMessage)
 +            dwRequiredSize += (wcslen(lpRebootMessage) + 1) * sizeof(WCHAR);
 +
 +        if (cbBufSize < dwRequiredSize)
 +        {
 +            *pcbBytesNeeded = dwRequiredSize;
 +            dwError = ERROR_INSUFFICIENT_BUFFER;
 +            goto done;
 +        }
 +
 +        lpFailureActions->cActions = 0; 
 +        lpFailureActions->dwResetPeriod = 0;
 +        lpFailureActions->lpCommand = NULL;
 +        lpFailureActions->lpRebootMsg = NULL;
 +        lpFailureActions->lpsaActions = NULL;
 +
 +        lpStr = (LPWSTR)(lpFailureActions + 1);
 +        if (lpRebootMessage)
 +        {
 +            wcscpy(lpStr, lpRebootMessage);
 +            lpFailureActions->lpRebootMsg = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpRebootMessage);
 +            lpStr += wcslen(lpRebootMessage) + 1;
 +        }
 +
 +        if (lpFailureCommand)
 +        {
 +            wcscpy(lpStr, lpFailureCommand);
 +            lpFailureActions->lpCommand = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpFailureCommand);
 +            lpStr += wcslen(lpRebootMessage) + 1;
 +        }
 +        dwError = STATUS_SUCCESS;
 +        goto done;
 +    }
 +
 +done:
 +    if (lpDescription != NULL)
 +        HeapFree(GetProcessHeap(), 0, lpDescription);
 +
 +    if (lpRebootMessage != NULL)
 +        HeapFree(GetProcessHeap(), 0, lpRebootMessage);
 +
 +    if (lpFailureCommand != NULL)
 +        HeapFree(GetProcessHeap(), 0, lpFailureCommand);
 +
 +    if (hServiceKey != NULL)
 +        RegCloseKey(hServiceKey);
 +
 +    /* FIXME: Unlock database */
 +
 +    DPRINT("RQueryServiceConfig2W() done (Error %lu)\n", dwError);
 +
 +    return dwError;
 +}
 +
 +
 +/* Function 40 */
 +DWORD RQueryServiceStatusEx(
 +    SC_RPC_HANDLE hService,
 +    SC_STATUS_TYPE InfoLevel,
 +    LPBYTE lpBuffer,
 +    DWORD cbBufSize,
 +    LPBOUNDED_DWORD_8K pcbBytesNeeded)
 +{
 +    LPSERVICE_STATUS_PROCESS lpStatus;
 +    PSERVICE_HANDLE hSvc;
 +    PSERVICE lpService;
 +
 +    DPRINT("RQueryServiceStatusEx() called\n");
 +
 +    if (ScmShutdown)
 +        return ERROR_SHUTDOWN_IN_PROGRESS;
 +
 +    if (InfoLevel != SC_STATUS_PROCESS_INFO)
 +        return ERROR_INVALID_LEVEL;
 +
 +    *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
 +
 +    if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
 +        return ERROR_INSUFFICIENT_BUFFER;
 +
 +    hSvc = ScmGetServiceFromHandle(hService);
 +    if (hSvc == NULL)
 +    {
 +        DPRINT1("Invalid service handle!\n");
 +        return ERROR_INVALID_HANDLE;
 +    }
 +
 +    if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
 +                                  SERVICE_QUERY_STATUS))
 +    {
 +        DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
 +        return ERROR_ACCESS_DENIED;
 +    }
 +
 +    lpService = hSvc->ServiceEntry;
 +    if (lpService == NULL)
 +    {
 +        DPRINT("lpService == NULL!\n");
 +        return ERROR_INVALID_HANDLE;
 +    }
 +
 +    lpStatus = (LPSERVICE_STATUS_PROCESS)lpBuffer;
 +
 +    /* Return service status information */
 +    RtlCopyMemory(lpStatus,
 +                  &lpService->Status,
 +                  sizeof(SERVICE_STATUS));
 +
 +    lpStatus->dwProcessId = lpService->ProcessId;     /* FIXME */
 +    lpStatus->dwServiceFlags = 0;                     /* FIXME */
 +
 +    return ERROR_SUCCESS;
 +}
 +
 +
 +/* Function 41 */
 +DWORD REnumServicesStatusExA(
 +    SC_RPC_HANDLE hSCManager,
 +    SC_ENUM_TYPE InfoLevel,
 +    DWORD dwServiceType,
 +    DWORD dwServiceState,
 +    LPBYTE lpBuffer,
 +    DWORD cbBufSize,
 +    LPBOUNDED_DWORD_256K pcbBytesNeeded,
 +    LPBOUNDED_DWORD_256K lpServicesReturned,
 +    LPBOUNDED_DWORD_256K lpResumeIndex,
 +    LPCSTR pszGroupName)
 +{
 +    LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtrW = NULL;
 +    LPENUM_SERVICE_STATUS_PROCESSA lpStatusPtrA = NULL;
 +    LPWSTR lpStringPtrW;
 +    LPSTR lpStringPtrA;
 +    LPWSTR pszGroupNameW = NULL;
 +    DWORD dwError;
 +    DWORD dwServiceCount;
 +
 +    DPRINT("REnumServicesStatusExA() called\n");
 +
 +    if (pszGroupName)
 +    {
 +        pszGroupNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (strlen(pszGroupName) + 1) * sizeof(WCHAR));
 +        if (!pszGroupNameW)
 +        {
 +             DPRINT("Failed to allocate buffer!\n");
 +             return ERROR_NOT_ENOUGH_MEMORY;
 +        }
 +
 +        MultiByteToWideChar(CP_ACP,
 +                            0,
 +                            pszGroupName,
 +                            -1,
 +                            pszGroupNameW,
 +                            strlen(pszGroupName) + 1);
 +    }
 +
 +    if ((cbBufSize > 0) && (lpBuffer))
 +    {
 +        lpStatusPtrW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbBufSize);
 +        if (!lpStatusPtrW)
 +        {
 +            DPRINT("Failed to allocate buffer!\n");
 +            return ERROR_NOT_ENOUGH_MEMORY;
 +        }
 +    }
 +
 +    dwError = REnumServicesStatusExW(hSCManager,
 +                                     InfoLevel,
 +                                     dwServiceType,
 +                                     dwServiceState,
 +                                     (LPBYTE)lpStatusPtrW,
 +                                     cbBufSize,
 +                                     pcbBytesNeeded,
 +                                     lpServicesReturned,
 +                                     lpResumeIndex,
 +                                     pszGroupNameW);
 +
 +    /* if no services were returned then we are Done */
 +    if (*lpServicesReturned == 0)
 +        goto Done;
 +
 +    lpStatusPtrA = (LPENUM_SERVICE_STATUS_PROCESSA)lpBuffer;
 +    lpStringPtrA = (LPSTR)((ULONG_PTR)lpBuffer +
 +                  *lpServicesReturned * sizeof(ENUM_SERVICE_STATUS_PROCESSA));
 +    lpStringPtrW = (LPWSTR)((ULONG_PTR)lpStatusPtrW + 
 +                  *lpServicesReturned * sizeof(ENUM_SERVICE_STATUS_PROCESSW));
 +
 +    for (dwServiceCount = 0; dwServiceCount < *lpServicesReturned; dwServiceCount++)
 +    {
 +        /* Copy the service name */
 +        WideCharToMultiByte(CP_ACP,
 +                            0,
 +                            lpStringPtrW,
 +                            -1,
 +                            lpStringPtrA,
 +                            wcslen(lpStringPtrW),
 +                            0,
 +                            0);
 +
 +        lpStatusPtrA->lpServiceName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
 +        lpStringPtrA += wcslen(lpStringPtrW) + 1;
 +        lpStringPtrW += wcslen(lpStringPtrW) + 1;
 +
 +        /* Copy the display name */
 +        WideCharToMultiByte(CP_ACP,
 +                            0,
 +                            lpStringPtrW,
 +                            -1,
 +                            lpStringPtrA,
 +                            wcslen(lpStringPtrW),
 +                            0,
 +                            0);
 +
 +        lpStatusPtrA->lpDisplayName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
 +        lpStringPtrA += wcslen(lpStringPtrW) + 1;
 +        lpStringPtrW += wcslen(lpStringPtrW) + 1;
 +
 +        /* Copy the status information */
 +        memcpy(&lpStatusPtrA->ServiceStatusProcess,
 +               &lpStatusPtrW->ServiceStatusProcess,
 +               sizeof(SERVICE_STATUS));
 +
 +        lpStatusPtrA->ServiceStatusProcess.dwProcessId = lpStatusPtrW->ServiceStatusProcess.dwProcessId; /* FIXME */
 +        lpStatusPtrA->ServiceStatusProcess.dwServiceFlags = 0; /* FIXME */
 +        lpStatusPtrA++;
 +    }
 +
 +Done:;
 +    if (pszGroupNameW)
 +        HeapFree(GetProcessHeap(), 0, pszGroupNameW);
 +
 +    if (lpStatusPtrW)
 +        HeapFree(GetProcessHeap(), 0, lpStatusPtrW);
 +
 +    DPRINT("REnumServicesStatusExA() done (Error %lu)\n", dwError);
 +
 +    return dwError;
 +}
 +
 +
 +/* Function 42 */
 +DWORD REnumServicesStatusExW(
 +    SC_RPC_HANDLE hSCManager,
 +    SC_ENUM_TYPE InfoLevel,
 +    DWORD dwServiceType,
 +    DWORD dwServiceState,
 +    LPBYTE lpBuffer,
 +    DWORD cbBufSize,
 +    LPBOUNDED_DWORD_256K pcbBytesNeeded,
 +    LPBOUNDED_DWORD_256K lpServicesReturned,
 +    LPBOUNDED_DWORD_256K lpResumeIndex,
 +    LPCWSTR pszGroupName)
 +{
 +    PMANAGER_HANDLE hManager;
 +    PSERVICE lpService;
 +    DWORD dwError = ERROR_SUCCESS;
 +    PLIST_ENTRY ServiceEntry;
 +    PSERVICE CurrentService;
 +    DWORD dwState;
 +    DWORD dwRequiredSize;
 +    DWORD dwServiceCount;
 +    DWORD dwSize;
 +    DWORD dwLastResumeCount = 0;
 +    LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtr;
 +    LPWSTR lpStringPtr;
 +
 +    DPRINT("REnumServicesStatusExW() called\n");
 +
 +    if (ScmShutdown)
 +        return ERROR_SHUTDOWN_IN_PROGRESS;
 +
 +    if (InfoLevel != SC_ENUM_PROCESS_INFO)
 +        return ERROR_INVALID_LEVEL;
 +
 +    hManager = ScmGetServiceManagerFromHandle(hSCManager);
 +    if (hManager == NULL)
 +    {
 +        DPRINT1("Invalid service manager handle!\n");
 +        return ERROR_INVALID_HANDLE;
 +    }
 +
 +    *pcbBytesNeeded = 0;
 +    *lpServicesReturned = 0;
 +
 +    if ((dwServiceType!=SERVICE_DRIVER) && (dwServiceType!=SERVICE_WIN32))
 +    {
 +        DPRINT("Not a valid Service Type!\n");
 +        return ERROR_INVALID_PARAMETER;
 +    }
 +
 +    if ((dwServiceState<SERVICE_ACTIVE) || (dwServiceState>SERVICE_STATE_ALL))
 +    {
 +        DPRINT("Not a valid Service State!\n");
 +        return ERROR_INVALID_PARAMETER;
 +    }
 +
 +    /* Check access rights */
 +    if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
 +                                  SC_MANAGER_ENUMERATE_SERVICE))
 +    {
 +        DPRINT("Insufficient access rights! 0x%lx\n",
 +               hManager->Handle.DesiredAccess);
 +        return ERROR_ACCESS_DENIED;
 +    }
 +
 +    if (lpResumeIndex) dwLastResumeCount = *lpResumeIndex;
 +
 +    /* Lock the service list shared */
 +
 +    lpService = ScmGetServiceEntryByResumeCount(dwLastResumeCount);
 +    if (lpService == NULL)
 +    {
 +        dwError = ERROR_SUCCESS;
 +        goto Done;
 +    }
 +
 +    dwRequiredSize = 0;
 +    dwServiceCount = 0;
 +
 +    for (ServiceEntry = &lpService->ServiceListEntry;
 +         ServiceEntry != &ServiceListHead;
 +         ServiceEntry = ServiceEntry->Flink)
 +    {
 +        CurrentService = CONTAINING_RECORD(ServiceEntry,
 +                                           SERVICE,
 +                                           ServiceListEntry);
 +
 +        if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
 +            continue;
 +
 +        dwState = SERVICE_ACTIVE;
 +        if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
 +            dwState = SERVICE_INACTIVE;
 +
 +        if ((dwState & dwServiceState) == 0)
 +            continue;
 +
 +        if (pszGroupName)
 +        {
 +            if (*pszGroupName == 0)
 +            {
 +                if (CurrentService->lpGroup != NULL)
 +                    continue;
 +            }
 +            else
 +            {
 +                if ((CurrentService->lpGroup == NULL) ||
 +                    _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName))
 +                    continue;
 +            }
 +        }
 +
 +        dwSize = sizeof(ENUM_SERVICE_STATUS_PROCESSW) +
 +                 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
 +                 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
 +
 +        if (dwRequiredSize + dwSize <= cbBufSize)
 +        {
 +            DPRINT("Service name: %S  fit\n", CurrentService->lpServiceName);
 +            dwRequiredSize += dwSize;
 +            dwServiceCount++;
 +            dwLastResumeCount = CurrentService->dwResumeCount;
 +        }
 +        else
 +        {
 +            DPRINT("Service name: %S  no fit\n", CurrentService->lpServiceName);
 +            break;
 +        }
 +
 +    }
 +
 +    DPRINT("dwRequiredSize: %lu\n", dwRequiredSize);
 +    DPRINT("dwServiceCount: %lu\n", dwServiceCount);
 +
 +    for (;
 +         ServiceEntry != &ServiceListHead;
 +         ServiceEntry = ServiceEntry->Flink)
 +    {
 +        CurrentService = CONTAINING_RECORD(ServiceEntry,
 +                                           SERVICE,
 +                                           ServiceListEntry);
 +
 +        if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
 +            continue;
 +
 +        dwState = SERVICE_ACTIVE;
 +        if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
 +            dwState = SERVICE_INACTIVE;
 +
 +        if ((dwState & dwServiceState) == 0)
 +            continue;
 +
 +        if (pszGroupName)
 +        {
 +            if (*pszGroupName == 0)
 +            {
 +                if (CurrentService->lpGroup != NULL)
 +                    continue;
 +            }
 +            else
 +            {
 +                if ((CurrentService->lpGroup == NULL) ||
 +                    _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName))
 +                    continue;
 +            }
 +        }
 +
 +        dwRequiredSize += (sizeof(ENUM_SERVICE_STATUS_PROCESSW) +
 +                           ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
 +                           ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR)));
 +
 +        dwError = ERROR_MORE_DATA;
 +    }
 +
 +    DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize);
 +
 +    if (lpResumeIndex)
 +        *lpResumeIndex = dwLastResumeCount;
 +
 +    *lpServicesReturned = dwServiceCount;
 +    *pcbBytesNeeded = dwRequiredSize;
 +
 +    /* If there was no services that matched */
 +    if ((!dwServiceCount) && (dwError != ERROR_MORE_DATA))
 +    {
 +        dwError = ERROR_SERVICE_DOES_NOT_EXIST;
 +        goto Done;
 +    }
 +
 +    lpStatusPtr = (LPENUM_SERVICE_STATUS_PROCESSW)lpBuffer;
 +    lpStringPtr = (LPWSTR)((ULONG_PTR)lpBuffer +
 +                           dwServiceCount * sizeof(ENUM_SERVICE_STATUS_PROCESSW));
 +
 +    dwRequiredSize = 0;
 +    for (ServiceEntry = &lpService->ServiceListEntry;
 +         ServiceEntry != &ServiceListHead;
 +         ServiceEntry = ServiceEntry->Flink)
 +    {
 +        CurrentService = CONTAINING_RECORD(ServiceEntry,
 +                                           SERVICE,
 +                                           ServiceListEntry);
 +
 +        if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
 +            continue;
 +
 +        dwState = SERVICE_ACTIVE;
 +        if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
 +            dwState = SERVICE_INACTIVE;
 +
 +        if ((dwState & dwServiceState) == 0)
 +            continue;
 +
 +        if (pszGroupName)
 +        {
 +            if (*pszGroupName == 0)
 +            {
 +                if (CurrentService->lpGroup != NULL)
 +                    continue;
 +            }
 +            else
 +            {
 +                if ((CurrentService->lpGroup == NULL) ||
 +                    _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName))
 +                    continue;
 +            }
 +        }
 +
 +        dwSize = sizeof(ENUM_SERVICE_STATUS_PROCESSW) +
 +                 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
 +                 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
 +
 +        if (dwRequiredSize + dwSize <= cbBufSize)
 +        {
 +            /* Copy the service name */
 +            wcscpy(lpStringPtr,
 +                   CurrentService->lpServiceName);
 +            lpStatusPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
 +            lpStringPtr += (wcslen(CurrentService->lpServiceName) + 1);
 +
 +            /* Copy the display name */
 +            wcscpy(lpStringPtr,
 +                   CurrentService->lpDisplayName);
 +            lpStatusPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
 +            lpStringPtr += (wcslen(CurrentService->lpDisplayName) + 1);
 +
 +            /* Copy the status information */
 +            memcpy(&lpStatusPtr->ServiceStatusProcess,
 +                   &CurrentService->Status,
 +                   sizeof(SERVICE_STATUS));
 +            lpStatusPtr->ServiceStatusProcess.dwProcessId = CurrentService->ProcessId; /* FIXME */
 +            lpStatusPtr->ServiceStatusProcess.dwServiceFlags = 0; /* FIXME */
 +
 +            lpStatusPtr++;
 +            dwRequiredSize += dwSize;
 +        }
 +        else
 +        {
 +            break;
 +        }
 +    }
 +
 +    if (dwError == 0) 
 +    {
 +        *pcbBytesNeeded = 0;
 +        if (lpResumeIndex)
 +            *lpResumeIndex = 0;
 +    }
 +
 +Done:;
 +    /* Unlock the service list */
 +
 +    DPRINT("REnumServicesStatusExW() done (Error %lu)\n", dwError);
 +
 +    return dwError;
 +}
 +
 +
 +/* Function 43 */
 +DWORD RSendTSMessage(
 +    handle_t BindingHandle)  /* FIXME */
 +{
 +    UNIMPLEMENTED;
 +    return ERROR_CALL_NOT_IMPLEMENTED;
 +}
 +
 +
 +/* Function 44 */
 +DWORD RCreateServiceWOW64A(
 +    handle_t BindingHandle,
 +    LPSTR lpServiceName,
 +    LPSTR lpDisplayName,
 +    DWORD dwDesiredAccess,
 +    DWORD dwServiceType,
 +    DWORD dwStartType,
 +    DWORD dwErrorControl,
 +    LPSTR lpBinaryPathName,
 +    LPSTR lpLoadOrderGroup,
 +    LPDWORD lpdwTagId,
 +    LPBYTE lpDependencies,
 +    DWORD dwDependSize,
 +    LPSTR lpServiceStartName,
 +    LPBYTE lpPassword,
 +    DWORD dwPwSize,
 +    LPSC_RPC_HANDLE lpServiceHandle)
 +{
 +    UNIMPLEMENTED;
 +    return ERROR_CALL_NOT_IMPLEMENTED;
 +}
 +
 +
 +/* Function 45 */
 +DWORD RCreateServiceWOW64W(
 +    handle_t BindingHandle,
 +    LPWSTR lpServiceName,
 +    LPWSTR lpDisplayName,
 +    DWORD dwDesiredAccess,
 +    DWORD dwServiceType,
 +    DWORD dwStartType,
 +    DWORD dwErrorControl,
 +    LPWSTR lpBinaryPathName,
 +    LPWSTR lpLoadOrderGroup,
 +    LPDWORD lpdwTagId,
 +    LPBYTE lpDependencies,
 +    DWORD dwDependSize,
 +    LPWSTR lpServiceStartName,
 +    LPBYTE lpPassword,
 +    DWORD dwPwSize,
 +    LPSC_RPC_HANDLE lpServiceHandle)
 +{
 +    UNIMPLEMENTED;
 +    return ERROR_CALL_NOT_IMPLEMENTED;
 +}
 +
 +
 +/* Function 46 */
 +DWORD RQueryServiceTagInfo(
 +    handle_t BindingHandle)  /* FIXME */
 +{
 +    UNIMPLEMENTED;
 +    return ERROR_CALL_NOT_IMPLEMENTED;
 +}
 +
 +
 +/* Function 47 */
 +DWORD RNotifyServiceStatusChange(
 +    SC_RPC_HANDLE hService,
 +    SC_RPC_NOTIFY_PARAMS NotifyParams,
 +    GUID *pClientProcessGuid,
 +    GUID *pSCMProcessGuid,
 +    PBOOL pfCreateRemoteQueue,
 +    LPSC_NOTIFY_RPC_HANDLE phNotify)
 +{
 +    UNIMPLEMENTED;
 +    return ERROR_CALL_NOT_IMPLEMENTED;
 +}
 +
 +
 +/* Function 48 */
 +DWORD RGetNotifyResults(
 +    SC_NOTIFY_RPC_HANDLE hNotify,
 +    PSC_RPC_NOTIFY_PARAMS_LIST *ppNotifyParams)
 +{
 +    UNIMPLEMENTED;
 +    return ERROR_CALL_NOT_IMPLEMENTED;
 +}
 +
 +
 +/* Function 49 */
 +DWORD RCloseNotifyHandle(
 +    LPSC_NOTIFY_RPC_HANDLE phNotify,
 +    PBOOL pfApcFired)
 +{
 +    UNIMPLEMENTED;
 +    return ERROR_CALL_NOT_IMPLEMENTED;
 +}
 +
 +
 +/* Function 50 */
 +DWORD RControlServiceExA(
 +    SC_RPC_HANDLE hService,
 +    DWORD dwControl,
 +    DWORD dwInfoLevel)
 +{
 +    UNIMPLEMENTED;
 +    return ERROR_CALL_NOT_IMPLEMENTED;
 +}
 +
 +
 +/* Function 51 */
 +DWORD RControlServiceExW(
 +    SC_RPC_HANDLE hService,
 +    DWORD dwControl,
 +    DWORD dwInfoLevel)
 +{
 +    UNIMPLEMENTED;
 +    return ERROR_CALL_NOT_IMPLEMENTED;
 +}
 +
 +
 +/* Function 52 */
 +DWORD RSendPnPMessage(
 +    handle_t BindingHandle)  /* FIXME */
 +{
 +    UNIMPLEMENTED;
 +    return ERROR_CALL_NOT_IMPLEMENTED;
 +}
 +
 +
 +/* Function 53 */
 +DWORD RValidatePnPService(
 +    handle_t BindingHandle)  /* FIXME */
 +{
 +    UNIMPLEMENTED;
 +    return ERROR_CALL_NOT_IMPLEMENTED;
 +}
 +
 +
 +/* Function 54 */
 +DWORD ROpenServiceStatusHandle(
 +    handle_t BindingHandle)  /* FIXME */
 +{
 +    UNIMPLEMENTED;
 +    return ERROR_CALL_NOT_IMPLEMENTED;
 +}
 +
 +
 +/* Function 55 */
 +DWORD RFunction55(
 +    handle_t BindingHandle)  /* FIXME */
 +{
 +    UNIMPLEMENTED;
 +    return ERROR_CALL_NOT_IMPLEMENTED;
 +}
 +
 +
 +void __RPC_FAR * __RPC_USER midl_user_allocate(size_t len)
 +{
 +    return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
 +}
 +
 +
 +void __RPC_USER midl_user_free(void __RPC_FAR * ptr)
 +{
 +    HeapFree(GetProcessHeap(), 0, ptr);
 +}
 +
 +
 +void __RPC_USER SC_RPC_HANDLE_rundown(SC_RPC_HANDLE hSCObject)
 +{
 +}
 +
 +
 +void __RPC_USER SC_RPC_LOCK_rundown(SC_RPC_LOCK Lock)
 +{
 +}
 +
 +
 +void __RPC_USER SC_NOTIFY_RPC_HANDLE_rundown(SC_NOTIFY_RPC_HANDLE hNotify)
 +{
 +}
 +
 +/* EOF */
index 78bc3d7,0000000..29dc28e
mode 100644,000000..100644
--- /dev/null
@@@ -1,262 -1,0 +1,269 @@@
-     freeldr/freeldr/windows/headless.c
 +
 +CreateBootSectorTarget(dosmbr ${CMAKE_CURRENT_SOURCE_DIR}/freeldr/bootsect/dosmbr.asm ${CMAKE_CURRENT_BINARY_DIR}/freeldr/bootsect/dosmbr.bin)
 +CreateBootSectorTarget(ext2 ${CMAKE_CURRENT_SOURCE_DIR}/freeldr/bootsect/ext2.asm ${CMAKE_CURRENT_BINARY_DIR}/freeldr/bootsect/ext2.bin)
 +CreateBootSectorTarget(fat32 ${CMAKE_CURRENT_SOURCE_DIR}/freeldr/bootsect/fat32.asm ${CMAKE_CURRENT_BINARY_DIR}/freeldr/bootsect/fat32.bin)
 +CreateBootSectorTarget(fat ${CMAKE_CURRENT_SOURCE_DIR}/freeldr/bootsect/fat.asm ${CMAKE_CURRENT_BINARY_DIR}/freeldr/bootsect/fat.bin)
 +CreateBootSectorTarget(isoboot ${CMAKE_CURRENT_SOURCE_DIR}/freeldr/bootsect/isoboot.asm ${CMAKE_CURRENT_BINARY_DIR}/freeldr/bootsect/isoboot.bin)
 +CreateBootSectorTarget(isobtrt ${CMAKE_CURRENT_SOURCE_DIR}/freeldr/bootsect/isobtrt.asm ${CMAKE_CURRENT_BINARY_DIR}/freeldr/bootsect/isobtrt.bin)
 +
 +include_directories(BEFORE freeldr/freeldr/include)
 +include_directories(${REACTOS_SOURCE_DIR}/ntoskrnl/include)
 +
++if(ARCH MATCHES arm)
++    if(SARCH MATCHES omap-zoom2)
++        add_definitions(-D_ZOOM2_)
++    endif()    
++endif()
++
 +if(ARCH MATCHES i386)
 +if(MSVC)
 +list(APPEND FREELDR_BASE64K_SOURCE
 +    freeldr/freeldr/arch/i386/realmode.S)
 +else()
 +list(APPEND FREELDR_STARTUP_SOURCE
 +    freeldr/freeldr/arch/i386/fathelp.S
 +    freeldr/freeldr/arch/i386/arch.S)
 +endif()
 +elseif(ARCH MATCHES amd64)
 +list(APPEND FREELDR_STARTUP_SOURCE
 +    freeldr/freeldr/arch/i386/fathelp.S
 +    freeldr/freeldr/arch/amd64/arch.S)
 +endif(ARCH MATCHES i386)
 +
 +if(ARCH MATCHES i386)
 +if(NOT MSVC)
 +list(APPEND FREELDR_BASE64K_SOURCE
 +    freeldr/freeldr/arch/i386/boot.S
 +    freeldr/freeldr/arch/i386/drvmap.S
 +    freeldr/freeldr/arch/i386/i386cpu.S
 +    freeldr/freeldr/arch/i386/i386idt.S
 +    freeldr/freeldr/arch/i386/i386pnp.S
 +    freeldr/freeldr/arch/i386/i386trap.S
 +    freeldr/freeldr/arch/i386/int386.S
 +    freeldr/freeldr/arch/i386/linux.S
 +    freeldr/freeldr/arch/i386/mb.S
 +    freeldr/freeldr/arch/i386/i386bug.c)
 +endif()
 +elseif(ARCH MATCHES amd64)
 +list(APPEND FREELDR_BASE64K_SOURCE
 +    freeldr/freeldr/arch/i386/drvmap.S
 +    freeldr/freeldr/arch/i386/i386cpu.S
 +    freeldr/freeldr/arch/i386/i386idt.S
 +    freeldr/freeldr/arch/i386/i386trap.S
 +    freeldr/freeldr/arch/amd64/mb.S)
 +endif(ARCH MATCHES i386)
 +
 +set_source_files_properties(${FREELDR_BASE64K_SOURCE} PROPERTIES COMPILE_DEFINITIONS "_NTHAL_")
 +
 +include_directories(${REACTOS_SOURCE_DIR}/lib/cmlib)
 +
 +list(APPEND FREELDR_BASE_SOURCE
 +    freeldr/freeldr/arcemul/mm.c
 +    freeldr/freeldr/arcemul/time.c
 +    freeldr/freeldr/cache/blocklist.c
 +    freeldr/freeldr/cache/cache.c
 +    freeldr/freeldr/comm/rs232.c
 +    freeldr/freeldr/disk/disk.c
 +    freeldr/freeldr/disk/partition.c
 +    freeldr/freeldr/disk/ramdisk.c
 +    freeldr/freeldr/disk/scsiport.c
 +    freeldr/freeldr/fs/ext2.c
 +    freeldr/freeldr/fs/fat.c
 +    freeldr/freeldr/fs/fs.c
 +    freeldr/freeldr/fs/iso.c
 +    freeldr/freeldr/fs/ntfs.c
 +    freeldr/freeldr/inifile/ini_init.c
 +    freeldr/freeldr/inifile/inifile.c
 +    freeldr/freeldr/inifile/parse.c
 +    freeldr/freeldr/mm/meminit.c
 +    freeldr/freeldr/mm/mm.c
 +    freeldr/freeldr/reactos/registry.c
 +    freeldr/freeldr/reactos/arcname.c
 +    freeldr/freeldr/reactos/archwsup.c
 +    freeldr/freeldr/reactos/binhive.c
 +    freeldr/freeldr/reactos/reactos.c
 +    freeldr/freeldr/reactos/imageldr.c
 +    freeldr/freeldr/rtl/bget.c
 +    freeldr/freeldr/rtl/libsupp.c
 +    freeldr/freeldr/ui/directui.c
 +    freeldr/freeldr/ui/gui.c
 +    freeldr/freeldr/ui/minitui.c
 +    freeldr/freeldr/ui/noui.c
 +    freeldr/freeldr/ui/tui.c
 +    freeldr/freeldr/ui/tuimenu.c
 +    freeldr/freeldr/ui/ui.c
 +    freeldr/freeldr/video/fade.c
 +    freeldr/freeldr/video/palette.c
 +    freeldr/freeldr/video/video.c
 +    freeldr/freeldr/windows/conversion.c
- list(APPEND FREELDR_BASE_SOURCE freeldr/freeldr/disk/scsiport.c)
 +    freeldr/freeldr/windows/peloader.c
 +    freeldr/freeldr/windows/winldr.c
 +    freeldr/freeldr/windows/wlmemory.c
 +    freeldr/freeldr/windows/wlregistry.c
 +    freeldr/freeldr/freeldr.c
 +    freeldr/freeldr/debug.c
 +    freeldr/freeldr/version.c
 +    freeldr/freeldr/cmdline.c
 +    freeldr/freeldr/machine.c
 +    freeldr/freeldr/options.c
 +    freeldr/freeldr/linuxboot.c
 +    freeldr/freeldr/oslist.c)
 +
 +if(ARCH MATCHES i386)
++list(APPEND FREELDR_BASE_SOURCE
++    freeldr/freeldr/windows/headless.c
++    freeldr/freeldr/disk/scsiport.c)
 +endif(ARCH MATCHES i386)
 +
 +set_source_files_properties(${FREELDR_BASE_SOURCE} PROPERTIES COMPILE_DEFINITIONS "_NTHAL_;_BLDR_;_NTSYSTEM_")
 +
 +include_directories(${REACTOS_SOURCE_DIR}/include/reactos/libs)
 +include_directories(${REACTOS_SOURCE_DIR}/include/reactos/elf)
 +
 +if(ARCH MATCHES i386)
 +list(APPEND FREELDR_ARCH_SOURCE
 +    freeldr/freeldr/arch/i386/archmach.c
 +    freeldr/freeldr/arch/i386/custom.c
 +    freeldr/freeldr/arch/i386/drivemap.c
 +    freeldr/freeldr/arch/i386/halstub.c
 +    freeldr/freeldr/arch/i386/hardware.c
 +    freeldr/freeldr/arch/i386/hwacpi.c
 +    freeldr/freeldr/arch/i386/hwapm.c
 +    freeldr/freeldr/arch/i386/hwpci.c
 +    freeldr/freeldr/arch/i386/i386disk.c
 +    freeldr/freeldr/arch/i386/i386rtl.c
 +    freeldr/freeldr/arch/i386/i386vid.c
 +    freeldr/freeldr/arch/i386/loader.c
 +    freeldr/freeldr/arch/i386/machpc.c
 +    freeldr/freeldr/arch/i386/miscboot.c
 +    freeldr/freeldr/arch/i386/ntoskrnl.c
 +    freeldr/freeldr/arch/i386/pccons.c
 +    freeldr/freeldr/arch/i386/pcdisk.c
 +    freeldr/freeldr/arch/i386/pcmem.c
 +    freeldr/freeldr/arch/i386/pcrtc.c
 +    freeldr/freeldr/arch/i386/pcvideo.c
 +    freeldr/freeldr/arch/i386/machxbox.c
 +    freeldr/freeldr/arch/i386/xboxcons.c
 +    freeldr/freeldr/arch/i386/xboxdisk.c
 +    freeldr/freeldr/arch/i386/xboxfont.c
 +    freeldr/freeldr/arch/i386/xboxhw.c
 +    freeldr/freeldr/arch/i386/xboxi2c.c
 +    freeldr/freeldr/arch/i386/xboxmem.c
 +    freeldr/freeldr/arch/i386/xboxrtc.c
 +    freeldr/freeldr/arch/i386/xboxvideo.c
 +    freeldr/freeldr/windows/i386/ntsetup.c
 +    freeldr/freeldr/windows/i386/wlmemory.c)
 +else()
 +#TBD
 +endif(ARCH MATCHES i386)
 +
 +set_source_files_properties(${FREELDR_ARCH_SOURCE} PROPERTIES COMPILE_DEFINITIONS "_NTHAL_;_BLDR_;_NTSYSTEM_")
 +
 +list(APPEND SETUPLDR_MAIN_SOURCE
 +    freeldr/freeldr/bootmgr.c
 +    freeldr/freeldr/inffile/inffile.c
 +    freeldr/freeldr/reactos/setupldr.c)
 +
 +if(ARCH MATCHES i386)
 +list(APPEND SETUPLDR_MAIN_SOURCE freeldr/freeldr/windows/setupldr2.c)
 +elseif(ARCH MATCHES amd64)
 +list(APPEND SETUPLDR_MAIN_SOURCE freeldr/freeldr/windows/setupldr2.c)
 +endif(ARCH MATCHES i386)
 +
 +set_source_files_properties(${SETUPLDR_MAIN_SOURCE} PROPERTIES COMPILE_FLAGS "-ffreestanding -fno-builtin -fno-inline -fno-zero-initialized-in-bss")
 +
 +
 +
 +list(APPEND FREELDR_SOURCE
 +    freeldr/freeldr/bootmgr.c
 +    ${FREELDR_STARTUP_SOURCE}
 +    ${FREELDR_BASE64K_SOURCE}
 +    ${FREELDR_BASE_SOURCE}
 +    ${FREELDR_ARCH_SOURCE})
 +
 +add_library(freeldr SHARED
 +    ${CMAKE_CURRENT_BINARY_DIR}/freeldr_freeldr.h.gch
 +    ${FREELDR_SOURCE})
 +
 +if(NOT MSVC)
 +set_target_properties(freeldr PROPERTIES LINK_FLAGS "-Wl,--strip-all -Wl,--exclude-all-symbols -Wl,--file-alignment,0x1000 -Wl,-T,${CMAKE_CURRENT_SOURCE_DIR}/freeldr/freeldr/freeldr_i386.lnk" SUFFIX ".sys")
 +set_image_base(freeldr 0x8000)
 +else()
 +set_target_properties(freeldr PROPERTIES LINK_FLAGS "/DRIVER /FIXED /ALIGN:0x400 /SECTION:.text,ERW /SECTION:.data,RW /MERGE:.text16=.text /MERGE:.data=.text /MERGE:.rdata=.text /MERGE:.bss=.text /SUBSYSTEM:BOOT_APPLICATION" SUFFIX ".sys")
 +set_image_base(freeldr 0x10000)
 +endif()
 +
 +set_subsystem(freeldr native)
 +set_entrypoint(freeldr mainCRTStartup)
 +
 +if(ARCH MATCHES i386)
 +target_link_libraries(freeldr mini_hal)
 +endif(ARCH MATCHES i386)
 +
 +target_link_libraries(freeldr
 +    cportlib
 +    rossym
 +    cmlib
 +    rtl
 +    libcntpr)
 +add_pch(freeldr ${CMAKE_CURRENT_SOURCE_DIR}/freeldr/freeldr/include/freeldr.h ${FREELDR_SOURCE})
 +add_dependencies(freeldr asm)
 +
 +list(APPEND SETUPLDR_SOURCE
 +    ${FREELDR_STARTUP_SOURCE}
 +    ${FREELDR_BASE64K_SOURCE}
 +    ${FREELDR_BASE_SOURCE}
 +    ${FREELDR_ARCH_SOURCE}
 +    ${SETUPLDR_MAIN_SOURCE})
 +
 +add_library(setupldr SHARED ${SETUPLDR_SOURCE})
 +
 +if(NOT MSVC)
 +set_target_properties(setupldr PROPERTIES LINK_FLAGS "-Wl,--strip-all -Wl,--exclude-all-symbols -Wl,--file-alignment,0x1000 -Wl,-T,${CMAKE_CURRENT_SOURCE_DIR}/freeldr/freeldr/freeldr_i386.lnk" SUFFIX ".sys" COMPILE_DEFINITIONS "FREELDR_REACTOS_SETUP")
 +set_image_base(setupldr 0x8000)
 +else()
 +set_target_properties(setupldr PROPERTIES LINK_FLAGS "/SECTION:.text,ERWP,ALIGN=0x1000" SUFFIX ".sys" COMPILE_DEFINITIONS "FREELDR_REACTOS_SETUP")
 +endif()
 +
 +set_subsystem(setupldr native)
 +set_entrypoint(setupldr mainCRTStartup)
 +
 +if(ARCH MATCHES i386)
 +target_link_libraries(setupldr mini_hal)
 +endif(ARCH MATCHES i386)
 +
 +target_link_libraries(setupldr
 +    cportlib
 +    rossym
 +    cmlib
 +    rtl
 +    libcntpr)
 +
 +add_dependencies(setupldr asm)
 +
 +# Bootcd files
 +add_minicd_target(setupldr loader setupldr.sys)
 +add_minicd_target(freeldr loader freeldr.sys)
 +add_minicd(${CMAKE_CURRENT_SOURCE_DIR}/bootdata/txtsetup.sif reactos txtsetup.sif)
 +add_minicd(${CMAKE_CURRENT_SOURCE_DIR}/bootdata/bootcd.ini "" freeldr.ini)
 +add_minicd(${CMAKE_CURRENT_SOURCE_DIR}/bootdata/hivecls_${ARCH}.inf reactos hivecls.inf)
 +add_minicd(${CMAKE_CURRENT_SOURCE_DIR}/bootdata/hivedef_${ARCH}.inf reactos hivedef.inf)
 +add_minicd(${CMAKE_CURRENT_SOURCE_DIR}/bootdata/hivesft_${ARCH}.inf reactos hivesft.inf)
 +add_minicd(${CMAKE_CURRENT_SOURCE_DIR}/bootdata/hivesys_${ARCH}.inf reactos hivesys.inf)
 +add_minicd(${CMAKE_CURRENT_SOURCE_DIR}/bootdata/autorun.inf "" autorun.inf)
 +add_minicd(${CMAKE_CURRENT_SOURCE_DIR}/bootdata/icon.ico "" icon.ico)
 +add_minicd(${CMAKE_CURRENT_SOURCE_DIR}/bootdata/readme.txt "" readme.txt)
 +# Livecd files
 +list(APPEND LIVECD_HIVES
 +    ${CMAKE_CURRENT_SOURCE_DIR}/bootdata/livecd.inf
 +    ${CMAKE_CURRENT_SOURCE_DIR}/bootdata/hiveinst_${ARCH}.inf)
 +
 +add_custom_command(
 +    OUTPUT ${LIVECD_DIR}/reactos/system32/config/sam
 +    COMMAND native-mkhive ${CMAKE_CURRENT_SOURCE_DIR}/bootdata ${LIVECD_DIR}/reactos/system32/config ${ARCH} ${LIVECD_HIVES}
 +    DEPENDS native-mkhive)
 +
 +add_custom_target(livecd_hives DEPENDS ${LIVECD_DIR}/reactos/system32/config/sam)
 +
 +add_livecd_target(setupldr loader)
 +add_livecd(${REACTOS_SOURCE_DIR}/boot/bootdata/livecd.ini "" freeldr.ini)
Simple merge
Simple merge
Simple merge
Simple merge
index 0000000,c1275c2..c1275c2
mode 000000,100755..100755
--- /dev/null
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 0000000,f557fff..f557fff
mode 000000,100755..100755
--- /dev/null
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 29c4eab,0000000..251c188
mode 100644,000000..100644
--- /dev/null
@@@ -1,704 -1,0 +1,706 @@@
 +/*
 + *  FreeLoader
 + *
 + *  Copyright (C) 1998-2003  Brian Palmer    <brianp@sginet.com>
 + *  Copyright (C) 2006       Aleksey Bragin  <aleksey@reactos.org>
 + *
 + *  This program is free software; you can redistribute it and/or modify
 + *  it under the terms of the GNU General Public License as published by
 + *  the Free Software Foundation; either version 2 of the License, or
 + *  (at your option) any later version.
 + *
 + *  This program 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 General Public License for more details.
 + *
 + *  You should have received a copy of the GNU General Public License along
 + *  with this program; if not, write to the Free Software Foundation, Inc.,
 + *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 + */
 +
 +#include <freeldr.h>
 +
 +#include <ndk/ldrtypes.h>
 +#include <debug.h>
 +
 +// TODO: Move to .h
 +void WinLdrSetupForNt(PLOADER_PARAMETER_BLOCK LoaderBlock,
 +                      PVOID *GdtIdt,
 +                      ULONG *PcrBasePage,
 +                      ULONG *TssBasePage);
 +
 +//FIXME: Do a better way to retrieve Arc disk information
 +extern ULONG reactos_disk_count;
 +extern ARC_DISK_SIGNATURE reactos_arc_disk_info[];
 +extern char reactos_arc_strings[32][256];
 +
 +extern BOOLEAN UseRealHeap;
 +extern ULONG LoaderPagesSpanned;
 +extern BOOLEAN AcpiPresent;
 +
 +extern HEADLESS_LOADER_BLOCK LoaderRedirectionInformation;
 +extern BOOLEAN WinLdrTerminalConnected;
 +
 +extern void WinLdrSetupEms(IN PCHAR BootOptions);
 +
 +BOOLEAN
 +WinLdrCheckForLoadedDll(IN OUT PLOADER_PARAMETER_BLOCK WinLdrBlock,
 +                        IN PCH DllName,
 +                        OUT PLDR_DATA_TABLE_ENTRY *LoadedEntry);
 +
 +// debug stuff
 +VOID DumpMemoryAllocMap(VOID);
 +VOID WinLdrpDumpMemoryDescriptors(PLOADER_PARAMETER_BLOCK LoaderBlock);
 +VOID WinLdrpDumpBootDriver(PLOADER_PARAMETER_BLOCK LoaderBlock);
 +VOID WinLdrpDumpArcDisks(PLOADER_PARAMETER_BLOCK LoaderBlock);
 +
 +
 +// Init "phase 0"
 +VOID
 +AllocateAndInitLPB(PLOADER_PARAMETER_BLOCK *OutLoaderBlock)
 +{
 +      PLOADER_PARAMETER_BLOCK LoaderBlock;
 +
 +      /* Allocate and zero-init the LPB */
 +      LoaderBlock = MmHeapAlloc(sizeof(LOADER_PARAMETER_BLOCK));
 +      RtlZeroMemory(LoaderBlock, sizeof(LOADER_PARAMETER_BLOCK));
 +
 +      /* Init three critical lists, used right away */
 +      InitializeListHead(&LoaderBlock->LoadOrderListHead);
 +      InitializeListHead(&LoaderBlock->MemoryDescriptorListHead);
 +      InitializeListHead(&LoaderBlock->BootDriverListHead);
 +
 +      /* Alloc space for NLS (it will be converted to VA in WinLdrLoadNLS) */
 +      LoaderBlock->NlsData = MmHeapAlloc(sizeof(NLS_DATA_BLOCK));
 +      if (LoaderBlock->NlsData == NULL)
 +      {
 +              UiMessageBox("Failed to allocate memory for NLS table data!");
 +              return;
 +      }
 +      RtlZeroMemory(LoaderBlock->NlsData, sizeof(NLS_DATA_BLOCK));
 +
 +      *OutLoaderBlock = LoaderBlock;
 +}
 +
 +// Init "phase 1"
 +VOID
 +WinLdrInitializePhase1(PLOADER_PARAMETER_BLOCK LoaderBlock,
 +                       PCHAR Options,
 +                       PCHAR SystemRoot,
 +                       PCHAR BootPath,
 +                       USHORT VersionToBoot)
 +{
 +      /* Examples of correct options and paths */
 +      //CHAR  Options[] = "/DEBUGPORT=COM1 /BAUDRATE=115200";
 +      //CHAR  Options[] = "/NODEBUG";
 +      //CHAR  SystemRoot[] = "\\WINNT\\";
 +      //CHAR  ArcBoot[] = "multi(0)disk(0)rdisk(0)partition(1)";
 +
 +      CHAR    HalPath[] = "\\";
 +      CHAR    ArcBoot[256];
 +      CHAR    MiscFiles[256];
 +      ULONG i, PathSeparator;
 +      PLOADER_PARAMETER_EXTENSION Extension;
 +
 +      /* Construct SystemRoot and ArcBoot from SystemPath */
 +      PathSeparator = strstr(BootPath, "\\") - BootPath;
 +      strncpy(ArcBoot, BootPath, PathSeparator);
 +      ArcBoot[PathSeparator] = 0;
 +
 +      DPRINTM(DPRINT_WINDOWS, "ArcBoot: %s\n", ArcBoot);
 +      DPRINTM(DPRINT_WINDOWS, "SystemRoot: %s\n", SystemRoot);
 +      DPRINTM(DPRINT_WINDOWS, "Options: %s\n", Options);
 +
 +      /* Fill Arc BootDevice */
 +      LoaderBlock->ArcBootDeviceName = MmHeapAlloc(strlen(ArcBoot)+1);
 +      strcpy(LoaderBlock->ArcBootDeviceName, ArcBoot);
 +      LoaderBlock->ArcBootDeviceName = PaToVa(LoaderBlock->ArcBootDeviceName);
 +
 +      /* Fill Arc HalDevice, it matches ArcBoot path */
 +      LoaderBlock->ArcHalDeviceName = MmHeapAlloc(strlen(ArcBoot)+1);
 +      strcpy(LoaderBlock->ArcHalDeviceName, ArcBoot);
 +      LoaderBlock->ArcHalDeviceName = PaToVa(LoaderBlock->ArcHalDeviceName);
 +
 +      /* Fill SystemRoot */
 +      LoaderBlock->NtBootPathName = MmHeapAlloc(strlen(SystemRoot)+1);
 +      strcpy(LoaderBlock->NtBootPathName, SystemRoot);
 +      LoaderBlock->NtBootPathName = PaToVa(LoaderBlock->NtBootPathName);
 +
 +      /* Fill NtHalPathName */
 +      LoaderBlock->NtHalPathName = MmHeapAlloc(strlen(HalPath)+1);
 +      strcpy(LoaderBlock->NtHalPathName, HalPath);
 +      LoaderBlock->NtHalPathName = PaToVa(LoaderBlock->NtHalPathName);
 +
 +      /* Fill load options */
 +      LoaderBlock->LoadOptions = MmHeapAlloc(strlen(Options)+1);
 +      strcpy(LoaderBlock->LoadOptions, Options);
 +      LoaderBlock->LoadOptions = PaToVa(LoaderBlock->LoadOptions);
 +
 +      /* Arc devices */
 +      LoaderBlock->ArcDiskInformation = (PARC_DISK_INFORMATION)MmHeapAlloc(sizeof(ARC_DISK_INFORMATION));
 +      InitializeListHead(&LoaderBlock->ArcDiskInformation->DiskSignatureListHead);
 +
 +      /* Convert ARC disk information from freeldr to a correct format */
 +      for (i = 0; i < reactos_disk_count; i++)
 +      {
 +              PARC_DISK_SIGNATURE ArcDiskInfo;
 +
 +              /* Get the ARC structure */
 +              ArcDiskInfo = (PARC_DISK_SIGNATURE)MmHeapAlloc(sizeof(ARC_DISK_SIGNATURE));
 +              RtlZeroMemory(ArcDiskInfo, sizeof(ARC_DISK_SIGNATURE));
 +
 +              /* Copy the data over */
 +              ArcDiskInfo->Signature = reactos_arc_disk_info[i].Signature;
 +              ArcDiskInfo->CheckSum = reactos_arc_disk_info[i].CheckSum;
 +
 +              /* Copy the ARC Name */
 +              ArcDiskInfo->ArcName = (PCHAR)MmHeapAlloc(sizeof(CHAR)*256);
 +              strcpy(ArcDiskInfo->ArcName, reactos_arc_disk_info[i].ArcName);
 +              ArcDiskInfo->ArcName = (PCHAR)PaToVa(ArcDiskInfo->ArcName);
 +
 +              /* Mark partition table as valid */
 +              ArcDiskInfo->ValidPartitionTable = TRUE; 
 +
 +              /* Insert into the list */
 +              InsertTailList(&LoaderBlock->ArcDiskInformation->DiskSignatureListHead,
 +                      &ArcDiskInfo->ListEntry);
 +      }
 +
 +      /* Convert all list's to Virtual address */
 +
 +      /* Convert the ArcDisks list to virtual address */
 +      List_PaToVa(&LoaderBlock->ArcDiskInformation->DiskSignatureListHead);
 +      LoaderBlock->ArcDiskInformation = PaToVa(LoaderBlock->ArcDiskInformation);
 +
 +      /* Convert configuration entries to VA */
 +      ConvertConfigToVA(LoaderBlock->ConfigurationRoot);
 +      LoaderBlock->ConfigurationRoot = PaToVa(LoaderBlock->ConfigurationRoot);
 +
 +      /* Convert all DTE into virtual addresses */
 +      List_PaToVa(&LoaderBlock->LoadOrderListHead);
 +
 +      /* this one will be converted right before switching to
 +         virtual paging mode */
 +      //List_PaToVa(&LoaderBlock->MemoryDescriptorListHead);
 +
 +      /* Convert list of boot drivers */
 +      List_PaToVa(&LoaderBlock->BootDriverListHead);
 +
 +      /* Initialize Extension now */
 +      Extension = MmHeapAlloc(sizeof(LOADER_PARAMETER_EXTENSION));
 +      if (Extension == NULL)
 +      {
 +              UiMessageBox("Failed to allocate LPB Extension!");
 +              return;
 +      }
 +      RtlZeroMemory(Extension, sizeof(LOADER_PARAMETER_EXTENSION));
 +
 +      /* Fill LPB extension */
 +      Extension->Size = sizeof(LOADER_PARAMETER_EXTENSION);
 +      Extension->MajorVersion = (VersionToBoot & 0xFF00) >> 8;
 +      Extension->MinorVersion = VersionToBoot & 0xFF;
 +      Extension->Profile.Status = 2;
 +
 +      /* Check if ACPI is present */
 +      if (AcpiPresent)
 +      {
 +              /* See KiRosFrldrLpbToNtLpb for details */
 +              Extension->AcpiTable = (PVOID)1;
 +      }
 +    
++#ifndef _M_ARM
 +    /* Set headless block pointer */
 +    if (WinLdrTerminalConnected)
 +    {
 +        Extension->HeadlessLoaderBlock = MmHeapAlloc(sizeof(HEADLESS_LOADER_BLOCK));
 +        if (Extension->HeadlessLoaderBlock == NULL)
 +        {
 +            UiMessageBox("Failed to allocate HLB Extension!");
 +            while (TRUE);
 +            return;
 +        }
 +        RtlCopyMemory(
 +            Extension->HeadlessLoaderBlock,
 +            &LoaderRedirectionInformation,
 +            sizeof(HEADLESS_LOADER_BLOCK));
 +        Extension->HeadlessLoaderBlock = PaToVa(Extension->HeadlessLoaderBlock);
 +    }
++#endif
 +      /* Load drivers database */
 +      strcpy(MiscFiles, BootPath);
 +      strcat(MiscFiles, "AppPatch\\drvmain.sdb");
 +      Extension->DrvDBImage = PaToVa(WinLdrLoadModule(MiscFiles,
 +              &Extension->DrvDBSize, LoaderRegistryData));
 +
 +      /* Convert extension and setup block pointers */
 +      LoaderBlock->Extension = PaToVa(Extension);
 +
 +      if (LoaderBlock->SetupLdrBlock)
 +              LoaderBlock->SetupLdrBlock = PaToVa(LoaderBlock->SetupLdrBlock);
 +
 +}
 +
 +BOOLEAN
 +WinLdrLoadDeviceDriver(PLOADER_PARAMETER_BLOCK LoaderBlock,
 +                       LPSTR BootPath,
 +                       PUNICODE_STRING FilePath,
 +                       ULONG Flags,
 +                       PLDR_DATA_TABLE_ENTRY *DriverDTE)
 +{
 +      CHAR FullPath[1024];
 +      CHAR DriverPath[1024];
 +      CHAR DllName[1024];
 +      PCHAR DriverNamePos;
 +      BOOLEAN Status;
 +      PVOID DriverBase;
 +
 +      // Separate the path to file name and directory path
 +      _snprintf(DriverPath, sizeof(DriverPath), "%wZ", FilePath);
 +      DriverNamePos = strrchr(DriverPath, '\\');
 +      if (DriverNamePos != NULL)
 +      {
 +              // Copy the name
 +              strcpy(DllName, DriverNamePos+1);
 +
 +              // Cut out the name from the path
 +              *(DriverNamePos+1) = 0;
 +      }
 +      else
 +      {
 +              // There is no directory in the path
 +              strcpy(DllName, DriverPath);
 +              DriverPath[0] = 0;
 +      }
 +
 +      DPRINTM(DPRINT_WINDOWS, "DriverPath: %s, DllName: %s, LPB %p\n", DriverPath, DllName, LoaderBlock);
 +
 +
 +      // Check if driver is already loaded
 +      Status = WinLdrCheckForLoadedDll(LoaderBlock, DllName, DriverDTE);
 +      if (Status)
 +      {
 +              // We've got the pointer to its DTE, just return success
 +              return TRUE;
 +      }
 +
 +      // It's not loaded, we have to load it
 +      _snprintf(FullPath, sizeof(FullPath), "%s%wZ", BootPath, FilePath);
 +      Status = WinLdrLoadImage(FullPath, LoaderBootDriver, &DriverBase);
 +      if (!Status)
 +              return FALSE;
 +
 +      // Allocate a DTE for it
 +      Status = WinLdrAllocateDataTableEntry(LoaderBlock, DllName, DllName, DriverBase, DriverDTE);
 +      if (!Status)
 +      {
 +              DPRINTM(DPRINT_WINDOWS, "WinLdrAllocateDataTableEntry() failed\n");
 +              return FALSE;
 +      }
 +
 +      // Modify any flags, if needed
 +      (*DriverDTE)->Flags |= Flags;
 +
 +      // Look for any dependencies it may have, and load them too
 +      sprintf(FullPath,"%s%s", BootPath, DriverPath);
 +      Status = WinLdrScanImportDescriptorTable(LoaderBlock, FullPath, *DriverDTE);
 +      if (!Status)
 +      {
 +              DPRINTM(DPRINT_WINDOWS, "WinLdrScanImportDescriptorTable() failed for %s\n",
 +                      FullPath);
 +              return FALSE;
 +      }
 +
 +      return TRUE;
 +}
 +
 +BOOLEAN
 +WinLdrLoadBootDrivers(PLOADER_PARAMETER_BLOCK LoaderBlock,
 +                      LPSTR BootPath)
 +{
 +      PLIST_ENTRY NextBd;
 +      PBOOT_DRIVER_LIST_ENTRY BootDriver;
 +      BOOLEAN Status;
 +
 +      // Walk through the boot drivers list
 +      NextBd = LoaderBlock->BootDriverListHead.Flink;
 +
 +      while (NextBd != &LoaderBlock->BootDriverListHead)
 +      {
 +              BootDriver = CONTAINING_RECORD(NextBd, BOOT_DRIVER_LIST_ENTRY, Link);
 +
 +              DPRINTM(DPRINT_WINDOWS, "BootDriver %wZ DTE %08X RegPath: %wZ\n", &BootDriver->FilePath,
 +                      BootDriver->LdrEntry, &BootDriver->RegistryPath);
 +
 +              // Paths are relative (FIXME: Are they always relative?)
 +
 +              // Load it
 +              Status = WinLdrLoadDeviceDriver(LoaderBlock, BootPath, &BootDriver->FilePath,
 +                      0, &BootDriver->LdrEntry);
 +
 +              // If loading failed - cry loudly
 +              //FIXME: Maybe remove it from the list and try to continue?
 +              if (!Status)
 +              {
 +                      UiMessageBox("Can't load boot driver!");
 +                      return FALSE;
 +              }
 +
 +              // Convert the RegistryPath and DTE addresses to VA since we are not going to use it anymore
 +              BootDriver->RegistryPath.Buffer = PaToVa(BootDriver->RegistryPath.Buffer);
 +              BootDriver->FilePath.Buffer = PaToVa(BootDriver->FilePath.Buffer);
 +              BootDriver->LdrEntry = PaToVa(BootDriver->LdrEntry);
 +
 +              NextBd = BootDriver->Link.Flink;
 +      }
 +
 +      return TRUE;
 +}
 +
 +PVOID WinLdrLoadModule(PCSTR ModuleName, ULONG *Size,
 +                                         TYPE_OF_MEMORY MemoryType)
 +{
 +      ULONG FileId;
 +      PVOID PhysicalBase;
 +      FILEINFORMATION FileInfo;
 +      ULONG FileSize;
 +      ULONG Status;
 +      ULONG BytesRead;
 +
 +      //CHAR ProgressString[256];
 +
 +      /* Inform user we are loading files */
 +      //sprintf(ProgressString, "Loading %s...", FileName);
 +      //UiDrawProgressBarCenter(1, 100, ProgressString);
 +
 +      DPRINTM(DPRINT_WINDOWS, "Loading module %s\n", ModuleName);
 +      *Size = 0;
 +
 +      /* Open the image file */
 +      Status = ArcOpen((PCHAR)ModuleName, OpenReadOnly, &FileId);
 +      if (Status != ESUCCESS)
 +      {
 +              /* In case of errors, we just return, without complaining to the user */
 +              return NULL;
 +      }
 +
 +      /* Get this file's size */
 +      Status = ArcGetFileInformation(FileId, &FileInfo);
 +      if (Status != ESUCCESS)
 +      {
 +              ArcClose(FileId);
 +              return NULL;
 +      }
 +      FileSize = FileInfo.EndingAddress.LowPart;
 +      *Size = FileSize;
 +
 +      /* Allocate memory */
 +      PhysicalBase = MmAllocateMemoryWithType(FileSize, MemoryType);
 +      if (PhysicalBase == NULL)
 +      {
 +              ArcClose(FileId);
 +              return NULL;
 +      }
 +
 +      /* Load whole file */
 +      Status = ArcRead(FileId, PhysicalBase, FileSize, &BytesRead);
 +      ArcClose(FileId);
 +      if (Status != ESUCCESS)
 +      {
 +              return NULL;
 +      }
 +
 +      DPRINTM(DPRINT_WINDOWS, "Loaded %s at 0x%x with size 0x%x\n", ModuleName, PhysicalBase, FileSize);
 +
 +      return PhysicalBase;
 +}
 +
 +
 +USHORT
 +WinLdrDetectVersion()
 +{
 +      LONG rc;
 +      FRLDRHKEY hKey;
 +
 +      rc = RegOpenKey(
 +              NULL,
 +              L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\Terminal Server",
 +              &hKey);
 +      if (rc != ERROR_SUCCESS)
 +      {
 +              // Key doesn't exist; assume NT 4.0
 +              return _WIN32_WINNT_NT4;
 +      }
 +
 +      // We may here want to read the value of ProductVersion
 +      return _WIN32_WINNT_WS03;
 +}
 +
 +
 +VOID
 +LoadAndBootWindows(PCSTR OperatingSystemName,
 +                   PSTR SettingsValue,
 +                   USHORT OperatingSystemVersion)
 +{
 +      BOOLEAN HasSection;
 +      char  FullPath[MAX_PATH], SystemRoot[MAX_PATH], BootPath[MAX_PATH];
 +      CHAR  FileName[MAX_PATH];
 +      CHAR  BootOptions[256];
 +      PCHAR File;
 +      PCHAR PathSeparator;
 +      PVOID NtosBase = NULL, HalBase = NULL, KdComBase = NULL;
 +      BOOLEAN Status;
 +      ULONG_PTR SectionId;
 +      PLOADER_PARAMETER_BLOCK LoaderBlock, LoaderBlockVA;
 +      KERNEL_ENTRY_POINT KiSystemStartup;
 +      PLDR_DATA_TABLE_ENTRY KernelDTE, HalDTE, KdComDTE = NULL;
 +      // Mm-related things
 +      PVOID GdtIdt;
 +      ULONG PcrBasePage=0;
 +      ULONG TssBasePage=0;
 +
 +      // Open the operating system section
 +      // specified in the .ini file
 +      HasSection = IniOpenSection(OperatingSystemName, &SectionId);
 +
 +      UiDrawBackdrop();
 +      UiDrawStatusText("Detecting Hardware...");
 +      UiDrawProgressBarCenter(1, 100, "Loading NT...");
 +
 +      /* Read the system path is set in the .ini file */
 +      if (!HasSection || !IniReadSettingByName(SectionId, "SystemPath", FullPath, sizeof(FullPath)))
 +      {
 +              strcpy(FullPath, OperatingSystemName);
 +      }
 +
 +      /* Special case for LiveCD */
 +      if (!_strnicmp(FullPath, "LiveCD", strlen("LiveCD")))
 +      {
 +              strcpy(BootPath, FullPath + strlen("LiveCD"));
 +              MachDiskGetBootPath(FullPath, sizeof(FullPath));
 +              strcat(FullPath, BootPath);
 +      }
 +
 +      /* Convert FullPath to SystemRoot */
 +      PathSeparator = strstr(FullPath, "\\");
 +      strcpy(SystemRoot, PathSeparator);
 +      strcat(SystemRoot, "\\");
 +
 +      /* Read booting options */
 +      if (!HasSection || !IniReadSettingByName(SectionId, "Options", BootOptions, sizeof(BootOptions)))
 +      {
 +              /* Get options after the title */
 +              const CHAR*p = SettingsValue;
 +              while (*p == ' ' || *p == '"')
 +                      p++;
 +              while (*p != '\0' && *p != '"')
 +                      p++;
 +              strcpy(BootOptions, p);
 +              DPRINTM(DPRINT_WINDOWS,"BootOptions: '%s'\n", BootOptions);
 +      }
 +
 +      /* Append boot-time options */
 +      AppendBootTimeOptions(BootOptions);
 +
 +      //
 +      // Check if a ramdisk file was given
 +      //
 +      File = strstr(BootOptions, "/RDPATH=");
 +      if (File)
 +      {
 +              //
 +              // Copy the file name and everything else after it
 +              //
 +              strcpy(FileName, File + 8);
 +
 +              //
 +              // Null-terminate
 +              //
 +              *strstr(FileName, " ") = ANSI_NULL;
 +
 +              //
 +              // Load the ramdisk
 +              //
 +              RamDiskLoadVirtualFile(FileName);
 +      }
 +
 +      /* Let user know we started loading */
 +      UiDrawStatusText("Loading...");
 +
 +      /* append a backslash */
 +      strcpy(BootPath, FullPath);
 +      if ((strlen(BootPath)==0) ||
 +          BootPath[strlen(BootPath)] != '\\')
 +              strcat(BootPath, "\\");
 +
 +      DPRINTM(DPRINT_WINDOWS,"BootPath: '%s'\n", BootPath);
 +
 +      /* Allocate and minimalistic-initialize LPB */
 +      AllocateAndInitLPB(&LoaderBlock);
 +    
++#ifndef _M_ARM
 +      /* Setup redirection support */
 +      WinLdrSetupEms(BootOptions);
++#endif
 +      /* Detect hardware */
 +      UseRealHeap = TRUE;
 +      LoaderBlock->ConfigurationRoot = MachHwDetect();
 +
 +      /* Load Hive */
 +      Status = WinLdrInitSystemHive(LoaderBlock, BootPath);
 +      DPRINTM(DPRINT_WINDOWS, "SYSTEM hive loaded with status %d\n", Status);
 +
 +      if (OperatingSystemVersion == 0)
 +              OperatingSystemVersion = WinLdrDetectVersion();
 +
 +      /* Load kernel */
 +      strcpy(FileName, BootPath);
 +      strcat(FileName, "SYSTEM32\\NTOSKRNL.EXE");
 +      Status = WinLdrLoadImage(FileName, LoaderSystemCode, &NtosBase);
 +      DPRINTM(DPRINT_WINDOWS, "Ntos loaded with status %d at %p\n", Status, NtosBase);
 +
 +      /* Load HAL */
 +      strcpy(FileName, BootPath);
 +      strcat(FileName, "SYSTEM32\\HAL.DLL");
 +      Status = WinLdrLoadImage(FileName, LoaderHalCode, &HalBase);
 +      DPRINTM(DPRINT_WINDOWS, "HAL loaded with status %d at %p\n", Status, HalBase);
 +
 +      /* Load kernel-debugger support dll */
 +      if (OperatingSystemVersion > _WIN32_WINNT_WIN2K)
 +      {
 +              strcpy(FileName, BootPath);
 +              strcat(FileName, "SYSTEM32\\KDCOM.DLL");
 +              Status = WinLdrLoadImage(FileName, LoaderBootDriver, &KdComBase);
 +              DPRINTM(DPRINT_WINDOWS, "KdCom loaded with status %d at %p\n", Status, KdComBase);
 +      }
 +
 +      /* Allocate data table entries for above-loaded modules */
 +      WinLdrAllocateDataTableEntry(LoaderBlock, "ntoskrnl.exe",
 +              "WINDOWS\\SYSTEM32\\NTOSKRNL.EXE", NtosBase, &KernelDTE);
 +      WinLdrAllocateDataTableEntry(LoaderBlock, "hal.dll",
 +              "WINDOWS\\SYSTEM32\\HAL.DLL", HalBase, &HalDTE);
 +      if (OperatingSystemVersion > _WIN32_WINNT_WIN2K)
 +      {
 +              WinLdrAllocateDataTableEntry(LoaderBlock, "kdcom.dll",
 +                      "WINDOWS\\SYSTEM32\\KDCOM.DLL", KdComBase, &KdComDTE);
 +      }
 +
 +      /* Load all referenced DLLs for kernel, HAL and kdcom.dll */
 +      strcpy(FileName, BootPath);
 +      strcat(FileName, "SYSTEM32\\");
 +      WinLdrScanImportDescriptorTable(LoaderBlock, FileName, KernelDTE);
 +      WinLdrScanImportDescriptorTable(LoaderBlock, FileName, HalDTE);
 +      if (KdComDTE)
 +              WinLdrScanImportDescriptorTable(LoaderBlock, FileName, KdComDTE);
 +
 +      /* Load NLS data, OEM font, and prepare boot drivers list */
 +      Status = WinLdrScanSystemHive(LoaderBlock, BootPath);
 +      DPRINTM(DPRINT_WINDOWS, "SYSTEM hive scanned with status %d\n", Status);
 +
 +      /* Load boot drivers */
 +      Status = WinLdrLoadBootDrivers(LoaderBlock, BootPath);
 +      DPRINTM(DPRINT_WINDOWS, "Boot drivers loaded with status %d\n", Status);
 +
 +      /* Alloc PCR, TSS, do magic things with the GDT/IDT */
 +      WinLdrSetupForNt(LoaderBlock, &GdtIdt, &PcrBasePage, &TssBasePage);
 +
 +      /* Initialize Phase 1 - no drivers loading anymore */
 +      WinLdrInitializePhase1(LoaderBlock, BootOptions, SystemRoot, BootPath, OperatingSystemVersion);
 +
 +      /* Save entry-point pointer and Loader block VAs */
 +      KiSystemStartup = (KERNEL_ENTRY_POINT)KernelDTE->EntryPoint;
 +      LoaderBlockVA = PaToVa(LoaderBlock);
 +
 +      /* "Stop all motors", change videomode */
 +      if (OperatingSystemVersion < _WIN32_WINNT_WIN2K)
 +              MachPrepareForReactOS(TRUE);
 +      else
 +              MachPrepareForReactOS(FALSE);
 +
 +      /* Debugging... */
 +      //DumpMemoryAllocMap();
 +
 +      /* Turn on paging mode of CPU*/
 +      WinLdrTurnOnPaging(LoaderBlock, PcrBasePage, TssBasePage, GdtIdt);
 +
 +      /* Save final value of LoaderPagesSpanned */
 +      LoaderBlockVA->Extension->LoaderPagesSpanned = LoaderPagesSpanned;
 +
 +      DPRINTM(DPRINT_WINDOWS, "Hello from paged mode, KiSystemStartup %p, LoaderBlockVA %p!\n",
 +              KiSystemStartup, LoaderBlockVA);
 +
 +      WinLdrpDumpMemoryDescriptors(LoaderBlockVA);
 +      WinLdrpDumpBootDriver(LoaderBlockVA);
 +      WinLdrpDumpArcDisks(LoaderBlockVA);
 +
 +      //FIXME: If I substitute this debugging checkpoint, GCC will "optimize away" the code below
 +      //while (1) {};
 +      /*asm(".intel_syntax noprefix\n");
 +              asm("test1:\n");
 +              asm("jmp test1\n");
 +      asm(".att_syntax\n");*/
 +
 +      /* Pass control */
 +      (*KiSystemStartup)(LoaderBlockVA);
 +
 +      return;
 +}
 +
 +VOID
 +WinLdrpDumpMemoryDescriptors(PLOADER_PARAMETER_BLOCK LoaderBlock)
 +{
 +      PLIST_ENTRY NextMd;
 +      PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor;
 +
 +      NextMd = LoaderBlock->MemoryDescriptorListHead.Flink;
 +
 +      while (NextMd != &LoaderBlock->MemoryDescriptorListHead)
 +      {
 +              MemoryDescriptor = CONTAINING_RECORD(NextMd, MEMORY_ALLOCATION_DESCRIPTOR, ListEntry);
 +
 +              DPRINTM(DPRINT_WINDOWS, "BP %08X PC %04X MT %d\n", MemoryDescriptor->BasePage,
 +                      MemoryDescriptor->PageCount, MemoryDescriptor->MemoryType);
 +
 +              NextMd = MemoryDescriptor->ListEntry.Flink;
 +      }
 +}
 +
 +VOID
 +WinLdrpDumpBootDriver(PLOADER_PARAMETER_BLOCK LoaderBlock)
 +{
 +      PLIST_ENTRY NextBd;
 +      PBOOT_DRIVER_LIST_ENTRY BootDriver;
 +
 +      NextBd = LoaderBlock->BootDriverListHead.Flink;
 +
 +      while (NextBd != &LoaderBlock->BootDriverListHead)
 +      {
 +              BootDriver = CONTAINING_RECORD(NextBd, BOOT_DRIVER_LIST_ENTRY, Link);
 +
 +              DPRINTM(DPRINT_WINDOWS, "BootDriver %wZ DTE %08X RegPath: %wZ\n", &BootDriver->FilePath,
 +                      BootDriver->LdrEntry, &BootDriver->RegistryPath);
 +
 +              NextBd = BootDriver->Link.Flink;
 +      }
 +}
 +
 +VOID
 +WinLdrpDumpArcDisks(PLOADER_PARAMETER_BLOCK LoaderBlock)
 +{
 +      PLIST_ENTRY NextBd;
 +      PARC_DISK_SIGNATURE ArcDisk;
 +
 +      NextBd = LoaderBlock->ArcDiskInformation->DiskSignatureListHead.Flink;
 +
 +      while (NextBd != &LoaderBlock->ArcDiskInformation->DiskSignatureListHead)
 +      {
 +              ArcDisk = CONTAINING_RECORD(NextBd, ARC_DISK_SIGNATURE, ListEntry);
 +
 +              DPRINTM(DPRINT_WINDOWS, "ArcDisk %s checksum: 0x%X, signature: 0x%X\n",
 +                      ArcDisk->ArcName, ArcDisk->CheckSum, ArcDisk->Signature);
 +
 +              NextBd = ArcDisk->ListEntry.Flink;
 +      }
 +}
 +
 +
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 0000000,2f3b06c..2f3b06c
mode 000000,100644..100644
--- /dev/null
index 0000000,7486fa9..7486fa9
mode 000000,100644..100644
--- /dev/null
index 0000000,90af6b9..90af6b9
mode 000000,100644..100644
--- /dev/null
Simple merge
index 2150b08,0000000..b186642
mode 100644,000000..100644
--- /dev/null
@@@ -1,171 -1,0 +1,180 @@@
 +/**
 + * This file has no copyright assigned and is placed in the Public Domain.
 + * This file is part of the w64 mingw-runtime package.
 + * No warranty is given; refer to the file DISCLAIMER within this package.
 + */
 +#ifndef _INC_SETJMP
 +#define _INC_SETJMP
 +
 +#include <crtdefs.h>
 +
 +#pragma pack(push,_CRT_PACKING)
 +
 +#ifdef __cplusplus
 +extern "C" {
 +#endif
 +
 +#if (defined(_X86_) && !defined(__x86_64))
 +
 +#define _JBLEN 16
 +#define _JBTYPE int
 +
 +  typedef struct __JUMP_BUFFER {
 +    unsigned long Ebp;
 +    unsigned long Ebx;
 +    unsigned long Edi;
 +    unsigned long Esi;
 +    unsigned long Esp;
 +    unsigned long Eip;
 +    unsigned long Registration;
 +    unsigned long TryLevel;
 +    unsigned long Cookie;
 +    unsigned long UnwindFunc;
 +    unsigned long UnwindData[6];
 +  } _JUMP_BUFFER;
 +
 +#elif defined(__ia64__)
 +
 +  typedef _CRT_ALIGN(16) struct _SETJMP_FLOAT128 {
 +    __MINGW_EXTENSION __int64 LowPart;
 +    __MINGW_EXTENSION __int64 HighPart;
 +  } SETJMP_FLOAT128;
 +
 +#define _JBLEN 33
 +  typedef SETJMP_FLOAT128 _JBTYPE;
 +
 +  typedef struct __JUMP_BUFFER {
 +
 +    unsigned long iAReserved[6];
 +
 +    unsigned long Registration;
 +    unsigned long TryLevel;
 +    unsigned long Cookie;
 +    unsigned long UnwindFunc;
 +
 +    unsigned long UnwindData[6];
 +
 +    SETJMP_FLOAT128 FltS0;
 +    SETJMP_FLOAT128 FltS1;
 +    SETJMP_FLOAT128 FltS2;
 +    SETJMP_FLOAT128 FltS3;
 +    SETJMP_FLOAT128 FltS4;
 +    SETJMP_FLOAT128 FltS5;
 +    SETJMP_FLOAT128 FltS6;
 +    SETJMP_FLOAT128 FltS7;
 +    SETJMP_FLOAT128 FltS8;
 +    SETJMP_FLOAT128 FltS9;
 +    SETJMP_FLOAT128 FltS10;
 +    SETJMP_FLOAT128 FltS11;
 +    SETJMP_FLOAT128 FltS12;
 +    SETJMP_FLOAT128 FltS13;
 +    SETJMP_FLOAT128 FltS14;
 +    SETJMP_FLOAT128 FltS15;
 +    SETJMP_FLOAT128 FltS16;
 +    SETJMP_FLOAT128 FltS17;
 +    SETJMP_FLOAT128 FltS18;
 +    SETJMP_FLOAT128 FltS19;
 +    __MINGW_EXTENSION __int64 FPSR;
 +    __MINGW_EXTENSION __int64 StIIP;
 +    __MINGW_EXTENSION __int64 BrS0;
 +    __MINGW_EXTENSION __int64 BrS1;
 +    __MINGW_EXTENSION __int64 BrS2;
 +    __MINGW_EXTENSION __int64 BrS3;
 +    __MINGW_EXTENSION __int64 BrS4;
 +    __MINGW_EXTENSION __int64 IntS0;
 +    __MINGW_EXTENSION __int64 IntS1;
 +    __MINGW_EXTENSION __int64 IntS2;
 +    __MINGW_EXTENSION __int64 IntS3;
 +    __MINGW_EXTENSION __int64 RsBSP;
 +    __MINGW_EXTENSION __int64 RsPFS;
 +    __MINGW_EXTENSION __int64 ApUNAT;
 +    __MINGW_EXTENSION __int64 ApLC;
 +    __MINGW_EXTENSION __int64 IntSp;
 +    __MINGW_EXTENSION __int64 IntNats;
 +    __MINGW_EXTENSION __int64 Preds;
 +
 +  } _JUMP_BUFFER;
 +
 +#elif defined(__x86_64)
 +
 +  typedef _CRT_ALIGN(16) struct _SETJMP_FLOAT128 {
 +    __MINGW_EXTENSION unsigned __int64 Part[2];
 +  } SETJMP_FLOAT128;
 +
 +#define _JBLEN 16
 +  typedef SETJMP_FLOAT128 _JBTYPE;
 +
 +  typedef struct _JUMP_BUFFER {
 +    __MINGW_EXTENSION unsigned __int64 Frame;
 +    __MINGW_EXTENSION unsigned __int64 Rbx;
 +    __MINGW_EXTENSION unsigned __int64 Rsp;
 +    __MINGW_EXTENSION unsigned __int64 Rbp;
 +    __MINGW_EXTENSION unsigned __int64 Rsi;
 +    __MINGW_EXTENSION unsigned __int64 Rdi;
 +    __MINGW_EXTENSION unsigned __int64 R12;
 +    __MINGW_EXTENSION unsigned __int64 R13;
 +    __MINGW_EXTENSION unsigned __int64 R14;
 +    __MINGW_EXTENSION unsigned __int64 R15;
 +    __MINGW_EXTENSION unsigned __int64 Rip;
 +    __MINGW_EXTENSION unsigned __int64 Spare;
 +    SETJMP_FLOAT128 Xmm6;
 +    SETJMP_FLOAT128 Xmm7;
 +    SETJMP_FLOAT128 Xmm8;
 +    SETJMP_FLOAT128 Xmm9;
 +    SETJMP_FLOAT128 Xmm10;
 +    SETJMP_FLOAT128 Xmm11;
 +    SETJMP_FLOAT128 Xmm12;
 +    SETJMP_FLOAT128 Xmm13;
 +    SETJMP_FLOAT128 Xmm14;
 +    SETJMP_FLOAT128 Xmm15;
 +  } _JUMP_BUFFER;
 +
++#elif defined(_M_ARM)
++
++#define _JBLEN  11
++#define _JBTYPE int
++
++#else
++
++#error Define Setjmp for this architecture!
++
 +#endif
 +
 +#ifndef _JMP_BUF_DEFINED
 +  typedef _JBTYPE jmp_buf[_JBLEN];
 +#define _JMP_BUF_DEFINED
 +#endif
 +
 +#ifdef USE_MINGW_SETJMP_TWO_ARGS
 +#ifndef _INC_SETJMPEX
 +#if defined(__x86_64)
 +# define mingw_getsp() \
 +  ({ void* value; __asm__ __volatile__("movq %%rsp, %[value]" : [value] "=r" (value)); value; })
 +#elif defined(_X86_)
 +# define mingw_getsp() \
 +  ({ void* value; __asm__ __volatile__("movl %%esp, %[value]" : [value] "=r" (value)); value; })
 +#endif
 +#define setjmp(BUF) _setjmp((BUF),mingw_getsp())
 +  int __cdecl __MINGW_NOTHROW _setjmp(jmp_buf _Buf,void *_Ctx);
 +#else /* _INC_SETJMPEX */
 +#undef setjmp
 +#define setjmp(BUF) _setjmpex((BUF),mingw_getsp())
 +#define setjmpex(BUF) _setjmpex((BUF),mingw_getsp())
 +  int __cdecl __MINGW_NOTHROW _setjmpex(jmp_buf _Buf,void *_Ctx);
 +#endif /* _INC_SETJMPEX */
 +#else /* !USE_MINGW_SETJMP_TWO_ARGS */
 +#ifndef _INC_SETJMPEX
 +#define setjmp _setjmp
 +#endif
 +  int __cdecl __MINGW_NOTHROW setjmp(jmp_buf _Buf);
 +#endif /* !USE_MINGW_SETJMP_TWO_ARGS */
 +
 +  __declspec(noreturn) __MINGW_NOTHROW void __cdecl ms_longjmp(jmp_buf _Buf,int _Value)/* throw(...)*/;
 +  __declspec(noreturn) __MINGW_NOTHROW void __cdecl longjmp(jmp_buf _Buf,int _Value);
 +
 +#ifdef __cplusplus
 +}
 +#endif
 +
 +#pragma pack(pop)
 +#endif
index 07b6191,0000000..97a519e
mode 100644,000000..100644
--- /dev/null
@@@ -1,396 -1,0 +1,389 @@@
- #if defined (_STDDEF_H) || defined (__need_NULL)
- #undef NULL           /* in case <stdio.h> has defined it. */
- #ifdef __GNUG__
- #define NULL __null
- #else   /* G++ */
- #ifndef __cplusplus
- #define NULL ((void *)0)
- #else   /* C++ */
 +/**
 + * This file has no copyright assigned and is placed in the Public Domain.
 + * This file is part of the w64 mingw-runtime package.
 + * No warranty is given; refer to the file DISCLAIMER within this package.
 + */
 +
 +#include <crtdefs.h>
 +
 +#ifndef _INC_STDDEF
 +#define _INC_STDDEF
 +
 +#ifdef __cplusplus
 +extern "C" {
 +#endif
 +
 +#include <errno.h>
 +
 +  _CRTIMP extern unsigned long __cdecl __threadid(void);
 +#define _threadid (__threadid())
 +  _CRTIMP extern uintptr_t __cdecl __threadhandle(void);
 +
 +#ifdef __cplusplus
 +}
 +#endif
 +
 +#endif
 +
 +/*
 + * ISO C Standard:  7.17  Common definitions  <stddef.h>
 + */
 +#if (!defined(_STDDEF_H) && !defined(_STDDEF_H_) && !defined(_ANSI_STDDEF_H) \
 +     && !defined(__STDDEF_H__)) \
 +    || defined(__need_wchar_t) || defined(__need_size_t) \
 +    || defined(__need_ptrdiff_t) || defined(__need_NULL) \
 +    || defined(__need_wint_t)
 +
 +/* Any one of these symbols __need_* means that GNU libc
 +   wants us just to define one data type.  So don't define
 +   the symbols that indicate this file's entire job has been done.  */
 +#if (!defined(__need_wchar_t) && !defined(__need_size_t)      \
 +     && !defined(__need_ptrdiff_t) && !defined(__need_NULL)   \
 +     && !defined(__need_wint_t))
 +#define _STDDEF_H
 +#define _STDDEF_H_
 +/* snaroff@next.com says the NeXT needs this.  */
 +#define _ANSI_STDDEF_H
 +/* Irix 5.1 needs this.  */
 +#define __STDDEF_H__
 +#endif
 +
 +#ifndef __sys_stdtypes_h
 +/* In 4.3bsd-net2, machine/ansi.h defines these symbols, which are
 +   defined if the corresponding type is *not* defined.
 +   FreeBSD-2.1 defines _MACHINE_ANSI_H_ instead of _ANSI_H_ */
 +#if defined(_ANSI_H_) || defined(_MACHINE_ANSI_H_)
 +#if !defined(_SIZE_T_) && !defined(_BSD_SIZE_T_)
 +#define _SIZE_T
 +#endif
 +#if !defined(_PTRDIFF_T_) && !defined(_BSD_PTRDIFF_T_)
 +#define _PTRDIFF_T
 +#endif
 +/* On BSD/386 1.1, at least, machine/ansi.h defines _BSD_WCHAR_T_
 +   instead of _WCHAR_T_. */
 +#if !defined(_WCHAR_T_) && !defined(_BSD_WCHAR_T_)
 +#ifndef _BSD_WCHAR_T_
 +#define _WCHAR_T
 +#endif
 +#endif
 +/* Undef _FOO_T_ if we are supposed to define foo_t.  */
 +#if defined (__need_ptrdiff_t) || defined (_STDDEF_H_)
 +#undef _PTRDIFF_T_
 +#undef _BSD_PTRDIFF_T_
 +#endif
 +#if defined (__need_size_t) || defined (_STDDEF_H_)
 +#undef _SIZE_T_
 +#undef _BSD_SIZE_T_
 +#endif
 +#if defined (__need_wchar_t) || defined (_STDDEF_H_)
 +#undef _WCHAR_T_
 +#undef _BSD_WCHAR_T_
 +#endif
 +#endif /* defined(_ANSI_H_) || defined(_MACHINE_ANSI_H_) */
 +
 +/* Sequent's header files use _PTRDIFF_T_ in some conflicting way.
 +   Just ignore it.  */
 +#if defined (__sequent__) && defined (_PTRDIFF_T_)
 +#undef _PTRDIFF_T_
 +#endif
 +
 +/* On VxWorks, <type/vxTypesBase.h> may have defined macros like
 +   _TYPE_size_t which will typedef size_t.  fixincludes patched the
 +   vxTypesBase.h so that this macro is only defined if _GCC_SIZE_T is
 +   not defined, and so that defining this macro defines _GCC_SIZE_T.
 +   If we find that the macros are still defined at this point, we must
 +   invoke them so that the type is defined as expected.  */
 +#if defined (_TYPE_ptrdiff_t) && (defined (__need_ptrdiff_t) || defined (_STDDEF_H_))
 +_TYPE_ptrdiff_t;
 +#undef _TYPE_ptrdiff_t
 +#endif
 +#if defined (_TYPE_size_t) && (defined (__need_size_t) || defined (_STDDEF_H_))
 +_TYPE_size_t;
 +#undef _TYPE_size_t
 +#endif
 +#if defined (_TYPE_wchar_t) && (defined (__need_wchar_t) || defined (_STDDEF_H_))
 +_TYPE_wchar_t;
 +#undef _TYPE_wchar_t
 +#endif
 +
 +/* In case nobody has defined these types, but we aren't running under
 +   GCC 2.00, make sure that __PTRDIFF_TYPE__, __SIZE_TYPE__, and
 +   __WCHAR_TYPE__ have reasonable values.  This can happen if the
 +   parts of GCC is compiled by an older compiler, that actually
 +   include gstddef.h, such as collect2.  */
 +
 +/* Signed type of difference of two pointers.  */
 +
 +/* Define this type if we are doing the whole job,
 +   or if we want this type in particular.  */
 +#if defined (_STDDEF_H) || defined (__need_ptrdiff_t)
 +#ifndef _PTRDIFF_T    /* in case <sys/types.h> has defined it. */
 +#ifndef _T_PTRDIFF_
 +#ifndef _T_PTRDIFF
 +#ifndef __PTRDIFF_T
 +#ifndef _PTRDIFF_T_
 +#ifndef _BSD_PTRDIFF_T_
 +#ifndef ___int_ptrdiff_t_h
 +#ifndef _GCC_PTRDIFF_T
 +#define _PTRDIFF_T
 +#define _T_PTRDIFF_
 +#define _T_PTRDIFF
 +#define __PTRDIFF_T
 +#define _PTRDIFF_T_
 +#define _BSD_PTRDIFF_T_
 +#define ___int_ptrdiff_t_h
 +#define _GCC_PTRDIFF_T
 +#ifndef __PTRDIFF_TYPE__
 +#ifdef _WIN64
 +#define __PTRDIFF_TYPE__ long long int
 +#else
 +#define __PTRDIFF_TYPE__ long int
 +#endif
 +#endif
 +#ifndef _PTRDIFF_T_DEFINED
 +#define _PTRDIFF_T_DEFINED
 +__MINGW_EXTENSION typedef __PTRDIFF_TYPE__ ptrdiff_t;
 +#endif
 +#endif /* _GCC_PTRDIFF_T */
 +#endif /* ___int_ptrdiff_t_h */
 +#endif /* _BSD_PTRDIFF_T_ */
 +#endif /* _PTRDIFF_T_ */
 +#endif /* __PTRDIFF_T */
 +#endif /* _T_PTRDIFF */
 +#endif /* _T_PTRDIFF_ */
 +#endif /* _PTRDIFF_T */
 +
 +/* If this symbol has done its job, get rid of it.  */
 +#undef        __need_ptrdiff_t
 +
 +#endif /* _STDDEF_H or __need_ptrdiff_t.  */
 +
 +/* Unsigned type of `sizeof' something.  */
 +
 +/* Define this type if we are doing the whole job,
 +   or if we want this type in particular.  */
 +#if defined (_STDDEF_H) || defined (__need_size_t)
 +#ifndef __size_t__    /* BeOS */
 +#ifndef __SIZE_T__    /* Cray Unicos/Mk */
 +#ifndef _SIZE_T       /* in case <sys/types.h> has defined it. */
 +#ifndef _SYS_SIZE_T_H
 +#ifndef _T_SIZE_
 +#ifndef _T_SIZE
 +#ifndef __SIZE_T
 +#ifndef _SIZE_T_
 +#ifndef _BSD_SIZE_T_
 +#ifndef _SIZE_T_DEFINED_
 +#ifndef _SIZE_T_DEFINED
 +#ifndef _BSD_SIZE_T_DEFINED_  /* Darwin */
 +#ifndef _SIZE_T_DECLARED      /* FreeBSD 5 */
 +#ifndef ___int_size_t_h
 +#ifndef _GCC_SIZE_T
 +#ifndef _SIZET_
 +#ifndef __size_t
 +#define __size_t__    /* BeOS */
 +#define __SIZE_T__    /* Cray Unicos/Mk */
 +#define _SIZE_T
 +#define _SYS_SIZE_T_H
 +#define _T_SIZE_
 +#define _T_SIZE
 +#define __SIZE_T
 +#define _SIZE_T_
 +#define _BSD_SIZE_T_
 +#define _SIZE_T_DEFINED_
 +#define _SIZE_T_DEFINED
 +#define _BSD_SIZE_T_DEFINED_  /* Darwin */
 +#define _SIZE_T_DECLARED      /* FreeBSD 5 */
 +#define ___int_size_t_h
 +#define _GCC_SIZE_T
 +#define _SIZET_
 +#if defined (__FreeBSD__) && (__FreeBSD__ >= 5)
 +/* __size_t is a typedef on FreeBSD 5!, must not trash it. */
 +#else
 +#define __size_t
 +#endif
 +#ifndef __SIZE_TYPE__
 +#ifdef _WIN64
 +#define __SIZE_TYPE__ long long unsigned int
 +#else
 +#define __SIZE_TYPE__ long unsigned int
 +#endif
 +#endif
 +#if !(defined (__GNUG__) && defined (size_t))
 +__MINGW_EXTENSION typedef __SIZE_TYPE__ size_t;
 +#ifdef __BEOS__
 +typedef long ssize_t;
 +#endif /* __BEOS__ */
 +#endif /* !(defined (__GNUG__) && defined (size_t)) */
 +#endif /* __size_t */
 +#endif /* _SIZET_ */
 +#endif /* _GCC_SIZE_T */
 +#endif /* ___int_size_t_h */
 +#endif /* _SIZE_T_DECLARED */
 +#endif /* _BSD_SIZE_T_DEFINED_ */
 +#endif /* _SIZE_T_DEFINED */
 +#endif /* _SIZE_T_DEFINED_ */
 +#endif /* _BSD_SIZE_T_ */
 +#endif /* _SIZE_T_ */
 +#endif /* __SIZE_T */
 +#endif /* _T_SIZE */
 +#endif /* _T_SIZE_ */
 +#endif /* _SYS_SIZE_T_H */
 +#endif /* _SIZE_T */
 +#endif /* __SIZE_T__ */
 +#endif /* __size_t__ */
 +#undef        __need_size_t
 +#endif /* _STDDEF_H or __need_size_t.  */
 +
 +
 +/* Wide character type.
 +   Locale-writers should change this as necessary to
 +   be big enough to hold unique values not between 0 and 127,
 +   and not (wchar_t) -1, for each defined multibyte character.  */
 +
 +/* Define this type if we are doing the whole job,
 +   or if we want this type in particular.  */
 +#if defined (_STDDEF_H) || defined (__need_wchar_t)
 +#ifndef __wchar_t__   /* BeOS */
 +#ifndef __WCHAR_T__   /* Cray Unicos/Mk */
 +#ifndef _WCHAR_T
 +#ifndef _T_WCHAR_
 +#ifndef _T_WCHAR
 +#ifndef __WCHAR_T
 +#ifndef _WCHAR_T_
 +#ifndef _BSD_WCHAR_T_
 +#ifndef _BSD_WCHAR_T_DEFINED_    /* Darwin */
 +#ifndef _BSD_RUNE_T_DEFINED_  /* Darwin */
 +#ifndef _WCHAR_T_DECLARED /* FreeBSD 5 */
 +#ifndef _WCHAR_T_DEFINED_
 +#ifndef _WCHAR_T_DEFINED
 +#ifndef _WCHAR_T_H
 +#ifndef ___int_wchar_t_h
 +#ifndef __INT_WCHAR_T_H
 +#ifndef _GCC_WCHAR_T
 +#define __wchar_t__   /* BeOS */
 +#define __WCHAR_T__   /* Cray Unicos/Mk */
 +#define _WCHAR_T
 +#define _T_WCHAR_
 +#define _T_WCHAR
 +#define __WCHAR_T
 +#define _WCHAR_T_
 +#define _BSD_WCHAR_T_
 +#define _WCHAR_T_DEFINED_
 +#define _WCHAR_T_DEFINED
 +#define _WCHAR_T_H
 +#define ___int_wchar_t_h
 +#define __INT_WCHAR_T_H
 +#define _GCC_WCHAR_T
 +#define _WCHAR_T_DECLARED
 +
 +/* On BSD/386 1.1, at least, machine/ansi.h defines _BSD_WCHAR_T_
 +   instead of _WCHAR_T_, and _BSD_RUNE_T_ (which, unlike the other
 +   symbols in the _FOO_T_ family, stays defined even after its
 +   corresponding type is defined).  If we define wchar_t, then we
 +   must undef _WCHAR_T_; for BSD/386 1.1 (and perhaps others), if
 +   we undef _WCHAR_T_, then we must also define rune_t, since
 +   headers like runetype.h assume that if machine/ansi.h is included,
 +   and _BSD_WCHAR_T_ is not defined, then rune_t is available.
 +   machine/ansi.h says, "Note that _WCHAR_T_ and _RUNE_T_ must be of
 +   the same type." */
 +#ifdef _BSD_WCHAR_T_
 +#undef _BSD_WCHAR_T_
 +#ifdef _BSD_RUNE_T_
 +#if !defined (_ANSI_SOURCE) && !defined (_POSIX_SOURCE)
 +typedef _BSD_RUNE_T_ rune_t;
 +#define _BSD_WCHAR_T_DEFINED_
 +#define _BSD_RUNE_T_DEFINED_  /* Darwin */
 +#if defined (__FreeBSD__) && (__FreeBSD__ < 5)
 +/* Why is this file so hard to maintain properly?  In contrast to
 +   the comment above regarding BSD/386 1.1, on FreeBSD for as long
 +   as the symbol has existed, _BSD_RUNE_T_ must not stay defined or
 +   redundant typedefs will occur when stdlib.h is included after this file. */
 +#undef _BSD_RUNE_T_
 +#endif
 +#endif
 +#endif
 +#endif
 +
 +#ifndef __WCHAR_TYPE__
 +#define __WCHAR_TYPE__ unsigned short
 +#endif
 +#ifndef __cplusplus
 +typedef __WCHAR_TYPE__ wchar_t;
 +#endif
 +#endif
 +#endif
 +#endif
 +#endif
 +#endif
 +#endif
 +#endif /* _WCHAR_T_DECLARED */
 +#endif /* _BSD_RUNE_T_DEFINED_ */
 +#endif
 +#endif
 +#endif
 +#endif
 +#endif
 +#endif
 +#endif
 +#endif /* __WCHAR_T__ */
 +#endif /* __wchar_t__ */
 +#undef        __need_wchar_t
 +#endif /* _STDDEF_H or __need_wchar_t.  */
 +
 +/*  In 4.3bsd-net2, leave these undefined to indicate that size_t, etc.
 +    are already defined.  */
 +/*  BSD/OS 3.1 and FreeBSD [23].x require the MACHINE_ANSI_H check here.  */
 +#if defined(_ANSI_H_) || defined(_MACHINE_ANSI_H_)
 +/*  The references to _GCC_PTRDIFF_T_, _GCC_SIZE_T_, and _GCC_WCHAR_T_
 +    are probably typos and should be removed before 2.8 is released.  */
 +#ifdef _GCC_PTRDIFF_T_
 +#undef _PTRDIFF_T_
 +#undef _BSD_PTRDIFF_T_
 +#endif
 +#ifdef _GCC_SIZE_T_
 +#undef _SIZE_T_
 +#undef _BSD_SIZE_T_
 +#endif
 +#ifdef _GCC_WCHAR_T_
 +#undef _WCHAR_T_
 +#undef _BSD_WCHAR_T_
 +#endif
 +/*  The following ones are the real ones.  */
 +#ifdef _GCC_PTRDIFF_T
 +#undef _PTRDIFF_T_
 +#undef _BSD_PTRDIFF_T_
 +#endif
 +#ifdef _GCC_SIZE_T
 +#undef _SIZE_T_
 +#undef _BSD_SIZE_T_
 +#endif
 +#ifdef _GCC_WCHAR_T
 +#undef _WCHAR_T_
 +#undef _BSD_WCHAR_T_
 +#endif
 +#endif /* _ANSI_H_ || _MACHINE_ANSI_H_ */
 +
 +#endif /* __sys_stdtypes_h */
 +
 +/* A null pointer constant.  */
- #endif  /* C++ */
- #endif  /* G++ */
- #endif        /* NULL not defined and <stddef.h> or need NULL.  */
- #undef        __need_NULL
++#ifndef NULL
++#ifdef __cplusplus
 +#define NULL 0
++#else
++#define NULL ((void*)0)
++#endif
++#endif
 +
 +#ifndef offsetof
 +
 +/* Offset of member MEMBER in a struct of type TYPE. */
 +#if defined(__GNUC__)
 +#define offsetof(TYPE, MEMBER) __builtin_offsetof (TYPE, MEMBER)
 +#else
 +#define offsetof(TYPE, MEMBER) ((size_t)&(((TYPE *)0)->MEMBER))
 +#endif
 +
 +#endif /* !offsetof */
 +
 +#endif /* !_STDDEF_H && !_STDDEF_H_ && !_ANSI_STDDEF_H && !__STDDEF_H__
 +        || __need_XXX was not defined before */
Simple merge
Simple merge
Simple merge
index 063c3b8,0000000..308e47f
mode 100644,000000..100644
--- /dev/null
@@@ -1,308 -1,0 +1,309 @@@
-     ULONG Unknown1,
-     ULONG Unknown2,
-     ULONG Unknown3
 +/*++ NDK Version: 0098
 +
 +Copyright (c) Alex Ionescu.  All rights reserved.
 +
 +Header Name:
 +
 +    umfuncs.h
 +
 +Abstract:
 +
 +    Function definitions for Native DLL (ntdll) APIs exclusive to User Mode.
 +
 +Author:
 +
 +    Alex Ionescu (alexi@tinykrnl.org) - Updated - 27-Feb-2006
 +
 +--*/
 +
 +#ifndef _UMFUNCS_H
 +#define _UMFUNCS_H
 +
 +//
 +// Dependencies
 +//
 +#include <umtypes.h>
 +#include <dbgktypes.h>
 +
 +//
 +// Don't force inclusion of csrss header, leave this opaque.
 +//
 +struct _CSR_API_MESSAGE;
 +struct _CSR_CAPTURE_BUFFER;
 +
 +//
 +// CSR Functions
 +//
 +PVOID
 +NTAPI
 +CsrAllocateCaptureBuffer(
 +    ULONG ArgumentCount,
 +    ULONG BufferSize
 +);
 +
 +ULONG
 +NTAPI
 +CsrAllocateMessagePointer(
 +    struct _CSR_CAPTURE_BUFFER *CaptureBuffer,
 +    ULONG MessageLength,
 +    PVOID *CaptureData
 +);
 +
 +VOID
 +NTAPI
 +CsrCaptureMessageBuffer(
 +    struct _CSR_CAPTURE_BUFFER *CaptureBuffer,
 +    PVOID MessageString,
 +    ULONG StringLength,
 +    PVOID *CapturedData
 +);
 +
 +NTSTATUS
 +NTAPI
 +CsrClientConnectToServer(
 +    PWSTR ObjectDirectory,
 +    ULONG ServerId,
 +    PVOID ConnectionInfo,
 +    PULONG ConnectionInfoSize,
 +    PBOOLEAN ServerToServerCall
 +);
 +
 +NTSTATUS
 +NTAPI
 +CsrClientCallServer(
 +    struct _CSR_API_MESSAGE *Request,
 +    struct _CSR_CAPTURE_BUFFER *CaptureBuffer OPTIONAL,
 +    ULONG ApiNumber,
 +    ULONG RequestLength
 +);
 +
 +NTSTATUS
 +NTAPI
 +CsrIdentifyAlertableThread(
 +    VOID
 +);
 +
 +VOID
 +NTAPI
 +CsrFreeCaptureBuffer(
 +    struct _CSR_CAPTURE_BUFFER *CaptureBuffer
 +);
 +
 +HANDLE
 +NTAPI
 +CsrGetProcessId(
 +    VOID
 +);
 +
 +NTSTATUS
 +NTAPI
 +CsrNewThread(VOID);
 +
 +NTSTATUS
 +NTAPI
 +CsrSetPriorityClass(
 +    HANDLE Process,
 +    PULONG PriorityClass
 +);
 +
 +VOID
 +NTAPI
 +CsrProbeForRead(
 +    IN PVOID Address,
 +    IN ULONG Length,
 +    IN ULONG Alignment
 +);
 +
 +VOID
 +NTAPI
 +CsrProbeForWrite(
 +    IN PVOID Address,
 +    IN ULONG Length,
 +    IN ULONG Alignment
 +);
 +
 +//
 +// Debug Functions
 +//
 +NTSYSAPI
 +VOID
 +NTAPI
 +DbgBreakPointWithStatus(
 +    IN ULONG Status
 +);
 +
 +NTSTATUS
 +NTAPI
 +DbgUiConnectToDbg(
 +    VOID
 +);
 +
 +NTSTATUS
 +NTAPI
 +DbgUiContinue(
 +    IN PCLIENT_ID ClientId,
 +    IN NTSTATUS ContinueStatus
 +);
 +
 +NTSTATUS
 +NTAPI
 +DbgUiDebugActiveProcess(
 +    IN HANDLE Process
 +);
 +
 +NTSTATUS
 +NTAPI
 +DbgUiStopDebugging(
 +    IN HANDLE Process
 +);
 +
 +NTSYSAPI
 +NTSTATUS
 +NTAPI
 +DbgUiWaitStateChange(
 +    IN PDBGUI_WAIT_STATE_CHANGE DbgUiWaitStateCange,
 +    IN PLARGE_INTEGER TimeOut
 +);
 +
 +NTSTATUS
 +NTAPI
 +DbgUiConvertStateChangeStructure(
 +    IN PDBGUI_WAIT_STATE_CHANGE WaitStateChange,
 +    IN PVOID DebugEvent
 +);
 +
 +VOID
 +NTAPI
 +DbgUiRemoteBreakin(
 +    VOID
 +);
 +
 +NTSTATUS
 +NTAPI
 +DbgUiIssueRemoteBreakin(
 +    IN HANDLE Process
 +);
 +
 +HANDLE
 +NTAPI
 +DbgUiGetThreadDebugObject(
 +    VOID
 +);
 +
 +//
 +// Loader Functions
 +//
 +
 +NTSTATUS
 +NTAPI
 +LdrAddRefDll(
 +    IN ULONG Flags,
 +    IN PVOID BaseAddress
 +);
 +
 +NTSTATUS
 +NTAPI
 +LdrDisableThreadCalloutsForDll(
 +    IN PVOID BaseAddress
 +);
 +
 +NTSTATUS
 +NTAPI
 +LdrGetDllHandle(
 +    IN PWSTR DllPath OPTIONAL,
 +    IN PULONG DllCharacteristics,
 +    IN PUNICODE_STRING DllName,
 +    OUT PVOID *DllHandle
 +);
 +
 +NTSTATUS
 +NTAPI
 +LdrFindEntryForAddress(
 +    IN PVOID Address,
 +    OUT PLDR_DATA_TABLE_ENTRY *Module
 +);
 +
 +NTSTATUS
 +NTAPI
 +LdrGetProcedureAddress(
 +    IN PVOID BaseAddress,
 +    IN PANSI_STRING Name,
 +    IN ULONG Ordinal,
 +    OUT PVOID *ProcedureAddress
 +);
 +
 +VOID
 +NTAPI
 +LdrInitializeThunk(
 +    ULONG Unknown1,
 +    ULONG Unknown2,
 +    ULONG Unknown3,
 +    ULONG Unknown4
 +);
 +
 +NTSTATUS
 +NTAPI
 +LdrLoadDll(
 +    IN PWSTR SearchPath OPTIONAL,
 +    IN PULONG LoadFlags OPTIONAL,
 +    IN PUNICODE_STRING Name,
 +    OUT PVOID *BaseAddress OPTIONAL
 +);
 +
 +PIMAGE_BASE_RELOCATION
 +NTAPI
 +LdrProcessRelocationBlock(
 +    IN ULONG_PTR Address,
 +    IN ULONG Count,
 +    IN PUSHORT TypeOffset,
 +    IN LONG_PTR Delta
 +);
 +
 +NTSTATUS
 +NTAPI
 +LdrQueryImageFileExecutionOptions(
 +    IN PUNICODE_STRING SubKey,
 +    IN PCWSTR ValueName,
 +    IN ULONG ValueSize,
 +    OUT PVOID Buffer,
 +    IN ULONG BufferSize,
 +    OUT PULONG RetunedLength OPTIONAL
 +);
 +
 +NTSTATUS
 +NTAPI
 +LdrQueryProcessModuleInformation(
 +    IN PRTL_PROCESS_MODULES ModuleInformation OPTIONAL,
 +    IN ULONG Size OPTIONAL,
 +    OUT PULONG ReturnedSize
 +);
 +
 +NTSTATUS
 +NTAPI
 +LdrShutdownProcess(
 +    VOID
 +);
 +
 +NTSTATUS
 +NTAPI
 +LdrShutdownThread(
 +    VOID
 +);
 +
 +NTSTATUS
 +NTAPI
 +LdrUnloadDll(
 +    IN PVOID BaseAddress
 +);
 +
++typedef VOID NTAPI (*PLDR_CALLBACK)(PVOID CallbackContext, PVOID Name);
 +NTSTATUS
 +NTAPI
 +LdrVerifyImageMatchesChecksum(
 +    IN HANDLE FileHandle,
++    IN PLDR_CALLBACK Callback,
++    IN PVOID CallbackContext,
++    OUT PUSHORT ImageCharacterstics
 +);
 +
 +#endif
index 0000000,de2c0ba..de2c0ba
mode 000000,100644..100644
--- /dev/null
Simple merge
index 50dbd6b,0000000..72bfc27
mode 100644,000000..100644
--- /dev/null
@@@ -1,5270 -1,0 +1,5338 @@@
 +#ifndef _WINNT_H
 +#define _WINNT_H
 +
 +#if !defined(__ROS_LONG64__)
 +#ifdef __WINESRC__
 +#define __ROS_LONG64__
 +#endif
 +#endif
 +
 +#ifdef __GNUC__
 +#include <msvctarget.h>
 +#endif
 +
++#ifndef __ANONYMOUS_DEFINED
++#define __ANONYMOUS_DEFINED
++#ifndef NONAMELESSUNION
++#ifdef __GNUC__
++#define _ANONYMOUS_UNION __extension__
++#define _ANONYMOUS_STRUCT __extension__
++#elif defined(__WATCOMC__) || defined(_MSC_VER)
++#define _ANONYMOUS_UNION
++#define _ANONYMOUS_STRUCT
++#endif /* __GNUC__/__WATCOMC__ */
++#endif /* NONAMELESSUNION */
++#ifndef _ANONYMOUS_UNION
++#define _ANONYMOUS_UNION
++#define _UNION_NAME(x) x
++#define DUMMYUNIONNAME        u
++#define DUMMYUNIONNAME1       u1
++#define DUMMYUNIONNAME2       u2
++#define DUMMYUNIONNAME3       u3
++#define DUMMYUNIONNAME4       u4
++#define DUMMYUNIONNAME5       u5
++#define DUMMYUNIONNAME6       u6
++#define DUMMYUNIONNAME7       u7
++#define DUMMYUNIONNAME8       u8
++#else
++#define _UNION_NAME(x)
++#define DUMMYUNIONNAME
++#define DUMMYUNIONNAME1
++#define DUMMYUNIONNAME2
++#define DUMMYUNIONNAME3
++#define DUMMYUNIONNAME4
++#define DUMMYUNIONNAME5
++#define DUMMYUNIONNAME6
++#define DUMMYUNIONNAME7
++#define DUMMYUNIONNAME8
++#endif
++#ifndef _ANONYMOUS_STRUCT
++#define _ANONYMOUS_STRUCT
++#define _STRUCT_NAME(x) x
++#define DUMMYSTRUCTNAME       s
++#define DUMMYSTRUCTNAME1 s1
++#define DUMMYSTRUCTNAME2 s2
++#define DUMMYSTRUCTNAME3 s3
++#define DUMMYSTRUCTNAME4 s4
++#define DUMMYSTRUCTNAME5 s5
++#else
++#define _STRUCT_NAME(x)
++#define DUMMYSTRUCTNAME
++#define DUMMYSTRUCTNAME1
++#define DUMMYSTRUCTNAME2
++#define DUMMYSTRUCTNAME3
++#define DUMMYSTRUCTNAME4
++#define DUMMYSTRUCTNAME5
++#endif
++#endif /* __ANONYMOUS_DEFINED */
++
++
 +#ifndef DECLSPEC_ALIGN
 +# if defined(_MSC_VER) && (_MSC_VER >= 1300) && !defined(MIDL_PASS)
 +#  define DECLSPEC_ALIGN(x) __declspec(align(x))
 +# elif defined(__GNUC__)
 +#  define DECLSPEC_ALIGN(x) __attribute__((aligned(x)))
 +# else
 +#  define DECLSPEC_ALIGN(x)
 +# endif
 +#endif
 +
 +# define DECLSPEC_HIDDEN
 +
 +#ifdef __cplusplus
 +extern "C" {
 +#endif
 +
 +#include <excpt.h>
 +#include <basetsd.h>
 +#include <guiddef.h>
 +
 +#include <ctype.h>
 +#undef __need_wchar_t
 +
 +#include <winerror.h>
 +#include <stddef.h>
 +#include <sdkddkver.h>
 +
 +#ifndef RC_INVOKED
 +#include <string.h>
 +
 +/* FIXME: add more architectures. Is there a way to specify this in GCC? */
 +#if defined(_M_AMD64)
 +#undef UNALIGNED
 +#define UNALIGNED __unaligned
 +#else
 +#define UNALIGNED
 +#endif
 +
 +#ifndef DECLSPEC_NOVTABLE
 +# if defined(_MSC_VER) && (_MSC_VER >= 1100) && defined(__cplusplus)
 +#  define DECLSPEC_NOVTABLE __declspec(novtable)
 +# else
 +#  define DECLSPEC_NOVTABLE
 +# endif
 +#endif
 +
 +#ifndef DECLSPEC_ADDRSAFE
 +#if (_MSC_VER >= 1200) && (defined(_M_ALPHA) || defined(_M_AXP64))
 +#define DECLSPEC_ADDRSAFE __declspec(address_safe)
 +#else
 +#define DECLSPEC_ADDRSAFE
 +#endif
 +#endif
 +
 +/*#ifdef _WINE*/
 +#if defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)))
 +#define __WINE_ALLOC_SIZE(x) __attribute__((__alloc_size__(x)))
 +#else
 +#define __WINE_ALLOC_SIZE(x)
 +#endif
 +/*#endif*/
 +
 +#ifndef FORCEINLINE
 +#if (_MSC_VER >= 1200)
 +#define FORCEINLINE __forceinline
 +#elif (_MSC_VER)
 +#define FORCEINLINE __inline
 +#else
 +#define FORCEINLINE extern __inline__ __attribute__((always_inline))
 +#endif
 +#endif
 +
 +#if !defined(_NTSYSTEM_)
 +#define NTSYSAPI     DECLSPEC_IMPORT
 +#define NTSYSCALLAPI DECLSPEC_IMPORT
 +#else
 +#define NTSYSAPI
 +#if defined(_NTDLLBUILD_)
 +#define NTSYSCALLAPI
 +#else
 +#define NTSYSCALLAPI DECLSPEC_ADDRSAFE
 +#endif
 +#endif
 +
 +#ifndef VOID
 +#define VOID void
 +#endif
 +typedef char CHAR;
 +typedef short SHORT;
 +#if !defined(__ROS_LONG64__) || defined(_M_AMD64)
 +typedef long LONG;
 +#else
 +typedef int LONG;
 +#endif
 +typedef char CCHAR, *PCCHAR;
 +typedef void *PVOID;
 +
 +/* FIXME for __WIN64 */
 +#ifndef  __ptr64
 +#define __ptr64
 +#endif
 +typedef void* __ptr64 PVOID64;
 +
 +#ifdef __cplusplus
 +# define EXTERN_C    extern "C"
 +#else
 +# define EXTERN_C    extern
 +#endif
 +
 +#define STDMETHODCALLTYPE       __stdcall
 +#define STDMETHODVCALLTYPE      __cdecl
 +#define STDAPICALLTYPE          __stdcall
 +#define STDAPIVCALLTYPE         __cdecl
 +
 +#define STDAPI                  EXTERN_C HRESULT STDAPICALLTYPE
 +#define STDAPI_(type)           EXTERN_C type STDAPICALLTYPE
 +#define STDMETHODIMP            HRESULT STDMETHODCALLTYPE
 +#define STDMETHODIMP_(type)     type STDMETHODCALLTYPE
 +#define STDAPIV                 EXTERN_C HRESULT STDAPIVCALLTYPE
 +#define STDAPIV_(type)          EXTERN_C type STDAPIVCALLTYPE
 +#define STDMETHODIMPV           HRESULT STDMETHODVCALLTYPE
 +#define STDMETHODIMPV_(type)    type STDMETHODVCALLTYPE
 +
 +/* C99 restrict support */
 +#if defined(ENABLE_RESTRICTED) && !defined(MIDL_PASS) && !defined(RC_INVOKED)
 +  #if defined(_MSC_VER) && defined(_M_MRX000)
 +    #define RESTRICTED_POINTER __restrict
 +  #elif defined(__GNUC__) && ((__GNUC__ > 2) || ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 95)))
 +    #define RESTRICTED_POINTER __restrict
 +  #else
 +    #define RESTRICTED_POINTER
 +  #endif
 +#else
 +  #define RESTRICTED_POINTER
 +#endif
 +
 +typedef wchar_t WCHAR;
 +typedef WCHAR *PWCHAR,*LPWCH,*PWCH,*NWPSTR,*LPWSTR,*PWSTR,*PZZWSTR;
 +typedef CONST WCHAR *LPCWCH,*PCWCH,*LPCWSTR,*PCWSTR,*PCZZWSTR;
 +typedef CHAR *PCHAR,*LPCH,*PCH,*NPSTR,*LPSTR,*PSTR;
 +typedef CONST CHAR *LPCCH,*PCCH,*PCSTR,*LPCSTR;
 +typedef PWSTR *PZPWSTR;
 +typedef CONST PWSTR *PCZPWSTR;
 +typedef WCHAR UNALIGNED *LPUWSTR,*PUWSTR;
 +typedef PCWSTR *PZPCWSTR;
 +typedef CONST WCHAR UNALIGNED *LPCUWSTR,*PCUWSTR;
 +typedef PSTR *PZPSTR;
 +typedef CONST PSTR *PCZPSTR;
 +typedef PCSTR *PZPCSTR;
 +
 +
 +#ifdef UNICODE
 +#ifndef _TCHAR_DEFINED
 +#define _TCHAR_DEFINED
 +  typedef WCHAR TCHAR,*PTCHAR;
 +  typedef WCHAR TBYTE ,*PTBYTE;
 +#endif
 +  typedef LPWSTR LPTCH,PTCH,PTSTR,LPTSTR,LP;
 +  typedef LPCWSTR PCTSTR,LPCTSTR;
 +  typedef LPUWSTR PUTSTR,LPUTSTR;
 +  typedef LPCUWSTR PCUTSTR,LPCUTSTR;
 +#define __TEXT(quote) L##quote
 +#else
 +#ifndef _TCHAR_DEFINED
 +#define _TCHAR_DEFINED
 +  typedef char TCHAR,*PTCHAR;
 +  typedef unsigned char TBYTE ,*PTBYTE;
 +#endif
 +  typedef LPSTR LPTCH,PTCH,PTSTR,LPTSTR,PUTSTR,LPUTSTR;
 +  typedef LPCSTR PCTSTR,LPCTSTR,PCUTSTR,LPCUTSTR;
 +#define __TEXT(quote) quote
 +#endif
 +
 +#define TEXT(quote) __TEXT(quote)
 +
 +typedef SHORT *PSHORT;
 +typedef LONG *PLONG;
 +#ifdef STRICT
 +typedef void *HANDLE;
 +#define DECLARE_HANDLE(n) typedef struct n##__{int i;}*n
 +#else
 +typedef PVOID HANDLE;
 +#define DECLARE_HANDLE(n) typedef HANDLE n
 +#endif
 +typedef HANDLE *PHANDLE;
 +typedef DWORD LCID;
 +typedef PDWORD PLCID;
 +typedef WORD LANGID;
 +#ifdef __GNUC__
 +#define _HAVE_INT64
 +#ifndef _INTEGRAL_MAX_BITS
 +# define _INTEGRAL_MAX_BITS 64
 +#endif
 +#undef __int64
 +#define __int64 long long
 +#elif (defined(__WATCOMC__) || defined(_MSC_VER)) && (defined(_INTEGRAL_MAX_BITS) && _INTEGRAL_MAX_BITS >= 64 )
 +#define _HAVE_INT64
 +#endif /* __GNUC__/__WATCOMC */
 +#if defined(_HAVE_INT64) || (defined(_INTEGRAL_MAX_BITS) && _INTEGRAL_MAX_BITS >= 64)
 +typedef __int64 LONGLONG;
 +typedef unsigned __int64 DWORDLONG;
 +#else
 +typedef double LONGLONG,DWORDLONG;
 +#endif
 +typedef LONGLONG *PLONGLONG;
 +typedef DWORDLONG *PDWORDLONG;
 +typedef DWORDLONG ULONGLONG,*PULONGLONG;
 +typedef LONGLONG USN;
 +#ifdef _HAVE_INT64
 +#define Int32x32To64(a,b) ((LONGLONG)(a)*(LONGLONG)(b))
 +#define UInt32x32To64(a,b) ((DWORDLONG)(a)*(DWORDLONG)(b))
 +#define Int64ShllMod32(a,b) ((DWORDLONG)(a)<<(b))
 +#define Int64ShraMod32(a,b) ((LONGLONG)(a)>>(b))
 +#define Int64ShrlMod32(a,b) ((DWORDLONG)(a)>>(b))
 +#endif
 +#define ANSI_NULL ((CHAR)0)
 +#define UNICODE_NULL ((WCHAR)0)
 +typedef BYTE BOOLEAN,*PBOOLEAN;
 +#endif
 +typedef BYTE FCHAR;
 +typedef WORD FSHORT;
 +typedef DWORD FLONG;
 +
 +#define C_ASSERT(expr) extern char (*c_assert(void)) [(expr) ? 1 : -1]
 +
 +#include "intrin.h"
 +
 +#define NTAPI __stdcall
 +#include <basetsd.h>
 +
 +#ifdef _MSC_VER
 +#pragma warning(push)
 +#pragma warning(disable:4201)
 +#pragma warning(disable:4214)
 +#pragma warning(disable:4820)
 +#endif
 +
 +#define ACE_OBJECT_TYPE_PRESENT           0x00000001
 +#define ACE_INHERITED_OBJECT_TYPE_PRESENT 0x00000002
 +#define APPLICATION_ERROR_MASK       0x20000000
 +#define ERROR_SEVERITY_SUCCESS       0x00000000
 +#define ERROR_SEVERITY_INFORMATIONAL 0x40000000
 +#define ERROR_SEVERITY_WARNING       0x80000000
 +#define ERROR_SEVERITY_ERROR         0xC0000000
 +/* also in ddk/ntifs.h */
 +#define COMPRESSION_FORMAT_NONE         (0x0000)
 +#define COMPRESSION_FORMAT_DEFAULT      (0x0001)
 +#define COMPRESSION_FORMAT_LZNT1        (0x0002)
 +#define COMPRESSION_ENGINE_STANDARD     (0x0000)
 +#define COMPRESSION_ENGINE_MAXIMUM      (0x0100)
 +#define COMPRESSION_ENGINE_HIBER        (0x0200)
 +#define ACCESS_ALLOWED_ACE_TYPE         (0x0)
 +#define ACCESS_DENIED_ACE_TYPE          (0x1)
 +#define SYSTEM_AUDIT_ACE_TYPE           (0x2)
 +#define SYSTEM_ALARM_ACE_TYPE           (0x3)
 +/*end ntifs.h */
 +#define ANYSIZE_ARRAY 1
 +#define OBJECT_INHERIT_ACE    1
 +#define CONTAINER_INHERIT_ACE 2
 +#define NO_PROPAGATE_INHERIT_ACE      4
 +#define INHERIT_ONLY_ACE      8
 +#define INHERITED_ACE 10
 +#define VALID_INHERIT_FLAGS   0x1F
 +#define SUCCESSFUL_ACCESS_ACE_FLAG    64
 +#define FAILED_ACCESS_ACE_FLAG        128
 +#define DELETE        0x00010000L
 +#define READ_CONTROL  0x20000L
 +#define WRITE_DAC     0x40000L
 +#define WRITE_OWNER   0x80000L
 +#define SYNCHRONIZE   0x100000L
 +#define STANDARD_RIGHTS_REQUIRED      0xF0000
 +#define STANDARD_RIGHTS_READ  0x20000
 +#define STANDARD_RIGHTS_WRITE 0x20000
 +#define STANDARD_RIGHTS_EXECUTE       0x20000
 +#define STANDARD_RIGHTS_ALL   0x1F0000
 +#define SPECIFIC_RIGHTS_ALL   0xFFFF
 +#define ACCESS_SYSTEM_SECURITY        0x1000000
 +
 +#define REG_STANDARD_FORMAT 1
 +#define REG_LATEST_FORMAT   2
 +#define REG_NO_COMPRESSION  4
 +
 +#ifndef WIN32_NO_STATUS
 +
 +#define STATUS_WAIT_0                    ((DWORD)0x00000000)
 +#define STATUS_ABANDONED_WAIT_0          ((DWORD)0x00000080)
 +#define STATUS_USER_APC                  ((DWORD)0x000000C0)
 +#define STATUS_TIMEOUT                   ((DWORD)0x00000102)
 +#define STATUS_PENDING                   ((DWORD)0x00000103)
 +#define STATUS_SEGMENT_NOTIFICATION      ((DWORD)0x40000005)
 +#define STATUS_GUARD_PAGE_VIOLATION      ((DWORD)0x80000001)
 +#define STATUS_DATATYPE_MISALIGNMENT     ((DWORD)0x80000002)
 +#define STATUS_BREAKPOINT                ((DWORD)0x80000003)
 +#define STATUS_SINGLE_STEP               ((DWORD)0x80000004)
 +#define STATUS_ACCESS_VIOLATION          ((DWORD)0xC0000005)
 +#define STATUS_IN_PAGE_ERROR             ((DWORD)0xC0000006)
 +#define STATUS_INVALID_HANDLE            ((DWORD)0xC0000008)
 +#define STATUS_NO_MEMORY                 ((DWORD)0xC0000017)
 +#define STATUS_ILLEGAL_INSTRUCTION       ((DWORD)0xC000001D)
 +#define STATUS_NONCONTINUABLE_EXCEPTION  ((DWORD)0xC0000025)
 +#define STATUS_INVALID_DISPOSITION       ((DWORD)0xC0000026)
 +#define STATUS_ARRAY_BOUNDS_EXCEEDED     ((DWORD)0xC000008C)
 +#define STATUS_FLOAT_DENORMAL_OPERAND    ((DWORD)0xC000008D)
 +#define STATUS_FLOAT_DIVIDE_BY_ZERO      ((DWORD)0xC000008E)
 +#define STATUS_FLOAT_INEXACT_RESULT      ((DWORD)0xC000008F)
 +#define STATUS_FLOAT_INVALID_OPERATION   ((DWORD)0xC0000090)
 +#define STATUS_FLOAT_OVERFLOW            ((DWORD)0xC0000091)
 +#define STATUS_FLOAT_STACK_CHECK         ((DWORD)0xC0000092)
 +#define STATUS_FLOAT_UNDERFLOW           ((DWORD)0xC0000093)
 +#define STATUS_INTEGER_DIVIDE_BY_ZERO    ((DWORD)0xC0000094)
 +#define STATUS_INTEGER_OVERFLOW          ((DWORD)0xC0000095)
 +#define STATUS_PRIVILEGED_INSTRUCTION    ((DWORD)0xC0000096)
 +#define STATUS_STACK_OVERFLOW            ((DWORD)0xC00000FD)
 +#define STATUS_CONTROL_C_EXIT            ((DWORD)0xC000013A)
 +#define STATUS_FLOAT_MULTIPLE_FAULTS     ((DWORD)0xC00002B4)
 +#define STATUS_FLOAT_MULTIPLE_TRAPS      ((DWORD)0xC00002B5)
 +#define STATUS_REG_NAT_CONSUMPTION       ((DWORD)0xC00002C9)
 +#define STATUS_SXS_EARLY_DEACTIVATION    ((DWORD)0xC015000F)
 +#define STATUS_SXS_INVALID_DEACTIVATION  ((DWORD)0xC0150010)
 +
 +#define DBG_EXCEPTION_HANDLED       ((DWORD)0x00010001)
 +#define DBG_CONTINUE                ((DWORD)0x00010002)
 +#define DBG_TERMINATE_THREAD        ((DWORD)0x40010003)
 +#define DBG_TERMINATE_PROCESS       ((DWORD)0x40010004)
 +#define DBG_CONTROL_C               ((DWORD)0x40010005)
 +#define DBG_CONTROL_BREAK           ((DWORD)0x40010008)
 +#define DBG_COMMAND_EXCEPTION       ((DWORD)0x40010009)
 +#define DBG_EXCEPTION_NOT_HANDLED   ((DWORD)0x80010001)
 +
 +#endif /* WIN32_NO_STATUS */
 +
 +#define MAXIMUM_ALLOWED       0x2000000
 +#define GENERIC_READ  0x80000000
 +#define GENERIC_WRITE 0x40000000
 +#define GENERIC_EXECUTE       0x20000000
 +#define GENERIC_ALL   0x10000000
 +
 +#define INVALID_FILE_ATTRIBUTES       ((DWORD)-1)
 +
 +/* Also in ddk/winddk.h */
 +#define FILE_LIST_DIRECTORY           0x00000001
 +#define FILE_READ_DATA                        0x00000001
 +#define FILE_ADD_FILE                 0x00000002
 +#define FILE_WRITE_DATA                       0x00000002
 +#define FILE_ADD_SUBDIRECTORY         0x00000004
 +#define FILE_APPEND_DATA              0x00000004
 +#define FILE_CREATE_PIPE_INSTANCE     0x00000004
 +#define FILE_READ_EA                  0x00000008
 +#define FILE_READ_PROPERTIES          0x00000008
 +#define FILE_WRITE_EA                 0x00000010
 +#define FILE_WRITE_PROPERTIES         0x00000010
 +#define FILE_EXECUTE                  0x00000020
 +#define FILE_TRAVERSE                 0x00000020
 +#define FILE_DELETE_CHILD             0x00000040
 +#define FILE_READ_ATTRIBUTES          0x00000080
 +#define FILE_WRITE_ATTRIBUTES         0x00000100
 +
 +#define FILE_SHARE_READ                       0x00000001
 +#define FILE_SHARE_WRITE              0x00000002
 +#define FILE_SHARE_DELETE             0x00000004
 +#define FILE_SHARE_VALID_FLAGS                0x00000007
 +
 +#define FILE_ATTRIBUTE_READONLY                       0x00000001
 +#define FILE_ATTRIBUTE_HIDDEN                 0x00000002
 +#define FILE_ATTRIBUTE_SYSTEM                 0x00000004
 +#define FILE_ATTRIBUTE_DIRECTORY              0x00000010
 +#define FILE_ATTRIBUTE_ARCHIVE                        0x00000020
 +#define FILE_ATTRIBUTE_DEVICE                 0x00000040
 +#define FILE_ATTRIBUTE_NORMAL                 0x00000080
 +#define FILE_ATTRIBUTE_TEMPORARY              0x00000100
 +#define FILE_ATTRIBUTE_SPARSE_FILE            0x00000200
 +#define FILE_ATTRIBUTE_REPARSE_POINT          0x00000400
 +#define FILE_ATTRIBUTE_COMPRESSED             0x00000800
 +#define FILE_ATTRIBUTE_OFFLINE                        0x00001000
 +#define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED    0x00002000
 +#define FILE_ATTRIBUTE_ENCRYPTED              0x00004000
 +#define FILE_ATTRIBUTE_VALID_FLAGS            0x00007fb7
 +#define FILE_ATTRIBUTE_VALID_SET_FLAGS                0x000031a7
 +
 +#define FILE_COPY_STRUCTURED_STORAGE          0x00000041
 +#define FILE_STRUCTURED_STORAGE                       0x00000441
 +
 +#define FILE_VALID_OPTION_FLAGS                       0x00ffffff
 +#define FILE_VALID_PIPE_OPTION_FLAGS          0x00000032
 +#define FILE_VALID_MAILSLOT_OPTION_FLAGS      0x00000032
 +#define FILE_VALID_SET_FLAGS                  0x00000036
 +
 +#define FILE_DIRECTORY_FILE           0x00000001
 +#define FILE_WRITE_THROUGH            0x00000002
 +#define FILE_SEQUENTIAL_ONLY          0x00000004
 +#define FILE_NO_INTERMEDIATE_BUFFERING        0x00000008
 +#define FILE_SYNCHRONOUS_IO_ALERT     0x00000010
 +#define FILE_SYNCHRONOUS_IO_NONALERT  0x00000020
 +#define FILE_NON_DIRECTORY_FILE               0x00000040
 +#define FILE_CREATE_TREE_CONNECTION   0x00000080
 +#define FILE_COMPLETE_IF_OPLOCKED     0x00000100
 +#define FILE_NO_EA_KNOWLEDGE          0x00000200
 +#define FILE_OPEN_REMOTE_INSTANCE     0x00000400
 +#define FILE_RANDOM_ACCESS            0x00000800
 +#define FILE_DELETE_ON_CLOSE          0x00001000
 +#define FILE_OPEN_BY_FILE_ID          0x00002000
 +#define FILE_OPEN_FOR_BACKUP_INTENT   0x00004000
 +#define FILE_NO_COMPRESSION           0x00008000
 +#define FILE_RESERVE_OPFILTER         0x00100000
 +#define FILE_OPEN_REPARSE_POINT               0x00200000
 +#define FILE_OPEN_NO_RECALL           0x00400000
 +#define FILE_OPEN_FOR_FREE_SPACE_QUERY        0x00800000
 +
 +#define FILE_ALL_ACCESS \
 +  (STANDARD_RIGHTS_REQUIRED | \
 +   SYNCHRONIZE | \
 +   0x1FF)
 +
 +#define FILE_GENERIC_EXECUTE \
 +  (STANDARD_RIGHTS_EXECUTE | \
 +   FILE_READ_ATTRIBUTES | \
 +   FILE_EXECUTE | \
 +   SYNCHRONIZE)
 +
 +#define FILE_GENERIC_READ \
 +  (STANDARD_RIGHTS_READ | \
 +   FILE_READ_DATA | \
 +   FILE_READ_ATTRIBUTES | \
 +   FILE_READ_EA | \
 +   SYNCHRONIZE)
 +
 +#define FILE_GENERIC_WRITE \
 +  (STANDARD_RIGHTS_WRITE | \
 +   FILE_WRITE_DATA | \
 +   FILE_WRITE_ATTRIBUTES | \
 +   FILE_WRITE_EA | \
 +   FILE_APPEND_DATA | \
 +   SYNCHRONIZE)
 +/* end winddk.h */
 +/* also in ddk/ntifs.h */
 +#define FILE_NOTIFY_CHANGE_FILE_NAME  0x00000001
 +#define FILE_NOTIFY_CHANGE_DIR_NAME   0x00000002
 +#define FILE_NOTIFY_CHANGE_NAME               0x00000003
 +#define FILE_NOTIFY_CHANGE_ATTRIBUTES 0x00000004
 +#define FILE_NOTIFY_CHANGE_SIZE               0x00000008
 +#define FILE_NOTIFY_CHANGE_LAST_WRITE 0x00000010
 +#define FILE_NOTIFY_CHANGE_LAST_ACCESS        0x00000020
 +#define FILE_NOTIFY_CHANGE_CREATION   0x00000040
 +#define FILE_NOTIFY_CHANGE_EA         0x00000080
 +#define FILE_NOTIFY_CHANGE_SECURITY   0x00000100
 +#define FILE_NOTIFY_CHANGE_STREAM_NAME        0x00000200
 +#define FILE_NOTIFY_CHANGE_STREAM_SIZE        0x00000400
 +#define FILE_NOTIFY_CHANGE_STREAM_WRITE       0x00000800
 +#define FILE_NOTIFY_VALID_MASK                0x00000fff
 +
 +#define FILE_CASE_SENSITIVE_SEARCH      0x00000001
 +#define FILE_CASE_PRESERVED_NAMES       0x00000002
 +#define FILE_UNICODE_ON_DISK            0x00000004
 +#define FILE_PERSISTENT_ACLS            0x00000008
 +#define FILE_FILE_COMPRESSION           0x00000010
 +#define FILE_VOLUME_QUOTAS              0x00000020
 +#define FILE_SUPPORTS_SPARSE_FILES      0x00000040
 +#define FILE_SUPPORTS_REPARSE_POINTS    0x00000080
 +#define FILE_SUPPORTS_REMOTE_STORAGE    0x00000100
 +#define FS_LFN_APIS                     0x00004000
 +#define FILE_VOLUME_IS_COMPRESSED       0x00008000
 +#define FILE_SUPPORTS_OBJECT_IDS        0x00010000
 +#define FILE_SUPPORTS_ENCRYPTION        0x00020000
 +#define FILE_NAMED_STREAMS              0x00040000
 +
 +#define IO_COMPLETION_QUERY_STATE       0x0001
 +#define IO_COMPLETION_MODIFY_STATE      0x0002
 +#define IO_COMPLETION_ALL_ACCESS        (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3)
 +/* end ntifs.h */
 +
 +/* also in ddk/winddk.h */
 +#define DUPLICATE_CLOSE_SOURCE                0x00000001
 +#define DUPLICATE_SAME_ACCESS         0x00000002
 +/* end winddk.k */
 +
 +#define MAILSLOT_NO_MESSAGE   ((DWORD)-1)
 +#define MAILSLOT_WAIT_FOREVER ((DWORD)-1)
 +#define PROCESS_TERMINATE     1
 +#define PROCESS_CREATE_THREAD 2
 +#define PROCESS_SET_SESSIONID 4
 +#define PROCESS_VM_OPERATION  8
 +#define PROCESS_VM_READ       16
 +#define PROCESS_VM_WRITE      32
 +#define PROCESS_CREATE_PROCESS        128
 +#define PROCESS_SET_QUOTA     256
 +#define PROCESS_SET_INFORMATION       512
 +#define PROCESS_QUERY_INFORMATION     1024
 +#define PROCESS_SUSPEND_RESUME        2048
 +#define PROCESS_QUERY_LIMITED_INFORMATION 0x1000
 +#define PROCESS_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0xFFF)
 +#define PROCESS_DUP_HANDLE    64
 +#define THREAD_TERMINATE      1
 +#define THREAD_SUSPEND_RESUME 2
 +#define THREAD_GET_CONTEXT    8
 +#define THREAD_SET_CONTEXT    16
 +#define THREAD_SET_INFORMATION        32
 +#define THREAD_QUERY_INFORMATION      64
 +#define THREAD_SET_THREAD_TOKEN       128
 +#define THREAD_IMPERSONATE    256
 +#define THREAD_DIRECT_IMPERSONATION   0x200
 +#define THREAD_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3FF)
 +#define MUTANT_QUERY_STATE    0x0001
 +#define MUTANT_ALL_ACCESS     (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|MUTANT_QUERY_STATE)
 +#define TIMER_QUERY_STATE     0x0001
 +#define TIMER_MODIFY_STATE    0x0002
 +#define TIMER_ALL_ACCESS      (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|TIMER_QUERY_STATE|TIMER_MODIFY_STATE)
 +#define THREAD_BASE_PRIORITY_LOWRT    15
 +#define THREAD_BASE_PRIORITY_MAX      2
 +#define THREAD_BASE_PRIORITY_MIN      (-2)
 +#define THREAD_BASE_PRIORITY_IDLE     (-15)
 +/*
 + * To prevent gcc compiler warnings, bracket these defines when initialising
 + * a  SID_IDENTIFIER_AUTHORITY, eg.
 + * SID_IDENTIFIER_AUTHORITY aNullSidAuthority = {SECURITY_NULL_SID_AUTHORITY};
 + */
 +#define SID_MAX_SUB_AUTHORITIES     15
 +
 +/* security entities */
 +#define SECURITY_NULL_RID                     (0x00000000L)
 +#define SECURITY_WORLD_RID                    (0x00000000L)
 +#define SECURITY_LOCAL_RID                    (0X00000000L)
 +
 +#define SECURITY_NULL_SID_AUTHORITY           {0,0,0,0,0,0}
 +
 +/* S-1-1 */
 +#define SECURITY_WORLD_SID_AUTHORITY          {0,0,0,0,0,1}
 +
 +/* S-1-2 */
 +#define SECURITY_LOCAL_SID_AUTHORITY          {0,0,0,0,0,2}
 +
 +/* S-1-3 */
 +#define SECURITY_CREATOR_SID_AUTHORITY                {0,0,0,0,0,3}
 +#define SECURITY_CREATOR_OWNER_RID            (0x00000000L)
 +#define SECURITY_CREATOR_GROUP_RID            (0x00000001L)
 +#define SECURITY_CREATOR_OWNER_SERVER_RID     (0x00000002L)
 +#define SECURITY_CREATOR_GROUP_SERVER_RID     (0x00000003L)
 +
 +/* S-1-4 */
 +#define SECURITY_NON_UNIQUE_AUTHORITY         {0,0,0,0,0,4}
 +
 +/* S-1-5 */
 +#define SECURITY_NT_AUTHORITY                 {0,0,0,0,0,5}
 +#define SECURITY_DIALUP_RID                     0x00000001L
 +#define SECURITY_NETWORK_RID                    0x00000002L
 +#define SECURITY_BATCH_RID                      0x00000003L
 +#define SECURITY_INTERACTIVE_RID                0x00000004L
 +#define SECURITY_LOGON_IDS_RID                  0x00000005L
 +#define SECURITY_SERVICE_RID                    0x00000006L
 +#define SECURITY_ANONYMOUS_LOGON_RID            0x00000007L
 +#define SECURITY_PROXY_RID                      0x00000008L
 +#define SECURITY_ENTERPRISE_CONTROLLERS_RID     0x00000009L
 +#define SECURITY_SERVER_LOGON_RID               SECURITY_ENTERPRISE_CONTROLLERS_RID
 +#define SECURITY_PRINCIPAL_SELF_RID             0x0000000AL
 +#define SECURITY_AUTHENTICATED_USER_RID         0x0000000BL
 +#define SECURITY_RESTRICTED_CODE_RID            0x0000000CL
 +#define SECURITY_TERMINAL_SERVER_RID            0x0000000DL
 +#define SECURITY_REMOTE_LOGON_RID               0x0000000EL
 +#define SECURITY_THIS_ORGANIZATION_RID          0x0000000FL
 +#define SECURITY_LOCAL_SYSTEM_RID               0x00000012L
 +#define SECURITY_LOCAL_SERVICE_RID              0x00000013L
 +#define SECURITY_NETWORK_SERVICE_RID            0x00000014L
 +#define SECURITY_NT_NON_UNIQUE                  0x00000015L
 +#define SECURITY_BUILTIN_DOMAIN_RID             0x00000020L
 +
 +#define SECURITY_PACKAGE_BASE_RID               0x00000040L
 +#define SECURITY_PACKAGE_NTLM_RID               0x0000000AL
 +#define SECURITY_PACKAGE_SCHANNEL_RID           0x0000000EL
 +#define SECURITY_PACKAGE_DIGEST_RID             0x00000015L
 +#define SECURITY_OTHER_ORGANIZATION_RID         0x000003E8L
 +
 +#define SECURITY_LOGON_IDS_RID_COUNT 0x3
 +#define SID_REVISION 1
 +
 +#define FOREST_USER_RID_MAX                     0x000001F3L
 +#define DOMAIN_USER_RID_ADMIN                   0x000001F4L
 +#define DOMAIN_USER_RID_GUEST                   0x000001F5L
 +#define DOMAIN_USER_RID_KRBTGT                  0x000001F6L
 +#define DOMAIN_USER_RID_MAX                     0x000003E7L
 +
 +#define DOMAIN_GROUP_RID_ADMINS                 0x00000200L
 +#define DOMAIN_GROUP_RID_USERS                  0x00000201L
 +#define DOMAIN_GROUP_RID_GUESTS                 0x00000202L
 +#define DOMAIN_GROUP_RID_COMPUTERS              0x00000203L
 +#define DOMAIN_GROUP_RID_CONTROLLERS            0x00000204L
 +#define DOMAIN_GROUP_RID_CERT_ADMINS            0x00000205L
 +#define DOMAIN_GROUP_RID_SCHEMA_ADMINS          0x00000206L
 +#define DOMAIN_GROUP_RID_ENTERPRISE_ADMINS      0x00000207L
 +#define DOMAIN_GROUP_RID_POLICY_ADMINS          0x00000208L
 +
 +#define SECURITY_MANDATORY_LABEL_AUTHORITY {0,0,0,0,0,16}
 +#define SECURITY_MANDATORY_UNTRUSTED_RID        0x00000000L
 +#define SECURITY_MANDATORY_LOW_RID              0x00001000L
 +#define SECURITY_MANDATORY_MEDIUM_RID           0x00002000L
 +#define SECURITY_MANDATORY_HIGH_RID             0x00003000L
 +#define SECURITY_MANDATORY_SYSTEM_RID           0x00004000L
 +#define SECURITY_MANDATORY_PROTECTED_PROCESS_RID 0x00005000L
 +
 +#define DOMAIN_ALIAS_RID_ADMINS                 0x00000220L
 +#define DOMAIN_ALIAS_RID_USERS                  0x00000221L
 +#define DOMAIN_ALIAS_RID_GUESTS                 0x00000222L
 +#define DOMAIN_ALIAS_RID_POWER_USERS            0x00000223L
 +
 +#define DOMAIN_ALIAS_RID_ACCOUNT_OPS            0x00000224L
 +#define DOMAIN_ALIAS_RID_SYSTEM_OPS             0x00000225L
 +#define DOMAIN_ALIAS_RID_PRINT_OPS              0x00000226L
 +#define DOMAIN_ALIAS_RID_BACKUP_OPS             0x00000227L
 +
 +#define DOMAIN_ALIAS_RID_REPLICATOR             0x00000228L
 +#define DOMAIN_ALIAS_RID_RAS_SERVERS            0x00000229L
 +#define DOMAIN_ALIAS_RID_PREW2KCOMPACCESS       0x0000022AL
 +#define DOMAIN_ALIAS_RID_REMOTE_DESKTOP_USERS   0x0000022BL
 +#define DOMAIN_ALIAS_RID_NETWORK_CONFIGURATION_OPS 0x0000022CL
 +#define DOMAIN_ALIAS_RID_INCOMING_FOREST_TRUST_BUILDERS 0x0000022DL
 +
 +#define DOMAIN_ALIAS_RID_MONITORING_USERS       0x0000022EL
 +#define DOMAIN_ALIAS_RID_LOGGING_USERS          0x0000022FL
 +#define DOMAIN_ALIAS_RID_AUTHORIZATIONACCESS    0x00000230L
 +#define DOMAIN_ALIAS_RID_TS_LICENSE_SERVERS     0x00000231L
 +#define DOMAIN_ALIAS_RID_DCOM_USERS             0x00000232L
 +
 +#define SECURITY_MANDATORY_LABEL_AUTHORITY  {0,0,0,0,0,16}
 +
 +typedef enum {
 +  WinNullSid = 0,
 +  WinWorldSid = 1,
 +  WinLocalSid = 2,
 +  WinCreatorOwnerSid = 3,
 +  WinCreatorGroupSid = 4,
 +  WinCreatorOwnerServerSid = 5,
 +  WinCreatorGroupServerSid = 6,
 +  WinNtAuthoritySid = 7,
 +  WinDialupSid = 8,
 +  WinNetworkSid = 9,
 +  WinBatchSid = 10,
 +  WinInteractiveSid = 11,
 +  WinServiceSid = 12,
 +  WinAnonymousSid = 13,
 +  WinProxySid = 14,
 +  WinEnterpriseControllersSid = 15,
 +  WinSelfSid = 16,
 +  WinAuthenticatedUserSid = 17,
 +  WinRestrictedCodeSid = 18,
 +  WinTerminalServerSid = 19,
 +  WinRemoteLogonIdSid = 20,
 +  WinLogonIdsSid = 21,
 +  WinLocalSystemSid = 22,
 +  WinLocalServiceSid = 23,
 +  WinNetworkServiceSid = 24,
 +  WinBuiltinDomainSid = 25,
 +  WinBuiltinAdministratorsSid = 26,
 +  WinBuiltinUsersSid = 27,
 +  WinBuiltinGuestsSid = 28,
 +  WinBuiltinPowerUsersSid = 29,
 +  WinBuiltinAccountOperatorsSid = 30,
 +  WinBuiltinSystemOperatorsSid = 31,
 +  WinBuiltinPrintOperatorsSid = 32,
 +  WinBuiltinBackupOperatorsSid = 33,
 +  WinBuiltinReplicatorSid = 34,
 +  WinBuiltinPreWindows2000CompatibleAccessSid = 35,
 +  WinBuiltinRemoteDesktopUsersSid = 36,
 +  WinBuiltinNetworkConfigurationOperatorsSid = 37,
 +  WinAccountAdministratorSid = 38,
 +  WinAccountGuestSid = 39,
 +  WinAccountKrbtgtSid = 40,
 +  WinAccountDomainAdminsSid = 41,
 +  WinAccountDomainUsersSid = 42,
 +  WinAccountDomainGuestsSid = 43,
 +  WinAccountComputersSid = 44,
 +  WinAccountControllersSid = 45,
 +  WinAccountCertAdminsSid = 46,
 +  WinAccountSchemaAdminsSid = 47,
 +  WinAccountEnterpriseAdminsSid = 48,
 +  WinAccountPolicyAdminsSid = 49,
 +  WinAccountRasAndIasServersSid = 50,
 +  WinNTLMAuthenticationSid = 51,
 +  WinDigestAuthenticationSid = 52,
 +  WinSChannelAuthenticationSid = 53,
 +  WinThisOrganizationSid = 54,
 +  WinOtherOrganizationSid = 55,
 +  WinBuiltinIncomingForestTrustBuildersSid = 56,
 +  WinBuiltinPerfMonitoringUsersSid = 57,
 +  WinBuiltinPerfLoggingUsersSid = 58,
 +  WinBuiltinAuthorizationAccessSid = 59,
 +  WinBuiltinTerminalServerLicenseServersSid = 60,
 +  WinBuiltinDCOMUsersSid = 61,
 +  WinBuiltinIUsersSid = 62,
 +  WinIUserSid = 63,
 +  WinBuiltinCryptoOperatorsSid = 64,
 +  WinUntrustedLabelSid = 65,
 +  WinLowLabelSid = 66,
 +  WinMediumLabelSid = 67,
 +  WinHighLabelSid = 68,
 +  WinSystemLabelSid = 69,
 +  WinWriteRestrictedCodeSid = 70,
 +  WinCreatorOwnerRightsSid = 71,
 +  WinCacheablePrincipalsGroupSid = 72,
 +  WinNonCacheablePrincipalsGroupSid = 73,
 +  WinEnterpriseReadonlyControllersSid = 74,
 +  WinAccountReadonlyControllersSid = 75,
 +  WinBuiltinEventLogReadersGroup = 76,
 +  WinNewEnterpriseReadonlyControllersSid = 77,
 +  WinBuiltinCertSvcDComAccessGroup = 78,
 +  WinMediumPlusLabelSid = 79,
 +  WinLocalLogonSid = 80,
 +  WinConsoleLogonSid = 81,
 +  WinThisOrganizationCertificateSid = 82,
 +} WELL_KNOWN_SID_TYPE;
 +
 +#define SE_CREATE_TOKEN_NAME  TEXT("SeCreateTokenPrivilege")
 +#define SE_ASSIGNPRIMARYTOKEN_NAME    TEXT("SeAssignPrimaryTokenPrivilege")
 +#define SE_LOCK_MEMORY_NAME   TEXT("SeLockMemoryPrivilege")
 +#define SE_INCREASE_QUOTA_NAME        TEXT("SeIncreaseQuotaPrivilege")
 +#define SE_UNSOLICITED_INPUT_NAME     TEXT("SeUnsolicitedInputPrivilege")
 +#define SE_MACHINE_ACCOUNT_NAME TEXT("SeMachineAccountPrivilege")
 +#define SE_TCB_NAME   TEXT("SeTcbPrivilege")
 +#define SE_SECURITY_NAME      TEXT("SeSecurityPrivilege")
 +#define SE_TAKE_OWNERSHIP_NAME        TEXT("SeTakeOwnershipPrivilege")
 +#define SE_LOAD_DRIVER_NAME   TEXT("SeLoadDriverPrivilege")
 +#define SE_SYSTEM_PROFILE_NAME        TEXT("SeSystemProfilePrivilege")
 +#define SE_SYSTEMTIME_NAME    TEXT("SeSystemtimePrivilege")
 +#define SE_PROF_SINGLE_PROCESS_NAME   TEXT("SeProfileSingleProcessPrivilege")
 +#define SE_INC_BASE_PRIORITY_NAME     TEXT("SeIncreaseBasePriorityPrivilege")
 +#define SE_CREATE_PAGEFILE_NAME TEXT("SeCreatePagefilePrivilege")
 +#define SE_CREATE_PERMANENT_NAME      TEXT("SeCreatePermanentPrivilege")
 +#define SE_BACKUP_NAME TEXT("SeBackupPrivilege")
 +#define SE_RESTORE_NAME       TEXT("SeRestorePrivilege")
 +#define SE_SHUTDOWN_NAME      TEXT("SeShutdownPrivilege")
 +#define SE_DEBUG_NAME TEXT("SeDebugPrivilege")
 +#define SE_AUDIT_NAME TEXT("SeAuditPrivilege")
 +#define SE_SYSTEM_ENVIRONMENT_NAME    TEXT("SeSystemEnvironmentPrivilege")
 +#define SE_CHANGE_NOTIFY_NAME TEXT("SeChangeNotifyPrivilege")
 +#define SE_REMOTE_SHUTDOWN_NAME       TEXT("SeRemoteShutdownPrivilege")
 +#define SE_UNDOCK_NAME        TEXT("SeUndockPrivilege")
 +#define SE_SYNC_AGENT_NAME    TEXT("SeSyncAgentPrivilege")
 +#define SE_ENABLE_DELEGATION_NAME     TEXT("SeEnableDelegationPrivilege")
 +#define SE_MANAGE_VOLUME_NAME TEXT("SeManageVolumePrivilege")
 +#define SE_IMPERSONATE_NAME   TEXT("SeImpersonatePrivilege")
 +#define SE_CREATE_GLOBAL_NAME TEXT("SeCreateGlobalPrivilege")
 +#define SE_GROUP_MANDATORY 1
 +#define SE_GROUP_ENABLED_BY_DEFAULT 2
 +#define SE_GROUP_ENABLED 4
 +#define SE_GROUP_OWNER 8
 +#define SE_GROUP_USE_FOR_DENY_ONLY 16
 +#define SE_GROUP_LOGON_ID 3221225472U
 +#define SE_GROUP_RESOURCE 536870912
 +#define LANG_NEUTRAL   0x00
 +#define LANG_INVARIANT   0x7f
 +#define LANG_AFRIKAANS   0x36
 +#define LANG_ALBANIAN   0x1c
 +#define LANG_ALSATIAN   0x84
 +#define LANG_AMHARIC   0x5e
 +#define LANG_ARABIC   0x01
 +#define LANG_ARMENIAN   0x2b
 +#define LANG_ASSAMESE   0x4d
 +#define LANG_AZERI   0x2c
 +#define LANG_BASHKIR   0x6d
 +#define LANG_BASQUE   0x2d
 +#define LANG_BELARUSIAN   0x23
 +#define LANG_BENGALI   0x45
 +#define LANG_BOSNIAN   0x1a
 +#define LANG_BRETON   0x7e
 +#define LANG_BULGARIAN   0x02
 +#define LANG_CATALAN   0x03
 +#define LANG_CHINESE   0x04
 +#define LANG_CHINESE_SIMPLIFIED   0x04
 +#define LANG_CORSICAN   0x83
 +#define LANG_CROATIAN   0x1a
 +#define LANG_CROATIAN   0x1a
 +#define LANG_CZECH   0x05
 +#define LANG_DANISH   0x06
 +#define LANG_DARI   0x8c
 +#define LANG_DIVEHI   0x65
 +#define LANG_DUTCH   0x13
 +#define LANG_ENGLISH   0x09
 +#define LANG_ESTONIAN   0x25
 +#define LANG_FAEROESE   0x38
 +#define LANG_FILIPINO   0x64
 +#define LANG_FINNISH   0x0b
 +#define LANG_FRENCH   0x0c
 +#define LANG_FRISIAN   0x62
 +#define LANG_GALICIAN   0x56
 +#define LANG_GEORGIAN   0x37
 +#define LANG_GERMAN   0x07
 +#define LANG_GREEK   0x08
 +#define LANG_GREENLANDIC   0x6f
 +#define LANG_GUJARATI   0x47