"Fossies" - the Fresh Open Source Software Archive

Member "rrdtool-1.7.2/bindings/dotnet/rrdlib.cs" (27 May 2019, 24309 Bytes) of package /linux/misc/rrdtool-1.7.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C# source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "rrdlib.cs" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.7.1_vs_1.7.2.

    1 /*****************************************************************************
    2  * RRDLIB .NET Binding
    3  *****************************************************************************
    4  * Created 2010/06/29 by Chris Larsen
    5  * 
    6  * This .NET interface allows the use of Tobias Oetiker's awesome RRDtool 
    7  * functions in .NET projects using the PInvoke method to load the rrdlib.dll
    8  * To use, please make sure that you place the rrdlib.dll in the same 
    9  * directory as this dll, or change the "const string dll" to point to the
   10  * proper location. For documentation, please see the RRDtool website at:
   11  * https://oss.oetiker.ch/rrdtool/
   12  * For usage examples, please see the rrd_binding_test project.
   13  ****************************************************************************/
   14 using System;
   15 using System.Linq;
   16 using System.Collections.Generic;
   17 using System.Runtime.InteropServices;
   18 
   19 #if X64
   20 #error 64-bit platform not yet supported.
   21 #endif
   22 
   23 /// <summary>
   24 /// Contains data structures and methods for working with round robin databases.
   25 /// </summary>
   26 namespace dnrrdlib
   27 {
   28     /// <summary>
   29     /// Information about a particular RRD parameter. The key is the name of the parameter,
   30     /// type determines what kind of value we have, value is the value, and next is a 
   31     /// pointer to another info object.
   32     /// </summary>
   33     [StructLayout(LayoutKind.Explicit, Pack = 1)]
   34     public struct rrd_info_t
   35     {
   36         [FieldOffset(0), MarshalAs(UnmanagedType.LPStr)]
   37         public string key;
   38         [FieldOffset(4)]    // for 64 bit, set this to 8 and increment everyone else by 4
   39         public rrd_info_type_t type;
   40         [FieldOffset(8)]
   41         public rrd_infoval_t value;
   42         [FieldOffset(16)]
   43         public IntPtr next;
   44     }
   45 
   46     /// <summary>
   47     /// This is a chunk of data returned from an RRD object
   48     /// </summary>
   49     [StructLayout(LayoutKind.Sequential)]
   50     public struct rrd_blob_t
   51     {
   52         public UInt32 size;     /* size of the blob */
   53         public IntPtr ptr;    /* pointer */
   54     };
   55 
   56     /// <summary>
   57     /// This contains the actual data values for an rrd_info_t structure. 
   58     /// NOTE: Only one of these will be valid per instance. Use the containing info_t's
   59     /// type field to determine which of these to read. 
   60     /// NOTE: If the type is RD_I_STR, you have to marshal the string value yourself
   61     /// </summary>
   62     [StructLayout(LayoutKind.Explicit)]
   63     public struct rrd_infoval_t
   64     {
   65         [FieldOffset(0)]
   66         public UInt32 u_cnt;
   67         [FieldOffset(0)]
   68         public double u_val;
   69         [FieldOffset(0)]
   70         public IntPtr u_str;
   71         [FieldOffset(0)]
   72         public Int32 u_int;
   73         [FieldOffset(0)]
   74         public rrd_blob_t u_blo;
   75     };
   76 
   77     /// <summary>
   78     /// Different rrd_info_t value types
   79     /// </summary>
   80     public enum rrd_info_type_t
   81     {
   82         RD_I_VAL = 0,
   83         RD_I_CNT,
   84         RD_I_STR,
   85         RD_I_INT,
   86         RD_I_BLO
   87     };
   88 
   89     /// <summary>
   90     /// Direct bindings to the RRD Library for .NET applications. Uses the PInvoke method
   91     /// of accessing the rrdlib.dll file.
   92     /// </summary>
   93     public class rrd
   94     {
   95         // Set this path to the location of your "rrdlib.dll" file
   96         const string dll = @"librrd-4.dll";
   97 
   98         // IMPORTS - Main methods
   99         [DllImport(dll)] static extern Int32 rrd_create(Int32 argc, string[] argv);
  100         [DllImport(dll)] static extern Int32 rrd_create_r([MarshalAs(UnmanagedType.LPStr)] string filename,
  101             UInt32 pdp_step, Int64 last_up, Int32 argc, [MarshalAs(UnmanagedType.LPArray)] string[] argv);
  102         [DllImport(dll)] static extern IntPtr rrd_info_r(string filename);
  103         [DllImport(dll)] static extern void rrd_info_print(IntPtr data);
  104         [DllImport(dll)] static extern void rrd_info_free(IntPtr data);
  105 
  106         [DllImport(dll)] static extern Int32 rrd_update(Int32 argc, string[] argv);
  107         [DllImport(dll)] static extern IntPtr rrd_update_v(Int32 argc, string[] argv);
  108         [DllImport(dll)] static extern Int32 rrd_update_r(string filename, string template, Int32 argc,
  109             string[] argv);
  110         /* Do not use this until someone adds the FILE structure */
  111         [DllImport(dll)] static extern Int32 rrd_graph(Int32 argc, string[] argv, ref string[] prdata,
  112             ref Int32 xsize, ref Int32 ysize, /* TODO - FILE, */ ref double ymin, ref double ymax);
  113         [DllImport(dll)] static extern IntPtr rrd_graph_v(Int32 argc, string[] argv);
  114         [DllImport(dll)] static extern Int32 rrd_fetch(Int32 argc, string[] argv, ref Int64 start,
  115             ref Int64 end, ref UInt32 step, [Out] out UInt32 ds_cnt, [Out] out IntPtr ds_namv, [Out] out IntPtr data);
  116         [DllImport(dll)] static extern Int32 rrd_first(Int32 argc, string[] argv);
  117         [DllImport(dll)] static extern Int32 rrd_first_r(string filename, Int32 rraindex);
  118         [DllImport(dll)] static extern Int32 rrd_last(Int32 argc, string[] argv);
  119         [DllImport(dll)] static extern Int32 rrd_last_r(string filename, Int32 rraindex);
  120         [DllImport(dll)] static extern Int32 rrd_lastupdate(Int32 argc, string[] argv);
  121         [DllImport(dll)] static extern Int32 rrd_lastupdate_r(string filename, ref Int32 ret_last_update,
  122             ref UInt32 ret_ds_count, [Out] out IntPtr ret_ds_names, [Out] out IntPtr ret_last_ds);
  123         [DllImport(dll)] static extern Int32 rrd_dump(Int32 argc, string[] argv);
  124         [DllImport(dll)] static extern Int32 rrd_dump_r(string filename, string outname);
  125         [DllImport(dll)] static extern Int32 rrd_xport(Int32 argc, string[] argv, Int32 unused,
  126             ref Int64 start, ref Int64 end, ref UInt32 step, ref UInt32 col_cnt,
  127             [Out] out IntPtr leggend_v, [Out] out  IntPtr data);
  128         [DllImport(dll)] static extern Int32 rrd_restore(Int32 argc, string[] argv);
  129         [DllImport(dll)] static extern Int32 rrd_resize(Int32 argc, string[] argv);
  130         [DllImport(dll)] static extern Int32 rrd_tune(Int32 argc, string[] argv);
  131 
  132         // IMPORTS - Utility methods
  133         [DllImport(dll)] static extern string rrd_strversion();
  134         [DllImport(dll)] static extern Int32 rrd_random();
  135         [DllImport(dll)] static extern IntPtr rrd_get_error();
  136         [DllImport(dll)] internal static extern void rrd_clear_error();
  137 
  138         // MAIN FUNCTIONS
  139 
  140         public static DateTime UnixTimestampToDateTime(Int32 unixTimeStamp)
  141         {
  142             return new DateTime(1970, 1, 1, 0, 0, 0, 0).AddSeconds(unixTimeStamp).ToLocalTime();
  143         }
  144 
  145         public static Int32 DateTimeToUnixTimestamp(DateTime input)
  146         {
  147             return (Int32)input.Subtract(new DateTime(1970, 1, 1, 0, 0, 0, 0)).TotalSeconds;
  148         }
  149 
  150         /// <summary>
  151         /// The create function of RRDtool lets you set up new Round Robin Database (RRD) files. 
  152         /// The file is created at its final, full size and filled with *UNKNOWN* data.
  153         /// </summary>
  154         /// <param name="argv">String array of command line arguments</param>
  155         /// <returns>0 if successful, -1 if an error occurred</returns>
  156         public static int Create(string[] argv)
  157         {
  158             return rrd_create(argv.Length, argv);
  159         }
  160 
  161         /// <summary>
  162         /// The create function of RRDtool lets you set up new Round Robin Database (RRD) files. 
  163         /// The file is created at its final, full size and filled with *UNKNOWN* data.
  164         /// </summary>
  165         /// <param name="filename">A full path to the location where you want the rrd to reside</param>
  166         /// <param name="pdp_step">Specifies the base interval in seconds with which data will be fed into the RRD</param>
  167         /// <param name="last_up">Timestamp of the last update</param>
  168         /// <param name="argv">String array of command line arguments</param>
  169         public static void Create(string filename, UInt32 pdp_step, Int32 last_up, string[] argv)
  170         {
  171             if (rrd_create_r(filename, pdp_step, last_up, argv.Length, argv) < 0)
  172             {
  173                 throw new RrdException();
  174             }
  175         }
  176 
  177         private static Dictionary<string, object> ConvertInfoToDict(IntPtr ptr)
  178         {
  179             var dict = new Dictionary<string, object>();
  180 
  181             rrd_info_t? info = (rrd_info_t)Marshal.PtrToStructure(ptr, typeof(rrd_info_t));
  182 
  183             while (info.HasValue)
  184             {
  185                 switch (info.Value.type)
  186                 {
  187                     case rrd_info_type_t.RD_I_STR:
  188                         dict.Add(info.Value.key, System.Runtime.InteropServices.Marshal.PtrToStringAnsi(info.Value.value.u_str));
  189                         break;
  190                     case rrd_info_type_t.RD_I_INT:
  191                         dict.Add(info.Value.key, info.Value.value.u_int);
  192                         break;
  193                     case rrd_info_type_t.RD_I_CNT:
  194                         dict.Add(info.Value.key, info.Value.value.u_cnt);
  195                         break;
  196                     case rrd_info_type_t.RD_I_VAL:
  197                         dict.Add(info.Value.key, info.Value.value.u_val);
  198                         break;
  199                     case rrd_info_type_t.RD_I_BLO:
  200                         //TODO: Properly extract the byte array
  201                         dict.Add(info.Value.key, "[BLOB]");
  202                         break;
  203                 }
  204 
  205                 if (info.Value.next != IntPtr.Zero)
  206                     info = (rrd_info_t)System.Runtime.InteropServices.Marshal.PtrToStructure(info.Value.next, typeof(rrd_info_t));
  207                 else
  208                     info = null;
  209             }
  210             return dict;
  211         }
  212 
  213         /// <summary>
  214         /// Returns a linked list of rrd_info_t objects that describe the rrd file. 
  215         /// </summary>
  216         /// <param name="filename">Full path to the rrd file</param>
  217         /// <returns>An rrd_info_t object</returns>
  218         public static Dictionary<string, object> Info(string filename)
  219         {
  220             if (string.IsNullOrEmpty(filename))
  221                 throw new Exception("Empty filename");
  222             IntPtr ptr = rrd_info_r(filename);
  223             if (ptr == IntPtr.Zero || ptr.ToInt64() == -1)
  224                 throw new RrdException();
  225 
  226             var ret = ConvertInfoToDict(ptr);
  227             rrd_info_free(ptr);
  228             return ret;
  229         }
  230 
  231         /// <summary>
  232         /// The update function feeds new data values into an RRD. The data is time aligned (interpolated) 
  233         /// according to the properties of the RRD to which the data is written.
  234         /// </summary>
  235         /// <param name="argv">String array of command line arguments</param>
  236         /// <returns>0 if successful, -1 if an error occurred</returns>
  237         public static void Update(params string[] argv)
  238         {
  239             if (rrd_update(argv.Length, argv) < 0)
  240             {
  241                 throw new RrdException();
  242             }
  243         }
  244 
  245         /// <summary>
  246         /// The update function feeds new data values into an RRD. The data is time aligned (interpolated) 
  247         /// according to the properties of the RRD to which the data is written.
  248         /// </summary>
  249         /// <param name="argv">String array of command line arguments</param>
  250         /// <returns>An rrd_info_t pointer with information about the update</returns>
  251         public static IntPtr Update2(params string[] argv)
  252         {
  253             return rrd_update_v(argv.Length, argv);
  254         }
  255 
  256         /// <summary>
  257         /// The update function feeds new data values into an RRD. The data is time aligned (interpolated) 
  258         /// according to the properties of the RRD to which the data is written.
  259         /// </summary>
  260         /// <param name="filename">Full path to the rrd to update</param>
  261         /// <param name="template">List of data sources to update and in which order</param>
  262         /// <param name="argv">String array of command line arguments</param>
  263         public static void Update(string filename, string template, params string[] argv)
  264         {
  265             if (rrd_update_r(filename, template, argv.Length, argv) < 0)
  266             {
  267                 throw new RrdException();
  268             }
  269         }
  270 
  271         /// <summary>
  272         /// Generate a graph from an RRD file. Specify all the graph options in the string array as you
  273         /// normally would with the command line version.
  274         /// </summary>
  275         /// <param name="argv">String array of command line arguments</param>
  276         /// <returns>0 if successful, -1 if an error occurred</returns>
  277         public static Dictionary<string, object> Graph(params string[] argv)
  278         {
  279             IntPtr ptr = rrd_graph_v(argv.Length, argv);
  280 
  281             if (ptr == IntPtr.Zero || ptr.ToInt64() == -1)
  282                 throw new RrdException();
  283 
  284             var ret = ConvertInfoToDict(ptr);
  285             rrd_info_free(ptr);
  286             return ret;
  287         }
  288 
  289         /// <summary>
  290         /// Returns an array of values for the period specified from a given rrd.
  291         /// Specify your parameters in the argv array and check the referenced parameters for
  292         /// values returned from the rrd
  293         /// </summary>
  294         /// <param name="argv">String array of command line arguments (must include the filename)</param>
  295         /// <param name="start">Starting timestamp found in the rrd</param>
  296         /// <param name="end">Ending timestamp found in the rrd</param>
  297         /// <param name="step">The rrd's step value</param>
  298         /// <param name="ds_cnt">Number of data sources found</param>
  299         /// <param name="ds_namv">Names of data sources found</param>
  300         /// <param name="data">Values found (in double type)</param>
  301         public static void Fetch(string[] argv, ref DateTime start, ref DateTime end, ref UInt32 step,
  302             ref UInt32 ds_cnt, ref string[] ds_namv, ref IntPtr data)
  303         {
  304             Int64 starti64 = 0, endi64 = 0;
  305             IntPtr ptr = new IntPtr();
  306             if (rrd_fetch(argv.Length, argv, ref starti64, ref endi64, ref step, out ds_cnt,
  307                 out ptr, out data) < 0)
  308             {
  309                 throw new RrdException();
  310             }
  311             ds_namv = GetStringArray(ptr, ds_cnt);
  312             start = UnixTimestampToDateTime((int)starti64);
  313             end = UnixTimestampToDateTime((int)endi64);
  314         }
  315 
  316         /// <summary>
  317         /// Returns the timestamp of the first value in the rrd given the rra index 
  318         /// </summary>
  319         /// <param name="filename">Full path to the rrd file</param>
  320         /// <param name="rraindex">0 based index of the rra to get a value for</param>
  321         /// <returns>Unix timestamp if successful, -1 if an error occurred</returns>
  322         public static Int32 First(string filename, int rraindex)
  323         {
  324             Int32 rv = rrd_first_r(filename, rraindex);
  325             if (rv < 0)
  326             {
  327                 throw new RrdException();
  328             }
  329             return rv;
  330         }
  331 
  332         /// <summary>
  333         /// Returns the timestamp of the first value in the rrd
  334         /// </summary>
  335         /// <param name="argv">String array of command line arguments</param>
  336         /// <returns>Unix timestamp if successful, -1 if an error occurred</returns>
  337         public static Int32 First(params string[] argv)
  338         {
  339             Int32 rv = rrd_first(argv.Length, argv);
  340             if (rv < 0)
  341             {
  342                 throw new RrdException();
  343             }
  344             return rv;
  345         }
  346 
  347         /// <summary>
  348         /// Returns the timestamp of the last value in the rrd given the rra index
  349         /// </summary>
  350         /// <param name="filename"></param>
  351         /// <param name="filename">Full path to the rrd file</param>
  352         /// <param name="rraindex">0 based index of the rra to get a value for</param>
  353         /// <returns>Unix timestamp if successful, -1 if an error occurred</returns>
  354         public static DateTime Last(string filename, int rraindex)
  355         {
  356             Int32 rv = rrd_last_r(filename, rraindex);
  357             if (rv < 0)
  358             {
  359                 throw new RrdException();
  360             }
  361             return UnixTimestampToDateTime(rv);
  362         }
  363 
  364         /// <summary>
  365         /// Returns the timestamp of the last value in the rrd
  366         /// </summary>
  367         /// <param name="argv">String array of command line arguments</param>
  368         /// <returns>Unix timestamp if successful, -1 if an error occurred</returns>
  369         public static DateTime Last(params string[] argv)
  370         {
  371             Int32 rv = rrd_last(argv.Length, argv);
  372             if (rv < 0)
  373             {
  374                 throw new RrdException();
  375             }
  376             return UnixTimestampToDateTime(rv);
  377         }
  378 
  379         /// <summary>
  380         /// Finds the timestamp of the last updated value in the rrd
  381         /// </summary>
  382         /// <param name="filename">Full path to the rrd file</param>
  383         /// <param name="ret_last_update">Unix timestamp of the last update</param>
  384         /// <param name="ret_ds_count">Number of data sources found</param>
  385         /// <param name="ret_ds_names">Names of the data sources found</param>
  386         /// <param name="ret_last_ds">Name of the last data source found</param>
  387         public static void Last_Update(string filename, ref DateTime ret_last_update, ref UInt32 ret_ds_count,
  388             ref string[] ret_ds_names, ref string[] ret_last_ds)
  389         {
  390             IntPtr ds_names = new IntPtr();
  391             IntPtr last_ds = new IntPtr();
  392             Int32 last_update = 0;
  393             Int32 rt = rrd_lastupdate_r(filename, ref last_update, ref ret_ds_count, out ds_names, out last_ds);
  394             if (rt < 0)
  395             {
  396                 throw new RrdException();
  397             }
  398             ret_last_update = UnixTimestampToDateTime(last_update);
  399             ret_ds_names = GetStringArray(ds_names, ret_ds_count);
  400             ret_last_ds = GetStringArray(last_ds, 1);
  401         }
  402 
  403         /// <summary>
  404         /// Writes the contents of an rrd file to an XML file
  405         /// </summary>
  406         /// <param name="filename">Full path to the rrd file</param>
  407         /// <param name="outname">Full path to write the XML output</param>
  408         /// <returns>0 if successful, -1 if an error occurred</returns>
  409         public static void Dump(string filename, string outname)
  410         {
  411             if (rrd_dump_r(filename, outname) < 0)
  412             {
  413                 throw new RrdException();
  414             }
  415         }
  416 
  417         /// <summary>
  418         /// Writes the contents of an rrd file to an XML file
  419         /// </summary>
  420         /// <param name="argv">String array of command line arguments</param>
  421         /// <returns>0 if successful, -1 if an error occurred</returns>
  422         public static void Dump(params string[] argv)
  423         {
  424             if (rrd_dump(argv.Length, argv) < 0)
  425             {
  426                 throw new RrdException();
  427             }
  428         }
  429 
  430         /// <summary>
  431         /// Grabs the values from an rrd. Similar to fetch but enables merging of multiple
  432         /// rrds and calculations
  433         /// </summary>
  434         /// <param name="argv">String array of command line arguments</param>
  435         /// <param name="start">Starting timestamp found in the rrd</param>
  436         /// <param name="end">Ending timestamp found in the rrd</param>
  437         /// <param name="step">Step size found in the rrd</param>
  438         /// <param name="col_cnt">Number of data sources found in the rrd</param>
  439         /// <param name="leggend_v">Add a legend</param>
  440         /// <param name="data">Values from the rrd as double type</param>
  441         public static void Xport(string[] argv, ref DateTime start, ref DateTime end, ref UInt32 step,
  442             ref UInt32 col_cnt, ref string[] legend_v, ref IntPtr data)
  443         {
  444             Int64 starti64 = 0, endi64 = 0;
  445             IntPtr legend = new IntPtr();
  446             Int32 rt = rrd_xport(argv.Length, argv, 0, ref starti64, ref endi64, ref step, ref col_cnt,
  447                 out legend, out data);
  448             if (rt < 0)
  449             {
  450                 throw new RrdException();
  451             }
  452             legend_v = GetStringArray(legend, col_cnt);
  453             start = UnixTimestampToDateTime((int)starti64);
  454             end = UnixTimestampToDateTime((int)endi64);
  455         }
  456 
  457         /// <summary>
  458         /// Creates an rrd from an XML data dump
  459         /// </summary>
  460         /// <param name="argv">String array of command line arguments</param>
  461         /// <returns>0 if successful, -1 if an error occurred</returns>
  462         public static void Restore(params string[] argv)
  463         {
  464             if (rrd_restore(argv.Length, argv) < 0)
  465             {
  466                 throw new RrdException();
  467             }
  468         }
  469 
  470         /// <summary>
  471         /// Alters the size of an RRA and creates a new rrd in the dll's directory
  472         /// NOTE: The new rrd may return unexpected results if you are not very careful
  473         /// NOTE: This may crash in version 1.4.3
  474         /// </summary>
  475         /// <param name="argv">String array of command line arguments</param>
  476         public static void Resize(params string[] argv)
  477         {
  478             if (rrd_resize(argv.Length, argv) < 0)
  479             {
  480                 throw new RrdException();
  481             }
  482         }
  483 
  484         /// <summary>
  485         /// Modify the characteristics of an rrd
  486         /// </summary>
  487         /// <param name="argv">String array of command line arguments</param>
  488         public static void Tune(params string[] argv)
  489         {
  490             if (rrd_tune(argv.Length, argv) < 0)
  491             {
  492                 throw new RrdException();
  493             }
  494         }
  495 
  496         // UTILITIES
  497         /// <summary>
  498         /// Returns a string with the numeric version of the rrdlib build version
  499         /// </summary>
  500         /// <returns>A string with version information</returns>
  501         public static string Version()
  502         {
  503             return rrd_strversion();
  504         }
  505 
  506         /// <summary>
  507         /// Generates a random number for testing rrdlib
  508         /// </summary>
  509         /// <returns>A random integer</returns>
  510         public static int Random()
  511         {
  512             return rrd_random();
  513         }
  514 
  515         /// <summary>
  516         /// Returns the latest error from rrdlib
  517         /// </summary>
  518         /// <returns>A string with the error message, or an empty string if no error occurred</returns>
  519         public static string Get_Error()
  520         {
  521             IntPtr ptr = rrd_get_error();
  522             if (ptr == IntPtr.Zero)
  523                 return "";
  524             return Marshal.PtrToStringAnsi(ptr);
  525         }
  526 
  527         /// <summary>
  528         /// Formats and prints information in the object to the standard output
  529         /// </summary>
  530         /// <param name="info">rrd_info_t object with data to print</param>
  531         public static void Info_Print(string filename)
  532         {
  533             if (string.IsNullOrEmpty(filename))
  534                 throw new Exception("Empty filename");
  535             IntPtr ptr = rrd_info_r(filename);
  536             if (ptr == IntPtr.Zero || ptr.ToInt64() == -1)
  537                 throw new RrdException();
  538 
  539             var data = (rrd_info_t)Marshal.PtrToStructure(ptr, typeof(rrd_info_t));
  540 
  541             rrd_info_print(ptr);
  542             rrd_info_free(ptr);
  543         }
  544 
  545         /// <summary>
  546         /// Converts a Char ** array of characters from the RRDLib returned as an IntPtr and converts
  547         /// it to a String array given the number of items in the ptr array.
  548         /// Re: http://stackoverflow.com/questions/1498931/marshalling-array-of-strings-to-char-in-c-must-be-quite-easy-if-you-know-ho
  549         /// </summary>
  550         /// <param name="ptr">Pointer to a character array returned from the RRDLib</param>
  551         /// <param name="size">Number of items in the character array (not the number of characters)</param>
  552         /// <returns>A string array</returns>
  553         private static string[] GetStringArray(IntPtr ptr, UInt32 size)
  554         {
  555             var list = new List<string>();
  556             for (int i = 0; i < size; i++)
  557             {
  558                 var strPtr = (IntPtr)Marshal.PtrToStructure(ptr, typeof(IntPtr));
  559                 list.Add(Marshal.PtrToStringAnsi(strPtr));
  560                 ptr = new IntPtr(ptr.ToInt64() + IntPtr.Size);
  561             }
  562             return list.ToArray();
  563         }
  564     }
  565 }