C#调用DLL函数,该函数返回指向结构数组的指针 [英] C# calling a DLL function that returns a pointer to pointer to an array of structures

查看:203
本文介绍了C#调用DLL函数,该函数返回指向结构数组的指针的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试了各种方法的许多不同组合来封送此调用.这是一个DLL,它返回一个指向结构数组的指针.像debugPort这样的类型实际上是枚举.

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. The types like debugPort are actually enums.

/**
* \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中的其余调用非常简单,但是我必须先开始进行这一操作,因为它是有关实际连接了哪些JTAG设备的信息.

I have tried replacing the using "out" and "ref" options. I have tried to find a version of IntPtr that it likes. I keep getting: System.AccessViolationException. I have contacted STMicroelectronics about how to interface with this DLL, but so far they have been no help. 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.

已更新(6/12/20)以添加实际的调用函数,现在,调用函数将结构从非托管结构复制到托管结构.但是对getStLinkList()的调用仍然无法正常工作.

Updated (6/12/20) to add the actual calling function and now the calling function copies the structures from unmanaged to managed structures. But the call to getStLinkList() still does not work.

        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.


    [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 函数时,有两点不利于我们工作:特别是图书馆.如果不对其进行更正,则该库将无法使用,即使在C ++中也是如此.

There are a two things working against us in regards to calling the getStLinkList function of the "CubeProgrammer_API.dll" library in particular. Without correcting them the library will not work, even from C++.

首先,在STM32CubeProgrammer安装的 api/lib 文件夹中找到的该库的依赖项并未针对x64进行全部编译. bin 文件夹中的版本是,这些是您希望在运行时可用的库.我是通过在项目调试"设置中将工作目录设置为该目录来完成此操作的.通过检查 api/lib bin 文件夹中每个DLL的目标计算机来验证这一点.

First, the dependencies for that library found in the api/lib folder of the STM32CubeProgrammer installation are not all compiled for x64. The versions in the bin folder are and those are the libraries you'll want to have available at runtime. 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.

第二,"CubeProgrammer_API.dll"需要通过调用 setLoadersPath setDisplayCallbacks 函数在调用 getStLinkList 之前进行初始化.必须向第一个功能提供"Flash Loader"的路径,在本例中为 bin/FlashLoader . setDisplayCallbacks 函数采用三个函数指针的结构.

Second, the "CubeProgrammer_API.dll" needs to be initialized before calling getStLinkList by calling the setLoadersPath and setDisplayCallbacks functions. The first function must be provided the path to the "Flash Loader", which is bin/FlashLoader in my case. The setDisplayCallbacks function takes a structure of three function pointers.

下面的示例可能不是类型封送处理的最佳示例,但它将说明该过程.

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

主要:

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

        }
    }

这将输出以下内容,并附带两个调试器,分别是STLink V3和STLink V2.这应该使您足够了解如何使用正确的类型.

This will output the following with two debuggers attached, a STLink V3 and an STLink V2 respectively. This should get you far enough along to discover the correct types to use.

0 002F001D3038511834333935
1 34FF6D065250343847110943
Press ENTER to exit

这篇关于C#调用DLL函数,该函数返回指向结构数组的指针的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆