将 C++ 数组返回到 C#

Posted

技术标签:

【中文标题】将 C++ 数组返回到 C#【英文标题】:Return C++ arrays to C# 【发布时间】:2012-02-18 10:18:21 【问题描述】:

我正在尝试一个小型互操作应用程序,其中我正在从 C# 调用一些 C++ 方法。我有一个非常基本的示例,用于调用方法并返回一个整数,效果很好。

InteropApp.h

#ifdef DLLFUNCTIONEXPOSETEST_EXPORTS
#define DLLFUNCTIONEXPOSETEST_API __declspec(dllexport)
#else
#define DLLFUNCTIONEXPOSETEST_API __declspec(dllimport)
#endif

extern "C" DLLFUNCTIONEXPOSETEST_API int fnSumofTwoDigits(int a, int b);

InteropApp.cpp

#include "stdafx.h"
#include "DLLFunctionExposeTest.h"
BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )

    return TRUE;

DLLFUNCTIONEXPOSETEST_API int fnSumofTwoDigits(int a, int b)

    return a + b;

C# InteropAppTest

static class TestImport
    
        [DllImport("DLLFunctionExposeTest.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "fnSumofTwoDigits")]
        public static extern int fnSumofTwoDigits(int a, int b);
    
public partial class MainWindow : Window
    
        public MainWindow()
        
            try
            
            InitializeComponent();
            int g = TestImport.fnSumofTwoDigits(2, 1);
        
        catch (Exception ex)
        
            MessageBox.Show(ex.ToString());
        
    

在上面的 C++ 应用程序中,我想要一个方法返回 strings 的数组,而另一种方法返回 integers 的数组。但是,正如我读过的那样,我很困惑这是否涉及编组? C++ 和 C# 的方法原型是什么样的?在 C# 应用程序中调用 c++ 数组返回函数还有什么变化?

为上述事情提供一个简单的例子会很棒,因为我找不到任何简单的例子。

【问题讨论】:

你试过什么?你到底指的是什么类型? std::string(或char*?)和int?还是没关系? @svick:我更愿意从 char*int 数组返回方法开始。 【参考方案1】:

为此推荐的方法是使用中间 C++/CLI 项目(也称为隐式 P/Invoke 技术)。对涉及使用 stl 容器或复杂类的任何事情执行显式 P/Invoke (DllImport) 可能会令人沮丧或不可能。此外,它的类型不安全:您必须猜测正确的签名才能进行编组,并且通常有多种可能可行,这可能会令人困惑。 C++(stl) 和 CLR 中字符串的内部表示根本不匹配,因此您必须在它们之间进行转换,这会导致显式 P/Invoke 编组很痛苦。

推荐的方式如下。请注意,我没有编译代码,所以可能会出现一些小错误,但我可以向您保证可以通过这种方式完成:我已经完成了很多次。

假设你在一个 DLL 原生项目(头文件 Utils.h)中有这个:

DLLFUNCTIONEXPOSETEST_API std::vector<std::string> GetStrings();

请注意,了解这些字符串在 c++ stl::string 中的内部编码方式很重要(例如 UTF-8,如果你很酷的话):

现在您创建一个 CRL C++ 项目(UtilsW.h/UtilsW.cpp 对):

#include <Utils.h>

using namespace std;
using namespace System;
using namespace System::Text;
using namespace System::Collections::Generics;

namespace Interop

    public ref class Utils
    
    public:
        static List<String ^> ^ GetStrings()
        
            List<String ^> ^ret = gcnew List<String ^>();
            vector<string> strings = ::GetStrings();
            vector<string>::iterator begin = strings.begin();
            vector<string>::iterator end = strings.end();
            for (; it != end; it++)
                ret.Add(gcnew String((*it).c_str(), 0, (*it).lenght(), Encoding::UTF-8);
            return ret;
        
    ;

现在您可以使用 C# 创建一个 .NET 项目:

using Interop;

namespace NET

    public class Program
    
        void foo()
        
            List<string> strings = Utils.GetStrings();
            // Do something with strings
        
    

【讨论】:

他似乎并不真正需要“stl 容器或复杂类”,所以 PInvoke 在这里可能是一种更简单的方法。【参考方案2】:

如果您不必在 C++ dll 中分配数组,您可以将一个空整数数组传递给函数并让它填充在那里。这适用于默认编组。

但是,您不能将 std::string 编组为 C#,因为此类未知。您必须将字符串作为 C 字符串传递,最好是 wchar_t*。

见:http://msdn.microsoft.com/en-us/library/bd99e6zt.aspx

【讨论】:

以上是关于将 C++ 数组返回到 C#的主要内容,如果未能解决你的问题,请参考以下文章

嵌入式单声道:将数组从 C# DLL 返回/复制到 C++

从 C# 到 C++ 并返回的数组,没有不安全的代码 [重复]

如何将结构数组从 c++ 传递到 c#?

从我的 c++ 应用程序调用 c# dll(解析 XML 文件)以将数组/列表返回给 c++

当 C# 调用 c++ 函数时,是不是可以在被调用的 c++ 函数中初始化数组并返回到 C#?

将对象数组从 C# 返回到 COM 中的 C