Маршал C ++ "строковый" класс в C # P / Invoke - PullRequest
7 голосов
/ 01 октября 2008

У меня есть функция в нативной DLL, определяемая следующим образом:

#include <string>
void SetPath(string path);

Я пытался поместить это в Microsoft P / Invoke Interop Assistant, но он задыхается от класса "string" (который, я думаю, из MFC?).

Я пытался маршалировать его как различные типы (C # String, char [], byte []), но каждый раз, когда я получаю исключение NotSupportedException или Native Assembly (в зависимости от того, какой маршалинг я пробовал).

Как кто-нибудь когда-либо делал Native / Managed Interop, где используется нативный класс строки? Есть ли способ маршала это? Я собираюсь написать свой собственный Marshaler?

Ответы [ 3 ]

6 голосов
/ 01 октября 2008

Похоже, вы пытаетесь использовать стандартный строковый класс библиотеки C ++. Я сомневаюсь, что маршалу будет легко. Лучше придерживаться символа * и маршала как StringBuilder. Это то, что я обычно делаю. Вам нужно будет добавить оболочку, которая генерирует для вас строку C ++.

2 голосов
/ 01 октября 2008

Помощник взаимодействия PInvoke поддерживает только C, а не C ++. К сожалению, класс MFC String (CString, я полагаю?) Является C ++ и не будет работать через помощника. Вместо этого попробуйте использовать следующее

void SetPath(__in const WCHAR* path);
0 голосов
/ 15 апреля 2013

Да. Вы можете. На самом деле, не только std::string, std::wstring, любой стандартный класс C ++ или ваши собственные классы можно маршалировать или создавать и вызывать из 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)

Если у вас есть готовый класс-оболочка C # для вашего класса C ++, можно легко реализовать ICustomMarshaler, чтобы вы могли маршалировать объект C ++ из .NET.

http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.icustommarshaler.aspx

...