简体   繁体   English

将C#字符串传递给C ++ / CLI不会在CPP程序中显示字符串值

[英]Passing a C# string to C++/CLI does not show the string value in the CPP program

I want to call a C# function from C++ , via CLI/C++. 我想通过CLI / C ++从C ++调用C#函数。

C# code C#代码

private string _text = " ";

public void setText(string text)
{
    // _text = text;
    _text = "HI World";
}

Ideally setText shall have the commented line only. 理想情况下,setText应该仅包含注释行。 The _text = "HI World" is an example. _text =“ HI World”是一个示例。

public string getText()
{
    return _text;
}

C++/CLI code C ++ / CLI代码

Header : 标头:

gcroot<Bridge> _managedObject;

virtual void setText(std::string text);
virtual std::string getText();

CPP file CPP文件

std::string CStringBridge::getText()
{

// _managedObject = gcnew Bridge(); // _managedObject = gcnew Bridge(); return (marshal_as(_managedObject->getText())); 返回(marshal_as(_managedObject-> getText())); } }

void CStringBridge::setText(std::string text)
{

// _managedObject = gcnew Bridge(); // _managedObject = gcnew Bridge(); _managedObject->setText(gcnew System::String(text.c_str())); _managedObject-> setText(gcnew System :: String(text.c_str())); } }

IStringBridgeWrapper* IStringBridgeWrapper::CreateInstance(void)
{
return ((IStringBridgeWrapper *)new CStringBridge());
}

Note : When I use the following code 注意:当我使用以下代码时

virtual void setText(System::String^ text);
virtual System::String^ getText();

I get the following error 3395 我收到以下错误3395

*__declspec(dllexport) cannot be applied to a function with the __clrcall calling convention* * __ declspec(dllexport)不能应用于具有__clrcall调用约定的函数*

, and so I stuck to std::string ,所以我坚持使用std :: string

When I use the library from the C++/CLI code, and call from my C++ program, "Hi World" should be printed ; 当我使用C ++ / CLI代码中的库并从我的C ++程序中调用时,应打印“ Hi World”; instead nothing gets printed 相反,什么都没有打印

C++ console application C ++控制台应用程序

IStringBridgeWrapper *pBridge = IStringBridgeWrapper::CreateInstance();

pBridge->setText(std::string("I am here"));
pBridge->getText();

I think the string is not being properly passed . 我认为该字符串未正确传递。

Any ideas to solve it shall be appreciated. 任何解决它的想法将不胜感激。

EDIT 编辑

I have updated the code after the comments , yet nothing shows up. 我已经在注释后更新了代码,但是什么也没有显示。

gcroot creates a handle, but does not allocate memory for it. gcroot创建一个句柄,但不为其分配内存。 But as Bridge has no memory allocated , the application does not work.My code is in the same lines at the article here - http://www.codeproject.com/Articles/10020/Using-managed-code-in-an-unmanaged-application . 但是由于Bridge没有分配内存,因此该应用程序无法正常工作。我的代码在本文的同一行中-http: //www.codeproject.com/Articles/10020/Using-managed-code-in-an-非托管应用程序

I want to call a C# function from C++ , via CLI/C++. 我想通过CLI / C ++从C ++调用C#函数。

Wait... you want to call a C++ function from C#, right? 等待...您想从C#调用C ++函数,对吧? That's what C++/CLI is good for. 这就是C ++ / CLI的优点。 Wrapping C++ code to be accessible in managed environments. 包装C ++代码以在托管环境中访问。 If you really want to call C# code from C++, you should look into COM registering your C# code. 如果您真的想从C ++调用C#代码,则应考虑使用COM注册您的C#代码。 If you use C++/CLI for this, your whole C++ program will be dragged into the .NET world and you could have used C# from the start. 如果为此使用C ++ / CLI,则整个C ++程序将被拖入.NET世界,并且您可能从一开始就使用C#。

In C++/CLI, your whole public class interface of ref (.NET) classes should consist of only managed types. 在C ++ / CLI中,您的ref(.NET)类的整个公共类接口应仅由托管类型组成。 That would be System::String^ instead of std::string . 那应该是System::String^而不是std::string

COM is your friend: COM是您的朋友:

Create a an interface in C# 在C#中创建接口

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;


namespace CsharpLibrary
{
   // Since the .NET Framework interface and coclass have to behave as 
   // COM objects, we have to give them guids.
   [Guid("56A868B1-0AD4-11CE-B03A-0020AF0BA770"),
    InterfaceType(ComInterfaceType.InterfaceIsDual)]
   public interface IStringHolder
   {
      String GetText();
      void SetText(String s);
   }
}

Implement the C# interface: 实现C#接口:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace CsharpLibrary
{
   [Guid("C6659361-1625-4746-931C-36014B146679")]
   public class MyStringHolder : IStringHolder
   {
      String _text;

      public String GetText()
      {
         return this._text;
      }

      public void SetText(String value)
      {
         _text = value;
      }

   }
}

Create and call your C# object from C++ 从C ++创建并调用C#对象

#include <windows.h>
#include <stdio.h>

#pragma warning (disable: 4278)

// To use managed-code servers like the C# server, 
// we have to import the common language runtime:
#import <mscorlib.tlb> raw_interfaces_only


#pragma warning (disable: 4278)

// To use managed-code servers like the C# server, 
// we have to import the common language runtime:
#import <mscorlib.tlb> raw_interfaces_only

#import "..\CsharpLibrary\bin\Debug\CsharpLibrary.tlb" no_namespace named_guids





int main(int argc, char* argv[])
{
   HRESULT hr = S_OK;

   IStringHolder *pStringHolder = NULL;

   //
   // Initialize COM and create an instance of the InterfaceImplementation class:
   //
   CoInitialize(NULL);

   hr = CoCreateInstance(   __uuidof(MyStringHolder),
                           NULL,
                           CLSCTX_INPROC_SERVER,
                           __uuidof(IStringHolder),
                           reinterpret_cast<void**>(&pStringHolder));

   if(SUCCEEDED(hr))
   {
      _bstr_t sHelloWorld = SysAllocString( L"Hello, World" );

      hr = pStringHolder->SetText(sHelloWorld);

      SysFreeString(sHelloWorld);
   }


   //
   // Be a good citizen and clean up COM
   //
   CoUninitialize();

   return hr;
}

On the C# side you have to generate the type library and register the class by a post-build event: 在C#端,您必须生成类型库并通过构建后事件注册类:

generate the type library: "$(FrameworkSDKDir)bin\\NETFX 4.0 Tools\\tlbexp.exe" "$(TargetPath)" /out:"$(TargetDir)$(TargetName).tlb" 生成类型库:“ $(FrameworkSDKDir)bin \\ NETFX 4.0 Tools \\ tlbexp.exe”“ $(TargetPath)” /out:"$(TargetDir)$(TargetName).tlb“

register the class: C:\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\RegAsm.exe "$(TargetPath)" 注册该类:C:\\ Windows \\ Microsoft.NET \\ Framework \\ v4.0.30319 \\ RegAsm.exe“ $(TargetPath)”

Enjoy! 请享用!

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

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