I need to integrate a native C++ library into a C# project. Now in this C++ library there is class with virtual functions that I need to inherit from in C++/CLI.
So in C++/CLI I wrote someting like
class C++CliClass : public C++Class
{
C++CliClass(Callback callback) { iCallback = callback; }
virtual VirualFunctionCallFromC++(int x, int y, int z, SomeClass *p)
{
// I need to call C++/CLI here
iCallback(x, y, z, p);
}
private:
Callback iCallback;
}
I defined the callback function as:
typedef int (__cdecl *Callback)(int x, int y, int z, SomeClass *p);
The idea is now that C++ library calls the virtual function of the C++Cli
class which on his turn calls the call back which gets me hopefully into C#.
// This delegate definition is needed to setup the callback for the C++ class
delegate int CallbackDelegate(int x, int y, int z, SomeClass *p);
So now I defined a managed C++/CLI class
public ref class GCClass
{
public:
delegate <Byte>^ GetDataDelegate();
GCClass(GetData^ getDataDelegate) { iGetDataDelegate = getDataDelegate };
private:
GetDataDelegate ^iGetDataDelegate;
int GetData(int x, int y, int z, SomeClass *p)
{
// call delegate into C#
<Byte>^ data = iGetDataDelegate->Invoke();
}
public:
void SomeFunctionWhichEventuallyCallsC++Libary
{
// create a delegate for the method that will call the C# delegate
CallbackDelegate ^d = gcnew CallbackDelegate(this, &GCClass::GetData);
IntPtr del = System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(d);
// Install in the C++ class
C++CliClass(del.ToPointer());
// Setup the C++ library and install my C++ class into the library
SomeObjectOfTheLibrary->Install(&C++CliClass);
SomeObjectOfTheLibrary->DoSometing() // will call the C++ virtual function and end up in C#
// The delegate is no longer needed anymore
}
Until here the code. So what I was hoping to achieve is that someone can call a method of my managed C++/CLI class which uses a native C++ library to do his stuff. The C++ library calls on his turn the C++/CLI callback and finally a C# delegate is called. Now finally the question: everything goes fine in debug mode. In release mode however sometimes an AccesException is thrown or sometimes the application just hangs. I suspect that it has something to do with different calling conventions for C++/CLI and C++. For example I observed that the second time the callback is called the value of iCallback is different from the first time it was called. However for all next calls the value of iCallback does not change anymore. I would expect that the iCallback value should be always the same but I'm not sure because I don't know how the framework internally works to be able to call a delegate from C++. I also tried to define the calling convention of the CallbackDelegate with [UnmanagedFunctionPointer(Cdecl)]. I tried all options but had no result: I always end up in an exception or the application hangs forever. Can someone give me a hint of what might be wrong?
Make sure the delegate is not garbage collected when it's still needed.
In class C++CliClass you could add a member of type CallbackDelegate and set it to d.
If the instance of C++CliClass only exists during execution of SomeFunction.. GC.KeepAlive(d) at the end of the function might be sufficient.
Perhaps even simpler: in C++CliClass define a memeber of type gcroot<GCClass^> then directly call the GetData function on this memeber in VirtualFunction without the need for a delegate.
One of the problems with your code above is that d is a managed reference, which means that it can be moved around at runtime. This in turn will invalidate your callback pointer.
In order to pass the delegate to native code, you need to tell the garbage collector not to move it, using GCHandle::Alloc:
CallbackDelegate^ d = gcnew CallbackDelegate(this, &GCClass::GetData);
// As long as this handle is alive, the GC will not move or collect the delegate
// This is important, because moving or collecting invalidate the pointer
// that is passed to the native function below
GCHandle delegate_handle = GCHandle::Alloc(d);
IntPtr del = System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(d);
C++CliClass native(del.ToPointer());
SomeObjectOfTheLibrary->Install(&native);
SomeObjectOfTheLibrary->DoSometing() // will call the C++ virtual function and end up in C#
// Release the handle
delegate_handle.Free();
Related
I want my C# program (A Unity app) to call into iOS native code so that I can communicate with, e.g., Apple Health. I've successfully got my program calling in to run Swift code, but I want to be able to provide callback functions for asynchronous action, and I think I'm missing some detail to allow these to work.
I've got two example Swift functions. returnTrue returns a bool immediately, and sendTrue takes in a callback to send the bool:
Example.swift
public struct Example {
static func returnTrue() -> Bool {
return true
}
static func sendTrue(callback: #escaping (Bool) -> Swift.Void) {
callback(true);
}
}
I've exposed these Swift functions to C using #_cedcl:
Bridge.swift
import Foundation
#_cdecl("Example_returnTrue")
public func Example_returnTrue() -> Bool {
print("Example_returnTrue started");
return Example.returnTrue();
}
#_cdecl("Example_sendTrue")
public func Example_sendTrue(callback: #escaping (Bool) -> Swift.Void) {
print("Example_sendTrue started");
Example.sendTrue(callback: callback);
}
Then I've set up a simple C# script in my Unity project to call these:
iOSCommunication.cs
using System;
using UnityEngine;
using System.Runtime.InteropServices;
using AOT;
public class iOSCommunication : MonoBehaviour
{
[DllImport("__Internal")]
private static extern bool Example_returnTrue();
[DllImport("__Internal")]
private static extern void Example_sendTrue(Action<bool> callback);
public void Start()
{
Debug.Log($"returnTrue: {Example_returnTrue()}");
Example_sendTrue(ResultHandler);
}
[MonoPInvokeCallback(typeof(Action<bool>))]
private static void ResultHandler(bool result)
{
Debug.Log($"sendTrue: {result}");
}
}
When I run this, the simple returnTrue function works but sendTrue crashes. Here's my brief log output:
Example_returnTrue started
returnTrue: True
Stacktrace is not supported on this platform.
(lldb)
The error given in Xcode is EXC_BAD_ACCESS and it seems to occur early within the Example_sendTrue function, but I can only see the machine code. Notably, we don't print Example_sendTrue started, so I think the problem is with initialisation of this function.
I've been advised to add (and have added) the decorator MonoPInvokeCallback to the C# method I pass through so that it's made visible to C, but I suspect I'm missing a declaration on the Swift side to describe what this is, or that I'm not correctly describing the callback's signature to C and/or Swift.
Adding a #convention(c) attribute to the callback's signature in both the static function and C declaration defines the parameter as a C function pointer. This is then correctly addressable by Swift when a C function is passed in as the parameter, and can be invoked in the expected way.
#_cdecl("Example_sendTrue")
public func Example_sendTrue(callback: #escaping #convention(c) (Bool) -> Swift.Void) {
print("Example_sendTrue started");
Example.sendTrue(callback: callback);
}
static func sendTrue(callback: #escaping #convention(c) (Bool) -> Swift.Void) {
callback(true);
There's no direct interoperability between C# and Swift, so any interoperability between them has to pass through a C interface, which has no native representation of Swift closures or C# Delegates/Actions.
The closest thing is to pass a function pointer, which must be #convention(c).
Here's an excerpt from a thread I started on the Swift forums about something this: https://forums.swift.org/t/add-api-that-makes-it-easier-to-interoperate-with-c-callbacks/62718.
It's more concerned with calling C APIs from Swift than having Swift APIs be called from C, but the function pointer+userInfo pointer idea is much the same.
C doesn't have the luxury of closures, and by extension, neither does Swift code that tries to interoperate with C APIs. C functions that want to have a callback have to take a function pointer, which is #convention(c) by Swift terms. If you try to pass a capturing closure, you'd get a compilation error:
❌ a C function pointer cannot be formed from a closure that captures context
Working around this is pretty tricky, and requires some pretty sophisticated knowledge. (There are Objective-C blocks which can be used in C code, but they're not a standard part of C itself, and there are plenty of APIs that don't use them, so I don't see them as a solution to this problem.)
C APIs often simulate closures by using a pair parameters:
A function pointer (for defining the behaviour)
And an accompanying context pointer (for the contextual data). This is often called "userInfo" or "context" and is just a void * pointer.
When the callback is called, you're passed back your context as an argument, which you can cast to whatever type you had given it, and unpack your contextual variables from there.
Here's an example simulated C API:
import Foundation
import Dispatch
// Just a simple example, written in Swift so you don't need to set up a complex multi-lang project.
Pretend this was an imported C API.
func runCallback(
after delaySeconds: Int,
userInfo: UnsafeRawPointer?,
callback: #convention(c) (_ currentTime: UInt64, _ userInfo: UnsafeRawPointer?) -> Void
) {
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(delaySeconds) ) {
callback(
DispatchTime.now().uptimeNanoseconds, // Some values given to you by the C API
userInfo // Passes back your `userInfo` for you to access your context.
)
}
}
Calling it from Swift is a little tricky, in part because you need to be pretty careful with specifying how userInfo's memory should be managed.
Here's an example of one way to call such an API with a userInfo parameter. This approach uses the userInfo value to smuggle in a closure which can be invoked. This lets you have the convenience of a normal Swift closure on the caller, while being compatible with the C API. It adds one extra layer of function indirection, but that's usually acceptable.
func cAPICaller_closure() {
let i = 123 // Some local state we want to close over and use in our callback
typealias ClosureType = (_ currentTimeNS: UInt64) -> Void
// This is just a simple Swift closure. It can capture variables like normal,
// and doesn't need to know/worry about the `userInfo` pointer
let closure: ClosureType = { currentTimeNS in
print("Hello, world! \(currentTimeNS) \(i)")
}
runCallback(
after: 1,
userInfo: Unmanaged.passRetained(closure as AnyObject).toOpaque(), // Needs `as AnyObject`? A bit odd, but sure.
callback: { currentTimeNS, closureP in
guard let closureP else { fatalError("The userInfo pointer was nil!") }
// Retain the pointer to get an object, and cast it to our Swift closure type
guard let closure = Unmanaged<AnyObject>.fromOpaque(closureP).takeRetainedValue() as? ClosureType else {
fatalError("The userInfo points to an object that wasn't our expected closure type.")
}
// Call our Swift closure, passing along the callback arguments, but not any `userInfo` pointer
closure(currentTimeNS)
}
)
}
I'm working with an unmanaged C library which has a callback function that gets called from an internal thread in the C library. The callback has a void * 'context' parameter.
I want to set this context to the address of a C# class instance so that I can access member fields and properties from the callback.
My understanding is that I need to pin the memory of the class to ensure the GC does not move it since the C code will take a copy of address of the instance.
However, GCHandle.Alloc() states that: "An instance with nonprimitive (non-blittable) members cannot be pinned."
And sure enough code attempting to pin a class or a struct containing a field of class type fails at runtime.
How can I pass the address of a C# class instance to my C++ code and ensure that the address remains valid (i.e. is not moved by GC)?
EDIT #1
Correction: the library is a C library, not C++ as previously stated (corrected in text above). Not that it should make any difference.
This the prototype for the C callback:
void Callback(uint32_t hCamera, uint32_t dwInterruptMask, void *pvParams);
And wrapped in C#:
[UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]
public unsafe delegate void PHX_AcquireCallBack(uint hCamera, uint dwInterruptMask,
IntPtr pvParams);
pvParams is passed into the C library when the callback is installed. The library stores the pointer, but does not attempt to access it in any way. It just passes it back whenever it calls the callback.
When using the library from C++ code, I usually pass a this pointer for pvParams.
in my next project I want to implement a GUI for already existing code in C++.
My plan is to wrap the C++ part in a DLL and to implement the GUI in C#. My problem is that I don't know how to implement a callback from the unmanaged DLL into the manged C# code. I've already done some development in C# but the interfacing between managed and unmanaged code is new to me. Can anybody give me some hints or reading tips or a simple example to start from? Unfortunatly I could not find anything helpful.
You don't need to use Marshal.GetFunctionPointerForDelegate(), the P/Invoke marshaller does it automatically. You'll need to declare a delegate on the C# side whose signature is compatible with the function pointer declaration on the C++ side. For example:
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
class UnManagedInterop {
private delegate int Callback(string text);
private Callback mInstance; // Ensure it doesn't get garbage collected
public UnManagedInterop() {
mInstance = new Callback(Handler);
SetCallback(mInstance);
}
public void Test() {
TestCallback();
}
private int Handler(string text) {
// Do something...
Console.WriteLine(text);
return 42;
}
[DllImport("cpptemp1.dll")]
private static extern void SetCallback(Callback fn);
[DllImport("cpptemp1.dll")]
private static extern void TestCallback();
}
And the corresponding C++ code used to create the unmanaged DLL:
#include "stdafx.h"
typedef int (__stdcall * Callback)(const char* text);
Callback Handler = 0;
extern "C" __declspec(dllexport)
void __stdcall SetCallback(Callback handler) {
Handler = handler;
}
extern "C" __declspec(dllexport)
void __stdcall TestCallback() {
int retval = Handler("hello world");
}
That's enough to get you started with it. There are a million details that can get you into trouble, you are bound to run into some of them. The much more productive way to get this kind of code going is writing a wrapper in the C++/CLI language. That also lets you wrap a C++ class, something you can't do with P/Invoke. A decent tutorial is available here.
P/Invoke can handle marshaling a managed delegate to a function pointer. So if you expose API's that register a call back function from your DLL and in C# pass a delegate to that function.
There is an example on MSDN of doing this with the EnumWindows function. In that article be careful to pay attention to the line in point 4 that states:
If, however, the callback function can
be invoked after the call returns, the
managed caller must take steps to
ensure that the delegate remains
uncollected until the callback
function finishes. For detailed
information about preventing garbage
collection, see Interop Marshaling
with Platform Invoke.
What that is saying is that you need to make sure that your delegate isn't garbage collected until after the managed code is done calling it by either keeping a reference to it in your code, or pinning it.
See Marshal.GetFunctionPointerForDelegate, which will give you a function pointer for calling managed (i.e. C# code) from unmanaged code.
Have a look at this, Marshal.GetDelegateForFunctionPointer?
in c++ i have these below classes
class A
{
public:
int __thiscall check(char *x,char *y,char *z);
private:
B *temp;
};
class B
{
friend class A;
Public:
B();
B(string x,string y,string z);
~B();
private:
string x;
string y;
string z;
};
my dll method in c++ is like this
__declspec(dllexport) int __thiscall A::check(char *x,char *y,char *z)
{
temp=new B(x,y,z);
return 1;
}
code for B() constructor is below:
B::B(string x, string y,string z)
{
.......
}
below mentioned is my c# dll import
[DllImport("sour.dll", CallingConvention = CallingConvention.ThisCall, ExactSpelling = true, EntryPoint = "check")]
public static extern void check(IntPtr val,string x,string y,string z);
the c++ build went successful with out any errors, but when i call this method from c# using dll import method i am getting this below error when i am trying to assign memory for "temp" class pointer. Below mentioned is the error.
Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
Can any one please help on this. Thanks in advance.
I would assume exporting methods instead of class members is easier.
Please make sure that the DllImport uses the correct calling convention.
__declspec(dllexport) void __cdecl check(int x)
Using PInvoke Interop Assistant results in
public partial class NativeMethods {
/// Return Type: void
///x: int
[System.Runtime.InteropServices.DllImportAttribute("<Unknown>", EntryPoint="check", CallingConvention=System.Runtime.InteropServices.CallingConvention.Cdecl)]
public static extern void check(int x) ;
}
Did you make sure that 32/64 bit version of your dll matches. If you run the x86 .net version (32bit) you can activate debugging of native and managed code and you should be able to set a break point in your C++ method to see what happens.
Using C++ directly via PInvoke will not work. A C++ class must first be instantiated via new on the heap which you cannot do from managaed code.
The member function you want to call needs to use in the DllImport statement the thiscall calling convention because it is a non static member method. This requires to implicitely pass the pointer to unmanaged class instance on the stack which you cannot really do here.
You should consider a managed C++ wrapper class (see link) to get direct access to it or you make a C wrapper where you can call ctor, dtor and instance members as direct C methods which accept and return the this pointer where necessary.
A very hacky solution might be to allocate the memory via Marshal.GlobalAlloc directly and call the ctor on this storage location via PInvoke but since you do not now in advance how much memory you need this is a dirty hack.
in my next project I want to implement a GUI for already existing code in C++.
My plan is to wrap the C++ part in a DLL and to implement the GUI in C#. My problem is that I don't know how to implement a callback from the unmanaged DLL into the manged C# code. I've already done some development in C# but the interfacing between managed and unmanaged code is new to me. Can anybody give me some hints or reading tips or a simple example to start from? Unfortunatly I could not find anything helpful.
You don't need to use Marshal.GetFunctionPointerForDelegate(), the P/Invoke marshaller does it automatically. You'll need to declare a delegate on the C# side whose signature is compatible with the function pointer declaration on the C++ side. For example:
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
class UnManagedInterop {
private delegate int Callback(string text);
private Callback mInstance; // Ensure it doesn't get garbage collected
public UnManagedInterop() {
mInstance = new Callback(Handler);
SetCallback(mInstance);
}
public void Test() {
TestCallback();
}
private int Handler(string text) {
// Do something...
Console.WriteLine(text);
return 42;
}
[DllImport("cpptemp1.dll")]
private static extern void SetCallback(Callback fn);
[DllImport("cpptemp1.dll")]
private static extern void TestCallback();
}
And the corresponding C++ code used to create the unmanaged DLL:
#include "stdafx.h"
typedef int (__stdcall * Callback)(const char* text);
Callback Handler = 0;
extern "C" __declspec(dllexport)
void __stdcall SetCallback(Callback handler) {
Handler = handler;
}
extern "C" __declspec(dllexport)
void __stdcall TestCallback() {
int retval = Handler("hello world");
}
That's enough to get you started with it. There are a million details that can get you into trouble, you are bound to run into some of them. The much more productive way to get this kind of code going is writing a wrapper in the C++/CLI language. That also lets you wrap a C++ class, something you can't do with P/Invoke. A decent tutorial is available here.
P/Invoke can handle marshaling a managed delegate to a function pointer. So if you expose API's that register a call back function from your DLL and in C# pass a delegate to that function.
There is an example on MSDN of doing this with the EnumWindows function. In that article be careful to pay attention to the line in point 4 that states:
If, however, the callback function can
be invoked after the call returns, the
managed caller must take steps to
ensure that the delegate remains
uncollected until the callback
function finishes. For detailed
information about preventing garbage
collection, see Interop Marshaling
with Platform Invoke.
What that is saying is that you need to make sure that your delegate isn't garbage collected until after the managed code is done calling it by either keeping a reference to it in your code, or pinning it.
See Marshal.GetFunctionPointerForDelegate, which will give you a function pointer for calling managed (i.e. C# code) from unmanaged code.
Have a look at this, Marshal.GetDelegateForFunctionPointer?