Взаимодействие С#/С++ - нужна помощь в определении моей структуры данных

Я работаю над приложением С#, которое пытается использовать функциональные возможности, предоставляемые через DLL С++. Мне немного трудно заставить определения DLLImport работать прямо сейчас.

Вот сторона C++ уравнения:

struct Result
{
    FLOAT   first;
    FLOAT   second;
};

struct ResultData
{
    UINT            uint1;
    UINT            uint2;
    Result          result;
    Result*         pResults;
};

#define DllImport __declspec(dllimport)    
extern "C"
{
    DllImport HRESULT APIENTRY Process(const PCWSTR FileName, const PCWSTR logfileFileName, const PCWSTR DataFileName, ResultData** ppResults);
    DllImport HRESULT APIENTRY Release(ResultData* pResults);
}

Что касается С#, вот что я сделал до сих пор:

    [StructLayout(LayoutKind.Sequential)]
    public struct Result
    {
        public float first;
        public float second;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct ResultData
    {
        public uint uint1;
        public uint uint2;
        public Result result;
        public Result[] Results;
    }    

        DllImport("MyDLL.dll")]
        static extern uint Release(ResultData pResults);

        [DllImport("MyDLL.dll")]
        static extern uint Process(string FileName, string logfileFileName, string DataFileName, ref ResultData ppResults);

Это правильный способ сделать это? Больше всего меня беспокоит член pResults структуры ResultData. Я не хочу, чтобы это копировалось по значению, так как это будет большой объем данных, и я не хочу копировать память... как я могу убедиться, что этого не произойдет?

Я ценю вашу помощь.


person Nazeeh    schedule 02.10.2009    source источник


Ответы (2)


Самая неотложная проблема, которая бросается мне в глаза, — член Results в ResultData. Родной тип — Result*, но вы перевели его как массив. Это может сработать, а может и не сработать (с ходу не помню). Что будет работать, так это сортировать его как тип IntPtr.

[StructLayout(LayoutKind.Sequential)]
public struct ResultData
{
    public uint uint1;
    public uint uint2;
    public Result result;
    public IntPtr RawResults;
    public Result Results { get { return (Result)Marshal.PtrToStructure(RawResults,typeof(Result)); }
} 

Предполагается, что это одно значение. Если это более одного значения, потребуется более сложная сортировка.

Также собственный метод Release принимает ResultData*, но у вас есть простой по значению тип ResultData в управляемой подписи. Он должен иметь тот же уровень косвенности. Вы можете добиться этого, сделав его параметром ref.

DllImport("MyDLL.dll")]
static extern uint Release(ref ResultData pResults);
person JaredPar    schedule 02.10.2009
comment
Хммм, одно значение == одно значение, афаик. Вы пропустили "более чем" в последнем предложении, я полагаю - person Vinko Vrsalovic; 02.10.2009
comment
@Винко, верно. Удивительно, как хорошо это читается про себя, пока кто-то не укажет на очевидное несоответствие :) - person JaredPar; 02.10.2009

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

person Dustin Getz    schedule 02.10.2009