簡體   English   中英

將結構數組從C#(。NET Core)傳遞到C ++(未使用)

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

因此,我在線閱讀了文檔和無數示例,說明如何編排結構數組。 我已經整理了一些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/zh-cn/dotnet/framework/interop/marshaling-data-with-platform-invoke上的所有內容,都表明我的方法是正確的,但事實並非如此工作。

任何幫助表示贊賞。

簡單的解決方案:C側將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 ++不得以任何方式修改接收到的數組,否則會發生內存泄漏。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM