Visual Studio C++的dll库在Qt应用程序中崩溃

9
我有一个问题,需要在 MS Visual C++ DLL 库和 Qt 程序之间共享“std::string”数据。

我拥有的是:

  • DLL library written in Visual C++ 2010 Express, which exports one method:

    extern "C" __declspec(dllexport) int Init(ITest* commandTest);
    
  • Abstract interface "ITest" and a class implementing it:

    class CTest: public ITest
    {
    public:
        CTest();
        virtual ~CTest();
        virtual void getVersion(std::string & version) const;
    };
    
  • Qt GUI application that needs to:

    * load the DLL dynamically
    * instantiate CTest and pass it to exported Init method.
    
在 DLL 的 "Init" 中调用了一个 "CTest::getVersion()" 方法。我预期会将 "&version" 字符串填充。但实际上,在我使用新字符串填充 "&version" 的那一行代码上却出现了崩溃。

我已经做过的事情:

  • http://qt-project.org/downloads下载了 "Qt libraries 4.8.3 for Windows (VS 2010, 235 MB)",安装并在 QtCreator 的项目设置中选择它。

  • 在 QtCreator 中切换到安装有 MS Visual Studio 2010 Express 的工具链,以解决问题。

    我以为这样就能解决问题了,因为我使用了使用 VS 2010 编译的 Qt 库,并且 Qt GUI 也是使用 VS C++ 工具链编译的。不幸的是,问题仍然存在,所以我尝试了最后一步:

  • 在 Visual Studio 中创建 Win32 控制台应用程序,通过 LoadLibrary 加载我的 DLL,以与我在 Qt GUI 中使用 "Init" 方法相同的方式使用了 "Init" 方法... 然后它奏效了!

小观察

在“CTest::getVersion()”中,我将通过引用传递的“version”字符串打印到控制台。当使用VS C++控制台应用程序作为主机时,它会正确地打印出来。但是当使用Qt应用程序时,“version”字符串会带有一些垃圾字符(例如┌►☻qwerty27)。
这使我认为Qt应用程序和我的DLL的ABI仍然不兼容,即使使用了上面提到的Qt VS 2010库。
问题:
  • 使用Windows(VS 2010)的Qt库以及Visual Studio工具链是否足以解决ABI兼容性问题?
  • 这是否意味着我应该自己编译Qt框架?
  • 请帮忙 - 欢迎任何想法...

5
对于每个项目(dll和exe),你使用的是哪个运行时库?如果你下载的预构建二进制文件是使用与VS2010 Express不同的std::string实现构建的,这将会是一个问题,可以通过自己构建Qt来解决。 - tmpearce
4
这听起来像是混合了发布版和调试版构建。在 MSVC 中,std::string 对象在发布版和调试版构建中默认具有不同的表示方式(具体取决于 _ITERATOR_DEBUG_LEVEL 宏设置)。如果您的 DLL 和 Qt 应用程序具有不同的 _ITERATOR_DEBUG_LEVEL 设置,则 std::string 对象将不同。 - Michael Burr
1
感谢大家的回复。在检查了@tmpearce的评论后,我解决了问题,虽然michael-burr的评论也很好。我使用Dependency Walker检查了运行时库。DLL是使用“Debug”配置构建的,这导致加载MSVCP100D.dll和MSVCR100D.dll调试库。当使用相同的库时,我下载的Qt VS 10可以正常工作。如果有人想尝试,请访问以下示例项目链接:http://dl.dropbox.com/u/176393/SO/12690457.ZIP 其中包含Dll库、VS C++控制台应用程序和一个Qt应用程序的示例源代码。 - schedar
3
@Schedar,我认为如果您自己回答这个问题并提供您解决问题的详细步骤,那么未来的搜索者们将从您的经验中受益最多。您可以回答并接受自己的问题。 - tmpearce
即使你不应该通过dll边界传递任何stl类 - 你可以尝试在编译程序时将wchar_t作为内置类型。Qt二进制文件是没有编译wchar_t的。 - David Feurle
显示剩余9条评论
2个回答

1
在一个项目中,我遇到了和你很像的情况,两个使用同一编译器(VC++2010)的DLL。我从一个DLL传递std::string到另一个DLL时经常遇到崩溃问题。
这个问题是因为一个DLL是用“多线程调试DLL(/MDd)”编译的,而另一个DLL是用“多线程调试(/MTd)”编译的,这引起了两个DLL之间的二进制不兼容性(崩溃)。此外,版本也必须匹配,无论是对于DEBUG还是RELEASE都要使用相同的DLL。
查看你的项目,两个DLL似乎都使用“多线程调试DLL(/MDd)”。这意味着两者都使用“MSVCP100D.dll”。这是可以的,唯一的问题是从QT网站下载的VC++版本是在RELEASE模式下编译的,并且使用“MSVCP100.DLL”。
我的建议是将你的运行时库更改为“多线程DLL(/MD)”来配置你的DEBUG。第二个建议是遵循Rebert的建议,使用“char*”而不是std::string。不管怎样,“char*”都是兼容的。

您也可以使用多线程调试 DLL (/MDd))重新编译QT,并将该版本的QT用于DEBUG配置(但这似乎太麻烦了)。


0
通常情况下,我不会尝试在应用程序和DLL之间传递复杂数据(超出我的控制范围,代码方面)。我只会使用POD结构来传递,即我会将接口更改为以下形式:
class CTest: public ITest
{
public:
    CTest();
    virtual ~CTest();
    virtual void getVersion(char* versionBuffer, unsigned length) const;
};

让生活变得轻松多了 ;)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接