简体   繁体   English

C ++ / CLI字符串互操作

[英]C++/CLI string interop

I am working on a C++/CLI wrapper for a native c++ class. 我正在为本机c ++类开发C ++ / CLI包装器。 The C++/CLI wrapper is being used in a WPF application. C ++ / CLI包装器正在WPF应用程序中使用。 I have encountered a weird problem when trying to marshal strings. 我在尝试编组字符串时遇到了一个奇怪的问题。

The WPF application passes a System::String object to my wrapper. WPF应用程序将System::String对象传递给我的包装器。 The wrapper then converts the System::String to a std::string that the native class expects. 然后包装器将System::String转换为本机类所期望的std::string This all goes fine, but once I pass the string to the native object, it is empty. 这一切都很顺利,但是一旦我将字符串传递给本机对象,它就是空的。

Here is some relevant code 这是一些相关的代码

WPF Event Handler (C#) WPF事件处理程序(C#)

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

Property In Wrapper Class (C++/CLI) 包装类中的属性(C ++ / CLI)

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

Native Code (C++) 本地代码(C ++)

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

So when I break in the WPF app and trace using the debugger, the String objects look fine, the std::string val marshaling looks good, but the parameter template_file in the setConfigFile function is an empty string. 因此,当我使用调试器中断WPF应用程序和跟踪时,String对象看起来很好, std::string val编组看起来很好,但setConfigFile函数中的参数template_file是一个空字符串。 When I step out of the native function, I can see that the std::string val variable still looks fine. 当我退出本机函数时,我可以看到std::string val变量看起来仍然很好。

I have tried using Marshal::StringToHGlobalAnsi function, it produces the same result. 我尝试过使用Marshal::StringToHGlobalAnsi函数,它会产生相同的结果。 I have tried changing the native function to take copy of the string instead of a reference, this produces an exception about an invalid block of memory (if requested I will post the exact message). 我已经尝试更改本机函数以获取字符串的副本而不是引用,这会产生关于无效内存块的异常(如果请求,我将发布确切的消息)。 I have tried allocating the string on the heap, no luck. 我试过在堆上分配字符串,没有运气。

Now for the kicker: The native code was compiled with Microsoft Visual Studio 2008, and the wrapper + wpf code was compiled with 2010. I hope this is not the problem because it will not be easy for us to migrate either codebase to the other version. 现在为踢球者:本机代码是用Microsoft Visual Studio 2008编译的,而包装器+ wpf代码是用2010编译的。我希望这不是问题,因为我们将代码库迁移到其他版本并不容易。

Any ideas? 有任何想法吗?

UPDATE UPDATE

I was able to switch the native code over to visual studio 2010 and this did fix the problem. 我能够将本机代码切换到visual studio 2010,这确实解决了问题。 (why must microsoft make my life so difficult?) While I did make the system build, the lead on the project is giving me MAJOR hassles about this solution (he is concerned that it may not run correctly or that we will have to switch over dependent libraries). (为什么微软必须让我的生活变得如此困难?)虽然我确实建立了系统,但是项目的主角给了我关于这个解决方案的主要麻烦(他担心它可能无法正常运行或我们将不得不切换依赖库)。

SO is there a solution to this problem that doesn't force me to switch visual studio version? 那么这个问题的解决方案是不是迫使我转换Visual Studio版本?

Passing C++ objects across DLL boundaries is a bad idea. 跨DLL边界传递C ++对象是个坏主意。 std::string is not the same type, layout, or implementation, which is causing your problem. std::string不是同一类型,布局或实现,这会导致您的问题。

If you pass either a BSTR ( SysStringAlloc et al) or raw char* across the DLL boundary, and convert to std::string inside the native code instead of in the wrapper, your problem will go away. 如果你跨越DLL边界传递BSTR( SysStringAlloc等)或raw char* ,并在本机代码而不是包装器中转换为std::string ,那么你的问题就会消失。

This problem is not specific to .NET or C++/CLI. 此问题不是特定于.NET或C ++ / CLI。 Any attempt to pass std::string instances to your native DLL from any other compiler version will fail. 任何将std::string实例从任何其他编译器版本传递到本机DLL的尝试都将失败。

Example fix: 示例修复:

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);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM