C ++ में C # से सरणी की सामग्री कैसे प्राप्त करें #

Jan 07 2021

मैं C # के साथ C ++ में DLL के फ़ंक्शन का उपयोग करना चाहता हूं।

मैं एक वेक्टर में स्ट्रिंग डेटा संग्रहीत करता हूं।

मेरी 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 # में

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Runtime.InteropServices;
namespace ConsoleApplication
{
    class Program
    {
        [DllImport("ProductLibrary.dll", CallingConvention = CallingConvention.Cdecl)]
        public static extern StringBuilder GetProduct();

        static void Main(string[] args)
        {
            StringBuilder vectProduct_impl = GetProduct();
        }
    }
}

मैं नहीं जानता कि कैसे सी # में सरणी ब्राउज़ करना जारी रखें। मुझे नहीं पता कि वेक्टर का उपयोग इष्टतम है या नहीं। अगर आपके पास कोई दूसरा उपाय है तो मैं तैयार हूं।

कृपया मदद करे।

जवाब

6 xanatos Jan 07 2021 at 00:45

तार का एक सरणी C ++ -> C # पास करने के लिए मेरा पसंदीदा तरीका एक प्रतिनिधि का उपयोग करके है।

सी#:

// If possible use UnmanagedType.LPUTF8Str
// or under Windows rewrite everything to use 
// wchar_t, std::wstring and UnmanagedType.LPWStr
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void AddAnsi([MarshalAs(UnmanagedType.LPStr)] string str);

[DllImport("CPlusPlusSide.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void TestReturnArrayStrings(AddAnsi add);

और फिर

var lst = new List<string>();

TestReturnArrayStrings(lst.Add);

foreach (string str in lst)
{
    Console.WriteLine(str);
}

और सी ++:

#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 # List<string>.Add()विधि के एक प्रतिनिधि को C ++ पास करता है , और C ++ "C" को सीधे "भरता है" List<>। C ++ द्वारा प्रबंधित मेमोरी C ++ साइड में रहती है, C # द्वारा प्रबंधित मेमोरी C # साइड में रहती है। क्रॉस-मेमोरी स्वामित्व की कोई समस्या नहीं। जैसा कि आप कल्पना कर सकते हैं, किसी भी अन्य .Add()विधि, जैसे HashSet<string>, या "ट्रिक" का विस्तार करना काफी आसान है Dictionary<string, string>

एक sidenote के रूप में, मैं एक बना लिया है GitHub C / C ++ और सी # (दोनों .नेट फ्रेमवर्क और .NET कोर / 5.0) के बीच प्रमुखता के बारे में कई उदाहरणों के साथ।

2 SimonMourier Jan 07 2021 at 05:47

ऐसा करने का एक तरीका COM की सुरक्षित संरचना का उपयोग करना है क्योंकि यह .NET द्वारा समर्थित है (पी / इनवॉइस द्वारा उपयोग किया जाने वाला .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;
}

और C # में, आप इसे परिभाषित कर सकते हैं:

[DllImport("ProductLibrary.dll", CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.SafeArray)]
public static extern string[] GetProduct();