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

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)

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 4.2.1 call dll method without params

i use jna 4.2.1
I have a method in the dll which returns a pointer to an object (C++)
basic_hash* getAlgorithmInstance( int algorithm )
basic_hash has the following methods (C++):
void reset ();
void partial (const byte* data, uint64 size);
void finalize (vector_byte& hash);
void hash (const byte* data, uint64 size, vector_byte& hash).
i have interface (java)
public interface HAL extends Library {
HAL INSTANCE = (HAL) Native.loadLibrary(
(Platform.isWindows() ? "HAL" : "libHAL"), HAL.class);
BasicHash getAlgorithmInstance(int i);
}
public static class BasicHash extends Structure {
public BasicHash() {}
public BasicHash(Pointer p) {
super(p);
read();
}
#Override
protected List getFieldOrder() {
return Arrays.asList(new String[] { "reset", "hash", "partial", "finalize" });
}
public interface Reset extends Callback { public void invoke();}
public Reset reset;
public interface Hash extends Callback {public void invoke(byte[] data, long size, byte[] hash);}
public Hash hash;
public interface Partial extends Callback {public void invoke(Pointer data, long size);}
public Partial partial;
public interface Finalize extends Callback {public void invoke(byte[] hash);}
public Finalize finalize;
}
and when I use the method without parameters in main()
HAL lib = HAL.INSTANCE;
BasicHash b = lib.getAlgorithmInstance(0);
b.reset.invoke();
I get an error:
Exception in thread "main" java.lang.Error: Invalid memory access
at com.sun.jna.Native.invokeVoid(Native Method)
at com.sun.jna.Function.invoke(Function.java:374)
at com.sun.jna.Function.invoke(Function.java:323)
at com.sun.jna.Function.invoke(Function.java:275)
at com.sun.jna.CallbackReference$NativeFunctionHandler.invoke(CallbackReference.java:646)
at com.sun.proxy.$Proxy1.invoke(Unknown Source)
at net.erver.ItServer.main(ItServer.java:79)
Why did I receive this error if the method resets the variables within the library? the method itself fulfills without problems (according to developers dll)
EDIT:
vector_byte has definition:
typedef unsigned char byte;
typedef std::vector< byte > vector_byte
and basic_hash has definition:
namespace HAL { namespace algorithms {
HAL_HASH_API enum class State : byte {
Normal,
Finished,
};
class HAL_HASH_API basic_hash
{
public:
virtual ~basic_hash() {}
virtual void reset() = 0;
virtual void partial( const byte*, uint64 ) = 0;
virtual void finalize( vector_byte& ) = 0;
virtual void hash( const byte*, uint64, vector_byte& ) = 0;
bool isFinished() {
return ( _state == State::Finished ? true : false );
}
protected:
State _state;
};
}
}
You need to use plain vanilla struct to pass data between JNA and your library. A C++ class (including a vector template) has a much different memory layout than does a simple C struct.

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);
}

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();
}

Calling a Scanner Win32 DLL from Java

We have to connect to a scanner and perform some functions from our Java application. The customer has provided us Win32 Scanner Library Specification.
Example: BOOL GetScannerInfo(ScannerInfo *scanner)
Structure ScannerInfo is defined in a header file.
#define scannerMAX 10 // Maximum number of connected scanners
typedef struct{
int count;// -> Number of scanners connected
BYTE host_no[scannerMAX]; // -> Host adapter number
BYTE scsi_id[scannerMAX]; // -> SCSI ID of the scanner
}ScannerInfo;
For example, if two scanners, SCSI IDs 1 and 2, are connected to one host adapter, the return values will be as follows:
count=2
host_no[0]=0, host_no[1]=0
scsi_id[0]=1, scsi_id[1]=2
Now, we have to call this function and get scanner related information from Java.
Got started with JNA for the first time and here is the code.
public interface ScannerInterface extends Library {
public boolean GetScannerInfo(?);
/* ? = They have a pointer of a custom object.What should be passed here
*/
}
public static void main(String[] args) {
ScannerInterface lib = (ScannerInterface) Native.loadLibrary("in64.dll",
ScannerInterface.class);
System.out.println(lib.GetScannerInfo(?));
}
I am stuck on how to pass the parameters that the Win32 function expects from JNA.
You can define the Java class ScannerInfo that maps to your struct like this:
public interface ScannerInterface extends Library {
public static class ScannerInfo extends Structure {
public static class ByReference
extends ScannerInfo
implements Structure.ByReference {}
public int count;
public byte[] host_no = new byte[10];
public byte[] scsi_id = new byte[10];
}
public int GetScannerInfo(ScannerInfo.ByReference scanner);
}
Then call it like this:
ScannerInterface lib = (ScannerInterface) Native.loadLibrary("in64.dll",
ScannerInterface.class);
ScannerInterface.ScannerInfo.ByReference scanner =
new ScannerInterface.ScannerInfo.ByReference();
int retval = lib.GetScannerInfo(scanner);
// check retval in case of error
int count = scanner.count;
// etc. etc.

Categories