5

我正在为原生 c++ 类开发 C++/CLI 包装器。C++/CLI 包装器正在 WPF 应用程序中使用。我在尝试编组字符串时遇到了一个奇怪的问题。

WPF 应用程序将一个System::String对象传递给我的包装器。然后包装器将 转换为System::String本地std::string类所期望的。这一切都很好,但是一旦我将字符串传递给本机对象,它就是空的。

这是一些相关的代码

WPF 事件处理程序 (C#)

private void tbInputConfig_TextChanged(object sender, TextChangedEventArgs e)
{
    _OrionBasicApp.ConfigTemplateFile = tbInputConfig.Text;
}

包装类中的属性 (C++/CLI)

void BasicApp::ConfigTemplateFile::set(String ^value)
{
    std::string val = marshal_as<std::string>(value);
    _NativeApp->setConfigTemplateFile(val);
}

本机代码 (C++)

void Basic_App::setConfigTemplateFile(const std::string& template_file)
{
   m_gParams.configTemplateFile = template_file;
}

因此,当我中断 WPF 应用程序并使用调试器进行跟踪时,String 对象看起来很好,std::string val编组看起来不错,但函数template_file中的参数setConfigFile是一个空字符串。当我退出本机函数时,我可以看到std::string val变量看起来仍然很好。

我尝试过使用Marshal::StringToHGlobalAnsi函数,它产生相同的结果。我尝试更改本机函数以获取字符串的副本而不是引用,这会产生有关无效内存块的异常(如果需要,我将发布确切的消息)。我试过在堆上分配字符串,没有运气。

现在是踢球者:本机代码是用 Microsoft Visual Studio 2008 编译的,而 wrapper + wpf 代码是用 2010 编译的。我希望这不是问题,因为我们将任何一个代码库迁移到另一个版本并不容易.

有任何想法吗?

更新

我能够将本机代码切换到 Visual Studio 2010,这确实解决了问题。(为什么微软必须让我的生活变得如此困难?)虽然我确实构建了系统,但该项目的负责人给我带来了这个解决方案的主要麻烦(他担心它可能无法正确运行或者我们将不得不切换依赖库)。

那么这个问题有没有不强制我切换 Visual Studio 版本的解决方案?

4

1 回答 1

6

跨 DLL 边界传递 C++ 对象是个坏主意。 std::string不是导致您的问题的相同类型、布局或实现。

如果您通过 DLL 边界传递 BSTR(SysStringAlloc等)或 raw char*,并转换std::string为本机代码内部而不是包装器,您的问题就会消失。

此问题并非特定于 .NET 或 C++/CLI。任何将std::string实例从任何其他编译器版本传递到本机 DLL 的尝试都将失败。

示例修复:

void BasicApp::ConfigTemplateFile::set(String ^value)
{
    std::string val = marshal_as<std::string>(value);
    _NativeApp->setConfigTemplateFile(val.c_str(), val.size());
}

void Basic_App::setConfigTemplateFile(const char* template_file_content, size_t template_file_length)
{
   m_gParams.configTemplateFile = std::string(template_file_content, template_file_length);
}
于 2012-08-24T18:27:39.540 回答