Маршалинг строит со строками и массивами из управляемого в неуправляемый код
У меня есть простая структура данных C# со строкой, int и вектором int:
class MyManagedClass
{
public string m_Str;
int m_Int;
int[] m_IntArray;
}
Эквивалент в C++:
struct myUnmanagedStruct
{
char* m_Str;
UINT m_Int;
UINT* m_IntArray;
}
У меня есть неуправляемая функция, которая создает массив структур myUnmanagedStruct. Каков наилучший способ написать управляемую оболочку, которая правильно упорядочивает данные таким образом, чтобы то, что создается на неуправляемой стороне, правильно передавалось обратно на управляемую сторону? (т.е. я хочу сделать массив объектов MyManagedClass из массива MyUnmanagedStructs)
Замечания:
а) Строка создается в неуправляемой структуре
б) вектор целых создается в неуправляемой структуре
Моя лучшая попытка на данный момент:
На управляемой стороне:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack=1)]
public class MyManagedClass
{
public MyManagedClass()
{
m_IntArray = new int[4];
}
public String m_Str;
public int m_Int;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public int[] m_IntArray;
}
[StructLayout(LayoutKind.Sequential)]
public struct UnsafeLCEArray
{
public int m_Int;
public IntPtr m_CharBuf;
public IntPtr m_IntBuf;
}
public unsafe class LibWrap
{
// Declares managed prototypes for the unmanaged function.
[DllImport("mydll.dll", EntryPoint = "GetUnmanagedStructs")]
public static extern voidGetUnmanagedStructs(out int size, out IntPtr outArray);
}
На неуправляемой стороне:
typedef struct _MyUnmanagedStruct
{
char* m_Str;
UINT m_Int;
UINT* m_IntArray;
} MyUnmanagedStruct;
typedef struct _UNSAFELCEARRAY
{
char* strBuf;
UINT intBuf;
UINT* intArrayBuf;
} UNSAFELCEARRAY;
extern "C" __declspec(dllexport) void GetUnmanagedStructs( int* pSize, UNSAFELCEARRAY** ppStruct )
{
const int cArraySize = 5;
*pSize = cArraySize;
int numBytes = cArraySize * sizeof( MyUnmanagedStruct);
*ppStruct = (UNSAFELCEARRAY*)CoTaskMemAlloc(numBytes);
UNSAFELCEARRAY* pCurStruct = *ppStruct;
char* typenamebuffer;
char* numBuffer;
int var = 999;
for( int i = 0; i < cArraySize; i++, pCurStruct++ )
{
pCurStruct->intBuf = i+1;
typenamebuffer = (char*)CoTaskMemAlloc( 8 );
memcpy_s(typenamebuffer, 8, "bufABCD", 8);
pCurStruct->strBuf = typenamebuffer;
numBuffer = (char*)CoTaskMemAlloc( 16 );
++var;
memcpy_s(numBuffer, 4, &var, 4);
++var;
memcpy_s(numBuffer+4, 4, &var, 4);
++var;
memcpy_s(numBuffer+8, 4, &var, 4);
++var;
memcpy_s(numBuffer+12, 4, &var, 4);
pCurStruct->intArrayBuf = (UINT*)numBuffer;
}
}
Все работает, если я удаляю вектор целых из управляемых и неуправляемых объектов, но с кодом выше массив целых по возвращаемому неинициализируется. Я использую функцию ниже для генерации MyManagedClasses из MyUnmanagedStructs
int size;
IntPtr outArray;
LibWrap.GetUnmanagedStructs(out size, out outArray);
manArray = new MyManagedClass[size];
IntPtr current = outArray;
for (int i = 0; i < size; i++)
{
manArray[i] = new MyManagedClass();
Marshal.PtrToStructure(current, manArray[i]);
Marshal.DestroyStructure(current, typeof(sb_LCE));
int numBytes = Marshal.SizeOf(manArray[i]);
current = (IntPtr)((long)current + numBytes);
}
Marshal.FreeCoTaskMem(outArray);
Простите за длинное объяснение и тот факт, что неуправляемая стойка заполняется фиктивными значениями. Это только для иллюстрации.