Loading .DLL in Java - java

I want to call a .DLL method in Eclipse. Here is my code :
class TestJNI1 {
public native void LireNoVersion();
public void a() {
System.loadLibrary("tttt.dll");
LireNoVersion();
}
}
public GlobalAction() {
this.setBackground(GlobalPreferences.PANEL_BACKGROUND_COLOR);
new TestJNI1().a();
}
The problem is that I have this error on compilation :
Exception in thread "AWT-EventQueue-0" java.lang.UnsatisfiedLinkError: Expecting an absolute path of the library: tttt.dll at java.lang.Runtime.load0(Unknown Source) at java.lang.System.load(Unknown Source)
I already tried to :
Set arguments in Eclipse
Moving at root of project and System32 folder
Added the folder path in native library location in Eclipse
Changing the %PATH% in windows
Giving the absolute path as an argument
Trying with "tttt.dll", "./tttt.dll" and ".tttt.dll"
Call with System.loadLibrary(...) and System.load(...)
UPDATE
I tried to print the java.library.path and get a path. I put the dll in this path and the error message is more confusing now :
Exception in thread "AWT-EventQueue-0" java.lang.UnsatisfiedLinkError: D:\My\Exact\Path\tttt.dll: Can't find dependent libraries
Here is the code to print the path :
String property = System.getProperty("java.library.path");
StringTokenizer parser = new StringTokenizer(property, ";");
while (parser.hasMoreTokens()) {
System.err.println(parser.nextToken());
}

The first problem was it couldn't find the dll because it wasn't in the path.
The second problem is that it can't find the dependencies on the dll that you are using. Your choices would seem to be
Copy all dependent libraries to the dll location
Run your code from the original dll location.

Give the absolute path of the file
try {
System.load("C:/myapplication/application.dll");
} catch (UnsatisfiedLinkError e) {
System.err.println("Native code library failed to load.\n" + e);
System.exit(1);
}
}

Using the Library interface in the sun.jna package did the trick :
import com.sun.jna.Library;
import com.sun.jna.Native;
public class DllTest {
public interface IDLL extends Library {
IDLL INSTANCE = (simpleDLL) Native.loadLibrary("tttt", IDLL.class);
int LireNoVersion(); // DWORD LireNoVersion();
}
public static void main(String[] args) {
IDLL sdll = IDLL.INSTANCE;
int nover = sdll.LireNoVersion();
System.out.println("version = " + nover + "\n");
}
}
Still don't know why it didn't worked before.

Try using this instead:
System.loadLibrary("tttt");

Related

ClassNotFoundError when I run the class outside of eclipse

I currently try to run java code in Maxmsp using a mxj object, and I want to load some classes inside of the code.
But I always get the errors, although the code runs properly in eclipse.
What is the problem?
This is my code.
If I bang in Maxmsp, call() will be called.
package Load;
import com.cycling74.max.*;
public class Loaded extends MaxObject{
public static void main(String[] args) {
//This works properly in eclipse
call();
}
public void bang() {
//This should work in Maxmsp, but get errors
call();
}
public static void call() {
try {
//this is just a example
//I want to load some classes which locate the same directory as this class
Thread.currentThread().getContextClassLoader().loadClass("Load.Loaded");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
And this is the error message:
java.lang.ClassNotFoundException: Load.Loaded
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at Load.Loaded.call(Loaded.java:21)
at Load.Loaded.bang(Loaded.java:16)
MXJ System class path is:
/Applications/Max.app/Contents/Resources/C74/packages/max-mxj/java-classes/lib/commons-codec-1.11.jar:
/Applications/Max.app/Contents/Resources/C74/packages/max-mxj/java-classes/lib/core.jar:
/Applications/Max.app/Contents/Resources/C74/packages/max-mxj/java-classes/lib/gluegen-rt-natives-macosx-universal.jar:
/Applications/Max.app/Contents/Resources/C74/packages/max-mxj/java-classes/lib/gluegen-rt.jar:
/Applications/Max.app/Contents/Resources/C74/packages/max-mxj/java-classes/lib/jitter.jar:
/Applications/Max.app/Contents/Resources/C74/packages/max-mxj/java-classes/lib/jode-1.1.2-pre-embedded.jar:
/Applications/Max.app/Contents/Resources/C74/packages/max-mxj/java-classes/lib/jogl-all-natives-macosx-universal.jar:
/Applications/Max.app/Contents/Resources/C74/packages/max-mxj/java-classes/lib/jogl-all.jar:
/Applications/Max.app/Contents/Resources/C74/packages/max-mxj/java-classes/lib/max.jar:
/Applications/Max.app/Contents/Resources/C74/packages/max-mxj/java-classes/lib/sadamLib.jar
MXJ Classloader CLASSPATH is:
/Applications/Max.app/Contents/Resources/C74/packages/max-mxj/java-classes/classes/
/Applications/Max.app/Contents/Resources/C74/packages/max-mxj/java-classes/
/Users/MyName/Documents/ecllipse-workspace/009_Processing/bin
Loaded.class is in /Users/MyName/Documents/ecllipse-workspace/009_Processing/bin
You need to include any of your dependencies on the classpath:
java -cp "path/to/maxmsp.jar;path/to/dependency2.jar;path/to/your.jar" classpath.of.your.Main
If you are just running directly from a classfile and haven't JARred your project then you can omit the path/to/your.jar and just run from the same directory with the classpath of your Main.
The above is for running java from command line.
Since Max is what is running and what's taking control of the classloading im guessing that sun.misc.Launcher$AppClassLoader is not working. Try debugging and see what it's doing. Also maybe try to find a way to use the Max classloader instead of the Java AppClassLoader.
The problem was what Max cannot load class properly.
So I created class loader method.
public static ClassLoader createClassLoader(String dirname) throws java.io.IOException {
java.net.URL[] url = new java.net.URL[1];
java.io.File file;
if (dirname.endsWith("/")) {
file = new java.io.File(dirname);
}
else {
file = new java.io.File(dirname + "/");
}
url[0]= file.toURI().toURL();
ClassLoader parent = ClassLoader.getSystemClassLoader();
java.net.URLClassLoader loader = new java.net.URLClassLoader(url, parent);
return loader
}
And call
ClassLoader loader = createClassLoader("ClassPath");
Class<?> c = Class.forName("Classname", true, loader);

call Windows Color System from Java

I need to call Windows Color System functions from Java. Following this tutorial i tried to call DLL function using Java Native Access. All examples from this tutorial works fine. When i try to load and use Mscms.dll (one of the WCS libraries) that DLL seems to be loaded successfully, but i can not call any functions. List of functions is here.
I got a message:
Exception in thread "main" java.lang.UnsatisfiedLinkError: Error looking up function 'GetColorDirectory'
What's wrong with my code? Could you help me please?
import com.sun.jna.Library;
import com.sun.jna.Native;
public class WCS_test {
public interface Mscms extends Library {
// http://msdn.microsoft.com/en-us/library/dd316928%28v=vs.85%29.aspx
boolean GetColorDirectory(String pMachineName, String[] pBuffer, int pdwSize);
}
private static Mscms mscms = (Mscms) Native.loadLibrary("C:/Windows/system32/Mscms.dll", Mscms.class);
public static void main(String[] args) {
if (mscms != null)
System.out.println("Library loaded\n");
else
System.err.println("Library loading error\n");
String[] pBuffer = new String[1024];
mscms.GetColorDirectory(null, pBuffer, pBuffer.length);
}
}
When you get a java.lang.UnsatisfiedLinkError that means that it could not find the function 'GetColorDirectory' inside of the Mscms.dll. Looking at the link from your source code http://msdn.microsoft.com/en-us/library/dd316928%28v=vs.85%29.aspx you should try the Unicode name GetColorDirectoryW.

Using DLL in java through JNA

I am using dll in java using JNA, but i am getting below error
Exception in thread "main" java.lang.UnsatisfiedLinkError: Error looking up function 'GetStatus': The specified procedure could not be found.
Not getting how to resolve this issue?
Please help.
Here is java code
import com.sun.jna.Library;
import com.sun.jna.Native;
/** Simple example of native library declaration and usage. */
public class First {
public interface TEST extends Library {
public String GetStatus();
}
public static void main(String[] args) {
TEST obj = (TEST ) Native.loadLibrary("TEST ", TEST .class);
System.out.println( obj.GetStatus());
}
}
This Nugget is super easy to use and works perfectly. https://www.nuget.org/packages/UnmanagedExports
You need Visual Studio 2012 (express).
Once installed, just add [RGiesecke.DllExport.DllExport] before any static function you want to export. That's it!
Example:
C#
[RGiesecke.DllExport.DllExport]
public static int YourFunction(string data)
{
/*Your code here*/
return 1;
}
Java
Add the import at the top:
import com.sun.jna.Native;
Add the interface in your class. Its your C# function name preceded by the letter "I":
public interface IYourFunction extends com.sun.jna.Library
{
public int YourFunction(String tStr);
};
Call your DLL where you need it in your class:
IYourFunction iYourFunction = (IYourFunction )Native.loadLibrary("full or relative path to DLL withouth the .dll extention", IYourFunction.class);//call JNA
System.out.println("Returned: " + IYourFunction.YourFunction("some parameter"));
EDIT:
If the DLL is 32bit, the JDK/JRE has to be 32bit as well. Add the following check to your code:
if(!System.getProperty("os.arch").equals("x86")) {
throw new Exception(".NET DLL " + "32bits JRE/JDK is required. Currently using " + System.getProperty("os.arch") + ".\r\nTry changing your PATH environement variable.");
}

NullPointerException when trying to run .jar file

I have just started learning java, and know only a small amount of code, however this is still a simple program. It is more of a prank program, but mostly just to test if I can make a jar file.
Here is the code:
import java.awt.*;
import java.awt.event.*;
import java.lang.*;
import java.util.Random;
public class randommouse {
public static void main(String[] args) {
for (int i=1; i<1000; i++) {
Random rand = new Random();
int w = rand.nextInt(1024) + 1;
int h = rand.nextInt(768) + 1;
int t = rand.nextInt(2000) + 1;
try {
Robot r = new Robot();
r.mouseMove(w,h);
Thread.sleep(t);
} catch (AWTException e) {}
catch (InterruptedException e) {}
catch (NullPointerException e) {}
}
}
}
I save this to file called randommouse.java,
then compile it using
javac randommouse.java
This works and when I run it using
java randommouse
it works fine also.
So then I try to create a jar file. I use the command
jar cvf randommouse.jar randommouse.class
and it works. Afterwards I double click the jar file and it comes up with an error Java Exception.
So then I run it in the cmd with
java -jar randommouse.jar
and get this error
F:\Java>java -jar randommouse.jar
Exception in thread "main" java.lang.NullPointerException
at sun.launcher.LauncherHelper.getMainClassFromJar(LauncherHelper.java:3
99)
at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:463)
F:\Java>
Do I need to put in an argument, and if so where do I put that in and how?
Thank you in advance
Sam
From the JDK doc:
In order for this option to work, the manifest of the JAR file must
contain a line of the form
Main-Class: classname
Here, classname
identifies the class having the public static void main(String[] args)
method that serves as your application's starting point. See the Jar
tool reference page and the Jar trail of the Java Tutorial for
information about working with Jar files and Jar-file manifests.
When you use this option, the JAR file is the source of all user
classes, and other user class path settings are ignored.
You have to set the entry point
$> echo "Main-Class: randommouse" > Manifest
$> jar cfm randommouse.jar Manifest randommouse.class
Did you specify the entry point in the manifest?
http://download.oracle.com/javase/tutorial/deployment/jar/appman.html
A couple of issues with your code that are not related to your actual problem, but are important nevertheless.
1) This statement is unnecessary:
import java.lang.*;
By default, every class in java.lang is implicitly imported. You don't need to do it explicitly.
2) This is dangerously bad code:
try {
// ...
} catch (AWTException e) {
} catch (InterruptedException e) {
} catch (NullPointerException e) {
}
You are catching exceptions that are most likely due to programming errors, and throwing away all evidence that they ever happened. At the very least, you should print out some kind of error message ... and the exception stacktrace to that you can diagnose it.
In this particular context (in a main method), the following is a better approach:
try {
// ...
} catch (Throwable e) {
System.err.println("An unexpected error has occurred:");
e.printStacktrace(System.err);
System.exit(1);
}
I took a look at the source code of the class and it seems to try to get the main class attribute from a list of attributes, which are Strings, and is then invoking the trim() method on the found main class attribute. When the main class is not being specified, there is no main class attribute, which causes the searching method to return null to indicate so, and when trim() is being invoked on it, it is causing the NullPointerException since the searching method has returned null. To avoid this, be sure that the main class is specified in the jar manifest:
[directory of class files]>jar -cvmf [name of manifest] MyApp.jar
And be sure that you have written the manifest right (with the line break at the end):
Main-Class: [name of main class]

Problems with loading resources during execution

Here's the background of the underlying problem, I am collaborating with a group on a project which uses Swt libraries and I am trying to package the software for deployment. As it turns out SWT is very platform/architecture dependent. I would like to be able to package all six jars (linux, mac, win and 32/64-bit) into the same package and use the appropriate library depending on the system. I realize that it is a tough challenge however, switching to Swing (or anything else) isn't really an option right now.
I have found a number of relevant threads (#Aaron Digulla's thread and #mchr's thread) which provided me valuable insights regarding the problem at hand. I have tried to implement the solution proposed by #Alexey Romanov here. With one difference, as the loadSwtJar() method he proposes is not static, I instantiate the object, and immediately following that, run the method before anything else is done to the object.
It appears as the loading procedure doesn't work properly. My reasoning for this statement is as follows:
If all Swt jars are removed from the classpath of the executable jar file, then Exception in thread "main" java.lang.NoClassDefFoundError: org/eclipse/swt/events/MouseListener is thrown which is caused by: java.lang.ClassNotFoundException: org.eclipse.swt.events.MouseListener
to me this means that the libraries are not found on classpath, am I mistaken?
If swt jars are left on the classpath then the first jar file is used by the system during execution. Meaning if gtk-linux-x86_64 happens to be the first swt jar on the list of jars then the system tries to use that, regardless if the system is win32 or Mac OSX.
I have tried to add some output to see if the loadSwtJar() method is choosing the right jar, and the output seems right on all platforms I have tried, as in the right package is selected (and the files do exist in the runnable jar). But nevertheless the right library is not loaded hence execution errors occur:
Exception in thread "main" java.lang.reflect.InvocationTargetException caused by for ex: Caused by: java.lang.UnsatisfiedLinkError: Cannot load 32-bit SWT libraries on 64-bit JVM
(Note that this is the error I get on my Linux machine if I change the order of appearance of 64-bit and 32 bit swt libraries on the build.xml file)
So, what seems to be the problem here? Am I missing out on some detail, or is it simply not possible to check system properties and load an appropriate library accordingly?
Finally below is an excerpt of my build file, figured it might help finding the source of the problem.
Thanks in advance,
EDIT: After a long debug session with a colleague, the problem is resolved (except an annoying bug regarding Thread management on MacOS as I mentioned here). It involved tweaking with the ANT build as well as the way the main class was written. (The main class, as it turns out, was extending & implementing references from the SWT library which meant that the code wouldn't compile at all, wrapped the main class with another class and loaded the SWT jars from there which seemed to be enough to tackle the problem)
Thanks and regards to everyone who contributed, especially #Aaron. Really appreciated!
Here is a copy of the latest version of my Main class. Let me know if that works for you. I tested it on Linux (32/64bit) and Windows (32bit).
package de.pdark.epen.editor;
import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import org.apache.commons.lang.SystemUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.core.util.StatusPrinter;
import de.pdark.epen.exceptions.WikiException;
public class Main
{
public final static String VERSION = "V0.9 (13.05.2010)"; //$NON-NLS-1$
private final static Logger log = LoggerFactory.getLogger (Main.class);
private static final String ORG_ECLIPSE_SWT_WIDGETS_SHELL = "org.eclipse.swt.widgets.Shell"; //$NON-NLS-1$
/**
* #param args
*/
#SuppressWarnings({"nls", "PMD.SystemPrintln"})
public static void main (String[] args)
{
String msg = "Starting ePen "+VERSION;
System.out.println (msg);
log.info (msg);
LoggerContext lc = (LoggerContext)LoggerFactory.getILoggerFactory ();
StatusPrinter.print (lc);
int rc = 1;
try
{
Main main = new Main ();
main.run (args);
rc = 0;
}
catch (Throwable t) //NOPMD
{
ExceptionUtils.printRootCauseStackTrace (t);
}
finally
{
System.out.println ("Done.");
log.info ("Exit {}", rc);
System.exit (rc); //NOPMD
}
}
#SuppressWarnings({"nls", "PMD.SystemPrintln", "PMD.SignatureDeclareThrowsException"})
private void run (String[] args) throws Exception
{
if (!SystemUtils.isJavaVersionAtLeast (150))
{
System.out.println ("Version="+SystemUtils.JAVA_VERSION_INT);
throw new WikiException ("Need at least Java 5 but this Java is only "+SystemUtils.JAVA_VERSION);
}
loadSwtJar ();
URLClassLoader cl = (URLClassLoader) getClass().getClassLoader(); //NOPMD
Class<?> c = cl.loadClass ("de.pdark.epen.editor.EPenEditor");
Class<?> shellClass = cl.loadClass (ORG_ECLIPSE_SWT_WIDGETS_SHELL);
Constructor<?> ctor = c.getConstructor (shellClass);
Object obj = ctor.newInstance (new Object[] { null });
Method run = c.getMethod ("run", args.getClass ()); //$NON-NLS-1$
run.invoke (obj, new Object[] { args });
}
#SuppressWarnings({"nls", "PMD"})
private void loadSwtJar ()
{
try {
Class.forName (ORG_ECLIPSE_SWT_WIDGETS_SHELL);
// Already on classpath
return;
} catch (ClassNotFoundException e) {
// Add the JAR
}
String osName = SystemUtils.OS_NAME.toLowerCase ();
String osArch = SystemUtils.OS_ARCH.toLowerCase ();
String swtFileNameOsPart =
osName.contains("win") ? "win32" :
osName.contains("mac") ? "macosx" :
osName.contains("linux") || osName.contains("nix") ? "linux" :
null;
String swtFileNameUiPart =
osName.contains("win") ? "win32" :
osName.contains("mac") ? "cocoa" :
osName.contains("linux") || osName.contains("nix") ? "gtk" :
null;
if (null == swtFileNameOsPart)
{
throw new RuntimeException ("Can't determine name of SWT Jar from os.name=[" + osName + "] and os.arch=["
+ osArch + "]");
}
String swtFileNameArchPart = osArch.contains ("64") ? ".x86_64" : ".x86";
if(".x86".equals(swtFileNameArchPart) && "macosx".equals(swtFileNameOsPart)) {
swtFileNameArchPart = "";
}
String swtFileName = "org.eclipse.swt." + swtFileNameUiPart + "." + swtFileNameOsPart + swtFileNameArchPart + "-3.6.0.jar";
File file = new File ("swt", swtFileName);
if (!file.exists ())
{
throw new RuntimeException ("Can't locate SWT Jar " + file.getAbsolutePath ());
}
try
{
URLClassLoader classLoader = (URLClassLoader) getClass ().getClassLoader ();
Method addUrlMethod = URLClassLoader.class.getDeclaredMethod ("addURL", URL.class);
addUrlMethod.setAccessible (true);
URL swtFileUrl = file.toURI ().toURL ();
log.info ("Adding {} to the classpath", swtFileUrl);
addUrlMethod.invoke (classLoader, swtFileUrl);
}
catch (Exception e)
{
throw new RuntimeException ("Unable to add the swt jar to the class path: " + file.getAbsoluteFile (), e);
}
}
}
You could use Java Web Start as a bootstrap mechanism for your multi platform SWT application. See a corresponding entry in SWT FAQ.
Alternatively, you could put SWT native libraries for each platform into a separate folders and specify them -Djava.library.path in your platform-specific startup script.

Categories