2009-12-10 42 views
8

我有一個DLL需要訪問主機應用程序中存儲在STL容器中的數據。因爲C++沒有標準的ABI,並且我想支持不同的編譯器,所以應用程序和DLL之間的接口基本上必須保持普通的舊數據。如何在DLL邊界上公開STL列表?

對於載體,這是相對簡單的。您可以簡單地返回向量的內存塊,因爲它是保證contigious:

// To return vector<int> data 
virtual void GetVectorData(const int*& ptr, size_t& count) const 
{ 
    if (!vec.empty()) 
     ptr = &(vec.front()); 

    count = vec.size(); 
} 

現在DLL可以通過該接口的矢量數據的安全只讀訪問。該DLL也可以包裝它以將內容複製到自身的矢量中。

但是STL列表(和deques)呢?是否有另一種直接的方式允許通過DLL邊界訪問?或者我將不得不訴諸某種GetFirst()/ GetNext()接口?我可能需要爲許多列表執行此操作,所以最好有一個像vector一樣簡單的解決方案。

回答

7

也許你可以傳遞類似「句柄」的列表/ deque迭代器?這些句柄類型將是不透明的,並將在您將交付給用戶的頭文件中聲明。在內部,您需要將句柄值映射到list/deque迭代器。基本上,用戶會寫這樣的代碼:

ListHandle lhi = GetListDataBegin(); 
const ListHandle lhe = GetListDataEnd(); 

while (lhi != lhe) 
{ 
    int value = GetListItem(lhi); 
    ... 
    lhi = GetNextListItem(lhi); 
} 
1

應用 和DLL之間的界面基本上具有保持 普通老式的數據。

不一定。您必須確保使用相同的編譯器版本。此外,構建影響STL對象佈局的設置在dll和應用程序之間完全相同。

如果你要將dll發佈到野外,你應該關心在dll邊界上暴露STL。但是,如果一切都在你的控制之下,純粹是內部的(或者你可以嚴格執行第三方編譯設置/編譯器),你應該沒問題。

+0

你說得對,如果所有的編譯設置都一樣的話,我可以避開它。但是這是一個插件架構,我想支持不同的編譯器。我編輯了這個問題來澄清這一點。 – AshleysBrain 2009-12-10 15:05:58

+0

我同意這一點,但也許你應該強調,它不僅僅是佈局 - 代碼必須已經用相同版本的編譯器編譯,以便像new和delete這樣的方法的實現相匹配。 – 2009-12-10 15:06:30

+0

如果您嚴格執行構建設置/編譯器版本並且所有內容都在您的控制之下,那麼DLL的優勢與使用靜態庫並將所有內容鏈接到一個可執行文件中有什麼區別? – 2009-12-11 10:02:46

10

可以傳遞的DLL之間的STL對象,並支持不同的編譯器,如果你你實例每個STL類型都小心翼翼。您需要一些智能的「DLLEXPORT」宏 - 我使用以下設置成功支持VC和gcc。

#ifdef WIN32 
#ifdef MYDLLLIB_EXPORTS  // DLL export macros 
#define MYDLLLIB_API __declspec(dllexport) 
#define MYDLLLIB_TEMPLATE 
#else 
#define MYDLLLIB_API __declspec(dllimport) 
#define MYDLLLIB_TEMPLATE extern 
#endif 
#else      // Not windows --- probably *nix/bsd 
#define MYDLLLIB_API 
#ifdef MYDLLLIB_EXPORTS 
#define MYDLLLIB_TEMPLATE 
#else 
#define MYDLLLIB_TEMPLATE extern 
#endif 
#endif // WIN32 

編譯DLL時,定義MYDLLLIB_EXPORTS。在DLL可以再實例您希望使用的每個STL類型,例如,列表或字符串

您的DLL的
MYDLLLIB_TEMPLATE template class MYDLLLIB_API std::vector<std::string>; 
MYDLLLIB_TEMPLATE template class MYDLLLIB_API std::list<std::string>; 

消費者的載體(沒有定義MYDLLLIB_EXPORTS誰),那麼會看到

extern template class __declspec(dllimport) std::vector<std::string>; 

並使用從您的DLL導出的二進制代碼,而不是實例化自己的。

+0

這是一個非常有趣的解決方案 - 我需要爲std :: vector :: iterator和std :: list :: iterator做同樣的事情嗎?對於宿主EXE中的DLL消耗STL類的方法是否一樣? – AshleysBrain 2009-12-11 10:33:51

+0

您不必實例化迭代器,因爲當您實例化特定stl容器類時,您還可以獲取容器類中所有類的代碼。不知道從宿主EXE中消費STL類 - 我沒有親自嘗試過,所以如果你想遵循這個方法,你將不得不做一些簡單測試的實驗。 – mcdave 2009-12-12 10:28:54

+2

它在MSDN中:http://support.microsoft.com/default.aspx?scid=kb;EN-US;Q168958 – k06a 2011-04-25 21:11:00