Invalid parameter implementing GetMenuItemInfoW with JNA - java

I am invoking the win32 API function GetMenuItemInfoW. When I invoke the function I it returns false, and Native.getLastError() returns 87:
ERROR_INVALID_PARAMETER 87 (0x57) The parameter is incorrect.
I think that my error is in my implementation of the structure MenuItemInfoW:
#Structure.FieldOrder({"cbSize", "fMask", "fType", "fState", "wId", "hSubMenu", "hBmpChecked", "hBmpUnchecked", "dwItemData", "dwTypeData", "cch", "hbmpItem"})
public class MENUITEMINFOW extends Structure {
public int cbSize;
public int fMask;
public int fType;
public int fState;
public int wId;
public Pointer hSubMenu;
public Pointer hBmpChecked;
public Pointer hBmpUnchecked;
public WinDef.ULONGByReference dwItemData;
public WString dwTypeData;
public int cch;
public Pointer hbmpItem;
public MENUITEMINFOW() {
super();
}
public MENUITEMINFOW(Pointer pointer) {
super(pointer);
}
}
And this is my code for invoking the function:
MENUITEMINFOW menuiteminfow = new MENUITEMINFOW();
menuiteminfow.fMask = 0x00000040 | 0x00000080 | 0x00000004 | 0x00000002;
menuiteminfow.fType = 0x00000000;
menuiteminfow.cch = 256;
menuiteminfow.dwTypeData = new WString(String.join("", Collections.nCopies(256, " ")));
menuiteminfow.cbSize = Native.getNativeSize(menuiteminfow.getClass());
WinDef.BOOL result = User32Ex.INSTANCE.GetMenuItemInfoW(hMenu.getPointer(), 0, true, menuiteminfow.getPointer());
if (!result.booleanValue()) {
int errorCode = Native.getLastError();
System.out.println("Error Code: " + errorCode);
}
I have edited my editing my code for your tip, but I get the same error 87. This is my new code:
MENUITEMINFOW menuiteminfow = new MENUITEMINFOW();
menuiteminfow.fMask = 0x00000040 | 0x00000080 | 0x00000004 | 0x00000002;
menuiteminfow.fType = 0x00000000;
menuiteminfow.cch = 0;
menuiteminfow.dwTypeData = Pointer.NULL;
menuiteminfow.cbSize = Native.getNativeSize(menuiteminfow.getClass());
WinDef.BOOL result = User32Ex.INSTANCE.GetMenuItemInfoW(hMenu.getPointer(),
new WinDef.UINT(0), new WinDef.BOOL(true), menuiteminfow.getPointer());
if (!result.booleanValue()) {
int errorCode = Native.getLastError();
System.out.println("Error Code: " + errorCode);
}
And this is new version of my structure:
#Structure.FieldOrder({"cbSize", "fMask", "fType", "fState", "wId", "hSubMenu", "hBmpChecked", "hBmpUnchecked", "dwItemData", "dwTypeData", "cch", "hbmpItem"})
public class MENUITEMINFOW extends Structure {
public int cbSize;
public int fMask;
public int fType;
public int fState;
public int wId;
public Pointer hSubMenu;
public Pointer hBmpChecked;
public Pointer hBmpUnchecked;
public BaseTSD.LONG_PTR dwItemData;
public Pointer dwTypeData;
public int cch;
public WinDef.HBITMAP hbmpItem;
public MENUITEMINFOW() {
super();
}
public MENUITEMINFOW(Pointer pointer) {
super(pointer);
this.read();
}
}
Thank you for your response.

Your structure mapping can be improved.
First, a ULONG_PTR is not the same as a WinDef.ULONGByReference. The ULONG_PTR is a pointer-sized value, but it does not actually point to anything.
JNA has a built-in BaseTSD.LONG_PTR type which you could use here.
While a Pointer technically works for hbmpItem and the other bitmap fields, the type WinDef.HBITMAP is already defined in JNA so you should use that mapping.
Finally, and the likely cause of your error, dwTypeData receives a String, but it is a buffer that you need to allocate and fill. From the MENUITEMINFO docs:
To retrieve a menu item of type MFT_STRING, first find the size of the string by setting the dwTypeData member of MENUITEMINFO to NULL and then calling GetMenuItemInfo. The value of cch+1 is the size needed. Then allocate a buffer of this size, place the pointer to the buffer in dwTypeData, increment cch, and call GetMenuItemInfo once again to fill the buffer with the string.
So in this case, you'd want to map a Pointer to dwTypeData, call the function the first time with that pointer set to Pointer.NULL, and then alloating memory for it based on incrementing cch:
menuiteminfow.cch++;
// allocate 2 bytes per widechar
menuiteminfow.dwTypeData = new Memory(cch * 2);
You can fetch the string from there after the function call with menuiteminfow.dwTypeData.getWideString().

Related

JNA : Get value from a pointer to a pointer to a structure

I'm getting trouble with JNA about pointer to pointer problem.
Example structure:
typedef struct _A {
unsigned int num;
struct _A *next;
} A, *PA;
C method:
void test(PA *a) {
PA current = (PA) malloc(sizeof(A));
current->num = 123321;
PA next = (PA) malloc(sizeof(A));
next->num = 456;
current->next = next;
*a = current;
}
A simple test in C:
int main() {
PA a = NULL;
test(&a);
printf("%d\n", a->num);
printf("%d", a->next->num);
}
JNA code
public interface DLLLibrary extends Library {
......
void test(PointerByReference a);
}
public class A extends Structure {
public int num;
public ByReference next;
public A() {
super();
}
protected List<String> getFieldOrder() {
return Arrays.asList("num", "next");
}
public A(Pointer peer) {
super(peer);
}
public static class ByReference extends A implements Structure.ByReference { }
public static class ByValue extends A implements Structure.ByValue { }
}
Finally , I am trying to get the structure fields that was updated in C, but get "Invalid memory access"
public static void main(String[] args) {
PointerByReference pointer = new PointerByReference();
DLLLibrary.INSTANCE.test(pointer);
assert pointer.getValue().getInt(0) == 123321; //this works
A a = new A(pointer.getValue());
//assert a.next.num == 456; //excepted action
a.read(); //java.lang.Error: Invalid memory access
}
Any mistakes in my steps?
When you get an "Invalid memory access" error you should start looking at when native memory allocations are done. Usually the API documents that (and tells you how to free it) and when not, you know it's your responsibility. In this case you can see in the C code you've posted, the allocation is done inside the test method:
PA current = (PA) malloc(sizeof(A));
and
PA next = (PA) malloc(sizeof(A));
The problem here is that the Java side doesn't know about that allocation so you have to do it manually.
Your mapping of the function using a PointerByReference looks fine. While you can use getInt(0) on the return, you'd probably be better off at this point just instantiating the A structure from the returned pointer as you've done:
A a = new A(pointer.getValue());
Then a.num should be your expected 123321. Then you have to take the returned pointer (to the native-allocated link) and use that to create another Java-side structure:
A b = new A(a.next);
(You may want to just use a Pointer in the structure to make that part easy. If you use ByReference or A.ByReference then use getPointer() at this part.)
At this point, I believe b.num should give you 456.

JNA getFieldOrder() results in names not matching in HashSet() comparison (JNA's Structure.java, line 925)

Running into a maddening blocking error:
Exception in thread "main" java.lang.Error: Structure.getFieldOrder() on class com.luke.generator.GeneratorEngine$VERSION_INFO returns names ([BuildString, ProtocolMajorVer, ProtocolMinorVer]) which do not match declared field names ([BiuldString, ProtocolMajorVer, ProtocolMinorVer])
at com.sun.jna.Structure.getFields(Structure.java:925)
at com.sun.jna.Structure.deriveLayout(Structure.java:1058)
at com.sun.jna.Structure.calculateSize(Structure.java:982)
at com.sun.jna.Structure.calculateSize(Structure.java:949)
at com.sun.jna.Structure.allocateMemory(Structure.java:375)
at com.sun.jna.Structure.<init>(Structure.java:184)
at com.sun.jna.Structure.<init>(Structure.java:172)
at com.sun.jna.Structure.<init>(Structure.java:159)
at com.sun.jna.Structure.<init>(Structure.java:151)
at com.luke.generator.GeneratorEngine$.<init>(GeneratorEngine.java:108)
at com.luke.generator.connectionVersion(GeneratorEngine.java:297)
at com.luke.generator.Main.main(Main.java:161)
Platform: Intel, Windows 8
JRE 1.7, 32-bit (x86)
Eclipse Kepler, Default encoding UTF-8
jna-4.1.0.jar
32-bit CPP DLL - I can confirm that I am loading the library and calling functions that do not include parameters. I also tried passing WStrings and Strings, but that did not address the issue.
Source:
CPP struct:
typedef struct {
UINT32 ProtocolMajorVer;
UINT32 ProtocolMinorVer;
UI_STRING BuildString; // Build version for the application.
} VERSION_INFO;
CPP Function
DLL_EXPORTS RETURN_TYPES ConnectionVersion (VERSION_INFO &Version) {<body omitted>}
Java code:
//Interface definition
public interface UiApi extends StdCallLibrary {
UiApi INSTANCE = (UiApi) Native.loadLibrary(UiApiPath,UiApi.class);
final String PROTOCOLMAJORVERSION = new String("ProtocolMajorVer");
final String PROTOCOLMINORVERSION = new String("ProtocolMinorVer");
final String BUILDSTRING = new String("BuildString");
public static class VERSION_INFO extends Structure {
public static class ByReference extends VERSION_INFO implements Structure.ByReference {}
public static class ByValue extends VERSION_INFO implements Structure.ByValue {}
public int ProtocolMajorVer;
public int ProtocolMinorVer;
public byte[] BiuldString;
protected List getFieldOrder() {
return Arrays.asList(new String[] { "ProtocolMajorVer","ProtocolMinorVer","BuildString" });
}
}
//Connection
public int Connect(byte[] strServerName);
public int Disconnect();
public int CloseProject();
public int ConnectionVersion(VERSION_INFO result);
public int ConnectionVersion(VERSION_INFO.ByReference result);
public int ConnectionVersion(VERSION_INFO.ByValue result);
}
//Engine.connectionVersion() method
public static int connectionVersion() {
int nReturn = 0;
String str = new String("This is my build version\n");
UiApi uiapilib;
uiapilib = UiApi.INSTANCE;
try {
UiApi.VERSION_INFO.ByReference result = new UiApi.VERSION_INFO.ByReference();
result.ProtocolMajorVer = 0;
result.ProtocolMinorVer = 0;
result.BiuldString = str.getBytes();
nReturn = uiapilib.ConnectionVersion(result);
}
catch (Exception e) {
System.out.println("Error=" + e.getLocalizedMessage());
}
return nReturn;
}
//This is the code in main that results in exception
private static Engine engine;
engine = new GeneratorEngine();
engine.connectionVersion();
I must be missing something basic. Is there something in Eclipse that could possibly be causing the HashSet name comparisons in JNA's Structure.java (line 925) that would result in names not matching? From the exception thrown, these definitions look identical.
Thanks for any tips, guidance, fresh perspectives you can offer.
Check your spelling - the field is called BiuldString not BuildString, you have the i and u reversed.

Syntax error, telling me it wants ; and several other things

Just trying to run through some code for an assignment I'm doing. It is probably simple but for the life of me I can't figure out why I get the above error at the first line
(public WaterLog.......).
Later I want to pass it this line:
[ log = new WaterLog(8, damCapacity); ]
Any help would be appreciated, I am new to this sorry.
public class WaterLog(Integer windowSize, Integer maxEntry) {
private Integer size = windowSize;
private Integer max = maxEntry;
private ArrayList theLog(int windowSize);
private int counter = 0;
public void addEntry(Integer newEntry) throws SimulationException {
theLog.add(0, newEntry);
counter++;
}
public Integer getEntry(Integer index) throws SimulationException {
If (thelog.isEmpty() || thelog.size() < index) {
return null;
}
return thelog.get(index);
}
public Integer variation() throws SimulationException {
int old, recent = 0;
recent = thelog.get(0);
old = thelog.get(thelog.size-1);
return recent-old;
}
public Integer numEntries() {
return counter;
}
}
Assuming SimulationException is defined correctly:
class WaterLog{
private Integer size;
private Integer max ;
private ArrayList<Integer> theLog; //parameterize your lists
private int counter = 0;
public WaterLog(Integer windowSize, Integer maxEntry) //this is the behavior you were looking for
{
this.size = windowSize;
this.max = maxEntry;
theLog = new ArrayList<Integer>(windowSize);
}
public void addEntry(Integer newEntry) throws SimulationException {
theLog.add(0, newEntry);
counter++;
}
public Integer getEntry(Integer index) throws SimulationException {
if (theLog.isEmpty() || theLog.size() < index) { //Java is case sensitive
return null;
}
return theLog.get(index);
}
public Integer variation() throws SimulationException {
int old, recent = 0;
recent = theLog.get(0);
old = theLog.get(theLog.size()-1); //again, watch case, also size is a method
return recent-old;
}
public Integer numEntries() {
return counter;
}
}
See the comments I added.
EDIT: To explain a bit further what was going on, let's take a look at what you were doing.
public class WaterLog(Integer windowSize, Integer maxEntry) {
private Integer size = windowSize;
private Integer max = maxEntry;
private ArrayList theLog(int windowSize);
private int counter = 0;
You seem to have confused a class with a constructor. The variables you defined were attributes, which was correct. You needed to use the syntax I showed in my answer to create a constructor. For that same reason, you don't have access to variables like windowSize. To remedy this, we allow them to still be defined outside the constructor, but assigned values inside it, where we have access to windowSize and maxEntry.
If you want to pass some parameters to this class you need a constructor. By default Each and EVERY class comes with a default constructor - which is there, you just don't see it ( but can declare it). What you can then do is make an overloaded construcotr ( which takes some arguments ) and this is what you want so..
if you have a class
class WaterLog {
// no constructor
}
the above is really a
class WaterLog {
public WaterLog() {
// this is the constructor - if you do not declare it its still here, you just dont see it. Ofcourse you have option to declare it.
}
}
The overloaded constructor is something like this
class WaterLog {
public WaterLog() {
//default constructor
}
public WaterLog(Integer int, String string, etc...) {
//overloaded constructor
}
}
and the above is what you need in order to pass arguments to this class constructor. I am not briliant at explaining things but if you need more clarification just let me know :)

JNA GetIfTable error

I need to get the index of a Network Interface in Windows.
There is NetworkInterface.getIndex() method to do this, but it's only available starting Java 7.
The requirement from the Boss is that the app needs to run in Java 6.
After some searching, I found JNA lib to call Win API functions.
The function itself is GetIfTable (http://msdn.microsoft.com/en-us/library/windows/desktop/aa365943(v=vs.85).aspx)
However, I've not been able to successfully call this function using JNA.
The return value of GetIfTable is always 122 which means ERROR_INSUFFICIENT_BUFFER. Even if I keep adding buffer it still says insufficient buffer, until when the supplied value reach certain number, then "Invalid memory access" error shows up.
Here's what I already did:
public interface IpHlpAPI extends StdCallLibrary {
IpHlpAPI INSTANCE = (IpHlpAPI) Native.loadLibrary("IpHlpAPI", IpHlpAPI.class);
public static class MIB_IFTABLE extends Structure {
public int dwNumEntries;
public MIB_IFROW table[] = new IpHlpAPI.MIB_IFROW[1];
public MIB_IFTABLE() {}
public MIB_IFTABLE(int size) {
this.allocateMemory(size);
}
#Override
protected List getFieldOrder() {
return Arrays.asList(new String[]{"dwNumEntries", "table"});
}
}
public static class MIB_IFROW extends Structure {
public char wszName[] = new char[256];
public int dwIndex;
public int dwType;
public int dwMtu;
public int dwSpeed;
public int dwPhysAddrLen;
public byte bPhysAddr[] = new byte[8];
public int dwAdminStatus;
public int dwOperStatus;
public int dwLastChange;
public int dwInOctets;
public int dwInUcastPkts;
public int dwInNUcastPkts;
public int dwInDiscards;
public int dwInErrors;
public int dwInUnknownProtos;
public int dwOutOctets;
public int dwOutUcastPkts;
public int dwOutNUcastPkts;
public int dwOutDiscards;
public int dwOutErrors;
public int dwOutQLen;
public int dwDescrLen;
public byte bDescr[] = new byte[256];
#Override
protected List getFieldOrder() {
return Arrays.asList(new String[]{"wszName", "dwIndex", "dwType", "dwMtu",
"dwSpeed", "dwPhysAddrLen", "bPhysAddr", "dwAdminStatus", "dwOperStatus",
"dwLastChange", "dwInOctets", "dwInUcastPkts", "dwInNUcastPkts", "dwInDiscards",
"dwInErrors", "dwInUnknownProtos", "dwOutOctets", "dwOutUcastPkts",
"dwOutNUcastPkts", "dwOutDiscards", "dwOutErrors", "dwOutQLen", "dwDescrLen", "bDescr"});
}
}
int GetIfTable(MIB_IFTABLE pIfTable, IntByReference pdwSize, boolean bOrder);
}
public static void main(String[] args) {
IpHlpAPI ipHlpApi = IpHlpAPI.INSTANCE;
IpHlpAPI.MIB_IFTABLE ifTable = new IpHlpAPI.MIB_IFTABLE();
IntByReference psize = new IntByReference(ifTable.size());
int status = ipHlpApi.GetIfTable(ifTable, psize, false);
if (status == 122) {
// Calculate the required number of elements in the MIB_IFROW array
ifTable = new IpHlpAPI.MIB_IFTABLE((psize.getValue() - 4) / ifTable.table[0].size());
psize.setValue(ifTable.size());
status = ipHlpApi.GetIfTable(ifTable, psize, false);
System.out.println(status);
}
System.exit(0);
}
Any ideas why is this happening?
Your input structure isn't large enough. You need to reallocate the table field to be sufficiently large based on the value returned in the pdwSize parameter.
Add a constructor to MIB_IFTABLE that indicates the size of the table array and initializes it accordingly. That will automatically give you a bigger buffer.
MIB_IFTABLE ifTable = new MIB_IFTABLE();
IntByReference psize = new IntByReference(ifTable.size());
int status = ipHlpApi.GetIfTable(ifTable, psize, false);
if (status == 122) {
// Calculate the required number of elements in the MIB_IFROW array
ifTable = new MIB_IFTABLE((psize.getValue() - 4) / ifTable.table[0].size());
psize.setValue(ifTable.size());
status = ipHlpApi.GetIfTable(ifTable, psize, false);
// If status is still 122, then there's an issue with the MIB_IFROW definition
// ...
}
EDIT
Change your constructor:
public MIB_IFTABLE(int nentries) {
this.dwNumEntries = nentries;
this.table = (MIB_IFROW[])new MIB_IFROW().toArray(nentries);
}
You should probably initialize your other ctor to have a default value for dwNumEntries; as it is you'll be passing in a default value of zero, which will guarantee you get a return value of 122 on the first call. I'm assuming dwNumEntries refers to the size of the array.

Detect the location of AppData\LocalLow with JNA

I'm trying to detect the location of AppData\LocalLow work on Java with JNA on Windows 7. But the closest function available for the job is:
W32API.HRESULT SHGetFolderPath(W32API.HWND hwndOwner,int nFolder,W32API.HANDLE
hToken,W32API.DWORD dwFlags,char[] pszPath)
Here we have the Solution in C#
But in my case, JAVA + JNA, I'm wondering how I can use the LocalLow GUID with SHGetFolderPath only, or maybe I should look at the problem from a different angle (maybe JNI would be better here?)
If somebody can help on that, thanks
Cheers
EDIT:
Ok, now I added SHGetKnownFolderPath, but here, it keeps returning me strings like that "?f"
static interface Shell32 extends Library {
public static final int MAX_PATH = 260;
public static final String FOLDERID_APPDATALOW = "{A520A1A4-1780-4FF6-BD18-167343C5AF16}";
static Shell32 INSTANCE = (Shell32) Native.loadLibrary("shell32",
Shell32.class, OPTIONS);
public int SHGetKnownFolderPath(Guid.GUID rfid, int dwFlags, HANDLE hToken,
char[] pszPath);
}
public static void main(String[] args) {
char[] pszPath = new char[Shell32.MAX_PATH];
Guid.GUID localLowId = Ole32Util.getGUIDFromString(Shell32.FOLDERID_APPDATALOW);
int hResult = Shell32.INSTANCE.SHGetKnownFolderPath(localLowId, 0, null, pszPath);
if (hResult == 0) {
String path = new String(pszPath);
int len = path.indexOf('\0');
path = path.substring(0, len);
System.out.println(path);
} else {
System.err.println("Error: " + hResult);
}
}
You can extend Shell32 (or create your own similar class) to get access to the SHGetKnownFolderPath API:
W32API.HRESULT SHGetKnownFolderPath(
Guid.GUID rfid,
W32API.DWORD dwFlags,
W32API.HANDLE hToken,
char[] pszPath);
This Question is Somewhat old However I managed to Solve this issue.
allow me to explain why Kyro approach does not work quite well. This is due
SHGetKnownFolderPath uses a POINTER and not a String or A character array (that why show odd output) . therefore you need to use something like this:
public int SHGetKnownFolderPath(Guid.GUID rfid, int dwFlags, HANDLE hToken, PointerByReference pszPath);
a pointer by reference...
so on this case i attach a example I used:
static interface Shell32 extends StdCallLibrary {
public static final String FOLDERID_APPDATALOW = "{A520A1A4-1780-4FF6-BD18-167343C5AF16}";
static Shell32 INSTANCE = (Shell32) Native.loadLibrary("shell32",
Shell32.class, W32APIOptions.UNICODE_OPTIONS);
public int SHGetKnownFolderPath(Guid.GUID rfid, int dwFlags, HANDLE hToken,
PointerByReference pszPath);
}
public static void main(String[] args) {
Guid.GUID localLowId = Ole32Util.getGUIDFromString(Shell32.FOLDERID_APPDATALOW);
PointerByReference e= new PointerByReference();
int hResult = Shell32.INSTANCE.SHGetKnownFolderPath(localLowId, 0, null, e);
if (hResult == 0) {
char delim='\0';
char Array[]=e.getValue().getCharArray(0,255);
for (int i = 0; i < Array.length; i++) {
if(Array[i]==delim){
char temparr[]=new char[i];
System.arraycopy(Array,0,temparr,0,i);
Array=temparr;
break;
}
}
/*dont forget to release the Pointer*/
Ole32.INSTANCE.CoTaskMemFree(e.getValue());
System.out.println(Array);
} else {
System.err.println("Error: " + hResult);
}
}
private static interface Ole32 extends StdCallLibrary {
Ole32 INSTANCE = (Ole32) Native.loadLibrary(
"Ole32", Ole32.class, W32APIOptions.UNICODE_OPTIONS);
void CoTaskMemFree(Pointer pv);
}

Categories