【问题标题】:How to pass C++ Object to C#如何将 C++ 对象传递给 C#
【发布时间】:2017-08-22 07:46:29
【问题描述】:

向有处理过 C++ 和 C# 经验的人寻求帮助

我现在正在写一个C#项目,需要调用内部库中已有的C++函数,遇到了一些困难。

C++ 代码函数头(无法更改)

typedef int (*PTR_func) 
(const char*             param1,      // input
 const char*             param2,      // input
 VirtualInternalString&  po_output);  // Third param is actually the output

内部字符串对象的 C++ 代码类(无法更改)

namespace InternalLib
{

    class VirtualInternalString
    {
        public :
            virtual ~VirtualInternalString(){};
            virtual void _cdecl SetString(const char *) =0;
            virtual const char * _cdecl c_str() const =0;
    };

    class SafeInternalString :public VirtualInternalString
    {
        public :
            SafeInternalString():TheString(""){};
            virtual ~SafeInternalString(){};
            virtual void _cdecl SetString(const char *  chararray) { TheString = chararray;};
            virtual const char * _cdecl c_str() const { return TheString.c_str() ;} ;           // This is the std::string

        protected:
            std::string TheString;
    };

    class SafePtrString :public VirtualInternalString
    {
        public :
            SafePtrString():PtrString(0){};
            SafePtrString(std::string &str):PtrString(&str){};
            virtual ~SafePtrString(){}; 
            virtual void _cdecl SetString(const char *  chararray) { (* PtrString) = chararray;};
            virtual const char * _cdecl c_str() const { return PtrString->c_str() ;} ;

        protected :
            std::string * PtrString;
    };
}

现在我必须在我的 C# 代码中使用这个“函数”。我可以正确调用和使用 C++ 函数,但是在输出返回(第三个参数)期间出现问题。应该是问题相关的返回类型。

C#(可更改)

[DllImport("xxxxlib", CallingConvention = CallingConvention.Cdecl)]
private extern static int func(string param1, 
                               string param2, 
                               [MarshalAs(UnmanagedType.LPStr)] StringBuilder res); // problem here

我知道我必须创建一个适当的包装器来将 c++ 对象分解为 C# 字符串,但我之前没有这方面的经验。我尝试了几种来自互联网的解决方案,但都不起作用。

有人知道我可以如何实现吗?你介意给我看一些简单的 C# 框架代码吗?

【问题讨论】:

  • 几分钟前我没有看到这个确切的问题吗?是你发了然后删了吗?如果是这样,请不要那样做。相反,您应该编辑已有的问题。
  • 抱歉...您对这篇文章有任何想法吗?目标是获取返回的 c++ 对象中的字符串。这应该不难,但我真的尝试了不同的方法并且很挣扎。还是不行
  • P/Invoke 仅适用于与 Win32 API 使用的 API 类似的 API。它只能翻译符合它知道如何翻译的 C 风格的函数和结构。对于像这样复杂的任何事情,您都需要。 C++/CLI 桥。或者您可以公开符合 P/Invoke 支持的函数。
  • @vasek 建议的副本不包括这种情况,因为帖子中的对象不能在 C++ 和 C# 之间编组。需要更多信息来解释为什么这是不可能的以及如何弥合差距。

标签: c# c++


【解决方案1】:

如果您只更改 C# 端,vasek 的 possible duplicate 将不起作用。但是您可以做的是在 C++ 中创建包装器,以创建原始的 char * 和关联的 length 参数。

您创建一个额外的 C++ 标头和源代码,其中包含:

int func 
(const char*             param1,      // input
 const char*             param2,      // input
 char*                   po_output,   // Third param is actually the output
 int                     length);     // Length of the buffer allocated by caller  

然后你让你的func 打电话给PTR_func。

【讨论】:

  • 难点在于c++函数返回一个VirtualInternalString&对象,使用这个函数不需要简单的C#初始化。你的意思是我可以创建另一个 c++ 函数,将对象中的 char * 暴露给外界?
  • 没错,您创建的额外func 包装器将char * 暴露给外部世界,同时处理内部的VirtualInternalString& 对象。
  • @passenger 没错!更准确地说,您需要将VirtualInternalString& 中的数据复制 到C# 提供的缓冲区中。不要忘记检查缓冲区长度!
  • @passenger 很高兴为您提供帮助,如果此答案解决了您的问题,请单击答案旁边的复选标记将其标记为已接受。请参阅:How does accepting an answer work? 了解更多信息
【解决方案2】:

在这种情况下,我认为使用 C++/CLI 确实有意义。您可能希望在本地 C++ DLL 和您的 C# 代码之间构建一个小型 C++/CLI 桥。

C++/CLI 层负责将您自定义的 C++ 字符串类作为 DLL 函数的输出参数,并将此自定义字符串转换为 C#/.NET 字符串对象。

您的自定义 C++ 字符串类似乎包含 std::string;另一方面,C#/.NET 字符串使用 Unicode UTF-16 作为其文本编码,因此您可能需要在 Unicode UTF-8(存储在 std::string 和您的自定义字符串类中)和 UTF-16(对于C#/.NET 字符串)。

同样,您还需要在此 C++/CLI 桥接层中将 C# UTF-16 字符串转换为 UTF-8,并将这些 UTF-8 编码的字符串作为您的 const char* 输入参数传递给本机 DLL 函数。

【讨论】:

  • 您介意展示一些简单的代码结构吗?那会很棒。
  • 是的,非常感谢你们所有人!我现在有一些线索,正在尝试 C++/CLI 桥以公开 const char*
  • @passenger:对于 Unicode 编码转换,您可能会发现 this MSDN article 很有趣。此外,也请看看这个marshaling library。
  • 非常感谢! C++/CLI 桥运行得非常好,尽管我们后来遇到了函数指针一些其他障碍。现在都解决了!
【解决方案3】:

使用 C++ COM 并使用 C# 代码。仅当您在 Windows 平台上时。

【讨论】:

    【解决方案4】:

    在过去的经验中,我确实使用 SWIG 工具来实现生成包装器 它支持 C++ 将生成包装到多种语言,其中 Java 是最流行的一种 有一个很棒的教程 - http://www.swig.org/tutorial.html 还支持 C# - http://www.swig.org/Doc3.0/CSharp.html

    /* InternalLib.i */
    %module InternalLib
    %{
    /* include header with a VirtualInternalString class*/
    #include "InternalLib.h"
    %}
    

    然后调用swig生成包装文件:

    swig -csharp InternalLib.i
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-07-13
      • 1970-01-01
      • 2018-11-09
      • 2016-09-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多