Как я могу получить карту <string, int> из C ++ в C # - PullRequest
0 голосов
/ 30 октября 2018

Я пытаюсь получить карту из DLL C ++ Поэтому я должен получить карту и проанализировать ее как словарь на стороне C #. Я попытался сделать ниже шаги, и это не сработало.

C ++ код:

extern "C" __declspec(dllexport) map<string, int> createMap(string &fileName) {
    ifstream infile(fileName);
    vector<string> bitsLine;
    bool headerEnded = false;
    string line;
    int i = 0;
    int length = 0;

    while (getline(infile, line)) {
        if (headerEnded) {
            bitsLine = split(line, ',');
            signalsMap.insert({ bitsLine.at(0), length });
        }
        else {
            if (line.find("HEADER_END") != std::string::npos) {
                headerEnded = true;
            }
        }
        length = infile.tellg();
        i++;
    }
    return signalsMap;
}

C # код:

Dictionary<string, int>  x =  createMap("C:/users/asalah/source/repos/WindowsFormsApp3/WindowsFormsApp3/RR_Test2_3.csv");

1 Ответ

0 голосов
/ 30 октября 2018

Простой ответ на этот вопрос, к сожалению, «вы не должны». Во-первых, вы не должны экспортировать типы STL из dll, тем более пытаться упорядочить их в C #. Тип STL может варьироваться в разметке памяти от компилятора к компилятору, от времени выполнения C ++ до времени выполнения C ++. Это может вызвать очень хрупкий код. Поэтому, если вы экспортируете функцию C, она должна взять const char* вместо std::string, например.

То, что вы могли бы сделать, это просто маршалировать каждый ключ и значение по мере их появления. Преимущество этого в том, что вам не нужно выполнять какую-либо работу с управлением памятью, и это довольно просто интегрировать в то, что у вас уже есть, хотя я не делаю никаких заявлений о производительности.

Вот краткий пример C ++ и C #, который поможет вам найти такое решение, если оно вам поможет:

extern "C" __declspec(dllexport) void doFoo(void(*adder)(const char*, int32_t))
{
    adder("Test", 346);
}

Ниже приведен код C # для использования этого API. Нужно просто добавить «Test» со значением 346 в словарь и ничего более. Это делается путем вызова функции обратного вызова, которая является родной оболочкой для Dictionary.Add для указанного экземпляра словаря.

namespace Eff3
{
    using System.Collections.Generic;
    using System.Runtime.InteropServices;

    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    delegate void DictionaryAdd(string key, int value);

    class Program
    {
        [DllImport("TestDll", CallingConvention = CallingConvention.Cdecl)]
        static extern void doFoo(DictionaryAdd callback);

        static void Main()
        {
            var result = new Dictionary<string, int>();
            doFoo(result.Add);
        }
    }
}

Я проверил это на своей машине и собрал DLL в Visual C ++ 2017 в x64 и отключил «Предпочитать 32-битную» в C #.

...