Call C++ Function Pointer from C#

Call C function inside C# via function pointer

You'll want to use Marshal.GetDelegateForFunctionPointer. You won't even need to use unsafe code.

delegate void TestCallbackDelegate(); //must match the signature of test_callback()

public static void callCallback(int ptr)
{
IntPtr nativePtr = new IntPtr( ptr );

var callback = Marshal.GetDelegateForFunctionPointer<TestCallbackDelegate>( nativePtr );

callback();
}

public static int test(string param)
{
char[] ptrChar = param.ToCharArray();
int ptrInt = 0;

ptrInt = ( ((int)(0xFF00 & (int)ptrChar[1]) | (0x00FF & (int)ptrChar[1])) << 16 ) |
(int)(0xFF00 & (int)ptrChar[0]) | (0x00FF & (int)ptrChar[0]);

callCallback(ptrInt);
}

Although a much simpler way would be to just pass a void* to the C# method, and it will automatically get marshalled to IntPtr. Here's a minimal example of that:

C++

//invoke.cpp
//compile with: cl /EHsc /LD /nologo invoke.cpp
#include <stdio.h>

static void test_callback()
{
printf("test_callback called\n");
}

extern "C" __declspec( dllexport ) void* getPointer()
{
return (void*)&test_callback; //Return a raw pointer to the test_callback function.
}

C#

//invoke.cs
//compile with: csc /nologo invoke.cs
using System;
using System.Runtime.InteropServices;

class Program
{
[DllImport( "invoke.dll" )]
private static extern IntPtr getPointer();

private delegate void TestCallbackDelegate(); //Delegate that matches the signature of test_callback

static void main()
{
IntPtr ptr = getPointer(); //Fetch the native void pointer.
TestCallbackDelegate test_callback = Marshal.GetDelegateForFunctionPointer<TestCallbackDelegate>( ptr ); //Marshal the void pointer to a delegate.
test_callback(); //Invoke the native C function.
}
}

I used the DllImport attribute to avoid having to invoke the CLR as you're doing, but it's the same idea.


EDIT: Because I realized the above doesn't apply to what the OP was asking, I'll include an updated and proper sample. The above will remain for posterity.

C

#define COBJMACROS

#include <stdio.h>
#include <windows.h>
#include <mscoree.h>

static void test_callback()
{
printf( "test_callback has been called.\n" );
}

int main( void )
{
HRESULT status;
ICLRRuntimeHost *Host;
BOOL Started;
DWORD Result;

Host = NULL;
Started = FALSE;

status = CorBindToRuntimeEx( NULL, NULL, 0, CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (void**)&Host );

if( FAILED( status ) )
goto cleanup;

status = ICLRRuntimeHost_Start( Host );

if( FAILED( status ) )
goto cleanup;

Started = TRUE;

int ptr = (int)&test_callback;
printf( "test_callback is at 0x%X\n", ptr );

char param[5];
param[0] = 0xFF & ( ptr >> 0 );
param[1] = 0xFF & ( ptr >> 8 );
param[2] = 0xFF & ( ptr >> 16 );
param[3] = 0xFF & ( ptr >> 24 );
param[4] = '\0';

status = ICLRRuntimeHost_ExecuteInDefaultAppDomain( Host, L"invoke.dll", L"InteropTesting.Invoker", L"InvokeCallback", (LPCWSTR)param, &Result );

if( FAILED( status ) )
goto cleanup;

cleanup:
if( Started )
ICLRRuntimeHost_Stop( Host );

if( Host != NULL )
ICLRRuntimeHost_Release( Host );

return SUCCEEDED( status ) ? 0 : 1;
}

C#

using System;
using System.Runtime.InteropServices;

namespace InteropTesting
{
public static class Invoker
{
private delegate void TestCallbackDelegate();

public static int InvokeCallback( string param )
{
//C# has a built-in means of turning byte arrays into integers
//so we'll use BitConverter instead of using the bitwise operators.
char[] chars = param.ToCharArray();
int ptr = BitConverter.ToInt32( Array.ConvertAll( chars, c => (byte)c ), 0 );

var test_callback = (TestCallbackDelegate)Marshal.GetDelegateForFunctionPointer( new IntPtr( ptr ), typeof( TestCallbackDelegate ) );
test_callback();

return 0;
}
}
}

Call c++ function pointer from c#

dtb is right. Here a more detailed example for Marshal.GetDelegateForFunctionPointer. It should work for you.

In C++:

static int __stdcall SomeFunction(void* someObject, void*  someParam)
{
CSomeClass* o = (CSomeClass*)someObject;
return o->MemberFunction(someParam);
}

int main()
{
CSomeClass o;
void* p = 0;
CSharp::Function(System::IntPtr(SomeFunction), System::IntPtr(&o), System::IntPtr(p));
}

In C#:

public class CSharp
{
delegate int CFuncDelegate(IntPtr Obj, IntPtr Arg);
public static void Function(IntPtr CFunc, IntPtr Obj, IntPtr Arg)
{
CFuncDelegate func = (CFuncDelegate)Marshal.GetDelegateForFunctionPointer(CFunc, typeof(CFuncDelegate));
int rc = func(Obj, Arg);
}
}

Set C Function Pointer to C# Function

I confirmed that this is not possible in C# directly, so interfacing with the libary load function is required. Thanks to both for answers though, definitely useful.

How to pass a delegate or function pointer from C# to C++ and call it there using InternalCall

After some more hours of digging I finally found a (the?) solution.

Basically, what works for the PInvoke approach works here as well, you can pass a function pointer instead of a delegate from C# to C(++).

I'd prefer a solution where you can pass a delegate directly, but you can always add some wrapper code in C# to at least make it look like that.

Solution:

C#:

public delegate void CallbackDelegate(string message);
[MethodImplAttribute(MethodImplOptions.InternalCall)]
public static extern void setCallback(IntPtr aCallback);

private CallbackDelegate del;
public void testCallbacks()
{
System.Console.Write("Registering C# callback...\n");
del = new CallbackDelegate(callback01);
setCallback(Marshal.GetFunctionPointerForDelegate(del));

System.Console.Write("Calling passed C++ callback...\n");
}

public void callback01(string message)
{
System.Console.Write("callback 01 called. Message: " + message + "\n");
}

C++:

typedef void (*CallbackFunction)(MonoString*);
void setCallback(CallbackFunction delegate)
{
std::cout << &delegate << std::endl;
delegate(mono_string_new(mono_domain_get(), "Test string set in C++"));
}

Watch out, though: You need to keep the delegate around in C# somehow (which is why I assigned it to "del") or it will be caught by the GC and your callback will become invalid.

It makes sense, of course, but I feel this is easy to forget in this case.

How to pass function pointer from C# to a C++ Dll?

Your delegate uses the cdecl calling convention. In C# you would therefore declare the delegate like this:

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate double CallbackDelegate(double x);

As an alternative, you could decide to declare the function pointer in C++ as __stdcall, in which case you would remove the UnmanagedFunctionPointer attribute and rely on the default calling convention being CallingConvention.StdCall.

Implement it like this:

public static double MyFunc(double x)
{
return Math.Sqrt(x);
}

In order to keep the unmanaged function pointer alive (guarding against GC), you need to hold an instance of the delegate in a variable.

private static CallbackDelegate delegateInstance;
....
delegateInstance = MyFunc;

In the simple example that you have here, the C++ code does not use the unmanaged function pointer outside of TestDelegate, but in a more complex example you may do so, in which case you must keep the unmanaged function pointer alive.

The function that you import is declared like this:

[DllImport("DllName.dll")]
public extern static double TestDelegate(CallbackDelegate f);

You can then call it like this:

double retval = TestDelegate(delegateInstance);

How do I call a c function from C#

Take a look at http://msdn.microsoft.com/en-us/library/ektebyzx(v=vs.80).aspx for how to marshal function pointers. There is an example on the bottom of that page.

I'll do the C# for you, and since I don't know which direction the pointer is going, I'll show both. There are some gotchas which could be problematic for you involving calling conventions. Marshal.GetDelegateForFunctionPointer and Marshal.GetFunctionPointerForDelegate assume the function pointer will be StdCall so if you don't have access to the unmanaged library to make sure the function pointer is standard call (I think C defaults to cdecl unfortunately), you'd have to create an unmanaged shim library to change the calling convention, unless there is some other way I don't know about.

This would be the header of a C DLL I named "UnmanagedLib.dll".

typedef void ( __stdcall *WRITE_CALLBACK)(int hMountEnv, unsigned __int64 NumBytesWritten, void* pContext);

extern "C" {
__declspec(dllexport) WRITE_CALLBACK __stdcall FunctionProducingFunctionPointer(void);
__declspec(dllexport) void __stdcall FunctionConsumingFunctionPointer(WRITE_CALLBACK callback);
}

This would be the CPP file of the DLL.

#include "UnmanagedLib.h"

void __stdcall SampleFunction(int hMountEnv, unsigned __int64 NumBytesWritten, void* pContext)
{
}

WRITE_CALLBACK __stdcall FunctionProducingFunctionPointer(void)
{
return &SampleFunction;
}

void __stdcall FunctionConsumingFunctionPointer(WRITE_CALLBACK callback)
{
// sample call
(*callback)(0,0,NULL);
}

And lastly, this is a C# program to make use of the DLL.

class Program
{
public delegate void WRITE_CALLBACK(int hMountEnv, ulong NumBytesWritten, IntPtr pContext);

[DllImport("UnmanagedLib.dll")]
public static extern IntPtr FunctionProducingFunctionPointer();

[DllImport("UnmanagedLib.dll")]
public static extern void FunctionConsumingFunctionPointer(IntPtr functionPointer);

public static void SampleFunction(int hMountEnv, ulong NumBytesWritten, IntPtr pContext)
{
}

static void Main(string[] args)
{
var functionDelegateToManagedSampleFunction = new WRITE_CALLBACK(SampleFunction);
var functionDelegateToUnmanagedSampleFunction = Marshal.GetDelegateForFunctionPointer(FunctionProducingFunctionPointer(), typeof(WRITE_CALLBACK));

// call the unmanaged sample function via its pointer
functionDelegateToUnmanagedSampleFunction.DynamicInvoke(new object[] {0,0ul,null});

// pass the managed sample function to the unmanaged code
FunctionConsumingFunctionPointer(Marshal.GetFunctionPointerForDelegate(functionDelegateToManagedSampleFunction));
}
}

Calling C function from C#, passing struct which contains pointers

C pointers are unsafe by nature, but you don't need to use the unsafe keyword here, even though the underlying concepts will be used.

You may declare the struct with an IntPtr:

struct myStruct
{
public int myInt;
public IntPtr myFloatPointer;
}

And initialize the field with Marshal method, after pinning the float array:

    float[] data = new float[15];
myStruct ms = new myStruct();

GCHandle gch = GCHandle.Alloc(data, GCHandleType.Pinned);
ms.myFloatPointer = Marshal.UnsafeAddrOfPinnedArrayElement(data, 0);

This way, you don't make use of the unsafe keyword.

Be aware that depending on the Platform you are running on, the size of pointer and its alignment may vary; the structure might need some specific layout.

Calling C function with pointers from F#

Couple of options for this.

Option #1

Create a byref or outref rather than a ref by binding mbuf and tbuf as mutable values and then passing them "by reference" using &.

let main argv =
...
let mutable mbuf = PCANBasic.TPCANMsg(0x010u, Array.zeroCreate 8)
let mutable tbuf = PCANBasic.TPCANTimestamp(0u,0us,0us)
let status = PCANBasic.read(handle, &mbuf, &tbuf)

Option #2

Define read as a member rather than a function to allow it to be invoked with ref arguments rather than byref. Your main function can then stay the same other than referencing the static Reader.Read method rather than the read function.

type Reader =
static member Read (chan : TPCANHandle, [<Out>] msgbuf : TPCANMsg byref, [<Out>] tsbuf : TPCANTimestamp byref) =
Imported.Read(chan, msgbuf, tsbuf)

[<Out>] Attribute

Looking at F# RFC FS-1053 indicates that a byref<T> argument with the [<Out>] attribute is equivalent to an outref<T> argument, so your read function/member definition could be (slightly) shortened to:

let read (chan : TPCANHandle, msgbuf : TPCANMsg outref, tsbuf : TPCANTimestamp outref) =
Imported.Read(chan, msgbuf, tsbuf)


Related Topics



Leave a reply



Submit