2010-11-28 67 views
1

我一直在試圖創建一個DLL並將DLL鏈接到我的程序,但每次我嘗試我的程序都找不到該函數。該DLL加載正常,但功能無法找到。動態鏈接C++ DLL ...我做錯了什麼?

計劃:

#include <iostream> 
#include <windows.h> 
using namespace std; 

typedef void (*HelloPtr)(); 

int main() { 
    HelloPtr hello; 
    HINSTANCE hDll = LoadLibrary("dll.dll"); 
    if(hDll) 
    { 
     hello = (HelloPtr)GetProcAddress(hDll, "hello"); 
     if(hello) { 
      hello(); 
     } else { 
      // Error code here 
     } 
    } 
    return 0; 
} 

dllmain.cpp

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

DLLIMPORT void hello() 
{ 
    MessageBox(NULL, "Hey", "", MB_OK);   
} 

DllClass::DllClass() 
{ 

} 

DllClass::~DllClass() 
{ 

} 


BOOL APIENTRY DllMain (HINSTANCE hInst  /* Library instance handle. */ , 
         DWORD reason  /* Reason this function is being called. */ , 
         LPVOID reserved  /* Not used. */) 
{ 
    switch (reason) 
    { 
     case DLL_PROCESS_ATTACH: 
     break; 

     case DLL_PROCESS_DETACH: 
     break; 

     case DLL_THREAD_ATTACH: 
     break; 

     case DLL_THREAD_DETACH: 
     break; 
    } 

    /* Returns TRUE on success, FALSE on failure */ 
    return TRUE; 
} 

dll.h

#ifndef _DLL_H_ 
#define _DLL_H_ 

#if BUILDING_DLL 
# define DLLIMPORT __declspec (dllexport) void hello(void) 
#else /* Not BUILDING_DLL */ 
# define DLLIMPORT __declspec (dllexport) void hello(void) 
#endif /* Not BUILDING_DLL */ 

class DLLIMPORT DllClass 
{ 
    public: 
    DllClass(); 
    virtual ~DllClass(void); 

    // Says hello world 
    DLLImport void hello(void); 

    private: 

}; 


#endif /* _DLL_H_ */ 

我想知道我做錯了什麼,所以我可以將其記錄下來並學習。

感謝

+1

我不認爲可以編譯:`class DLLIMPORT DllClass`會展開成`class __declspec(dllexport)void hello(void)DllClass`。 – 2010-11-28 11:11:58

+0

當你不在類中放置`void hello(void)`,並在其周圍添加`extern「C」{}`塊時會發生什麼? – stakx 2010-11-28 11:12:53

回答

1

你需要把你的DLL的代碼在extern "C"塊的所有功能,否則編譯器的所有功能都mangle the names

看看這個問題作進一步的信息: C++ DLL Export: Decorated/Mangled names

+0

爲了方便您自己查看,請在DLL上使用[Dependency Walker](http://www.dependencywalker.com/)。它會告訴你所有的出口。 – kichik 2010-11-28 11:18:12

0

在DLL把你想要導出到

#ifdef __cplusplus 
    extern "C" { 
    #endif 

    DLLIMPORT void hello() 
    { 
    MessageBox(NULL, "Hey", "", MB_OK);   
    } 

    #ifdef __cplusplus 
    } 
    #endif 
0

函數名are mangled出口時,出於顯而易見的原因。如果你正在使用函數重載呢?如果在兩個不同的類中有一個名爲hello()的函數呢?例如,Qt的QString& remove(const QRegExp& rx)導出爲[email protected]@@[email protected]@@@Z。解決這個問題的最簡單的方法是使用extern "C"和cdecl或stdcall導出函數,以便它們不被破壞(或以更標準/可預測的方式破壞)。

0

您有:

#if BUILDING_DLL 
# define DLLIMPORT __declspec (dllexport) void hello(void) 
#else /* Not BUILDING_DLL */ 
# define DLLIMPORT __declspec (dllexport) void hello(void) 
#endif /* Not BUILDING_DLL */ 

然後,你必須:

DLLIMPORT void hello() 

的組合會變成這樣,這沒有任何意義:

__declspec (dllexport) void hello(void) void hello() 

更改您的DllImport宏代之以:

#if BUILDING_DLL 
# define DLLIMPORT __declspec(dllexport) 
#else /* Not BUILDING_DLL */ 
# define DLLIMPORT __declspec(dllimport) 
#endif /* Not BUILDING_DLL */ 

編輯:你也有dllexport兩種情況;下層應該是dllimport。

您還在hello方法中使用了DLLImport而不是DLLIMPORT。

你也不能(或至少不應該)在DLL中導出非靜態類成員。如果你想導出C++類,我會推薦:

  1. 導出DLL函數,它會在你的類對象上創建,銷燬和調用方法。創建函數會返回類似HANDLE,void *或類似的不透明指針。其他方法會將其作爲參數,將其轉換爲實際的內容,然後調用該方法。

  2. 使用COM。

您還應該遵循Sanja Melnichuk的建議,以避免導出的函數名稱被修飾。

下面是一個例子Dll.h:

#ifndef _DLL_H_ 
#define _DLL_H_ 

#if BUILDING_DLL 
# define DLLIMPORT __declspec(dllexport) 
#else /* Not BUILDING_DLL */ 
# define DLLIMPORT __declspec(dllimport) 
#endif /* Not BUILDING_DLL */ 


extern "C" 
{ 
    DLLIMPORT void hello(void); 
} 

注意DllClass走了。 (你在dllmain.cpp中的hello函數沒有變化,因爲它從未指定它是DllClass的一部分。)

不要忘記在DLL項目中定義BUILDING_DLL,並確保不在項目中定義它它試圖加載DLL。