Reputation: 14286
I am using a camera API that calls a callback function every time there is a new image. The callback function is passed as:
BOOL WINAPI StTrg_SetTransferEndCallback(HANDLE hCamera, funcTransferEndCallback func, PVOID pvContext);
Where funcTransferEndCallback
is:
typedef void (WINAPI *funcTransferEndCallback)(HANDLE hCamera, DWORD dwFrameNo, DWORD dwWidth, DWORD dwHeight, WORD wColorArray, PBYTE pbyteRaw, PVOID pvContext);
I don't want to make a callback function but actually use a method in a class instead. I am calling this StTrg_SetTransferEndCallback()
inside my classe's constructor, so I can initialize the camera and pass my classe's method to capture every new frame and process it.
My method is defined in my class .h as:
public class Camera
{
public:
.....
void TakePicture(string pictureFileName);
void StartRecording(string videoFileName);
void StopRecording(void);
.....
private:
volatile bool takePictureFlag;
volatile bool startRecordingFlag;
volatile bool stoptRecordingFlag;
void __stdcall TransferEndCallback(HANDLE hCamera, DWORD dwFrameNo, DWORD dwWidth, DWORD dwHeight, WORD wColorArray, PBYTE pbyteRaw, PVOID pvContext);
};
If I try this:
StTrg_SetTransferEndCallback(cameraHandle, TransferEndCallback, NULL);
Or this:
StTrg_SetTransferEndCallback(cameraHandle, this->TransferEndCallback, NULL)
Visual Studio 2013 says:
error C3867: 'MyNamespace::MyClass::TransferEndCallback': function call missing argument list; use '&MyNamespace::MyClass::TransferEndCallback' to create a pointer to member
So I use it as suggested:
StTrg_SetTransferEndCallback(cameraHandle, &MyNamespace::MyClass::TransferEndCallback, NULL)
And I receive this error message:
error C2664: 'BOOL StTrg_SetTransferEndCallback(HANDLE,funcTransferEndCallback,PVOID)' : cannot convert argument 2 from 'void (__stdcall MyNamespace::MyClass::* )(HANDLE,DWORD,DWORD,DWORD,WORD,PBYTE,PVOID)' to 'funcTransferEndCallback' There is no context in which this conversion is possible
So, is it possible to pass a member method as a function? Is this a case for std::bind
?
Upvotes: 0
Views: 1302
Reputation: 17648
Usual pattern is to pass the instance pointer this
into the PVOID pvContext
parameter, then use it within the callback to call a member function.
public class Camera
{
// ...
void ThisTransferEndCallback(HANDLE hCamera, DWORD dwFrameNo, DWORD dwWidth, DWORD dwHeight, WORD wColorArray, PBYTE pbyteRaw);
static void __stdcall TransferEndCallback(HANDLE hCamera, DWORD dwFrameNo, DWORD dwWidth, DWORD dwHeight, WORD wColorArray, PBYTE pbyteRaw, PVOID pvContext);
};
Set the callback as
StTrg_SetTransferEndCallback(cameraHandle, TransferEndCallback, this);
Then write the static callback to dispatch it to the member function
void __stdcall Camera::TransferEndCallback(HANDLE hCamera, DWORD dwFrameNo, DWORD dwWidth, DWORD dwHeight, WORD wColorArray, PBYTE pbyteRaw, PVOID pvContext)
{
((Camera *)pvContext)->ThisTransferEndCallback(hCamera, dwFrameNo, dwWidth, dwHeight, wColorArray, pbyteRaw);
}
The above doesn't include error checking etc.
Upvotes: 2
Reputation: 4770
The interface requires a function
callback. In C++
that means a non-member
function or static
function. That's because both of these types of functions are invoked without the need for an instance of an class object. Member functions of a class are invoked differently and require an instance of a class object.
If you need more explanation, others can elaborate on how, under the hood, member functions are call.
Upvotes: 2
Reputation: 413
StTrg_SetTransferEndCallback(cameraHandle, &MyNamespace::MyClass::TransferEndCallback, NULL)
That will not work, because there is no object to call the method on. As Anon Mail suggested, a static function is the best way to do that. But, you stated that you can't do that.
My suggestion is to refactor your class into a singleton and add a static forward-function. Example:
public class Camera
{
public:
static *Camera the()
{
if (!singleton)
singleton = new Camera;
return singleton;
}
void destroy() { delete singleton; singleton = nullptr; }
.....
private:
static void TransferEndCallbackForward(HANDLE hCamera, DWORD dwFrameNo, DWORD dwWidth, DWORD dwHeight, WORD wColorArray, PBYTE pbyteRaw, PVOID pvContext)
{
assert(singleton != nullptr); // Implement your own error handling here
singleton->TransferEndCallback(hCamera, dwFrameNo, dwWidth, dwHeight, wColorArray, pbyteRaw, pvContext);
}
void __stdcall TransferEndCallback(HANDLE hCamera, DWORD dwFrameNo, DWORD dwWidth, DWORD dwHeight, WORD wColorArray, PBYTE pbyteRaw, PVOID pvContext);
static Camera *singleton = nullptr;
};
I hope that can help you.
Upvotes: 1