将 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# 到 C++ 并返回的数组,没有不安全的代码 [重复]
从我的 c++ 应用程序调用 c# dll(解析 XML 文件)以将数组/列表返回给 c++