Calling C++ method with callback from ObjectiveC - c++

I need to call a C++ method and pass in a callback method as a parameter... from ObjectiveC method...
This callback method would then be triggered multiple times in ObjectiveC... as it's a callback... and so then I need to trap that ObjectiveC callback method back as it will be called as a closure from Swift code...
This is the C++ Method Signature
static bool cPlusPlusMethodWithCallBack(const std::string& someText, void (*someCallback)(unsigned int) = NULL, unsigned int someNum = 0);
My Question is what should be the Block syntax of this Callback Method declared in ObjectiveC (in .mm and .h) which can then be passed as a parameter to this someCallback in C++
I am a Swift developer so bit stuck on ObjectiveC... Many Thanks

You can't pass an Objective-C block (or a Swift closure) as a function pointer argument like that. You'll need to create a separate, standalone function, and pass that in as the callback.
void MyCallback(unsigned int value)
{
// ...do something...
}
And in your main code:
cPlusPlusMethodWithCallBack("something", MyCallback);
Now, the downside of this is that in your callback, you'll often need to reference a particular Objective-C object in order to properly handle the callback. If that's something you need with this particular callback, you'll need to save it off somewhere as a static variable so that it can be accessed from the MyCallback function.
Alternatively, if you have control over the cPlusPlusMethodWithCallBack source code, you can update it to take a void * "reference" parameter, and then supply that parameter as an argument when you call the callback:
static void cPlusPlusMethodWithCallback(void (*callback)(void *ref), void *ref)
{
// ...really time consuming processing...
callback(ref);
}
Then, update your callback function:
void MyCallback(void *ref)
{
ObjectiveCObject *obj = (ObjectiveCObject *)ref;
[obj doSomething];
}
And when you initially call the method, just pass in the object you need as the reference parameter:
cPlusPlusMethodWithCallback(MyCallback, myObjectiveCObject);

Related

How can I use UpdateData func in controlling function (UINT) in MFC App?

I'm creating a multi-threading program with MFC using controlling function is UINT.
Now I want to update GUI using UpdateData(FALSE), but visual studio 2022 say that
- a nonstatic member reference must be relative to a specific object
- CWnd::UpdateData': illegal call of non-static member function
Here is my UINT code:
UINT MyThreadProc(LPVOID Param) {
CFolderPickerDialog m_dlg;
m_dlg.m_ofn.lpstrTitle = _T("Select Folder To Scan");
m_dlg.m_ofn.lpstrInitialDir = _T("C:\\");
if (m_dlg.DoModal() == IDOK) {
m_Path = m_dlg.GetPathName();
m_Path += _T("\\");
CWnd::UpdateData(FALSE);
}
}
void CMultithreadDlg::OnBnClickedButtonBrowse(){
AfxBeginThread(MyThreadProc,this);
UpdateData(FALSE);
GetDlgItem(IDC_BUTTON_Browse)->EnableWindow(FALSE);
GetDlgItem(IDC_EDIT_PATH)->EnableWindow(FALSE);
}
How can I fix this, thanks
Let's consider that CFolderPickerDialog was just an example, and get back to the core of the question.
Your compiler told you that the way you call UpdateData()
CWnd::UpdateData(FALSE);
is specifying a call to a static function UpdateData() of the class CWnd, and that doesn't exists.
You need to call that function on a specific instance of CWnd. Luckily - you have it! You pass your this pointer to that thread function:
AfxBeginThread(MyThreadProc,this);
So inside that function you can safely cast LPVOID Param (that you are not using currently) to a pointer to CWnd or CMultithreadDlg. Then you will be able to call any non-static functions via that pointer.

How do I convert V8 objects to pointers?

I'm writing a Node application (in TS) that needs to be interfaced with some native library.
I have a library (written in C) - let's consider it's a blackbox - and I'm writing a wrapper using NAN. The library native interface can be simplified into a following functions:
typedef void (*got_message_reply_cb)(context ctx, void * priv, struct X * the_reply);
context lib_connect();
bool lib_send_message(context ctx, message msg, got_message_reply_cb callback, void * priv);
I believe this is pretty straight-forward to understand.
So, I'm trying to wrap that black-box native library into something like:
class TheLibrary : public Nan::ObjectWrap {
Initialize(v8::Handle<v8::Object> target);
SendMessage(...)
}
And then to javascript object like:
class TheLibrary {
SendMessage(message: whatever, callback: (reply) => void); // or return promise, doesn't matter
}
How to do the actual handling of the callback in the NAN C++ module? I need to somehow pass the callback (represented probably by Local<Function> - which have, if I understand it correctly, limited scope) as a pointer to the function and then retrieve it back. How to do that? Thanks for your replies.
The high level answer is that you don't pass the JS callback function directly, but pass in a pointer to a function that somehow has your JS callback as a context value (in your example the priv parameter).
So for your case you write something like this:
void TheLibraryCallback(context ctx, void *instance, struct X *the_reply) {
((TheLibrary*)instance)->callback(ctx, the_reply);
}
In your TheLibrary you add a method void callback(context ctx, struct X * the_reply) that handles the callback. You call your library like this: lib_send_message(ctx, msg, TheLibraryCallback, this); with this being a TheLibrary instance.
So how do you call back the JS callback in your callback method? With nan you will have to make sure you are back in the main thread. There are examples out there, but I would suggest that you use the new N-API instead. The AsyncWorker helps with the boilerplate that you need to do to call the callback in the main thread.

Storing Lua callback functions

I have a game I am integrating with Lua scripting in order to allow customization.
I am using a C++ Lua wrapper:
https://github.com/tomaka/luawrapper
In my Lua script I am calling something like this:
function sprite_factory()
local sprite = sprite_new() -- register_new_sprite(name)
sprite:RegisterCallback("on_activate", function ()
sprite:SetState("closed")
end)
end
In my C++ code I have built a Sprite class and I'm using registerFunction to make the member methods available to Lua e.g. RegisterCallback is called on the sprite object returned by sprite_new()
bool RegisterCallback(const std::string hook, const std::function<void()> callback) {
callback();
mCallback = callback;
return true;
}
If I do the callback inside the RegisterCallback method, it works fine. However, I want to store the callback to be used as a raised event.
When I call this method later in my code:
void DoCallback() {
mCallback(); //raises exception
}
I get an exception:
libc++abi.dylib: terminating with uncaught exception of type
std::__1::bad_function_call: std::exception
I am declaring mCallback as a private:
std::function<void()> mCallback = NULL;
I'm not sure what is going on here.
I would suspect that there is an issue with the way mCallback is declared.

C++ Passing a member function as a callback

I am trying to create a very simple event system to be used in a game. I have a EventManager class that looks something like this:
typedef std::function<void(IEvent* event)> CallbackType;
class EventManager
{
public:
void AddListener(const std::string eventName, IEventListener* listener)
{
CallbackType callback = std::bind(&IEventListener::HandleEvent, listener, std::placeholders::_1);
listeners[eventName].push_back(callback);
}
void AddListener(const std::string eventName, CallbackType callback)
{
// ...
}
void TriggerEvent(IEvent* event)
{
for (CallbackType callback : listeners[event->GetName()])
{
callback(event);
}
}
private:
std::map<std::string, std::vector<CallbackType>> listeners;
}
The 1st AddListener function works perfectly. The TriggerEvent function calls the HandleEvent function, which is implemented by each class that extends my IEventListener interface.
I would really like to be able to pass a callback to the 2nd AddListener function. This callback would then get called in the TriggerEvent function as before. I can pass in a callback constructed using std::bind and this works. For example:
eventManager->AddListener("WindowResize", std::bind(&MyClass::MemberFunction, this, std::placeholders::_1));
where MyClass extends the IEventListener interface. However, I'd really like to be able to just pass a simple function pointer instead:
eventManager->AddListener("WindowResize", this, &MyClass::MemberFunction);
Is this possible?
Edit
For anyone interested, I wrote a couple of macros that I think makes things a little cleaner.
#define MEMBER_CALLBACK(funPtr) \
std::bind(&funPtr, this, std::placeholders::_1)
#define MEMBER_CALLBACK_WITH_INSTANCE(funPtr, instancePtr) \
std::bind(&funPtr, instancePtr, std::placeholders::_1)
Now I can subscribe to an event by:
eventManager->AddListener("EventName", MEMBER_CALLBACK(MyClass::MemberFunction));
You can't pass a simple function pointer because MyClass::MemberFunction isn't a simple function. The std::bind() works because it associates an instance of MyClass with the reference to the member function. Without that information, the member function would not have access to the instance's data.

How do I pass an OpenGL context from Qt4?

I'm currently developing a game in the LeadWerks 2 engine and I've decided to use Qt4 as the GUI and window manager. What I want to do is create a Qt QGLWidget window and have the LeadWerks engine run inside of that.
There is some information of building a basic QGLWidget application here.
I'm really struggling to understand how to do this exactly. I can create a custom GL buffer within the LeadWerks engine and I believe what I need to do is give that buffer the GL context Qt created.
As for the LeadWerks side of things, the main thing I need to do is call a method called CreateCustomBuffer and pass it a few things:
virtual void Buffer::CreateCustom( byte* getsize, byte* makecurrent)
Creates and returns a new custom buffer. GetSize (defined as void _stdcall GetSize(int* width, int* height)) and MakeCurrent (defined as void _stdcall MakeCurrent(void)) are callback functions for the buffer. GetSize should return (by changing the value provided with a pointer) the size of the custum OpenGL buffer/context used. MakeCurrent should set the custom buffer as the current OpenGL context.
and MakeCurrent (defined as void _stdcall MakeCurrent(void)) are callback functions for the buffer
If I understand it correct, this callback will be called whenever LeadWerks wants the context to become active (it doesn't manage it itself then), similar the getsize callback is to obtain the size of the available window. So normally you'd use this to activate the context from another interface you've access for.
Unfortunately those callbacks don't allow for passing a pointer, which means, you can't pass the QGLWidget class instance pointer, so that you could delegate the call to a class member function. Not being able to pass user data to callbacks is a sign of bad API design, because it makes things hard, which would be easy otherwise.
There is a library called ffcall which provides a mechanism to get around this http://www.gnu.org/s/libffcall/callback.html
So you'd write a delegator function
void qglwidget_makecurrent(void *data, va_list alist)
{
GQLWidget *widget = (QGLWidget*) data;
widget->makeCurrent();
}
void qglwidget_getsize(void *data, va_list alist)
{
int *widthptr, *heightptr;
GQLWidget *widget = (QGLWidget*) data;
va_start_ptr(alist, void);
widthptr = va_arg_ptr(alist, int*);
heightptr = va_arg_ptr(alist, int*);
va_return_void(alist);
*widthptr = widget->width();
*heightptr = widget->height();
}
create callback wrappers (as in your QGLWidget derives class' constructor) as class member variables:
class MyGLWidget : QGLWidget {
/* ... */
__TR_function qglwidget_makecurrent_callback;
__TR_function qglwidget_getsize_callback;
}
MyGLWidget::MyGLWidget() {
qglwidget_makecurrent_callback = alloc_callback(qglwidget_makecurrent, (void)this);
qglwidget_getsize_callback = alloc_callback(qglwidget_makecurrent, (void*)this);
}
And those you can pass to LeadEngine:
buffer->CreateCustom((void(*)(int, int))qglwidget_getsize_callback, (void(*)(void))qglwidget_makecurrent_callback);