Как собрать коллекцию в C #, чтобы перейти к нативному (C ++) коду - PullRequest
5 голосов
/ 24 февраля 2011

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

C # Side Code

List<string> lst = new List<string>();
lst.Add("1");
lst.Add("2");
lst.Add("3");
lst.Add("4");

C ++ Side Code

std::vector<std::string> vStr;

Теперь, как мне передать lst в нативный код C ++

Ответы [ 3 ]

3 голосов
/ 24 февраля 2011

Как упоминал Мзабский, вы не можете маршалировать эти типы.Однако вы можете упорядочить массив:

Теоретический экспорт C ++:

extern "C" __declspec(dllexport) void __stdcall Foo(wchar_t const* const* values, int length)
{
    // Check argument validity...

    // If you really need a vector
    std::vector<std::wstring> vStr(values, values + length);

    //...
}

Подпись P / Invoke:

[DllImport("foo.dll")]
static extern void Foo([MarshalAs(UnmanagedType.LPArray, ArraySubType=UnmanagedType.LPWStr)] string[] values, int length);

Вызов из C #:

Foo(lst.ToArray(), lst.Count);

Обратите внимание, что я использую здесь std :: wstring;вместо этого вы можете использовать char вместо wchar_t, LPStr вместо LPWStr и std :: string вместо std :: wstring.

Обратите внимание, что это выделит массив из списка, а затем вектор скопирует массивсодержание.Если исходный список имеет небольшой размер, это должно вызывать незначительную озабоченность.

Редактировать: исправление разметки (<и>).

1 голос
/ 24 февраля 2011

Вы не можете сделать это, только типы C могут быть собраны. Вам придется написать оболочку C ++ / CLI (или оболочку C вокруг вектора C ++).

См. Этот ответ.

0 голосов
/ 15 апреля 2013

Да. Вы можете. На самом деле, не только std::string, std::wstring, любой стандартный класс C ++ или ваши собственные классы можно маршалировать или создавать и вызывать из C # /. NET.

Завершение std::vector<any_type> в C # действительно возможно только с обычным P / Invoke Interop, хотя это сложно. даже std::map любого типа можно сделать в C # /. NET.

Основная идея создания экземпляра объекта C ++ из мира .NET состоит в том, чтобы выделить точный размер объекта C ++ из .NET, затем вызвать конструктор, который экспортируется из DLL C ++, для инициализации объекта, после чего вы сможете Вызовите любую из функций для доступа к этому объекту C ++, если какой-либо из методов включает другие классы C ++, вам нужно будет также обернуть их в класс C #, для методов с примитивными типами вы можете просто P / Invoke их. Если у вас есть только несколько методов для вызова, это будет просто, ручное кодирование не займет много времени. Когда вы закончите работу с объектом C ++, вы вызываете метод деструктора объекта C ++, который также является функцией экспорта. если его нет, вам просто нужно освободить память из .NET.

Вот пример.

public class SampleClass : IDisposable
{    
    [DllImport("YourDll.dll", EntryPoint="ConstructorOfYourClass", CharSet=CharSet.Ansi,          CallingConvention=CallingConvention.ThisCall)]
    public extern static void SampleClassConstructor(IntPtr thisObject);

    [DllImport("YourDll.dll", EntryPoint="DoSomething", CharSet=CharSet.Ansi,      CallingConvention=CallingConvention.ThisCall)]
    public extern static void DoSomething(IntPtr thisObject);

    [DllImport("YourDll.dll", EntryPoint="DoSomethingElse", CharSet=CharSet.Ansi,      CallingConvention=CallingConvention.ThisCall)]
    public extern static void DoSomething(IntPtr thisObject, int x);

    IntPtr ptr;

    public SampleClass(int sizeOfYourCppClass)
    {
        this.ptr = Marshal.AllocHGlobal(sizeOfYourCppClass);
        SampleClassConstructor(this.ptr);  
    }

    public void DoSomething()
    {
        DoSomething(this.ptr);
    }

    public void DoSomethingElse(int x)
    {
        DoSomethingElse(this.ptr, x);
    }

    public void Dispose()
    {
        Marshal.FreeHGlobal(this.ptr);
    }
}

Подробнее см. По ссылке ниже,

C # /. NET PInvoke Interop SDK

(я автор инструмента SDK)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...