diff --git a/contrib/platform/src/com/sun/jna/platform/win32/Psapi.java b/contrib/platform/src/com/sun/jna/platform/win32/Psapi.java
index dfd13d204d..31abe99896 100644
--- a/contrib/platform/src/com/sun/jna/platform/win32/Psapi.java
+++ b/contrib/platform/src/com/sun/jna/platform/win32/Psapi.java
@@ -28,6 +28,7 @@
import com.sun.jna.Structure;
import com.sun.jna.Structure.FieldOrder;
import com.sun.jna.platform.win32.BaseTSD.SIZE_T;
+import com.sun.jna.platform.win32.BaseTSD.ULONG_PTR;
import com.sun.jna.platform.win32.WinDef.DWORD;
import com.sun.jna.platform.win32.WinDef.HMODULE;
import com.sun.jna.platform.win32.WinNT.HANDLE;
@@ -292,6 +293,18 @@ public interface Psapi extends StdCallLibrary {
*/
boolean EnumProcesses(int[] lpidProcess, int cb, IntByReference lpcbNeeded);
+ /**
+ * Retrieves extended information about the pages at specific
+ * virtual addresses in the address space of the specified process.
+ *
+ * @param hProcess A Handle to the Process
+ * @param pv A pointer to an array of PSAPI_WORKING_SET_EX_INFORMATION structures
+ * @param cb The size of the pv buffer, in bytes.
+ * @return If the function succeeds, the return value is nonzero.
+ * @see MSDN
+ */
+ boolean QueryWorkingSetEx(HANDLE hProcess, PSAPI_WORKING_SET_EX_INFORMATION pv, DWORD cb);
+
@FieldOrder({"lpBaseOfDll", "SizeOfImage", "EntryPoint"})
class MODULEINFO extends Structure {
public Pointer EntryPoint;
@@ -320,4 +333,97 @@ class PERFORMANCE_INFORMATION extends Structure {
public DWORD ProcessCount;
public DWORD ThreadCount;
}
+
+ @FieldOrder({"Flags", "Data"})
+ class PSAPI_WORKING_SET_EX_BLOCK extends Structure {
+ public ULONG_PTR Flags;
+ public ULONG[] Data = new ULONG[Native.POINTER_SIZE == 8 ? 1 : 2];
+ private long innerValue;
+
+ @Override
+ public void read() {
+ super.read();
+ innerValue = this.Data[0].longValue();
+ }
+
+ /**
+ * If this bit is 1, the subsequent members are valid; otherwise they should be ignored.
+ */
+ public boolean Valid() {
+ return getBitFieldValue(1, 0) == 1;
+ }
+
+ /**
+ * The number of processes that share this page. The maximum value of this member is 7.
+ */
+ public int ShareCount() {
+ return getBitFieldValue(3, 1);
+ }
+
+ /**
+ * The memory protection attributes of the page. For a list of values see below.
+ * @see Memory Protection Constants.
+ */
+ public int Win32Protection() {
+ return getBitFieldValue(11, 3 + 1);
+ }
+
+ /**
+ * If this bit is 1, the page can be shared.
+ */
+ public boolean Shared() {
+ return getBitFieldValue(1, 11 + 3 + 1) == 1;
+ }
+
+ /**
+ * The NUMA node. The maximum value of this member is 63.
+ */
+ public int Node() {
+ return getBitFieldValue(6, 1 + 11 + 3 + 1);
+ }
+
+ /**
+ * If this bit is 1, the virtual page is locked in physical memory.
+ */
+ public boolean Locked() {
+ return getBitFieldValue(1, 6 + 1 + 11 + 3 + 1) == 1;
+ }
+
+ /**
+ * If this bit is 1, the page is a large page.
+ */
+ public boolean LargePage() {
+ return getBitFieldValue(1, 1 + 6 + 1 + 11 + 3 + 1) == 1;
+ }
+
+ /**
+ * If this bit is 1, the page is has been reported as bad.
+ */
+ public boolean Bad() {
+ return getBitFieldValue(1,1 + 1 + 1 + 6 + 1 + 11 + 3 + 1) == 1;
+ }
+
+ /**
+ * Returns innerValue after shifting the value rightShiftAmount, and applying a Bit Mask of size maskLength. Example,
+ * innerValue = 0011
getBitFieldValue(2, 1) = 0011 >> 1 & 11 = 01
+ * @param maskLength Size of the Bit Mask
+ * @param rightShiftAmount Amount to Shift innerValue to the right by
+ * @return innerValue with the mask and shift applied.
+ */
+ private int getBitFieldValue(final int maskLength, final int rightShiftAmount) {
+ long bitMask = 0;
+
+ for (int l = 0; l <= maskLength - rightShiftAmount; l++) {
+ bitMask |= 1 << l;
+ }
+ return (int) ((innerValue >> rightShiftAmount) & bitMask);
+ }
+ }
+
+
+ @FieldOrder({"VirtualAddress", "VirtualAttributes"})
+ class PSAPI_WORKING_SET_EX_INFORMATION extends Structure {
+ public Pointer VirtualAddress;
+ public PSAPI_WORKING_SET_EX_BLOCK VirtualAttributes;
+ }
}
diff --git a/contrib/platform/test/com/sun/jna/platform/win32/PsapiTest.java b/contrib/platform/test/com/sun/jna/platform/win32/PsapiTest.java
index 7af0c9b275..6f4dd674f8 100644
--- a/contrib/platform/test/com/sun/jna/platform/win32/PsapiTest.java
+++ b/contrib/platform/test/com/sun/jna/platform/win32/PsapiTest.java
@@ -24,6 +24,7 @@
package com.sun.jna.platform.win32;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
import java.util.LinkedList;
import java.util.List;
@@ -34,12 +35,15 @@
import com.sun.jna.Memory;
import com.sun.jna.Native;
+import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.Psapi.MODULEINFO;
import com.sun.jna.platform.win32.Psapi.PERFORMANCE_INFORMATION;
import com.sun.jna.platform.win32.WinDef.DWORD;
import com.sun.jna.platform.win32.WinDef.HMODULE;
import com.sun.jna.platform.win32.WinDef.HWND;
import com.sun.jna.platform.win32.WinNT.HANDLE;
+import com.sun.jna.platform.win32.WinNT.MEMORY_BASIC_INFORMATION;
+import com.sun.jna.platform.win32.BaseTSD.SIZE_T;
import com.sun.jna.ptr.IntByReference;
/**
@@ -273,4 +277,42 @@ public void testEnumProcesses() {
}
assertTrue("List should contain my pid", foundMyPid);
}
+
+ @Test
+ public void testQueryWorkingSetEx() {
+ Win32Exception we = null;
+ HANDLE selfHandle = Kernel32.INSTANCE.GetCurrentProcess();
+ MEMORY_BASIC_INFORMATION mbi = new MEMORY_BASIC_INFORMATION();
+ try {
+ SIZE_T bytesRead = Kernel32.INSTANCE.VirtualQueryEx(selfHandle, Pointer.NULL, mbi, new SIZE_T(mbi.size()));
+ assertTrue("It should read correctly", bytesRead.intValue() != 0);
+ Psapi.PSAPI_WORKING_SET_EX_INFORMATION pswsi = new Psapi.PSAPI_WORKING_SET_EX_INFORMATION();
+ pswsi.VirtualAddress = mbi.baseAddress;
+ if (!Psapi.INSTANCE.QueryWorkingSetEx(selfHandle, pswsi, new DWORD(pswsi.size()))) {
+ throw new Win32Exception(Native.getLastError());
+ }
+ assertTrue("Virual Attributes should not be null", pswsi.VirtualAttributes != null);
+ if (Psapi.INSTANCE.QueryWorkingSetEx(new HANDLE(), pswsi, new DWORD(pswsi.size()))) {
+ throw new Win32Exception(Native.getLastError());
+ }
+ assertFalse("This line should never be called", true);
+ } catch (Win32Exception e) {
+ we = e;
+ throw we; // re-throw to invoke finally block
+ } finally {
+ try {
+ Kernel32Util.closeHandle(selfHandle);
+ } catch (Win32Exception e) {
+ if (we == null) {
+ we = e;
+ } else {
+ we.addSuppressedReflected(e);
+ }
+ }
+ if (we != null) {
+ throw we;
+ }
+ }
+ }
}
+