Skip to content

Commit

Permalink
Added c.s.j.win32.Psapi.QueryWorkingSetEx
Browse files Browse the repository at this point in the history
  • Loading branch information
Crain-32 committed Aug 9, 2022
1 parent 999c60a commit e27e18a
Show file tree
Hide file tree
Showing 3 changed files with 151 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Next Release (5.13.0)

Features
--------
* [#1454](https://github.com/java-native-access/jna/pull/1454): Add `c.s.j.p.win32.Psapi.QueryWorkingSetEx` and associated Types = [@crain-32](https://github.com/Crain-32).

Bug Fixes
---------
Expand Down
107 changes: 107 additions & 0 deletions contrib/platform/src/com/sun/jna/platform/win32/Psapi.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import com.sun.jna.Structure.ByReference;
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;
Expand Down Expand Up @@ -292,6 +294,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 <a href="https://docs.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-queryworkingsetex">MSDN</a>
*/
boolean QueryWorkingSetEx(HANDLE hProcess, Pointer pv, int cb);

@FieldOrder({"lpBaseOfDll", "SizeOfImage", "EntryPoint"})
class MODULEINFO extends Structure {
public Pointer EntryPoint;
Expand Down Expand Up @@ -320,4 +334,97 @@ class PERFORMANCE_INFORMATION extends Structure {
public DWORD ProcessCount;
public DWORD ThreadCount;
}

@FieldOrder({"Flags", "Data"})
class PSAPI_WORKING_SET_EX_BLOCK extends Structure implements ByReference {
public ULONG_PTR Flags;
public ULONG_PTR[] Data = new ULONG_PTR[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 <a href="https://docs.microsoft.com/en-us/windows/desktop/Memory/memory-protection-constants">Memory Protection Constants</a>.
*/
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, <br/>
* innerValue = 0011<br/> 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; 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;
}
}
43 changes: 43 additions & 0 deletions contrib/platform/test/com/sun/jna/platform/win32/PsapiTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
package com.sun.jna.platform.win32;

import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertNotEqual;
import static org.junit.Assert.assertFalse;

import java.util.LinkedList;
import java.util.List;
Expand All @@ -34,12 +36,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;

/**
Expand Down Expand Up @@ -273,4 +278,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()));
assertNotEqual("Kernel should be able to read this Process' Bytes", 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.VirtualAddress, pswsi.size())) {
throw new Win32Exception(Native.getLastError());
}
assertTrue("Virual Attributes should not be null", pswsi.VirtualAttributes != null);
if (Psapi.INSTANCE.QueryWorkingSetEx(new HANDLE(), pswsi, 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;
}
}
}
}

0 comments on commit e27e18a

Please sign in to comment.