I am having trouble with JNA and a DLL file created from LabVIEW. I am able to call it when I don't use this line, the first one:
FileWriter writer = new FileWriter(FirstPath);
BufferedWriter writing = new BufferedWriter(writer);
writing.write("Here goes my strings");
writing.close();
After this the DLL class is followed as:
DLLClass dll = (DLLClass)Native.loadLibrary("DLLFile",DLLClass.class);
dll.myMethodInsideDLLClass(FirstPath,SecondPath,ThirdPath);
It looks that it's trying to access some random FirstPath or I don't know what. It gives me this error.
Exception in thread "AWT-EventQueue-0" java.lang.Error: Invalid memory access
at com.sun.jna.Native.getStringBytes(Native Method)
at com.sun.jna.Native.getString(Native.java:2224)
at com.sun.jna.Pointer.getString(Pointer.java:681)
at com.sun.jna.Function.invokeString(Function.java:667)
at com.sun.jna.Function.invoke(Function.java:434)
at com.sun.jna.Function.invoke(Function.java:361)
at com.sun.jna.Library$Handler.invoke(Library.java:265)
at com.sun.proxy.$Proxy0.myMethodInsideDLLClass(Unknown Source)
I mean how in the world can I access the same file I am trying to write to and then call it again in the dll method? I tried and nothing worked. Can someone help me? I would appreciate this very much!
Note: This is my DllClass:
public interface DLLClass extends Library{
public int myMethodInsideDLLClass(String
FirstPath, String SecondPath, String ThirdPath);
}
extends Libray comes from jna.jar.
This is what inside my FileDll.h file:
#ifdef __cplusplus
extern "C" {
#endif
int32_t __cdecl myMethodInsideDLLClass(
char FirstPath[], char SecondPath[],
char ThirdPath[]);
MgErr __cdecl LVDLLStatus(char *errStr, int errStrLen, void *module);
void __cdecl SetExcursionFreeExecutionSetting(Bool32 value);
#ifdef __cplusplus
} // extern "C"
#endif
#pragma pack(pop)
After you have tried Daniel's suggestion, and in case it does not work, please try this:
Replace this line:
public interface DLLClass extends Library
With this line:
public interface DLLClass extends com.sun.jna.win32.StdCallLibrary
Another potential problem that I can think of is that you might be using a somewhat recent version of java, but your version of JNA is old, or your version of library "DLLFile" is old, and it does not know that the internal representation of java strings has changed in recent java versions, storing the bytes in whatever encoding was used at the time of creation instead of always UTF16. But this is really grasping at straws here.
Your stack trace gives a strong hint at the source of the problem.
at com.sun.jna.Pointer.getString(Pointer.java:681)
at com.sun.jna.Function.invokeString(Function.java:667)
If you look at the JNA source for invokeString() you'll see it's calling the getString() method, assuming 1-byte character encoding (ASCII). But Windows by default uses a 2-byte Unicode character encoding, and this method needs to know to use a wide string so it will call getWideString().
This can be addressed by assigning the appropriate Type Mapper when loading the DLL. The easiest way to do this is to add the default Windows type mapping:
DLLClass dll = (DLLClass) Native.loadLibrary("DLLFile", DLLClass.class,
W32APIOptions.DEFAULT_OPTIONS);
That is the standard way of doing it with a WinAPI method. Technically if your method is not part of the WinAPI you should probably define your own type mapper, using that one as a template.
Related
We are working on a C library and trying to consume it on an Android kotlin project.
Everything works fine except for enum declared in the library itself.
It seems that cases defined are not available.
We had the same issue on Swift but we were able to takle it by conditional compiling the library and adding a specific attribute in the C code. Here a sample .h that once consumed by swift compiler can show the correct number of enum cases instead of just the uint32_t raw value.
#if defined (__APPLE__)
#include <CoreFoundation/CFAvailability.h>
typedef CF_ENUM(uint32_t, Cases) {
case_zero = 0,
case_one = 1
};
#else
typedef enum {
case_zero = 0,
case_one = 1
} Cases;
#endif
Is there any way to mark the enumeration to make it visible with all cases also on a kotlin(or maybe java) project without the need of rewriting a remapping?
I am writing a wrapper class for C++ ".so". I want to use the library in Java application and Android app using JNI. So I have to create header file and cpp file which will do JNI calls.
I could use that on Linux in Java application.
The steps I followed:
Created java class and called native functions in that class
public class TestWrapper {
static {
System.load("/home/native.so");
}
public static void main(String[] args) {
new TestWrapper().TestWrapper();
}
private native void sayHello();
}
Created header file and cpp file. CCP contains following code
JNIEXPORT void JNICALL Java_TestWrapper_sayHello(JNIEnv *, jobject){
uint16_t data = 0;
void (*func_print_name)(const uint16_t*);
void* handle = dlopen("libCppTobeUsed.so.0", RTLD_LAZY);
if (handle){
*(void**)(&func_print_name) = dlsym(handle, function_name);
func_print_name(&data);
dlclose(handle);
std::cout << "data received .." << data << std::endl;
}
}
}
Compiled this cpp class and generated "native.so"
This is working fine. The "native.so" could call the fuction form "ibCppTobeUsed.so.0" when called from TestWrapper.java.
I want to use same library for android as well. So, I have to write wrapper class all over again in Android NDK? Or I can compile my "native.so" for Android platform?
If I try to use it directly, I get error
"install_failed_no_matching_abis".
No, you cannot use the same shared library. Android is not GNU. You need to compile your libraries for Android.
So, I have to write wrapper class all over again in Android NDK?
No, you can write it in a way that works for both. You need to factor our your JNI wrapper class from your main class, since Android uses Activity instead of main.
I would also strongly recommend against ever relying on dlclose on any platform. The API is not sound, and will lead to surprising behavior with modern C++. A single global thread_local with a non-trivial destructor renders the library un-unloadable, so the next dlopen will not reset library state as you might expect. If you need to implement initialization/finalization logic for your library, make explicit Initialize and Finalize functions a part of the libary and call them directly.
Without knowing your architecture's full architecture I can't be sure, but from the sample you've given here I'd recommend dropping the dlopen/dlsym from your JNI entirely and just link against libCppTobeUsed directly.
I've noticed that java/android/media has a method called createDecoderByType() that is supposed to return a MediaCodec object. However, when I look at the MediaCodec.java source code on GoogleGit, I can't really see how the actual decoder is generated. Here is the code for that method:
public static MediaCodec createDecoderByType(String type) {
return new MediaCodec(type, true /* nameIsType */, false /* encoder */);
}
Then when I look at the constructor to see what is returned, this is what I see:
private MediaCodec(
String name, boolean nameIsType, boolean encoder) {
native_setup(name, nameIsType, encoder);
}
Okay, great. Let's look at native_setup(). Here's the definition:
private native final void native_setup(
String name, boolean nameIsType, boolean encoder);
That function appears to have no body!
At first I assumed that this meant the method would be defined in a child class. But I am seeing this method called directly on MediaCodec itself in other functioning source code.
So my question is: Is there any way I can trace down and see how Android creates a decoder of a given type depending on the environment and parameters? I seem to have hit a dead end, and no amount of Googling is giving me any helpful results.
Just found the answer to this the minute after I posted it...of course. The issue is with the native keyword. From GeeksforGeeks:
The native keyword is applied to a method to indicates that the method is implemented in native code using JNI (Java Native Interface).
This means that it can be written in another language such as C or C++, or invoke hardware stuff. The MediaCodec JNI code that I was looking for is here.
I am trying to use a public interface in a .dll file in JAVA. This is what a public interface in the .dll shows:
// Interface declaration.
public interface ISslTcpClient
{
string Encrypt(string requestContent);
string Decrypt(string requestContent);
};
Here is how I load my dll and use it in my Java application in eclipse:
public class NJInew {
static {
System.loadLibrary("ICVTnsClient");
}
native String Encrypt(String requestContent);
public static void main(String[] args) {
NJInew p= new NJInew ();
p.Encrypt("pejman");
}
}
However I get the following error:
Exception in thread "main" java.lang.UnsatisfiedLinkError: NJInew.Encrypt(Ljava/lang/String;)Ljava/lang/String;
at NJInew.Encrypt(Native Method)
at NJInew.main(NJInew.java:13)
Please let me know how to fix this issue and I would greatly appreciate it.
I do not understand how the native DLL can possibly look like a Java interface. Are you sure it's a JNI DLL? You can't call any old DLL from Java. If it isn't a JNI DLL you'll either need to add the required JNI entry points to it, starting with the javah tool, or write a wrapper DLL that contains those and calls this one.
This interface looks definitely like written in .NET C#. Therefore you do not need to call native DLL but managed .NET DLL and that is completely different topic.
You can achieve it yourself by wrapping .NET DLL with native C++ code and calling it from JAVA but number of obstacles and challenges is huge... You need to take care of type conversion, memory management, threads, C++ runtime depndencies and more... so that approach is not recommended.
What you should look for is native bridge like Javonet which takes care of all those things for you and makes sure you can run your code on any machine.
Using your interface would like like this:
Javonet.addReference("ICVTnsClient.dll");
NObject client = Javonet.New("SslTcpClient");
//some concreto type which implements this interface
String encryptedStr = client.invoke("Encrypt", "some string");
You can get free license for academic and non-commercial usage or try the free trial: http://www.javonet.com
Edit 2 After recieving a response from Mathworks support I've answered the question myself. In brief, there is an options class MWComponentOptions that is passed to the exported class when instantiated. This can, among other things, specify unique print streams for error output and regular output (i.e. from disp()-liked functions). Thanks for all the responses none the less :)
====================================================================
Just a quick question - is there any way to prevent MATLAB code from outputting to the Java console with disp (and similar) functions once compiled? What is useful debugging information in MATLAB quickly becomes annoying extra text in the Java logs.
The compilation tool I'm using is MATLAB Compiler (which I think is not the same as MATLAB Builder JA, but I might be wrong). I can't find any good documentation on the mcc command so am not sure if there are any options for this.
Of course if this is impossible and a direct consequence of the compiler converting all MATLAB code to its Java equivalent then that's completely understandable.
Thanks in advance
Edit This will also be useful to handle error reporting on the Java side alone - currently all MATLAB errors are sent to the console regardless of whether they are caught or not.
The isdeployed function returns true if run in a deployed application (with e.g. MATLAB Compiler or Builder JA) and false when running in live MATLAB.
You can surround your disp statements with an if isdeployed block.
I heard back from a request to Mathworks support, and they provided the following solution:
When creating whatever class has been exported, you can specify an MWComponentOptions object. This is poorly documented in R2012b, but for what I wanted the following example would work:
MWComponentOptions options = new MWComponentOptions();
PrintStream o = new PrintStream(new File("MATLAB log.log"));
options.setPrintStream(o); // send all standard dips() output to a log file
// the following ignores all error output (this will be caught by Java exception handling anyway)
options.setErrorStream((java.io.PrintStream)null);
// instantiate and use the exported class
myClass obj = new myClass(options);
obj.myMatlabFunction();
// etc...
Update
In case anyone does want to suppress all output, casing null to java.io.PrintStream ended up causing a NullPointerException in deployment. A better way to suppress all output is use to create a dummy print stream, something like:
PrintStream dummy = new PrintStream(new OutputStream() {
public void close() {}
public void flush() {}
public void write(byte[] b) {}
public void write(byte[] b, int off, int len) {}
public void write(int b) {}
} );
Then use
options.setErrorStream(dummy);
Hope this helps :)
Another possible hack if you have a stand-alone application and don't want to bother with classes at all:
Use evalc and deploy your func name during compile:
function my_wrap()
evalc('my_orig_func(''input_var'')');
end
And compile like
mcc -m my_wrap my_orig_func <...>
Well, it is obviously yet another hack.