I have two dlls, C:\foo\x.dll and C:\bar\y.dll, where x.dll depends on y.dll (i.e. the implementation of functions in x will call functions in y).
In a Java application, when I load x.dll using JNA what do I need to set up to ensure that I don't get a UnsatisfiedLinkException?
I'm currently setting up jna.library.path to C:\foo, but it seems that it is not enough. Including both C:\foo and C:\bar in java.library.path also doesn't help.
You can usually call System.load("/name.dll") with the path to your dependent library prior to making the JNA call to load the primary.
System.loadLibrary("name") will work if the library is on java.library.path and conforms to expected naming conventions.
Related
I have an .so file that I successfully integrated into android studio and I can load the file by calling System.loadLibrary.
Is there a way I can see what methods and classes I can use now with this library loaded?
Depends on how the library maps Java methods to native function pointers: it can do one or both of the following:
Dynamic symbols that start with Java_ are mangled names for the class and method name.
If the code uses RegisterNatives system call you will have to put a breakpoint on env->RegisterNatives and look at the surrounding code/arguments.
I wonder how java.* libraries implement the java native interface?
To be more specific I am investigating the java.awt.Robot and come across native method calls. As I am in windows - does that mean there is a .cpp file laying around somewhere (inside the java.awt.* package?) - that the java.awt.Robot uses?
Whenever you call native code, you have to go via JNI. Typically, you need to build shared library. Calling schema follows (note that you don't call C file - it's just visualization of which method will be called):
So, in a sense, there is a file that contains source code of the library that you call.
In case of Windows, shared libraries are DLL files in case of Linux they are typically so files and in macOS dylib. If you want to make them "visible" to your Java code, you have few options here. You can put location (directory where library is) in:
PATH (windows)
LD_LIBRARY_PATH (macOS/Linux)
-Djava.library.path - work for all systems, it's just a jvm's argument.
I have a jni dll that has functions being called from java. The problem is that this dll has all the java classes in the default package (in the dll "Java_classname_methodname"). It is impossible to get the source of this dll and it would take EXTREMELY long to rewrite. So I basically need to call the functions in this dll from java in a different package than default. I've tried for hours on end to rename the functions in the dll with a hex editor and several tools to modify the checksum and addresses in the dll but it's just too much for me because I have almost no experience with this. I would very much prefer this route, but I just don't have the proper tools or the know-how. So what I'm left with is trying to hardcode the package name in java. I tried using jna as described in this stack overflow post to do something like this:
Map options = new HashMap();
options.
put(
Library.OPTION_FUNCTION_MAPPER,
new StdCallFunctionMapper() {
public String getFunctionName(NativeLibrary library, Method method) {
method.setName(method.getName().replace("com.test.", "");
return super.getFunctionName(library, method);
}
}
);
Native.loadLibrary(..., ..., options);
But there is no setName in Method. Ideally I'd like to get this done without any extra libraries but I'm obviously not opposed to using something like jna. And before anyone asks, yes this is permitted by the library's usage license. Please don't tell me it's not possible because know that it's possible, just difficult. Whichever way it must be done I am willing to put in the work (either modifying dll or using java code with some external library). And by the way, I also need this done on .so and .dylib files eventually (not as important as dll). Thank you for your time.
I have a JNI dll that has functions being called from java. The problem is that this DLL has all the java classes in the default package (in the dll "Java_classname_methodname").
So the corresponding Java class with the native methods wasn't in a package either.
It is impossible to get the source of this dll and it would take EXTREMELY long to rewrite. So I basically need to call the functions in this dll from java in a different package than default.
Correct.
I've tried for hours on end to rename the functions in the dll with a hex editor and several tools to modify the checksum and addresses in the dll but it's just too much for me because I have almost no experience with this.
You may be able to alias the function names somehow, but it's been about 20 years since I practiced in this area.
I would very much prefer this route, but I just don't have the proper tools or the know-how. So what I'm left with is trying to hardcode the package name in java.
No. There is no package name to hard-code. What you're left with is trying to call native methods in a class without a package from a class in a package, which since 1.4 is not possible.
What you need to to do is either:
It is possible to call the package-less Java native methods via reflection. So, you can write a wrapper class that does that, which lives in the package of your choice, and the rest of your code can call the wrapper.
Or
As follows:
Write another Java class in the package of your choice with the appropriate native methods.
Create an import library from the existing DLL.
Write another DLL and link it with this import library.
Load this new DLL from your Java code.
Have this DLL use the RegisterNatives method on initialization, to register the existing JNI entry points in the old DLL under the new native method names & signatures.
Use javah to get the required native method names and javap to get the required Java signatures. Don't try to guess them by hand.
Don't ask me how this maps to .so files.
I am having problems with relative file paths that native functions use. When I call native C function from Java code, I get segmentation fault due to null file pointer. The only thing that works is to change these paths into absolute file paths, which is not solution for me. Is there any way to set root directory for native functions or to use Java project root folder to navigate through directories, or the absolute path is the only way?
Java does not have a way to change the working directory.
This is because the Java developers consider changing the working directory to create more problems than it solves. specifically:
It would be global mutable state. Global mutable state makes it harder to isolate parts of the application from each other.
It would be prone to race conditions (another side effect of being global mutable state).
It would not have a significant benefit. Everything that you could do by changing the current directory you can already do with absolute paths.
Your C code will need to use absolute paths.
Alternatively, if you are willing to write additional C code, your C code could call the operating system's chdir function directly. This may be dangerous, as the JVM is not designed for this possibility.
I solved the problem! Solution is using File.getAbsoluteFilePath() function, and passing it to native C function. It can be used for finding absolute path of shared library also, which makes application platform independent. C code can navigate through it's directories like before bounding with Java code.
Do you work in Linux?
in Linux,you can add the path
$LD_LIBRARY_PATH=.so file path
to the ~/.bashrcfile and then reboot..
If you work with windows, you can put the .dll file in the path that as the .class file path.
I would like to know if there is any alternative to load a library more than System.LoadLibrary or System.load.
Due to the circustances I cant use them. Is there anyway in Java to specify the address where the dll has to be loaded?
thanks!