I'm good in c# and i need help in JAVA.
I have a c++ function that outs 4 variables
int Func1(int inParam1, unsigned char* inParam2, int *outParam1, int *outParam2, int *outParam3, unsigned char** outParam4);
I can call this function from C# using PInvoke like this
[DllImport("CLSFPCaptureDLL.dll"]
int Func1(int inParam1, byte[] inParam2, out IntPtr outParam1, out IntPtr outParam2, out IntPtr outParam3, out IntPtr outParam4);
But now i need to call the c++ function in java. I have write a JNI with a java class
that needs to out these 4 variables. How can i do it in JAVA ?
You need a bridge in c++.
Be sure to read about JNI so you can better follow my sample.
In C++, create a class and compile it to a dll so that it finds and links to CLSFPCaptureDLL.dll.
Read about JNI function, that will help you build the output.
Java:
Test1.java:
package test;
public class Test1 {
static {
System.loadLibrary("YourLibrary");
}
public static byte[] myJniFunc();
}
and C++:
Test.cpp:
extern "C"
{
JNIEXPORT jobject JNICALL Java_test_Test1_myJniFunc(JNIEnv *env, jclass cls)
{
// Make all the data you need, and pass it back as a jbyteArray
}
}
Related
I am looking at the MoreTeapots sample:
https://github.com/googlesamples/android-ndk/tree/master/MoreTeapots
and I see that is easy to call a Java method from the C++ code using android_native_app_glue.c by using this method:
jclass clazz = jni->GetObjectClass(app_->activity->clazz);
jmethodID methodID = jni->GetMethodID(clazz, "updateCamera", "(FFF)V");
jni->CallVoidMethod(app_->activity->clazz, methodID, x, y, z);
yet, can I do the reverse in that sample?
Declare a function into java code and that calls the native code. Notice that sample uses "glue"; therefore, the answer is not just these steps:
https://developer.android.com/ndk/samples/sample_hellojni.html
it is different. I see no hooks from java to glue, only from glue to java. I believe glue is running in its own thread.
any leads?
thx!
you could declare a callback in your native code
JNIEXPORT void JNICALL Java_package_Activity_nativeCallback(JNIEnv* jenv, jobject obj);
And then from Java code, just declared as native
native void nativeCallback();
Remember that this execute in main thread, and you should send a command to the background thread to process.
Best regards.
That does not work with "glue". If you look at the sample I mentioned it is different. It uses glue. So I added to the java code:
public native void nativeCallback();
then to native:
extern "C" {
JNIEXPORT void JNICALL Java_com_sample_moreteapots_MoreTeapotsNativeActivity_nativeCallback(JNIEnv *env, jobject obj);
};
JNIEXPORT void JNICALL Java_com_sample_moreteapots_MoreTeapotsNativeActivity_nativeCallback(JNIEnv *env, jobject obj) {
int i = 0;
return;
}
it compiled and linked. But when I tried to invoke the method from Java I get this:
FATAL EXCEPTION: main
Process: com.sample.moreteapots, PID: 31733
java.lang.UnsatisfiedLinkError: No implementation found for void com.sample.moreteapots.MoreTeapotsNativeActivity.nativeCallback()
(tried Java_com_sample_moreteapots_MoreTeapotsNativeActivity_nativeCallback
and Java_com_sample_moreteapots_MoreTeapotsNativeActivity_nativeCallback__)
I have a significant library of classes written in C++. I'm trying to make use of them through some type of bridge within Swift rather than rewrite them as Swift code. The primary motivation is that the C++ code represents a core library that is used on multiple platforms. Effectively, I'm just creating a Swift based UI to allow the core functionality to work under OS X.
There are other questions asking, "How do I call a C++ function from Swift." This is not my question. To bridge to a C++ function, the following works fine:
Define a bridging header through "C"
#ifndef ImageReader_hpp
#define ImageReader_hpp
#ifdef __cplusplus
extern "C" {
#endif
const char *hexdump(char *filename);
const char *imageType(char *filename);
#ifdef __cplusplus
}
#endif
#endif /* ImageReader_hpp */
Swift code can now call functions directly
let type = String.fromCString(imageType(filename))
let dump = String.fromCString(hexdump(filename))
My question is more specific. How can I instantiate and manipulate a C++ Class from within Swift? I can't seem to find anything published on this.
I've worked out a perfectly manageable answer. How clean you'd like this to be is entirely based upon how much work you're willing to do.
First, take your C++ class and create C "wrapper" functions to interface with it. For example, if we have this C++ class:
class MBR {
std::string filename;
public:
MBR (std::string filename);
const char *hexdump();
const char *imageType();
const char *bootCode();
const char *partitions();
private:
bool readFile(unsigned char *buffer, const unsigned int length);
};
We then implement these C++ functions:
#include "MBR.hpp"
using namespace std;
const void * initialize(char *filename)
{
MBR *mbr = new MBR(filename);
return (void *)mbr;
}
const char *hexdump(const void *object)
{
MBR *mbr;
static char retval[2048];
mbr = (MBR *)object;
strcpy(retval, mbr -> hexdump());
return retval;
}
const char *imageType(const void *object)
{
MBR *mbr;
static char retval[256];
mbr = (MBR *)object;
strcpy(retval, mbr -> imageType());
return retval;
}
The bridge header then contains:
#ifndef ImageReader_hpp
#define ImageReader_hpp
#ifdef __cplusplus
extern "C" {
#endif
const void *initialize(char *filename);
const char *hexdump(const void *object);
const char *imageType(const void *object);
#ifdef __cplusplus
}
#endif
#endif /* ImageReader_hpp */
From Swift, we can now instantiate the object and interact with it like so:
let cppObject = UnsafeMutablePointer<Void>(initialize(filename))
let type = String.fromCString(imageType(cppObject))
let dump = String.fromCString(hexdump(cppObject))
self.imageTypeLabel.stringValue = type!
self.dumpDisplay.stringValue = dump!
So, as you can see, the solution (which is actually rather simple) is to create wrappers that will instantiate an object and return a pointer to that object. This can then be passed back into the wrapper functions which can easily treat it as an object conforming to that class and call the member functions.
Making It Cleaner
While this is a fantastic start and proves that it is completely feasible to use existing C++ classes with a trivial bridge, it can be even cleaner.
Cleaning this up would simply mean that we remove the UnsafeMutablePointer<Void> from the middle of our Swift code and encapsulate it into a Swift class. Essentially, we use the same C/C++ wrapper functions but interface them with a Swift class. The Swift class maintains the object reference and essentially just passes all method and attribute reference calls through the bridge to the C++ object!
Having done this, all of the bridging code is completely encapsulated in the Swift class. Even though we are still using a C bridge, we are effectively using C++ objects transparently without having to resort to recoding them in Objective-C or Objective-C++.
Swift has no C++ interop currently. It's a long-term goal, but is very unlikely to happen in the near future.
In addition to your own solution, there is another way to do it. You can call or directly write C++ code in objective-c++.
So you can create an objective-C++ wrapper on top of your C++ code and create a suitable interface.
Then call objective-C++ code from your swift code. To be able to write objective-C++ code you may have to rename file extension from .m to .mm
Do not forget to release memory allocated by your C++ objects when suitable.
You can use Scapix Language Bridge to automatically bridge C++ to Swift (among other languages). Bridge code automatically generated on the fly directly from C++ header files. Here is an example:
C++:
#include <scapix/bridge/object.h>
class contact : public scapix::bridge::object<contact>
{
public:
std::string name();
void send_message(const std::string& msg, std::shared_ptr<contact> from);
void add_tags(const std::vector<std::string>& tags);
void add_friends(std::vector<std::shared_ptr<contact>> friends);
};
Swift:
class ViewController: UIViewController {
func send(friend: Contact) {
let c = Contact()
contact.sendMessage("Hello", friend)
contact.addTags(["a","b","c"])
contact.addFriends([friend])
}
}
As another answer mentioned, using ObjC++ to interact is much easier. Just name your files .mm instead of .m and xcode/clang, gives you access to c++ in that file.
Note that ObjC++ does not support C++ inheritance. I you want to subclass a c++ class in ObjC++, you can't. You will have to write the subclass in C++ and wrap it around an ObjC++ class.
Then use the bridging header you would normally use to call objc from swift.
This question already has answers here:
Calling C++ dll from Java
(3 answers)
Closed 8 years ago.
I have one c++ dll which is previously used for c# application. now we want to use the same dll for java . i know that we can use JNI technology for this but the problem we have to use the same method signature we don't want to change the method singnature. please advise me.
One option is using JNA instead of JNI. It eliminates the need for the boilerplate native code. An example would look something like this...
import com.sun.jna.Library;
import com.sun.jna.Native;
public class Example {
public interface NativeMath extends Library {
public bool isPrime(int x);
}
public static void main(String[] args) {
int x = 83;
NativeMath nm = (NativeMath) Native.loadLibrary("nm", NativeMath.class);
System.out.println(x + " is prime: " + nm.isPrime(x));
}
}
You don't have to change the method signature, you simply add a native method which then calls the native C++ code. Here is a simple example:
public class Someclass
{
public native void thisCallsCMethod(Someparams);
}
Now create the JNI wrappers:
javac Someclass.java
javah Someclass
This will create a Someclass.h, then you create Someclass.cpp and include the .h in it.
At this point all you have to do is write the C/C++ code for thiCallsCMethod
In the .h you'll see a method signature that you have to implement. Something along the lines of:
#include "clibraryHeader.h"
using namespace clibraryNamespace;
JNIEXPORT void JNICALL thisCallsCMethod(JNIEnv *, someparameters)
{
cout<<"Yeah C code is being called"<<endl;
someCfunction();
}
Obviously you have to massage the parameters in the JNI call, but you can create some temporary variables, then copy back the values you get from the C calls into the incoming parameters (if they need to be returned) etc.
Maybe:
#include "clibraryHeader.h"
using namespace clibraryNamespace;
JNIEXPORT void JNICALL thisCallsCMethod(JNIEnv *, someparameters)
{
cout<<"Yeah C code is being called"<<endl;
Cstruct temp;
temp1.somevar = param1.getSomeVal()
someCfunction(temp);
}
I have a command line (+HTTP interface) audio application in C, which currently is being compiled with gcc on Mac OSX, but which I would like to keep this application linux compatible.
However, I would like to use the freeverb3 library. This is in C++. I would prefer not to convert all my code to C++. I don't (as far as I can see) need to call any C code from C++, nor will I need to use C++ objects in my C code. Simple method calls passing arrays of doubles plus a few ints as arguments will be all that I need in terms of interaction from my main application an the C++ code.
From some quick googling, it seems that I can write a C++ interface module, which can then expose some c compatible functions that I can call to make use of freeverb3. I"ve written a micro example to see how this might work. For this example, I have a dummy c++ file called test.cpp:
#include <iostream>
using namespace std;
class test_class
{
int a;
public:
int get_a();
void set_a( int v );
};
int test_class::get_a()
{
return a;
}
void test_class::set_a( int v )
{
a = v;
}
static test_class *c;
extern "C"
{
void init();
void set( int v );
int get();
}
void init()
{
c = new test_class();
}
void set( int v )
{
c->set_a( v );
}
int get()
{
return c->get_a();
}
I have a dummy c file that calls the functions:
#include <stdio.h>
/* Forward declaratoins for extern "C" functions in C++ code */
void init();
int get();
void set( int v );
/* C language code that references functions in C++ code */
int main()
{
init();
set( 55 );
printf( "value: %d\n", get() );
set( get() + 12 );
printf( "value: %d\n", get() );
return 0;
}
And, I have a makefile that creates an executable.
test: test.o user.o
g++ -o test user.o test.o
test.o: test.cpp
g++ -c test.cpp
user.o: user.c
gcc -c user.c
Is this a good way of using C++ code from C? Is there a better/more sophisticated/more traditional way of achieving this aim?
You might want to think about it the other way.
Write your higher level application in C++, invoke the C++ library where you want without complications and call all your current C modules from the C++ level.
IMHO, this is easier to achieve than doing the same with C as high level.
If you intend to use more than one C++ object from C you need to pass an extra instance pointer (this) to the C wrapper functions:
struct A {
A();
~A();
void set(int);
};
The C wrapper:
extern "C"
{
struct A* a_create(void);
void a_destroy(struct A*);
void a_set(struct A*, int);
}
You may also like to catch all C++ exceptions in the C wrapper functions and convert them to error codes.
Pass a pointer to your object instead of using a static variable.
C++ class:
class Foo
{
public:
void doStuff();
};
Common include file:
#ifdef __cplusplus
extern "C"
{
#endif
void Foo_doStuff(void* handle);
void* Foo_create();
void Foo_destroy(void* handle);
#ifdef __cplusplus
}
#endif
Wrapper functions
void Foo_doStuff(void* handle)
{((Foo*)handle)->doStuff();}
void* Foo_create()
{return new(nothrow)Foo;}
void Foo_destroy(void* handle)
{delete (Foo*)handle;}
Not sure whether this goes from C to C++ but it is well worth looking into Swig
Make an extern "C" wrapper in C++, e.g.
// myWrapper.h
#ifdef __cplusplus
extern "C"
{
#endif
void func1(void);
int func2(void);
void func3(char const *str_ptr, size_t len);
#ifdef __cplusplus
}
#endif
// myWrapper.cpp
#include "myWrapper.h"
#include "your_cpp_library.h"
void func3(char const *str_ptr, size_t len)
{
std::string s(str_ptr, str_ptr + len);
call_cpp_function(s);
}
// etc.
In your C code you #include "myWrapper.h" and call those functions. Make sure that:
The code in myWrapper.h stays in the common subset of C and C++
You do not do any cross-boundary resource allocation
The latter might work but it's best to avoid it to be safe. The latter point means that if memory is to be allocated, it must be allocated and freed by the same side; e.g. you can't have the C++ side call malloc and give a pointer to the C side, and then have the C side call free. You have to pass the pointer back to whoever allocated it and let them free it.
Important: as Alf says in a comment, you must have main() in C++ and use the C++ linker , when doing C - C++ inter-linking. This is not a big hurdle though; you can rename your C code's main() function to main2(), and have the C++ code do extern "C" int main2(); and call it.
I'm kinda' new to JNI, but been reading alot about JNI when I wanted to use a legacy dll in my project.
Quick enough, I found out that I can't parameters to native methods. Here's an example that I tried to code with no success:
Hello.java:
package HelloWorld;
Public class Hello {
Private static native int HelloWorld();
Private static native int Mirror(int a);
Static {
System.loadLibrary("Example"); //got path in
vm arguments - works.
}
Public static void main(String[] args) {
Int a = 8;
System.out.println(Mirror(a));
}
Used javah to create header which got me this signature:
JNIEXPORT jint JNICALL Java_HelloWorld_Hello_Mirror (JNIEnv *, jclass, jint);
Wrote a cpp:
Same signature as the h with impl of: "return 1";
That's it and... This is the error I get from eclipse:
Exception in thread "main" java.lang.UnsatisfiedLinkError: HelloWorld/Hello.Mirror(I)I
at HelloWorld.Hello.main (Hello.java:14)
These are my ideas:
A. Saw something about c and cpp, am I mixing things.
B. jdk or stuff?
C. The library loads perfectly (checked the other function that does not get parameters), maybe the types are incompatible?
Stuck on this for a while, Hope you guys can help me!
Solved!
Just needed to add '{' around both functions in the cpp file, after the "extern c" command...