- Home /
Using native plugin with callbacks in editor (OS X)
I have a native plugin that has callbacks back to the C# code. This is how the callbacks are setup:
C# Side (Unity):
public delegate void Callback(int value);
[DllImport("NativePlugin")]
public static extern void setup_callback(Callback callback);
[MonoPInvokeCallback(typeof(Callback))]
private static void OnCallback(int value)
{
Debug.Log("Callback called with value: " + value);
}
void Start()
{
setup_callback(OnCallback);
}
The Objective-C side (with C wrapper so you'd be able to call it from C#):
typedef void(*Callback)(int);
Callback _callback = NULL;
void setup_callback(Callback callback)
{
_callback = callback;
}
void on_something_happened(int value)
{
if(_callback)
_callback(value);
}
Now, most of the time the above code works ok, and I receive the correct values in Unity. But sometimes when I make changes to any one of my C# scripts, Unity crashes with this:
Exception Type: EXC_BAD_ACCESS (SIGABRT)
Exception Codes: KERN_INVALID_ADDRESS at 0x00000000ffffffa9
Exception Note: EXC_CORPSE_NOTIFY
Looking at Unity's Editor logs I found out that when I make changes to a C# script it recompiles Assembly-CSharp.dll and reloads it togheter with some other C# assemblies. So that made me think that this might cause the pointer saved in the native plugin to now point to an invalid address (because Assembly-CSharp.dll is now probably in a different address space). Note that it does not happen every time the dll gets reloaded, is it possible that it gets reloaded to the exact same address space sometimes?
Can I get an event from Unity when the editor reloads the DLL and then re-register the callbacks (assuming that this is the real problem)? Is this even the correct way to setup a callback from native code?
Hey @Untrade, did you ever resolve this? I'm dealing with the same issue. AppDomain.DomainUnload is not getting called, and object destructors are not called, so I don't know how to tell when Unity is recompiling the script and my callback is no longer valid...
Answer by Untrade · Mar 04, 2017 at 03:12 AM
I ended up using LockReloadAssemblies https://docs.unity3d.com/ScriptReference/EditorApplication.LockReloadAssemblies.html
It let's you prevent Unity from reloading until you call UnlockReloadAssemblies. I just created a new script:
void Awake()
{
//Prevent editor from reloading dlls files during the gameplay
#if UNITY_EDITOR
UnityEditor.EditorApplication.LockReloadAssemblies();
#endif
}
void OnApplicationQuit()
{
//Prevent editor from reloading dlls files during the gameplay
#if UNITY_EDITOR
UnityEditor.EditorApplication.UnlockReloadAssemblies();
#endif
}
And put it on some object in the scene.
Answer by ETLang · Mar 05, 2017 at 03:39 PM
For anyone else with a similar issue, another solution that might work for you is documented here:
http://answers.unity3d.com/questions/704066/callback-before-unity-reloads-editor-assemblies.html
In the code below, Unity will call OnDisable immediately before unloading the assembly and performing a recompile.
[InitializeOnLoad]
internal sealed class MyScriptableFriend : ScriptableObject {
static MyScriptableFriend() { s_Instance = CreateInstance<MyScriptableFriend>(); }
private static MyScriptableFriend s_Instance;
private void OnDisable() {
// Incoming recompile... save yourself!
}
}