Subclass a C++ abstract class in Java using JNI - android-ndk

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.

Related

Using Thread in in Mixed App C++ /cli to Call native Function in native class from managed class

I am working on mixed application, using both managed & native codes
I want to call a function deployed in a native class from Main() function located in Program.cpp which is managed class.
i tried using std::thread but failed with /cli
i tried to use Managed System::Threading::Thread but failed because i need to call a native function in a native class.
So how i can handle thing without using any third-party?
If you start from a native project you need to do the following steps:
Select project properties and change the option "No Common Language Runtime Support" to "Common Language Runtime Support /clr".
Open the "Property Manager" from "View" menu / "Other Windows" and add the property sheet "C++ Common Language Runtime Support" to the needed configuration (eg.: Debug | Win32) on my system this sheet is under "C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V140". I use the "Microsoft.Cpp.ManagedExtensions.props" file.
You need to remove std::thread completely.
headerish:
#pragma once
#include<stddef.h>
using namespace System;
using namespace System::Threading;
namespace FooSpace
{
// Native stuff
public class Native
{
public:
static void Foo() { }
void Bar() {
}
};
// Managed stuff
public ref class Managed
{
private:
Native* m_Native;
public:
Managed()
{
m_Native = new Native();
}
~Managed()
{
if (NULL != m_Native)
{
delete m_Native;
m_Native = NULL;
}
}
void Bar()
{
m_Native->Bar();
}
static void ThreadCall(Object^ o)
{
auto me = (Managed^)o;
me->Bar(); // Call a method of an instance of the native class
Native::Foo(); // Call a static method of the Native class
}
void StartThread()
{
auto t = gcnew Thread(gcnew ParameterizedThreadStart(ThreadCall));
t->Start(this);
t->Join();
}
};
}
soure file:
#include "stdafx.h"
#include "CppCli_Native.h"
using namespace FooSpace;
int main()
{
Native::Foo(); // call native static method
auto native = new Native(); // create native instance
native->Bar(); // call native method
auto managed = gcnew Managed();
managed->Bar(); // This will call bar
managed->StartThread(); // This will start a thread
delete managed;
Console::ReadLine();
return 0;
}
Edit: It turns out that you don't need to use IntPtr to store native class.
I find this answer also useful, it also gives us a fast introduction to c++-cli syntax.

Can a managed ref-class directly implement a COM interface?

Is there a built-in way to allow a managed ref-class to implement and expose a COM inerface that is safely callable from native code?
Looking at the C# side, this is easily done by decorating the target interface with the proper COM-interop attributes, for example:
Native Interface
interface ISampleGrabberCB: public IUnknown
{
virtual STDMETHODIMP SampleCB( double SampleTime, IMediaSample *pSample ) = 0;
virtual STDMETHODIMP BufferCB( double SampleTime, BYTE *pBuffer, long BufferLen ) = 0;
};
static const IID IID_ISampleGrabberCB = { 0x0579154A, 0x2B53, 0x4994,
{ 0xB0, 0xD0, 0xE7, 0x73, 0x14, 0x8E, 0xFF, 0x85 } };
Managed Equivalent Interface
[Guid("0579154A-2B53-4994-B0D0-E773148EFF85")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[SuppressUnmanagedCodeSecurity]
public interface ISampleGrabberCB {
int BufferCB(double SampleTime, IntPtr pBuffer, int BufferLen);
int SampleCB(double SampleTime, IMediaSample pSample);
}
Once this declaration is done, through the magic of P-Invoke you can do something like this:
public class FooClass : ISampleGrabberCB {
int ISampleGrabberCB.BufferCB(double SampleTime, IntPtr pBuffer, int BufferLen) {
Console.WriteLine("BufferCB called");
}
int ISampleGrabberCB.SampleCB(double SampleTime, IMediaSample pSample) {
Console.WriteLine("SampleCB called");
}
public void SomeMethod(IBaseFilter aDirectShowFilter) {
ISampleGrabber sampleGrabber = (ISampleGrabber)aDirectShowFilter;
// By the magic of PInvoke, this is possible and works!
// ISampleGrabber->SetCallback() is expecting an ISampleGrabberCB* COM interface
// After the following line, native code is able to callback safely
// into our managed code
sampleGrabber.SetCallback(this, 0);
}
}
Is there a way to mimic this behavior on C++/CLI?
Evidently, the Interop plumbing to make this possible exists as it is used by C#. Furthermore, the compiler could generate the necessary managed interface from inspecting the available native interfaces (I still think we would need to provide the relevant Guids, as this is not an attribute within the native interface)
I just got curious about this topic and played around and I found out some minor differences:
I have IVI-COM class library on my PC, and always wanted to try to interface some of them, although the IVI also has .Net interfaces so it does not make too much sense...
I started with C#, where we get good IntelliSense support. I have added the necessary references and added a class to my project. With the object browser we can select an interface.
public class MyDmm : IIviDmmMultiPoint
{
}
After that just use IntelliSense (Ctrl-.) to add the ‘using’ statement and let them make the necessary properties and methods for us.
using Ivi.Dmm.Interop;
///...
public int Count
{
get
{
throw new NotImplementedException();
}
///...
So now we need the C++-CLI dialect :) Which is as follows:
using namespace IviDmmLib;
///...
public ref class Dmm : IIviDmmMultiPoint
{
Note that the name used by the using statement is different, we can obtain this by selecting the reference at the Solution Explorer and check the name shown at the ‘Properties’ below.
I did not fully complete the experiment but I saw that the COM library was x64 bit, so we may compile the project for the same.
Further interesting readings:
Windows Runtime C++ Template Library
Please, give me feedback if you find some more differences, so we can put them here too.

C++ how to change private members of managed object using a native one?

I'm working on a student project. It's a network card game. The solution contains 3 projects. Client's GUI using Windows Forms so it has managed classes. Static client's library in native C++. GUI's project has reference to it thus uses 'Mixed Rules'. Server is in native C++ as well. I use RPC middleware for communication. It works only with native C++. That is why I need the static library to hide there all the details of communication on client's side.
Since the server can at any moment change its state and that should be shown in client's GUI, I use callback approach to change Windows Forms' components. And here I found a problem because I need to change private members of managed class with the help of a native object.
There are probably different ways to do that. My idea is sending a pointer to instance of managed class into instance of native class and saving it there. So later I can call from that native object public member functions of that managed class to change components.
This is from my 'Mixed Rules' GUI project:
//Native class for changing window 'Lobby'
class LobbyI : public ClientLib::Lobby {
public:
LobbyI();
~LobbyI();
//Should change window due to current Server's state
void reDraw(const CommonLogic::ServerState&);
};
// Managed class implements GUI for window 'Lobby'
// generated by Visual Studio designer
public ref class LobbyGUI : public System::Windows::Forms::Form {
//My members
ClientLib::Mediator* mediatorPtr; // Is it correct?
LobbyI* lobbyPtr; // ?
public:
LobbyGUI(void) {
InitializeComponent();
mediatorPtr = new ClientLib::Mediator(); // Is it correct?
lobbyPtr = new LobbyI(); // ?
mediatorPtr->setCallback(lobbyPtr);
}
protected:
~LobbyGUI() {
if (components) { delete components; }
delete lobbyPtr; // Is it correct?
lobbyPtr = nullptr; // ?
delete mediatorPtr; // ?
mediatorPtr = nullptr; // ?
}
private: System::Windows::Forms::Button^ buttonLogIn;
//...
This is from native static library ClientLib:
class Lobby {
public:
virtual ~Lobby();
virtual void reDraw(const CommonLogic::ServerState&) = 0;
};
class Mediator {
CommonLogic::ServerState serverState;
Lobby* lobbyPtr;
public:
Mediator();
~Mediator();
void setCallback(Lobby* ptr) { lobbyPtr = ptr; }
void reDrawLobby() { lobbyPtr->reDraw(serverState); }
};
This code builds ok. The only thing I need now is that the member function reDraw() of native derived class LobbyI is able to change the window implemented by managed class LobbyGUI. Thus getting and keeping and using pointer to it. And then I think it all will work. How to do that?
Maybe it's not the nicest implementation in general. I would be happy to read other suggestion.
I'm also doubtful about the way I used pointers to native classes inside managed class. Is it correct? It didn't work correct until I inserted ptr=nullptr; after delete ptr; in destructor.
UPDATE: Now I see redundancy in my code. Abstract class Lobby is useless. I need only to implement reDraw() function in managed class which will have obviously access to components of the window. And then pass safe pointer to native class function which expects pointer to a function as a parameter.
Finally I've solved it!! Using this article. In the following code a native object stores provided pointer to a function of managed object. So this callback function can be invoked at any time. A delegate is used as a form of type-safe function pointer. Instance of GCHandle is used to prevent the delegate from being relocated by garbage collector.
Here is simple CLR Console Application which increments and prints some integer using callback function invoked from native object. Thus we can "change private members of managed object using a native one".
using namespace System;
using namespace System::Runtime::InteropServices;
typedef void(__stdcall *ANSWERCB)(); // define type of callback function
#pragma unmanaged
class NativeClass {
ANSWERCB cbFuncPtr = 0; // pointer to callback function
public:
void setCallback(ANSWERCB fptr) {
cbFuncPtr = fptr;
incAndPrint();
}
void incAndPrint() { cbFuncPtr(); } // invokes callback which increments and prints
};
#pragma managed
ref class ManagedClass {
public: delegate void Del();
private:
Int32 i;
NativeClass* nativePtr;
Del^ delHandle;
GCHandle gch;
public:
ManagedClass(Int32 ii) : i(ii) {
nativePtr = new NativeClass;
delHandle = gcnew Del(this, &ManagedClass::changeAndPrintInt);
gch = GCHandle::Alloc(delHandle);
IntPtr ip = Marshal::GetFunctionPointerForDelegate(delHandle);
ANSWERCB callbackPtr = static_cast<ANSWERCB>(ip.ToPointer());
nativePtr->setCallback(callbackPtr);
}
~ManagedClass() {
delete nativePtr;
nativePtr = __nullptr;
gch.Free();
}
private:
void changeAndPrintInt() // callback function
{
Console::WriteLine(++i);
}
};
int main(array<System::String ^> ^args)
{
ManagedClass mc(1);
return 0;
}

how to pass java class instance as a parameter to JNI method?

I'd like to pass java class object to JNI method,
And I want to call few methods in JNI method like below.
Is there anyone who have some example like below?
class JavaClassParameter{
void javaMethodTobeCalledInJNI(){
...java source...
}
}
class MainJavaClass{
void somemethod(){
JavaClassParameter object = new JavaClassParameter();
JNIMethod(object);
}
native void JNIMethod(JavaClassParameter object);
}
// C++ code
void JNIMethod(object){
object->javaMethodTobeCalledInJNI();
}
Your method declaration:
class MainJavaClass {
native void JNIMethod(JavaClassParameter object);
}
means javah should generate a forward declaration like the following:
JNIEXPORT void JNICALL Java_MainJavaClass_JNIMethod(JNIEnv* env, jobject mainJavaClass);
In the implementation of that, you have a few things to do:
Find JavaClassParameter
Use FindClass, which takes a string name:
jclass cls = env->FindClass("JavaClassParameter");
Find javaMethodTobeCalledInJNI()
Use GetMethodID, which takes the class to check, the string name of the method, and its signature. Since this is a void function with no arguments, its signature is just ()V:
jmethodID method = env->GetMethodID(cls, "javaMethodTobeCalledInJNI", "()V");
Call javaMethodTobeCalledInJNI()
Use CallVoidMethod, which takes the object instance, the method ID, and any arguments (none in this case):
env->CallVoidMethod(mainJavaClass, method);
You should check for NULL results after each step; if you get a NULL back from one JNI function and pass it to another, you'll usually crash the JVM

Visual C++ static library

I am writing a c++ static library A.lib in visual studio 2008. In my static library, I am using few APIs exposed by another static library B.lib(.lib).
I have a written an application that uses A.lib. Since few header files in A.lib are using headers from B.lib, my application wants a path of B.lib header files. How can I avoid my application so that I need not to provide path of B.lib header files for compilation ?
Refrain from using types from B-headers in the interface of your library. A good way of totally hiding the implementation is using the factory-pattern along with pure abstract base classes as interfaces. You will still have to link B.lib in your application though.
Sample Before:
// A.h
#include "B.h"
class Foo {
public:
void DoStuff();
private:
B::Bar Data; // B::Data comes from library B
};
This in your header adds a dependency to B.
With Factory, your application now uses IFoo.h instead of A.h:
// IFoo.h
class IFoo {
public:
static IFoo * CreateInstance( ); // implemented in IFoo.cpp, just returns new Foo
virtual void DoStuff() = 0;
virtual ~IFoo() {}
};
// A.h
class Foo : public IFoo {
public:
virtual void DoStuff();
private:
B::Bar Data; // B::Data comes from library B
};
You can go to settings and add the directory to the additional include directory's and you can just use the header by name.

Resources