2017-11-27 3 views
0

C/C++에서 작성한 두 개의 프로젝트가있었습니다. 프로젝트 1 출력은 exe 파일이며 MyProject입니다. 프로젝트 2 출력은 dll 파일이며 Bridge라는 이름입니다. Bridge에서 MyProject의 기능을 실행하도록합니다. 함수가 작동하는 것처럼 보이지만 오류가 발생했습니다.런타임 검사 실패 # 0 오류가있는 DLL을 통해 함수 포인터가있는 콜백 함수

"런타임 점검 오류 # 0 - ESP 값이 함수 호출을 통해 올바르게 저장되지 않았습니다. 이것은 일반적으로 하나의 호출로 선언 된 함수를 호출 한 결과입니다 관례는 다른 호출 규칙으로 선언 된 함수 포인터를 가지고 있습니다. "

근본 원인이 __cdecl __stdcall 규칙에서 발생할 수는 있지만 여전히 해결 방법을 알지는 못합니다. 모든 프로젝트의 호출 규칙 설정 (/ 하나님) __cdecl, 그리고 VS IDE는 VS 2013입니다

DLL 프로젝트 (다리) 코드

헤더

typedef void(*sfcTrace)(const char *logLevel, const char *logMessage); 

    class OnRequestHandler 
    { 
    public: 
     virtual void writeLog(sfcTrace callback) = 0; 
    }; 

    class GenericInfoHandler : public OnRequestHandler 
    { 
    public: 

     GenericInfoHandler(); 
     ~GenericInfoHandler() { delete this; }; 
     void writeLog(sfcTrace callback); 

    }; 

    extern "C" __declspec (dllexport) OnRequestHandler* __cdecl oneBridgeCallBack() 
    { 
     return new GenericInfoHandler; 
    } 

CPP

void GenericInfoHandler::writeLog(sfcTrace callback) 
{ 
    const char *level = "DEBUG"; 
    const char *message = "TEST"; 
    callback(level, message); 
} 

MyProject 소스 코드 :

MyProject를에서3210
typedef OnRequestHandler* (__cdecl *test)(); 
    HINSTANCE getDLL = LoadLibrary("Bridge.dll"); 

    if (!getDLL) 
    { 
     cout << "Cannot not load DLL." << endl; 
    } 

    test func = (test)::GetProcAddress(getDLL, "oneBridgeCallBack"); 

    if (!func) 
    { 
     cout << "Cannot not locate the function." << endl; 
    } 

    OnRequestHandler* instance = func(); 
    instance->writeLog(&MyProject::TestCallBack); <----- Error Occurs here 

기능 구현

void MyProject::TestCallBack(const char *level, const char *message) 
{ 
    if (strcmp(level, "INFO") == 0){ 
     // do something 
    } 
    else if (strcmp(level, "DEBUG") == 0){ 
     // do something 
    } 

} 

헤더 :

typedef void(MyProject::*TestCallBack)(const char *logLevel, const char *logMessage); 

    class OnRequestHandler 
    { 
    public: 
     virtual void writeLog(sfcTrace callback) = 0; 
    }; 

    class GenericInfoHandler : public OnRequestHandler 
    { 
    public: 

     GenericInfoHandler(); 
     ~GenericInfoHandler() { delete this; }; 
     void writeLog(sfcTrace callback); 

    }; 
+0

콜백에 대한 호출 규칙을 명시 적으로 지정하십시오. 'typedef void (__ cdecl * sfcTrace) (const char * logLevel, const char * logMessage);' – lockcmpxchg8b

+0

또한 MyProject는 네임 스페이스입니까? (나는 네임 스페이스를 가정하고, 그렇지 않으면 콜백에 대한 포인터 - 투 - 멤버 함수를 전달하는 것에 대한 컴파일러 경고를 기대할 것이다.) – lockcmpxchg8b

+0

Thx, 그리고 MyProject는 클래스이다. MyProject 클래스에서 TestCallBack 함수를 구현하고 TestCallBack의 주소를 전달하고 DLL writeLog를 호출하도록했습니다. – user3738211

답변

0

다음 시도 : 나는 MyProject::TestCallback 정적 방법이 아니라고 추정하고있다 (그리고 그것이 일반으로 소용입니다 스택 손상을 일으키는 기능)

업데이트 typedef void(*sfcTrace)(const char *logLevel, const char *logMessage); 추가 void * 인수가 콜백과 함께 제공됩니다. 예 :

typedef void(*sfcTrace)(void *cb_arg, const char *logLevel, const char *logMessage); 
         ^^^^^^^^^^^^ 

OnRequestHandler::writeLog(sfcTrace callback) 및 그 재정의를 업데이트하여 호출자의 추가 인수를 취하십시오. 나는.,

virtual void OnRequestHandler::writeLog(sfcTrace callback, void *cb_arg) = 0; 
                  ^^^^^^^^^^^^ 
void GenericInfoHandler::writeLog(sfcTrace callback, void *cb_arg); 
                ^^^^^^^^^^^^ 

업데이트 WRITELOG의 구현은 콜백이 새 인수를 전달하는 :

void GenericInfoHandler::writeLog(sfcTrace callback, void *cb_arg) 
{             ^^^^^^^^^^^^ 
    const char *level = "DEBUG"; 
    const char *message = "TEST"; 
    callback(cb_arg, level, message); 
}   ^^^^^^ 

지금 우리가 MyProject 객체의 메소드를 호출 할 수있는 새로운 비회원 콜백 함수를 작성할 수 있습니다, 너무 오래 MyProject 객체가 cb_arg를 통해 전달되는 같이

void myprj_method_callback(void *arg, const char *logLevel, const char *logMessage) { 
    MyProject *mp = (MyProject *)arg; 
    mp->TestCallBack(level, message); 
} 

을 마지막으로, 우리는 새를 전달하는 전화를 업데이트 할 수 있습니다 콜백 기능, 인수 : 여담으로

instance->writeLog(myprj_method_callback, (void *)this); 

, 일반적으로 콜백 공급 업체가 호출 될 때 다시 콜백에 전달 될 인수를 전달할 수 있도록 모든 콜백에 좋습니다. 이를 통해 콜백 메커니즘의 사용자는 콜백 함수에 관련된 데이터 구조를 전역 변수에 저장하지 않고 전달할 수 있습니다.

+0

Thx. 나는 당신의 방법을 사용하기를 피곤하지만 인스턴스 -> writeLog (myprj_method_callback, (void *) this)에 C2664 오류가 발생했습니다. myprj_method_callback이 sfcTrace로 어떻게 바뀌 었습니까? – user3738211