Passing Objective-C method to c++ method - c++

I created void type method in Objective-C to pass it to C++ method shown below:
C++ method to which Objectiv-C method will be passed:
glfwSetWindowSizeCallback(m_Window, windowResize);
Here is Objective-C method:
- (void) windowResize:(GLFWwindow *)window :(int)width :(int)height {glViewport(0, 0, width, height);}
I know it can be solved by adding C++ file to the project and linking it to .m file with C++ method, but i would like to implement it in Cocoa syntax

ObjC methods can be passed arround as selectors like
SEL method = #selector(windowResize:width:height:);
glfwSetWindowSizeCallback(m_Window, method);
Then applied inside glfwSetWindowSizeCallback. Alternately you could wrap the ObjC call in a c function and pass the function pointer.
A more complete example might be:
void func(NSApplication * target, SEL method) {
if ([target respondsToSelector: method] ) {
[target performSelector:method];
}
}
elsewhere:
- (void)applicationWillTerminate:(NSNotification *)aNotification {
SEL method = #selector(unhideAllApplications:);
func([NSApplication sharedApplication] , method);
}

Related

Is it possible to create a new jobject of a java listener in JNI?

In Android Studio MainActivity, I write something like
int itemA_num = 0;
int itemB_num = 0;
ABCListener mabclistener = new ABCListenter() {
#Override
public void onEventActivated(CustomResult result) {
//do sth secret e.g.
itemA_num ++;
}
}
ABCobject mabcobject = (ABCobject) findviewById(R.id.abcobject1);
mabcobject.setListener(mabcListener);
I don't want people to decompile my APK and modify the code by amending the value or adding something like this:
ABCListener mabclistener = new ABCListenter() {
#Override
public void onEventActivated(CustomResult result) {
//do sth secret e.g.
itemA_num += 10000; //possibly some general name read by those guys and modified as int1 +=10000;
itemB_num += 500; //possibly some general name read by those guys and added this line int2 +=500;
}
}
So I want to use JNI with Cmake. Inside a .cpp file, I want to create the Class Object, findviewById, setListener and create the ABCListener.
I know using the format
jclass cls = (jclass) env->FindClass("abc/def/GHI");
jmethodID mid = (jmethod) env->GetMethodID(cls, "methodname", "(xxxx)yyy");
jobject obj = (jobject) env->CallObjectMethod(cls, mid, params);
However, if I want to write code about ABCListener and make a jobject of it, I don't know how and where to tell the machine I am going to write some code relating to #Override public void onEventActivated(CustomResult result) { ... }. I also want to add some lines of code inside the response in JNI.
I have found a website "similar" to this question but it is from 2011 and about Runnable. https://community.oracle.com/tech/developers/discussion/2298550/overriding-interface-methods-via-jni
I don't know if it still works in 2021.
First, define a new class on the Java side:
class NativeABCListener implements ABCListener {
#Override public native void onEventActivated(CustomResult result);
}
Next, create an instance of NativeABCListener, either in Java or in native code, and attach it to your mabcobject. You know how to do this so I will not repeat it.
On the native side, you simply define a C++ method with the appropriate name:
JNIEXPORT void JNICALL Java_your_package_NativeABCListener_onEventActivated(JNIEnv *env, jobject thiz, jobject result) {
...
}
If you need multiple ABCListeners that do different things, you can choose to create multiple NativeABCListener classes (each with their own corresponding native function), or you can modify NativeABCListener to store a C++ function pointer in a Java long field. In the ..._onEventActivated function you then extract the field from thiz and call it like a regular functino pointer.

Delegate issue between Objective-C and Swift

I'm just about to get into the basics of Swift, Objective-C & C++. I'm trying to build a bridge between Objective-C & Swift & set up a suitable delegate (MyDelegate).
The code below is working quite fine but I got some problems calling the Swift function callbackInteger() from a static function like:
MyFile.mm:
static void test() {
// how to call callbackInteger?
}
MyFile.mm:
- (void)callbackToSwift:(int)testInteger {
if (self.delegate != nil) {
[self.delegate callbackInteger: testInteger];
}
}
MyDelegate.h:
#protocol MyDelegate <NSObject>
- (void) callbackInteger: (int) testInteger;
#end
ViewController.swift:
class ViewController: UIViewController, MyDelegate {
func callbackInteger(_ testInteger: Int) {
print("testInteger: \(testInteger)");
}
}
Note: I really have no idea how to achieve a call to the callbackInteger function using the delegate call.
A protocol is nothing more that a set of requirements (methods) that a class has to implement. We say that a class conforms to a protocol.
So in your static function test(), you can't call the method of the protocol if you don't have an instance/object around (here a ViewController). A working way (but not necessary a beautiful one) would be to store somewhere (as a global variable for example) an instance of ViewController in order to reuse it in the function.
Something like this :
// Top of your file
#import <Foundation/Foundation.h>
// other headers...
id<MyDelegate> globalDelegate;
static void test() {
[globalDelegate callbackInteger:42];
}
// rest of your file
There are plenty of resources about protocols and the delegation pattern like this guide from Apple. Read carefully how they use it in Cocoa & Cocoa Touch.

How to access Swift-objects from a c++ class?

I want to change the properties of some objects (Labels, Buttons..), I created using the Storyboard out of c++-code. So I need a way of running ViewController-class-internal methods.
Is there any proper way to do this? Is there another possibility?
I've tried using callbacks, but there is always this barrier between global and internal in the ViewController-class. Thanks in advance!
EDIT:
Since I don't know how to access a swift class out of c++ code, i cannot give any proper examples, but I thought of something like this (pseudo code):
In c++:
int main(){
say_hello();
}
and in Swift:
class ViewController: NSViewController {
#IBOutlet weak var label: NSTextField!
func say_hello(){
label.stringValue = "Hello"
}
}
Here is an oversimplified example of how this could be done using an Objective-C++ wrapper, as suggested by Richard. Memory management and thread safety aspects, and many other things, are not addressed here. In this example there is a 1-to-1 relationship between Swift and C++ class instances. Also, Swift object pointers are used as identifiers to decide which Swift object should receive a notification. This is kind of dangerous, see comments in the code below. Using more sophisticated data structures in the Objective-C++ wrapper to maintain a connection between Swift and C++ objects, one could easily work around this danger and support relationships other than 1-to-1.
First of all, here is a C++ class that triggers changes in Swift code:
typedef void (*cb_t)(const char *, void *);
class MyClassCPP {
public:
MyClassCPP(cb_t callBack, void * p) : myCallBack(callBack), clientPtr(p) {}
void doWork(); // perform some work and invoke the callback
private:
cb_t myCallBack;
void * clientPtr;
};
void MyClassCPP::doWork() {
myCallBack("C++ code at work...", clientPtr);
}
Here is an Objective-C++ wrapper interface that should be made visible to Swift code via the bridging header, directly or indirectly. Please note that it does not reference any C++ types.
#class SwiftClass; // forward declaration
// can't include *-Swift.h in a header
#interface OCWrapper : NSObject
-(instancetype)init:(SwiftClass * )sc;
-(void)requestWorkFromCPP;
#end
And here is the wrapper implementation. It does reference C++ types. We cannot provide a Swift global function as a callback to C++ code, but we can provide an Objective-C++ global function for this purpose.
// Extension that deals with C++ specifics that can't be visible to Swift
#interface OCWrapper ()
{
MyClassCPP * myClassCPP;
}
#end
void callBack(const char * msg, void * swiftClient)
{
// Danger: what if swiftClient does not point to a SwiftClass instance?
[(__bridge SwiftClass*)swiftClient sayHello:
[[NSString alloc] initWithBytes: msg length:strlen(msg)
encoding:NSASCIIStringEncoding]];
}
#implementation OCWrapper
-(instancetype)init:(SwiftClass * )sc
{
myClassCPP = new MyClassCPP(callBack, (__bridge void*)sc);
return self;
}
-(void)requestWorkFromCPP{
myClassCPP->doWork();
}
#end
The above should be in an Objective-C++ file. Create an Objective-C file and then rename it to have the .mm extension. You will also need to include the *-Swift.h header, so Objective-C++ can use Swift types.
Finally, here is some Swift code that uses the C++ code via the Objective-C++ wrapper:
// This is like your Swift view controller
class SwiftClass : NSObject
{
var label = "[Empty]"
var name : String;
init(name : String) {
self.name = name
}
func sayHello(greeting : String) {
label = "SwiftClass named " + name + " received greeting: " + greeting
}
}
...
let sc = SwiftClass( name : "Zero")
let ocWrapper = OCWrapper(sc)
let sc1 = SwiftClass( name : "One" )
let ocWrapper1 = OCWrapper(sc1)
ocWrapper1.requestWorkFromCPP()
print("The label value from C++: \(sc1.label)")
ocWrapper.requestWorkFromCPP()
print("The label value from C++: \(sc.label)")
...

Implementing C++ -to-lua observer pattern?

I have an observer (or "listener") pattern implemented in my code as such:
struct EntityListener
{
public:
virtual void entityModified(Entity& e) = 0;
};
class Entity
{
public:
Entity();
void setListener(EntityListener* listener);
private:
EntityListener* m_listener;
};
Now, this works in C++; the Entity class calls the entityModified() method whenever it needs. Now, I'd like to transfer some of the functionality to Lua, and among those function points is this listener callback. The entities are now created from the Lua scripts. The question is, how do I achieve the listener functionality in Lua?
For example, the Lua script currently does something like this:
function initializeEntity()
-- The entity object is actually created in C++ by the helper
Entity = Helper.createEntity()
-- Here I'd like to hook a Lua function as the Entity's listener
end
One possible solution is to have a LuaListener class in your C++ code that contains a "pointer" to the Lua function, and a Lua-specific setListener function that is called from the Lua script that takes a Lua function as argument, and creates a LuaListener instance and passes that to the actual C++ setListener.
So the Lua code would look something like
function onModified(entity)
-- ...
end
function initializeEntity()
entity = Helper.createEntity()
entity.setListener(onModified)
end
And the C++ code would look something like (pseudoish-code only):
class LuaListener : public EntityListener
{
private:
lua_State* state;
std::string funcName;
public:
void entityModified(Entity& e)
{
// Call function `funcName` in `state`, passing `e` as argument
}
};
class LuaEntity : public Entity
{
public:
void setListenerLua(state, funcName, ...)
{
Entity::setListener(new LuaListener(state, funcName, ...));
}
};

Call back on JNI

How can I register call back on JNI from android app? My requirement is, I want to make a JNI call from Android application and want to register a call back, so that I can get call back on java application from JNI.
Thanks
First, check out Swig. It wraps C++ in Java and also has a "director" fcility that makes it easier to call C++ methods from Java.
With raw JINI, you cannot do this directly. Although the RegisterNatives() call can be made to bind a native method, it cannot be changed. If you want to call a C function by pointer, you will need to do this in two steps. I am glossing over a lot, because JNI is incredibly verbose and tedious. The basic trick is, wrap the C function pointer in a java long.
First declare a java class:
public class Callback {
public Callback(long cMethodPointer) { this.cMethod = cMethod; }
public void doCallback() { callCMethod(cMethod); }
public static native void callCMethod(long cMethod);
public long cMethod;
}
Run javah on that class file, and you'll get a stub header generated that looks like:
JNIEXPORT void JNICALL Java_Callback_callCMethod
(JNIEnv *, jclass, jlong);
Implement that method in a DLL/so:
typedef void (*FP)();
JNIEXPORT void JNICALL Java_Callback_callCMethod
(JNIEnv *, jclass, jlong pointer) {
((FP)(void*)pointer)();
}
and call System.loadLibrary() on that DLL/so in your Java main() method.
Finally, from your C/C++ code, you will need to create an instance of the Callback object via JNI, and pass the pointer to an actual method to it:
void MyFunction() { ... }
void Register() {
jclass cls = env->FindClass("Callback");
jmethodID mid = env->GetMethodID(cls, "<init>", "(J)V");
jvalue arg;
arg.j = (jlong)(void*)MyFunction;
jobject callback = env->NewObjectA(confCls, mid, &arg);
}
So this gives you a brand new Callback object that points to your C function! But then, how do you do anything with that? Well, you have to pass the Callback object to Java via JNI (step omitted), so that your Java code has the Callback object from which to call your C method:
public class Foo {
public Callback callback;
public void doSomeStuff() {
...
callback.doCallback();
}
}