2017-01-04 8 views
2

동적으로 C++ dll을로드하려고했는데, 먼저 "LoadLibrary"함수를 사용하여 dll을로드 했으므로 올바르게 처리됩니다. 그런 다음 "GetProcAddress"를 사용하여 DLL 함수의 함수 포인터를 얻으려고 시도했지만 NULL을 반환합니다. 내 DLL 코드와 응용 프로그램 코드를 찾고 코드에서 어디서 잘못되었는지 알려주십시오.NULL을 반환하는 GetProcAddress 함수

dummy2.h

namespace newer 
{ 
    class dllclass 
    { 
    public: 
     static __declspec(dllexport) int run(int a,int b); 
    }; 
} 

dummy2.cpp

#include <iostream> 
using namespace std; 

#include "dummy2.h" 

namespace newer 
{ 
    int dllclass::run(int a,int b) 
    { 
    return a+b; 
    } 
} 

dummy1.cpp

#include "stdafx.h" 
#include <windows.h> 

#include <iostream> 
using namespace std; 
typedef int (*Addition)(int,int); 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    Addition add; 
    HINSTANCE hDLL; 
    hDLL = LoadLibrary(TEXT("Dummy2.dll")); 

    add = (Addition)GetProcAddress(hDLL, "run"); 

    getchar(); 
    return 0; 
} 

위의 코드를 참조하여 나를 인도 해주십시오.

+2

당신은 아마'GetProcAddress를 (hDLL, "dllclass :: 실행")가 필요합니다; '또는'GetProcAddress (hDLL, "newer :: dllclass :: run");'? –

+1

GetProcAddress는 대/소문자와 특수 문자, 하이픈, 물음표, @ 기호 등 내 보낸 ** 정확한 ** 이름을 알아야합니다. 따라서 "실행"은 다음과 같은 "실행"과 다릅니다. "@ 4"를 실행하십시오. Dependency Walker 또는 * exact * 이름이 무엇인지보기위한 다른 도구와 같은 DLL에 DLL을로드해야하며, GetProcAddress에서 사용해야하는 이름입니다. – PaulMcKenzie

+1

실제로는 "__imp_? run @ dllclass @ [email protected]@ SAHHH @ Z"와 같은 것입니다. – axalis

답변

4

이름이 잘못 되었기 때문에 (즉, 함수의 이름이 "실행"되었지만 다른 것).

귀하의 코드 (I 테스트 곳 MSVC 2013)와 함께 작동합니다 : 일반적으로

add = (Addition)GetProcAddress(hDLL, "[email protected]@[email protected]@[email protected]"); 
cout << add(1, 2) << endl; 

, 당신이 플러그인을 통해 클래스를로드하려는 경우, 당신의 최선은 가상 인터페이스를 사용하는 것입니다. 예 :

//dummy2.h 
namespace newer 
{ 
    class dllclass_interface 
    { 
    public: 
     virtual int run(int a,int b) = 0; 
}; 

} 

extern "C" __declspec(dllexport) newer::dllclass_interface* getDllClass(); 

//dummy2.cpp 
#include <iostream> 
using namespace std; 

#include "dummy2.h" 

namespace newer 
{ 
    class dllclass: public dllclass_interface 
    { 
    public: 
     virtual int run(int a,int b); 
}; 

    int dllclass::run(int a,int b) 
    { 
    return a+b; 
    } 
} 

extern "C" newer::dllclass_interface* getDllClass() 
{ 
    static newer::dllclass instance; 
    return &instance; 
} 

typedef newer::dllclass_interface* (*GetClassFunc)(); 

GetClassFunc getClassFunc = (GetClassFunc)GetProcAddress(hDLL, "getDllClass"); 

newer::dllclass_interface* dllClass = getClassFunc(); 
cout << dllClass->run(a, b) << endl; 
+0

나에게도 잘 작동하지만, 무엇이 "? @ dllclass @ newer @@ SAHHH @ Z" – sivanesan1

+0

이것은'never :: dllclass :: run()'함수를 DLL에서 내 보낸 것과 같습니다. 동일한 DLL 내에서'run()'을 제공하거나 같은 클래스 내에서 또 다른'run()'override를 제공하는 또 다른 클래스'dllclass2 '가 있다고 가정합니다 - 내 보낸 이름이 어떻게 구별 될까요? 따라서 이름 맹 글링 (장식)이 제자리에 있습니다. 이름에 네임 스페이스와 클래스 이름도 포함되어 있고 다른 문자가 다른 오버로드를 구분하는 매개 변수에 따라 거기에 있음을 알 수 있습니다. – axalis

+0

다른 컴파일러 (GCC, Borland 등)에서 내 보낸 경우 이름이 완전히 다르게 보일 것입니다. 따라서 가상 인터페이스가 더 잘 작동합니다 (클래스 intance에 대해 하나의 'extern "C"export 된 접근자가 있고 이름이 엉망이 아닙니다 - extern "C"로 모든 컴파일러에서 똑같이 간단합니다. 다른 컴파일러 사이에서도 DLL을 사용할 수 있습니다. – axalis

1

실제로 DLL은 C 시대에 도입되었습니다. 이후 C++에서는 함수 유형을 매개 변수의 유형에 따라 오버로드하고 "mangled names"라는 이름을 사용하여 함수 호출을 적절한 이름으로 연결할 수 있습니다. C++ 표준에서는이 이름의 모양을 지정하지 않습니다. 다른 컴파일러는 매개 변수의 유형을 이름에 다르게 구현했습니다.

C++은이 문제를 이해하고 때로는 예측 가능한 이름을 가져야합니다. C++의 특별한 구조는 거기에 있습니다 :

extern "C" 
{ 
    int run(int, int); 
} 

당신이 GetProcAddress에서 함수의 이름을 지정하는 경우가 DLL에서 내 보낸으로 정확히해야한다. DependencyWalker과 같은 특수 유틸리티를 사용하여이 이름을 볼 수 있습니다.

+0

함수의 이름은 꾸며질 수 있지만 맹 글링되지는 않습니다. 깔끔한 이름을 얻는 방법은 이름을 분리하고 모듈 정의 파일 (DEF) 파일에서 실제 이름을 지정하는 것입니다. – PaulMcKenzie

+0

DependencyWalker가 구형이되어 VS의 최신 버전으로 컴파일 된 것에 많은 경고와 오류가 발생합니다. – rubenvb

+0

내 보낸 함수 이름 만 가져 오기 위해 종속성 워커를 사용하는 경우 올바르게 작동합니다. 다른 용도는 "구식"일 수 있지만 수출 된 이름의 목록을 얻는 것이지 그다지 많지 않습니다. – PaulMcKenzie