2014-12-05 2 views
0

Я пытаюсь установить ссылку на внешнюю библиотеку в приложении QT. Внешняя библиотека имеет заголовочный файл со следующим соответствующим кодом я пытаюсь позвонить:Ошибка преобразования void (__ cdecl MyClass :: *)() в void *

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 

Что мне нужно сделать? Благодарю.

+0

Указатели функций не являются указателями данных и не могут быть отнесены к 'void *' (часто потому, что они больше, особенно с виртуальным наследованием). Это ошибка в API сторонней библиотеки. В любом случае вы не можете преобразовать указатель на функцию из одного вызова (__stdcall) в другой (__cdecl). – Cameron

ответ

2

У вас есть две проблемы. Во-первых, 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.

+0

Прошу прощения, но я довольно новичок в C++, и я все еще очень смущен. Существует только один экземпляр MainWindow, но я не уверен, как вы будете хранить 'MainWindow *' как глобальную переменную. Кроме того, фактические входы гораздо больше: 'void MainWindow :: MyFrameSizeCallback (int a, int b, float c, ...)', но все уникальные и предсказуемые. – user2406671

+0

@ user2406671: Я обновил (упростил) код как для одного окна. Я использовал статический член, но вы могли бы просто использовать реальный глобальный (выведите 'MainWindow ::' из 'the_window') –

+0

Я думаю, что мы почти там. Теперь моя ошибка: 'mainwindow.obj: -1: ошибка: LNK2001: неразрешенный внешний символ" public: static class MainWindow * MainWindow :: the_window "(?the_window @ MainWindow @@ 2PEAV1 @ EA) ' Где мне нужно определить' MainWindow * MainWindow :: the_window'? Существует соответствующий файл 'mainwindow.h' – user2406671