2014-12-05 5 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 *'로 캐스트 할 수 없습니다. 제 3 자 라이브러리 API의 버그입니다. 어쨌든 함수 호출 포인터를 한 호출 규칙 (__stdcall)에서 다른 포인터 (__cdecl)로 변환 할 수는 없습니다. – Cameron

답변

2

두 가지 문제가 있습니다. 첫째, void*은 데이터 포인터이며 함수 포인터는 아닙니다. C++ 표준에 따르면이 둘 사이의 캐스팅은 작동하지 않을 것으로 예상됩니다. 일부 플랫폼은 Windows GetProcAddress 및 * nix dlsym과 같이 강력한 보증을 제공합니다.

다음으로 &MainWindow::MyFrameSizeCallback은 함수 포인터가 아니며 멤버 -function으로 포인터입니다. 이 함수를 호출하려면 MainWindow 객체가 필요합니다.이 객체는 외부 라이브러리에서 전혀 알지 못합니다.

멤버 함수가 아닌 일반 함수를 라이브러리에 제공해야합니다. MainWindow* 개체 포인터를 얻는 방법이 있다면 실제 작업을 수행하기 위해 해당 멤버 함수를 호출 할 수 있습니다. 때로는 라이브러리가 콜백에 전달되는 "컨텍스트"매개 변수를 제공합니다. 그것은 객체 포인터를 놓을 수있는 좋은 장소입니다. 그렇지 않으면 MainWindow*을 전역 변수에 저장해야합니다. 당신은 하나만 있다면 쉽게, 두 개 이상 있다면 std::map<IGrabChannel*, MainWindow*> 함께 갈 수도 있습니다.

코드 : 매개 변수 xIGrabChannel하지

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 매개 변수가 예측 가능한 고유 한 식별자가 아닌 경우 하나의 MainWindow 인스턴스에 대한 콜백 만 수행하도록 제한 될 수 있습니다.

+0

죄송합니다. C++을 처음 접했을 때 저는 여전히 혼란 스럽습니다. 하나의 MainWindow 인스턴스 만 있지만'MainWindow * '를 전역 변수로 저장하는 방법을 모르겠습니다. 또한 실제 입력은 훨씬 더 많습니다 :'void MainWindow :: MyFrameSizeCallback (int a, int b, float c, ...)'하지만, 유일하고 예측 가능합니다. – user2406671

+0

@ user2406671 : 하나의 창에 대해 코드를 업데이트 (단순화)했습니다. 정적 멤버를 사용했지만 실제 전역을 사용할 수도 있습니다 (the_window 앞에있는 MainWindow ::를 꺼내십시오) –

+0

거의 다 왔을 것 같습니다. 이제 내 오류입니다 : 'mainwindow.obj : -1 : 오류 : LNK2001 : 해결되지 않은 외부 기호 "public : static class MainWindow * MainWindow :: the_window"(?the_window @ MainWindow @@ 2PEAV1 @ EA)' 어디에서'MainWindow * MainWindow :: the_window'를 정의해야합니까? 상응하는'mainwindow.h' 파일이 있습니다 – user2406671