CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 12 of 12
  1. #1
    Join Date
    Dec 2007
    Location
    Brazil
    Posts
    37

    [RESOLVED] Interop of native C callback functions with void* parameter

    Resuming an older topic (accessing the native library GSL) which I never managed to solve, I wrote a primitive example dll (with MingW/gcc on Windows XP) just to demonstrate the problem.

    GSL (Gnu Scientific Library) contains a lot of functions (e.g.: integration routine) which require another (callback) function as argument with the prototype

    double f (double x, void *params).

    My library function example is

    double average (double (*f) (double x, void *params),
    void *par, double a, double b, int n)
    {
    int i;
    double sum, x, dx;

    sum = 0; x = a; dx = (b-a) / (n-1);
    for (i=0; i<n; i++) { sum += f(x,par); x += dx; }
    return sum / n;
    }

    I created a native dll from that and call it from a C test program which defines the actual callback function:

    double quadratic (double x, void *par)
    { double *p;
    p = par;
    return (*p * x + *(p+1)) * x + *(p+2);
    }

    and calls it with

    struct Par3 params = {1.0, 0.0, -5.0};

    printf("Average in [0,2] (10 points): %f\n",
    average (&quadratic, &params, 0.0, 2.0, 10));

    and everything works fine.

    After several tentatives to call that from .NET/CSharp, which didn't work, I came up to the following, which doesn't work either, but which is the most complete one. Delegate and dllimport are

    [StructLayout (LayoutKind.Sequential)]
    class Parameters { public double a, b, c; }

    public delegate double Func (double x, IntPtr p);

    [DllImport ("generic.dll")] public static extern
    double average (Func f, IntPtr p, double a, double b, int n);

    The actual callback function is
    public static double Quad (double x, IntPtr par)
    {
    GCHandle gch;
    Parameters p;

    gch = (GCHandle) par;
    p = (Parameters)gch.Target;
    return (p.a*x + p.b)*x + p.c;
    }

    and eveything is called like

    par = new Parameters();
    par.a = 1.0; par.b = 0.0; par.c = -5.0;
    gch = GCHandle.Alloc (par, GCHandleType.Pinned);
    func = new Func (Quad);
    avg = average (func, (IntPtr)gch, 0.0, 2.0, 10);

    which finally provokes the error message

    FatalExecutionEngineError was detected
    Message: The runtime has encountered a fatal error. The address of the error was at 0x79eb059e, on thread 0x56c. The error code is 0xc0000005. This error may be a bug in the CLR or in the unsafe or non-verifiable portions of user code. Common sources of this bug include user marshaling errors for COM-interop or PInvoke, which may corrupt the stack.

    The complete source code with makefile and everything is attached.
    What is wrong?
    Attached Files Attached Files

  2. #2
    Join Date
    Mar 2001
    Posts
    2,529

    Re: Interop of native C callback functions with void* parameter

    May I ask why you are not using delegates?

    Function pointers doubtless would not be "safe".
    ahoodin
    To keep the plot moving, that's why.

  3. #3
    Join Date
    May 2007
    Posts
    1,546

    Re: Interop of native C callback functions with void* parameter

    Code:
    [StructLayout (LayoutKind.Sequential)]
    class Parameters { public double a, b, c; }
    That should be

    Code:
    [StructLayout (LayoutKind.Sequential)]
    struct Parameters { public double a, b, c; }
    Code:
    double quadratic (double x, void *par)
    Assuming the "void* par" part refers to a Parameters type, you can safely change this to:

    Code:
    double quadratic (double x, ref Parameters par)
    
    // called like:
    Parameters p = new Parameters { a = 1, b = 2, c = 3};
    quadratic (5, ref p);
    Code:
     double average (Func f, IntPtr p, double a, double b, int n);
    This can be rewritten to use ref Parameters instead of IntPtr aswell.

    That should help.
    www.monotorrent.com For all your .NET bittorrent needs

    NOTE: My code snippets are just snippets. They demonstrate an idea which can be adapted by you to solve your problem. They are not 100% complete and fully functional solutions equipped with error handling.

  4. #4
    Join Date
    Mar 2002
    Location
    St. Petersburg, Florida, USA
    Posts
    12,125

    Re: Interop of native C callback functions with void* parameter

    The following advice applies to specific situations, notably:

    1) The person has a C++ bacckground...
    2) The person is NOT an expert on "internals"...
    3) Performance is not a 100% driving factor...


    a) In native C++, write a COM compliant wrapper (if the target code is not already)

    b) Use the COM interop functionallity to create a managed wrapper.

    c) USe the managed wrapper.

    Even if 1-3 do not "fully" apply, this approach (inconjunction with a tool like Reflector] is often the best way to "derive" the necessary mapping.
    TheCPUWizard is a registered trademark, all rights reserved. (If this post was helpful, please RATE it!)
    2008, 2009,2010
    In theory, there is no difference between theory and practice; in practice there is.

    * Join the fight, refuse to respond to posts that contain code outside of [code] ... [/code] tags. See here for instructions
    * How NOT to post a question here
    * Of course you read this carefully before you posted
    * Need homework help? Read this first

  5. #5
    Join Date
    Dec 2007
    Location
    Brazil
    Posts
    37

    Re: Interop of native C callback functions with void* parameter

    Quote Originally Posted by ahoodin View Post
    May I ask why you are not using delegates?

    Function pointers doubtless would not be "safe".
    As an act of despair. Changed it back. See my other response below.

  6. #6
    Join Date
    Dec 2007
    Location
    Brazil
    Posts
    37

    Re: Interop of native C callback functions with void* parameter

    Did as suggested. The complete C# program is now:
    Code:
    using System;
    using System.Runtime.InteropServices;
    
    namespace TestSharp
    {
    class MainClass
    {
      [StructLayout (LayoutKind.Sequential)]
      struct Parameters { public double a, b, c; }
    
      delegate double Func (double x, ref Parameters p);
    
      [DllImport ("generic.dll")] static extern
      double average (Func f, ref Parameters p, double a, double b, int n);
    
      static double Quadratic (double x, ref Parameters p)
      { return (p.a*x + p.b)*x + p.c;}
    
      public static void Main(string[] args)
      {
        Parameters	par;
        Func	func;
        double	avg;
    
        par = new Parameters();    { par.a = 1;  par.b = 0;  par.c=-5;}
        func = new Func (Quadratic);
        avg = average (func, ref par, 0.0, 2.0, 10);
        Console.WriteLine("Average in [0,2] (10 points): " + avg.ToString() +"\r\n");
        Console.WriteLine("RETURN to terminate ...");
        Console.ReadLine();
      }
    }
    }
    The error message is now:
    Exception System.ExecutionEngineException was thrown in debuggee:
    <null reference>

    Main() - c:\Documents and Settings\Frank\My Documents\Exercises\C\GSL\Generic\TestSharp\Main.cs:28,5

    Line 28 is the one which goes avg = average (func, ref par, ...,
    but neither func nor par is null when looking at it with the debugger.
    The result is independent of 'Parameters' being a class or a struct.

  7. #7
    Join Date
    Dec 2007
    Location
    Brazil
    Posts
    37

    Re: Interop of native C callback functions with void* parameter

    Unfortunately, prerequisite (1) cannot be supposed
    (as well as the one about knowledge of COM) :-(

  8. #8
    Join Date
    Mar 2001
    Posts
    2,529

    Re: Interop of native C callback functions with void* parameter

    Quote Originally Posted by hreba View Post
    Did as suggested. The complete C# program is now:
    I think I see now.

    http://msdn.microsoft.com/en-us/library/aa288468.aspx
    I dug just far enough to find examples of delegates / function pointers and PInvoke that cover the needed syntax. You can find the syntax down near the bottom of the article.

    HTH,
    ahoodin
    To keep the plot moving, that's why.

  9. #9
    Join Date
    Nov 2008
    Posts
    10

    Re: Interop of native C callback functions with void* parameter

    Quote Originally Posted by ahoodin View Post
    I think I see now.

    http://msdn.microsoft.com/en-us/library/aa288468.aspx
    I dug just far enough to find examples of delegates / function pointers and PInvoke that cover the needed syntax. You can find the syntax down near the bottom of the article.

    HTH,
    Thanks for this link, I used this to fix a similar problem I was experiencing

    http://www.codeguru.com/forum/showthread.php?t=465078

    Thanks,

    Matt

  10. #10
    Join Date
    Mar 2001
    Posts
    2,529

    Re: Interop of native C callback functions with void* parameter

    To Quote from the MSDN:
    Registering Callback Methods

    To register a managed callback that calls an unmanaged function, declare a delegate with the same argument list and pass an instance of it via PInvoke. On the unmanaged side it will appear as a function pointer. For more information about PInvoke and callback, see A Closer Look at Platform Invoke.

    For example, consider the following unmanaged function, MyFunction, which requires callback as one of the arguments:
    Copy Code

    typedef void (__stdcall *PFN_MYCALLBACK)();
    int __stdcall MyFunction(PFN_ MYCALLBACK callback);
    To call MyFunction from managed code, declare the delegate, attach DllImport to the function declaration, and optionally marshal any parameters or the return value:
    Copy Code

    Code:
    public delegate void MyCallback();
    [DllImport("MYDLL.DLL")]
    public static extern void MyFunction(MyCallback callback);
    Also, make sure the lifetime of the delegate instance covers the lifetime of the unmanaged code; otherwise, the delegate will not be available after it is garbage-collected.
    HTH,
    ahoodin
    To keep the plot moving, that's why.

  11. #11
    Join Date
    Dec 2007
    Location
    Brazil
    Posts
    37

    Re: Interop of native C callback functions with void* parameter

    Quote Originally Posted by ahoodin View Post
    I think I see now.

    http://msdn.microsoft.com/en-us/library/aa288468.aspx
    I dug just far enough to find examples of delegates / function pointers and PInvoke that cover the needed syntax. You can find the syntax down near the bottom of the article.

    HTH,
    I cannot help myself, I think I have done everything as recommended there. Reinstalled MinGW and MSys and compiled everything anew. Nevertheless, I get the null reference error message. Attached eveything (native and C#).
    Attached Files Attached Files

  12. #12
    Join Date
    Dec 2007
    Location
    Brazil
    Posts
    37

    Re: Interop of native C callback functions with void* parameter

    Resolved finally. The crucial hints came from ahoodin and from the Mingw-users list with a reference to
    http://www.nabble.com/Using-a-mingw-...d18586582.html:

    Either the callback prototype in the native dll has to be specified as stdcall, or the calling convention of the C# delegate must be specified as cdecl:

    Code:
      [UnmanagedFunctionPointer (CallingConvention.Cdecl)]
      delegate double Func (double x, ref Parameters p);
    Thank you all!

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured