.Net and Legacy Code
As you can see from my previous post I am interested in recycling my old “C” code for use in .Net. I don’t want to rewrite the code in C# or VB so I am wrapping it with a C# DLL. The good thing about .Net is that it already has much of the functionality that I put into some of these old C libraries. However, there is a lot that I didn’t write that I would like to wrap, in particular: GSL gets wrapped here: Gnu.dll.
One of the big problems I have had with wrapping old DLLs is with arrays. .Net managed arrays are quite different from C arrays. Consider the following from GSL:
// double gsl_stats_mean (const double data[]
// , const size_t stride
// , const size_t n);
[DllImport("libgsl.dll"
exact spelling=true,
CharSet = CharSet.Ansi,
CallingConvention=CallingConvention.Cdecl,
EntryPoint="gsl_stats_mean"]
public static extern double mean
( [In] [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=3)]
double [] data
, [In] int stride
, [In] int n);
It seems to work OK, so what’s the problem? Try using this on a bunch of 1,000,000 element arrays and see what happens to the resources on your PC and you’ll soon see!
The MarshalAs class copies the data in the .Net array into a new C array. Here is a better implementation that uses the GCHandle:
public class gsl_stats { internal static unsafe GCHandle _gch_pinned_ptr(double[] data, ref double *p) { GCHandle gch = GCHandle.Alloc(data, GCHandleType.Pinned); IntPtr ip = gch.AddrOfPinnedObject(); p = (double*)ip.ToPointer(); return gch; }public unsafe static double mean (double [] data , int stride, int n) { double *p = null; GCHandle gch = _gsl._gch_pinned_ptr(data, ref p); double d = gsl_stats_DLL.mean(p, stride, n); gch.Free(); return d; } // mean()} //gsl_stats
public class gsl_stats_Dll {[DllImport("libgsl.dll" , ExactSpelling=true , CharSet = CharSet.Ansi , CallingConvention=CallingConvention.Cdecl , EntryPoint="gsl_stats_mean")]public static extern unsafe double mean ( [In] double *data, [In] int stride, [In] int n); } //gsl_stats_DLL