Skip to content

Commit f0e8dcc

Browse files
Crain-32dbwiddis
authored andcommitted
Added c.s.j.win32.Psapi.QueryWorkingSetEx
1 parent 999c60a commit f0e8dcc

File tree

3 files changed

+159
-0
lines changed

3 files changed

+159
-0
lines changed

CHANGES.md

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Next Release (5.13.0)
77

88
Features
99
--------
10+
* [#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).
1011

1112
Bug Fixes
1213
---------

contrib/platform/src/com/sun/jna/platform/win32/Psapi.java

+116
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,10 @@
2626
import com.sun.jna.Native;
2727
import com.sun.jna.Pointer;
2828
import com.sun.jna.Structure;
29+
import com.sun.jna.Structure.ByReference;
2930
import com.sun.jna.Structure.FieldOrder;
3031
import com.sun.jna.platform.win32.BaseTSD.SIZE_T;
32+
import com.sun.jna.platform.win32.BaseTSD.ULONG_PTR;
3133
import com.sun.jna.platform.win32.WinDef.DWORD;
3234
import com.sun.jna.platform.win32.WinDef.HMODULE;
3335
import com.sun.jna.platform.win32.WinNT.HANDLE;
@@ -292,6 +294,18 @@ public interface Psapi extends StdCallLibrary {
292294
*/
293295
boolean EnumProcesses(int[] lpidProcess, int cb, IntByReference lpcbNeeded);
294296

297+
/**
298+
* Retrieves extended information about the pages at specific
299+
* virtual addresses in the address space of the specified process.
300+
*
301+
* @param hProcess A Handle to the Process
302+
* @param pv A pointer to an array of PSAPI_WORKING_SET_EX_INFORMATION structures
303+
* @param cb The size of the pv buffer, in bytes.
304+
* @return If the function succeeds, the return value is nonzero.
305+
* @see <a href="https://docs.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-queryworkingsetex">MSDN</a>
306+
*/
307+
boolean QueryWorkingSetEx(HANDLE hProcess, Pointer pv, int cb);
308+
295309
@FieldOrder({"lpBaseOfDll", "SizeOfImage", "EntryPoint"})
296310
class MODULEINFO extends Structure {
297311
public Pointer EntryPoint;
@@ -320,4 +334,106 @@ class PERFORMANCE_INFORMATION extends Structure {
320334
public DWORD ProcessCount;
321335
public DWORD ThreadCount;
322336
}
337+
338+
@FieldOrder({"Flags", "Data"})
339+
class PSAPI_WORKING_SET_EX_BLOCK extends Structure implements ByReference {
340+
public ULONG_PTR Flags;
341+
public ULONG_PTR[] Data = new ULONG_PTR[Native.POINTER_SIZE == 8 ? 1 : 2];
342+
private long innerValue;
343+
344+
@Override
345+
public void read() {
346+
super.read();
347+
innerValue = this.Data[0].longValue();
348+
}
349+
350+
/**
351+
* If this bit is 1, the subsequent members are valid; otherwise they should be
352+
* ignored.
353+
*/
354+
public boolean isValid() {
355+
return getBitFieldValue(1, 0) == 1;
356+
}
357+
358+
/**
359+
* The number of processes that share this page. The maximum value of this
360+
* member is 7.
361+
*/
362+
public int getShareCount() {
363+
return getBitFieldValue(3, 1);
364+
}
365+
366+
/**
367+
* The memory protection attributes of the page. For a list of values see below.
368+
*
369+
* @see <a href=
370+
* "https://docs.microsoft.com/en-us/windows/desktop/Memory/memory-protection-constants">Memory
371+
* Protection Constants</a>.
372+
*/
373+
public int getWin32Protection() {
374+
return getBitFieldValue(11, 3 + 1);
375+
}
376+
377+
/**
378+
* If this bit is 1, the page can be shared.
379+
*/
380+
public boolean isShared() {
381+
return getBitFieldValue(1, 11 + 3 + 1) == 1;
382+
}
383+
384+
/**
385+
* The NUMA node. The maximum value of this member is 63.
386+
*/
387+
public int getNode() {
388+
return getBitFieldValue(6, 1 + 11 + 3 + 1);
389+
}
390+
391+
/**
392+
* If this bit is 1, the virtual page is locked in physical memory.
393+
*/
394+
public boolean isLocked() {
395+
return getBitFieldValue(1, 6 + 1 + 11 + 3 + 1) == 1;
396+
}
397+
398+
/**
399+
* If this bit is 1, the page is a large page.
400+
*/
401+
public boolean isLargePage() {
402+
return getBitFieldValue(1, 1 + 6 + 1 + 11 + 3 + 1) == 1;
403+
}
404+
405+
/**
406+
* If this bit is 1, the page is has been reported as bad.
407+
*/
408+
public boolean isBad() {
409+
return getBitFieldValue(1, 1 + 1 + 1 + 6 + 1 + 11 + 3 + 1) == 1;
410+
}
411+
412+
/**
413+
* Returns innerValue after shifting the value rightShiftAmount, and applying a
414+
* Bit Mask of size maskLength. Example, <br/>
415+
* innerValue = 0011<br/>
416+
* getBitFieldValue(2, 1) = 0011 >> 1 & 11 = 01
417+
*
418+
* @param maskLength
419+
* Size of the Bit Mask
420+
* @param rightShiftAmount
421+
* Amount to Shift innerValue to the right by
422+
* @return innerValue with the mask and shift applied.
423+
*/
424+
private int getBitFieldValue(final int maskLength, final int rightShiftAmount) {
425+
long bitMask = 0;
426+
427+
for (int bit = 0; bit < maskLength; bit++) {
428+
bitMask |= 1 << bit;
429+
}
430+
return (int) ((innerValue >>> rightShiftAmount) & bitMask);
431+
}
432+
}
433+
434+
@FieldOrder({"VirtualAddress", "VirtualAttributes"})
435+
class PSAPI_WORKING_SET_EX_INFORMATION extends Structure {
436+
public Pointer VirtualAddress;
437+
public PSAPI_WORKING_SET_EX_BLOCK VirtualAttributes;
438+
}
323439
}

contrib/platform/test/com/sun/jna/platform/win32/PsapiTest.java

+42
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
*/
2424
package com.sun.jna.platform.win32;
2525

26+
import static org.junit.Assert.assertFalse;
27+
import static org.junit.Assert.assertNotEquals;
2628
import static org.junit.Assert.assertTrue;
2729

2830
import java.util.LinkedList;
@@ -34,12 +36,15 @@
3436

3537
import com.sun.jna.Memory;
3638
import com.sun.jna.Native;
39+
import com.sun.jna.Pointer;
3740
import com.sun.jna.platform.win32.Psapi.MODULEINFO;
3841
import com.sun.jna.platform.win32.Psapi.PERFORMANCE_INFORMATION;
3942
import com.sun.jna.platform.win32.WinDef.DWORD;
4043
import com.sun.jna.platform.win32.WinDef.HMODULE;
4144
import com.sun.jna.platform.win32.WinDef.HWND;
4245
import com.sun.jna.platform.win32.WinNT.HANDLE;
46+
import com.sun.jna.platform.win32.WinNT.MEMORY_BASIC_INFORMATION;
47+
import com.sun.jna.platform.win32.BaseTSD.SIZE_T;
4348
import com.sun.jna.ptr.IntByReference;
4449

4550
/**
@@ -273,4 +278,41 @@ public void testEnumProcesses() {
273278
}
274279
assertTrue("List should contain my pid", foundMyPid);
275280
}
281+
282+
@Test
283+
public void testQueryWorkingSetEx() {
284+
Win32Exception we = null;
285+
HANDLE selfHandle = Kernel32.INSTANCE.GetCurrentProcess();
286+
MEMORY_BASIC_INFORMATION mbi = new MEMORY_BASIC_INFORMATION();
287+
try {
288+
SIZE_T bytesRead = Kernel32.INSTANCE.VirtualQueryEx(selfHandle, Pointer.NULL, mbi, new SIZE_T(mbi.size()));
289+
assertNotEquals("Kernel should be able to read this Process' Bytes", bytesRead.intValue(), 0);
290+
Psapi.PSAPI_WORKING_SET_EX_INFORMATION pswsi = new Psapi.PSAPI_WORKING_SET_EX_INFORMATION();
291+
pswsi.VirtualAddress = mbi.baseAddress;
292+
if (!Psapi.INSTANCE.QueryWorkingSetEx(selfHandle, pswsi.VirtualAddress, pswsi.size())) {
293+
throw new Win32Exception(Native.getLastError());
294+
}
295+
assertTrue("Virual Attributes should not be null", pswsi.VirtualAttributes != null);
296+
if (Psapi.INSTANCE.QueryWorkingSetEx(new HANDLE(), pswsi.VirtualAddress, pswsi.size())) {
297+
throw new Win32Exception(Native.getLastError());
298+
}
299+
assertFalse("This line should never be called", true);
300+
} catch (Win32Exception e) {
301+
we = e;
302+
throw we; // re-throw to invoke finally block
303+
} finally {
304+
try {
305+
Kernel32Util.closeHandle(selfHandle);
306+
} catch (Win32Exception e) {
307+
if (we == null) {
308+
we = e;
309+
} else {
310+
we.addSuppressedReflected(e);
311+
}
312+
}
313+
if (we != null) {
314+
throw we;
315+
}
316+
}
317+
}
276318
}

0 commit comments

Comments
 (0)