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