0

I am using JNA to call a function from a C DLL :

extern _declspec( dllexport )
int ReadCP(IN OUT unsigned char* Id, IN OUT unsigned int* Size);

In Java I am using an interface for JNA with this method :

int ReadCP(byte[] id, IntByReference size);

I load the DLL successfully and call the method that way :

byte[] id= new byte[10];
IntByReference size = new IntByReference();
IMimicDLL demo = (IMimicDLL) Native.loadLibrary("MyLib", IMimicDLL.class);
size.setValue(10);
//....
while(true){
  demo.ReadCP(id, size);
  //...
}

The first time in the loop id has a correct value, but it keeps the same value even if the logic should change it. What can be the problem? Is that something to do with pointers?

Toby
  • 9,696
  • 16
  • 68
  • 132
Anass Boukalane
  • 539
  • 10
  • 26

2 Answers2

3

Your mapping of id is wrong: you cannot pass a primitive array as an argument via JNA.

You should change your interface to use a Pointer:

int ReadCP(Pointer id, IntByReference size);

Then you would allocate native-side memory for id:

Pointer id = new Memory(10);

After passing and retrieving id from the function you would then fetch the byte array from the native memory:

byte[] idByteArray = id.getByteArray(0, 10);

There are other get*() methods for Pointer, such as getString(), that may or may not be more applicable to the ultimate type of the Id field that you're trying to fetch.

As far as the value updating once but not after repeated calls, this sounds like at some point the system is taking a "snapshot" of the current hardware state and you must find a way to refresh that snapshot. Troubleshooting steps would include:

  • Clear out the data in the array/pointer and see if it's repopulated from the C-side DLL (the problem is not in your JNA it's in usage of the DLL).
  • Check your size variable throughout the process to make sure it's remaining the value of 10 you expect. It's possible that when you remove the card it may return 0, and then if you try to read a new value (of length 0) you're not overwriting the old array past index 0.
  • Alternate which card is used first.
  • Alternate the order of starting the program, loading, and swapping out the cards to collect data on which step of the process seems to cause the value to stick.
  • Investigate the DLL for methods to "refresh" or "reload" a snapshot of the hardware state.
  • Try unloading and reloading the DLL in between loops.

Most of these steps are outside of the scope of your question, on using JNA, and would require you to provide more information about the DLL being used for us to help further.

Community
  • 1
  • 1
Daniel Widdis
  • 8,424
  • 13
  • 41
  • 63
  • thank you for your answer , but i still have the same issue : in the while loop i have a logic that should read a card id , i got the same first card's id even if i change the card , the **id** doesn't change. – Anass Boukalane Apr 19 '17 at 15:55
  • That's about all I can help with, with the Java/JNA pieces you've provided. Is there more documentation available for the DLL methods? – Daniel Widdis Apr 19 '17 at 21:40
  • here is my logic in the while loop `while(true){ try { Thread.sleep(1500); } catch (InterruptedException e1) { e1.printStackTrace(); } if(demo.cardPresent() == 0 && read == false){ demo.ReadCP(id, size); try { System.out.println(" -- id : " + new String(id.getByteArray(0, 10),"UTF-8")); read = true; continue; } catch (Exception ex) { ex.printStackTrace(); } }else if(demo.cardPresent() != 0){ read = false; } }` – Anass Boukalane Apr 20 '17 at 11:53
  • 1
    *you cannot pass an array as an argument via JNA* And that's just one of the reasons I gave up on JNA a long time ago and just learned how to do JNI reliably. Once you know how, implementing the JNI side of the Java `static native byte[] getByteArray();` or `static native int fillInByteArray( byte arr[] );` methods is almost trivial. – Andrew Henle Apr 20 '17 at 12:07
  • Fair point, @AndrewHenle. And if you have the ability to write your own C, that's preferred for a variety of reasons. However, if you're stuck with someone else's DLL and can't write your own, JNA isn't a bad backup. (NOTE: I edited my post to clarify "primitive array". You can pass arrays of structures or pointers or other things JNA reserves native memory for.) – Daniel Widdis Apr 20 '17 at 14:59
  • @AnassBoukalane what is the nature of the `id` being read? Does documentation for `ReadCP` indicate it should be different or might it possibly be the same, e.g., a `PNPDeviceID` is not necessarily unique if one is removed and another replaces it. – Daniel Widdis Apr 20 '17 at 15:02
  • @DanielWiddis the id is a document id , it's unique and should be different from card to another one – Anass Boukalane Apr 20 '17 at 15:14
  • @AnassBoukalane are there any other methods in the DLL that prompt a re-read of the card after it's been swapped out? Have you tried starting your program with the second card in first and switching back to the first one? This sounds like not a java/jna issue but more a hardware/dll interface issue. – Daniel Widdis Apr 20 '17 at 15:30
  • @DanielWiddis there is no re-read methods in the DLL and if i switched cards it keeps always the first card id – Anass Boukalane Apr 20 '17 at 15:34
  • Try generating a new Pointer each time in the loop (`id = new Memory(10)` before each `ReadCP()`). That will get rid of the old card ID: if it still doesn't read the new card ID then you've ruled out Java/JNA as the problem. – Daniel Widdis Apr 20 '17 at 15:43
  • Also track what happens to `size` after the read. If it ends up being `0` then you might be reading a 0-length array and not overwriting the old one. – Daniel Widdis Apr 20 '17 at 15:45
  • i have already tried to generate a new pointer each time in the loop , same result – Anass Boukalane Apr 20 '17 at 15:51
  • If a new pointer is reading an old card ID then the problem is outside of Java/JNA and there's nothing else we can help you with here. – Daniel Widdis Apr 20 '17 at 16:03
  • One final thought. It's possible that when you first load the DLL it takes a snapshot of the current state, and you may need to unload/reload the DLL. Again, impossible to further troubleshoot with what you have given us, but offering suggestions on how you can narrow this down. – Daniel Widdis Apr 20 '17 at 17:25
1

here the business login in the while loop

while(true){ 
 try { 
   Thread.sleep(1500); 
 } catch (InterruptedException e1) 
 { 
   e1.printStackTrace();
 } 
if(demo.cardPresent() == 0 && read == false){
 demo.ReadCP(id, size);
 try { 
System.out.println(" -- id : " + new String(id.getByteArray(0, 10),"UTF-8"));
 read = true;
 continue; 
} catch (Exception ex) {
 ex.printStackTrace();
 }
}else if(demo.cardPresent() != 0){
read = false;
} 
Anass Boukalane
  • 539
  • 10
  • 26