Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added EnumResourceTypes and EnumResourceNames to Kernel32 #545

Merged
merged 1 commit into from
Dec 1, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Features
* [#535](https://github.com/java-native-access/jna/pull/535): Added `GetDesktopWindow` to `com.sun.jna.platform.win32.User32` - [@mlfreeman2](https://github.com/mlfreeman2).
* [#543](https://github.com/java-native-access/jna/pull/543): Added `ProcessIdToSessionId`, `LoadLibraryEx`, `FreeLibrary` and `Find/Load/Lock/SizeofResource` to `com.sun.jna.platform.win32.Kernel32` - [@mlfreeman2](https://github.com/mlfreeman2).
* [#547](https://github.com/java-native-access/jna/pull/547): Added `GetSystemTimes` to `com.sun.jna.platform.win32.Kernel32` - [@dbwiddis](https://github.com/dbwiddis).
* [#545](https://github.com/java-native-access/jna/pull/545): Added `EnumResourceTypes` and `EnumResourceNames` to `com.sun.jna.platform.win32.Kernel32` - [@mlfreeman2](https://github.com/mlfreeman2).

Bug Fixes
---------
Expand Down
67 changes: 67 additions & 0 deletions contrib/platform/src/com/sun/jna/platform/win32/Kernel32.java
Original file line number Diff line number Diff line change
Expand Up @@ -3202,4 +3202,71 @@ boolean GetVolumePathNamesForVolumeName(String lpszVolumeName,
* information, call the GetLastError function.
*/
boolean FreeLibrary(HMODULE module);

/**
* Enumerates resource types within a binary module.<br>
* Starting with Windows Vista, this is typically a language-neutral
* Portable Executable (LN file), and the enumeration also includes
* resources from one of the corresponding language-specific resource files
* (.mui files)-if one exists-that contain localizable language resources.
* It is also possible to use hModule to specify a .mui file, in which case
* only that file is searched for resource types.<br>
* Alternately, applications can call EnumResourceTypesEx, which provides
* more precise control over which resource files to enumerate.
*
* @param hModule
* A handle to a module to be searched.<br>
* This handle must be obtained through LoadLibrary or
* LoadLibraryEx.<br>
* See Remarks for more information. If this parameter is NULL,
* that is equivalent to passing in a handle to the module used
* to create the current process.
* @param proc
* A pointer to the callback function to be called for each
* enumerated resource type.<br>
* For more information, see the EnumResTypeProc function.
* @param lParam
* An application-defined value passed to the callback function.
* @return Returns TRUE if successful; otherwise, FALSE. To get extended
* error information, call GetLastError.
*/
boolean EnumResourceTypes(HMODULE hModule, WinBase.EnumResTypeProc proc, Pointer lParam);

/**
* Enumerates resources of a specified type within a binary module. <br>
* For Windows Vista and later, this is typically a language-neutral
* Portable Executable (LN file), and the enumeration will also include
* resources from the corresponding language-specific resource files (.mui
* files) that contain localizable language resources.<br>
* It is also possible for hModule to specify an .mui file, in which case
* only that file is searched for resources.
*
* @param hModule
* A handle to a module to be searched. <br>
* Starting with Windows Vista, if this is an LN file, then
* appropriate .mui files (if any exist) are included in the
* search.<br>
* If this parameter is NULL, that is equivalent to passing in a
* handle to the module used to create the current process.
* @param type
* The type of the resource for which the name is being
* enumerated.<br>
* Alternately, rather than a pointer, this parameter can be
* MAKEINTRESOURCE(ID), where ID is an integer value representing
* a predefined resource type.<br>
* For a list of predefined resource types, see Resource Types.
* For more information, see the Remarks section below.
* @param proc
* A pointer to the callback function to be called for each
* enumerated resource name or ID. For more information, see
* EnumResNameProc.
* @param lParam
* An application-defined value passed to the callback function.
* This parameter can be used in error checking.
* @return The return value is TRUE if the function succeeds or FALSE if the
* function does not find a resource of the type specified, or if
* the function fails for another reason. To get extended error
* information, call GetLastError.
*/
boolean EnumResourceNames(HMODULE hModule, Pointer type, WinBase.EnumResNameProc proc, Pointer lParam);
}
114 changes: 113 additions & 1 deletion contrib/platform/src/com/sun/jna/platform/win32/Kernel32Util.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
import java.io.File;
import java.io.FileNotFoundException;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
Expand Down Expand Up @@ -702,6 +704,7 @@ public static byte[] getResource(String path, String type, String name) {
Win32Exception err = null;
Pointer start = null;
int length = 0;
byte[] results = null;
try {
Pointer t = null;
try {
Expand Down Expand Up @@ -741,6 +744,8 @@ public static byte[] getResource(String path, String type, String name) {
if (start == null) {
throw new IllegalStateException("LockResource returned null.");
}
// have to capture it into a byte array before you free the library, otherwise bad things happen.
results = start.getByteArray(0, length);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was the mistake. If you don't get the resource into a byte array before calling FreeLibrary() you're doomed.

} catch (Win32Exception we) {
err = we;
} finally {
Expand All @@ -760,7 +765,114 @@ public static byte[] getResource(String path, String type, String name) {
throw err;
}

return start.getByteArray(0, length);
return results;
}

/**
* Gets a list of all resources from the specified executable file
*
* @param path
* The path to the executable file
* @return A map of resource type name/ID => resources.<br>
* A map key + a single list item + the path to the executable can
* be handed off to getResource() to actually get the resource.
*/
public static Map<String, List<String>> getResourceNames(String path) {
HMODULE target = Kernel32.INSTANCE.LoadLibraryEx(path, null, Kernel32.LOAD_LIBRARY_AS_DATAFILE);

if (target == null) {
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
}

final List<String> types = new ArrayList<String>();
final Map<String, List<String>> result = new LinkedHashMap<String, List<String>>();

WinBase.EnumResTypeProc ertp = new WinBase.EnumResTypeProc() {

@Override
public boolean invoke(HMODULE module, Pointer type, Pointer lParam) {
// simulate IS_INTRESOURCE macro defined in WinUser.h
// basically that means that if "type" is less than or equal to 65,535
// it assumes it's an ID.
// otherwise it assumes it's a pointer to a string
if (Pointer.nativeValue(type) <= 65535) {
types.add(Pointer.nativeValue(type) + "");
} else {
types.add(type.getWideString(0));
}
return true;
}
};

WinBase.EnumResNameProc ernp = new WinBase.EnumResNameProc() {

@Override
public boolean invoke(HMODULE module, Pointer type, Pointer name, Pointer lParam) {
String typeName = "";

if (Pointer.nativeValue(type) <= 65535) {
typeName = Pointer.nativeValue(type) + "";
} else {
typeName = type.getWideString(0);
}

if (Pointer.nativeValue(name) < 65535) {
result.get(typeName).add(Pointer.nativeValue(name) + "");
} else {
result.get(typeName).add(name.getWideString(0));
}

return true;
}
};


Win32Exception err = null;
try {
if (!Kernel32.INSTANCE.EnumResourceTypes(target, ertp, null)) {
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
}

for (final String typeName : types) {
result.put(typeName, new ArrayList<String>());

// simulate MAKEINTRESOURCE macro in WinUser.h
// basically, if the value passed in can be parsed as a number then convert it into one and run with that.
// otherwise, assume it's a string and construct a pointer to said string.
Pointer pointer = null;
try {
pointer = new Pointer(Long.parseLong(typeName));
} catch (NumberFormatException e) {
pointer = new Memory(Native.WCHAR_SIZE * (typeName.length() + 1));
pointer.setWideString(0, typeName);
}

boolean callResult = Kernel32.INSTANCE.EnumResourceNames(target, pointer, ernp, null);

if (!callResult) {
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
}
}
} catch (Win32Exception e) {
err = e;
} finally {
// from what I can tell on MSDN, the only thing that needs cleanup
// on this is the HMODULE from LoadLibrary
if (target != null) {
if (!Kernel32.INSTANCE.FreeLibrary(target)) {
Win32Exception we = new Win32Exception(Kernel32.INSTANCE.GetLastError());
if (err != null) {
we.addSuppressed(err);
}
throw we;
}
}
}

if (err != null) {
throw err;
}
return result;
}

}
Loading