简体   繁体   English

将结构数组从C#(。NET Core)传递到C ++(未使用)

[英]Passing Array of Structures from C#(.NET Core) to C++(unamnaged)

So I've read the documentation and countless examples online how to marshal array of structures. 因此,我在线阅读了文档和无数示例,说明如何编排结构数组。 I've marshalled array of int's, I've marshalled structures, but now I'm completely stuck and can't get it to work no matter what I've try. 我已经整理了一些int数组,我已经整理了结构,但是现在我完全陷入了困境,无论我如何尝试都无法使其正常工作。 Been stuck on it for over a day now. 现在被卡住了一天以上。

Structure/class, tried as both 结构/类,两者都尝试过

    [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 and call delegate 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()
    {

    }
}

Call 呼叫

      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++ exposed call 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);

Path to destination gets passed properly, but array of structures never goes through resulting in access violation when trying to access it. 到目的地的路径已正确传递,但是结构数组从未尝试通过,因此在尝试访问它时会导致访问冲突。 At first I thought it was issue with LPTSTR not going through properly but I've implemented other calls with it on its own and succeeded marshalling it through. 起初,我认为LPTSTR的处理不正确是一个问题,但我自己实施了其他调用,并成功地将其编组。

I've read everything on https://docs.microsoft.com/en-us/dotnet/framework/interop/marshaling-data-with-platform-invoke , it all indicates that my approach is correct, but it doesn't work. 我已经阅读了https://docs.microsoft.com/zh-cn/dotnet/framework/interop/marshaling-data-with-platform-invoke上的所有内容,都表明我的方法是正确的,但事实并非如此工作。

Any help is appreciated. 任何帮助表示赞赏。

Simple solution: C side change PLOG_SAVE_DETAILS ppLogs [] to LOG_SAVE_DETAILS ppLogs [] , then C#-side change public class SaveDetails to public struct SaveDetails . 简单的解决方案:C侧将PLOG_SAVE_DETAILS ppLogs []更改为LOG_SAVE_DETAILS ppLogs [] ,然后C#侧将public class SaveDetails更改为public struct SaveDetails

Marshaling array of objects seems to be difficult (I wasn't able to do it). 整理对象数组似乎很困难(我无法做到)。 Marshaling array of structs works. 编组结构体的工作原理。 An alternative is to do the marshaling manually, but it is a pain. 另一种方法是手动进行封送处理,但这很麻烦。

The "pain" of manual marshaling (only modified lines of code): 手动封送处理的“痛苦”(仅修改的代码行):

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

and then 接着

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;
}

Important: this is a marshaler C#->C++. 重要说明:这是封送处理程序C#-> C ++。 The C++ mustn't modify the received array in any way or there will be a memory leak. C ++不得以任何方式修改接收到的数组,否则会发生内存泄漏。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM