Java Callback from Delphi using JNA crashes VM - java

I am trying to implement a simple callback from Delphi to Java using JNA using the following java code:
package jnaapp;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Platform;
import com.sun.jna.Callback;
public class JnaAppTest {
public interface CLibrary extends Library {
CLibrary INSTANCE = (CLibrary)
Native.loadLibrary((Platform.isWindows() ? "helloDelphi" : "c"),
CLibrary.class);
public interface eventCallback extends Callback {
public void callback(int id);
}
boolean setCallback(eventCallback callback);
boolean TestFunction(byte[] text, int length);
}
public static void main(String[] args) throws Exception{
byte[] text = new byte[100];
CLibrary.eventCallback callback = new CLibrary.eventCallback(){
public void callback(int id){
System.out.println("I was called with: "+id);
}
};
System.out.println(CLibrary.INSTANCE.setCallback(callback));
System.out.println(CLibrary.INSTANCE.TestFunction(text, 100));
System.out.println(Native.toString(text));
}
}
The corresponding Delphi code is given below:
Library helloDelphi;
uses
SysUtils,
Classes;
{$R *.res}
type TCallback = procedure(val: Integer); stdcall;
var
cb : TCallback;
function setCallback(callBack : TCallback) : WordBool; stdcall; export;
begin
cb := callBack;
Result := True;
end;
function TestFunction(stringBuffer : PAnsiChar; bufferSize : integer) : WordBool; stdcall; export
var s : string;
begin
s := 'Hello World 2';
StrLCopy(stringBuffer, PAnsiChar(s), bufferSize-1);
cb(bufferSize);
Result := True;
end;
exports TestFunction;
exports setCallback;
begin
end.
When the callback is called from Delphi, this crashes the VM. If I remove the callback from Testfunction, everything works fine! Thanks for your help!

Delphi uses the stdcall calling convention, so you need to use StdCallLibrary, not Library. The wrong convention will cause a crash because the called function will be expecting to use a different stack layout than the calling code.
You'll also need to use StdCallCallback rather than Callback.

Related

Is it possible to import Java models on Objective c?

I have some Java model on the server but in my iOS app I'm using JSON without a serializator because my server hasn't an Objective-C model generator.
Is it possible to integrate Java model class in Objective-C?
How?
Yes you definitely can but you will see you are much better off "translating".
These are the step by step instructions (source: http://hints.macworld.com/article.php?story=20040321163154226).
Create a new Foundation project called "HelloBridge"
Create a new Pure Java Package target called "JavaClasses"
Create a new Java class called "HelloBridge.java" an add it to target
"JavaClasses":
public class HelloBridge {
private String string = "Hello";
public void setString(String string) {
this.string = string;
}
public String getString() {
return this.string;
}
public void printString() {
System.out.println(this.string);
}
}
Add "HelloBridge.java" to the "Sources" build phase in target
"JavaClasses"
Create a new empty file called "JavaInterfaces.h" and add it to
target "HelloBridge":
// Provide Objective-C interfaces for the Java classes
// Not only good practice, it provides Code Sense
#interface java_util_Vector : NSObject
{}
- (void)add:(id)anObject;
- (id)get:(int)index;
#end
#interface HelloBridge : NSObject
{}
- (void)setString:(NSString *)string;
- (NSString *)getString;
- (void)printString;
#end
Modify "main.m":
#import <Foundation/Foundation.h>
#import "JavaInterfaces.h"
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
// Load the Java VM
id vm = NSJavaSetupVirtualMachine();
// Start the Java class loader
NSJavaClassesFromPath(nil, nil, YES, &vm);
// Load a new instance of the java.util.Vector Java class into an Objective-C pointer
java_util_Vector * vector = NSJavaObjectNamedInPath(#"java.util.Vector", nil);
[vector add:#"one item!"];
NSLog(#"item 1=%#",[vector get:0]);
[vector release];
// Load a new instance of our custom HelloBridge Java class into an Objective-C pointer
HelloBridge * hello = NSJavaObjectNamedInPath(#"HelloBridge", nil);
NSLog(#"item 1=%#",[hello getString]);
[hello setString:#"Test"];
NSLog(#"item 1=%#",[hello getString]);
[hello printString];
[hello release];
[pool release];
return 0;
}
Select "JavaClasses" from the targets drop box and Build it
Select "HelloBridge" from the targets drop box and Build/Run it

Call DLL from Java using JNA

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!

Loading java library functions to Luaj

I am stuck with loading java functions so that it can be called from lua file using luaj.
What i currently do is create something like this :
in some_package/aif.java :
package some_package;
public class aif extends TwoArgFunction {
public aif() {
}
#Override
public LuaValue call(LuaValue modname, LuaValue env) {
LuaValue library = tableOf();
library.set("foo", new foo());
env.set("aif", library);
return library;
}
//the rest contains the implementations of java functions
}
and then in lua file :
require "some_package/aif"
--etc ...
and then in Main.java file :
public static void Main(String[] args) {
String script = "lib/some_lua_file.lua";
globals = JsePlatform.standardGlobals();
LuaValue chunk = globals.loadFile(script);
chunk.call( LuaValue.valueOf(script) );
}
this code works , but what i want is that in lua file we dont have to use "require". I have achieved this similarly but in c++ using this line :
luaL_requiref(L, "aif", luaopen_aiflib, 1);
can we do like that in luaj? i tried :
globals.load(new aif());
but gets Exception in thread "main" org.luaj.vm2.LuaError: index expected, got nil (variable env in call function of aif class is nil)
anybody knows how to setup aif as lua libary to use with luaj?
You can write your MyXArgImpl like the following:
package mypackage;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.lib.ZeroArgFunction;
public class MyZeroArgImpl extends ZeroArgFunction {
public LuaValue call() {
return valueOf("My Zero Arg Implementation");
}
}
and then add it to your LUA as the following:
LuaValue globals = JsePlatform.standardGlobals();
globals.get("dofile").call( LuaValue.valueOf(yourScriptfile));
globals.set("callMyFunction", new MyZeroArgImpl());
Now you can call your function inside your LUA script even without require('...'):
print(callMyFunction())
I have found the answer after looking at the luaj implementation of Lua library.
i modified my code :
package some_package;
public class aif extends OneArgFunction{
public aif() {
}
#Override
public LuaValue call(LuaValue env) {
Globals globals = env.checkglobals();
LuaTable aif = new LuaTable();
aif.set("foo", new foo());
env.set("aif", aif);
globals.package_.loaded.set("aif", aif);
return aif;
}
//the rest contains the implementations of java functions
}
I code the aif class to TwoArgFunction is because the tutorial said to do so. Now with the above code, no need to require the class in lua file
Lets say your script that you are loading has a function "receive_aif"
function receive_aif( aifObj )
--This is how you can invoke public function associated with aifObj
aifObj:someAifFunction()
end
From java, you can pass aif instance as: (This should work with any java object )
aif aifObj = new aif()
LuaValue receive_aif_handle = globals.get("receive_aif");
LuaValue retvals = receive_aif_handle.call( CoerceJavaToLua.coerce( aifObj ) );
I am using similar constructs in my application using "3.0 aplha-2" release

JNA - Unable to get a call from native function to a callback function

I am using JNA to call functions of a dll file.
One of the functions requires a pointer to a callback function
// Dll function
void MyFunction (*CallBackFnName);
Below is the JNA proxy interface in java
import com.sun.jna.Callback;
import com.sun.jna.Library;
import com.sun.jna.Pointer;
public interface Dll extends Library {
interface CallBackFnName extends Callback {
void callback(Pointer dataBuffer, int dataLen);
}
public void MyFunction(Dll.CallBackFnName fn);
public int StartReading(short arg1, short arg2);
}
According to the API of the dll, after passing the pointer to a callback function to the function MyFunction(*CallBackFnName), whenever you call StartReading() function it will send data to the callback function.
When I am trying to do that, It is not calling my callback function. It is not throwing any exception also.
Below is the code from which I am calling functions:
import com.sun.jna.Native;
import com.sun.jna.Pointer;
public class Start {
private static Dll dll = (Dll) Native.loadLibrary("MyDll", Dll.class);
private static Dll.CallBackFnName fn = new Dll.CallBackFnName() {
#Override
public void callback(Pointer dataBuffer, int dataLen) {
System.err.println("Callback function is called successfully");
}
};
public static void main(String[] args) throws InterruptedException {
dll.MyFunction(fn); //passed the pointer to the callback function
short arg1 = 0;
short arg2 = 0;
dll.StartReading(arg1, arg2));
Thread.sleep(10 * 1000);
}
}
After running the above code, I am getting the following on the console:
DeviceAttach: received and accepted attach for vendor id 0x3eb, product id 0x2ffd, interface 0, device handle 0x037825E8
Main Menu (active Dev/Prod/Interface/Alt. Setting: 0x3eb/0x2ffd/0/0)
Read FailReadWritePipesMenu: WDU_Transfer(control receive) failed: error 0x2000000e ("
Read Fail")
Read FailReadWritePipesMenu: WDU_Transfer(control receive) failed: error 0x2000000e ("
Read Fail")
Read FailReadWritePipesMenu: WDU_Transfer(control receive) failed: error 0x2000000e ("
Read Fail")
Transferred 0 bytes
0 0
Don't know if you still need the answer , but to anyone else who has this problem,
I had this problem before.I had to create an anonymous class as such (using the above example),
dll.myfunc(new Dll.CallBackFnName() {
#Override
public void callback(Pointer dataBuffer, int dataLen) {
System.err.println("Callback function is called successfully");
} } );
This worked for me . although i can't explain why.

JNA undefined symbol

I'm trying to bind the dhcpctl library to Java using JNA. This is mi code (I didn't declare all the functions yet):
package com.abiquo.abicloud.omapi;
import com.abiquo.abicloud.omapi.DHCPControlStructure.DHCPCtrlDataString;
import com.abiquo.abicloud.omapi.DHCPControlStructure.DHCPHandle;
import com.abiquo.abicloud.omapi.OmapiControlStructure.OmapiObjectTypeT;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
/**
* Binding of the dhcpctl header.
* #author jdevesa#abiquo.com
*/
public interface DHCPControlLibrary extends Library
{
/**
* Create the loaded instance of the native library
*/
DHCPControlLibrary INSTANCE =
(DHCPControlLibrary) Native.loadLibrary("dhcpctl", DHCPControlLibrary.class);
/**
* Define as synchronized
*/
DHCPControlLibrary SYNC_INSTANCE=(DHCPControlLibrary) Native.synchronizedLibrary(INSTANCE);
int dhcpctl_initialize ();
int dhcpctl_connect (DHCPHandle handle1, String address, int port, DHCPHandle.ByValue handle2);
int dhcpctl_wait_for_completion (DHCPHandle handle, Pointer int1);
int dhcpctl_get_value (DHCPCtrlDataString dataString , DHCPHandle.ByValue handleValue, String str1);
int dhcpctl_get_boolean (Pointer int1, DHCPHandle.ByValue handleValue, String str1);
int dhcpctl_set_value (DHCPHandle.ByValue handleValue, DHCPCtrlDataString dataString, String str1);
... etc ...
}
dhcpctl uses omapi library to call the remote DHCP server. So, when I try to load the library with:
DHCPControlLibrary dhcpExecutor = DHCPControlLibrary.INSTANCE;
it throws the following error:
Exception in thread "main" java.lang.UnsatisfiedLinkError: Unable to load library 'dhcpctl': /usr/lib/libdhcpctl.so: undefined symbol: omapi_type_generic
at com.sun.jna.NativeLibrary.loadLibrary(NativeLibrary.java:160)
at com.sun.jna.NativeLibrary.getInstance(NativeLibrary.java:228)
at com.sun.jna.Library$Handler.<init>(Library.java:140)
at com.sun.jna.Native.loadLibrary(Native.java:372)
at com.sun.jna.Native.loadLibrary(Native.java:357)
at com.abiquo.abicloud.omapi.DHCPControlLibrary.<clinit>(DHCPControlLibrary.java:40)
at com.abiquo.abicloud.omapi.DHCPexecution.main(DHCPexecution.java:11)
omapi__type__generic is an external variable stored in omapi.h. I think I have to do a sort of linking when i load the library, but I don't know how to do it.
Many thanks.
omapi_type_generic is not "an external variable stored in omap.h".
This variable must be defined in some .c file somewhere and hence in some .so or .a.
If it is not defined in any .c file then there is your problem right there. Find out why it is so and fix it and you should overcome this exception.
I think u forget extern "C" while writing c++ code.
In my case
c++ code:
#include <stdlib.h>
#include <iostream>
using namespace std;
extern "C"
{
void test() {
cout << "TEST" << endl;
}
int addTest(int a,int b)
{
int c = a + b ;
return c ;
}
}
and java code
import com.sun.jna.Library;
import com.sun.jna.Native;
public class jnatest1 {
public interface Clibrary extends Library {
Clibrary INSTANTCE = (Clibrary) Native.loadLibrary("hello",
Clibrary.class);
void test();
int addTest(int a,int b);
}
public static void main(String[] args) {
Clibrary.INSTANTCE.test();
int c = Clibrary.INSTANTCE.addTest(10,20);
System.out.println(c);
}
}
it works for me
Most likely you will need to either explicitly load the omapi library or ensure that it is in LD_LIBRARY_PATH so that the system can find it automatically when the dhcpctl library is loaded.

Categories