1

I am trying to link to an external library in my QT application. The external library has a header file with the following relevant code I'm trying to call:

 extern VGRABDEVICE_API bool V_AssignFrameSizeCallback(IGrabChannel* pChannel, void* pFunc);

In the demo C++ program provided, which has no problems compiling, the following relevant code is:

// in main.cpp    
void _stdcall MyFrameSizeCallback(T x) {
    do_stuff;
}

int main(int argc, char* argv[]) {
    IGrabChannel* pChannel0 = something;
    V_AssignFrameSizeCallback(pChannel0, MyFrameSizeCallback);
}

I am trying to incorporate this code into my QT application, but getting problems. In my mainwindow.cpp file:

void _stdcall MainWindow::MyFrameSizeCallback(T x) {
    do_stuff;
}

void MainWindow::someFunction() {
    IGrabChannel* pChannel0 = something;
    V_AssignFrameSizeCallback(pChannel0, &MainWindow::MyFrameSizeCallback);
}

The error I'm getting is:

error: C2664: 'bool V_AssignFrameSizeCallback(IGrabChannel *,void *)' :
cannot convert argument 2 from 'void (__cdecl MainWindow::* )(T)' to 'void *'
There is no context in which this conversion is possible

What do I need to do? Thanks.

user2406671
  • 37
  • 1
  • 7
  • Function pointers are not data pointers, and can't be cast to `void*` (often because they're larger, especially with virtual inheritance). It's a bug in the third-party library's API. In any case, you can't convert a function pointer from one calling convention (__stdcall) to another (__cdecl). – Cameron Dec 05 '14 at 20:40

1 Answers1

3

You have two problems. First, void* is a data pointer, not a function pointer. According to the C++ standard, casting between the two is not expected to work. Some platforms provide a stronger guarantee... for example Windows GetProcAddress and *nix dlsym mix the two.

Next, your &MainWindow::MyFrameSizeCallback is not a function pointer, it is a pointer-to-member-function. Calling it requires a MainWindow object, which the external library doesn't know anything about.

You need to provide an ordinary function, not a member function, to the library. If you have some way to get ahold of the MainWindow* object pointer, you can then call its member function to do the real work. Sometimes the library provides a "context" parameter which is passed to your callback; that's a great place to put the object pointer. Otherwise, you'll need to store your MainWindow* in a global variable. Easy if you have just one, while if you have more than one you might go with std::map<IGrabChannel*, MainWindow*>.

Code:

MainWindow* MainWindow::the_window;

void MainWindow::MyFrameSizeCallback(T x)
{
    do_stuff;
}

void _stdcall MyFrameSizeCallbackShim(T x)
{
    MainWindow::the_window->MyFrameSizeCallback(x);
}

void MainWindow::someFunction()
{
    IGrabChannel* pChannel0 = something;
    the_window = this;
    V_AssignFrameSizeCallback(pChannel0, &MyFrameSizeCallbackShim);
}

If the parameter x isn't an IGrabChannel, change the map datatype and insertion logic accordingly. If the parameter x isn't some sort of unique predictable identifier, you may be limited to only doing callbacks to one MainWindow instance.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • I'm sorry, but I'm pretty new to C++ and I'm still very confused. There is only a single MainWindow instance, but I'm not sure how you would store `MainWindow*` as a global variable. Also, the actual inputs are much more: `void MainWindow::MyFrameSizeCallback(int a, int b, float c,...)`, but all unique and predictable. – user2406671 Dec 05 '14 at 20:57
  • @user2406671: I updated (simplified) the code as for one window. I used a static member, but you could just as well use a real global (take out `MainWindow::` from in front of `the_window`) – Ben Voigt Dec 05 '14 at 21:53
  • I think we're almost there. Now my error is: `mainwindow.obj:-1: error: LNK2001: unresolved external symbol "public: static class MainWindow * MainWindow::the_window" (?the_window@MainWindow@@2PEAV1@EA)` Where do I need to define `MainWindow* MainWindow::the_window`? There is a corresponding `mainwindow.h` file – user2406671 Dec 06 '14 at 14:38
  • You wouldn't get that error unless you left out the first line of code in my answer. Put it in any implementation file, probably alongside the functions that use it. Don't put definitions in headers, since that would cause multiple definition errors. – Ben Voigt Dec 06 '14 at 16:02
  • Thank you so much. I have gotten it to work now. I figured out how to access the current MainWindow object, and all is working now. `MainWindow *mw=(MainWindow*)qApp->topLevelWidgets().at(0);` – user2406671 Dec 06 '14 at 17:45