2009-11-26 24 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的更好选择。