Index: /trunk/src/VBox/Additions/WINNT/VBoxTray/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Additions/WINNT/VBoxTray/Makefile.kmk	(revision 26291)
+++ /trunk/src/VBox/Additions/WINNT/VBoxTray/Makefile.kmk	(revision 26292)
@@ -37,6 +37,4 @@
 	VBoxVRDP.cpp \
 	VBoxRestore.cpp \
-	VBoxStatistics.cpp \
-	VBoxMemBalloon.cpp \
 	helpers.cpp \
 	VBoxTray.rc
Index: unk/src/VBox/Additions/WINNT/VBoxTray/VBoxMemBalloon.cpp
===================================================================
--- /trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxMemBalloon.cpp	(revision 26291)
+++ 	(revision )
@@ -1,162 +1,0 @@
-/* $Id: $ */
-/** @file
- * VBoxMemBalloon - Memory balloon notification.
- */
-
-/*
- * Copyright (C) 2006-2007 Sun Microsystems, Inc.
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
- * Clara, CA 95054 USA or visit http://www.sun.com if you need
- * additional information or have any questions.
- */
-#define _WIN32_WINNT 0x0500
-#include <windows.h>
-#include <psapi.h>
-#include "VBoxTray.h"
-#include "VBoxMemBalloon.h"
-#include <VBoxDisplay.h>
-#include <VBox/VMMDev.h>
-#include <VBoxGuestInternal.h>
-#include <iprt/assert.h>
-#include "helpers.h"
-#include <winternl.h>
-
-typedef struct _VBOXMEMBALLOONCONTEXT
-{
-    const VBOXSERVICEENV *pEnv;
-    uint32_t              uMemBalloonSize;
-} VBOXMEMBALLOONCONTEXT;
-
-
-static VBOXMEMBALLOONCONTEXT gCtx = {0};
-
-
-int VBoxMemBalloonInit(const VBOXSERVICEENV *pEnv, void **ppInstance, bool *pfStartThread)
-{
-    HANDLE gVBoxDriver = pEnv->hDriver;
-    DWORD  cbReturned;
-
-    Log(("VBoxMemBalloonInit: Init\n"));
-
-    gCtx.pEnv                   = pEnv;
-    gCtx.uMemBalloonSize        = 0;
-
-    /* Check balloon size */
-    DWORD dwMemBalloonSize;
-    if (DeviceIoControl(gVBoxDriver, VBOXGUEST_IOCTL_CTL_CHECK_BALLOON_MASK, NULL, 0, &dwMemBalloonSize, sizeof(dwMemBalloonSize), &cbReturned, NULL))
-    {
-        Log(("VBoxMemBalloonInit: new balloon size %d MB\n", dwMemBalloonSize));
-        gCtx.uMemBalloonSize = dwMemBalloonSize;
-    }
-    else
-        Log(("VBoxMemBalloonInit: DeviceIoControl (balloon) failed with %d\n", GetLastError()));
-
-    *pfStartThread = true;
-    *ppInstance = &gCtx;
-    return VINF_SUCCESS;
-}
-
-
-void VBoxMemBalloonDestroy(const VBOXSERVICEENV *pEnv, void *pInstance)
-{
-    Log(("VBoxMemBalloonDestroy\n"));
-    return;
-}
-
-uint32_t VBoxMemBalloonQuerySize()
-{
-    return gCtx.uMemBalloonSize;
-}
-
-/**
- * Thread function to wait for and process seamless mode change
- * requests
- */
-unsigned __stdcall VBoxMemBalloonThread(void *pInstance)
-{
-    VBOXMEMBALLOONCONTEXT *pCtx = (VBOXMEMBALLOONCONTEXT *)pInstance;
-    HANDLE gVBoxDriver = pCtx->pEnv->hDriver;
-    bool fTerminate = false;
-    VBoxGuestFilterMaskInfo maskInfo;
-    DWORD cbReturned;
-
-    maskInfo.u32OrMask = VMMDEV_EVENT_BALLOON_CHANGE_REQUEST;
-    maskInfo.u32NotMask = 0;
-    if (DeviceIoControl (gVBoxDriver, VBOXGUEST_IOCTL_CTL_FILTER_MASK, &maskInfo, sizeof (maskInfo), NULL, 0, &cbReturned, NULL))
-    {
-        Log(("VBoxMemBalloonThread: DeviceIOControl(CtlMask - or) succeeded\n"));
-    }
-    else
-    {
-        Log(("VBoxMemBalloonThread: DeviceIOControl(CtlMask) failed, SeamlessChangeThread exited\n"));
-        return 0;
-    }
-
-    do
-    {
-        /* wait for a seamless change event */
-        VBoxGuestWaitEventInfo waitEvent;
-        waitEvent.u32TimeoutIn = 5000;
-        waitEvent.u32EventMaskIn = VMMDEV_EVENT_BALLOON_CHANGE_REQUEST;
-        if (DeviceIoControl(gVBoxDriver, VBOXGUEST_IOCTL_WAITEVENT, &waitEvent, sizeof(waitEvent), &waitEvent, sizeof(waitEvent), &cbReturned, NULL))
-        {
-            Log(("VBoxMemBalloonThread: DeviceIOControl succeded\n"));
-
-            /* are we supposed to stop? */
-            if (WaitForSingleObject(pCtx->pEnv->hStopEvent, 0) == WAIT_OBJECT_0)
-                break;
-
-            Log(("VBoxMemBalloonThread: checking event\n"));
-
-            /* did we get the right event? */
-            if (waitEvent.u32EventFlagsOut & VMMDEV_EVENT_BALLOON_CHANGE_REQUEST)
-            {
-                DWORD dwMemBalloonSize;
-                if (DeviceIoControl(gVBoxDriver, VBOXGUEST_IOCTL_CTL_CHECK_BALLOON_MASK, NULL, 0, &dwMemBalloonSize, sizeof(dwMemBalloonSize), &cbReturned, NULL))
-                {
-                    Log(("VBoxMemBalloonThread: new balloon size % MB\n", dwMemBalloonSize));
-                    pCtx->uMemBalloonSize = dwMemBalloonSize;
-                }
-                else
-                    Log(("VBoxMemBalloonThread: DeviceIoControl (balloon) failed with %d\n", GetLastError()));
-            }
-        }
-        else
-        {
-            Log(("VBoxMemBalloonThread: error 0 from DeviceIoControl VBOXGUEST_IOCTL_WAITEVENT\n"));
-
-            /* sleep a bit to not eat too much CPU in case the above call always fails */
-            if (WaitForSingleObject(pCtx->pEnv->hStopEvent, 10) == WAIT_OBJECT_0)
-            {
-                fTerminate = true;
-                break;
-            }
-        }
-    }
-    while (!fTerminate);
-
-    maskInfo.u32OrMask = 0;
-    maskInfo.u32NotMask = VMMDEV_EVENT_BALLOON_CHANGE_REQUEST;
-    if (DeviceIoControl (gVBoxDriver, VBOXGUEST_IOCTL_CTL_FILTER_MASK, &maskInfo, sizeof (maskInfo), NULL, 0, &cbReturned, NULL))
-    {
-        Log(("VBoxMemBalloonThread: DeviceIOControl(CtlMask - not) succeeded\n"));
-    }
-    else
-    {
-        Log(("VBoxMemBalloonThread: DeviceIOControl(CtlMask) failed\n"));
-    }
-
-    Log(("VBoxMemBalloonThread: finished mem balloon change request thread\n"));
-    return 0;
-}
-
-
Index: unk/src/VBox/Additions/WINNT/VBoxTray/VBoxMemBalloon.h
===================================================================
--- /trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxMemBalloon.h	(revision 26291)
+++ 	(revision )
@@ -1,32 +1,0 @@
-/** @file
- *
- * VBoxMemBalloon - Memory balloon notification
- */
-
-/*
- * Copyright (C) 2006-2007 Sun Microsystems, Inc.
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
- * Clara, CA 95054 USA or visit http://www.sun.com if you need
- * additional information or have any questions.
- */
-
-#ifndef __VBOXSERVICEMEMBALLOON__H
-#define __VBOXSERVICEMEMBALLOON__H
-
-/* The guest management service prototypes. */
-int                VBoxMemBalloonInit    (const VBOXSERVICEENV *pEnv, void **ppInstance, bool *pfStartThread);
-unsigned __stdcall VBoxMemBalloonThread  (void *pInstance);
-void               VBoxMemBalloonDestroy (const VBOXSERVICEENV *pEnv, void *pInstance);
-
-uint32_t           VBoxMemBalloonQuerySize();
-
-#endif /* __VBOXSERVICEMEMBALLOON__H */
Index: unk/src/VBox/Additions/WINNT/VBoxTray/VBoxStatistics.cpp
===================================================================
--- /trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxStatistics.cpp	(revision 26291)
+++ 	(revision )
@@ -1,328 +1,0 @@
-/* $Id: $ */
-/** @file
- * VBoxStats - Guest statistics notification
- */
-
-/*
- * Copyright (C) 2006-2007 Sun Microsystems, Inc.
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
- * Clara, CA 95054 USA or visit http://www.sun.com if you need
- * additional information or have any questions.
- */
-#define _WIN32_WINNT 0x0500
-#include <windows.h>
-#include <psapi.h>
-#include "VBoxTray.h"
-#include "VBoxStatistics.h"
-#include "VBoxMemBalloon.h"
-#include <VBoxDisplay.h>
-#include <VBox/VMMDev.h>
-#include <VBox/VBoxGuest.h>
-#include <VBoxGuestInternal.h>
-#include <iprt/assert.h>
-#include "helpers.h"
-#include <winternl.h>
-
-typedef struct _VBOXSTATSCONTEXT
-{
-    const VBOXSERVICEENV *pEnv;
-    uint32_t              uStatInterval;
-
-    uint64_t              ullLastCpuLoad_Idle;
-    uint64_t              ullLastCpuLoad_Kernel;
-    uint64_t              ullLastCpuLoad_User;
-
-    NTSTATUS (WINAPI *pfnNtQuerySystemInformation)(SYSTEM_INFORMATION_CLASS SystemInformationClass, PVOID SystemInformation, ULONG SystemInformationLength, PULONG ReturnLength);
-    void     (WINAPI *pfnGlobalMemoryStatusEx)(LPMEMORYSTATUSEX lpBuffer);
-    BOOL     (WINAPI *pfnGetPerformanceInfo)(PPERFORMANCE_INFORMATION pPerformanceInformation, DWORD cb);
-} VBOXSTATSCONTEXT;
-
-
-static VBOXSTATSCONTEXT gCtx = {0};
-
-
-int VBoxStatsInit(const VBOXSERVICEENV *pEnv, void **ppInstance, bool *pfStartThread)
-{
-    HANDLE gVBoxDriver = pEnv->hDriver;
-    DWORD  cbReturned;
-
-    Log(("VBoxStatsInit\n"));
-
-    gCtx.pEnv                   = pEnv;
-    gCtx.uStatInterval          = 0;     /* default */
-    gCtx.ullLastCpuLoad_Idle    = 0;
-    gCtx.ullLastCpuLoad_Kernel  = 0;
-    gCtx.ullLastCpuLoad_User    = 0;
-
-    VMMDevGetStatisticsChangeRequest req;
-    vmmdevInitRequest(&req.header, VMMDevReq_GetStatisticsChangeRequest);
-    req.eventAck = 0;
-
-    if (DeviceIoControl(gVBoxDriver, VBOXGUEST_IOCTL_VMMREQUEST(req.header.size), &req, req.header.size, &req, req.header.size, &cbReturned, NULL))
-    {
-        Log(("VBoxStatsInit: new statistics interval %d seconds\n", req.u32StatInterval));
-        gCtx.uStatInterval = req.u32StatInterval * 1000;
-    }
-    else
-        Log(("VBoxStatsInit: DeviceIoControl failed with %d\n", GetLastError()));
-
-    /* NtQuerySystemInformation might be dropped in future releases, so load it dynamically as per Microsoft's recommendation */
-    HMODULE hMod = LoadLibrary("NTDLL.DLL");
-    if (hMod)
-    {
-        *(uintptr_t *)&gCtx.pfnNtQuerySystemInformation = (uintptr_t)GetProcAddress(hMod, "NtQuerySystemInformation");
-        if (gCtx.pfnNtQuerySystemInformation)
-            Log(("gCtx.pfnNtQuerySystemInformation = %x\n", gCtx.pfnNtQuerySystemInformation));
-        else
-        {
-            Log(("NTDLL.NtQuerySystemInformation not found!!\n"));
-            return VERR_NOT_IMPLEMENTED;
-        }
-    }
-
-    /* GlobalMemoryStatus is win2k and up, so load it dynamically */
-    hMod = LoadLibrary("KERNEL32.DLL");
-    if (hMod)
-    {
-        *(uintptr_t *)&gCtx.pfnGlobalMemoryStatusEx = (uintptr_t)GetProcAddress(hMod, "GlobalMemoryStatusEx");
-        if (gCtx.pfnGlobalMemoryStatusEx)
-            Log(("gCtx.GlobalMemoryStatusEx = %x\n", gCtx.pfnGlobalMemoryStatusEx));
-        else
-        {
-            /** @todo now fails in NT4; do we care? */
-            Log(("KERNEL32.GlobalMemoryStatusEx not found!!\n"));
-            return VERR_NOT_IMPLEMENTED;
-        }
-    }
-    /* GetPerformanceInfo is xp and up, so load it dynamically */
-    hMod = LoadLibrary("PSAPI.DLL");
-    if (hMod)
-    {
-        *(uintptr_t *)&gCtx.pfnGetPerformanceInfo = (uintptr_t)GetProcAddress(hMod, "GetPerformanceInfo");
-        if (gCtx.pfnGetPerformanceInfo)
-            Log(("gCtx.pfnGetPerformanceInfo= %x\n", gCtx.pfnGetPerformanceInfo));
-        /* failure is not fatal */
-    }
-
-    *pfStartThread = true;
-    *ppInstance = &gCtx;
-    return VINF_SUCCESS;
-}
-
-
-void VBoxStatsDestroy(const VBOXSERVICEENV *pEnv, void *pInstance)
-{
-    Log(("VBoxStatsDestroy\n"));
-    return;
-}
-
-void VBoxStatsReportStatistics(VBOXSTATSCONTEXT *pCtx)
-{
-    SYSTEM_INFO systemInfo;
-    PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION pProcInfo;
-    MEMORYSTATUSEX memStatus;
-    VMMDevReportGuestStats req;
-    uint32_t cbStruct;
-    DWORD    cbReturned;
-    HANDLE   gVBoxDriver = pCtx->pEnv->hDriver;
-
-    Assert(gCtx.pfnGlobalMemoryStatusEx && gCtx.pfnNtQuerySystemInformation);
-    if (    !gCtx.pfnGlobalMemoryStatusEx
-        ||  !gCtx.pfnNtQuerySystemInformation)
-        return;
-
-    vmmdevInitRequest(&req.header, VMMDevReq_ReportGuestStats);
-
-    /* Query and report guest statistics */
-    GetSystemInfo(&systemInfo);
-
-    memStatus.dwLength = sizeof(memStatus);
-    gCtx.pfnGlobalMemoryStatusEx(&memStatus);
-
-    req.guestStats.u32PageSize          = systemInfo.dwPageSize;
-    req.guestStats.u32PhysMemTotal      = (uint32_t)(memStatus.ullTotalPhys / systemInfo.dwPageSize);
-    req.guestStats.u32PhysMemAvail      = (uint32_t)(memStatus.ullAvailPhys / systemInfo.dwPageSize);
-    /* The current size of the committed memory limit, in bytes. This is physical memory plus the size of the page file, minus a small overhead. */
-    req.guestStats.u32PageFileSize      = (uint32_t)(memStatus.ullTotalPageFile / systemInfo.dwPageSize) - req.guestStats.u32PhysMemTotal;
-    req.guestStats.u32MemoryLoad        = memStatus.dwMemoryLoad;
-    req.guestStats.u32PhysMemBalloon    = VBoxMemBalloonQuerySize() * (_1M/systemInfo.dwPageSize);    /* was in megabytes */
-    req.guestStats.u32StatCaps          = VBOX_GUEST_STAT_PHYS_MEM_TOTAL | VBOX_GUEST_STAT_PHYS_MEM_AVAIL | VBOX_GUEST_STAT_PAGE_FILE_SIZE | VBOX_GUEST_STAT_MEMORY_LOAD | VBOX_GUEST_STAT_PHYS_MEM_BALLOON;
-
-    if (gCtx.pfnGetPerformanceInfo)
-    {
-        PERFORMANCE_INFORMATION perfInfo;
-
-        if (gCtx.pfnGetPerformanceInfo(&perfInfo, sizeof(perfInfo)))
-        {
-            req.guestStats.u32Processes         = perfInfo.ProcessCount;
-            req.guestStats.u32Threads           = perfInfo.ThreadCount;
-            req.guestStats.u32Handles           = perfInfo.HandleCount;
-            req.guestStats.u32MemCommitTotal    = perfInfo.CommitTotal;     /* already in pages */
-            req.guestStats.u32MemKernelTotal    = perfInfo.KernelTotal;     /* already in pages */
-            req.guestStats.u32MemKernelPaged    = perfInfo.KernelPaged;     /* already in pages */
-            req.guestStats.u32MemKernelNonPaged = perfInfo.KernelNonpaged;  /* already in pages */
-            req.guestStats.u32MemSystemCache    = perfInfo.SystemCache;     /* already in pages */
-            req.guestStats.u32StatCaps |= VBOX_GUEST_STAT_PROCESSES | VBOX_GUEST_STAT_THREADS | VBOX_GUEST_STAT_HANDLES | VBOX_GUEST_STAT_MEM_COMMIT_TOTAL | VBOX_GUEST_STAT_MEM_KERNEL_TOTAL | VBOX_GUEST_STAT_MEM_KERNEL_PAGED | VBOX_GUEST_STAT_MEM_KERNEL_NONPAGED | VBOX_GUEST_STAT_MEM_SYSTEM_CACHE;
-        }
-        else
-            Log(("GetPerformanceInfo failed with %d\n", GetLastError()));
-    }
-
-    /* Query CPU load information */
-    cbStruct = systemInfo.dwNumberOfProcessors*sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION);
-    pProcInfo = (PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)malloc(cbStruct);
-    Assert(pProcInfo);
-    if (!pProcInfo)
-        return;
-
-    /* Unfortunately GetSystemTimes is XP SP1 and up only, so we need to use the semi-undocumented NtQuerySystemInformation */
-    NTSTATUS rc = gCtx.pfnNtQuerySystemInformation(SystemProcessorPerformanceInformation, pProcInfo, cbStruct, &cbReturned);
-    if (    !rc
-        &&  cbReturned == cbStruct)
-    {
-        if (gCtx.ullLastCpuLoad_Kernel == 0)
-        {
-            /* first time */
-            gCtx.ullLastCpuLoad_Idle    = pProcInfo->IdleTime.QuadPart;
-            gCtx.ullLastCpuLoad_Kernel  = pProcInfo->KernelTime.QuadPart;
-            gCtx.ullLastCpuLoad_User    = pProcInfo->UserTime.QuadPart;
-
-            Sleep(250);
-
-            rc = gCtx.pfnNtQuerySystemInformation(SystemProcessorPerformanceInformation, pProcInfo, cbStruct, &cbReturned);
-            Assert(!rc);
-        }
-
-        uint64_t deltaIdle    = (pProcInfo->IdleTime.QuadPart - gCtx.ullLastCpuLoad_Idle);
-        uint64_t deltaKernel  = (pProcInfo->KernelTime.QuadPart - gCtx.ullLastCpuLoad_Kernel);
-        uint64_t deltaUser    = (pProcInfo->UserTime.QuadPart - gCtx.ullLastCpuLoad_User);
-        deltaKernel          -= deltaIdle;  /* idle time is added to kernel time */
-        uint64_t ullTotalTime = deltaIdle + deltaKernel + deltaUser;
-
-        req.guestStats.u32CpuLoad_Idle      = (uint32_t)(deltaIdle  * 100 / ullTotalTime);
-        req.guestStats.u32CpuLoad_Kernel    = (uint32_t)(deltaKernel* 100 / ullTotalTime);
-        req.guestStats.u32CpuLoad_User      = (uint32_t)(deltaUser  * 100 / ullTotalTime);
-
-        req.guestStats.u32StatCaps |= VBOX_GUEST_STAT_CPU_LOAD_IDLE | VBOX_GUEST_STAT_CPU_LOAD_KERNEL | VBOX_GUEST_STAT_CPU_LOAD_USER;
-
-        gCtx.ullLastCpuLoad_Idle    = pProcInfo->IdleTime.QuadPart;
-        gCtx.ullLastCpuLoad_Kernel  = pProcInfo->KernelTime.QuadPart;
-        gCtx.ullLastCpuLoad_User    = pProcInfo->UserTime.QuadPart;
-    }
-
-    for (uint32_t i=0;i<systemInfo.dwNumberOfProcessors;i++)
-    {
-        req.guestStats.u32CpuId = i;
-
-        if (DeviceIoControl(gVBoxDriver, VBOXGUEST_IOCTL_VMMREQUEST(req.header.size), &req, req.header.size, &req, req.header.size, &cbReturned, NULL))
-        {
-            Log(("VBoxStatsReportStatistics: new statistics reported successfully!\n"));
-        }
-        else
-            Log(("VBoxStatsReportStatistics: DeviceIoControl (stats report) failed with %d\n", GetLastError()));
-    }
-
-    free(pProcInfo);
-}
-
-/**
- * Thread function to wait for and process seamless mode change
- * requests
- */
-unsigned __stdcall VBoxStatsThread(void *pInstance)
-{
-    VBOXSTATSCONTEXT *pCtx = (VBOXSTATSCONTEXT *)pInstance;
-    HANDLE gVBoxDriver = pCtx->pEnv->hDriver;
-    bool fTerminate = false;
-    VBoxGuestFilterMaskInfo maskInfo;
-    DWORD cbReturned;
-
-    maskInfo.u32OrMask = VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE_REQUEST;
-    maskInfo.u32NotMask = 0;
-    if (DeviceIoControl (gVBoxDriver, VBOXGUEST_IOCTL_CTL_FILTER_MASK, &maskInfo, sizeof (maskInfo), NULL, 0, &cbReturned, NULL))
-    {
-        Log(("VBoxStatsThread: DeviceIOControl(CtlMask - or) succeeded\n"));
-    }
-    else
-    {
-        Log(("VBoxStatsThread: DeviceIOControl(CtlMask) failed, SeamlessChangeThread exited\n"));
-        return 0;
-    }
-
-    do
-    {
-        /* wait for a seamless change event */
-        VBoxGuestWaitEventInfo waitEvent;
-        waitEvent.u32TimeoutIn = (pCtx->uStatInterval) ? pCtx->uStatInterval : 5000;
-        waitEvent.u32EventMaskIn = VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE_REQUEST;
-        if (DeviceIoControl(gVBoxDriver, VBOXGUEST_IOCTL_WAITEVENT, &waitEvent, sizeof(waitEvent), &waitEvent, sizeof(waitEvent), &cbReturned, NULL))
-        {
-            Log(("VBoxStatsThread: DeviceIOControl succeded\n"));
-
-            /* are we supposed to stop? */
-            if (WaitForSingleObject(pCtx->pEnv->hStopEvent, 0) == WAIT_OBJECT_0)
-                break;
-
-            Log(("VBoxStatsThread: checking event\n"));
-
-            /* did we get the right event? */
-            if (waitEvent.u32EventFlagsOut & VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE_REQUEST)
-            {
-                VMMDevGetStatisticsChangeRequest req;
-                vmmdevInitRequest(&req.header, VMMDevReq_GetStatisticsChangeRequest);
-                req.eventAck = VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE_REQUEST;
-
-                if (DeviceIoControl(gVBoxDriver, VBOXGUEST_IOCTL_VMMREQUEST(req.header.size), &req, req.header.size, &req, req.header.size, &cbReturned, NULL))
-                {
-                    Log(("VBoxStatsThread: new statistics interval %d seconds\n", req.u32StatInterval));
-                    pCtx->uStatInterval = req.u32StatInterval * 1000;
-                }
-                else
-                    Log(("VBoxStatsThread: DeviceIoControl (stat) failed with %d\n", GetLastError()));
-            }
-        }
-        else
-        {
-            Log(("VBoxStatsThread: error 0 from DeviceIoControl VBOXGUEST_IOCTL_WAITEVENT\n"));
-
-            /* sleep a bit to not eat too much CPU in case the above call always fails */
-            if (WaitForSingleObject(pCtx->pEnv->hStopEvent, 10) == WAIT_OBJECT_0)
-            {
-                fTerminate = true;
-                break;
-            }
-        }
-        /* Report statistics to the host */
-        if (    gCtx.uStatInterval
-            &&  gCtx.pfnNtQuerySystemInformation)
-        {
-            VBoxStatsReportStatistics(pCtx);
-        }
-    }
-    while (!fTerminate);
-
-    maskInfo.u32OrMask = 0;
-    maskInfo.u32NotMask = VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE_REQUEST;
-    if (DeviceIoControl (gVBoxDriver, VBOXGUEST_IOCTL_CTL_FILTER_MASK, &maskInfo, sizeof (maskInfo), NULL, 0, &cbReturned, NULL))
-    {
-        Log(("VBoxStatsThread: DeviceIOControl(CtlMask - not) succeeded\n"));
-    }
-    else
-    {
-        Log(("VBoxStatsThread: DeviceIOControl(CtlMask) failed\n"));
-    }
-
-    Log(("VBoxStatsThread: finished statistics change request thread\n"));
-    return 0;
-}
-
-
Index: unk/src/VBox/Additions/WINNT/VBoxTray/VBoxStatistics.h
===================================================================
--- /trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxStatistics.h	(revision 26291)
+++ 	(revision )
@@ -1,29 +1,0 @@
-/** @file
- * VBoxGuest - Guest statistics notification
- */
-
-/*
- * Copyright (C) 2006-2007 Sun Microsystems, Inc.
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
- * Clara, CA 95054 USA or visit http://www.sun.com if you need
- * additional information or have any questions.
- */
-
-#ifndef __VBOXSERVICESTATS__H
-#define __VBOXSERVICESTATS__H
-
-/* The guest management service prototypes. */
-int                VBoxStatsInit    (const VBOXSERVICEENV *pEnv, void **ppInstance, bool *pfStartThread);
-unsigned __stdcall VBoxStatsThread  (void *pInstance);
-void               VBoxStatsDestroy (const VBOXSERVICEENV *pEnv, void *pInstance);
-
-#endif /* __VBOXSERVICESTATS__H */
Index: /trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxTray.cpp
===================================================================
--- /trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxTray.cpp	(revision 26291)
+++ /trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxTray.cpp	(revision 26292)
@@ -25,6 +25,4 @@
 #include "VBoxRestore.h"
 #include "VBoxVRDP.h"
-#include "VBoxStatistics.h"
-#include "VBoxMemBalloon.h"
 #include "VBoxHostVersion.h"
 #include <VBoxHook.h>
@@ -72,18 +70,4 @@
         VBoxSeamlessDestroy
     },
-#ifdef VBOX_WITH_MANAGEMENT
-    {
-        "Memory Balloon",
-        VBoxMemBalloonInit,
-        VBoxMemBalloonThread,
-        VBoxMemBalloonDestroy,
-    },
-    {
-        "Guest Statistics",
-        VBoxStatsInit,
-        VBoxStatsThread,
-        VBoxStatsDestroy,
-    },
-#endif
 #ifdef VBOX_WITH_VRDP_SESSION_HANDLING
     {
Index: /trunk/src/VBox/Additions/common/VBoxService/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Additions/common/VBoxService/Makefile.kmk	(revision 26291)
+++ /trunk/src/VBox/Additions/common/VBoxService/Makefile.kmk	(revision 26292)
@@ -34,5 +34,6 @@
 VBoxService_TEMPLATE      = VBOXGUESTR3EXE
 VBoxService_DEFS          = VBOXSERVICE_TIMESYNC
-VBoxService_DEFS.win     += _WIN32_WINNT=0x0501
+VBoxService_DEFS.win     += _WIN32_WINNT=0x0501 
+##VBOXSERVICE_MANAGEMENT
 VBoxService_DEFS.os2      = VBOX_WITH_HGCM VBOXSERVICE_CLIPBOARD
 ifdef VBOX_WITH_GUEST_PROPS
@@ -67,4 +68,8 @@
 	VBoxService-win.rc \
 	VBoxService-win.cpp
+
+##	VBoxServiceStats.cpp \
+##	VBoxServiceBalloon.cpp
+
 VBoxService_SOURCES.os2   = \
 	VBoxService-os2.def \
Index: /trunk/src/VBox/Additions/common/VBoxService/VBoxService.cpp
===================================================================
--- /trunk/src/VBox/Additions/common/VBoxService/VBoxService.cpp	(revision 26291)
+++ /trunk/src/VBox/Additions/common/VBoxService/VBoxService.cpp	(revision 26292)
@@ -93,4 +93,8 @@
 #ifdef VBOXSERVICE_CPUHOTPLUG /* Disabled by default. Use --enable-cpuhotplug to enable */
     { &g_CpuHotPlug, NIL_RTTHREAD, false, false, false, false },
+#endif
+#ifdef VBOXSERVICE_MANAGEMENT
+    { &g_MemBalloon, NIL_RTTHREAD, false, false, false, false },
+    { &g_VMStatistics, NIL_RTTHREAD, false, false, false, false },
 #endif
 };
Index: /trunk/src/VBox/Additions/common/VBoxService/VBoxServiceBalloon.cpp
===================================================================
--- /trunk/src/VBox/Additions/common/VBoxService/VBoxServiceBalloon.cpp	(revision 26292)
+++ /trunk/src/VBox/Additions/common/VBoxService/VBoxServiceBalloon.cpp	(revision 26292)
@@ -0,0 +1,162 @@
+/* $Id: $ */
+/** @file
+ * VBoxMemBalloon - Memory balloon notification.
+ */
+
+/*
+ * Copyright (C) 2006-2007 Sun Microsystems, Inc.
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+#define _WIN32_WINNT 0x0500
+#include <windows.h>
+#include <psapi.h>
+#include "VBoxTray.h"
+#include "VBoxMemBalloon.h"
+#include <VBoxDisplay.h>
+#include <VBox/VMMDev.h>
+#include <VBoxGuestInternal.h>
+#include <iprt/assert.h>
+#include "helpers.h"
+#include <winternl.h>
+
+typedef struct _VBOXMEMBALLOONCONTEXT
+{
+    const VBOXSERVICEENV *pEnv;
+    uint32_t              uMemBalloonSize;
+} VBOXMEMBALLOONCONTEXT;
+
+
+static VBOXMEMBALLOONCONTEXT gCtx = {0};
+
+
+int VBoxMemBalloonInit(const VBOXSERVICEENV *pEnv, void **ppInstance, bool *pfStartThread)
+{
+    HANDLE gVBoxDriver = pEnv->hDriver;
+    DWORD  cbReturned;
+
+    Log(("VBoxMemBalloonInit: Init\n"));
+
+    gCtx.pEnv                   = pEnv;
+    gCtx.uMemBalloonSize        = 0;
+
+    /* Check balloon size */
+    DWORD dwMemBalloonSize;
+    if (DeviceIoControl(gVBoxDriver, VBOXGUEST_IOCTL_CTL_CHECK_BALLOON_MASK, NULL, 0, &dwMemBalloonSize, sizeof(dwMemBalloonSize), &cbReturned, NULL))
+    {
+        Log(("VBoxMemBalloonInit: new balloon size %d MB\n", dwMemBalloonSize));
+        gCtx.uMemBalloonSize = dwMemBalloonSize;
+    }
+    else
+        Log(("VBoxMemBalloonInit: DeviceIoControl (balloon) failed with %d\n", GetLastError()));
+
+    *pfStartThread = true;
+    *ppInstance = &gCtx;
+    return VINF_SUCCESS;
+}
+
+
+void VBoxMemBalloonDestroy(const VBOXSERVICEENV *pEnv, void *pInstance)
+{
+    Log(("VBoxMemBalloonDestroy\n"));
+    return;
+}
+
+uint32_t VBoxMemBalloonQuerySize()
+{
+    return gCtx.uMemBalloonSize;
+}
+
+/**
+ * Thread function to wait for and process seamless mode change
+ * requests
+ */
+unsigned __stdcall VBoxMemBalloonThread(void *pInstance)
+{
+    VBOXMEMBALLOONCONTEXT *pCtx = (VBOXMEMBALLOONCONTEXT *)pInstance;
+    HANDLE gVBoxDriver = pCtx->pEnv->hDriver;
+    bool fTerminate = false;
+    VBoxGuestFilterMaskInfo maskInfo;
+    DWORD cbReturned;
+
+    maskInfo.u32OrMask = VMMDEV_EVENT_BALLOON_CHANGE_REQUEST;
+    maskInfo.u32NotMask = 0;
+    if (DeviceIoControl (gVBoxDriver, VBOXGUEST_IOCTL_CTL_FILTER_MASK, &maskInfo, sizeof (maskInfo), NULL, 0, &cbReturned, NULL))
+    {
+        Log(("VBoxMemBalloonThread: DeviceIOControl(CtlMask - or) succeeded\n"));
+    }
+    else
+    {
+        Log(("VBoxMemBalloonThread: DeviceIOControl(CtlMask) failed, SeamlessChangeThread exited\n"));
+        return 0;
+    }
+
+    do
+    {
+        /* wait for a seamless change event */
+        VBoxGuestWaitEventInfo waitEvent;
+        waitEvent.u32TimeoutIn = 5000;
+        waitEvent.u32EventMaskIn = VMMDEV_EVENT_BALLOON_CHANGE_REQUEST;
+        if (DeviceIoControl(gVBoxDriver, VBOXGUEST_IOCTL_WAITEVENT, &waitEvent, sizeof(waitEvent), &waitEvent, sizeof(waitEvent), &cbReturned, NULL))
+        {
+            Log(("VBoxMemBalloonThread: DeviceIOControl succeded\n"));
+
+            /* are we supposed to stop? */
+            if (WaitForSingleObject(pCtx->pEnv->hStopEvent, 0) == WAIT_OBJECT_0)
+                break;
+
+            Log(("VBoxMemBalloonThread: checking event\n"));
+
+            /* did we get the right event? */
+            if (waitEvent.u32EventFlagsOut & VMMDEV_EVENT_BALLOON_CHANGE_REQUEST)
+            {
+                DWORD dwMemBalloonSize;
+                if (DeviceIoControl(gVBoxDriver, VBOXGUEST_IOCTL_CTL_CHECK_BALLOON_MASK, NULL, 0, &dwMemBalloonSize, sizeof(dwMemBalloonSize), &cbReturned, NULL))
+                {
+                    Log(("VBoxMemBalloonThread: new balloon size % MB\n", dwMemBalloonSize));
+                    pCtx->uMemBalloonSize = dwMemBalloonSize;
+                }
+                else
+                    Log(("VBoxMemBalloonThread: DeviceIoControl (balloon) failed with %d\n", GetLastError()));
+            }
+        }
+        else
+        {
+            Log(("VBoxMemBalloonThread: error 0 from DeviceIoControl VBOXGUEST_IOCTL_WAITEVENT\n"));
+
+            /* sleep a bit to not eat too much CPU in case the above call always fails */
+            if (WaitForSingleObject(pCtx->pEnv->hStopEvent, 10) == WAIT_OBJECT_0)
+            {
+                fTerminate = true;
+                break;
+            }
+        }
+    }
+    while (!fTerminate);
+
+    maskInfo.u32OrMask = 0;
+    maskInfo.u32NotMask = VMMDEV_EVENT_BALLOON_CHANGE_REQUEST;
+    if (DeviceIoControl (gVBoxDriver, VBOXGUEST_IOCTL_CTL_FILTER_MASK, &maskInfo, sizeof (maskInfo), NULL, 0, &cbReturned, NULL))
+    {
+        Log(("VBoxMemBalloonThread: DeviceIOControl(CtlMask - not) succeeded\n"));
+    }
+    else
+    {
+        Log(("VBoxMemBalloonThread: DeviceIOControl(CtlMask) failed\n"));
+    }
+
+    Log(("VBoxMemBalloonThread: finished mem balloon change request thread\n"));
+    return 0;
+}
+
+
Index: /trunk/src/VBox/Additions/common/VBoxService/VBoxServiceInternal.h
===================================================================
--- /trunk/src/VBox/Additions/common/VBoxService/VBoxServiceInternal.h	(revision 26291)
+++ /trunk/src/VBox/Additions/common/VBoxService/VBoxServiceInternal.h	(revision 26292)
@@ -146,4 +146,8 @@
 extern VBOXSERVICE g_Exec;
 extern VBOXSERVICE g_CpuHotPlug;
+#ifdef VBOXSERVICE_MANAGEMENT
+extern VBOXSERVICE g_MemBalloon;
+extern VBOXSERVICE g_VMStatistics;
+#endif
 
 #ifdef RT_OS_WINDOWS
Index: /trunk/src/VBox/Additions/common/VBoxService/VBoxServiceStats.cpp
===================================================================
--- /trunk/src/VBox/Additions/common/VBoxService/VBoxServiceStats.cpp	(revision 26292)
+++ /trunk/src/VBox/Additions/common/VBoxService/VBoxServiceStats.cpp	(revision 26292)
@@ -0,0 +1,374 @@
+/* $Id: $ */
+/** @file
+ * VBoxStats - Guest statistics notification
+ */
+
+/*
+ * Copyright (C) 2006-2007 Sun Microsystems, Inc.
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
+ * Clara, CA 95054 USA or visit http://www.sun.com if you need
+ * additional information or have any questions.
+ */
+#define _WIN32_WINNT 0x0500
+#include <windows.h>
+#include <psapi.h>
+#include "VBoxTray.h"
+#include <VBoxDisplay.h>
+#include <VBox/VMMDev.h>
+#include <VBox/VBoxGuest.h>
+#include <VBoxGuestInternal.h>
+#include <iprt/assert.h>
+#include "helpers.h"
+#include <winternl.h>
+
+typedef struct _VBOXSTATSCONTEXT
+{
+    uint32_t              uStatInterval;
+
+    uint64_t              ullLastCpuLoad_Idle;
+    uint64_t              ullLastCpuLoad_Kernel;
+    uint64_t              ullLastCpuLoad_User;
+
+#ifdef RT_OS_WINDOWS
+    NTSTATUS (WINAPI *pfnNtQuerySystemInformation)(SYSTEM_INFORMATION_CLASS SystemInformationClass, PVOID SystemInformation, ULONG SystemInformationLength, PULONG ReturnLength);
+    void     (WINAPI *pfnGlobalMemoryStatusEx)(LPMEMORYSTATUSEX lpBuffer);
+    BOOL     (WINAPI *pfnGetPerformanceInfo)(PPERFORMANCE_INFORMATION pPerformanceInformation, DWORD cb);
+#endif
+} VBOXSTATSCONTEXT;
+
+/*******************************************************************************
+*   Global Variables                                                           *
+*******************************************************************************/
+static VBOXSTATSCONTEXT gCtx = {0};
+
+/** The semaphore we're blocking on. */
+static RTSEMEVENTMULTI  g_VMStatEvent = NIL_RTSEMEVENTMULTI;
+/** The vmstats interval (millseconds). */
+uint32_t                g_VMStatsInterval = 0;
+
+
+/** @copydoc VBOXSERVICE::pfnPreInit */
+static DECLCALLBACK(int) VBoxServiceVMStatsPreInit(void)
+{
+    return VINF_SUCCESS;
+}
+
+
+/** @copydoc VBOXSERVICE::pfnOption */
+static DECLCALLBACK(int) VBoxServiceVMStatsOption(const char **ppszShort, int argc, char **argv, int *pi)
+{
+    int rc = -1;
+    if (ppszShort)
+        /* no short options */;
+    else if (!strcmp(argv[*pi], "--vmstats-interval"))
+        rc = VBoxServiceArgUInt32(argc, argv, "", pi,
+                                  &g_VMStatsInterval, 1000, UINT32_MAX - 1);
+    return rc;
+}
+
+
+/** @copydoc VBOXSERVICE::pfnInit */
+static DECLCALLBACK(int) VBoxServiceVMStatsInit(void)
+{
+    VBoxServiceVerbose(3, "VBoxServiceVMStatsInit\n");
+
+    int rc = RTSemEventMultiCreate(&g_VMStatEvent);
+    AssertRCReturn(rc, rc);
+
+    gCtx.pEnv                   = pEnv;
+    gCtx.uStatInterval          = 0;     /* default */
+    gCtx.ullLastCpuLoad_Idle    = 0;
+    gCtx.ullLastCpuLoad_Kernel  = 0;
+    gCtx.ullLastCpuLoad_User    = 0;
+
+    VMMDevGetStatisticsChangeRequest req;
+    vmmdevInitRequest(&req.header, VMMDevReq_GetStatisticsChangeRequest);
+    req.eventAck = 0;
+
+    if (DeviceIoControl(gVBoxDriver, VBOXGUEST_IOCTL_VMMREQUEST(req.header.size), &req, req.header.size, &req, req.header.size, &cbReturned, NULL))
+    {
+        Log(("VBoxStatsInit: new statistics interval %d seconds\n", req.u32StatInterval));
+        gCtx.uStatInterval = req.u32StatInterval * 1000;
+    }
+    else
+        Log(("VBoxStatsInit: DeviceIoControl failed with %d\n", GetLastError()));
+
+#ifdef RT_OS_WINDOWS
+    /* NtQuerySystemInformation might be dropped in future releases, so load it dynamically as per Microsoft's recommendation */
+    HMODULE hMod = LoadLibrary("NTDLL.DLL");
+    if (hMod)
+    {
+        *(uintptr_t *)&gCtx.pfnNtQuerySystemInformation = (uintptr_t)GetProcAddress(hMod, "NtQuerySystemInformation");
+        if (gCtx.pfnNtQuerySystemInformation)
+            VBoxServiceVerbose(3, "VBoxStatsInit: gCtx.pfnNtQuerySystemInformation = %x\n", gCtx.pfnNtQuerySystemInformation);
+        else
+        {
+            VBoxServiceError("VBoxStatsInit: NTDLL.NtQuerySystemInformation not found!!\n");
+            return VERR_NOT_IMPLEMENTED;
+        }
+    }
+
+    /* GlobalMemoryStatus is win2k and up, so load it dynamically */
+    hMod = LoadLibrary("KERNEL32.DLL");
+    if (hMod)
+    {
+        *(uintptr_t *)&gCtx.pfnGlobalMemoryStatusEx = (uintptr_t)GetProcAddress(hMod, "GlobalMemoryStatusEx");
+        if (gCtx.pfnGlobalMemoryStatusEx)
+            VBoxServiceVerbose(3, "VBoxStatsInit: gCtx.GlobalMemoryStatusEx = %x\n", gCtx.pfnGlobalMemoryStatusEx);
+        else
+        {
+            /** @todo now fails in NT4; do we care? */
+            VBoxServiceError("VBoxStatsInit: KERNEL32.GlobalMemoryStatusEx not found!!\n");
+            return VERR_NOT_IMPLEMENTED;
+        }
+    }
+    /* GetPerformanceInfo is xp and up, so load it dynamically */
+    hMod = LoadLibrary("PSAPI.DLL");
+    if (hMod)
+    {
+        *(uintptr_t *)&gCtx.pfnGetPerformanceInfo = (uintptr_t)GetProcAddress(hMod, "GetPerformanceInfo");
+        if (gCtx.pfnGetPerformanceInfo)
+            VBoxServiceVerbose(3, "VBoxStatsInit: gCtx.pfnGetPerformanceInfo= %x\n", gCtx.pfnGetPerformanceInfo);
+        /* failure is not fatal */
+    }
+#endif /* RT_OS_WINDOWS */
+
+    return VINF_SUCCESS;
+}
+
+
+static void VBoxServiceVMStatsReport(VBOXSTATSCONTEXT *pCtx)
+{
+    SYSTEM_INFO systemInfo;
+    PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION pProcInfo;
+    MEMORYSTATUSEX memStatus;
+    VMMDevReportGuestStats req;
+    uint32_t cbStruct;
+    DWORD    cbReturned;
+    HANDLE   gVBoxDriver = pCtx->pEnv->hDriver;
+
+    Assert(gCtx.pfnGlobalMemoryStatusEx && gCtx.pfnNtQuerySystemInformation);
+    if (    !gCtx.pfnGlobalMemoryStatusEx
+        ||  !gCtx.pfnNtQuerySystemInformation)
+        return;
+
+    vmmdevInitRequest(&req.header, VMMDevReq_ReportGuestStats);
+
+    /* Query and report guest statistics */
+    GetSystemInfo(&systemInfo);
+
+    memStatus.dwLength = sizeof(memStatus);
+    gCtx.pfnGlobalMemoryStatusEx(&memStatus);
+
+    req.guestStats.u32PageSize          = systemInfo.dwPageSize;
+    req.guestStats.u32PhysMemTotal      = (uint32_t)(memStatus.ullTotalPhys / systemInfo.dwPageSize);
+    req.guestStats.u32PhysMemAvail      = (uint32_t)(memStatus.ullAvailPhys / systemInfo.dwPageSize);
+    /* The current size of the committed memory limit, in bytes. This is physical memory plus the size of the page file, minus a small overhead. */
+    req.guestStats.u32PageFileSize      = (uint32_t)(memStatus.ullTotalPageFile / systemInfo.dwPageSize) - req.guestStats.u32PhysMemTotal;
+    req.guestStats.u32MemoryLoad        = memStatus.dwMemoryLoad;
+    req.guestStats.u32PhysMemBalloon    = VBoxMemBalloonQuerySize() * (_1M/systemInfo.dwPageSize);    /* was in megabytes */
+    req.guestStats.u32StatCaps          = VBOX_GUEST_STAT_PHYS_MEM_TOTAL | VBOX_GUEST_STAT_PHYS_MEM_AVAIL | VBOX_GUEST_STAT_PAGE_FILE_SIZE | VBOX_GUEST_STAT_MEMORY_LOAD | VBOX_GUEST_STAT_PHYS_MEM_BALLOON;
+
+    if (gCtx.pfnGetPerformanceInfo)
+    {
+        PERFORMANCE_INFORMATION perfInfo;
+
+        if (gCtx.pfnGetPerformanceInfo(&perfInfo, sizeof(perfInfo)))
+        {
+            req.guestStats.u32Processes         = perfInfo.ProcessCount;
+            req.guestStats.u32Threads           = perfInfo.ThreadCount;
+            req.guestStats.u32Handles           = perfInfo.HandleCount;
+            req.guestStats.u32MemCommitTotal    = perfInfo.CommitTotal;     /* already in pages */
+            req.guestStats.u32MemKernelTotal    = perfInfo.KernelTotal;     /* already in pages */
+            req.guestStats.u32MemKernelPaged    = perfInfo.KernelPaged;     /* already in pages */
+            req.guestStats.u32MemKernelNonPaged = perfInfo.KernelNonpaged;  /* already in pages */
+            req.guestStats.u32MemSystemCache    = perfInfo.SystemCache;     /* already in pages */
+            req.guestStats.u32StatCaps |= VBOX_GUEST_STAT_PROCESSES | VBOX_GUEST_STAT_THREADS | VBOX_GUEST_STAT_HANDLES | VBOX_GUEST_STAT_MEM_COMMIT_TOTAL | VBOX_GUEST_STAT_MEM_KERNEL_TOTAL | VBOX_GUEST_STAT_MEM_KERNEL_PAGED | VBOX_GUEST_STAT_MEM_KERNEL_NONPAGED | VBOX_GUEST_STAT_MEM_SYSTEM_CACHE;
+        }
+        else
+            Log(("GetPerformanceInfo failed with %d\n", GetLastError()));
+    }
+
+    /* Query CPU load information */
+    cbStruct = systemInfo.dwNumberOfProcessors*sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION);
+    pProcInfo = (PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)malloc(cbStruct);
+    Assert(pProcInfo);
+    if (!pProcInfo)
+        return;
+
+    /* Unfortunately GetSystemTimes is XP SP1 and up only, so we need to use the semi-undocumented NtQuerySystemInformation */
+    NTSTATUS rc = gCtx.pfnNtQuerySystemInformation(SystemProcessorPerformanceInformation, pProcInfo, cbStruct, &cbReturned);
+    if (    !rc
+        &&  cbReturned == cbStruct)
+    {
+        if (gCtx.ullLastCpuLoad_Kernel == 0)
+        {
+            /* first time */
+            gCtx.ullLastCpuLoad_Idle    = pProcInfo->IdleTime.QuadPart;
+            gCtx.ullLastCpuLoad_Kernel  = pProcInfo->KernelTime.QuadPart;
+            gCtx.ullLastCpuLoad_User    = pProcInfo->UserTime.QuadPart;
+
+            Sleep(250);
+
+            rc = gCtx.pfnNtQuerySystemInformation(SystemProcessorPerformanceInformation, pProcInfo, cbStruct, &cbReturned);
+            Assert(!rc);
+        }
+
+        uint64_t deltaIdle    = (pProcInfo->IdleTime.QuadPart - gCtx.ullLastCpuLoad_Idle);
+        uint64_t deltaKernel  = (pProcInfo->KernelTime.QuadPart - gCtx.ullLastCpuLoad_Kernel);
+        uint64_t deltaUser    = (pProcInfo->UserTime.QuadPart - gCtx.ullLastCpuLoad_User);
+        deltaKernel          -= deltaIdle;  /* idle time is added to kernel time */
+        uint64_t ullTotalTime = deltaIdle + deltaKernel + deltaUser;
+
+        req.guestStats.u32CpuLoad_Idle      = (uint32_t)(deltaIdle  * 100 / ullTotalTime);
+        req.guestStats.u32CpuLoad_Kernel    = (uint32_t)(deltaKernel* 100 / ullTotalTime);
+        req.guestStats.u32CpuLoad_User      = (uint32_t)(deltaUser  * 100 / ullTotalTime);
+
+        req.guestStats.u32StatCaps |= VBOX_GUEST_STAT_CPU_LOAD_IDLE | VBOX_GUEST_STAT_CPU_LOAD_KERNEL | VBOX_GUEST_STAT_CPU_LOAD_USER;
+
+        gCtx.ullLastCpuLoad_Idle    = pProcInfo->IdleTime.QuadPart;
+        gCtx.ullLastCpuLoad_Kernel  = pProcInfo->KernelTime.QuadPart;
+        gCtx.ullLastCpuLoad_User    = pProcInfo->UserTime.QuadPart;
+    }
+
+    for (uint32_t i=0;i<systemInfo.dwNumberOfProcessors;i++)
+    {
+        req.guestStats.u32CpuId = i;
+
+        if (DeviceIoControl(gVBoxDriver, VBOXGUEST_IOCTL_VMMREQUEST(req.header.size), &req, req.header.size, &req, req.header.size, &cbReturned, NULL))
+        {
+            Log(("VBoxStatsReportStatistics: new statistics reported successfully!\n"));
+        }
+        else
+            Log(("VBoxStatsReportStatistics: DeviceIoControl (stats report) failed with %d\n", GetLastError()));
+    }
+
+    free(pProcInfo);
+}
+
+/** @copydoc VBOXSERVICE::pfnWorker */
+DECLCALLBACK(int) VBoxServiceVMStatsWorker(bool volatile *pfShutdown)
+{
+    VBOXSTATSCONTEXT *pCtx = (VBOXSTATSCONTEXT *)pInstance;
+    HANDLE gVBoxDriver = pCtx->pEnv->hDriver;
+    bool fTerminate = false;
+    VBoxGuestFilterMaskInfo maskInfo;
+    DWORD cbReturned;
+
+    int rc = VINF_SUCCESS;
+
+    /*
+     * Tell the control thread that it can continue
+     * spawning services.
+     */
+    RTThreadUserSignal(RTThreadSelf());
+
+    maskInfo.u32OrMask = VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE_REQUEST;
+    maskInfo.u32NotMask = 0;
+    if (DeviceIoControl (gVBoxDriver, VBOXGUEST_IOCTL_CTL_FILTER_MASK, &maskInfo, sizeof (maskInfo), NULL, 0, &cbReturned, NULL))
+    {
+        Log(("VBoxStatsThread: DeviceIOControl(CtlMask - or) succeeded\n"));
+    }
+    else
+    {
+        Log(("VBoxStatsThread: DeviceIOControl(CtlMask) failed, SeamlessChangeThread exited\n"));
+        return 0;
+    }
+
+    /*
+     * Now enter the loop retrieving runtime data continuously.
+     */
+    for (;;)
+    {
+        /* Report statistics to the host */
+        if (gCtx.pfnNtQuerySystemInformation)
+        {
+            VBoxServiceVMStatsReport();
+        }
+
+        /*
+         * Block for a while.
+         *
+         * The event semaphore takes care of ignoring interruptions and it
+         * allows us to implement service wakeup later.
+         */
+        if (*pfShutdown)
+            break;
+        int rc2 = RTSemEventMultiWait(g_VMStatEvent, g_VMStatsInterval);
+        if (*pfShutdown)
+            break;
+        if (rc2 != VERR_TIMEOUT && RT_FAILURE(rc2))
+        {
+            VBoxServiceError("RTSemEventMultiWait failed; rc2=%Rrc\n", rc2);
+            rc = rc2;
+            break;
+        }
+    }
+
+    maskInfo.u32OrMask = 0;
+    maskInfo.u32NotMask = VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE_REQUEST;
+    if (DeviceIoControl (gVBoxDriver, VBOXGUEST_IOCTL_CTL_FILTER_MASK, &maskInfo, sizeof (maskInfo), NULL, 0, &cbReturned, NULL))
+    {
+        Log(("VBoxStatsThread: DeviceIOControl(CtlMask - not) succeeded\n"));
+    }
+    else
+    {
+        Log(("VBoxStatsThread: DeviceIOControl(CtlMask) failed\n"));
+    }
+
+    RTSemEventMultiDestroy(g_VMStatsEvent);
+    g_VMStatsEvent = NIL_RTSEMEVENTMULTI;
+
+    Log(("VBoxStatsThread: finished statistics change request thread\n"));
+    return 0;
+}
+
+
+/** @copydoc VBOXSERVICE::pfnTerm */
+static DECLCALLBACK(void) VBoxServiceVMStatsTerm(void)
+{
+    VBoxServiceVerbose(3, "VBoxServiceVMStatsTerm\n");
+    return;
+}
+
+
+/** @copydoc VBOXSERVICE::pfnStop */
+static DECLCALLBACK(void) VBoxServiceVMStatsStop(void)
+{
+    RTSemEventMultiSignal(g_VMStatsEvent);
+}
+
+
+/**
+ * The 'vminfo' service description.
+ */
+VBOXSERVICE g_VMStatistics =
+{
+    /* pszName. */
+    "vmstats",
+    /* pszDescription. */
+    "Virtual Machine Statistics",
+    /* pszUsage. */
+    "[--vmstats-interval <ms>]"
+    ,
+    /* pszOptions. */
+    "    --vmstats-interval   Specifies the interval at which to retrieve the\n"
+    "                        VM statistcs. The default is 10000 ms.\n"
+    ,
+    /* methods */
+    VBoxServiceVMStatsPreInit,
+    VBoxServiceVMStatsOption,
+    VBoxServiceVMStatsInit,
+    VBoxServiceVMStatsWorker,
+    VBoxServiceVMStatsStop,
+    VBoxServiceVMStatsTerm
+};
