Calling callback function from c++ to objective c - c++

I am using c++ library in my objective c project.
I integrated c++ library and implemented .mm file to bridge c++ and objective c.
I can successfully call c++ function from my objective c using this .mm bridge.
The issue is that methods in given c++ library return's nothing i.e Void.
For example void login( const char* email, const char* password);
This c++ library have call back function implemented to know the result of this login method.
Example:
class DemoApp : public XClass
{
int urandomfd;
public:
uint32_t dstime(void);
FileAccess* newfile();
void request_error(MegaClient*, error);
void login_result(MegaClient*, error);
void users_updated(MegaClient*, User**, int);
void nodes_updated(MegaClient*, Node**, int);
int prepare_download(MegaClient*, Node*);
void share_result(MegaClient*, int, error);
void account_details(MegaClient*, AccountDetails*, int, int, int, int, int, int);
void topen_result(MegaClient*, int, error);
void topen_result(MegaClient*, int, string*, const char*, int);
void transfer_update(MegaClient*, int, off_t, off_t, uint32_t);
void transfer_error(MegaClient*, int, int, int);
void transfer_failed(MegaClient*, int, error);
void transfer_failed(MegaClient*, int, string&, error);
void transfer_limit(MegaClient*, int);
void transfer_complete(MegaClient*, int, chunkmac_map*, const char*);
void transfer_complete(MegaClient*, int, const byte*, const byte*, SymmCipher*);
void changepw_result(MegaClient*, error);
void reload(MegaClient*, const char*);
void notify_retry(MegaClient*, int);
void debug_log(MegaClient*, const char*);
DemoApp();
};
So now my concern is how and when should i call these CALLBACK function's in my objective C library, which look's to me that they are called internally in c++ library.
This is my wrapper.mm file, wrapping c++ methods, need to call in objective c.
-(void) WrapLogin:(NSString*) email :(NSString*) pwd{
self.wrappedModelAccessMega->Login([email UTF8String], [pwd UTF8String]);
//No return as Login mfunction from c++ library returns nothing i.e void
}
I am working on it from a while and already pushed hard to integrate this library to my objective C library now i got stuck to it due to these callback function's.
Please small example showing how should i use callback function of c++, wrap it and call in my objective c to get/know result/return of my login function will do the great job for me.

The Simple answer is:
logic behind writing callback function is that they should get call
internally when response comes from server or certain event happens.
If you want to use this, you need to implement logic let say store
value in variable and return this variable after this callback
function get called. (Not Recommended)
If you want to use this callback function in other platform let say
objective C then bridge this callback function with Delegates. (Recommended)
Thanks to Mr Jaggu who helped me in knowing this.

Related

C++ implemented interface calling wrong virtual overloaded method

I have a problem in which a function call during executing is calling a completely wrong implemented interface function that is overloaded. I call a function passing a bool parameter and the implemeted function actually being called is the one with a float paramater...
Here's my use case, may be a little bit confusing:
I'm writing a game in which a user will write arduino code in a Unreal Engine (UE) widget that will be saved into a .cpp file.
Behind the curtains, usercode.cpp (saved file) will get the user written code and "inject" some useful stuff, making a small code look like this:
#include "IArduino.h"
extern "C"
{
__declspec(dllexport) void setup();
__declspec(dllexport) void loop();
__declspec(dllexport) void InitArduinoPtrs(IArduino*);
};
IArduino* arduinoPtr = nullptr;
void InitArduinoPtrs(IArduino* InArduinoPtr)
{
arduinoPtr = InArduinoPtr;
}
void setup()
{
arduinoPtr->pinMode(true);
}
**Injected code: "IArduino.h", "extern C stuff", "arduinoPtr" and "InitArduinoPtrs()"
I have a interface called "IArduino" that has a function defined as virtual that is overloaded (test only):
class IArduino
{
public:
virtual void pinMode(float) = 0;
virtual void pinMode(bool) = 0;
};
I'm compiling this usercode.cpp as a shared library (usercode.cpp using IArduino.h):
g++ -c -I[IArduino.h_PATH] -Wall -fpic ./usercode.cpp -o ./usercode.o 2>&1
g++ -shared -o ./usercode.so ./usercode.o 2>&1
On my Unreal Engine project, I created a "ArduinoImpl[.h,.cpp]" that implements "IArduino" interface:
class ARDUCOMPILATIONTEST_API ArduinoImpl : public IArduino
{
public:
void pinMode(bool portNumBoolTest);
void pinMode(float portNumTest);
};
At runtime in Unreal Engine, I'm using GetProcAddress() to get setup() and InitArduinoPtrs() functions.
With linked InitArduinoPtrs(), I call it passing the pointer to a new object of "ArduinoImpl()" (that implements IArduino.h):
At another class that runs in runtime:
m_setup_function = (m_setup)FPlatformProcess::GetDllExport(m_dllHandle, TEXT("setup"));
m_init_function = (m_init)FPlatformProcess::GetDllExport(m_dllHandle, TEXT("InitArduinoPtrs"));
ArduinoImpl* arduinoImplPtr = new ArduinoImpl();
if (m_init_function)
m_init_function(arduinoImplPtr);
if (m_setup_function)
m_setup_function();
My problem is, usercode.cpp setup() is run, then:
When the "arduinoPtr->pinMode(true)" is called, it's calling "ArduinoImpl::pinMode(float)" instead of "ArduinoImpl::pinMode(bool)", completely messing up the overloaded call. Moreover, if I try to write "arduinoPtr->pinMode(2.5f)", it calls the bool overload instead of float overload... The same thing happens if I try with different parameters, such as int, string, etc.
Does anybody know why this is happening?
I tried logging the results, such as logging the float I receive when "arduinoPtr->pinMode(true)" is called and I get garbage value (such as 0.5, 512.803, 524288.187500, ...). Trying to log the "bool" value when "arduinoPtr->pinMode(2.5f)" is called, I get "208".
I tried forcing a cast on call like "arduinoPtr->pinMode(static_cast(true))" and it still calls the float param overloaded function.
I tried with different params type and the same thing keeps hapenning.

Cast function pointer to (void*)

I have a simple question which is breaking my mind.
On my solution, I'm working with a DLL that offers me the following function:
int RegisterCallback(TCallbackType CallbackType, void *pLLTProfileCallback, void *pUserData);
For more information, the parameter pLLTProfileCallback is a function type defined as:
typedef void (__stdcall *TNewProfile_s)(const unsigned char *pData,
unsigned int nSize, void *pUserData);
I'm trying to insert my function 'NewProfile' in this parameter as follows:
RegisterCallback(STD_CALL, (void*)NewProfile, m_pLLT1);
But it says: 'Error: invalid type conversion'.
The function definition for 'NewProfile' is:
void __stdcall NewProfile(const unsigned char* pucData, unsigned int uiSize, void* pUserData){...}
Where is my error exactly? What can I do in order to fix it?

Error converting void(__cdecl MyClass::*)() to void *

I am trying to link to an external library in my QT application. The external library has a header file with the following relevant code I'm trying to call:
extern VGRABDEVICE_API bool V_AssignFrameSizeCallback(IGrabChannel* pChannel, void* pFunc);
In the demo C++ program provided, which has no problems compiling, the following relevant code is:
// in main.cpp
void _stdcall MyFrameSizeCallback(T x) {
do_stuff;
}
int main(int argc, char* argv[]) {
IGrabChannel* pChannel0 = something;
V_AssignFrameSizeCallback(pChannel0, MyFrameSizeCallback);
}
I am trying to incorporate this code into my QT application, but getting problems. In my mainwindow.cpp file:
void _stdcall MainWindow::MyFrameSizeCallback(T x) {
do_stuff;
}
void MainWindow::someFunction() {
IGrabChannel* pChannel0 = something;
V_AssignFrameSizeCallback(pChannel0, &MainWindow::MyFrameSizeCallback);
}
The error I'm getting is:
error: C2664: 'bool V_AssignFrameSizeCallback(IGrabChannel *,void *)' :
cannot convert argument 2 from 'void (__cdecl MainWindow::* )(T)' to 'void *'
There is no context in which this conversion is possible
What do I need to do? Thanks.
You have two problems. First, void* is a data pointer, not a function pointer. According to the C++ standard, casting between the two is not expected to work. Some platforms provide a stronger guarantee... for example Windows GetProcAddress and *nix dlsym mix the two.
Next, your &MainWindow::MyFrameSizeCallback is not a function pointer, it is a pointer-to-member-function. Calling it requires a MainWindow object, which the external library doesn't know anything about.
You need to provide an ordinary function, not a member function, to the library. If you have some way to get ahold of the MainWindow* object pointer, you can then call its member function to do the real work. Sometimes the library provides a "context" parameter which is passed to your callback; that's a great place to put the object pointer. Otherwise, you'll need to store your MainWindow* in a global variable. Easy if you have just one, while if you have more than one you might go with std::map<IGrabChannel*, MainWindow*>.
Code:
MainWindow* MainWindow::the_window;
void MainWindow::MyFrameSizeCallback(T x)
{
do_stuff;
}
void _stdcall MyFrameSizeCallbackShim(T x)
{
MainWindow::the_window->MyFrameSizeCallback(x);
}
void MainWindow::someFunction()
{
IGrabChannel* pChannel0 = something;
the_window = this;
V_AssignFrameSizeCallback(pChannel0, &MyFrameSizeCallbackShim);
}
If the parameter x isn't an IGrabChannel, change the map datatype and insertion logic accordingly. If the parameter x isn't some sort of unique predictable identifier, you may be limited to only doing callbacks to one MainWindow instance.

pthread_create argument passing error

Trying to write some simple multithreaded server program and got that error recently:
Server.cpp:64:64: error: argument of type ‘void* (Server::)(void*)’ does not match ‘void* (*)(void*)
Here is some lines from my code:
Header file:
class Server
{
public:
void establishConnection(const char * );
...
private:
void *listening(void *);
void *acceptingConnection(void *);
pthread_attr_t attrr;
}
cpp file:
void Server:: establishConnection(const char *port_number )
{
...
pthread_create(&listn, &attrr, Server::listening, (void*)socketfd);//pthread_t listn, socketfd is a socket destricptor(int)
pthread_join(listn, NULL);
}
void* Server::listening(void *arg)
{
int socketfd = (int)arg;
...
}
Normally, if I define thread function prototypes in the cpp file instead of header file, it works properly(without Server:: definition of course) Tried few other things like (void*)Server::listening, listening, (void*)listening but still didnt work. Could you enlighten me? How to pass the method parameter to listening method?
Secondly, I am learning c++ currently(already know C), is it true to use some C methods, char* arrays instead of strings, header files in the c++ program? Such as string.h, stdlib.h, pthread.h?
You need to create a wrapper function for pthread_create(), and from there call into your class method.
class Server
{
...
private:
int sock;
};
extern "C" void * server_listening (void *arg) {
Server *s = static_cast<Server *>(arg);
return s->listening();
}
void Server:: establishConnection(const char *port_number )
{
...
this->sock = socketfd;
pthread_create(&listn, &attrr, server_listening, this);
pthread_join(listn, NULL);
}
The extern "C" linkage on the wrapper function is in place since pthread_create() is a C function, and expects a function pointer with C linkage. This is important if on your system the C ABI and the C++ ABI are not the same. A static method of a class can only have C++ linkage.
You can just read the error message:
type ‘void* (Server::)(void*)’ does not match ‘void* (*)(void*)‘
Because Server::listening is a non-static member function of Server, and a pointer non-static member function cannot possibly be converted to a pointer-to-non-member-function.
You have to make your Server::listening function static, or write a stand-alone function outside the Server class.

C++ Windows Plugins - Passing Classes

I am working on a plugin system in C++ whereby a C++ executable loads a dll and runs plugin_start(someclass&) via GetProcAddress.
I fully understand how to pass function pointers to the dll, and visa versa, and how the dll may use anything defined in a header file, but I would like the dll to be able to use someclass where someclass is declared in someclass.h BUT DEFINED in someclass.cpp.
The catch is, someclass is compiled into the calling executable which means when the dll tries to call a function it gets a linker error. I even understand why this is, what I don't understand is how to achieve what I want.
I imagine I can pass a pointer to the object, and a pointer to the function ie someclass* somefunction* and then call it as someclass->*somefunction() but this means I would have to pass a pointer to every function in every class.
Is there an easier way to do this, or should I stick to C-style functions and function pointers alone and forget trying to pass entire classes between the two?
Thanks,
Ben
#ifndef EVENTREGISTRAR_H
#define EVENTREGISTRAR_H
#include <vector>
typedef void (__stdcall *error_callback_t)(const char *error);
class EventRegistrar
{
public:
void OnError(error_callback_t fn);
void FireError(const char *error);
private:
std::vector<error_callback_t> errors;
};
#endif
-- Cpp
#include "PluginLoader.h"
void EventRegistrar::OnError(error_callback_t fn)
{
this->errors.push_back(fn);
}
void EventRegistrar::FireError(const char *error)
{
for (std::vector<error_callback_t>::iterator it = this->errors.begin();
it != this->errors.end(); ++it)
{
(*it)(error);
}
}
-- DLL
#include "../plugin.h"
#include <stdio.h>
void __stdcall error(const char *error) { printf("Error: %s\n",error); }
extern "C" int __stdcall plugin_start(plugin_start_data& data)
{
error_callback_t fn = error;
data.events.OnError(fn);
return LOAD_SUCCESS;
}
--Error
Error 1 error LNK2001: unresolved external symbol "public: void __thiscall EventRegistrar::OnError(void (__stdcall*)(char const *))" (?OnError#EventRegistrar##QAEXP6GXPBD#Z#Z) D:\Files\C++ Workspace\BLib\BLib\Example Plugin\main.obj Example Plugin
I did something like this a long time ago. I simply used a straight C interface to keep things simple.
There may be a better way but I think passing a pointer to the object is your best and most straight-forward approach.