How to access DLL methods in Java code using JNA? - java

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.

Related

Import .jar libraries in VS Code

I need to use a .jar library, given by my teacher, to code for my Java class.
I am using VS Code, with the Java Extension Pack installed, for Java Project Management.
Can someone please explain me step by step how is it possible to import the .jar library, in order to use the classes defined by my teacher.
I have tried to copy the .jar in the lib folder and then add the reference, but it still did not work. I also know that I have to declare the classpath, but when I create the Java Project the .classpath file is not created automatically.
Thanks already!
First you should examine the classes in .jar file. Then you should load that class as,
Class<?> c1 = Class.forName("java.lang.String");
Then after you can use that class by calling that Class reference type variable.
See this example as well,
public class Test {
public static void main(String[] args) throws ClassNotFoundException {
// get the Class instance using forName method
Class c1 = Class.forName("java.lang.String");
System.out.print("Class represented by c1: "+ c1.toString());
} }
Try to understand the code and implement proper solution to your project.
Good Luck.

Java compilation issue on Linux, using Windows specific

I encountered a compilation issue under Linux.
I'm compiling java programs on Linux; the target use is both Linux and Windows.
The code check if in there are platform specific classes (as shown in the code below).
So if the code is running under Linux, the specific Windows code will not be executed.
The issue arise on the use of a platform specific class Win32MediaTray
The compile error reported is
PrinterScanner.java:9: error: cannot find symbol
import sun.print.Win32MediaTray;
^
Is it possible to compile it under Linux? Or is it just impossible?
I can use some workaround (reflection?)
Needless to say that the compilation under Windows gives no errors.
Thankyou for your help.
For reference, the code behind this issue is the following:
private String getTrayName(Media media) {
String result = "id:" + media.getValue();
boolean isWin32 = media.getClass().getName().equals("sun.print.Win32MediaTray");
if (isWin32) {
Win32MediaTray w32 = (Win32MediaTray) media;
result = result + ",winId:" + w32.winID;
}
return result;
}
I believe that the class you are trying to use is sun.print.Win32MediaTray.
And the answer is that you cannot use it ... or compile a class that uses it ... on a Linux release of Java. That class is not included in the rt.jar file on a Linux release of Java.
Furthermore, you shouldn't be using it. The Java documentation makes it very clear that application code should not make use of classes in the sun.* package hierarchy.
If you have no choice but to do this, then your best bet is to use reflection to fetch the value of that w32Id field. You'll also need to deal with the case where the media object is not an instance of the Win32MediaTray class. Beware that you are relying on implementation details that Oracle says specifically that you shouldn't. There is a risk that they will change (without notice!) in some future Windows release.
The other alternatives are:
Implement your own platform adapter classes with a different one for each platform. These have to be compiled separately on each platform, and then dynamically loaded.
Implement separate codebases for each platform.
To make the compiler happy you could implement a dummy class named sun.print.Win32MediaTray and make it available both on the compile and runtime classpath. The class doesn't need to work, it only has to be API compatible (same signatures and return types, but in this case you only really need to extend Media and have a public int winID), so that you can satisfy both the compiler and the verifier.
At runtime, the version included in rt.jar should be loaded on Windows thanks to loading delegation. On Linux, the dummy version is the only one available, but you stated that the program checks for the platform and executes another branch of code, so it shouldn't cause your program to fail.
For example, with the following class on the classpath:
package sun.print;
import javax.print.attribute.standard.Media;
public class Win32MediaTray extends Media {
public int winID = 0xBADC0DE;
protected Win32MediaTray(int value) {
super(value);
}
static {
System.out.println("Won't see me on Windows");
}
}
I managed to run this program on Windows:
public class Main {
public static void main(String[] args) {
PrintService[] services = PrintServiceLookup.lookupPrintServices(null, null);
for (PrintService svc : services ) {
DocFlavor flavor = DocFlavor.SERVICE_FORMATTED.PAGEABLE;
Object o = svc.getSupportedAttributeValues(Media.class, flavor, null);
if (o != null && o.getClass().isArray()) {
for (Media media : (Media[]) o) {
if ( media instanceof Win32MediaTray )
System.out.println( ((Win32MediaTray) media).winID );
}
}
}
}
}
The message in the static initializer is not printed on Windows, because the definition that is actually loaded is the one from rt.jar. Obviously, the code can be compiled on any platform.
How about putting the code that uses windows-specific stuff into a separate jar; then you can compile and include that jar on windows, and leave it off systems otherwise.
One standard way to do this is to have one or more interfaces used by your application code; you can have a factory provide the implementing classes or inject them with Spring or whatever. But I think rather than "how can I compile this on Linux" your question should be "I have this Windows dependency in an app targeted at multiple operating systems, how do I handle it?"

Changing the Functionality of a Java ImageIO class

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.

Code for running the method declared in DLL

I created a Java code that tries to access the method LoadProject of the class IProjectFactory defined in myAPI.dll. The description of the DLL file says: IProjectFactory is used to load a project file into memory. IProjectFactory is a static class in the myAPI.dll assembly. It exposes the LoadProject method that takes a string containing the path to the file to load, and returns a reference to the resulting IProject. Using the IProject interface you can then manipulate the loaded project in various ways.
import com.sun.jna.Library;
import com.sun.jna.Native;
public class MyClass {
public interface IProjectFactory extends Library {
public Object LoadProject(String fileName);
}
public MyClass() {
//System.loadLibrary("myAPI");
load();
}
void load() {
String fileName = "xxx.sp";
IProjectFactory api = (IProjectFactory) Native.loadLibrary("myAPI",IProjectFactory.class);
try {
Object project = api.LoadProject(fileName);
}
catch (Exception e) {
e.printStackTrace();
}
}
}
After running this code, the following error message has been generated:
Exception in thread "AWT-EventQueue-0" java.lang.UnsatisfiedLinkError: Error looking up function 'LoadProject': The specified procedure could not be found.
at com.sun.jna.Function.<init>(Function.java:179)
at com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:350)
at com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:330)
at com.sun.jna.Library$Handler.invoke(Library.java:203)
at $Proxy0.LoadProject(Unknown Source)
Does it mean that myAPI does not contain the class IProjectFactory with the method LoadProject?
You can call functions in native libraries with JNI or JNA. Primitive types are mapped. Certain structures are possible also. Even callback functions are possible. See JNA's mapping table.
What is impossible, by design: Getting a class or interface that was designed for a different runtime environment (like CLR) and use it seamless within the JVM.
So if you have a native procedural/functional library that just returns pointers or primitive types then you can use it quite well.
If you need to work with objects that are returned then you are out of luck. You need to run them in their native environment and find some way of interprocess communication.

Scala trouble accessing Java methods

So, I have something written in Java, and I want to extend it in Scala... The issue I'm running into is that Scala isn't seeing methods I need.
Here is how it's set up:
Player extends Mob, and Mob extends Entity.
I need to access a method in Player that isn't defined in Mob or Entity, but Scala doesn't think it exists even though Java does.
It can see methods defined by Mob and Entity just fine. Also, all the methods I'm talking about are non-static.
So, am I doing something wrong, or is this a limitation imposed by Scala?
Edit --
Here is the relevant code:
package test
import rsca.gs.model.Player
object Test {
def handle(p:Player): Unit = {
p.getActionSender().sendTeleBubble(0, 0, false);
}
}
Player class:
package rsca.gs.model;
// imports
public final class Player extends Mob {
// Implemented methods (not going to post them, as there are quite a few)
// Relevant code
private MiscPacketBuilder actionSender;
public MiscPacketBuilder getActionSender() {
return actionSender;
}
}
Error:
value getActionSender is not a member of rsca.gs.model.Player
I never encountered such problems, and you probably checked your configuration and everything else twice, so I would guess this is some Eclipse related build issue. You should try to build from the command line in order to see whether Scala or Eclipse is the problem.
Is it possible for you to run a test against the class just to see if you got the right one?
p.getClass.getMethods
... and if possible (may run into NPE) in order to find the source:
p.getClass.getProtectionDomain.getCodeSource.getLocation.getPath
When compiling the Scala class, do something like this:
scalac *.scala *.java
This way, Scala will look a the Java code to see what is available. If, however, the Java code is already compiled and provided as a jar file, just add it to the classpath used when compiling the Scala code.

Categories

Resources