I need to call a method in dll using Java Applet.
The dll is written in C++.
Whether it is possible, if so what are the things needed.
can anyone provide sample api
You should use JNI.
Take a look on this article.
Make sure that the environment variable, CLASSPATH, contains a
reference to "[WINDIR]\Java\Classes\Classes.zip" and "C:" (assuming
that C: is your development drive).
Make sure that your "[SDK-Java]\Bin" directory is included in your
path (for JavaH, JVC, and JView).
Make sure that Visual C++ is properly set up for command-line use.
See your Visual C++ documentation for details.
Write your Java code:
public class TestJNI {
public native void greetings();
static {
System.loadLibrary("greet");
}
public static void main(String args[]) {
new TestJNI().greetings();
}
}
Compile the Java file:
jvc TestJNI.java
Run JavaH on the generated class file:
javah -jni TestJNI
Write the C/C++ code based on the generated header file:
#include "TestJNI.h"
#include <stdio.h>
JNIEXPORT void JNICALL Java_TestJNI_greetings(JNIEnv *env,jobject jobj) {
printf("Hello from Visual C++!");
}
Compile the C/C++ code:
cl greet.cpp -Ic:\sdk-java.31\include -Fegreet.dll -MD -LD
Test the application:
jview TestJNI
See the linked threads by rkosegi re. 'trusted code' - important to understand. aviad has covered many details of one way to do it. This post will simply focus on deploying the natives.
The real problem with applets using natives is getting the natives installed in a place where the applet can access them. That is where deploying the applet using Java Web Start becomes useful. JWS can not only partition the download of natives according to OS & architecture (32/64 bit), but then make the natives available on the run-time class-path of the app., ready for loading.
As of the 'Next Generation' plug-in (Sun's 1.6.0_10+, for e.g.), JWS could deploy embedded applets (previously it could only launch them free-floating).
But then, why do you want an applet at all?
The better alternative is usually to launch a free-floating frame direct from a link (using JWS). The same security restrictions apply, but it is easier to deploy and a better user experience.
Related
I'm trying to invoke a C++ function from java that uses C++-style strings. The program executes just fine when I'm using C-style strings but just as I declare std::string somehow it can't find dependent libraries anymore. I checked my includes folder in eclipse environment and it does contain <string> library and all its dependencies.
package test_strings;
public class TestString {
static {
System.load("C:\\Users\\aurok\\eclipse-workspace\\native_cpp\\Debug\\libnative_cpp.dll");
}
public native String sayHelloC();
public native String sayHelloCpp();
public static void main(String[] args) {
TestString test = new TestString();
System.out.println(test.sayHelloC());
System.out.println(test.sayHelloCpp());
}
}
And this is my native file:
#include "test_strings_TestString.h"
#include<string>
using namespace std;
JNIEXPORT jstring JNICALL Java_test_1strings_TestString_sayHelloC
(JNIEnv *env, jobject thisObj){
jstring str = env->NewStringUTF("Hello World C-style !!");
return str;
}
JNIEXPORT jstring JNICALL Java_test_1strings_TestString_sayHelloCpp
(JNIEnv *env, jobject thisObj){
//std::string str = "Hello World C++ style !!";
//return env->NewStringUTF(str.c_str());
return env->NewStringUTF("Hello World C++ style !!");
}
This code compiles fine and runs well from java but as soon as I try to use the std::string version(commented) the code compiles and the dynamic library is created but on running the java code I get the following error:
Exception in thread "main" java.lang.UnsatisfiedLinkError: C:\Users\aurok\eclipse-workspace\native_cpp\Debug\libnative_cpp.dll: Can't find dependent libraries
at java.base/jdk.internal.loader.NativeLibraries.load(Native Method)
at java.base/jdk.internal.loader.NativeLibraries$NativeLibraryImpl.open(NativeLibraries.java:383)
at java.base/jdk.internal.loader.NativeLibraries.loadLibrary(NativeLibraries.java:227)
at java.base/jdk.internal.loader.NativeLibraries.loadLibrary(NativeLibraries.java:169)
at java.base/java.lang.ClassLoader.loadLibrary(ClassLoader.java:2383)
at java.base/java.lang.Runtime.load0(Runtime.java:746)
at java.base/java.lang.System.load(System.java:1857)
at test_strings.TestString.<clinit>(TestString.java:6)
I have searched various sources for a possible explanation but couldn't find one. Guys, help me!
<string> is a header file, and if your C++ code containing #include <string> directive compiles this means that paths of standard include folders are configured correctly.
However, depending on how your project is configured to be linked to the C and C++ runtime libraries (statically or dynamically), the resulting executable may or may not depend on additional DLLs. (For example, in case of Microsoft Visual Studio 2019 C++ compiler, the C runtime library DLL is vcruntime140.dll and C++ runtime library DLL is msvcp140.dll.)
Using std::string probably causes your executable to depend on the C++ runtime library DLL (in addition to the C runtime DLL), and perhaps it is not found in the same folder as the executable (and not in the DLL search path).
On Windows, C runtime DLL is often already available system-wide, but C++ runtime DLL needs to be either installed (using the Microsoft Visual C++ Redistributable package) or placed into the same folder along the executable itself.
Another option is to link runtime libraries statically, so the resulting executable won't have those DLL dependencies. But usually, dynamic linking is preferred.
Note that depending on which C++ compiler you are using with your Eclipse IDE — either GCC (G++), Clang, MSVC or some another — the required C++ runtime DLL will have a different filename.
Thanks a lot heap underrun for your answer. I finally figured out a way to make it work. I used the Dependencies tool by lucasg and found that libgcc_s_seh-1.dll and libstdc++-6.dll were missing even though they are present in MinGW bin.
So I explicitly added them in the same folder as my dynamic library and loaded them in the java virtual environment. This is how the java side looks now:
package test_strings;
import java.io.IOException;
public class TestString {
static {
System.load("C:\\Users\\aurok\\eclipse-workspace\\native_cpp\\Debug\\libwinpthread-1.dll");
System.load("C:\\Users\\aurok\\eclipse-workspace\\native_cpp\\Debug\\libgcc_s_seh-1.dll");
System.load("C:\\Users\\aurok\\eclipse-workspace\\native_cpp\\Debug\\libstdc++-6.dll.dll");
System.load("C:\\Users\\aurok\\eclipse-workspace\\native_cpp\\Debug\\libnative_cpp.dll");
}
public native String sayHelloC();
public native String sayHelloCpp();
public static void main(String[] args) {
TestString test = new TestString();
System.out.println(test.sayHelloC());
System.out.println(test.sayHelloCpp());
}
}
NOTE: The order in which the dlls are loaded is important. It won't work in any another order.
I'm having trouble loading a statically compiled library from Java using System.loadLibrary("") but I can load it as a dynamically compiled library (when I build it that way) just fine. I'm using JDK 8 and my understanding is it can load static libraries via System.loadLibrary("") if you provide a JNI_OnLoad_L in the *.cpp and *.h files.
My kdu_jni.h has:
extern "C"
JNIEXPORT jint JNICALL JNI_OnLoad_kdu_1jni(JavaVM *, void *);
My kdu_jni.cpp has:
JNIEXPORT jint JNICALL JNI_OnLoad_kdu_1jni(JavaVM *vm, void *reserved)
{
return JNI_VERSION_1_8;
}
I have the libkdu_jni.a file in my java.library.path directory when I try to run with the compiled version. It's working fine with a libkdu_jni.so file in that same directory when I try to load it dynamically. When trying with the static file (libkdu_jni.a), I get:
Exception in thread "main" java.lang.UnsatisfiedLinkError: no kdu_jni in java.library.path
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1867)
at java.lang.Runtime.loadLibrary0(Runtime.java:870)
at java.lang.System.loadLibrary(System.java:1122)
I've taken out the .so file before trying to load the .a file.
I'm not sure what I'm doing wrong. I don't think it's even seeing the libkdu_jni.a file's JNI_OnLoad_kdu_1jni() because I put an exception in there and I don't see that getting thrown. I've tried several iterations on that name: JNI_OnLoad_kdu_jni(), JNI_OnLoad_kdu_1jni(), JNI_OnLoad(), etc.
Any ideas?
my understanding is it can load static libraries via System.loadLibrary("") if you provide a JNI_OnLoad_L in the *.cpp and *.h files.
Your understanding is incorrect. You can't load a .a file dynamically. It isn't executable in any way shape or form:
infra-library references are not resolved
references outside the library are not resolved either: for example, to the C library.
The link step is essential, and the JVM doesn't do it for you. What you have read applies to libraries statically linked into the JVM.
I suggest you try JNI_OnLoad_kdu_jni as the function name. If that doesn't work, it might not work with library names that contain an underscore.
--- Original post follows ---
Prior to Java 8, only shared object libraries were supported.
This means that to know if the static library is Java 8, a new function must be implemented in the library.
JNI_OnLoad_libname must return a value of JNI_VERSION_1_8 or higher.
I'm guessing since your code works dynamically, but not staticly, perhaps this function is not present. The portion of JEP 178 below lead me to believe this:
The specifications of the java.lang.System.loadLibrary and
java.lang.Runtime.loadLibrary methods will be revised to read:
Loads the native library specified by the libname argument. The libname must not contain any platform-specific prefix, file extension,
or path.
If a native library called libname is statically linked with the VM, then the JNI_OnLoad_libname function exported by the
library is invoked. See the JNI Specification for more details.
Otherwise, the libname is loaded from a system library location and mapped to a native-library image in an
implementation-dependent manner.
Also the notes in the enhancement echo this sentiment
The source code for the loader is helpful
I'd fire up java under debug (gdb) and put a break point in at Java_java_lang_ClassLoader_00024NativeLibrary_findBuiltinLib. You're right, there aren't many great examples.
We are trying to develop a Java application that loads a DLL (written in C++) and uses its functions.
When opening this DLL in "DLL Export Viewer" we can see the full signature of the functions exported, unlike any other DLL we load into the viewer:
Exported view of the DLL that doesn't work
We have tried to create some sample DLLs and load them to Java, and we were successful. The visibile difference was that when we loaded these DLLs we created into "DLL Export Viewer", we saw the functions without full signatures (only names):
DLL We created, works from Java
The code we use to load the DLL from Java is using JNA, and looks like this:
Declaring an interface that mathces the DLL functions:
public interface Ariel extends Library {
Ariel INSTANCE = (Ariel) Native.loadLibrary("ariel", Ariel.class);
void _ZN5ArielC1Ev();
int _ZN5Ariel8getArielEv();
}
Loading it and calling its functions:
public static void main(String[] args) {
Ariel ariel = Ariel.INSTANCE;
ariel._ZN5ArielC1Ev();
System.out.println("done");
}
Only when trying to load the DLL shown in the first image, we can't call any function and we always get the following error:
Exception in thread "main" java.lang.UnsatisfiedLinkError: Error looking up function 'resetScale': The specified procedure could not be found.
at com.sun.jna.Function.<init>(Function.java:208)
at com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:536)
at com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:513)
at com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:499)
at com.sun.jna.Library$Handler.invoke(Library.java:199)
at com.sun.proxy.$Proxy0.resetScale(Unknown Source)
at Bolet.main(Bolet.java:6)
Your DLL is exporting C++-mangled names. The DLL export is un-mangling them for you. If you examine the DLL with a different viewer, you should see the raw names instead.
If you want to export the names in a non-mangled manner, you need to use the extern "C" decorator on a given function declaration. This generally will only work for static methods (not class methods).
However, this is only part of your problem. If you want to directly map Java classes onto C++ classes, you'll need to use something like SWIG and compile some native glue code.
I'm a newbie to JNI, so I was trying this introduction to JNI tutorial earlier that just calls native to print Hello World! Everything went fine until the point that I wanted to run the java file, at which I keep getting the error: Exception in thread "main": java.lang.UnsatisfiedLinkError: no hello library found in java.library.path. I have googled the error and looked at a lot of peoples' suggestions, but none worked for me unfortunately! I have tried the following:
Running with command: java -Djava.library.path = "Path to library" HelloWorld
setting the LD_LIBRARY_PATH to my .so path
Everyone else had their issues resolved after doing one of the two above, but not me!
Here is the Java Code:
public class HelloWorld {
static {
System.loadLibrary("hello");
}
private native void printHelloWorld();
public static void main(String[] args) {
new HelloWorld().printHelloWorld();
}
}
And code for native is as follows:
void JNICALL Java_printHelloWorld(JNIEnv *env, jobject obj) {
printf("HelloWorld!");
}
EDIT: I even tried copying the library to the actually directory of java.library.path, but it's still giving me the same error!
What is your library called? If your paths are correct, your library name is probably wrong. If the library you are loading is called hello, on Windows the file needs to be called hello.dll, on every other SO you also need to prepend the lib prefix:
on OS X (Java < 1.7) libhello.jnilib
on OS X (Java >= 1.7) libhello.dylib
on just about everything else will be libhello.so.
Notice that the Windows dll file is the only file name without the "lib" prefix and that the "lib" prefix is not used when calling System.loadLibrary("hello").
If you are still experiencing a problem loading the lib, try System.load("/path/to/my/libhello.so") to try and load the library directly.
You can always check the file the system will look for by running
System.mapLibraryName(libName)
#Alex Barker
The version
System.load("/path/to/my/libhello.so")
does not resolve dependencies. If there are dependencies upon other user-defined libraries, they need to be loaded before.
I have seen a few posts on this, but I haven't seen any solutions so far. I have a .jar file that I'm converting to a .NET DLL via IKVM. I'm trying to figure out how to make the methods in the DLL available inside the excel VBA environment. here are the details.
1.) installed IKVM & registered it's DLL's to GAC
2.) ran IKVM to create the a .net .dll (mytest.dll)
ikvmc mytest.jar
3.) registered the new .dll
regasm mytest.dll
4.) From here i created a VB.NET project and added mytest.dll and IKVM.OpenJDK.Core.dll as references to the project. I am then able to access the methods within the .dll in .NET. This is great!
5.) what I really want to do is be able to use the .dll in VBA as well. Initially vba wouldn't accept the .dll directly as it's a .net library. I attempted to create a type library:
regasm /codebase /tlb mytest.dll
This created a .tlb file which is nice, but it did throw a warning about the library not being strongly named.
6.) then I loaded the .tlb as a reference in my vba editor. This works, however when I try to access the methods nothing shows up. Similarly if I look in the object viewer for my library i can see my two classes but not the members of those classes.
Additionally, I imagine that I probably also need to somehow reference the IKVM.OpenJDK.Core.dll inside VBA as well. However I can't do that either since it's a .NET .dll.
Has anyone had success converting a .jar file into something that can be used with VBA?
I think you always need to explicitly mark a class to be usable via COM interop. Here's an example of a Java class that is usable from VBA:
import cli.System.Runtime.InteropServices.*;
#ClassInterfaceAttribute.Annotation(ClassInterfaceType.__Enum.AutoDual)
public class SampleWidget {
public int Add(int x, int y) {
return x + y;
}
}
Here are the steps to compile:
Copy IKVM.Runtime.dll and all IKVM.OpenJDK.*.dll into the current directory or the GAC.
Run "ikvmstub mscorlib" to generate mscorlib.jar.
Create a Java source named SampleWidget.java containing the code above.
javac -cp mscorlib.jar;. SampleWidget.java
ikvmc -out:SampleLibrary.dll SampleWidget.class -r:mscorlib.dll
tlbexp SampleLibrary.dll
regasm /codebase SampleLibrary.dll (this step needs administrator rights)
Now you can add a reference to the SampleLibrary.tlb from VBA and use the SampleWidget class.