float* from C to C#

2019-02-13 12:34发布

问题:

I'm not truly a CS guy, so if any of you geniuses on here can point me in the right direction I'll be eternally grateful.

I have a c-code command line function that used to write its results to file. I converted it to return it's data via a float* array to a C++ program like such (to avoid constant file I/O):

float * mgrib(int argc, char **argv)

This worked perfectly. I now need to get this into a C# program, and here's where things go haywire.

The first thing I did to avoid the char ** was to make the arguments a series of bool. That worked fine if I allow it to still dump to file.

The problem is juggling the c-style float array in C#. Within the c-code it was allocated with malloc.

So here's everything I've tried with no success(I know the size of the array):

  1. Make a "free" function to export to call from C# to release the memory when I'm done with it. After a few loops the C# crashes with no warning.

  2. Release the malloc from C# with Marshal.FreeCoTaskMem. Same result.

  3. Move the float* to an argument and remove the c-code malloc. (void mgrib(..., float* data,...)

__a)Allocate it with Marshal.AllocCoTaskMem. Free it with Marshal.FreeCoTaskMem.

__b)Use Marshal.Copy to allocate. Free it with Marshal.FreeCoTaskMem (Maybe this is wrong?)

I've dabbled in just about everything I could find in the internet. Please let me know if more info is necessary. I'm hoping this just a simple concept that I'm missing.

回答1:

Use this signature for your C function (replace the mgrib.dll with real library name).

[DllImport( "mgrib.dll", EntryPoint = "mgrib" )]
public static extern IntPtr mgrib(
    int argc,
    [MarshalAs( UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStr )]
    StringBuilder[] argv );

Call the mgrib function as follows:

// Prepare arguments in proper manner
int argc = 0;
StringBuilder[] argv = new StringBuilder[ argc ];
IntPtr pointer = mgrib( argc, argv );

When the call is done, you can get the result like this:

float[] result = new float[ size ];
Marshal.Copy( pointer, result, 0, size );

EDIT:

Since the mgrib is allocating the memory using malloc, we need to free the memory using free function. However, you will have to wrap the call to free function in another function that will be exported from native library.

extern "C" __declspec(dllexport) void mgrib_free( float* pointer );

void mgrib_free( float* pointer )
{
    free( result );
}

And then import it into like this:

[DllImport( "mgrib.dll", EntryPoint = "mgrib_free",
            CallingConvention = CallingConvention.Cdecl )]
public static extern void mgrib_free( IntPtr pointer );

And invoke it as follows:

mgrib_free( pointer );