I have a 3rd party Win32 dll, written in C++, which I need to load in my eclipse java project and call some methods from it. What is problematic - all the classes which I really need from this dll have virtual functions. I've created a dummy C++ project, which received all the stuff via static linking and via my self-defined C++ class. Everything is working in my C++ world. Now I want to load my dummy dll (which in turn loads all other stuff I need) in my java project. The code in cpp world looks like this (I've mixed up .h and .cpp for simplicity):
class Dummy : public VirtualClassFromLib
{
public:
//...
//some standard stuff here
//...
void method1()
{
VirtualClassFromLib::function1();
}
void method2()
{
//a header is loaded with #include
AdditionalStructureFromHeader object;
VirtualClassFromLib::function2(object);
}
void virtual_function()
{
std::cout << "Cool, now you are not virtual";
}
//...
}
where function1 and function2 are not virtual in the base class and virtual_function is.
I'm a newbie in JNI and as far as I understood, I should write a "mirror" class with the same method's and other stuff's names in my java project. Question: how to deal with this VirtualClassFromLib? Like, this VirtualClassFromLib has a very complicated structure with a wide usage of self-defined structures in the original dll. Or don't I need to "mirror" that completely to java project? I don't get it from examples and tutorials in the Internet.
Related
Let's take the following code
public class SomeClass {
public OtherClass method(final String param1,final String param2){
AnotherClass obj1 = AnotherClass.getInstance();
return obj.instanceMethod(new YetAnotherClass<OtherClass>() {
#Override
public OtherClass run() {
return OtherClass.get(param1, param2);
}
});
}
}
My question is there any way that I can implement the interface in C/C++ through JNI, without creating a native method in Java?
One option is the Java Native Access (JNA) library. Have a look at its project page at JNA. I quote from its project site:
JNA provides Java programs easy access to native shared libraries without writing anything but Java code - no JNI or native code is required. This functionality is comparable to Windows' Platform/Invoke and Python's ctypes.
The following example from the project's toturial page demonstrates how it is used to call the printf function from the native library that the function is defined in:
package com.sun.jna.examples;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Platform;
/** Simple example of JNA interface mapping and usage. */
public class HelloWorld {
// This is the standard, stable way of mapping, which supports extensive
// customization and mapping of Java to native types.
public interface CLibrary extends Library {
CLibrary INSTANCE = (CLibrary)
Native.loadLibrary((Platform.isWindows() ? "msvcrt" : "c"),
CLibrary.class);
void printf(String format, Object... args);
}
public static void main(String[] args) {
CLibrary.INSTANCE.printf("Hello, World\n");
for (int i=0;i < args.length;i++) {
CLibrary.INSTANCE.printf("Argument %d: %s\n", i, args[i]);
}
}
}
On Windows, the printf function is defined in the msvcrt.dll and the sample loads that DLL and calls the function from it.
The JNA project is mature and according to its web page, it has some very famous users.
It should be pointed out that JNA itself uses the JNI under the hood but in most cases, you do not need to use JNI yourself. Therefore, you can focus on implementing your native code in C (create your own DLL or Shared Library files) and then load them in Java with JNA.
I am trying to wrap some libraries written in C++ to interface with JAVA using SWIG.
I have one C++ struct in one library used in one C++ function of another library as an argument.
common.h
namespace rina {
namespace cdap_rib {
typedef struct{
int size_;
void* message_;
} ser_obj_t;
}
}
This library is wrapped producing a class called eu.irati.librina.ser_obj_t in JAVA. That's fine. Then I have
utilities.h
class IPCPConfigEncoder {
public:
void encode (rina::cdap_rib::ser_obj_t& ser_obj);
}
which is wraped with SWIG producing
public void encode(SWIGTYPE_p_rina__cdap_rib__ser_obj_t ser_obj) {
...
}
in a JAVA class. Looking around in I found (SWIG Importing generated class from a different module and package into the current class) and I added to .i
%typemap(javaimports) SWIGTYPE
%{
import eu.irati.librina.ser_obj_t;
%}
which produced
import eu.irati.librina.ser_obj_t;
public void encode(SWIGTYPE_p_rina__cdap_rib__ser_obj_t ser_obj) {
...
}
Then, I have a couple of questions
The import is added to all the java classes... how can I enclose it only to the desired class?
How can I tell SWIG to change SWIGTYPE_p_rina__cdap_rib__ser_obj_t for eu.irati.librina.ser_obj_t.
Note: Since common.h and utilities.h are in different libraries I can not put them together in the same swig module.
As #Felxo pointed in the coments, the only solution is to tell swig to understand also the other libraries interface wraping (so headers and how are they wrapped).
What I did:
I copied common.i into utilities wrapping folder.
I added into utilities.i
/* this is the "copied" common.i */
%import "common.i"
%pragma(java) jniclassimports=%{
import eu.irati.librina.ser_obj_t;
%}
to add the import of the proxy class (you should change thais to point to your proxy class from a java path)
Remove from the copied common.i the unecessary instructions like %template, remember that, at this point, you are only "importing" the common.h, not wrapping it (you already wraped it before). Actually, the common.i should only include:
%{
#include "common.h"
}%
but no
%include "common.h"
Tell SWIG where are is the common.h as well as where is the utilities.husing the -I option
I'm having trouble trying to call a function writed in C# from Java. I have already loaded the dll that contains the function.
Error message:
java.lang.UnsatisfiedLinkError: app.clsValidation.validate(Ljava/lang/String;)Ljava/lang/String;
C# code compiled into a 64-bit dll:
namespace library {
public class clsValidation {
public string validate(string txt) {
return txt;
}
}
}
Java code
The class:
package app;
public class clsValidation {
static {
System.loadLibrary("library");
}
public native String validate(String txt);
}
How I'm calling it in Java:
String txt = "something";
String result = new clsValidation().validate(txt);
That's to be expected. Your Java code treats the C# DLL as if it were an unmanaged library. It is not. It does not export unmanaged functions that can be imported using LoadLibrary and GetProcAddress.
If you wish to export unmanaged functions from your .net DLL then you can:
Use Robert Giesecke's UnamanagedExports to do so.
Make a mixed mode C++/CLI assembly which exports unmanaged functions.
Other options would include exposing the functionality through COM which is readily consume from Java.
I was working with
javax.imageio.ImageIO class
The one provided by sun doesn't provide support for reading .tif files. So if I try to read a .tif file, it just returns a null. Then I downloaded this api from oracle's website and included it in the classpath. This api uses jni as was evident from a .so file in that folder. After that I didn't have to change anything in my code and it worked. How could this happen? Wouldn't the class names have clashed?
There were 3 things in the api that i had downloaded:
clibwrapper_jiio.jar
jai_imageio.jar
libclib_jiio.so
I didn't have to do any additional import. In fact, the functionality provided by the ImageIO class was enchanced
I am really curious about how this works.
Here is the class in javax.imageio package. The class has been declared as final. And it does some weird complex stuff that I can't understand. Could someone explain how to achieve this effect with a simpler example.
http://docs.oracle.com/javase/7/docs/api/javax/imageio/ImageIO.html
ImageIO has a scanForPlugins(...) method. I'd imagine that on class load time it takes a peek around the CLASSPATH and looks for anything that could extend its functionality.
The javadoc which hints to this is here.
You could do something similar by putting a static block in one of your classes
public class MyClass {
public static scanForExtensions() {
... code looking for extensions goes here ...
... for each found extension, register them in the "ExtensionRegistry"
ExtensionRegistry.register(extension);
}
static {
scanForExtensions();
}
public void doSomething(String input) {
for (Extension extension : ExtensionRegistry.getExtensions()) {
if (extension.canHandle(input)) {
extension.handle(input);
return;
}
}
throw UnhandledInputException("No extension to handle " + input);
}
}
Java's Image IO works using the Service Provider Interface (see links below for more details).
JavaSound works the same way. To add support for (e.g.) MP3 to JavaSound, it is only necessary to add the mp3plugin.jar of the JMF to the run-time class-path, then JavaSound can decode MP3 files as easily as it can a WAV (using the exact same classes - very funky).
I expect the installation of JAI did a similar thing, by adding a bunch of service providers for different image types to the lib directory of the JRE.
ImageWriterSpi
Creating Extensible Applications With the Java Platform.
By running System.loadLibrary("myAPI"), I verified that the DLL file "myAPI.dll" can be successfully loaded into my Eclipse Java project. Now I need to call methods specified inside this DLL file from my Java code. To do this, I added JNA to my Java project. Then I wrote the below-given code snippet that should be able to get instances of classes IProject and ProjectFactory (specified in the DLL file).
I still don't understand how to properly implement this with JNA. I checked different threads, e.g. this one, but the ones I checked don't provide an answer. Any help is highly appreciated. Thanks.
import com.sun.jna.Library;
import com.sun.jna.Native;
public class MyClass {
public interface myAPI extends Library {
//...
}
void LoadProj() {
myAPI api = (myAPI) Native.loadLibrary("myAPI",myAPI.class);
String fileName = "xxx.sp";
IProject project; // this is wrong but shows what I am trying to do
try {
project = ProjectFactory.LoadProject(fileName);
}
catch (Exception ex) {
MessageBox.Show(this, ex.Message, "Load failure");
}
}
}
Not sure what problem you are facing but as a practice your myAPI interface should declare all the methods verbatim with appropriate parameter mapping. I don't see any methods inside your interface.
Please checkout the this link as well as the link mentioned above by #Perception
If there are no Java classes or Java source hidden inside this DLL (which would be ... strange), then it will never work this way. You can't instantiate C# classes or use C# interfaces. MessageBox.Show( isn't Java either, it is Windows Forms code.