C # pinvoke структура маршаллинга, связывающая вектор <structure> - PullRequest
2 голосов
/ 20 января 2011

Мне нужно вызвать функцию, которая возвращает структуру, которая содержит int и вектор других структур в C # для проекта windows ce 6.0:

Функция предоставляется сторонним поставщиком(Китайский производитель КПК), и они доставили мне только файлы .h, dll и lib.

Функция, которую я пытаюсь вызвать в C #, определена в файле .h как:

DLLGSMADAPTER ApnInfoData* GetAvailApnList();

структура ApnInfoData выглядит следующим образом:

typedef struct ApnInfoData
{
    int m_iDefIndex;
    ApnInfoArray m_apnList;
}

typedef struct ApnInfo
{
    DWORD m_dwAuthType;
    TCHAR m_szName[64];
    TCHAR m_szTel[32];
    TCHAR m_szUser[32];
    TCHAR m_szPassword[32];
    TCHAR m_szApnName[32];
}*LPAppInfo;

typedef vector<ApnInfo> ApnInfoArray;

DLLGSMADAPTER представляет собой

#define DLLGSMADAPTER _declspec(dllexport)

Мой вопрос заключается в том, как я могу выполнить эту функцию в .net cf, поскольку он использует векторный класс, и я не знаю, как это упорядочить.

Ответы [ 2 ]

3 голосов
/ 20 января 2011

Это невозможно. P / Invoke предназначен только для типов C. У вас есть несколько вариантов:

  • Используйте C ++ / CLI для создания управляемой оболочки вокруг вашей библиотеки C, а затем используйте ее из C #
  • Напишите обертку C вокруг ваших типов C ++, а затем P / Invoke обертку C
  • Напишите оболочку COM вокруг типов C ++, а затем сгенерируйте заглушку взаимодействия.

Самая базовая оболочка C вокруг этого будет выглядеть примерно так:

// creates/loads/whatever your vector<ApnInfo> and casts it to void*, and then returns it through 'handle'
int GetAppInfoHandle(void **handle);

// casts handle back to vector<ApnInfo> and calls .size()
int GetAppInfoLength(void *handle);   

// Load into 'result' the data at ((vector<ApnInfo>*)handle)[idx];
void GetAppInfo(void *handle, int idx, ApnInfo *result);  
1 голос
/ 14 апреля 2013

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

Основная идея создания экземпляра объекта 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)

...