2015-02-11 41 views
1

我實現一個C++類作爲DLL。但是當我連接到dll時,我有鏈接器錯誤。我有適當的設置,不知道什麼是錯的。我研究過,但找不到相關的解決方案,所以我提出了這個問題。錯誤LNK2019在實現一個C++類的DLL

ASM_Lib.h 

    #ifdef EXPORT 
    #define DLLCLASS __declspec(dllexport) 
    #else 
    #define DLLCLASS __declspec(dllimport) 
    #endif 
    class ASM 
    { 
     public: 
      ASM(); 
      ~ASM(); 
      int loadData(string path, string ext); 
      int landmarkEqualization(); 

     private: 
      vector<PtsData_<CurrentType_>> pts;//this vector size is same as number of images, released after use 
      vector<string> files;//file names 
      vector<TrainingData_<CurrentType_>> td;//this vector size is same as number of images, released after use 
      vector<Mat> images; 
    }; 

    extern "C" /*Important for avoiding Name decoration*/ 
    { 
     DLLCLASS ASM* _cdecl CreateASMObject(); 
    }; 

    // Function Pointer Declaration of CreateASMObject() [Entry Point Function] 
    typedef ASM* (*CREATE_ASM)(); 

ASM_Lib.cpp

namespace VIDEO_ANALYTICS_PLATFORM{ 

    DLLCLASS ASM* _cdecl CreateASMObject() { 
     return new ASM(); 
    } 

    ASM::ASM() 
    { 
    } 

    ASM::~ASM() 
    { 
    } 

    int ASM::loadData(string path, string ext) 
    { 

      return FILE_READ_WRITE_ERROR; 
    } 

    ///* 
    //This loop equalize all landmark points to 
    //be equal distances 
    //*/ 
    int ASM::landmarkEqualization() 
    { 
     //Clear vector 
     pts.clear(); 
     vector<PtsData_<CurrentType_>>().swap(pts); 
     return SUCCESS; 
    } 


} 

然後在我的測試程序,我作爲接口

#include "stdafx.h" 
#include <iostream> 
#include "ASM_Lib.h" 
using namespace VIDEO_ANALYTICS_PLATFORM; 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    HINSTANCE hDLL = LoadLibrary(L"ASM_Lib.dll"); 

    if (hDLL == NULL){ 
     std::cout << "Failed to load library.\n"; 
    }else{ 
     CREATE_ASM pEntryFunction = (CREATE_ASM)GetProcAddress(hDLL, "CreateASMObject"); 
     ASM* pASM = pEntryFunction(); 
     if (pASM) {        
      pASM->loadData("C:\\PointsFiles", "pts");       
     } 
     FreeLibrary(hDLL); 
    } 

    std::cin.get(); 

    return 0; 
} 

但我有LNK2019鏈接錯誤(在功能wmain引用),我不有wmain。可能是什麼問題呢?

test.obj : error LNK2019: unresolved external symbol "public: int __cdecl VIDEO_ANALYTICS_PLATFORM::ASM::loadData(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)" ([email protected]@[email protected]@[email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@[email protected]) referenced in function wmain 

如果我註釋掉這個API pASM->loadData("C:\\PointsFiles", "pts");,那麼它的工作原理,並能夠正確地加載DLL。

編輯: 最後更新

ASM_Lib.h 
#ifdef EXPORT 
#define DLLCLASS __declspec(dllexport) 
#else 
#define DLLCLASS __declspec(dllimport) 
#endif 

namespace VIDEO_ANALYTICS_PLATFORM{ 

    class i_ASM 
    { 
     public: 
      virtual ~i_ASM(){ ; }; 
      virtual int loadData(string path, string ext)=0; 
      virtual int landmarkEqualization() = 0; 
    }; 

    class ASM : public i_ASM 
    { 
     public: 
      ASM(){ } 
      int loadData(string path, string ext); 
      int landmarkEqualization(); 

     private: 
      vector<PtsData_<CurrentType_>> pts;//this vector size is same as number of images, released after use 
      vector<string> files;//file names 
      vector<TrainingData_<CurrentType_>> td;//this vector size is same as number of images, released after use 
      vector<Mat> images; 
    }; 

    extern "C" 
    { 
     DLLCLASS i_ASM* _cdecl CreateASMObject(); 
    }; 
} 

ASM_Lib.cpp 
namespace VIDEO_ANALYTICS_PLATFORM{ 

    DLLCLASS i_ASM* _cdecl CreateASMObject() { 
     return new ASM(); 
    } 

    int ASM::loadData(string path, string ext) 
    { 
     return 0; 
    } 

    ///* 
    //This loop equalize all landmark points to 
    //be equal distances 
    //*/ 
    int ASM::landmarkEqualization() 
    { 
     //Clear vector 
     pts.clear(); 
     vector<PtsData_<CurrentType_>>().swap(pts); 
     return SUCCESS; 
    } 
} 

Test.cpp 
#include "ASM_Lib.h" 
using namespace VIDEO_ANALYTICS_PLATFORM; 

int _tmain(int argc, _TCHAR* argv[]) 
{  
    ASM* pASM = ::CreateASMObject(); 
    if (pASM) { 
     pASM->loadData("C:\\PointsFiles", "pts"); 
     pASM->~ASM(); 
     pASM = NULL; 
    } 

    return 0; 
} 

我想,我的最後一次更新應該工作。但對於loadData()~ASM(),仍然存在鏈接器錯誤LNK2019。我在同一個解決方案中同時測試了項目和ASM_Lib項目。什麼可能是錯的?

+1

loadData沒有實現,剛剛聲明? – LPs 2015-02-11 07:07:28

+0

@LPs;對不起,我編輯過,我在cpp文件中實現。 – batuman 2015-02-11 07:12:20

+0

如果你要動態加載dll,爲什麼你要鏈接到lib呢?對於你的錯誤,_tmain可能轉換爲wic爲unicode構建。不知道,我從來沒有使用tchar的東西。 – 2015-02-11 07:20:33

回答

2

DLL只導出CreateASMObject函數。 ASM :: loadData未導出,但在測試應用程序中使用。 我可以提出兩種修復方法:

1)使用__declspec(dllexport)的整個ASM類或loadData成員的唯一屬性,並添加ASM_Lib.lib來測試應用程序項目。

2)聲明純抽象類(接口)IASM和改變CreateASMObject的返回類型:

class IASM 
{ 
public: 
    virtual ~IASM() = 0; 
    virtual int loadData(string path, string ext) = 0; 
}; 

extern "C" 
{ 
    DLLCLASS IASM* _cdecl CreateASMObject(); 
}; 

然後從IASM派生ASM和實施abstact方法(它可以CPP文件內完成)。 在這種情況下,鏈接器不需要loadData方法的地址,因爲它將在運行時通過vtable進行解析。

PS。您必須確保DLL及其客戶端使用相同的堆管理器實例(例如相同版本的C運行時DLL)。否則,調用另一個模塊中創建的對象的delete是不安全的。解決方法是添加一個實現刪除的方法:

class IASM 
{ 
public: 
    virtual void destroy() = 0; 
protected: 
    ~IMyAPI() = default; 
};  

class ASM: public IASM 
{ 
public: 
    virtual void destroy() override 
    { 
    delete this; 
    } 
};  
+0

按照您在選項2中的建議執行。此鏈接(http://www.codeproject.com/Articles/28969/HowTo-Export-C-classes-from-a-DLL)表示您的方法是成熟方法。但我仍然有錯誤。讓我調查更多。 – batuman 2015-02-11 14:31:49

+0

我在第一篇文章中更新爲編輯。我認爲,我最後一次更新應該可以工作,它與您的建議相同。但是'loadData()'和'〜ASM()'仍然存在鏈接器錯誤LNK2019。我在同一個解決方案中同時測試了項目和ASM_Lib項目。什麼可能是錯的? – batuman 2015-02-11 14:58:43

+0

如果我在我的test.cpp中註釋掉這兩行,它就可以工作。所以這意味着,該類被加載,但方法沒有正確加載。 – batuman 2015-02-11 15:23:42