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.
Related
am using JACOB as a bridge with java to access objects of a simulator (PTV vissim)to be able to manipulate it in real time , most objects has methods and properties... i was going well , because i was using the ...
getProperty and invoke functions but now I need to access an object attribute e.g. name but i don't know which function should I use , the object am dealing with is an instance of
ActiveXComponent
package com.vissim;
import java.util.List;
import java.util.Scanner;
import com.jacob.activeX.ActiveXComponent;
import com.jacob.com.Variant;
public class Main {
/**
* #param args
*/
public static void main(String[] args) {
Vissim vissim = new Vissim();
vissim.start();
vissim.LoadNet("H:\\MY VISSIM\\projects\\new.inpx");
Net net = new Net(vissim);
ActiveXComponent linkContainer = net.getNetProperty("links");
System.out.println("links fetched");
ActiveXComponent link =linkContainer.invokeGetComponent("itemByKey", new Variant(1));
// the problem is here , i need to do something like
//link.getProperty("Attributes");
System.out.println("we are here ");
}
Use com4j to generate some wrapper files. com4j will probably crash saying that it is unable to handle some of the types, but if you go to the generated java files you will see the names of all of the methods that can be called from the Dispatch object e.g. ISimulation.java will have all of the methods that you can call on a Simulation object.
Here is an example of some function / method calls:
Dispatch vissim = VISSIM.getObject();
Dispatch.call(vissim, "loadNet", new Object[]{new Variant("C:\\Users\\userName\\workspace\\VISSIMNetworks\\network.inp"), new Variant(0)});
Dispatch simulation = Dispatch.call(vissim, "simulation").toDispatch();
Dispatch.call(simulation, "runContinuous");
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!
I am using JPachube.jar and Matlab in order to send data to my datastream. This java code works on my machine:
package smartclassroom;
import Pachube.Data;
import Pachube.Feed;
//import Pachube.FeedFactory;
import Pachube.Pachube;
import Pachube.PachubeException;
public class SendFeed {
public static void main(String arsg[]) throws InterruptedException{
SendFeed s = new SendFeed(0.0);
s.setZainteresovanost(0.3);
double output = s.getZainteresovanost();
System.out.println("zainteresovanost " + output);
try {
Pachube p = new Pachube("MYAPIKEY");
Feed f = p.getFeed(MYFEED);
f.updateDatastream(0, output);
} catch (PachubeException e) {
System.out.println(e.errorMessage);
}
}
private double zainteresovanost;
public SendFeed(double vrednost) {
zainteresovanost = vrednost;
}
public void setZainteresovanost(double vrednost) {
zainteresovanost = vrednost;
}
public double getZainteresovanost() {
return zainteresovanost;
}
}
but I need to do this from Matlab. I have tried rewriting example (example from link is working on my machine): I have compile java class with javac and added JPachube.jar and SendFeed.class into path and then utilize this code in Matlab:
javaaddpath('C:\work')
javaMethod('main','SendFeed','');
pachubeValue = SendFeed(0.42);
I get an error:
??? Error using ==> javaMethod
No class SendFeed can be located on Java class path
Error in ==> post_to_pachube2 at 6
javaMethod('main','SendFeed','');
This is strange because, as I said example from the link is working.
Afterwards, I decided to include JPachube directly in Matlab code and to write equivalent code in Matlab:
javaaddpath('c:\work\JPachube.jar')
import Pachube.Data.*
import Pachube.Feed.*
import Pachube.Pachube.*
import Pachube.PachubeException.*
pachube = Pachube.Pachube('MYAPIKEY');
feed = pachube.getFeed(MYFEED);
feed.updateDatastream(0, 0.54);
And I get this error:
??? No method 'updateDatastream' with matching signature found for class 'Pachube.Feed'.
Error in ==> post_to_pachube2 at 12
feed.updateDatastream(0, 0.54);
So I have tried almost everything and nothing! Any method making this work will be fine for me. Thanks for help in advance!
This done trick for me (answer from here)
javaaddpath('c:\work\httpcore-4.2.2.jar');
javaaddpath('c:\work\httpclient-4.2.3.jar');
import org.apache.http.impl.client.DefaultHttpClient
import org.apache.http.client.methods.HttpPost
import org.apache.http.entity.StringEntity
httpclient = DefaultHttpClient();
httppost = HttpPost('http://api.cosm.com/v2/feeds/FEEDID/datastreams/0.csv?_method=put');
httppost.addHeader('Content-Type','text/plain');
httppost.addHeader('X-ApiKey','APIKEY');
params = StringEntity('0.7');
httppost.setEntity(params);
response = httpclient.execute(httppost);
I would rather use built-in methods. Matlab hasurlread/urlwrite, which could work if all you wish to do is request some CSV data from Cosm API. If you do need to use JSON, it can be handled in Matlab via a plugin.
Passissing the Cosm API key, that can be done via key parameter like so:
cosm_feed_url = "https://api.cosm.com/v2/feeds/61916.csv?key=<API_KEY>"
cosm_feed_csv = urlread(cosm_feed_url)
However, the standard library methods urlread/urlwrite are rather limited. In fact, the urlwrite function is only designed for file input, and I cannot even see any official example of how one could use a formatted string instead. Creating a temporary file would reasonable, unless it's only a few lines of CSV.
You will probably need to use urlread2 for anything more serious.
UPDATE: it appears that urlread2 can be problematic.
As many questions begin, this is driving me crazy.
I have a homegrown StarTeam java library. I have one static method like this:
public static Label getLatestDeploymentLabel(com.starbase.starteam.File child) {
// blah
}
The method works as expected when I call it from java. When I call it from Groovy, I get:
Caught: groovy.lang.MissingMethodException:
No signature of method: static pkg.starteam.StarTeamUtils.getLatestDeploymentLabel()
is applicable for argument types: (com.starbase.starteam.File)
values: [FILENAME-FOO.sql] at starteam.run(starteam.groovy:54)
I put in a println right before I call that method:
chgset.elements().each() { item ->
println "type of item is ${item.class.getName()}"
def latestlabel = StarTeamUtils.getLatestDeploymentLabel(item)
}
And confirm that, in fact, it's iterating what I expect it's iterating over:
type of item is com.starbase.starteam.File
I've seen a few different similar issues in other posts relating to static methods and the responses are along the lines of "are you sure it's a static method?". I'm sure it's a static method.
There isn't much groovy code to this. What there is of it is all contained in a single script in the default package. The main method is then called implicitly and it's in the body of the script class that the call out to the java library is made. I set the classpath in a DOS batch wrapper script, e.g.:
SET INITIALCLASSPATH=%CLASSPATH%
SET NEWCP=c:/libs/etc.jar;c:/etc/etc.jar
SET GROOVYPATH=c:/groovy.bat
SET CLASSPATH=%NEWCP%
%GROOVYPATH% %*
SET CLASSPATH=%INITIALCLASSPATH%
I created a simple situation which I think emulates my situation.
C:\apps\groovy-1.8.6\scripts>type Other.java
class Other {
private String name = "notset";
public Other(String name) {
this.name = name;
System.out.println("Created an other");
}
public String toString() {
return name;
}
}
C:\apps\groovy-1.8.6\scripts>type ThingList.java
import java.util.ArrayList;
import java.util.Iterator;
class ThingList {
ArrayList ourlist = new ArrayList<Other>();
public ThingList(){}
public ArrayList add(Other thing) {
ourlist.add(thing);
return ourlist;
}
public Iterator iterator(){
return ourlist.iterator();
}
}
C:\apps\groovy-1.8.6\scripts>type JavaLib.java
class JavaLib {
public JavaLib() {}
public static ThingList getThingList(Other thing) {
ThingList tl = new ThingList();
Other one = new Other("extra one");
tl.add(thing);
tl.add(one);
return ThingList;
}
}
C:\apps\groovy-1.8.6\scripts>type testthing.groovy
def myOther = new Other("A new other")
println "type of myOther is ${myOther.class.getName()}"
def myList = getThingList(myOther)
myList.each() {
println it
}
C:\apps\groovy-1.8.6\scripts>type wrapper.bat
#ECHO OFF
SET INITIALCLASSPATH=%CLASSPATH%
SET GROOVY=C:\apps\groovy-1.8.6\bin\groovy.bat
SET CP=.
SET CLASSPATH=%CP%
%GROOVY% %*
SET CLASSPATH=%INITIALCLASSPATH%
C:\apps\groovy-1.8.6\scripts>wrapper.bat testthing.groovy
Created an other
type of myOther is Other
Caught: groovy.lang.MissingMethodException: No signature of method: testthing.ge
tThingList() is applicable for argument types: (Other) values: [A new other]
groovy.lang.MissingMethodException: No signature of method: testthing.getThingLi
st() is applicable for argument types: (Other) values: [A new other]
at testthing.run(testthing.groovy:3)
C:\apps\groovy-1.8.6\scripts>
Any insights or suggestions would be greatly appreciated!
AndyJ
Without a way to reproduce, it's impossible to say for sure what the problem is. One possibility is that it is a class loading problem. Is the Groovy code contained in a regular Groovy class that's sitting on the class path, or does the Groovy code get loaded dynamically (e.g. by using GroovyShell)?
I'm not really sure how I can explain this, but here goes:
I want to be able to "insert" some commands into parts of my code which will be loaded from external files. To parse and execute these commands, I presumably have to use some scripting like BeanShell's eval method. The problem is that it doesn't seem to recognize the instance/method it's inside of. As a very basic example, I want to do something like
public void somethingHappens()
{
Foo foo = new Foo();
Interpreter i = new Interpreter();
i.eval("print(foo.getName());");
}
Is this possible? Should I use other scripting tools?
If you're using 1.6, you can use the built in JavaScript support.
The Java Scripting Programmer's Guide explains how to import Java classes into your script.
Code example 9 in this article explains how to pass objects into the script's scope.
Using beanshell, this is something you can try
package beanshell;
import bsh.EvalError;
import bsh.Interpreter;
public class DemoExample {
public static void main( String [] args ) throws EvalError {
Interpreter i = new bsh.Interpreter();
String usrIp = "if(\"abc\".equals(\"abc\")){"
+ "demoExmp.printValue(\"Rohit\");"
+ "}";
i.eval(""
+ "import beanshell.DemoExample;"
+ "DemoExample demoExmp = new beanshell.DemoExample();"
+ ""+usrIp);
}
public static void printValue(String strVal){
System.out.println("Printing Value "+strVal);
}
}