简体   繁体   中英

Using c++ class method as a function callback

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 ?

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.

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM