i need to register to a callback function provided by a third party dll, this function does not accept any arguments, and hence i cannot pass in the "this" to it. here the pData is the just the data.
//This is declared as static function in my class
void CMyClass::ThirdPartyCallBack(void *pData)
{
//How to access the member variables of the class
}
how to do this without using a global variable, appreciate you attention and time
A void* is a pointer to whatever you like. You can pass anything you like as the data pointer to the dll, for example "this". And in your callback, you convert it back to an object pointer.
You can create a table of context pointers that is associated with a table of 'thunks' that are used as the callback function(s) you give to the DLL:
class foo {
public:
void callback(void* data);
};
enum {
kMAX_CALLBACKS = 3,
};
foo* context_table [kMAX_CALLBACKS] = {
0,
0,
0
// however many you might need...
};
extern "C" void callback_0( void* data)
{
foo* ctx = context_table[0];
ctx->callback(data);
}
extern "C" void callback_1( void* data)
{
foo* ctx = context_table[1];
ctx->callback(data);
}
extern "C" void callback_2( void* data)
{
foo* ctx = context_table[2];
ctx->callback(data);
}
// ....
extern "C" {
typedef void (*dll_callback)(void*);
}
dll_callback callback_table[kMAX_CALLBACKS] = {
callback_0,
callback_1,
callback_2
// however many you might need...
};
dll_callback set_callback_context(foo* ctx)
{
for (int i =0; i < kMAX_CALLBACKS; ++i) {
if (context_table[i] == 0) {
context_table[i] = ctx;
return callback_table[i];
}
}
return 0;
}
void clear_callback_context(foo* ctx)
{
for (int i =0; i < kMAX_CALLBACKS; ++i) {
if (context_table[i] == ctx) {
context_table[i] = 0;
return;
}
}
}
Now when you need to set up a callback to foo::callback() pass the DLLs function that sets up the callback with something like:
third_party_set_callback( set_callback_context(foo_instance_ptr));
and the callback will end up at foo:callback() with the appropriate this pointer.
Related
I am currently developing a library in C++ (Mainly because dependent libraries have C++ interfaces). I created a proof-of-concept implementation with C++ interfaces for quick development. The library has to mandatorily provide C interface for it. The C++ interface is good to have but can be modified/removed if it gets in the way of the C interface.
The C++ API right now looks something like this:
typedef struct {
// only basic C data types like int,float.
int a;
float b;
} Object;
typedef struct {
std::vector<Object> objects;
} GroupOfObjects;
typedef struct {
std::vector<GroupOfObjects> groups;
} Result;
typedef struct {
// some basic C data types
int init1;
int init2;
float init3;
// some C++ types which I can possibly replace with something compatible with C
std::string init4;
std::vector<std::string> init5;
} MyClassInitParams;
struct IMyClass {
public:
virtual bool initialize(MyClassInitParams ¶ms) = 0;
virtual bool getResult(Result &result) = 0;
//Other public methods, constructor, virtual destructor
}
// Actual implementation of the above interface
class MyClass : IMyClass {
}
IMyClass *createMyClassInstance();
I have come up with this C interface till now:
extern "C" {
typedef struct MyClass *MyClassHandle;
// A C version of the above MyClassInitParams
typedef struct{
} MyClassInitParams_C;
typedef struct {
Object * objects;
int numObjects;
} GroupOfObjects_C;
// A C version of the above Result structure
typedef struct{
GroupOfObjects_C *groups;
int numGroups;
}Result_C;
MyClassHandle MyClass_Create();
MyClass_Destroy(MyClassHandle handle);
int MyClass_Initialize(MyClassHandle handle, MyClassInitParams_C *params);
int MyClass_GetResult(MyClassHandle handle , Result_C *result);
void MyClass_FreeResult(Result_C *result);
} // end of extern "C"
Implementation of the C interface:
MyClassHandle MyClass_Create()
{
return createMyClassInstance();
}
MyClass_Destroy(MyClassHandle handle)
{
delete handle;
}
int MyClass_Initialize(MyClassHandle handle, MyClassInitParams_C *params)
{
MyClassInitParam params_cpp;
// fill params_cpp using the params structure
return handle->initialize (params_cpp);
}
int MyClass_GetResult(MyClassHandle handle , Result_C *result)
{
Result result_cpp;
bool ret = handle->getResult(result_cpp);
if (!ret)
return 0;
// Fill the C structure using the cpp structure
result->numGroups = result_cpp.groups.size();
result->groups = new GroupOfObjects_C[result->numGroups];
for (int i = 0; i < result->numGroups; i++) {
result->groups[i].numObjects = result_cpp.groups[i].objects.size();
result->groups[i].objects = new Object[result->groups[i].numObjects];
for (int j = 0; j < result->groups[i].numObjects; j++) {
result->groups[i].objects[j] = result_cpp.groups[i].objects[j];
}
}
return 1;
}
void MyClass_FreeResult(Result_C *result) {
// free all the arrays allocated in the above function
}
I have a few questions regarding this:
The GetResult method has a overhead of copying the objects from C++ vectors to the C arrays. Is there a more elegant and efficient way to handle this?
I will have to maintain the structures for both C and C++. Should I just use the C versions of the MyClassInitParams and Result structures in C++ interface? This will also help with (1).
If I use the solution in (2), does it make sense to even have the C++ interface? Or are there any advantages of keeping both the C and C++ interfaces in this case?
I'd suggest to return Result* from C MyClass_GetResult method, like int MyClass_GetResult(MyClassHandle handle, Result_C **result) or Result_C* MyClass_GetResult(MyClassHandle handle). Then, add accessors for groups and objects.
It's up to you to decide, but I'd rather to use one or the other, but not both.
First of all, I'd suggest to decide what language and its features (C or C++) you're going to use in order to implement your business logic. Next, another language becomes nothing more than a wrapper over logic implemented in another language. Again, if you use functions for accessing actual underlying data you'll get rid of copying this data, as you did in MyClass_GetResult method.
Here's an example
struct Object {
int a;
float b;
};
struct GroupOfObjects;
struct Result;
struct MyClass;
#ifdef __cplusplus
#include <vector>
struct GroupOfObjects {
std::vector<Object> objects;
};
struct Result {
std::vector<GroupOfObjects> groups;
};
struct MyClass {
private:
public:
Result getResult() { /*...*/ }
MyClass(int init1, int init2, float init3, const std::string& init4, const std::vector<std::string>& init5);
}
#endif
#ifdef __cplusplus
extern "C" {
#endif __cplusplus
struct Object* GroupOfObjects_GetObject(struct GroupOfObjects* g, size_t i)
/* { return &g.objects[i]; } */ // commented sections must be in cpp file, not in this header
size_t GroupOfObjects_GetCount(struct GroupOfObjects* g)
/* { return g.objects.size(); } */
struct GroupOfObjects* Result_GetGroup(struct Result* r, size_t i)
/* { return &r.groups[i]; } */
size_t Result_GetGroupCount(struct Result* r)
/* { return g.groups.size(); } */
MyClass *CreateMyClassInstance(int init1, int init2, float init3, const char* init4, const char** init5)
/* {
try {
std::vector<std::string> init5_v;
while (init5 != nullptr)
init5_v.push_back(std::string(*init5++));
return new MyClass(init1, init2, init3, std::string(init4), init5_v);
}
catch (...) {
return nullptr;
}
} */
void FreeMyClassInstance(struct MyClass* mc)
/* { delete mc; } */
Result* MyClass_GetResult(struct MyClass* mc)
/* {
Result *result = nullptr;
try {
result = new Result;
*result = mc->GetResult();
return result;
}
catch (...) {
delete result;
return nullptr;
}
} */
void FreeResult(struct Result* r)
/* { delete r; } */
#ifdef __cplusplus
} // end of extern "C"
#endif
I am trying to create a dynamic function pointer that points to some methods all the methods I want to save on the array return a bool and have an uint32_t parameter. The functions are Service functions. These are intended to be dynamic, so when a class is started, the constructor links the service function from the object to be called from outside the object.
With the code below I am getting the following error:
Build error: ISO C++ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to member function.
I have no clue what to do to overcome this problem, any idea would be greatly appreciated, thanks!
//File 1
typedef bool (*ServiceFunctionsType)(uint32_t);
//File 2
#include "File1.hpp"
extern uint8_t ServiceFunctions_size;
extern ServiceFunctionsType *ServiceFunctions;
void Service_Functions_Setup();
bool SetPtr(ServiceFunctionsType a);
void ClearPtr(uint8_t id);
//File 3
#include "File1.hpp"
ServiceFunctionsType *ServiceFunctions;
uint8_t ServiceFunctions_size = 0;
//File 4
#include "File2.hpp"
#include <stdlib.h>
void Service_Functions_Setup()
{
ServiceFunctions = NULL;
if(SERVICE_FUNCTION_POINTER_START_SIZE != 0)
{
ServiceFunctions_size = SERVICE_FUNCTION_POINTER_START_SIZE;
ServiceFunctions = (ServiceFunctionsType*)malloc(sizeof(ServiceFunctionsType)*SERVICE_FUNCTION_POINTER_START_SIZE);
for(uint8_t i = 0; i < SERVICE_FUNCTION_POINTER_START_SIZE; i++)
{
ServiceFunctions[i] = NULL;
}
}
}
uint8_t SetServiceFunctionPointer(ServiceFunctionsType a, bool _realloc)
{
if( ServiceFunctions == NULL )
{
ServiceFunctions = (ServiceFunctionsType*)malloc(sizeof(ServiceFunctionsType));
ServiceFunctions[0] = a;
return 0;
}
for(uint8_t i = 0; i < ServiceFunctions_size; i++)
{
if( ServiceFunctions[i] == NULL )
{
ServiceFunctions[i] = a;
return i;
}
}
if(_realloc)
{
ServiceFunctions_size++;
ServiceFunctions = (ServiceFunctionsType*)realloc(ServiceFunctions,sizeof(ServiceFunctionsType)*ServiceFunctions_size);
ServiceFunctions[ServiceFunctions_size - 1] = a;
return ServiceFunctions_size - 1;
}
return INVALID_SERVICE_FUNCTION_POINTER;
}
void ClearServiceFunctionPointer(uint8_t id)
{
ServiceFunctions[id] = NULL;
}
//File 5
class MonoStepSequencer
{
public:
MonoStepSequencer();
~MonoStepSequencer();
uint8_t ServicePointerID;
bool Service(uint32_t time);
private:
};
//File 6
#include "File2.hpp"
MonoStepSequencer::MonoStepSequencer()
{
ServicePointerID = SetServiceFunctionPointer(&this -> Service);
}
//This is the function to be called with a pointer
bool MonoStepSequencer::Service(uint32_t time)
{
//Some Code
}
You can try, to use lambdas. Create method like
std::function<void()> getService()
Where inside you can use:
return [this](){
Service();
};
Also if your methods should use arguments, you can use this method, but add arguments into return value and lambda.
One more, you can create lambda outside of class methods, like:
[&object]()
{
object.Service();
}
In this way, better to use std::shared_ptr to guŠ°rantee that object exists, when lambda called.
this -> Service is an unqualified or parenthesized non-static member function
You probably meant :: instead of -> Also, you need a type on the left, not a variable.
Also, please don't put spaces around ->. That makes it look like you're specifying a trailing return type or something.
I'm busy with making a leveleditor class in an engine but I'm stuck at passing a member function as parameter of another member function.
First I've made a typedef
typedef void (LevelEditor::*CallFunctionPtr)();
Then I have made a member function to check if the user clicks with his mouse on a hitregion. If so, another function needs to be called. So I've my first member function with 2 parameters
LevelEditor.h
void CheckClickCollision(HitRegion* region, CallFunctionPtr callFunctionPtr);
LevelEditor.cpp
void LevelEditor::CheckClickCollision( HitRegion* region, CallFunctionPtr callFunctionPtr)
{
if(GAME_ENGINE->GetLButtonMouseState())
{
if(!m_bIsLeftPressed && region->HitTest(m_MousePosition))
(this->*callFunction)();
m_bIsLeftPressed = true;
}
else
m_bIsLeftPressed = false;
}
Then I've two stupid example member functions:
LevelEditor.h
void LevelUp();
void LevelDown();
LevelEditor.cpp
void LevelEditor::LevelUp()
{
++m_iCurrentLevel;
}
void LevelEditor::LevelDown()
{
if(m_iCurrentLevel > 0)
--m_iCurrentLevel;
else
return;
}
And now I want to call that function every tick to check if there is a hit. So in my tick function:
CheckClickCollision(m_LeftArrowRegionPtr, LevelDown);
CheckClickCollision(m_RightArrowRegionPtr, LevelUp);
And here I get the error on LevelDown and Levelup:
Error: argument of type void (LevelEditor::*)()" is incompatible with parameter of type "CallFunctionPtr *"
Dont know how to fix it. Tried different things, nothing worked
Try
CheckClickCollision(m_LeftArrowRegionPtr, &LevelEditor::LevelDown);
CheckClickCollision(m_RightArrowRegionPtr, &LevelEditor::LevelUp);
For your convenience, here's the working sample (the compiler is GCC 4.7):
#include <stdio.h>
class LevelEditor;
typedef void (LevelEditor::*CallFunctionPtr)();
class LevelEditor
{
public:
LevelEditor() {}
void CheckClickCollision(void* region, CallFunctionPtr callFunction)
{
(this->*callFunction)();
}
void LevelUp() { printf("up\n"); }
void LevelDown() { printf("down\n"); }
void Test()
{
CheckClickCollision(NULL, &LevelEditor::LevelDown);
CheckClickCollision(NULL, &LevelEditor::LevelUp);
}
};
int main()
{
LevelEditor e;
e.Test();
return 0;
}
The other way to call this:
void Test()
{
CallFunctionPtr p;
p = &LevelEditor::LevelDown;
CheckClickCollision(NULL, p);
p = &LevelEditor::LevelUp;
CheckClickCollision(NULL, p);
}
You need to use std::function and std::bind, or lambdas if you have a supporting compiler.
void LevelEditor::CheckClickCollision( HitRegion* region, std::function<void()> callFunction)
{
if(GAME_ENGINE->GetLButtonMouseState())
{
if(!m_bIsLeftPressed && region->HitTest(m_MousePosition))
callFunction();
m_bIsLeftPressed = true;
}
else
m_bIsLeftPressed = false;
}
void Test()
{
// lambda
CheckClickCollision(NULL, [this] { LevelDown(); });
// bind
CheckClickCollision(NULL, std::bind(&LevelEditor::LevelDown, this));
}
I have an error compiling this code:
template <class T> class purple_multitimer {
public:
typedef struct _timerinfo timerinfo, *ptimerinfo;
typedef gboolean (T::*multitimer_callback) (ptimerinfo pti);
typedef struct _timerinfo {
guint id;
multitimer_callback cb;
T * pthis;
purple_multitimer<T> * pmt;
} timerinfo, *ptimerinfo;
purple_multitimer() {
memset(m_ti, 0, sizeof(m_ti));
}
~purple_multitimer() {
stop();
}
void start(multitimer_callback mt_cb, T * pthis, guint timeout = 10) {
ptimerinfo pti = ti_get();
assert(pti);
pti->pthis = pthis;
pti->pmt = this;
pti->cb = mt_cb;
pti->id = purple_timeout_add_seconds(timeout, GSourceFunc(timeout_cb), pti);
}
void stop(multitimer_callback mt_cb = NULL) {
for (register guint n = 0; n < sizeof(m_ti)/sizeof(timerinfo); ++ n)
if (m_ti[n].cb == mt_cb) {
purple_timeout_remove(m_ti[n].id);
ti_zero(n);
}
}
private:
timerinfo m_ti[32];
inline ptimerinfo ti_get(guint n) {
return &m_ti[n];
}
inline ptimerinfo ti_get() {
for (register guint n = 0; n < sizeof(m_ti)/sizeof(timerinfo); ++ n)
if (m_ti[n].id == 0) return &m_ti[n];
return NULL;
}
inline ptimerinfo ti_zero(ptimerinfo pti) {
memset(pti, 0, sizeof(timerinfo));
return pti;
}
inline ptimerinfo ti_zero(guint n) {
memset(&m_ti[n], 0, sizeof(timerinfo));
return &m_ti[n];
}
static gboolean timeout_cb(ptimerinfo pti) {
gboolean res = (pti->pthis->*(pti->cb))(pti);
if (!res) pti->pmt->stop(pti->cb);
return res;
}
};
class _ctrl {
public:
purple_multitimer<_ctrl> pmt;
gboolean on_tomeout (purple_multitimer<_ctrl>::ptimerinfo pti) {
return false;
};
void on_connected(PurpleConnection *gc) {
pmt.start(purple_multitimer<_ctrl>::multitimer_callback(&_ctrl::on_tomeout), this);
}
void on_disconnected(PurpleConnection *gc) {
}
} controller;
When compiling this code got error:
[Error] E:\dnc-imexchange\dnc-imexchange.cpp:117: error: no matching function for call to `purple_multitimer<_ctrl>::start(gboolean (_ctrl::*)(_timerinfo*), _ctrl* const)'
[Warning] E:\dnc-imexchange\dnc-imexchange.cpp:52: note: candidates are: void purple_multitimer<T>::start(gboolean (T::*)(_timerinfo*), T*, guint) [with T = _ctrl]
I need to implement callbacks in such way.
If you want some good quality callbacks (able to call multiple functions at once, suitable for observer pattern), may I suggest boost::signals2.
If you just want to call one function as a callback you can use std::function:
void Foo(const std::function<bool (const int)> &callback)
{
const int number = 4;
if (callback(number))
{
std::cout << "Callback returned true!" << std::endl;
}
else
{
std::cout << "Callback returned false!" << std::endl;
}
}
// Use this if you have C++11
void CallFooLambda()
{
const auto lambda = [](const int number) -> bool
{
return number % 2;
};
Foo(lambda);
}
// Else use these functions
bool FooCallback(const int number)
{
return number % 2;
}
void CallFoo()
{
Foo(&FooCallback);
}
The _ctrl is a const pointer, and the function you try to call require a non-const ptr-to _ctrl (pthis).
Can you define pthis as follows?
T *pthis const
That should make your code match the 'candidate' in the error message.
this is a pointer that you can't change.
Boost.Function is a good toolkit for simplifying callback syntax and implementation.
The Boost.Function library contains a
family of class templates that are
function object wrappers. The notion
is similar to a generalized callback.
It shares features with function
pointers in that both define a call
interface (e.g., a function taking two
integer arguments and returning a
floating-point value) through which
some implementation can be called, and
the implementation that is invoked may
change throughout the course of the
program.
Generally, any place in which a
function pointer would be used to
defer a call or make a callback,
Boost.Function can be used instead to
allow the user greater flexibility in
the implementation of the target.
Targets can be any 'compatible'
function object (or function pointer),
meaning that the arguments to the
interface designated by Boost.Function
can be converted to the arguments of
the target function object.
I wanted to call Test1() Method Within WaitAndCallFunc() Function.
Code:
typedef void (*func)();
void StartTimer(void* pFuncAddr);
void WaitAndCallFunc(void* pPtr);
void WaitAndCallFunc(void* pPtr)
{
int i = 0;
int nWaitTime = 3;
while(1)
{
Sleep(1000);
// I want pPtr to call Test1 Function;
if(i == nWaitTime)
break;
}
_endthread();
}
void StartTimer(void* pFuncAddr)
{
_beginthread(WaitAndCallFunc, 0, pFuncAddr);
}
void Test1();
int main(int argc, char* argv[])
{
StartTimer(Test1);
Sleep(5000);
return 0;
}
void Test1()
{
cout << "Testing Thread\n";
}
I'm not sure I understand what your question is exactly, but try this:
((func)pPtr)();
Cast and call:
typedef void (*func)();
void WaitAndCallFunc(void* pPtr)
{
int i = 0;
int nWaitTime = 3;
while(1)
{
Sleep(1000);
func f=(func)pPtr; // cast to correct pointer to function type
f(); // and call!
if(i == nWaitTime)
break;
}
_endthread();
}
Strictly in C you're not supposed to convert between function pointers and other types of pointers. It's not guaranteed to work how you expect.
So a more pedantically correct version would look something like:
struct hook {
void (*func)();
};
void StartTimer(void* pFuncAddr);
void WaitAndCallFunc(void* pPtr);
void WaitAndCallFunc(void* pPtr)
{
struct hook *hook_ptr = pPtr;
hook_ptr->func();
_endthread();
}
void StartTimer(void* pFuncAddr)
{
_beginthread(WaitAndCallFunc, 0, pFuncAddr);
}
void Test1();
int main(int argc, char* argv[])
{
struct hook hook_test1 = { &Test1 };
StartTimer(&hook_test1);
Sleep(5000);
return 0;
}
Note that in this it's the struct pointer that's cast to and from void *, not the function pointer itself. This also has the advantage that you can stuff some more values into the struct, if you need them to be passed down to Test1().
Actually, converting a function pointer to a void* or a void* to a function pointer is not directly allowed in current C or C++ - even though most compilers compile it.
There are two ways to convert back and forth (using C syntax) on compilers that don't compile the direct cast:
Method 1 (convert first to an integral intermediary)
((func) (intptr_t) pPtr)(); // call the void*
StartTimer( (void*) (intptr_t) &Test1); // pass function pointer to void*
Method 2 (use void**)
func f = 0;
*((void**)&f) = pPtr;
f();
StartTimer( *((void**) &Test1)); // pass function pointer to void*
You can refer to the following thread for more of an explanation: Function pointers casting in C++