无法跨DLL传递std::wstring

Unable to pass std::wstring across DLL

本文关键字:std wstring 传递 DLL      更新时间:2023-10-16

我在Visual Studio 2010中建立了一个项目,针对现有的MFC DLL编写单元测试。我使用的是单头单元测试框架,并从单元测试项目链接到MFC DLL的库包装器。我试图构建一个类,在它的构造函数中需要一个std::wstring。下面是我的测试:

TEST_CASE("MyProject/MyTest", "Do the test.")
{
    MockDbService mockDbService;
    Foobar foo(L"{F00DFACE-FEED-DEAD-BEEF-C0FFEEDECADE}", mockDbService);
    foo.loadObject();
    REQUIRE(mockDbService.getMethodInvokeCount("query()") >= 1);
}

其中Foobar是从被测试的MFC DLL导出的类。然而,测试框架报告了一个意外的异常。当将字符串复制到Foobar的构造函数时,我将其跟踪到std::wstring的复制构造函数。MSVC调试器将源字符串报告为<Bad Ptr>

我创建了一个虚拟构造函数,Foobar::Foobar(long num, IDbService& db)和所有的值(包括IDbService&)都很好。

MFC DLL和我的单元测试EXE都共享一个属性表,应该保持编译器标志相等。我在调试模式下构建和运行测试。任何想法为什么std::wstring不能跨DLL复制?

您应该检查EXE和DLL是否与相同的调试CRT (/MDd编译器选项)动态链接。确保其他设置,如_HAS_ITERATOR_DEBUGGING,对于EXE和DLL都是相同的。

(一种快捷方式可以是在类接口上使用const wchar_t*而不是std::wstring,并从构造函数体内的原始指针构建std::wstring)。

EDIT:您确认CRT不匹配(即使用/MD构建的EXE与使用/MDd构建的DLL)是问题所在。事实上,相同的类名std::wstring在调试版本(/MDd)和发布版本(/MD)中意味着两个不同的类。事实上,在调试构建中,类实现中可以有额外的机制来帮助调试;这种机制会导致效率低下,所以在发布版本中被移除。因此,调试版本的std::wstring的内部结构不同于发布版本的std::wstring(例如,如果你试图打印std::wstring实例的原始sizeof,你可以在发布版本和调试版本中找到不同的数字)。因此,使用/MD构建的EXE期待发布std::wstring;相反,用/MDd构建的DLL期望调试构建的std::wstring:这两个期望之间存在不匹配(一个模块期望类X,但另一个模块给出类Y),所以你有一个崩溃。