I'm new to ffi. But I successfully used dart-ffi with functions call.
Now, I'd like to use a C++ object in dart ffi. I don't know if it is possible, but I tried like this.
The prototypes of constructor call are :
function_dart = lib
.lookup<NativeFunction<function_native>>("constructor_function")
.asFunction();
But I've got :
Failed to lookup symbol <constructor_function>, where I tried constructor function with :
constructor_function
class::constructor_function
class::constructor_function(args)
I did nm -gDC <lib>, and I can see the constructor.
Help !
edit 1 : #Botje, #Richard-Heap
I'm trying to use the VideoCapture instance from OpenCV.
I have followed the instructions from Botje's answer.
So I created a lib, like this :
bind.hpp :
#ifndef BIND_HPP
# define BIND_HPP
#include <opencv2/videoio.hpp>
extern "C" {
cv::VideoCapture *cvCreateVideoCapture(char *filename, int apiPreference);
}
#endif
bind.cpp :
#include "bind.hpp"
cv::VideoCapture *createVideoCapture(char *filename, int apiPreference) {
return new cv::VideoCapture(filename, apiPreference);
}
The commands I use to compile :
g++ -c bind.cpp -lopencv -o bind.o
g++ bind.o -shared -o bind.so
I get : dart: symbol lookup error: ./lib/src/bind.so: undefined symbol: _ZN2cv12VideoCaptureC1ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEi
Next step, is to use a method of VideoCapture instance.
Thank you
Dart ffi uses a C interface, so you have to adapt as follows.
Start with C++ class
Rect::Rect(int32_t width, int32_t height) {
m_width = width;
m_height = height;
}
void Rect::setWidth(int32_t width) {
m_width = width;
}
void Rect::setHeight(int32_t height) {
m_height = height;
}
int32_t Rect::area() {
return m_width * m_height;
}
create a C adapter header
EXTERNC void* rect_init(int32_t width, int32_t height);
EXTERNC void rect_destroy(void *ptr);
EXTERNC int32_t rect_area(void *ptr);
and implementation
void* rect_init(int32_t width, int32_t height){
return new Rect(width, height);
}
void rect_destroy(void *ptr){
auto typed_ptr = static_cast<Rect*>(ptr);
delete typed_ptr;
}
int32_t rect_area(void *ptr){
auto typed_ptr = static_cast<Rect*>(ptr);
return typed_ptr->area();
}
in Dart, create the typedefs
typedef example_init_rect = Pointer<Void> Function(Int32 w, Int32 h);
typedef ExampleInitRect = Pointer<Void> Function(int w, int h);
typedef example_free_rect = Void Function(Pointer<Void> p);
typedef ExampleFreeRect = void Function(Pointer<Void> p);
typedef example_area_rect = Int32 Function(Pointer<Void> p);
typedef ExampleAreaRect = int Function(Pointer<Void> p);
and bind the C adapter functions. Finally, you could create a Dart class that proxies the underlying C++ class.
class NativeRect {
Pointer<Void> _nativeInstance;
NativeRect(int width, int height) {
_nativeInstance = Example()._exInitRect(width, height);
}
void free() {
Example()._exFreeRect(_nativeInstance);
}
int get area => Example()._exAreaRect(_nativeInstance);
}
C++ compilers use "name mangling" to ensure symbol names are unique. The fact that you had to add the -C option (or --demangle) to make it show up is a hint.
For example, here is the mangled symbol for some_class::some_class(int, std::string):
_ZN10some_classC2EiNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
You will need to pass the mangled name (not the demangled name) in order to call the constructor. You will also need to match the ABI for an object (ie have a pointer to the object's memory in the correct register). Sometimes this is simply a hidden first argument to the constructor, but not in all ABIs.
If at all possible, write a C++ wrapper function that constructs the object for you and tag it with extern "C" so you don't have to jump through these hoops.
For example:
extern "C"
some_class* create_some_class(int x, const char * some_text) {
return new some_class(x, some_text);
}
You can now simply call create_some_class from Dart with basic types and you will get back a pointer to the constructed C++ object.
If you intend to wrap a large API like this, consider migrating to something like SWIG that can auto-generate these wrappers.
Related
I'm new to ffi. But I successfully used dart-ffi with functions call.
Now, I'd like to use a C++ object in dart ffi. I don't know if it is possible, but I tried like this.
The prototypes of constructor call are :
function_dart = lib
.lookup<NativeFunction<function_native>>("constructor_function")
.asFunction();
But I've got :
Failed to lookup symbol <constructor_function>, where I tried constructor function with :
constructor_function
class::constructor_function
class::constructor_function(args)
I did nm -gDC <lib>, and I can see the constructor.
Help !
edit 1 : #Botje, #Richard-Heap
I'm trying to use the VideoCapture instance from OpenCV.
I have followed the instructions from Botje's answer.
So I created a lib, like this :
bind.hpp :
#ifndef BIND_HPP
# define BIND_HPP
#include <opencv2/videoio.hpp>
extern "C" {
cv::VideoCapture *cvCreateVideoCapture(char *filename, int apiPreference);
}
#endif
bind.cpp :
#include "bind.hpp"
cv::VideoCapture *createVideoCapture(char *filename, int apiPreference) {
return new cv::VideoCapture(filename, apiPreference);
}
The commands I use to compile :
g++ -c bind.cpp -lopencv -o bind.o
g++ bind.o -shared -o bind.so
I get : dart: symbol lookup error: ./lib/src/bind.so: undefined symbol: _ZN2cv12VideoCaptureC1ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEi
Next step, is to use a method of VideoCapture instance.
Thank you
Dart ffi uses a C interface, so you have to adapt as follows.
Start with C++ class
Rect::Rect(int32_t width, int32_t height) {
m_width = width;
m_height = height;
}
void Rect::setWidth(int32_t width) {
m_width = width;
}
void Rect::setHeight(int32_t height) {
m_height = height;
}
int32_t Rect::area() {
return m_width * m_height;
}
create a C adapter header
EXTERNC void* rect_init(int32_t width, int32_t height);
EXTERNC void rect_destroy(void *ptr);
EXTERNC int32_t rect_area(void *ptr);
and implementation
void* rect_init(int32_t width, int32_t height){
return new Rect(width, height);
}
void rect_destroy(void *ptr){
auto typed_ptr = static_cast<Rect*>(ptr);
delete typed_ptr;
}
int32_t rect_area(void *ptr){
auto typed_ptr = static_cast<Rect*>(ptr);
return typed_ptr->area();
}
in Dart, create the typedefs
typedef example_init_rect = Pointer<Void> Function(Int32 w, Int32 h);
typedef ExampleInitRect = Pointer<Void> Function(int w, int h);
typedef example_free_rect = Void Function(Pointer<Void> p);
typedef ExampleFreeRect = void Function(Pointer<Void> p);
typedef example_area_rect = Int32 Function(Pointer<Void> p);
typedef ExampleAreaRect = int Function(Pointer<Void> p);
and bind the C adapter functions. Finally, you could create a Dart class that proxies the underlying C++ class.
class NativeRect {
Pointer<Void> _nativeInstance;
NativeRect(int width, int height) {
_nativeInstance = Example()._exInitRect(width, height);
}
void free() {
Example()._exFreeRect(_nativeInstance);
}
int get area => Example()._exAreaRect(_nativeInstance);
}
C++ compilers use "name mangling" to ensure symbol names are unique. The fact that you had to add the -C option (or --demangle) to make it show up is a hint.
For example, here is the mangled symbol for some_class::some_class(int, std::string):
_ZN10some_classC2EiNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
You will need to pass the mangled name (not the demangled name) in order to call the constructor. You will also need to match the ABI for an object (ie have a pointer to the object's memory in the correct register). Sometimes this is simply a hidden first argument to the constructor, but not in all ABIs.
If at all possible, write a C++ wrapper function that constructs the object for you and tag it with extern "C" so you don't have to jump through these hoops.
For example:
extern "C"
some_class* create_some_class(int x, const char * some_text) {
return new some_class(x, some_text);
}
You can now simply call create_some_class from Dart with basic types and you will get back a pointer to the constructed C++ object.
If you intend to wrap a large API like this, consider migrating to something like SWIG that can auto-generate these wrappers.
This question already has answers here:
Use class member functions as callbacks?
(6 answers)
Closed 3 years ago.
Arduino's attachInterrupt requires a callback function of type void(*)(), but I'd like to pass it a member function instead. I can't use a C++ member function here because of its implicit this argument.
Background
I know it's possible to use C++ member functions as callbacks. For example, FreeRTOS' xTaskCreate(...) takes a callback function of type void(*)(*).
isocpp.org has a nice FAQ on the use of member functions as callbacks.
In this related question user thiton writes:
Most sane callback libraries allow you to pass this void* argument to the functions as a way to have user-defined data in it
Perhaps the Arduino library is not "sane?" or perhaps this is design decision made to simplify the Arduino API?
it's there... inside attachInterrupt
I'm programming for an ESP32. In the arduino-esp32 implementation of attachInterrupt, there's a function called __attachInterruptFunctionalArg(...) that seems to do exactly what I want, but since it's not part of the Arduino API, I'm hesitant to include it in a project that's for public consumption because it may break.
Example program
// An attempt to summarize https://github.com/pierremolinaro/acan2517/issues/4
#include <stdio.h>
#include <stdint.h>
#include <functional>
#define IRAM_ATTR __attribute__((section(".iram1")))
// from `esp32-hal-gpio.c`
typedef void (*voidFuncPtrArg)(void*);
extern void __attachInterruptFunctionalArg(uint8_t pin, voidFuncPtrArg userFunc, void * arg, int intr_type, bool functional);
// from Arduino `FunctionalInterrupt.cpp`
void attachInterrupt(uint8_t pin, std::function<void(void)> intRoutine, int mode);
void IRAM_ATTR interruptFunctional(void* arg);
// from Arduino `FunctionalInterrupt.h`
struct InterruptArgStructure {
std::function<void(void)> interruptFunction;
};
// from ACAN2517
class ACAN2517
{
public: ACAN2517 (const int interrupt_pin);
public: void begin (void (* inInterruptServiceRoutine) (void));
public: void begin_functional (void (* inInterruptServiceRoutine) (void *), void *);
public: void isr(void);
private: const int interrupt_pin;
};
ACAN2517::ACAN2517 (const int interrupt_pin):
interrupt_pin(interrupt_pin)
{};
#define FALLING 0
// This won't work with a member function
void ACAN2517::begin (void (* inInterruptServiceRoutine) (void)) {
attachInterrupt(interrupt_pin, inInterruptServiceRoutine, FALLING);
}
// This will, but is prone to breakage when the Arduino internals change
void ACAN2517::begin_functional (void (* inInterruptServiceRoutine) (void *), void *arg)
{
__attachInterruptFunctionalArg(interrupt_pin, inInterruptServiceRoutine, arg, FALLING, true);
}
void ACAN2517::isr(void)
{
printf("fhtagn");
}
//===
// User code begin
//===
#define N_DRIVERS 3
ACAN2517 g_driver(23); // Initializing a driver instance statically
ACAN2517 *drivers[N_DRIVERS];
void call_ACAN_isr(void *arg)
{
ACAN2517 *driver = (ACAN2517 *)arg;
driver->isr();
}
int main()
{
g_driver.begin( []{g_driver.isr();} ); // No problem
for (int i = 0; i < N_DRIVERS; i++)
{
drivers[i] = &ACAN2517(i);
drivers[i]->begin( []{drivers[i]->isr();} );
// ERROR
// static void lambda []void ()->void::_FUN()
// an enclosing-function local variable cannot be referenced in a lambda body unless it is in the capture list
}
for (int i = 0; i < N_DRIVERS; i++)
{
drivers[i] = &ACAN2517(i);
drivers[i]->begin( [i]{drivers[i]->isr();} );
// ERROR
// no suitable conversion function from "lambda []void ()->void" to "void (*)()" exists
}
for (int i = 0; i < N_DRIVERS; i++)
{
drivers[i] = &ACAN2517(i);
ACAN2517 *driver = drivers[i];
drivers[i]->begin_functional( [driver]{driver->isr();}, driver);
// Not sure how to get this to work in a lambda...
}
for (int i = 0; i < N_DRIVERS; i++)
{
drivers[i] = &ACAN2517(i);
ACAN2517 *driver = drivers[i];
drivers[i]->begin_functional( call_ACAN_isr, driver);
// OK
}
}
//===
// User code end
//===
// from esp32-hal-gpio.c
extern void __attachInterruptFunctionalArg(uint8_t pin, voidFuncPtrArg userFunc, void * arg, int intr_type, bool functional)
{
// ...
}
// from Arduino `FunctionalInterrupt.cpp`
void attachInterrupt(uint8_t pin, std::function<void(void)> intRoutine, int mode)
{
// use the local interrupt routine which takes the ArgStructure as argument
__attachInterruptFunctionalArg (pin, (voidFuncPtrArg)interruptFunctional, new InterruptArgStructure{intRoutine}, mode, true);
}
void IRAM_ATTR interruptFunctional(void* arg)
{
InterruptArgStructure* localArg = (InterruptArgStructure*)arg;
if (localArg->interruptFunction)
{
localArg->interruptFunction();
}
}
I can't use a C++ member function here because of its implicit this argument.
Yes, that is exactly the problem and this can't be solved without extra code, if your API did not provide something what lets you store some additional data like the this pointer.
What you simply can do is:
Write your own wrapper and register the callback to the original handler. But that creates another indirection which increases the latency.
The other way is not as simple, but a bit less slow:
Write your own interrupt handler and callback registration. As you have the original sources of the arduino libs, you simply can replace the stuff around the attachInterrupt function.
Sorry, but there is no magic way to generate a data store for this without any additional software.
I have two classes, and this is the header of one of them:
#ifndef WRAPPER_HPP
#define WRAPPER_HPP
#include <SDL/SDL.h>
using namespace std;
class Wrapper
{
private:
//SDL_Surface *screen;
public:
static SDL_Surface *screen;
static void set_screen(SDL_Surface *_screen);
static void set_pixel(int x, int y, Uint8 color);
static void clear_screen(int r, int g, int b);
static SDL_Surface* load_image(char path[500]);
static void draw_image(SDL_Surface *img, int x, int y, int width, int height);
static void draw_line(int x1, int y1, int x2, int y2, Uint8 color);
};
#endif
I am calling Wrapper::set_screen(screen) from another file and I get this error:
In file included from /home/david/src/aships/src/Wrapper.cpp:6:0:
/home/david/src/aships/src/Wrapper.hpp: In static member function ‘static void Wrapper::set_screen(SDL_Surface*)’:
/home/david/src/aships/src/Wrapper.hpp:11:18: error: invalid use of member ‘Wrapper::screen’ in static member function
/home/david/src/aships/src/Wrapper.cpp:10:3: error: from this location
I also get a similar error for the definition of every single function on Wrapper.cpp, for example:
void Wrapper::set_pixel(int x, int y, Uint8 color)
{
/* Draws a pixel on the screen at (x, y) with color 'color' */
Uint8 *p;
p = (Uint8 *) screen->pixels + y * screen->pitch + x * screen->format->BytesPerPixel;
*p = color;
}
On compile:
/home/david/src/aships/src/Wrapper.hpp: In static member function ‘static void Wrapper::set_pixel(int, int, Uint8)’:
/home/david/src/aships/src/Wrapper.hpp:11:18: error: invalid use of member ‘Wrapper::screen’ in static member function
/home/david/src/aships/src/Wrapper.cpp:17:17: error: from this location
I know it's related to the class being static and thus the variable Wrapper.screen is not accessible or something, but I'm not sure of how to fix it. Any ideas?
You are using a static variable
static SDL_Surface *screen;
in your code.
In C++ when you declare a static variable in the .h (or .hpp) you are creating a variable that is general (static) to the class. Thus, to use it in another file you have to redeclare it (which I'm guessing you didn't) to create a variable in that file referencing the static one. In your case put this:
SDL_Surface* Wrapper::screen;
in the .cpp file.
I'm not sure the theory is well explained, but it works like that.
Your class and member (screen) are not static, which means they don't actually exist.
You can't access a non static member in a static function.
Try to make your data members to be static.
I'm not convinced that the code abstract you show us is an accurate characterization of your problem.
Your header should not include using namespace std; — it doesn't use or declare anything from the std namespace, and specifying using namespace std; is generally regarded as 'not a good idea', doubly so when it appears in a header file.
It also isn't clear that your header needs to include SDL/SDL.h. If the Uint8 type is easily isolated (not necessarily valid), then your header file can simply use a forward declaration of the SDL_Surface class. (Your implementation code will need to include SDL/SDL.h; but you should not burden the users of your wrapper class with unnecessary #include directives when simple forward declarations would suffice.)
This code is self-contained (does not need any headers), but more or less simulates what you could use, and it compiles OK:
#ifndef WRAPPER_HPP
#define WRAPPER_HPP
typedef unsigned char Uint8;
class SDL_Surface;
class Wrapper
{
public:
static SDL_Surface *screen;
static void set_screen(SDL_Surface *_screen);
static void set_pixel(int x, int y, Uint8 color);
static void clear_screen(int r, int g, int b);
static SDL_Surface *load_image(char path[500]);
static void draw_image(SDL_Surface *img, int x, int y, int width, int height);
static void draw_line(int x1, int y1, int x2, int y2, Uint8 color);
};
#endif
//#include <SDL/SDL.h>
typedef unsigned short Uint16;
class SDL_Surface
{
public:
Uint8 *pixels;
Uint16 pitch;
struct
{
Uint8 BytesPerPixel;
} *format;
};
// End of SDL/SDL.h
void Wrapper::set_pixel(int x, int y, Uint8 color)
{
/* Draws a pixel on the screen at (x, y) with color 'color' */
Uint8 *p;
p = (Uint8 *) screen->pixels + y * screen->pitch + x * screen->format->BytesPerPixel;
*p = color;
}
It also compiles without warnings. The (Uint8 *) cast (copied from the original) is unnecessary. With the class definition given, it is superfluous; if you are needing to use a cast because the type of the pixels member of SDL_Surface actually isn't Uint8, are you sure it is a good idea? And can't you use reinterpret_cast<Uint8>(screen->pixels) instead to make it clearer?
Can you reduce your problem to code analogous to this that still shows the actual error?
I'm trying to get the address of a class static data member from a DLL and keep it around in host code. However, I'm loosing the pointer / reference to the member the minute I exit the method in the dll-manager which opens all the (Windows typedef) HINSTANCE s, even though I'm keeping them open.
My setup is:
A Qt GUI application, which includes a class that loads plugins from dlls. This dll-manager class doesn't use Qt stuff but for Qdir and Qstrings here and there...
The dll-manager should issue a bunch of LoadLibrary() calls to open DLLs and for each, call an exported function which returns the address of a static "info" struct inside the class the DLL exports.
For instance, The DLL class looks like this:
BlackNWhite.h
#ifdef BLACKNWHITE_EXPORTS
#define BLACKNWHITE_API __declspec(dllexport)
#else
#define BLACKNWHITE_API __declspec(dllimport)
#endif
// This class is exported from the BlackNWhite.dll
class BLACKNWHITE_API CBlackNWhite : PCOperatorBase
{
public:
CBlackNWhite(void);
virtual ~CBlackNWhite(void);
virtual int process(int* inBuffer, int* outBuffer, int bufferSize);
void getParametersInfo(const std::vector<ParameterDescriptor>*& outParameters);
static const OperatorInfo& info();
protected:
static OperatorInfo operatorInfo;
};
extern "C" __declspec(dllexport) PCOperatorBase* getOperatorInstance();
extern "C" __declspec(dllexport) const PCOperatorBase::OperatorInfo& getOperatorInfo();
BlackNWhite.cpp
#include "stdafx.h"
#include "BlackNWhite.h"
PCOperatorBase::OperatorInfo CBlackNWhite::operatorInfo = {L"Black N White", L"modifier", L"color"};
const PCOperatorBase::OperatorInfo& CBlackNWhite::info()
{
return CBlackNWhite::operatorInfo;
}
extern "C" __declspec(dllexport) PCOperatorBase* getOperatorInstance()
{
return (PCOperatorBase*)(new CBlackNWhite());
}
extern "C" __declspec(dllexport) const PCOperatorBase::OperatorInfo& getOperatorInfo()
{
return CBlackNWhite::info();
}
CBlackNWhite::CBlackNWhite()
: PCOperatorBase()
{
ParameterDescriptor newParameter;
newParameter.label = L"Parameter 1";
parameters.push_back(newParameter);
}
CBlackNWhite::~CBlackNWhite()
{
}
int CBlackNWhite::process(int* inBuffer, int* outBuffer, int bufferSize)
{
while(bufferSize--)
*outBuffer++ = *inBuffer++;
return 0;
}
void CBlackNWhite::getParametersInfo(const std::vector<ParameterDescriptor>*& outParameters)
{
outParameters = ¶meters;
}
And this class inherits from a base class:
PCOperatorBase.h
#pragma once
#include "PCOperatorParameters.h"
#include <vector>
class PCOperatorBase
{
public:
typedef struct OperatorInfo
{
wchar_t* name;
wchar_t* type;
wchar_t* subtype;
} OperatorInfo;
PCOperatorBase(void){};
virtual ~PCOperatorBase(void){};
virtual void getParametersInfo(const std::vector<ParameterDescriptor>*& outParameters) = 0;
virtual int process(int* inBuffer, int* outBuffer, int bufferSize) = 0;
protected:
std::vector<ParameterDescriptor>parameters;
};
And the DLL-manager has two relevant methods. One builds the list of available plugins and the other one just returns the string names of the plugins.
void PCOperatorManager::buildOperatorList(const QString path)
{
QDir operatorDirectory(QDir::currentPath() + path);
if(operatorList.size())
operatorList.clear();
QStringList operatorNameList = operatorDirectory.entryList(QStringList("*.dll"));
typedef PCOperatorBase::OperatorInfo*(*PCOClassInfoFunction)();
for(QStringList::iterator PCOClassName = operatorNameList.begin();
PCOClassName != operatorNameList.end();
PCOClassName++)
{
HINSTANCE PCOClassHandle;
if((PCOClassHandle = LoadLibrary((operatorDirectory.absolutePath() + "/"+ *PCOClassName).toStdWString().c_str())))
{
OperatorDescriptor newPCOClassDescriptor;
newPCOClassDescriptor.handle = PCOClassHandle;
newPCOClassDescriptor.info = (*((PCOClassInfoFunction)GetProcAddress(PCOClassHandle, "getOperatorInfo")))();
operatorList.push_back(newPCOClassDescriptor);
printf("\n we have: %ls", operatorList[0].info->name);
}
}
}
QStringList PCOperatorManager::getOperatorNameList()
{
QStringList operatorNameList;
printf("\n the list length is: %i", operatorList.size());
for(int i = 0; i < operatorList.size(); i++)
printf("\n we have again: %ls", operatorList[0].info->name);
//operatorNameList << QString::fromWCharArray((*PCOClass).info.name);
return operatorNameList;
}
What's happening is: inside buildOperatorList() I can access the static member of the DLL-class and assign it to the info member in the OperatorDescriptor struct. That is, the "test" printf statement that reads "we have" does print out the right value for that field.
However, inside getOperatorNameList() the info member is not valid anymore.
My line of thought is that what I'm doing is:
I have a pointer to a OperatorInfo struct, called info.
I get the address of a static OperatorInfo struct in the DLL-class,
called operatorInfo.
I assign the address of the class' operatorInfo to the pointer
called info. That is info = &CBlackNWhite::operatorInfo;
At this point, the pointer should stay valid as long as I don't issue a FreeLibrary() on the DLL HINSTANCE
So what's going on?
I see here operatorList is not a member variable of PCOperatorManager once it is added and constructed as in buildOperatorList I think you should ave access in getOperatorNameList()
I am using Microsoft Visual Studio 2010 and the OpenCV 2.3.0 libraries to write up an application for image processing.
I have a piece of code that is erroneous for me and I am not sure how to fix it. I am implementing an application where there will be 2 or 3 windows open at the same time and I want each one of them to be assigned with a different CvMouseCallback function. I want all these CvMouseCallback functions to be in a different class together with another function that returns a pointer to one of these functions according to what the user selects.
My Window.h contains this piece of code.
class Window
{
public:
... // constructors and destructors
void setMouseHandler( CvMouseCallback mouseHandler );
private:
... // other stuff
};
and Window.cpp
#include "stdafx.h"
void Window::setMouseHandler( CvMouseCallback mouseHandler )
{
cvSetMouseCallback( win, mouseHandler, NULL );
}
Now, the MouseHandler.h file
class MouseHandler
{
public:
...
CvMouseCallback selectHandler( int option );
void __cdecl selectROI( int event, int x, int y, int flags, void *param );
private:
Image *in;
Window *win;
void ( CV_CDECL MouseHandler::*callback )( int event, int x, int y, int flags, void *param );
};
and lastly, in MouseHandler.cpp I contain
void __cdecl MouseHandler::selectROI( int event, int x, int y, int flags, void *param )
{
//do something
}
CvMouseCallback MouseHandler::selectHandler( int option )
{
callback = (MouseHandler::selectROI);
return callback;
}
The last bit of information you might need is the definition of CvMouseCallback from the OpenCV library which is
typedef void (CV_CDECL *CvMouseCallback )(int event, int x, int y, int flags, void* param);
Now, the question is: When I return the callback from the last function in MouseHandler.cpp it is underlined with an error saying:
Error: return value type does not match the function type.
I know what it says is that I am trying to impose to that function to return something that does not look like the object it is being asking for. However, it's just a function and if I could do that in the main class it would be ok. My problem is how can selectHandler return a pointer to the selectROI function so that it can be used by another class?
I think that you need to use a static function here:
static void __cdecl selectROI( int event, int x, int y, int flags, void *param );
and
void ( CV_CDECL *callback )( int event, int x, int y, int flags, void *param );
accordingly.
The thing is that this definition:
typedef void (CV_CDECL *CvMouseCallback )(int event, int x, int y, int flags, void* param);
Is not a class member function, while yours is a member of class MouseHandler, which means its a different signature and different parameter list (to accommodate for this). Using static class member function solves it for you.
You'll have to figure out how to pass the object context data to the static function of course.
Your selectROI() method, since it is not static, requires an implicit this parameter as its first argument. If you try making it static, you will have a better chance at getting it working, though really if you are passing it to a C API as you are, you technically need to pass an extern "C" function pointer for everything to be fully proper and portable. That might be a trivial forwarding function like this:
extern "C" void selectROI( int event, int x, int y, int flags, void *param );
Then, if you want your C++ class method to not be static (so it can access class member variables), you just need to pass a pointer to a MouseHandler object as the third argument to cvSetMouseCallback() and you will then receive the same in your callback, which can then look like this:
extern "C" void selectROI( int event, int x, int y, int flags, void *param )
{
static_cast<MouseHandler*>(param)->selectROI( event, x, y, flags);
}