Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing a C# callback function through Interop/pinvoke

Tags:

I am writing a C# application which uses Interop services to access functions in a native C++ DLL. I am already using about 10 different functions which are working.

Now I am not sure how to handle passing a callback as a parameter so that the DLL can call my code.

Here is the function prototype of the DLL:

typedef void (WINAPI * lpfnFunc)(const char *arg1, const char *arg2) 

And the function that allows me to pass the above type:

int WINAPI SetFunc(lpfnFunc f) 

Here is my C# code for the delegate and function definitions:

public delegate void Func(string arg1, string arg2);  public static void MyFunc(string arg1, string arg2) 

Here is my C# code for the SetFunc Interop function:

[DllImport("lib.dll", CharSet = CharSet.Ansi)] public static extern int SetFunc(Func lpfn); 

And finally here is the code where I call the SetFunc function and pass it my callback:

SetFunc(new Func(MyFunc)); 

Unfortunately my function is not being called when it should be. The return value of the SetFunc function is returning the error code for a Success, so either it's not calling my function or it's not working because my code is wrong.

like image 424
Trevor Elliott Avatar asked Nov 01 '11 17:11

Trevor Elliott


People also ask

What is passing in C?

Arguments in C and C++ language are copied to the program stack at run time, where they are read by the function. These arguments can either be values in their own right, or they can be pointers to areas of memory that contain the data being passed. Passing a pointer is also known as passing a value by reference.

What is pass by value in C?

Pass by Value, means that a copy of the data is made and stored by way of the name of the parameter. Any changes to the parameter have NO affect on data in the calling function.

How are arguments passed in C?

By default, LotusScript® passes arguments to functions and subs by reference. If the argument is an array, a user-defined data type variable, or an object reference variable, you must pass it by reference. In most other cases, you use the ByVal keyword to pass variables by value.


2 Answers

This works for me:

Calc.h (Calc.dll, C++):

extern "C" __declspec(dllexport) double Calc(double x, double y, double __stdcall p(double, double)); 

Calc.cpp (Calc.dll, C++):

#include "calc.h"  __declspec(dllimport) double Calc(double x, double y, double __stdcall p(double, double)) {     double s = p(x*x, y*y);     return x * y + s; } 

Program.cs (Sample.exe, C#):

class Program {     delegate double MyCallback(double x, double y);     [DllImport("Calc.dll", CallingConvention = CallingConvention.Cdecl)]     static extern double Calc(double x, double y, [MarshalAs(UnmanagedType.FunctionPtr)]MyCallback func);      static void Main(string[] args)     {         double z = Calc(1, 2, (x, y) => 45);     } } 
like image 184
stop-cran Avatar answered Oct 11 '22 05:10

stop-cran


Can you try changing the Func delegate to

    public delegate void Func([In, MarshalAs(UnmanagedType.LPStr)] string arg1, [In, MarshalAs(UnmanagedType.LPStr)] string arg2); 

And the SetFunc method to

[DllImport("lib", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Winapi)] public static extern int SetFunc(Func lpfn); 
like image 44
Hasani Blackwell Avatar answered Oct 11 '22 05:10

Hasani Blackwell