C# C++/CLI字符串互操作 我正在为C++ C++类编写一个C++/CLI包装器。WPF应用程序中正在使用C++/CLI包装。我在尝试封送字符串时遇到了一个奇怪的问题

C# C++/CLI字符串互操作 我正在为C++ C++类编写一个C++/CLI包装器。WPF应用程序中正在使用C++/CLI包装。我在尝试封送字符串时遇到了一个奇怪的问题,c#,wpf,string,interop,c++-cli,C#,Wpf,String,Interop,C++ Cli,WPF应用程序将System::String对象传递给我的包装器。然后包装器将System::String转换为本机类所期望的std::String。这一切都很顺利,但一旦我将字符串传递给本机对象,它就会是空的 下面是一些相关代码 WPF事件处理程序(C#) 包装类中的属性(C++/CLI) 因此,当我打开WPF应用程序并使用调试器进行跟踪时,字符串对象看起来很好,std::String val封送看起来很好,但是setConfigFile函数中的参数template_file是一个空字符串。当

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

下面是一些相关代码

WPF事件处理程序(C#)

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

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

我尝试过使用
Marshal::StringToHGlobalAnsi
函数,它会产生相同的结果。我已尝试将本机函数更改为复制字符串而不是引用,这会产生一个关于无效内存块的异常(如果请求,我将发布确切的消息)。我试过在堆上分配字符串,但没有成功

现在让我们来看一下:本机代码是用MicrosoftVisualStudio2008编译的,包装器+wpf代码是用2010编译的。我希望这不是问题所在,因为将任一代码库迁移到另一个版本对我们来说并不容易

有什么想法吗

更新

我能够将本机代码切换到VisualStudio2010,这确实解决了这个问题。(为什么微软一定要让我的生活如此艰难?)虽然我确实进行了系统构建,但该项目的负责人对此解决方案给了我很大的麻烦(他担心它可能无法正常运行,或者我们将不得不切换依赖库)


这是不是有一个解决这个问题的方法,它不强制我切换VisualStudio版本?

跨越DLL边界传递C++对象是个坏主意。代码>标准::字符串的类型、布局或实现不同,这导致了您的问题

如果通过DLL边界传递BSTR(
SysStringAlloc
等)或原始
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);
}
void basicap::ConfigTemplateFile::set(字符串^value)
{
std::string val=marshal_as(值);
_NativeApp->setConfigTemplateFile(val.c_str(),val.size());
}
void Basic_App::setConfigTemplateFile(常量字符*模板文件内容、大小、模板文件长度)
{
m_gParams.configTemplateFile=std::string(模板文件内容、模板文件长度);
}

<>代码>你的C++是编译为Unicode、MBCS还是ANSI?好问题我忘记添加这个信息了。本机代码使用多字节字符集。我已经在Unicode和MultiByte中尝试了C++/CLI层,但这对我的问题没有任何影响。您如何包装本机代码?本机代码在一个DLL中,包装器在单独的DLL中,还是链接到单个DLL中?本机代码在visual studio 2009中构建的单独DLL中。C++/CLI从VS2010编译为自己的程序集dll。WPF应用程序也从2010年开始编译为自己的程序集exe。其原理是,通过这种方式,每个组件都很容易被不同的源使用(例如,一些完全基于本机命令行的测试是为本机层编写的),很想知道std::string在不同版本之间发生了很大的变化。我最后做了一些类似的工作,作为一个变通办法,因为似乎没有其他的方式,我给你的答案answer@Max,这并不意味着
std::string
完全改变了。允许不同的编译器以不兼容的方式编译完全相同的代码,只要在隔离的每个模块中满足总体行为。只有POD(或者在C++11中,标准布局)类型可以在编译器之间安全地传递。但是,是的,对于
std::string
来说,有一些事情,比如小字符串优化,或者使用不同的分配器,在编译器之间确实会发生变化。没错,这很有意义。我猜我(显然是错误的)假设是关闭VisualStudio版本将是compatible@Max:啊,这是一个合理的问题,但肯定值得一问,而不仅仅是假设。现实更糟一些。。。即使是具有不同编译选项的相同编译器版本也可能不兼容。对于某些编译选项,您根本无法在DLL之间传递对象,即使对所有DLL使用相同的编译器和选项(DLL本地分配器)。
void BasicApp::ConfigTemplateFile::set(String ^value)
{
    std::string val = marshal_as<std::string>(value);
    _NativeApp->setConfigTemplateFile(val);
}
void Basic_App::setConfigTemplateFile(const std::string& template_file)
{
   m_gParams.configTemplateFile = template_file;
}
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);
}