From: Marc-André Lureau <marcandre.lur...@redhat.com>

Signed-off-by: Marc-André Lureau <marcandre.lur...@redhat.com>
---
 configure            |   1 +
 qga/commands-win32.c | 164 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 163 insertions(+), 2 deletions(-)

diff --git a/configure b/configure
index c5c4b82..82ee185 100755
--- a/configure
+++ b/configure
@@ -734,6 +734,7 @@ if test "$mingw32" = "yes" ; then
   local_statedir=
   confsuffix=""
   libs_qga="-lws2_32 -lwinmm -lpowrprof -liphlpapi -lnetapi32 $libs_qga"
+  libs_qga="-lole32 -loleaut32 -lwbemuuid -lpsapi $libs_qga"
 fi
 
 werror=""
diff --git a/qga/commands-win32.c b/qga/commands-win32.c
index bf9cd93..be11221 100644
--- a/qga/commands-win32.c
+++ b/qga/commands-win32.c
@@ -27,6 +27,8 @@
 #include <initguid.h>
 #endif
 #include <lm.h>
+#include <wbemcli.h>
+#include <psapi.h>
 
 #include "qga/guest-agent-core.h"
 #include "qga/vss-win32.h"
@@ -1333,8 +1335,166 @@ void ga_command_state_init(GAState *s, GACommandState 
*cs)
     ga_command_state_add(cs, guest_file_init, NULL);
 }
 
+#define chk(msg)                                                        \
+    do {                                                                \
+        if (FAILED(hr)) {                                               \
+            gchar *emsg = g_win32_error_message(GetLastError());        \
+            slog("Failed to %s: %s", (msg), emsg);                      \
+            g_free(emsg);                                               \
+            goto out;                                                   \
+        }                                                               \
+    } while (0)
+
+static gboolean get_memory_wmi_info(GuestMemoryInfo *info)
+{
+    HRESULT hr = 0;
+    IWbemLocator *locator  = NULL;
+    IWbemServices *services = NULL;
+    IEnumWbemClassObject *results  = NULL;
+    BSTR resource, language, query_perf, query_swap;
+    gboolean success = FALSE;
+
+    g_return_val_if_fail(info != NULL, FALSE);
+
+    resource = SysAllocString(L"ROOT\\CIMV2");
+    language = SysAllocString(L"WQL");
+    query_perf = SysAllocString(L"SELECT * FROM "
+                                "Win32_PerfFormattedData_PerfOS_Memory");
+    query_swap = SysAllocString(L"SELECT * FROM "
+                                "Win32_PageFileUsage");
+
+    /* initialize COM */
+    hr = CoInitializeEx(0, COINIT_MULTITHREADED);
+    chk("initialize COM");
+
+    hr = CoInitializeSecurity(NULL, -1, NULL, NULL,
+                              RPC_C_AUTHN_LEVEL_DEFAULT,
+                              RPC_C_IMP_LEVEL_IMPERSONATE,
+                              NULL, EOAC_NONE, NULL);
+    chk("initialize COM security");
+
+    /* connect to WMI */
+    hr = CoCreateInstance(&CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER,
+                          &IID_IWbemLocator, (LPVOID *) &locator);
+    chk("create WbemLocator instance");
+
+    hr = locator->lpVtbl->ConnectServer(locator, resource, NULL, NULL, NULL, 0,
+                                        NULL, NULL, &services);
+    chk("connect to CIMV2 server");
+
+    /* issue a WMI perf query */
+    hr = services->lpVtbl->ExecQuery(services, language, query_perf,
+                                     WBEM_FLAG_BIDIRECTIONAL, NULL, &results);
+    chk("execute perf query");
+
+    if (results != NULL) {
+        IWbemClassObject *result = NULL;
+        ULONG returnedCount = 0;
+
+        /* enumerate the retrieved objects */
+        while ((hr = results->lpVtbl->Next(results, WBEM_INFINITE, 1,
+                                           &result, &returnedCount)) == S_OK) {
+            VARIANT pages_in, pages_out, pf, pfr;
+
+            hr = result->lpVtbl->Get(result, L"PagesInputPersec", 0,
+                                     &pages_in, 0, 0);
+            hr = result->lpVtbl->Get(result, L"PagesOutputPersec", 0,
+                                     &pages_out, 0, 0);
+            hr = result->lpVtbl->Get(result, L"PageFaultsPersec", 0,
+                                     &pf, 0, 0);
+            hr = result->lpVtbl->Get(result, L"PageReadsPersec", 0,
+                                     &pfr, 0, 0);
+
+            info->swap_in += pages_in.ulVal;
+            info->swap_out += pages_out.ulVal;
+            info->pf_minor += pf.ulVal - pfr.ulVal;
+            info->pf_major += pfr.ulVal;
+
+            result->lpVtbl->Release(result);
+        }
+
+        results->lpVtbl->Release(results);
+    }
+
+    /* issue a WMI swap query */
+    hr = services->lpVtbl->ExecQuery(services, language, query_swap,
+                                     WBEM_FLAG_BIDIRECTIONAL, NULL, &results);
+    chk("execute swap query");
+
+    if (results != NULL) {
+        IWbemClassObject *result = NULL;
+        ULONG returnedCount = 0;
+
+        /* enumerate the retrieved objects */
+        while ((hr = results->lpVtbl->Next(results, WBEM_INFINITE, 1,
+                                           &result, &returnedCount)) == S_OK) {
+            VARIANT usage, alloc;
+
+            hr = result->lpVtbl->Get(result, L"AllocatedBaseSize", 0,
+                                     &alloc, 0, 0);
+            hr = result->lpVtbl->Get(result, L"CurrentUsage", 0,
+                                     &usage, 0, 0);
+
+            /* MiB to kiB */
+            info->swap_total += alloc.ulVal * 1024;
+            info->swap_free += (alloc.ulVal - usage.ulVal) * 1024;
+
+            result->lpVtbl->Release(result);
+        }
+
+        results->lpVtbl->Release(results);
+    }
+
+    success = TRUE;
+
+out:
+    /* release WMI COM interfaces */
+    if (services) {
+        services->lpVtbl->Release(services);
+    }
+    if (locator) {
+        locator->lpVtbl->Release(locator);
+    }
+
+    /* unwind everything else we've allocated */
+    CoUninitialize();
+
+    if (query_perf) {
+        SysFreeString(query_perf);
+    }
+    if (query_swap) {
+        SysFreeString(query_swap);
+    }
+    if (language) {
+        SysFreeString(language);
+    }
+    if (resource) {
+        SysFreeString(resource);
+    }
+
+    return success;
+}
+
 GuestMemoryInfo *qmp_guest_get_memory_info(Error **errp)
 {
-    error_setg(errp, QERR_UNSUPPORTED);
-    return NULL;
+    GuestMemoryInfo *info = g_new0(GuestMemoryInfo, 1);
+    PERFORMANCE_INFORMATION perf = { .cb = sizeof(PERFORMANCE_INFORMATION) };
+
+    if (!get_memory_wmi_info(info)) {
+        error_setg(errp, "Failed to get WMI info");
+        g_free(info);
+        return NULL;
+    }
+
+    if (!GetPerformanceInfo(&perf, perf.cb)) {
+        error_setg(errp, "Failed to get performance info");
+        g_free(info);
+        return NULL;
+    }
+
+    info->mem_total = (perf.PhysicalTotal * perf.PageSize) / 1024;
+    info->mem_free = (perf.PhysicalAvailable * perf.PageSize) / 1024;
+    info->mem_cached = (perf.SystemCache * perf.PageSize) / 1024;
+
+    return info;
 }
-- 
2.4.3


Reply via email to