Call DLL from Java using JNA - java

I am new to accessing DLLs from Java using JNA. I need to access methods from a class within a DLL(written in .net). Form this sample DLL below, I am trying to get AuditID and Server ID. I am ending with the following error while I am running my code. Any guidance really appreciated.
/// Error ///
Exception in thread "main" java.lang.UnsatisfiedLinkError: Error looking up function 'GetEnrollcontext': The specified procedure could not be found.
//DLL File Code//
SampleDLL.ProfileEnroll enrollcontext = new SampleDLL.ProfileEnroll();
enrollcontext.Url =” url”;
enrollcontext.AuditIdType = SampleDLL.ProfileId;
enrollcontext.AuditId = “22222222 “;
enrollcontext.ServerId = “server1”;
/// Java Code ///
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Structure;
import dllExtract.DLLExtractTest.SampleDLL.Enrollcontext;
public class SampleDLLExtract {
public interface SampleDLL extends Library {
SampleDLL INSTANCE = (SampleDLL) Native.loadLibrary("SampleDLL",
SampleDLL.class);
public static class Enrollcontext extends Structure {
public String auditId;
public String serverId;
}
void GetEnrollcontext(Enrollcontext ec); // void ();
}
public static void main(String[] args) {
SampleDLL sdll = SampleDLL.INSTANCE;
SampleDLL.Enrollcontext enrollContext = new SampleDLL.Enrollcontext();
sdll.GetEnrollcontext(enrollContext);
System.out.println(sdll.toString(sdll.GetEnrollcontext(enrollContext)));
}
}

in fact there is a solution for you to use C#, VB.NET or F# code via JNA in Java (and nothing else)! and it is also very easy to use:
https://www.nuget.org/packages/UnmanagedExports
with this package all you need to do is, add [RGiesecke.DllExport.DllExport] to your methods like that:
C# .dll Project:
[RGiesecke.DllExport.DllExport]
public static String yourFunction(String yourParameter)
{
return "CSharp String";
}
Java Project:
public interface jna extends Library {
jna INSTANCE = (jna) Native.loadLibrary("yourCSharpProject.dll", jna.class);
public String yourFunction(String yourParameter);
}
use it in the code:
System.out.println(jna.INSTANCE.yourFunction("nothingImportant"));
Viola!
As already mentioned it works very easy, but this solution has some limitations:
only available for simple datatypes as parameter & return values
no MethodOverloading available. yourFunction(String yourParameter) and yourFunction(String yourParameter, String yourSecondParameter) does not work! you have to name them differently
Use arrays as parameter or return values. (JNA offers StringArray, but I am not able to use them in C#) (maybe there is a solution, but I couldn't come up with one so far!)
if you export a method you can't call it internally in your C# code (simple to bypass that by the following:
.
[RGiesecke.DllExport.DllExport]
public static Boolean externalAvailable(String yourParameter)
{
return yourInternalFunction(yourParameter);
}
With C# it works great, with VB.NET and F# I have no experience.
hope this helps!

Related

JNI Unsatisfied Link Error when calling the methods of one class but not the other

I want to wrap a C++ library (PCL) in Java code using JNI, but I am having inconsistent results. I have first created a PointXYZ class for testing and it looks like this:
package pcl;
public class PointXYZ extends NativeObject {
PointXYZ() { }
#Override
public native void alloc(); // creates pointer + handle on the native side
#Override
public native void dispose(); // sets handle to 0 and deletes pointer
public native float getX();
// ...
}
I have generated the C header for this class using javah, compiled everything using CMake, tested it using its getters and setters and everything works perfectly.
static {
System.setProperty("java.library.path", System.getProperty("user.dir") + "/lib");
System.loadLibrary("pcl_java_common");
}
#Test
void attributeAccessTest() {
PointXYZ p = new PointXYZ();
p.alloc();
p.setX(3);
assertEquals(p.getX(), 3);
p.dispose();
// all is good
}
Now I have done the exact same steps for a PointXYZRGB class which inherits from PointXYZ and when I try to test that it throws java.lang.UnsatisfiedLinkError. Here is the class:
package pcl;
public class PointXYZRGB extends PointXYZ {
public PointXYZRGB() { }
#Override
public native void alloc();
#Override
public native void dispose();
public native short getR();
// ...
}
I have checked the generated .dll using Dependency Walker and the PointXYZRGB methods are all present. Anyone knows what the problem could be?
UPDATE: Here are the .dll functions as requested in the comment:
The problem was that System.setProperty("java.library.path", System.getProperty("user.dir") + "/lib"); does not actually make Java look for .dll files in the given path. It essentially does nothing. Then why do the tests work for PointXYZ? This is was my mistake of having put an older .dll into the project root folder, so it was essentially looking for methods in that.

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.");
}

How to get the Groovy generated java source code

We have some legacy code with Groovy, and we want to remove Groovy from the application, so, we need to get the java source code generated after using the gmaven plug-in.
Basically, in other words I am dynamically generating new classes (using gmaven Groovy maven plug in) and I would like to be able to obtain the java source code of such generated classes.
I researched a little bit and can see that the only goals for this plug in are
<goal>generateStubs</goal>
<goal>compile</goal>
<goal>generateTestStubs</goal>
<goal>testCompile</goal>
I can't see any goal that allows you to obtain the fully implemented java source code, the stub code is not enough for us as we need the final implementation source code in order to get rid of Groovy.
I'm not very familiar with the gmaven plugin, but I assume it compiles the groovy code into byte code. In this case, you can use a byte code decompiler, there is a nice list here. In the past I've used JAD and it was quite nice. The best ones will also try to create meaningful variable names based on class names.
One warning though - Groovy objects are derived from GObject, not java.lang.Object, so you would probably need to keep the groovy jar until the groovy->java porting is done. Also, be prepared that it won't be a very easy to read java...
It may be out of your scope (1 year old) but I fought against the same problem and found a method to retrieve the algorithm (not the java source code) from the decompiled groovy classes.
You may want to take a look : http://michael.laffargue.fr/blog/2013/11/02/decompiling-groovy-made-classes/
The generated stubs will be useless for you. They are just what their names suggests: stubs.
The stubs are only useful when doing joint java/groovy compilation. That's because there are two compilers involved in a java/groovy mixed project.
Parse groovy
Create stubs
Compile java and stubs (using javac)
Continue groovy compilation (using groovyc)
The groovy code will be compiled using groovyc compiler and the result is byte code.
This is an example of a generated stub:
package maba.groovy;
import java.lang.*;
import java.io.*;
import java.net.*;
import java.util.*;
import groovy.lang.*;
import groovy.util.*;
#groovy.util.logging.Log4j() public class Order
extends java.lang.Object implements
groovy.lang.GroovyObject {
public groovy.lang.MetaClass getMetaClass() { return (groovy.lang.MetaClass)null;}
public void setMetaClass(groovy.lang.MetaClass mc) { }
public java.lang.Object invokeMethod(java.lang.String method, java.lang.Object arguments) { return null;}
public java.lang.Object getProperty(java.lang.String property) { return null;}
public void setProperty(java.lang.String property, java.lang.Object value) { }
public int getPrice() { return (int)0;}
public void setPrice(int value) { }
public int getQuantity() { return (int)0;}
public void setQuantity(int value) { }
#java.lang.Override() public java.lang.String toString() { return (java.lang.String)null;}
}
As you can see there is nothing useful. And you will still depend on some groovy libraries.
This question has been on the mailing-list some time ago [0]. To summarize: Groovy to Java is hard to achieve since there are language constructs and APIs (if you do want to totally remove the Groovy dependency) that are not available in Java.
Especially with the introduction of call-site caching and other performance optimizing techniques the generated Java code would look a lot like this (for the matter of simplicity I just threw some script into JD-GUI [1]):
public class script1351632333660 extends Script
{
public script1351632333660()
{
script1351632333660 this;
CallSite[] arrayOfCallSite = $getCallSiteArray();
}
public script1351632333660(Binding arg1)
{
Binding context;
CallSite[] arrayOfCallSite = $getCallSiteArray();
ScriptBytecodeAdapter.invokeMethodOnSuperN($get$$class$groovy$lang$Script(), this, "setBinding", new Object[] { context });
}
public Object run()
{
CallSite[] arrayOfCallSite = $getCallSiteArray(); Object items = ScriptBytecodeAdapter.createList(new Object[0]);
Object[] item = (Object[])ScriptBytecodeAdapter.castToType(ScriptBytecodeAdapter.createList(new Object[] { "Fluff", arrayOfCallSite[1].callConstructor($get$$class$java$util$Date()), (Integer)DefaultTypeTransformation.box(11235813) }), $get$array$$class$java$lang$Object());
arrayOfCallSite[2].call(items, item);
arrayOfCallSite[3].callCurrent(this, items);
ValueRecorder localValueRecorder = new ValueRecorder();
try
{
Object tmp102_101 = items; localValueRecorder.record(tmp102_101, 8);
Object tmp126_121 = arrayOfCallSite[4].call(tmp102_101, new script1351632333660._run_closure1(this)); localValueRecorder.record(tmp126_121, 14); if (DefaultTypeTransformation.booleanUnbox(tmp126_121)) localValueRecorder.clear(); else ScriptBytecodeAdapter.assertFailed(AssertionRenderer.render("assert items.findAll { it }", localValueRecorder), null); } finally {
localValueRecorder.clear(); throw finally; } return null; return null; }
static { __$swapInit();
Long localLong1 = (Long)DefaultTypeTransformation.box(0L);
__timeStamp__239_neverHappen1351632333665 = localLong1.longValue();
Long localLong2 = (Long)DefaultTypeTransformation.box(1351632333665L);
__timeStamp = localLong2.longValue(); }
class _run_closure1 extends Closure implements GeneratedClosure { public _run_closure1(Object _thisObject) { super(_thisObject); }
public Object doCall(Object it) { CallSite[] arrayOfCallSite = $getCallSiteArray(); return it; return null;
}
// ...
[0] http://groovy.329449.n5.nabble.com/Java-lt-gt-Groovy-converters-td337442.html
[1] http://java.decompiler.free.fr

renaming DLL functions in JNA using StdCallFunctionMapper

I'm trying to use JNA with a DLL in Windows, so far I was able to successfully call a function called c_aa_find_devices(). But all the functions start with c_aa and I would like to rename it to find_devices().
From what I gather the way to do this is with StdCallFunctionMapper but I can't find the documentation of how to use it in an example (i.e. how to map a DLL function by name or by ordinal to a desired name in the wrapped Java library interface). Any suggestions on where the docs are?
A complete working example, using a function mapper.
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.NativeLibrary;
import com.sun.jna.win32.StdCallFunctionMapper;
import java.io.File;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
public class JnaTest {
static {
Map options = new HashMap();
options.
put(
Library.OPTION_FUNCTION_MAPPER,
new StdCallFunctionMapper() {
HashMap<String, String> map = new HashMap() {
{
put("testMethod", "testMethod#0");
}
};
#Override
public String getFunctionName(NativeLibrary library, Method method) {
String methodName = method.getName();
return map.get(methodName);
}
}
);
File LIB_FILE = new File("test.dll");
Native.register(NativeLibrary.getInstance(LIB_FILE.getAbsolutePath(), options));
}
private static native int testMethod();
public static void main(String[] args) {
testMethod(); // call the native method in the loaded dll with the function name testMethod#0
}
}
Using StdCallMapper won't do good - it is supposed to map werid windows std lib names that have embedded total byte lenght of parameters embedded as part of the name. Since it is done to std lib only (just guessing on that, but 99% you'r functions are not the case).
If your dll uses some common prefix on all functions you need just to use something like:
class Mapper implements FunctionMapper{
public String getFunctionName(NativeLibrary library, Method method) {
return GenieConnector.FUNCTION_PREFIX + method.getName();
}
}
Where GenieConnector.FUNCTION_PREFIX is that common prefix. Bear in mind that i implement FunctionMapper, not extend StdCallMapper
From the documentation you need to provide a FunctionMapper in the original call to loadLibrary that converts the name. However you also need to keep the standard call mapping so try something like the following:
Map options = new HashMap();
options.
put(
Library.OPTION_FUNCTION_MAPPER,
new StdCallFunctionWrapper() {
public String getFunctionName(NativeLibrary library, Method method) {
if (method.getName().equals("findDevices")
method.setName("c_aa_find_devices");
// do any others
return super.getFunctionName(library, method);
}
}
);
Native.loadLibrary(..., ..., options);
All JNA documentation is located at the primary web page, the JavaDoc overview, and the JavaDocs themselves.
The example above is the right idea, in that you need to tweak the function name returned by the generic StdCallFunctionMapper (assuming you're using the stdcall calling convention). However, Method.setName() doesn't exist and you wouldn't want to call it if it did. You'll need to get the String result and replace the Java function name within it with the target native name, e.g.
name = super.getFunctionName();
name = name.replace("find_devices", "c_aa_find_devices");
More generically, you can simply tack on a "c_aa_" prefix to the returned name (or after any leading underscore), since stdcall decorations are at the end of the name.

Categories