C# 如何从C++;C语言中的动态链接库# 我想用C++中的DLL函数用C语言来实现。

C# 如何从C++;C语言中的动态链接库# 我想用C++中的DLL函数用C语言来实现。,c#,c++,pinvoke,C#,C++,Pinvoke,我将字符串数据存储在向量中 我的C++文件包含: #include "stdafx.h" #include <stdlib.h> #include <stdio.h> #include <string.h> extern "C" __declspec(dllexport) std::vector<std::string> GetProduct(); std::vector<std::string&g

我将字符串数据存储在向量中

我的C++文件包含:

#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

extern "C" __declspec(dllexport) std::vector<std::string> GetProduct();

std::vector<std::string> GetProduct()
{
  std::vector<std::string> vectProduct;
  vectProduct.push_back("Citroen");
  vectProduct.push_back("C5");
  vectProduct.push_back("MOP-C5");
  return vectProduct;
}
我不知道如何继续在c#中浏览数组。 我不知道向量的使用是否最优。如果你有别的解决办法,我准备好了


请帮助。

我最喜欢的传递字符串数组C++-->C#的方法是使用委托

C#:

然后

var lst = new List<string>();

TestReturnArrayStrings(lst.Add);

foreach (string str in lst)
{
    Console.WriteLine(str);
}
var lst=newlist();
TestReturnArrayStrings(lst.Add);
foreach(lst中的字符串str)
{
控制台写入线(str);
}
和C++:

#include <string>
#include <vector>

extern "C"
{
    __declspec(dllexport) void TestReturnArrayStrings(void (add)(const char* pstr))
    {
        std::string str1 = "Hello";
        std::string str2 = "World";

        add(str1.data());
        add(str2.data());

        // Example with std::vector

        add("--separator--"); // You can even use C strings

        std::vector<std::string> v = { "Foo", "Bar" };

        // for (std::vector<std::string>::iterator it = v.begin(); it != v.end(); ++it)
        for (std::vector<std::string>::const_iterator it = v.begin(); it != v.end(); ++it)
        {
            add(it->data());
        }

        add("--separator--"); // You can even use C strings

        // With C++ 11

        // for (auto& it: v)
        for (const auto& it: v)
        {
            add(it.data());
        }
    }
}
#包括
#包括
外部“C”
{
__declspec(dllexport)void TestReturnArrayStrings(void(add)(const char*pstr))
{
std::string str1=“你好”;
std::string str2=“世界”;
添加(str1.data());
添加(str2.data());
//std::vector示例
add(“--separator--”;//您甚至可以使用C字符串
向量v={“Foo”,“Bar”};
//对于(std::vector::iterator it=v.begin();it!=v.end();++it)
对于(std::vector::const_迭代器it=v.begin();it!=v.end();+it)
{
添加(it->data());
}
add(“--separator--”;//您甚至可以使用C字符串
用C++ 11
//用于(自动和it:v)
用于(const auto&it:v)
{
添加(it.data());
}
}
}

这里的“技巧”是C++向C++代码委托到“代码>列表”。C++所管理的内存保留在C++端,由C管理的内存保留在C端。没有跨内存所有权的问题。可以想象,将“技巧”扩展到任何其他

.Add()
方法,如
HashSet
Dictionary
,都非常容易


作为旁注,我创建了一个包含许多关于在C/C++和C#(包括.NET Framework和.NET Core/5.0)之间封送处理的示例的应用程序。

一种方法是使用.NET支持的COM(p/Invoke使用的.NET分配器是COM分配器),包括大多数相关的子类型,如

因此,在C/C++中,您可以定义:

extern "C" __declspec(dllexport) LPSAFEARRAY GetProduct();

LPSAFEARRAY GetProduct()
{
    LPSAFEARRAY psa = SafeArrayCreateVector(VT_BSTR, 0, 3);
    LONG index = 0;

    // _bstr_t is a smart class that frees allocated memory automatically
    // it needs #include <comdef.h>
    // but you can also use raw methods like SysAllocString / SysFreeString

    _bstr_t s0(L"Citroen"); // could use "Citroen" if you really want ANSI strings

    // note SafeArrayPutElement does a copy internally
    SafeArrayPutElement(psa, &index, s0.GetBSTR());
    index++;

    _bstr_t s1(L"C5");
    SafeArrayPutElement(psa, &index, s1.GetBSTR());
    index++;

    _bstr_t s2(L"MOP - C5");
    SafeArrayPutElement(psa, &index, s2.GetBSTR());
    index++;
    return psa;
}
[DllImport("ProductLibrary.dll", CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.SafeArray)]
public static extern string[] GetProduct();

不要试图从DLL中移植C++数据结构,编译为其他项目。C++没有定义良好的ABI,什么意思,这是定义的未定义行为。首先:正如本文所述,您要么导出一个C接口,要么使用其他技术,如COM或C++/CLI。。。作为旁注,对于
std::vector
std::string
来说,您可以为内部“数据”获取一个C指针,但是如果您将它们“混合”在一起,那么一切都会变得一团糟……另一个问题是:如果内存是从C/C++端分配的,那么释放它通常很复杂。。。但最大的问题是为什么你要尝试混合两种语言,这两种语言本身是完整的。。。学滑翔或者学滑冰。不要试图同时做这两件事,除非真的有必要。有没有可能使用另一种方法来存储字符串数据并在C#please中获取它。我尝试创建另一个返回类型为int*的函数。我还使用IntPtr获取ptr的数据。但我并不是为字符串类型而来的。@正确的一切都可以完成。在风险和回报之间总是有一个交易。嗨,西蒙,谢谢你的回答,但是我在你的暗示中,没有为C++代码定义一个错误。我可以包括什么来解决这个问题呢?我可以用oaidl.h试试。
extern "C" __declspec(dllexport) LPSAFEARRAY GetProduct();

LPSAFEARRAY GetProduct()
{
    LPSAFEARRAY psa = SafeArrayCreateVector(VT_BSTR, 0, 3);
    LONG index = 0;

    // _bstr_t is a smart class that frees allocated memory automatically
    // it needs #include <comdef.h>
    // but you can also use raw methods like SysAllocString / SysFreeString

    _bstr_t s0(L"Citroen"); // could use "Citroen" if you really want ANSI strings

    // note SafeArrayPutElement does a copy internally
    SafeArrayPutElement(psa, &index, s0.GetBSTR());
    index++;

    _bstr_t s1(L"C5");
    SafeArrayPutElement(psa, &index, s1.GetBSTR());
    index++;

    _bstr_t s2(L"MOP - C5");
    SafeArrayPutElement(psa, &index, s2.GetBSTR());
    index++;
    return psa;
}
[DllImport("ProductLibrary.dll", CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.SafeArray)]
public static extern string[] GetProduct();