Version: Unity 6.0 (6000.0)
Language : English
Call unmanaged functions from managed code
Import unmanaged functions as C# methods

Call managed functions from unmanaged code

To call a managed function from unmanaged code, pass a function pointer to the unmanaged code. Use a delegate to define the signature of the callback function. The callback function must be static and have an AOT.MonoPInvokeCallbackAttribute that indicates the matching delegate type.

Register a managed callback

The following C# example defines a delegate type and a static callback function, and passes the callback to the unmanaged RegisterMyCallback function:

using System;
using System.Runtime.InteropServices;
using UnityEngine;

public class PluginImport : MonoBehaviour
{
    delegate void MyFuncType();

    [AOT.MonoPInvokeCallback(typeof(MyFuncType))]
    static void MyFunction() {
        Debug.Log("Got a call back from native code.");
    }

    [DllImport("__Internal")]
    static extern void RegisterMyCallback(MyFuncType func);

    // Keep a reference to the delegate so the garbage collector doesn't collect it
    // while native code still holds the function pointer.
    static MyFuncType s_callback;

    void Start()
    {
        s_callback = MyFunction;
        RegisterMyCallback(s_callback);
    }
}

Important: When you pass a method to RegisterMyCallback, the runtime creates a delegate instance. The marshaller keeps that delegate alive only for the duration of the call, so a callback that native code invokes immediately is safe. If native code stores the function pointer to call later, as in this example, keep a managed reference to the delegate, such as in a static field, for as long as native code might call it. Otherwise, the garbage collector can collect the delegate, and a later callback uses an invalid function pointer, which crashes or corrupts your application.

Note: If you use a precompiled, dynamically linked library, change the DllImport value to the library name. Use the special string __Internal for source code plug-ins and statically linked libraries. For more information, refer to DllImport attribute.

Receive the callback in unmanaged code

The unmanaged code must define a function pointer type that corresponds to the C# delegate. It must also export a function that receives the pointer to your delegate:

// On Windows, a C# delegate passed to native code defaults to the __stdcall calling convention,
// but C and C++ function pointers default to __cdecl.
// Define a macro so the function pointer type and the exported function use a matching convention on every platform.
// A mismatch crashes the 32-bit Windows Player.
// Check the target platform (_WIN32), not the compiler, because every Windows compiler
// (MSVC, MinGW, and Clang) supports __stdcall.
#if defined(_WIN32)
#define STDCALL __stdcall
#else
#define STDCALL
#endif

typedef void (STDCALL *MyFuncType)();
MyFuncType registeredCallback;

extern "C"
{
    void STDCALL RegisterMyCallback(MyFuncType func) {
        registeredCallback = func;
    }
}

Your unmanaged code can invoke the callback immediately, or store the function pointer and invoke it later:

if (registeredCallback)
{
    registeredCallback();
}

Additional resources

Call unmanaged functions from managed code
Import unmanaged functions as C# methods