What is the correct way to map a callback function that has void* as an argument?
I am working with native library (.dll) using JNA.
Library defines the following callback function:
typedef void (__stdcall *NotifyFunc)(int code, void *value);.
Here is how it is mapped in java:
public static NatLib.NotifyFunc notifyFunction = new MyNotifyFuncImpl();
public static void main(String[] args) {
NatLib.INSTANCE.SetCallbackFunc(notifyFunction);
}
public interface NatLib extends Library {
NatLib INSTANCE = Native.load("Nat.dll", NatLib.class);
//...
void SetCallbackFunc(NotifyFunc func);
interface NotifyFunc extends Callback {
void MyNotifyFunc(int code, Pointer value);
}
}
public static class MyNotifyFuncImpl implements NatLib.NotifyFunc {
#Override
public void MyNotifyFunc(int code, Pointer value) {
System.out.println("Notification: " + Integer.toHexString(code));
}
}
I set the callback function. However problems start at runtime. Callback function is executed only once, and then java application fails with non-zero exit value -1073740791. hs_err_pid* log file is not generated.
Is there something wrong with the mapping? I could not find examples for mappings with void* as parameter. Generally void* is mapped as Pointer, is it different when it is used as a parameter?
Do I need to free memory after each callback? I tried to do Native.free(Pointer.nativeValue(value)); inside callback, but this didn't solve the problem.
P.S. I did read JNA - callback method with void* arguments stackoverflow question, but it doesn't seem to be my case. I declared callback as static member public static NatLib.NotifyFunc notifyFunction = new MyNotifyFuncImpl(); - this should keep the reference to callback function unchanged and not garbage collected during runtime.
The problem is that you can not use Callback, if it is a __stdcall function. In this case you need to implement StdCallLibrary.StdCallCallback. So your code should be like this:
interface NotifyFunc extends StdCallLibrary.StdCallCallback{
void MyNotifyFunc(int code, Pointer value);
}
The reason behind this is that __stdcall is used to call functions of the Win32 API. And if you only use Callback Jna does not know it has to use these.
Related
I'm using a native library coded in C or C++, after a lot of multiple tests i successed to make it work, but i'm not sure if what i do correspond to the correct coding rules, and some parts are not clear for me.
So my question is : could you confirm and complete what i understood.
Thanks
the C prototype function is:
typedef void (*pfHook) (const char *pText);
and the function to set the callback function is:
short LogHookEx(void (*pfHook) (const char*));
So i created an interface for my native dll like that:
So if i understood "interface pfHookCallback" correspond to the C prototype function and "sCscSetApiLogHookEx" is a classic method from my native dll.
public interface Reader extends Library {
Reader INSTANCE = (Reader) Native.load((Platform.isWindows() ? "ReaderDll" : "c"),
Reader.class);
interface pfHookCallback extends Callback {
void invoke(String pText);
}
short LogHookEx(pfHookCallback pfHook);
}
The part that i understand less, is the part that i include in my "main":
public class Principal {
public static void main(String[] args) {
Reader.pfHookCallback pfHook = new Reader.pfHookCallback() {
public void invoke(String pText) {
System.out.println(pText);
}
};
res = Reader.INSTANCE.LogHookEx(pfHook);
To be more clear this callback function is used for tracing from an hardware device.
As described above, it's working, but it's not cleat for me.
And another question is , the goal of my code is to save the logs (so the pText string) into a file. Is there a best practice to do that, because if i create buffered writer, i don't know if it's good or not to do something like that:
public class Principal {
public static void main(String[] args) {
Reader.pfHookCallback pfHook = new Reader.pfHookCallback() {
public void invoke(String pText) {
bw.write(pText);
bw.close;
}
};
res = Reader.INSTANCE.LogHookEx(pfHook);
My question is i don't know if it's really good to open and close a file very quickly every time there is a log to be saved ?
I have a cpp function pointer:
using MyclassPtr = std::shared_ptr<Myclass>;
using UpdateCallback = std::function<void(const MyclassPtr&)>;
Now in java I have a interface:
public interface UpdateCallback {
void OnDataUpdate(MyClass data);
}
Requirement is that the cpp library should add itself as a listener to the java event. So, cpp will call setUpdateCallback(UpdateCallback) to add itself as a callback to the application events if occured.
JNI Method:
void MyCustomClassJNI::setUpdateCallback(const UpdateCallback & callback)
{.......}
How to get the function pointer from cpp and map it with the interface, so that when application class calls the interface methods, the cpp function callback is invoked??
Please help.
Your void OnDataUpdate(MyClass data); is actually passing down the MyClass data object to JNI.
Rather than passing down the callback interface pointer, probably, MyClass data should be the meaningful object to your C++ layer.
From Java side
// Java code
public class MyCustomClassJNI implements UpdateCallback {
public native void notifyJni(MyClass data);
#Override
void OnDataUpdate(MyClass data) {
this.notifyJniPeer(data);
}
}
Then on C++ side, you should have a JNI method like below:
JNIEXPORT void JNICALL
Java_your_package_name_MyCustomClassJNI_notifyJni(JNIEnv *env, jobject myClassData) {
// read myClassData object.
}
For example, in C# I have
[MonoPInvokeCallback(typeof(PointDelegate))]
public static void Callback(int x, int y)
{ .... }
This method is stored in a delegate of signature return void (int, int).
public delegate void PointDelegate(int x, int y);
I sent this delegate variable to Objective-C and over there I was able to call it directly to invoke Callback(). It just works. (I have declared the equivalent typedef at Objective-C side to match)
C#
objC(Callback);
Objective-C
typedef void (*PointDelegate)(int x, int y);
void objC(PointDelegate delegateFromCSharp)
{
delegateFromCSharp(1,2);
}
What is the equivalent in Java? Assuming I can call a method in Java already and the delegate is being passed as the only parameter, what would be the signature of that Java method? And how to invoke the received delegate?
I managed to get it working. This solution uses Unity's "AndroidJavaProxy" class so I am not sure what it will be using pure JNI. But I am glad it works for my case.
This is C# :
public class IntInterface : AndroidJavaProxy
{
public IntInterface() : base("com.YourCompany.YourApp.YourClass$IntInterface") { }
void Call(int i)
{
Debug.Log("Java says : " + i);
}
}
Then I call static method on Java with new IntInterface() as a parameter.
At Java side I have a matching interface waiting. It can accept IntInterface from C# side without throwing JNI : unknown signature for type anymore. The Call is also being matched with C# ones.
public static void StaticMethod(IntInterface intInterface) {
intInterface.Call(555);
}
#FunctionalInterface
public static interface IntInterface{
void Call(int i);
}
The result is "Java says : 555" I just invoked C# method Call(int i) with parameter from Java.
I have a C++ library that I have to use in an existing Android implementation. I'm using Android NDK and using the C++ classes via JNI.
However, I am not able to find how to subclass a C++ abstract class in Java using JNI.
Problems I face:
My aim is to provide Java implementation for the virtual methods in C++ by subclassing the abstract C++ class.
I have loaded the native library and I'm trying to declare the native methods.
The C++ methods have keyword 'virtual'. When I declare the native functions in Java after loading the C++ library, 'virtual' is not recognized. What is wrong here?
Any help is appreciated. I'm a newbie to JNI. Thanks in advance.
Let's consider we have a C++ class:
class iVehicle
{
public:
virtual void Run() {}; // not-pure virtual here for simplicity of a wrapper, but could be pure (see the end of the post)
virtual int GetSize() const; // we want to reuse it in Java
};
We want to create a class Bot in Java that extends class iVehicle in the sense that calls to super invoke the C++ code from iVehicle::GetSize() and, from the C++ point of view, we can use the instances of Bot as iVehicle* variables. That's tough since C++ provides no good built-in functionality for reflection.
Here is one possible solution.
To use C++ class in Java we need to generate a Java wrapper, i.e:
class iVehicle
{
public void Run() { Native_Run(); }
public int GetSize() { return Native_GetSize(); }
private native void Native_Run();
private native int Native_GetSize();
// typecasted to pointer in C++
private int NativeObjectHolder;
// create C++ object
native static private int CreateNativeObject();
}
The usage in Java is simple:
class Bot extends iVehicle
{
public int GetSize()
{
if ( condition ) return 0;
// call C++ code
return super.GetSize();
}
}
However, there is a C++ part to this code:
static jfieldID gNativeObjectHolderFieldID;
JNIEXPORT void JNICALL Java_com_test_iVehicle_Run( JNIEnv* env, jobject thiz )
{
int Value = env->GetIntField(thiz, gNativeObjectHolderFieldID);
iVehicle* Obj = (iVehicle*)Obj;
// todo: add checks here, for NULL and for dynamic casting
Obj->Run();
}
The similar code is for GetSize().
Then creating an instance of Java's Bot you have to call CreateNativeObject() and assign the returned value to the NativeObjectHolder field.
JNIEXPORT int JNICALL Java_com_test_iVehicle_CreateNativeObject( JNIEnv* env, jobject thiz )
{
iVehicle* Obj = new iVehicle;
return (int)Obj;
}
So, this is the scheme. To make this work you will need to add the destruction code and to parse C++ classes to generate all this glue code.
Added:
In case where iVehicle is actually abstract you will have to generate a non-abstract wrapper that you are able to instantiate:
class iVehicle
{
virtual void Run() = 0;
}
class iVehicle_Wrapper: public iVehicle
{
virtual void Run() { ERROR("Abstract method called"); };
}
And instantiate iVehicle_Wrapper in CreateNativeObject(). Vuala! You have inherited an abstract C++ class in Java.
I am writing a library in Java. A object in the library is referenced by the main application.
The application requires a method to be called at a certain point on one of its objects.
The library object wants to invoke this method in the application, with parameters.
I do not want to pass the application object to the library object as a reference because I want it loosely coupled and the Application object is specific to that application. If I pass it just as a Object data type, it will not have the method attached as not that type without casting.
As they are separate jars, static will not work either and want it loosely coupled again.
Example
Application A is running and has class watched. In its own jar.
public class WatchedInApplication extends BaseRichBolt {
// has a reference to the lib class
private WatcherInLibrary lib;
...
public void invoke (string.. args) {
// invoke this method from another jar reference as a API.
// to replay some data.
outputCollector.emit(args)
}
}
The library B is referenced by Application A and it wants to invoke a method in a object in Application A at a certain point. This library B is also another jar, that is running and monitoring Application A.
public class WatcherInLibrary {
public void invokeApplicationsinvokeMethod() {
// invoke the applications method invoke, but with no specific reference to it
// basically want to invoke the output collector.emit to replay tuples.
}
}
Points
I could simply pass the outputcollector or the BaseRichBolt to the library class B. But I want to keep it loosely coupled. Also both applications are referencing Storm which may cause future issues, even if no issues it is tied closely to Storm if I start passing outputcollector or BaseRichBolt around.
Does a clever design pattern exist? Simply user interface see below
Following on the comments it was simple. Use an interface that defines a invoke(args) method. Implement the interface on the Bolt object. This can then be passed and is generic. Then called from the library method.
Quick toy example, could be improved by generics on the interface.
WatchedApplication
public class WatchedInApplication implements Invoke {
private WatcherInLibrary lib;
public WatchedInApplication(WatcherInLibrary lib) {
super();
this.setLib(lib);
}
public WatcherInLibrary getLib() {
return lib;
}
public void setLib(WatcherInLibrary lib) {
this.lib = lib;
}
// where the method is implemented.
#Override
public void invokeRemote(String data) {
System.out.println("Method Invoked " + data.toString());
}
}
WatcherLibrary
public class WatcherInLibrary {
private Invoke obj;
public void setWatchedApplication(Invoke object) {
this.obj = object;
}
public void invokeRemoteObject() {
this.obj.invokeRemote("data passed");
}
}
The interface solution
public interface Invoke {
public void invokeRemote(String data);
}
Example Main
WatcherInLibrary lib = new WatcherInLibrary();
WatchedInApplication watched = new WatchedInApplication(lib);
lib.setWatchedApplication(watched);
lib.invokeRemoteObject();
The use of the interface enables this solution to work with any data type.