Skip to content

Commit

Permalink
Merge pull request #552 from mlfreeman2/kernel32-additional-3
Browse files Browse the repository at this point in the history
added Module32First and Module32Next to Kernel32
  • Loading branch information
twall committed Dec 10, 2015
2 parents ee896b7 + 2710345 commit a6a0c4e
Show file tree
Hide file tree
Showing 6 changed files with 297 additions and 13 deletions.
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ Features
* [#524](https://github.com/java-native-access/jna/pull/524): Added IShellFolder interface plus necessary utility functions to Windows platform, and a sample for enumerating objects in My Computer - [@lwahonen](https://github.com/lwahonen).
* [#484](https://github.com/twall/jna/pull/484): Added `XFetchName` to `X11` interface - [@pinaf](https://github.com/pinaf).
* [#554](https://github.com/java-native-access/jna/pull/554): Initial code for a few Unix 'libc' API(s) [@lgoldstein](https://github.com/lgoldstein)
* [#552](https://github.com/java-native-access/jna/pull/552): Added `Module32FirstW` and `Module32NextW` to `com.sun.jna.platform.win32.Kernel32` (and helper to `com.sun.jna.platform.win32.Kernel32Util`) and `MODULEENTRY32W` structure to `com.sun.jna.platform.win32.Tlhelp32` - [@mlfreeman2](https://github.com/mlfreeman2).

Bug Fixes
---------
Expand Down
49 changes: 42 additions & 7 deletions contrib/platform/src/com/sun/jna/platform/win32/Kernel32.java
Original file line number Diff line number Diff line change
Expand Up @@ -1269,18 +1269,18 @@ boolean CreateProcessW(String lpApplicationName, char[] lpCommandLine,
* This function retrieves the full path of the executable file of a given process.
*
* @param hProcess
* Handle for the running process
* Handle for the running process
* @param dwFlags
* 0 - The name should use the Win32 path format.
* 1(WinNT.PROCESS_NAME_NATIVE) - The name should use the native system path format.
* 0 - The name should use the Win32 path format.
* 1(WinNT.PROCESS_NAME_NATIVE) - The name should use the native system path format.
* @param lpExeName
* pre-allocated character buffer for the returned path
* pre-allocated character buffer for the returned path
* @param lpdwSize
* input: the size of the allocated buffer
* output: the length of the returned path in characters
* input: the size of the allocated buffer
* output: the length of the returned path in characters
*
* @return true if successful false if not. To get extended error information,
* call GetLastError.
* call GetLastError.
*/
boolean QueryFullProcessImageName(HANDLE hProcess, int dwFlags, char[] lpExeName, IntByReference lpdwSize);

Expand Down Expand Up @@ -3289,4 +3289,39 @@ boolean GetVolumePathNamesForVolumeName(String lpszVolumeName,
* information, call GetLastError.
*/
boolean EnumResourceNames(HMODULE hModule, Pointer type, WinBase.EnumResNameProc proc, Pointer lParam);

/**
* Retrieves information about the first module associated with a process.
*
* @see <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms684218(v=vs.85).aspx">MSDN</a>
* @param hSnapshot
* A handle to the snapshot returned from a previous call to the
* CreateToolhelp32Snapshot function.
* @param lpme
* A pointer to a MODULEENTRY32 structure.
* @return Returns TRUE if the first entry of the module list has been
* copied to the buffer or FALSE otherwise.<br>
* The ERROR_NO_MORE_FILES error value is returned by the
* GetLastError function if no modules exist or the snapshot does
* not contain module information.
*/
boolean Module32FirstW(HANDLE hSnapshot, Tlhelp32.MODULEENTRY32W lpme);

/**
* Retrieves information about the next module associated with a process or
* thread.
*
* @see <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms684221(v=vs.85).aspx">MSDN</a>
* @param hSnapshot
* A handle to the snapshot returned from a previous call to the
* CreateToolhelp32Snapshot function.
* @param lpme
* A pointer to a MODULEENTRY32 structure.
* @return Returns TRUE if the first entry of the module list has been
* copied to the buffer or FALSE otherwise.<br>
* The ERROR_NO_MORE_FILES error value is returned by the
* GetLastError function if no modules exist or the snapshot does
* not contain module information.
*/
boolean Module32NextW(HANDLE hSnapshot, Tlhelp32.MODULEENTRY32W lpme);
}
64 changes: 60 additions & 4 deletions contrib/platform/src/com/sun/jna/platform/win32/Kernel32Util.java
Original file line number Diff line number Diff line change
Expand Up @@ -686,13 +686,13 @@ public static final String extractVolumeGUID(String volumeGUIDPath) {
* This function retrieves the full path of the executable file of a given process.
*
* @param hProcess
* Handle for the running process
* Handle for the running process
* @param dwFlags
* 0 - The name should use the Win32 path format.
* 1(WinNT.PROCESS_NAME_NATIVE) - The name should use the native system path format.
* 0 - The name should use the Win32 path format.
* 1(WinNT.PROCESS_NAME_NATIVE) - The name should use the native system path format.
*
* @return the full path of the process's executable file of null if failed. To get extended error information,
* call GetLastError.
* call GetLastError.
*/
public static final String QueryFullProcessImageName(HANDLE hProcess, int dwFlags) {
char[] path = new char[WinDef.MAX_PATH];
Expand Down Expand Up @@ -895,4 +895,60 @@ public boolean invoke(HMODULE module, Pointer type, Pointer name, Pointer lParam
}
return result;
}

/**
* Returns all the executable modules for a given process ID.<br>
*
* @param processID
* The process ID to get executable modules for
* @return All the modules in the process.
*/
public static List<Tlhelp32.MODULEENTRY32W> getModules(int processID) {
HANDLE snapshot = Kernel32.INSTANCE.CreateToolhelp32Snapshot(Tlhelp32.TH32CS_SNAPMODULE, new DWORD(processID));
if (snapshot == null) {
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
}

List<Tlhelp32.MODULEENTRY32W> modules = new ArrayList<Tlhelp32.MODULEENTRY32W>();
Win32Exception we = null;
try {
Tlhelp32.MODULEENTRY32W first = new Tlhelp32.MODULEENTRY32W();
modules.add(first);

if (!Kernel32.INSTANCE.Module32FirstW(snapshot, first)) {
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
}

Tlhelp32.MODULEENTRY32W next = new Tlhelp32.MODULEENTRY32W();
while (Kernel32.INSTANCE.Module32NextW(snapshot, next)) {
modules.add(next);
next = new Tlhelp32.MODULEENTRY32W();
}

int lastError = Kernel32.INSTANCE.GetLastError();
// if we got a false from Module32Next,
// check to see if it returned false because we're genuinely done
// or if something went wrong.
if (lastError != W32Errors.ERROR_SUCCESS && lastError != W32Errors.ERROR_NO_MORE_FILES) {
throw new Win32Exception(lastError);
}
} catch (Win32Exception e) {
we = e;
} finally {
if (snapshot != null) {
if (!Kernel32.INSTANCE.CloseHandle(snapshot)) {
Win32Exception e = new Win32Exception(Kernel32.INSTANCE.GetLastError());
if (we != null) {
e.addSuppressed(we);
}
we = e;
}
}
}

if (we != null) {
throw we;
}
return modules;
}
}
108 changes: 108 additions & 0 deletions contrib/platform/src/com/sun/jna/platform/win32/Tlhelp32.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,11 @@
import java.util.Arrays;
import java.util.List;

import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import com.sun.jna.platform.win32.WinDef.DWORD;
import com.sun.jna.platform.win32.WinDef.HMODULE;

/**
* Interface for the Tlhelp32.h header file.
Expand Down Expand Up @@ -156,4 +159,109 @@ protected List getFieldOrder() {
return Arrays.asList(new String[] { "dwSize", "cntUsage", "th32ProcessID", "th32DefaultHeapID", "th32ModuleID", "cntThreads", "th32ParentProcessID", "pcPriClassBase", "dwFlags", "szExeFile" });
}
}


/**
* Describes an entry from a list of the modules belonging to the specified
* process.
*
* @see <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms684225(v=vs.85).aspx">MSDN</a>
*/
public class MODULEENTRY32W extends Structure {

/**
* A representation of a MODULEENTRY32 structure as a reference
*/
public static class ByReference extends MODULEENTRY32W implements Structure.ByReference {
public ByReference() {
}

public ByReference(Pointer memory) {
super(memory);
}
}

public MODULEENTRY32W() {
dwSize = new WinDef.DWORD(size());
}

public MODULEENTRY32W(Pointer memory) {
super(memory);
read();
}

/**
* The size of the structure, in bytes. Before calling the Module32First
* function, set this member to sizeof(MODULEENTRY32). If you do not
* initialize dwSize, Module32First fails.
*/
public DWORD dwSize;

/**
* This member is no longer used, and is always set to one.
*/
public DWORD th32ModuleID;

/**
* The identifier of the process whose modules are to be examined.
*/
public DWORD th32ProcessID;

/**
* The load count of the module, which is not generally meaningful, and
* usually equal to 0xFFFF.
*/
public DWORD GlblcntUsage;

/**
* The load count of the module (same as GlblcntUsage), which is not
* generally meaningful, and usually equal to 0xFFFF.
*/
public DWORD ProccntUsage;

/**
* The base address of the module in the context of the owning process.
*/
public Pointer modBaseAddr;

/**
* The size of the module, in bytes.
*/
public DWORD modBaseSize;

/**
* A handle to the module in the context of the owning process.
*/
public HMODULE hModule;

/**
* The module name.
*/
public char[] szModule = new char[MAX_MODULE_NAME32 + 1];

/**
* The module path.
*/
public char[] szExePath = new char[Kernel32.MAX_PATH];

/**
* @return The module name.
*/
public String szModule() {
return Native.toString(this.szModule);
}

/**
* @return The module path.
*/
public String szExePath() {
return Native.toString(this.szExePath);
}

@Override
protected List<String> getFieldOrder() {
return Arrays.asList(new String[] { "dwSize", "th32ModuleID", "th32ProcessID", "GlblcntUsage",
"ProccntUsage", "modBaseAddr", "modBaseSize", "hModule", "szModule", "szExePath" });
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ public void testOpenProcess() {
public void testQueryFullProcessImageName() {
HANDLE h = Kernel32.INSTANCE.OpenProcess(0, false, Kernel32.INSTANCE.GetCurrentProcessId());
assertNotNull("Failed (" + Kernel32.INSTANCE.GetLastError() + ") to get process handle", h);
char[] path = new char[WinDef.MAX_PATH];
IntByReference lpdwSize = new IntByReference(path.length);
boolean b = Kernel32.INSTANCE.QueryFullProcessImageName(h, 0, path, lpdwSize);
Expand Down Expand Up @@ -1043,4 +1043,76 @@ public boolean invoke(HMODULE module, Pointer type, Pointer lParam) {
assertEquals("GetLastError should be set to 0", WinError.ERROR_SUCCESS, Kernel32.INSTANCE.GetLastError());
assertTrue("EnumResourceTypes should return some resource type names", types.size() > 0);
}

public void testModule32FirstW() {
HANDLE snapshot = Kernel32.INSTANCE.CreateToolhelp32Snapshot(Tlhelp32.TH32CS_SNAPMODULE, new DWORD(Kernel32.INSTANCE.GetCurrentProcessId()));
if (snapshot == null) {
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
}

Win32Exception we = null;
Tlhelp32.MODULEENTRY32W first = new Tlhelp32.MODULEENTRY32W();
try {
if (!Kernel32.INSTANCE.Module32FirstW(snapshot, first)) {
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
}
} catch (Win32Exception e) {
we = e;
} finally {
if (snapshot != null) {
if (!Kernel32.INSTANCE.CloseHandle(snapshot)) {
Win32Exception e = new Win32Exception(Kernel32.INSTANCE.GetLastError());
if (we != null) {
e.addSuppressed(we);
}
we = e;
}
}
}

if (we != null) {
throw we;
}

// not sure if this will be run against java.exe or javaw.exe but this
// check tests both
assertTrue("The first module in the current process should be java.exe or javaw.exe", first.szModule().startsWith("java"));
assertEquals("The process ID of the module ID should be our process ID", Kernel32.INSTANCE.GetCurrentProcessId(), first.th32ProcessID.intValue());
}

public void testModule32NextW() {
HANDLE snapshot = Kernel32.INSTANCE.CreateToolhelp32Snapshot(Tlhelp32.TH32CS_SNAPMODULE, new DWORD(Kernel32.INSTANCE.GetCurrentProcessId()));
if (snapshot == null) {
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
}

Win32Exception we = null;
Tlhelp32.MODULEENTRY32W first = new Tlhelp32.MODULEENTRY32W();
try {
if (!Kernel32.INSTANCE.Module32NextW(snapshot, first)) {
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
}
} catch (Win32Exception e) {
we = e;
} finally {
if (snapshot != null) {
if (!Kernel32.INSTANCE.CloseHandle(snapshot)) {
Win32Exception e = new Win32Exception(Kernel32.INSTANCE.GetLastError());
if (we != null) {
e.addSuppressed(we);
}
we = e;
}
}
}

if (we != null) {
throw we;
}

// not sure if this will be run against java.exe or javaw.exe but this
// check tests both
assertTrue("The first module in the current process should be java.exe or javaw.exe", first.szModule().startsWith("java"));
assertEquals("The process ID of the module ID should be our process ID", Kernel32.INSTANCE.GetCurrentProcessId(), first.th32ProcessID.intValue());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@
import java.util.List;
import java.util.Map;

import com.sun.jna.platform.win32.Tlhelp32.MODULEENTRY32W;
import com.sun.jna.platform.win32.WinNT.HANDLE;
import com.sun.jna.platform.win32.WinNT.LARGE_INTEGER;
import com.sun.jna.ptr.IntByReference;

import junit.framework.TestCase;

Expand Down Expand Up @@ -293,4 +293,16 @@ public void testGetResourceNames() {
assertTrue("explorer.exe should contain a resource of type '14' in it.", names.containsKey("14"));
assertTrue("resource type 14 should have a name named ICO_MYCOMPUTER associated with it.", names.get("14").contains("ICO_MYCOMPUTER"));
}

public void testGetModules() {
List<MODULEENTRY32W> results = Kernel32Util.getModules(Kernel32.INSTANCE.GetCurrentProcessId());

// not sure if this will be run against java.exe or javaw.exe but these checks should work with both
assertNotNull("There should be some modules returned from this helper", results);
assertTrue("The first module in this process should be java.exe or javaw.exe", results.get(0).szModule().startsWith("java"));

// since this is supposed to return all the modules in a process, there should be an EXE and at least 1 Windows DLL
// so assert total count is at least two
assertTrue("This is supposed to return all the modules in a process, so there should be an EXE and at least 1 Windows API DLL.", results.size() > 2);
}
}

0 comments on commit a6a0c4e

Please sign in to comment.