Я пытаюсь связаться с внешней библиотекой в моем приложении QT. Внешняя библиотека имеет заголовочный файл со следующим соответствующим кодом, который я пытаюсь вызвать:
extern VGRABDEVICE_API bool V_AssignFrameSizeCallback(IGrabChannel* pChannel, void* pFunc);
В представленной демонстрационной программе C ++, которая не имеет проблем с компиляцией, следующий соответствующий код:
// in main.cpp
void _stdcall MyFrameSizeCallback(T x) {
do_stuff;
}
int main(int argc, char* argv[]) {
IGrabChannel* pChannel0 = something;
V_AssignFrameSizeCallback(pChannel0, MyFrameSizeCallback);
}
Я пытаюсь включить этот код в мое приложение QT, но получаю проблемы. В моем файле mainwindow.cpp:
void _stdcall MainWindow::MyFrameSizeCallback(T x) {
do_stuff;
}
void MainWindow::someFunction() {
IGrabChannel* pChannel0 = something;
V_AssignFrameSizeCallback(pChannel0, &MainWindow::MyFrameSizeCallback);
}
Я получаю ошибку:
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
Что мне нужно сделать? Благодарю.
У тебя две проблемы. Первый, void*
это указатель данных, а не указатель на функцию. В соответствии со стандартом C ++ приведение между ними не должно работать. Некоторые платформы предоставляют более надежную гарантию … например, Windows GetProcAddress
и * nix dlsym
смешайте два.
Далее ваш &MainWindow::MyFrameSizeCallback
это не указатель на функцию, это указатель начлен-функция. Для вызова требуется MainWindow
объект, о котором внешняя библиотека ничего не знает.
Вы должны предоставить библиотеке обычную функцию, а не функцию-член. Если у вас есть какой-то способ получить MainWindow*
указатель объекта, затем вы можете вызвать его функцию-член для выполнения реальной работы. Иногда библиотека предоставляет параметр «context», который передается вашему обратному вызову; это отличное место для размещения указателя объекта. В противном случае вам нужно будет хранить ваши MainWindow*
в глобальной переменной. Легко, если у вас есть только один, а если у вас есть больше, вы можете пойти с std::map<IGrabChannel*, MainWindow*>
,
Код:
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);
}
Если параметр x
не является IGrabChannel
, измените тип данных карты и логику вставки соответственно. Если параметр x
не какой-то уникальный предсказуемый идентификатор, вы можете ограничиться только обратными вызовами одного MainWindow
пример.