B4J Question JNA : access C++ DLL methods & variables type conversion

GabrielM

Member
Licensed User
Longtime User
Hello,

Happened to need to call some methods from C++ generated Windows DLL (I do not have access to its source, but methods prototype are available). Looking around I have tried to use JNA examples.
I have compiled with SLC the library though when I try to use the method in B4J I get :

B4X:
java.lang.Error: Invalid memory access
...

The C++ method prototype is:

B4X:
C++ method :
unsigned short ASTDiscoverDevice(int &DeviceNum, char deviceName[][17],
unsigned char* deviceType);

and I though to have the JNA side method prototype like:

B4X:
public int ASTDiscoverDevice(int DeviceNum, byte[] deviceName, byte[] deviceType);

The SDK I can not post as it is licensed, but I can attach the attempted JNA code as I have it so far. I do not have experience with JNA or Java and will appreciate any help here or private.



Gabi.
 

Attachments

  • JNA_Test.zip
    286.1 KB · Views: 222

rboeck

Well-Known Member
Licensed User
Longtime User
You got two mistakes in your paramters. The vers first parameter of ASTDiscoverDevice is not of type int but a reference to type (int&, notice the & before the paramtere name DeviceNum). I have little experience with JNA but it seems like you need to use IntByReference instead of int. Second parameter you got wrong is deviceName. The C++ API itsself is not very nice admittedly as this is actually an array of unkown size of an array of fixed size of 17 of type char. This is either mappable using an array of strings, so String[], or char[][]. Hope this helps!
 
Upvote 0

GabrielM

Member
Licensed User
Longtime User
... and here is the B4J code I have used to test the above JNA library.
 

Attachments

  • JNA_Test._B4J.zip
    297 KB · Views: 248
Upvote 0

GabrielM

Member
Licensed User
Longtime User
Thanks rboek

Have added/replaced as below and it seems I got no more Memory errors like before.
Probably I should use the same ByRef for the other two array parameters.


B4X:
import com.sun.jna.ptr.IntByReference;

IntByReference DeviceNum = new IntByReference();

public int ASTDiscoverDevice(IntByReference DeviceNum, char[] deviceName, char[] deviceType);
 
Upvote 0

GabrielM

Member
Licensed User
Longtime User
Got it running all ok while in B4J compiled though when I produce the EXE file (using Launch4J) and try to execute it seems that it does not find the required dll file. The program does not crash or such but it just does not perform the related actions to dll calls.
The dll is placed in Files folder in B4J program and when compiling the library the dll is in /libs folder. Library compiled with SLC v1.1

In library src I use:

B4X:
@BA.Hide
   public interface libA extends Library {

// create a run-time link to the DLL
        libA INSTANCE = (libA) Native.loadLibrary("libA", libA.class);
...
...
}

I do have tried to place the dll in the EXE folder to no joy.

I have read around and seen this:
B4X:
static { System.load(anywheresoftware.b4a.objects.streams.File.getDirApp() + "/libA.dll");  }
but I have no knowledge on how to modify the library source.

This is the library source:

B4X:
package LibA;

import anywheresoftware.b4a.BA.Author;
import anywheresoftware.b4a.BA.ShortName;
import anywheresoftware.b4a.BA.Version;
import anywheresoftware.b4a.BA;
import anywheresoftware.b4a.BA.DependsOn;

import com.sun.jna.Library;
import com.sun.jna.Memory;
import com.sun.jna.Native;
import com.sun.jna.ptr.IntByReference;


@Version(1.0f)
@Author("test")
@ShortName("LibA")
@DependsOn(values={"jna-4.3.0","jna-platform-4.3.0"})


public class LibA {
    
    //static { System.load(anywheresoftware.b4a.objects.streams.File.getDirApp() + "/libA.dll");  }

    public  char DeviceIndex ;


    @BA.Hide
    public interface libA extends Library {
        
        // create a run-time link to the DLL
        libAs INSTANCE = (libA) Native.loadLibrary("libA", libA.class);
        
        // method prototypes
        public short AConnectDevice(char DeviceIndex);
    }
    
    
    public short ConnectALP()
    {
        char devIndex = 0;
        short result;
        
        result = libA.INSTANCE.AConnectDevice(devIndex);
        return result;
    }
    
}
 
Last edited:
Upvote 0

GabrielM

Member
Licensed User
Longtime User
Yes, the app launches and runs ok while I run jar from \Objects.

Solved it now, took your advice on using the B4J Packager, got the distributable installed nicely by Inno, wonderful.
My bad, honestly I did not know it exist. I should read the forum more often.
Many thanks for the great support !


There aren't many good reasons to use Launch4j. If you want to create a standalone distributable then you should use B4J Packager (11) otherwise there is a small difference between an executable jar and the generated EXE file.

Does it work in release mode when you run the jar directly?
 
Upvote 0
Top