Может ли указатель быть маршалированным в массив при передаче структуры? - PullRequest
0 голосов
/ 25 декабря 2018

В приведенном ниже примере dataArray, определенный в C ++, работает, если он определен как массив, но не как указатель (просто выдает мусорные данные).Есть ли другой способ упорядочить массив C #, чтобы он считывал указатель как массив?

C #

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct CSharpFoo{
    int alpha;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5]
    public int[] dataArray;
    int beta;
}

C ++

struct CPPFoo{
    int alpha;
    //int* dataArray; //Doesn't work, even though initialized to an array elsewhere
    int dataArray[5];
    int beta;
}

Передается черезфункция, подобная этой
C #

[DllImport("MyDll.dll", CallingConvention = CallingConvention.Cdecl, BestFitMapping = false, ThrowOnUnmappableChar = true)]
public extern static bool InitializeDLL([MarshalAs(UnmanagedType.FunctionPtr)] ResultCallback callbackPointer);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void ResultCallback(CSharpFoo value);

C ++

//Callback
typedef void(__stdcall * ResultCallback)(CPPFoo);
__declspec(dllexport) bool InitializeDLL(ResultCallback callback);

Заранее спасибо!

Edit :: Потому что "инициализирован в массив в другом месте" не былоясно:

CPPFoo(int dummy){ //Constructor
    alpha = 32;
    dataArray = new int[5];
    for (int i = 0; i < 5; i++){
        dataArray[i] = i;
    }
    beta = 13;
}
//dataArray C++ {0,1,2,3,4}
//alpha C# 32
//dataArray C# {Total random garbage} (dataArray[3] is 13!)
//beta C# 0

PS, структура CPPFoo является сложной структурой, которая приходит из DLL, поэтому я не могу ее изменить.Сейчас, чтобы все заработало, я копирую его в более подходящий массив, как в ответе NonCreature0714, но это приводит к тому, что все данные копируются - дважды.Именно эту двойную копию я стараюсь избегать.

Еще одно редактирование: хотя кажется, что для структуры, содержащей один массив, значения передаются правильно, для сложной структуры мусор выбрасывается. У меня естьобновил код, чтобы отразить более сложную структуру!

Ответы [ 3 ]

0 голосов
/ 25 декабря 2018

Используйте вектор.

#include <vector>

struct CPPFoo {
    std::vector<int> dataArray;
};

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

0 голосов
/ 25 декабря 2018

Я провел пару тестов на своей локальной машине, насколько я понял ваш код.У меня не было проблем со следующим кодом

c # side

struct Foo
{
    public int alpha;

    public IntPtr Data;

    public int beta;

    public void GetData(ref int[] buffer,int length)
    {
        Marshal.Copy(Data,buffer,0,length);
    }

}

Программа класса {

    [DllImport("MyPtr.dll",EntryPoint = "InitializeDLL", CallingConvention = CallingConvention.Cdecl)]
    public static extern bool InitializeDLL([MarshalAs(UnmanagedType.FunctionPtr)]ResultCallback callbackPointer);

    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
    public delegate void ResultCallback(ref Foo value);

    static void CallBackMe(ref Foo value)
    {
        var buffer = new int[5];
        value.GetData(ref buffer,buffer.Length);
    }
    static void Main(string[] args)
    {
        InitializeDLL(CallBackMe);
    }
}

C ++ side

struct CPPFoo {
    int* dataArrayPtr;
    CPPFoo()
    {
        dataArrayPtr = new int[5];
        for (int i = 0; i < 5; i++) {
            dataArrayPtr[i] = i;
        }
    }
};

typedef void(__stdcall * ResultCallback)(CPPFoo);
extern "C" __declspec(dllexport) bool InitializeDLL(ResultCallback callback)
{
    CPPFoo f;
    callback(f);
    return true;
}

Код вдействие enter image description here

0 голосов
/ 25 декабря 2018

Мой опыт работы с C # очень ограничен, но кажется, что он работает с int dataArray [5]; , потому что код соответствует типу CSharpFoo и CPPFoo.Размер обоих составляет пять дюймов.Когда вы изменяете тип на указатель, то один имеет размер пять дюймов, а другой - один указатель, который будет меньше пяти дюймов.

Скорее всего, для передачи массива динамического размера потребуется размер иполучить указатель, вам может понадобиться что-то сделать с небезопасным кодом, но я не пишу на C #, так что это всего лишь предположение.

struct CPPFoo {
    int* dataArray = nullptr;
    int size = 0;
}
...