Reputation: 317
I have an old .dll with plain C interface which takes callbacks to invoke when some work is done. The callback it takes is of type void (f*)(char* arg)
.
I'm looking for a trick to pass a C++ function object there so that the callback is invoked with "this" pointer stored somewhere, something like bind, but simple bind doesn't work
To illustrate this: C interface:
typedef void (f*)(char* param) Callback;
void registerCallback(Callback c);
Usage in C++:
class A
{
void func1()
{
registerCallback(std::bind(&A::func2, _1, this)); // obviously doens't work
}
void func2(char* param)
{ ... }
};
Upvotes: 5
Views: 2122
Reputation: 206567
The only way that to make this work with an instance of a class and a member function of the class, that I am aware of, is:
class A
{
void func1();
void func2(char* param)
{ ... }
};
// Global pointer
A* aPtr = NULL;
// Non-member function.
// extern "C" is probably needed if the older DLL is expecting
// an unmangled C function pointer.
extern "C" void globalFunc2(char* param)
{
if ( aPtr == NULL )
{
// Deal with error
}
else
{
aPtr->func2(param);
}
}
void A::func1()
{
aPtr = this;
registerCallback(globalFunc2);
}
Upvotes: 3
Reputation: 84
Maybe I'm not understanding the problem but why not just build a simple wrapper to hold the "this" pointer. So, the application will use this callback (or lambda)
void RegisterCallback_withthis(char* arg, void* thisptr)
Only a single callback function can be registered with the DLL at one time. So, a single global thisptr is good.
static void* thisptr;
void RegisterCallback(char* arg)
{
RegisterCallback_withthis(argc, thisptr);
}
The application will have to setup the thisptr while registering the callback.
thisptr = this;
Upvotes: 0
Reputation: 148880
This is simply an alternative to @RSahu's solution using static members in A
class. IMHO, is is functionnally the same as global variables, but at least you get a namespace containment in you class:
class A
{
static A* current_obj;
public:
void func1()
{
current_obj = this;
registerCallback(func3);
}
private:
void func2(char* param)
{ ... }
static void func3(char *param) {
if (NULL == current_obj) {
// error ...
}
current_obj->func2(param);
}
...
};
And as demonstrated above, the registered functions can be private to the class, because the only function that need to be called externally is here func1
.
But it suffers the same problem: you can register only one object at the same time.
Upvotes: 0
Reputation: 1006
The way I see it, the core of the problem is letting the caller of the callback function (the entity registerCallback
is registering with) know which A
object's func2
to call.
As far as I can understand from your problem, you basically have a bunch of A
objects and you only want a number of these A
objects to execute their respective func2
s when the callback event occurs. However, the caller of the callback function does not know who to call when the callback event occurs. Since you mentioned that it's an old .dll, I assume we cannot just go in and change how registerCallback
works, but we need to store the A
objects that are registered for callback.
Therefore,
class Informer {
public:
static void InformAllMembers(char* param) {
for(auto& a : m_Members) { //Inform all As registered with me
a->func2(param);
}
}
static void Register(A* a) {
m_Members.push_back(a);
}
private:
static std::vector<A*> m_Members;
};
std::vector<A*> Informer::m_Members;
...
registerCallback(Informer::InformAllMembers);
A a;
Informer::Register(&a);
NOTE: You will have to handle cases where some of the registered A
objects are destroyed and unregister them from the Informer
.
Upvotes: 1