簡體   English   中英

C# 調用 DLL function 返回指向結構數組的指針

[英]C# calling a DLL function that returns a pointer to pointer to an array of structures

我嘗試了各種方法的許多不同組合來編組此調用。 這是一個 DLL,它返回一個指向結構數組指針的指針。 像 debugPort 這樣的類型實際上是枚舉。

/**
* \struct debugConnectParameters 
* \brief Get device characterization and specify connection parameters through ST-LINK interface. 
*/ 
typedef struct debugConnectParameters { 
    debugPort dbgPort;        /**< Select the type of debug interface #debugPort. */ 
    int index;                /**< Select one of the debug ports connected. */ 
    char serialNumber[33];    /**< ST-LINK serial number. */ 
    char firmwareVersion[20]; /**< Firmware version. */ 
    char targetVoltage[5];    /**< Operate voltage. */ 
    int accessPortNumber;     /**< Number of available access port. */ 
    int accessPort;           /**< Select access port controller. */ 
    debugConnectMode connectionMode; /**< Select the debug CONNECT mode #debugConnectMode. */ 
    debugResetMode resetMode; /**< Select the debug RESET mode #debugResetMode. */ 
    int isOldFirmware;        /**< Check Old ST-LINK firmware version. */ 
    frequencies freq;         /**< Supported frequencies #frequencies. */ 
    int frequency;            /**< Select specific frequency. */ 
    int isBridge;             /**< Indicates if it's Bridge device or not. */ 
    int shared;               /**< Select connection type, if it's shared, use ST-LINK Server. */ 
} debugConnectParameters;

int getStLinkList(debugConnectParameters** stLinkList, int shared);
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
    public unsafe struct debugConnectParameters
    {
        debugPort dbgPort;                  /**< Select the type of debug interface #debugPort. */
        int index;                          /**< Select one of the debug ports connected. */
        fixed char serialNumber[33];        /**< ST-LINK serial number. */
        fixed char firmwareVersion[20];     /**< Firmware version. */
        fixed char targetVoltage[5];        /**< Operate voltage. */
        int accessPortNumber;               /**< Number of available access port. */
        int accessPort;                     /**< Select access port controller. */
        debugConnectMode connectionMode;    /**< Select the debug CONNECT mode #debugConnectMode. */
        debugResetMode resetMode;           /**< Select the debug RESET mode #debugResetMode. */
        int isOldFirmware;                  /**< Check Old ST-LINK firmware version. */
        frequencies freq;                   /**< Supported frequencies #frequencies. */
        int frequency;                      /**< Select specific frequency. */
        int isBridge;                       /**< Indicates if it's Bridge device or not. */
        int shared;                         /**< Select connection type, if it's shared, use ST-LINK Server. */
    }
    [DllImport(dllPath + "CubeProgrammer_API.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
    public unsafe extern static int getStLinkList(
        debugConnectParameters** stLinkList,
        int shared
        );

我嘗試使用“out”和“ref”選項替換。 我試圖找到它喜歡的 IntPtr 版本。 我不斷收到:System.AccessViolationException。 我已經聯系 STMicroelectronics 關於如何與這個 DLL 接口,但到目前為止他們沒有幫助。 DLL 中的調用 rest 非常簡單,但我必須讓這個開始工作,因為它是關於實際連接的 JTAG 設備的信息。

更新 (6/12/20) 以添加實際調用 function,現在調用 function 將結構從非托管結構復制到托管結構。 但是對 getStLinkList() 的調用仍然不起作用。

        public unsafe static int GetDeviceList(ref debugConnectParameters[] debugParams, int maxCount)
        {
            IntPtr unManagedListPtr = Marshal.AllocHGlobal(sizeof(debugConnectParameters*));
            IntPtr *unManagedListPtrPtr = &unManagedListPtr;
            int count = getStLinkList((debugConnectParameters**)unManagedListPtrPtr, 0);
            IntPtr copyPtr = unManagedListPtr;
            if (count > maxCount) count = maxCount;
            for (int i = 0; i < count; i++)
            {
                debugParams[i] = (debugConnectParameters)Marshal.PtrToStructure(copyPtr, typeof(debugConnectParameters));
                copyPtr += sizeof(debugConnectParameters);
            }
            Marshal.FreeHGlobal(unManagedListPtr);
            return (count);
        }

我也嘗試了這些更改,但沒有成功。 我仍然看到訪問沖突。 嘗試讀取或寫入受保護的 memory。


    [DllImport(dllPath + "CubeProgrammer_API.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
        unsafe private static extern int getStLinkList(
            ref IntPtr stLinkList,
            int shared
            );
    unsafe public static int GetDeviceList(List<debugConnectParameters> list)
    {
        IntPtr unManagedListPtr = Marshal.AllocHGlobal(sizeof(debugConnectParameters*));
        IntPtr copyPtr = unManagedListPtr;

            int count = getStLinkList(ref unManagedListPtr, 0);

            if (count > 10) count = 10;
            for (int i = 0; i < count; i++)
            {
                debugConnectParameters parameter = (debugConnectParameters)Marshal.PtrToStructure(copyPtr, typeof(debugConnectParameters));
                list.Add(parameter);
                copyPtr += sizeof(debugConnectParameters);
            }

            Marshal.FreeHGlobal(unManagedListPtr);
            return (count);
    }

特別是在調用“CubeProgrammer_API.dll”庫的getStLinkList function 方面,有兩件事對我們不利。 如果不更正它們,庫將無法工作,即使是 C++。

首先,在 STM32CubeProgrammer 安裝的api/lib文件夾中找到的該庫的依賴項並非全部針對 x64 編譯。 bin文件夾中的版本是您希望在運行時可用的庫。 我通過在項目調試設置中將工作目錄設置為該目錄來完成此操作。 這是通過檢查api/libbin文件夾中每個 DLL 的目標機器來驗證的。

其次,“CubeProgrammer_API.dll”需要在通過調用setLoadersPathsetDisplayCallbacks函數調用getStLinkList之前進行初始化。 第一個 function 必須提供“Flash Loader”的路徑,在我的例子中是bin/FlashLoader setDisplayCallbacks function 采用三個 function 指針的結構。

下面的示例可能不是類型編組的最佳示例,但它會說明該過程。

public static class CubeProgrammerApi
{
    public enum DebugConnectionMode
    {
        NormalMode = 0,
        HotplugMode = 1,
        UnderResetMode = 2,
        PreResetMode = 3
    }
    
    public enum DebugResetMode
    {
        SoftwareReset = 0,
        HardwareReset = 1,
        CoreReset = 2
    }
    
    [StructLayout(LayoutKind.Sequential)]
    public class Frequencies
    {
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
        uint[] JtagFrequency;
        uint JTagFrequencyNumber;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
        uint[] SwdFrequency;
        uint SwdFrequencyNumber;
    }
    
    [StructLayout(LayoutKind.Sequential)]
    public class DebugConnectParameters
    {
        DebugPort DebugPort;
        public int Index;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 33)]
        public string SerialNumber;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
        public string FirmwareVersion;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 5)]
        public string TargetVoltage;
        public int AccesPortNumber;
        public int AccessPort;
        public DebugConnectionMode connectionMode;
        public DebugResetMode resetMode;
        public bool IsOldFirmware;
        public Frequencies Freqencies;
        public int Frequency;
        public bool IsBridge;
        public int Shared;
    }
    
    public delegate void LogMessageReceived(int messageType, [MarshalAs(UnmanagedType.LPWStr)] string message);
    public delegate void InitProgressBar();
    public delegate void ProgressBarUpdateReceived(int currentProgress, int total);

    internal static class NativeMethods
    {
        public struct DisplayCallbacks
        {
            public InitProgressBar initProgressBar;
            public LogMessageReceived logMessage;
            public ProgressBarUpdateReceived loadBar;
        }

        [DllImport("CubeProgrammer_API.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "setLoadersPath")]
        internal static extern void SetLoadersPath(string path);

        [DllImport("CubeProgrammer_API.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "setDisplayCallbacks")]
        internal static extern void SetDisplayCallbacks(ref DisplayCallbacks callbacks);

        [DllImport("CubeProgrammer_API.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "getStLinkList")]
        internal static extern int GetStLinkList(IntPtr stLinkList, uint shared);

        [DllImport("CubeProgrammer_API.dll", CallingConvention = CallingConvention.Cdecl)]
        internal static extern void deleteInterfaceList();

        [DllImport("CubeProgrammer_API.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "reset")]
        internal static extern int Reset([MarshalAs(UnmanagedType.U4)] DebugResetMode rstMode);
    }

    public static void SetLoadersPath(string path)
    {
        NativeMethods.SetLoadersPath(path);
    }

    public static void SetDisplayCallbacks(InitProgressBar initProgressBar, LogMessageReceived messageReceived, ProgressBarUpdateReceived progressBarUpdate)
    {
        NativeMethods.DisplayCallbacks callbacksHandle;

        callbacksHandle.initProgressBar = initProgressBar;
        callbacksHandle.logMessage = messageReceived;
        callbacksHandle.loadBar = progressBarUpdate;

        NativeMethods.SetDisplayCallbacks(ref callbacksHandle);
    }

    public static IList<DebugConnectParameters> GetStLinkProgrammers(bool shared = false)
    {
        var listPtr = Marshal.AllocHGlobal(Marshal.SizeOf<IntPtr>());
        var parametersList = new List<DebugConnectParameters>();

        try
        {
            var size = Marshal.SizeOf<DebugConnectParameters>();
            var numberOfItems = NativeMethods.GetStLinkList(listPtr, shared ? 1U : 0U);
            var listDereference = Marshal.PtrToStructure<IntPtr>(listPtr);

            for (var i = 0; i < numberOfItems; i++)
            {
                var currentItem = Marshal.PtrToStructure<DebugConnectParameters>(listDereference + (i * size));

                parametersList.Add(currentItem);
            }

            NativeMethods.deleteInterfaceList();
        }
        finally
        {
            Marshal.FreeHGlobal(listPtr);
        }

        return parametersList;
    }

    public static void FreeStLinkProgrammers()
    {
        NativeMethods.deleteInterfaceList();
    }
}

和主要的:

class Program
    {
        static void Main(string[] args)
        {
            CubeProgrammerApi.SetLoadersPath(@"C:\Program Files\STMicroelectronics\STM32Cube\STM32CubeProgrammer\bin\FlashLoader");
            CubeProgrammerApi.SetDisplayCallbacks(InitProgressBar, ReceiveMessage, ProgressBarUpdate);
            var stLinkList = CubeProgrammerApi.GetStLinkProgrammers();

            foreach (var stlink in stLinkList)
            {
                Console.WriteLine("{0} {1}", stlink.Index, stlink.SerialNumber);
            }

            Console.WriteLine("Press ENTER to exit");
            Console.ReadLine();

            CubeProgrammerApi.FreeStLinkProgrammers();
        }

        static void ReceiveMessage(int messgaeType, string message)
        {

        }

        static void InitProgressBar()
        {

        }

        static void ProgressBarUpdate(int currentProgress, int total)
        {

        }
    }

這將 output 連接兩個調試器,分別是一個 STLink V3 和一個 STLink V2。 這應該讓您走得足夠遠,可以發現要使用的正確類型。

0 002F001D3038511834333935
1 34FF6D065250343847110943
Press ENTER to exit

暫無
暫無

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

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