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

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.

Related

How to set up a correct size of buffer of the structure?

I have a documentation for DLL which I have to use where is defined a structure which is an argument to one of the native mathod.
It looks like here:
typedef struct
{
UNUM32 uiModuleState;
UNUM32 uiSerialNumber;
UNUM32 uiVCIIf;
UNUM32 uiModuleType;
CHAR8 szModuleName[256];
}
VTX_RT_VCI_ITEM;
typedef struct
{
UNUM32 uiNumVCIItems;
VTX_RT_VCI_ITEM * pVCIItems;
}
VTX_RT_VCI_ITEM_LIST;
Calling Convention:
SNUM32 VtxRtGetModuleIds( IO UNUM32* puiBufferLen,
IO VTX_RT_VCI_ITEM_LIST* pVCIItemList);
I have modeled that structure in the JNA like here
VTX_RT_VCI_ITEM
#Structure.FieldOrder({ "uiModuleState",
"uiSerialNumber",
"uiVCIIf",
"uiModuleType",
"szModuleName" })
public class VtxRtVciItem extends Structure
{
public int uiModuleState;
public int uiSerialNumber;
public int uiVCIIf;
public int uiModuleType;
public char[] szModuleName = new char[VciRuntimeAPI.VTX_RT_SMALL_BUF_SIZE];
public static class ByReference extends VtxRtVciItem implements Structure.ByReference {}
public static class ByValue extends VtxRtVciItem implements Structure.ByValue {}
public VtxRtVciItem()
{
super();
read();
}
}
VTX_RT_VCI_ITEM_LIST
#Structure.FieldOrder({ "uiNumVCIItems",
"pVCIItems" })
public class VtxRtVciItemList extends Structure
{
public int uiNumVCIItems;
public VtxRtVciItem.ByReference pVCIItems;
public VtxRtVciItemList()
{
super();
}
}
A first argument is described as follow
puiBufferLen
Size of the buffer pointed to by pVCIItemList.
How to set up a correct buffer size of that structure?
I was trying to do something like here but the size of that structure is 8 which means that VtxRtVciItem is not callculated.
VtxRtVciItemList vtxRtVciItemList = new VtxRtVciItemList();
IntByReference puiBufferLen = new IntByReference();
puiBufferLen.setValue(vtxRtVciItemList.size());
Your vtxRtVciItemList is just a structure with the number of list elements and a pointer to the actual list. The list buffer itself will be the size of each structure in the list (new VtxRtVciItem().size()) multiplied by the number of those elements (uiNumVCIItems).
You don't show where you actually allocate that buffer, which you'll need to use the Structure.toArray() method to do.
I think this is what you want to do, let me know if I've misinterpreted your request.
int numItems = 42; // whatever your number of list items is
VtxRtVciItem.ByReference[] vtxRtVciItemPointerArray =
(VtxRtVciItem.ByReference[]) new VtxRtVciItem.ByReference().toArray(numItems);
VtxRtVciItemList vtxRtVciItemList = new VtxRtVciItemList();
vtxRtVciItemList.uiNumVCIItems = numItems;
vtxRtVciItemList.pVCIItems = vtxRtVciItemPointerArray[0];
And then pass to your function:
IntByReference puiBufferLen =
new IntByReference(vtxRtVciItemList.uiNumVCIItems * vtxRtVciItemPointerArray[0].size());
VtxRtGetModuleIds(puiBufferLen, pVCIItemList);

How do I use a more specific struct type in place of a more general one?

I am working on a windows device manager which will work with java.
I stick on trying to pass without error SetupDiSetClassInstallParams function. (I am trying disable an device.)
I am running exact same structure(necessary way) in C++ and I do not have any problem.
I am getting ERROR_INVALID_USER_BUFFER error. When I tried get this error in C++ I need to change SP_PROPCHANGE_PARAMS structs values with wrong ones.
My struct declerations:
public static class SP_CLASSINSTALL_HEADER extends Structure {
public static class ByReference extends SP_CLASSINSTALL_HEADER implements Structure.ByReference {
public ByReference() {
}
public ByReference(Pointer memory) {
super(memory);
}
}
public SP_CLASSINSTALL_HEADER() {
cbSize = size();
}
public SP_CLASSINSTALL_HEADER(Pointer memory) {
super(memory);
read();
}
public int cbSize;
public long InstallFunction; **/* <-- this should be int or else buffer size changes, dll cannot place variables on right places. */**
protected List getFieldOrder() {
return Arrays.asList(new String[] { "cbSize", "InstallFunction" });
}
}
public static class SP_PROPCHANGE_PARAMS extends Structure {
public static class ByReference extends SP_PROPCHANGE_PARAMS implements Structure.ByReference {
public ByReference() {
}
public ByReference(Pointer memory) {
super(memory);
}
}
public SP_PROPCHANGE_PARAMS() {
}
public SP_PROPCHANGE_PARAMS(Pointer memory) {
super(memory);
read();
}
public SP_CLASSINSTALL_HEADER ClassInstallHeader = new SP_CLASSINSTALL_HEADER();
public int StateChange;
public int Scope;
public int HwProfile;
protected List getFieldOrder() {
return Arrays.asList(new String[] { "ClassInstallHeader", "StateChange", "Scope", "HwProfile" });
}
}
My function decleration:
boolean SetupDiSetClassInstallParams(WinNT.HANDLE hDevInfo, Pointer deviceInfoData, Pointer classInstallHeader, int size);
How do I calling this function:
SP_PROPCHANGE_PARAMS spPropChangeParams = new SP_PROPCHANGE_PARAMS();
spPropChangeParams.ClassInstallHeader.InstallFunction = DISetupApi.DIF_PROPERTYCHANGE;
spPropChangeParams.Scope = DISetupApi.DICS_FLAG_GLOBAL;
spPropChangeParams.HwProfile = 0;
spPropChangeParams.StateChange = DISetupApi.DICS_DISABLE;
int spPropChangeParamsSize = spPropChangeParams.size();
SP_CLASSINSTALL_HEADER classInstallHeaderReference = new SP_CLASSINSTALL_HEADER(spPropChangeParams.getPointer());
setupApi.SetupDiSetClassInstallParams(hDevInfo, device.getSPDeviceInfoData().getPointer(), classInstallHeaderReference.getPointer(),
spPropChangeParamsSize);
How It works in c++:
SP_PROPCHANGE_PARAMS spPropChangeParams;
spPropChangeParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
spPropChangeParams.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
spPropChangeParams.Scope = DICS_FLAG_GLOBAL;
spPropChangeParams.HwProfile = 0;
spPropChangeParams.StateChange = DICS_DISABLE;
SetupDiSetClassInstallParams(hDeviceInfo, &device.getDeviceInfoData(), (SP_CLASSINSTALL_HEADER*)&spPropChangeParams, sizeof(spPropChangeParams));
Actually I mixed and matched too many ways these structs and function I changed variable types of structs and parameter types of function at the end I could not get anything but error. I cannot find what is my mistake. Could you please help me solve this.
Thanks in advance!
When you're passing around a Structure, don't use Structure.getPointer() unless you have to. When you do that, JNA can't automatically synch the native and Java data, and it's error-prone to remember where to do that yourself. In your case, whatever is in the Java fields never gets copied to native memory in your call to setupApi.SetupDiSetClassInstallParams.
Change your function mapping to this:
boolean SetupDiSetClassInstallParams(WinNT.HANDLE hDevInfo, SP_DEVINFO_DATA deviceInfoData, SP_CLASSINSTALL_HEADER classInstallHeader, int size);
and change the invocation to this:
setupApi.SetupDiSetClassInstallParams(hDevInfo, device.getSPDeviceInfoData(), classInstallHeaderReference, spPropChangeParamsSize);
EDIT
If you stick to your original struct definition (where SP_CLASSINSTALL_HEADER is a field), you need to add a function mapping to the interface (extend the interface and create your own instance of the native library):
public interface MySetupApi extends SetupApi {
MySetupApi INSTANCE = (MySetupApi)Native.loadLibrary(MySetupApi.class, W32APIOptions.DEFAULT_OPTIONS);
boolean SetupDiSetClassInstallParams(WinNT.HANDLE hDevInfo, SP_DEVINFO_DATA deviceInfoData, SP_PROPCHANGE_PARAMS propChangeParams, int size);
}

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.

Odd return from WlanEnumInterfaces (Windows Native WiFi) in Java

I'm trying to map the Windows Native Wifi API in Java but I'm having problems with the WlanEnumInterfaces function. Basically, this function outputs a WLAN_INTERFACE_INFO_LIST structure containing an array of WLAN_INTERFACE_INFO structures.
When I call the WlanEnumInterfaces in my Java program, its return value indicates that the function succeeds, but when I check the number of items in the WLAN_INTERFACE_INFO array, I get inconsistent values like 1367280 or 4000000. This value should be 1 as I have only one wireless interface on my machine.
Here it's my mapping of the WlanEnumInterfaces function:
public int WlanEnumInterfaces(
HANDLE hClientHandle,
PointerByReference pReserved,
WLAN_INTERFACE_INFO_LIST.ByReference ppInterfaceList);
Implementation of WLAN_INTERFACE_INFO_LIST:
public static class WLAN_INTERFACE_INFO_LIST extends Structure {
public static class ByReference extends WLAN_INTERFACE_INFO_LIST implements Structure.ByReference{}
public int dwNumberOfItems;
public int dwIndex;
public WLAN_INTERFACE_INFO[] InterfaceInfo = new WLAN_INTERFACE_INFO[10];
#Override
protected List getFieldOrder() {
return Arrays.asList(new String[] {"dwNumberOfItems","dwIndex","InterfaceInfo"});
}
}
And part of the code that calls the function:
HANDLE wlanHandle = getWlanHandle();
WLAN_INTERFACE_INFO_LIST.ByReference ppInterfaceList = new WLAN_INTERFACE_INFO_LIST.ByReference();
int ret = Wlanapi.INSTANCE.WlanEnumInterfaces(wlanHandle,null,ppInterfaceList);
System.out.println("Return: " + ret);
System.out.println("WlanEnumInterfaces->number of items: "+ppInterfaceList.dwNumberOfItems);
Does anyone know what is happening?
Thanks!
The WlanEnumInterfaces populates the field you provide it with the address of a struct. You are passing in the address of a struct rather than the address of an address.
Use PointerByReference to get the address of the struct, e.g.
PointerByReference pref = new PointerByReference();
Wlanapi.INSTANCE.WlanEnumInterfaces(handle, null, pref);
WLAN_INTERFACE_INFO_LIST list = new WLAN_INTERFACE_INFO_LIST(pref.getValue());
Then you need a Pointer-based constructor for WLAN_INTERFACE_INFO_LIST, i.e.
WLAN_INTERFACE_INFO_LIST(Pointer p) {
super(p);
this.dwNumberOfItems = p.readInt(0);
this.InterfaceInfo = new WLAN_INTERFACE_INFO[this.dwNumberOfItems];
read();
}

how do i pass pointer ref to native method in JNI [duplicate]

This is native method from ITLSSPProc.dll
NOMANGLE int CCONV OpenSSPComPort (SSP_COMMAND * cmd);
Here, SSP_COMMAND is structure in ITLSSPProc.dll which is in C++
Language.
struct SSP_COMMAND
{
unsigned long BaudRate;
unsigned char PortNumber;
};
So, I have to access OpenSSPComPort (SSP_COMMAND * cmd) in java using
JNI. Here is a code i have written,
public class Main {
public interface ITLSSPProc extends Library {
ITLSSPProc INSTANCE = (ITLSSPProc) Native.loadLibrary(
(Platform.isWindows() ? "ITLSSPProc" : "simpleDLLWindowsPort"), ITLSSPProc.class);
int OpenSSPComPort(Pointer param);
int CloseSSPComPort();
}
public static void main(String[] args)throws IOException {
ITLSSPProc sdll = ITLSSPProc.INSTANCE;
Memory intMem = new Memory(10); // allocating space
intMem.setLong(0,9600);
intMem.setString(1,"com7");
if(sdll.OpenSSPComPort(intMem)==1)
{// calling function with int parameter&result
System.out.println("connected");
}
else
{
System.out.println("failed");
}
}
}
Output : failed
Port number is COM7 on which we are working. So, when i run this
application and as i passing baud rate as manually as given in user
manual and if port number is correct it has to print "connected" on
console. So, anybody know where i am going wrong, i dont understand
where is actual problem..
JNA documentation for basic types (long, char).
JNA documentation for aggregate types (struct, struct *).
// tl;dr
class SSP_COMMAND extends Structure {
public NativeLong BaudRate;
public byte PortNumber;
}
int OpenSSPComPort(SSP_COMMAND param)

Categories