2009-11-26 68 views
0

我有一個用VC++ 6編寫的動態鏈接庫。我用VC++ 2005編寫了一些代碼,它調用了原生的VC++ 6庫。每當我將std :: string傳遞給本地庫時,結果總是垃圾。但是,如果我通過其他類型,如char *,int等,這不會發生。任何理想的是什麼造成這種情況?從VC++ 2005向VC++ 6傳遞std :: string DLL導致垃圾回收

以下代碼說明了這一點。

// VC++ 6碼

class __declspec(dllexport) VC6 
{ 
     public: 
     VC6(); 
     void DoSomething(const std::string &s); 
} 

VC6()::VC6() {}  

void VC6::DoSomething(const std::string &s) 
{ 
     std::cout << s; // Resulting output on screen is garbage 
} 

// VC++ 2005代碼

void VC2005::DoSomething() 
{  
     VC6 *vc6 = new VC6(); 

     std::string s("Test String"); 
     vc6->DoSomething(s); 

     delete vc6; 
} 

回答

0

不要這樣做。它不起作用。

C++不限定固定的ABI,所以你不能在由不同的編譯器編譯庫或翻譯單元之間一般通非POD類型。

在你的情況下,VC6和VC8有std::string的不同定義(並且編譯器也可能插入不同的填充和其他更改),結果是垃圾和/或不可預知的行爲和崩潰。

如果您需要將數據傳遞給VC6 DLL(更好的選擇可能是在合理的編譯器下重新編譯該代碼),您必須堅持使用類型,以確保它可以正常工作。這意味着1)POD類型(內置原語,如char*或僅包含POD類型的C結構)或COM對象。

+0

即使是POD也不安全。位字段和聯合可能會成爲麻煩的候選對象,但即使是簡單結構的打包也可能會從編譯器變爲編譯器。你希望字節排序不會改變,但它可以合法。 – 2009-11-27 00:30:30

+0

我需要從VC8調用VC6的原因是因爲我無法訪問使用VC6編寫的庫的源代碼,但我需要將其轉換爲託管代碼,以便C#可以調用庫。 問題是,VC6庫大量使用std :: vector和std :: string,並且沒有辦法將這些類型直接封裝到c#中。所以我需要的是VC6和C#之間的橋樑,這就是我選擇VC6的VC8封裝的原因。 您提到過有關COM對象。你可以給我一些關於如何使用COM對象來達到上述目的的例子嗎? – Lopper 2009-11-27 00:37:11

+0

Stephen Nutt:不錯,但是對於POD類型,你通常可以在沒有太多麻煩的情況下使用包裝編譯指示等。對於非POD類型,從一開始就幾乎失敗了。 – jalf 2009-12-01 12:37:41

3

類如的std :: string不一定在每一個版本中定義的相同方式運行時庫(即使它們具有相同的名稱),所以您不應該以這種方式混合這些庫。另一方面,int和char *等類型對於給定平臺是相同的,因此您可以傳遞它們。

在您的例子,這是更好的字符串傳遞作爲(指針,大小)對或簡稱爲空終止字符串。

編輯:忘記提及使用相同編譯器版本的明顯解決方案。如果要傳遞物體,請執行此操作。

0

你可以編寫一個包含C接口的包裝器DLL。如果p-invoke本身無法處理互操作,則可能需要C++/CLI包裝器。在ATL中編寫COM服務器可能是在本機代碼中提供面向對象接口並避免在C++/CLI中編寫另一個包裝器DLL的更好選擇。