Передача массива структур из C # (.NET Core) в C ++ (без изменений)

Итак, я прочитал документацию и бесчисленные примеры онлайн, как собрать множество структур. Я собрал массив int, я собрал структуры, но теперь я полностью застрял и не могу заставить его работать, что бы я ни пытался. Застрял на нем больше суток.

Структура / класс, пробовал как оба

    [StructLayout(LayoutKind.Sequential,CharSet = CharSet.Unicode)]
public class SaveDetails
{
[MarshalAs(UnmanagedType.LPWStr)]
public string Log;
public FILETIME FileTime;
[MarshalAs(UnmanagedType.Bool)]
public bool Saved;
}

Pinvoke и вызов делегата

public class LogSaveFiles : IDisposable
{
[UnmanagedFunctionPointer(CallingConvention.Winapi,CharSet = CharSet.Unicode)]
private delegate Status DLogSaveFiles([ In, Out] SaveDetails[] logsToSave, string destinationPath);
private static DLogSaveFiles _dLogSaveFiles;

private IntPtr PLogSaveFiles { get; set; }
public bool LogSaveFilesAvailable => PLogSaveFiles != IntPtr.Zero;

public LogSaveFiles(Importer importer)
{
if (importer.dllLibraryPtr!= IntPtr.Zero)
{
PLogSaveFiles = Importer.GetProcAddress(importer.dllLibrary, "LogSaveFiles");
}
}

public Status SaveFiles(SaveDetails[] logsToSave,string destinationPath)
{
Status result = Status.FunctionNotAvailable;

if (LogSaveFilesAvailable)
{
_dLogSaveFiles = (DLogSaveFiles)Marshal.GetDelegateForFunctionPointer(PLogSaveFiles, typeof(DLogSaveFiles));

result = _dLogSaveFiles(logsToSave, destinationPath);
}

return result;
}

public void Dispose()
{

}
}

Вызов

      private void SaveLogs()
{
var logsToSave = new[]{
new SaveDetails{
FileTime = new FILETIME {dwHighDateTime = 3,dwLowDateTime = 5},
Log = LogTypes.logDeviceLog,
Saved = true},
new SaveDetails{
FileTime = new FILETIME {dwHighDateTime = 1,dwLowDateTime = 2},
Log = LogTypes.logDeviceLog,
Saved = false}
};

var pathToSave = "C:\\Logs";
_logSaveFiles.SaveFiles(logsToSave, pathToSave);
}

открытый вызов c ++

    typedef struct _LOG_SAVE_DETAILS
{
LPTSTR      szLog;
FILETIME    fromFileTime;
BOOL        bSaved;
} LOG_SAVE_DETAILS, *PLOG_SAVE_DETAILS;/* Function definitions */

ULY_STATUS _API LogSaveFiles (PLOG_SAVE_DETAILS   ppLogs [],
LPCTSTR                szDestinationPath);

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

Я прочитал все на https://docs.microsoft.com/en-us/dotnet/framework/interop/marshaling-data-with-platform-invoke , все это говорит о том, что мой подход правильный, но он не работает.

Любая помощь приветствуется.

0

Решение

Простое решение: Смена стороны PLOG_SAVE_DETAILS ppLogs [] в LOG_SAVE_DETAILS ppLogs []затем изменение C # стороны public class SaveDetails в public struct SaveDetails,

Маршалинг множества объектов кажется трудным (я не смог этого сделать). Маршалинг массив конструкций работает. Альтернатива состоит в том, чтобы сделать маршалинг вручную, но это боль.

«Боль» ручного маршалинга (только модифицированные строки кода):

[UnmanagedFunctionPointer(CallingConvention.Winapi, CharSet = CharSet.Unicode)]
private delegate Status DLogSaveFiles(IntPtr[] logsToSave, string destinationPath);

а потом

public Status SaveFiles(SaveDetails[] logsToSave, string destinationPath)
{
Status result = Status.FunctionNotAvailable;

if (LogSaveFilesAvailable)
{
if (_dLogSaveFiles == null)
{
_dLogSaveFiles = (DLogSaveFiles)Marshal.GetDelegateForFunctionPointer(PLogSaveFiles, typeof(DLogSaveFiles));
}

int size = Marshal.SizeOf(typeof(SaveDetails));

IntPtr basePtr = IntPtr.Zero;
IntPtr[] ptrs = new IntPtr[logsToSave.Length + 1];

try
{
basePtr = Marshal.AllocHGlobal(size * logsToSave.Length);

for (int i = 0; i < logsToSave.Length; i++)
{
ptrs[i] = IntPtr.Add(basePtr, (i * size));
Marshal.StructureToPtr(logsToSave[i], ptrs[i], false);
}

result = _dLogSaveFiles(ptrs, destinationPath);
}
finally
{
if (basePtr != IntPtr.Zero)
{
for (int i = 0; i < logsToSave.Length; i++)
{
if (ptrs[i] != IntPtr.Zero)
{
Marshal.DestroyStructure(ptrs[i], typeof(SaveDetails));
}
}

Marshal.FreeHGlobal(basePtr);
}
}
}

return result;
}

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

1

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector