Version: Unity 6.3 LTS (6000.3)
Language : English
Call unmanaged functions from managed code
DllImport attribute

Call managed functions from unmanaged code

To call a managed function from unmanaged code, you can use a delegate to define the signature of the callback function. The callback function itself must be static and have an AOT.MonoPInvokeCallbackAttribute indicating the matching delegate type:

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 it (and the native function pointer
    // that points back to it) isn't garbage collected while native code still
    // holds the function pointer.
    static MyFuncType s_callback;

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

Notes:

  • Passing a method to RegisterMyCallback creates a delegate instance. The marshaller keeps that delegate alive only for the duration of the P/Invoke call, so a callback invoked immediately is safe. If native code stores the function pointer to call later (as in this example), you must keep a managed reference to the delegate yourself – for example in a static field – for as long as native code might call it. Otherwise the garbage collector can collect the delegate and the later callback dereferences a dangling function pointer, which crashes or corrupts your program.
  • Change DllImport to use the library name if you use precompiled, dynamically linked libraries. Use the special string, __Internal for source code plug-ins and statically linked libraries. Refer to DllImport attribute for more information.

You must pass a function pointer to the unmanaged code so that it can call your managed function. In this example, the C# RegisterMyCallback function passes the function pointer.

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

// A C# delegate passed to native code defaults to the __stdcall calling convention
// on Windows, but C/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. Guard on the target
// platform (_WIN32), not the compiler: __stdcall applies to the 32-bit Windows ABI
// and is understood by every Windows compiler (MSVC, MinGW, and Clang).
#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;
    }
} // end of export C block

Your unmanaged code can invoke the callback immediately or store the function pointer to invoke later:

if(registeredCallback)
{
    registeredCallback();
}
Call unmanaged functions from managed code
DllImport attribute