2016-06-16 16 views
0

我有一個dll(「so.dll」)定義如下,其中我有一個函數TestWrongClass,它將一個指針 返回給類對象(TestWrongClass)。檢測並清除在C++中從dll導入的錯誤對象

/////// "IOReader.h" ////////////// 
class IOReader 
{ 
public : 
    IOReader() {}; 
    virtual ~IOReader() {}; 
    virtual bool open(const std::string &format, 
    const std::string &fileName, const int mask) = 0; 
    std::string errorMessage; 
}; 
// "IOReader.h" Ends Here 

// ---- so.dll ----/
//////////////// sio.h //////////// 
#ifdef SEIO_EXPORTS 
#define SEIO_API __declspec(dllexport) 
#else 
#define SEIO_API __declspec(dllimport) 
#endif 

#include <string> 
#include "IOReader.h" 

class SReaderIO : public IOReader 
{ 
public: 
    SReaderIO() {}; 
    bool open(const std::string &format, 
    const std::string &fileName, const int mask) 
    { 
    return true; 
    } 
}; 

class TestWrongClass 
{ 
public: 
    TestWrongClass() { }; 
    bool open(const std::string &format, 
    const std::string &fileName, const int mask) 
    { 
    return true; 
    } 
}; 

SEIO_API TestWrongClass* CreateIOReader() 
{ 
    TestWrongClass * module = new TestWrongClass(); 
    return module; 
} 

//// sio.h ends here /////// 

//in the main executable I am loading the dll on run time 
// and after creating a object of type TestWrongClass, 
//I explicitly try to cast it with the wrong object, as follows 

/// Main Source // 
#include <iostream> 
#include <windows.h> 
#include "IOReader.h" 

int main() 
{ 

    HMODULE hDLL=LoadLibrary(L"sIO.dll"); 
    CreateSealafineReaderFn _funcSelafinCreator = NULL; 
    _funcSelafinCreator = (CreateSealafineReaderFn) GetProcAddress (hDLL, 
    "CreateIOReader"); 

    // Method 1 
    void *Iref = (_funcSelafinCreator)(); 
    IOReader * locReader = NULL; 
    locReader = reinterpret_cast <IOReader *>(Iref); // but how to check 
        // that object locReader is not of base type IOReader 
        // so that I may call delete Iref 
    // If I try to do as follow, then I get illegal error from compiler 
    // locReader = dynamic_cast <IOReader *>(Iref); // illegal 

    // Method 2 
    try 
    { 
    locReader = dynamic_cast <IOReader *>((_funcSelafinCreator)()); 
    // works but how can I check wrong casting and catch exception 
    } catch (std::bast_cast) 
    { 
    // how to clear the object created by CreateIOReader 
    } 
} 

// 

爲什麼這樣做過程的原因是爲了檢查是否有任何的DLL,其主要程序將從DLL目錄 被掃描可以是具有相同名稱的方法,但是返回所創建的指針類型通過該方法的對象可能是不同的,這是不期望的。 (在上述情況下該方法是CreateIOReader)

如果我使用的dynamic_cast,我可以檢查bad_cast例外,但是該對象將在DLL中已經創建,並且不會被釋放,因爲我 無法訪問dll的內部代碼。

上面的方法,我已經使用reintepret_cast工作,但是我無法檢查是否返回正確的對象類型。 如果通過某種方法瞭解,如果鑄件的類型不正確,則可以在Iref指針「delete Iref」上調用delete以清除堆中的對象。

是否存在被法CreateIOReader檢查錯了對象的創建,從而從可執行代碼

+0

「CreateSealafineReaderFn」類型擴展爲什麼? – Smeeheey

+0

@Smeeheey我忘記添加語句 typedef IOReader *(* CreateSealafineReaderFn)(); just befor int main() – Gourish

回答

2

刪除它對於這個問題dynamic_cast幫不了你任何方法。問題是,你不知道你的函數的真正返回類型,只是假裝它是IOReader*,實際上它可能是別的東西(即TestWrongClass*)。在別名規則下,這是不允許的。

對比這與情況:

class IBase { ... }; 
class IOReader : public IBase { ... }; 
class TestWrongClass : public IBase { ... }; 

,你也知道,你的函數返回一個IBase*。這裏確實有一個動態演員可以幫助你,因爲IOReaderTestWrongClass有共同的祖先,並且通過IBase*來指代是有效的。

我不得不說這是一個奇怪的問題:有一個庫函數的調用,你不知道可能返回什麼。我會建議有所改變的設計。你可以(除其他事項外):

  1. 創建統一的層次結構按上述
  2. 有調用返回類似std::pair<int, void*>,其中int(或enum)將確定正在返回什麼可靠的辦法之後,您可以reinterpret_castvoid*

如果您選擇的方法1,然後解決你的問題刪除,你可以像destroy()添加函數到IBase接口,會導致圖書館刪除該對象(請注意:delete自己的對象由外部庫提供給您不是個好主意)。

如果您選擇方法2,那麼也許您可以擁有一個庫函數,如void destroy(int, void*),如果您收到除您想要的東西以外的其他東西,您可以將其傳遞給std::pair的成員。然後庫可以使用這些來將void*重新放回正確的位置以在內部刪除它。