Вернуть массивы C ++ в C # - PullRequest
       35

Вернуть массивы C ++ в C #

1 голос
/ 18 февраля 2012

Я пробую небольшое приложение взаимодействия, в котором я вызываю некоторые методы 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 #?

Было бы здорово получить простой пример для вышеупомянутой вещи, так как я не смог найти ничего простого, например, для началас.

Ответы [ 2 ]

0 голосов
/ 18 февраля 2012

Для этого рекомендуется использовать промежуточный проект C ++ / CLI (также называемый неявным P / Invoke tecnique). Выполнение явного P / Invoke (DllImport) для всего, что связано с использованием контейнеров stl или сложных классов, может быть разочаровывающим или невозможным. Более того, это небезопасный тип: вам нужно угадать правильную сигнатуру, чтобы выполнить сортировку, и часто есть несколько возможностей, которые могут работать, и это может сбивать с толку. Внутренние представления строки в 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;
        }
    };
}

Теперь вы создаете проект .NET, например, в C #:

using Interop;

namespace NET
{
    public class Program
    {
        void foo()
        {
            List<string> strings = Utils.GetStrings();
            // Do something with strings
        }
    }
}
0 голосов
/ 18 февраля 2012

Если вам не нужно выделять массив в dll C ++, вы можете передать пустой целочисленный массив функции и позволить ему заполниться там.Это работает с маршалингом по умолчанию.

Однако вы не можете маршалировать std :: string в C #, так как этот класс неизвестен.Вы должны передавать строки как строки C, предпочтительно wchar_t *.

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

...