简体   繁体   English

C# 调用 DLL function 返回指向结构数组的指针

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

I have tried many different combinations of the various methods to marshal this call.我尝试了各种方法的许多不同组合来编组此调用。 This is a DLL that returns a pointer to a pointer to an array of structures.这是一个 DLL,它返回一个指向结构数组指针的指针。 The types like debugPort are actually enums.像 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
        );

I have tried replacing the using "out" and "ref" options.我尝试使用“out”和“ref”选项替换。 I have tried to find a version of IntPtr that it likes.我试图找到它喜欢的 IntPtr 版本。 I keep getting: System.AccessViolationException.我不断收到:System.AccessViolationException。 I have contacted STMicroelectronics about how to interface with this DLL, but so far they have been no help.我已经联系 STMicroelectronics 关于如何与这个 DLL 接口,但到目前为止他们没有帮助。 The rest of the calls in the DLL are pretty simple but I must have this one working to get started, since it is the information about what JTAG device is actually connected. DLL 中的调用 rest 非常简单,但我必须让这个开始工作,因为它是关于实际连接的 JTAG 设备的信息。

Updated (6/12/20) to add the actual calling function and now the calling function copies the structures from unmanaged to managed structures.更新 (6/12/20) 以添加实际调用 function,现在调用 function 将结构从非托管结构复制到托管结构。 But the call to getStLinkList() still does not work.但是对 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);
        }

I also tried these changes with no luck.我也尝试了这些更改,但没有成功。 I am still seeing access violations.我仍然看到访问冲突。 Attempt to read or write protected memory.尝试读取或写入受保护的 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);
    }

There are a two things working against us in regards to calling the getStLinkList function of the "CubeProgrammer_API.dll" library in particular.特别是在调用“CubeProgrammer_API.dll”库的getStLinkList function 方面,有两件事对我们不利。 Without correcting them the library will not work, even from C++.如果不更正它们,库将无法工作,即使是 C++。

First, the dependencies for that library found in the api/lib folder of the STM32CubeProgrammer installation are not all compiled for x64.首先,在 STM32CubeProgrammer 安装的api/lib文件夹中找到的该库的依赖项并非全部针对 x64 编译。 The versions in the bin folder are and those are the libraries you'll want to have available at runtime. bin文件夹中的版本是您希望在运行时可用的库。 I've done this by setting the working directory to that directory in the project Debug settings.我通过在项目调试设置中将工作目录设置为该目录来完成此操作。 This was verified by checking the target machine of each DLL in the api/lib and bin folders.这是通过检查api/libbin文件夹中每个 DLL 的目标机器来验证的。

Second, the "CubeProgrammer_API.dll" needs to be initialized before calling getStLinkList by calling the setLoadersPath and setDisplayCallbacks functions.其次,“CubeProgrammer_API.dll”需要在通过调用setLoadersPathsetDisplayCallbacks函数调用getStLinkList之前进行初始化。 The first function must be provided the path to the "Flash Loader", which is bin/FlashLoader in my case.第一个 function 必须提供“Flash Loader”的路径,在我的例子中是bin/FlashLoader The setDisplayCallbacks function takes a structure of three function pointers. setDisplayCallbacks function 采用三个 function 指针的结构。

The example below might not be the best example of type marshaling, but it will illustrate the process.下面的示例可能不是类型编组的最佳示例,但它会说明该过程。

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

And main:和主要的:

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)
        {

        }
    }

This will output the following with two debuggers attached, a STLink V3 and an STLink V2 respectively.这将 output 连接两个调试器,分别是一个 STLink V3 和一个 STLink V2。 This should get you far enough along to discover the correct types to use.这应该让您走得足够远,可以发现要使用的正确类型。

0 002F001D3038511834333935
1 34FF6D065250343847110943
Press ENTER to exit

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

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