From 47aac624a6f5259bd5f630f1987e47de7a6cb7ca Mon Sep 17 00:00:00 2001 From: oetiker Date: Thu, 24 Nov 2011 14:51:24 +0000 Subject: [PATCH] fix some string marshaling bugs in the Dot Net binding -- Chris Larsen git-svn-id: svn://svn.oetiker.ch/rrdtool/trunk/program@2222 a5681a0c-68f1-0310-ab6d-d61299d08faa --- bindings/dotnet/rrd_binding_test.cs | 2 ++ bindings/dotnet/rrdlib.cs | 60 +++++++++++++++++++++++++++++-------- 2 files changed, 49 insertions(+), 13 deletions(-) diff --git a/bindings/dotnet/rrd_binding_test.cs b/bindings/dotnet/rrd_binding_test.cs index c907e75..09bab0b 100644 --- a/bindings/dotnet/rrd_binding_test.cs +++ b/bindings/dotnet/rrd_binding_test.cs @@ -2,6 +2,8 @@ * RRDLIB .NET Binding Test ***************************************************************************** * Created 2010/06/29 by Chris Larsen + * Updated 2011/04/15 - Modified the string arrays to use pointers as the old + * automatic marshalling of strings didn't seem to work well with 1.4.5 * * This project tests the .NET binding library by creating an rrd, inserting * data, fetching data, creating graphs, dumping and exporting the data to diff --git a/bindings/dotnet/rrdlib.cs b/bindings/dotnet/rrdlib.cs index d6f9079..71c41d9 100644 --- a/bindings/dotnet/rrdlib.cs +++ b/bindings/dotnet/rrdlib.cs @@ -12,6 +12,7 @@ * For useage examples, please see the rrd_binding_test project. ****************************************************************************/ using System; +using System.Collections.Generic; using System.Runtime.InteropServices; /// @@ -87,7 +88,7 @@ namespace dnrrdlib public class rrd { // Set this path to the location of your "rrdlib.dll" file - const string dll = @"rrdlib.dll"; + const string dll = @"C:\Programming\RRDTool\SVN\win32\DebugDLL\rrdlib.dll"; // IMPORTS - Main methods [DllImport(dll)] static extern Int32 rrd_create(Int32 argc, string[] argv); @@ -104,19 +105,19 @@ namespace dnrrdlib ref Int32 xsize, ref Int32 ysize, /* TODO - FILE, */ ref double ymin, ref double ymax); [DllImport(dll)] static extern Int32 rrd_graph_v(Int32 argc, string[] argv); [DllImport(dll)] static extern Int32 rrd_fetch(Int32 argc, string[] argv, ref Int32 start, - ref Int32 end, ref UInt32 step, ref UInt32 ds_cnt, ref string[] ds_namv, ref IntPtr data); + ref Int32 end, ref UInt32 step, [Out] out UInt32 ds_cnt, [Out] out IntPtr ds_namv, [Out] out IntPtr data); [DllImport(dll)] static extern Int32 rrd_first(Int32 argc, string[] argv); [DllImport(dll)] static extern Int32 rrd_first_r(string filename, Int32 rraindex); [DllImport(dll)] static extern Int32 rrd_last(Int32 argc, string[] argv); [DllImport(dll)] static extern Int32 rrd_last_r(string filename, Int32 rraindex); [DllImport(dll)] static extern Int32 rrd_lastupdate(Int32 argc, string[] argv); [DllImport(dll)] static extern Int32 rrd_lastupdate_r(string filename, ref Int32 ret_last_update, - ref UInt32 ret_ds_count, ref string[] ret_ds_names, ref string[] ret_last_ds); + ref UInt32 ret_ds_count, [Out] out IntPtr ret_ds_names, [Out] out IntPtr ret_last_ds); [DllImport(dll)] static extern Int32 rrd_dump(Int32 argc, string[] argv); [DllImport(dll)] static extern Int32 rrd_dump_r(string filename, string outname); [DllImport(dll)] static extern Int32 rrd_xport(Int32 argc, string[] argv, Int32 unused, ref Int32 start, ref Int32 end, ref UInt32 step, ref UInt32 col_cnt, - ref string[] leggend_v, ref IntPtr data); + [Out] out IntPtr leggend_v, [Out] out IntPtr data); [DllImport(dll)] static extern Int32 rrd_restore(Int32 argc, string[] argv); [DllImport(dll)] static extern Int32 rrd_resize(Int32 argc, string[] argv); [DllImport(dll)] static extern Int32 rrd_tune(Int32 argc, string[] argv); @@ -124,7 +125,7 @@ namespace dnrrdlib // IMPORTS - Utility methods [DllImport(dll)] static extern string rrd_strversion(); [DllImport(dll)] static extern Int32 rrd_random(); - [DllImport(dll)] static extern string rrd_get_error(); + [DllImport(dll)] static extern IntPtr rrd_get_error(); // MAIN FUNCTIONS @@ -230,8 +231,11 @@ namespace dnrrdlib public static Int32 Fetch(string[] argv, ref Int32 start, ref Int32 end, ref UInt32 step, ref UInt32 ds_cnt, ref string[] ds_namv, ref IntPtr data) { - return rrd_fetch(argv.GetUpperBound(0) + 1, argv, ref start, ref end, ref step, ref ds_cnt, - ref ds_namv, ref data); + IntPtr ptr = new IntPtr(); + Int32 rv = rrd_fetch(argv.GetUpperBound(0) + 1, argv, ref start, ref end, ref step, out ds_cnt, + out ptr, out data); + ds_namv = GetStringArray(ptr, ds_cnt); + return rv; } /// @@ -289,8 +293,12 @@ namespace dnrrdlib public static Int32 Last_Update(string filename, ref Int32 ret_last_update, ref UInt32 ret_ds_count, ref string[] ret_ds_names, ref string[] ret_last_ds) { - return rrd_lastupdate_r(filename, ref ret_last_update, ref ret_ds_count, ref ret_ds_names, - ref ret_last_ds); + IntPtr ds_names = new IntPtr(); + IntPtr last_ds = new IntPtr(); + Int32 rt = rrd_lastupdate_r(filename, ref ret_last_update, ref ret_ds_count, out ds_names,out last_ds); + ret_ds_names = GetStringArray(ds_names, ret_ds_count); + ret_last_ds = GetStringArray(last_ds, 1); + return rt; } /// @@ -327,10 +335,13 @@ namespace dnrrdlib /// Values from the rrd as double type /// 0 if successful, -1 if an error occurred public static Int32 Xport(string[] argv, ref Int32 start, ref Int32 end, ref UInt32 step, - ref UInt32 col_cnt, ref string[] leggend_v, ref IntPtr data) + ref UInt32 col_cnt, ref string[] legend_v, ref IntPtr data) { - return rrd_xport(argv.GetUpperBound(0) + 1, argv, 0, ref start, ref end, ref step, ref col_cnt, - ref leggend_v, ref data); + IntPtr legend = new IntPtr(); + Int32 rt = rrd_xport(argv.GetUpperBound(0) + 1, argv, 0, ref start, ref end, ref step, ref col_cnt, + out legend, out data); + legend_v = GetStringArray(legend, col_cnt); + return rt; } /// @@ -390,7 +401,10 @@ namespace dnrrdlib /// A string with the error message, or an emtpy string if no error occurred public static string Get_Error() { - return rrd_get_error(); + IntPtr ptr = rrd_get_error(); + if (ptr == IntPtr.Zero) + return ""; + return Marshal.PtrToStringAnsi(ptr); } /// @@ -403,5 +417,25 @@ namespace dnrrdlib Marshal.StructureToPtr(info, newptr, true); rrd_info_print(newptr); } + + /// + /// Converts a Char ** array of characters from the RRDLib returned as an IntPtr and converts + /// it to a String array given the number of items in the ptr array. + /// Re: http://stackoverflow.com/questions/1498931/marshalling-array-of-strings-to-char-in-c-must-be-quite-easy-if-you-know-ho + /// + /// Pointer to a character array returned from the RRDLib + /// Number of items in the character array (not the number of characters) + /// A string array + private static string[] GetStringArray(IntPtr ptr, UInt32 size) + { + var list = new List(); + for (int i = 0; i < size; i++) + { + var strPtr = (IntPtr)Marshal.PtrToStructure(ptr, typeof(IntPtr)); + list.Add(Marshal.PtrToStringAnsi(strPtr)); + ptr = new IntPtr(ptr.ToInt64() + IntPtr.Size); + } + return list.ToArray(); + } } } -- 2.11.0