is it possible at all to make C/C++ function callback into Unity scripts, provided that you can create a new thread from the scripts? I tried but Unity crashes as soon as the scripts get executed.
I googled about it and found this thread which says
Unity is not callback nor threadsafe, any access to classes that extend UnityEngine.Object is only allowed from within the same thread as unity scripts are running in, not asyncronous from other threads nor from asyncrnous callbacks from COM / OS async operations
If thats the case for you there are two possible ways:
(1) Write a wrapper that gets these callbacks and queues the stuff and then expose a function that allows unity to request the next event / dataobject or whatever in a blocking, unthreaded form (2) Make the callbacks call into a static function on something extending from System.Object and write the same kind of logic as above to request the information on classes extending UnityEngine.Object
But I think if I create a thread and callback into that thread, it will be okay right? I am thinking like this because I've read threads like this one that introduces how to make C functions calling back C# functions. So I reasoned that if I create a new thread, it's no longer Unity, it will just be mono and C#.
Here is my code that crashes Unity:
The C++ code:
#include <iostream>
// #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");
}
The C# code:
using UnityEngine;
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
class UnManagedInterop : MonoBehaviour {
private delegate int Callback(string text);
private Callback mInstance; // Ensure it doesn't get garbage collected
public void Test() {
mInstance = new Callback(Handler);
SetCallback(mInstance);
TestCallback();
}
private int Handler(string text) {
// Do something...
print(text);
return 42;
}
[DllImport("test0")]
private static extern void SetCallback(Callback fn);
[DllImport("test0")]
private static extern void TestCallback();
void Start()
{
Thread oThread = new Thread(new ThreadStart(Test));
// Start the thread
oThread.Start();
}
}
The answer is Yes!
I tested again on August 8, 2012, with Unity 3.5.2f2, Pro license. Thanks for @hatboyzero's comment I found this example.
Although the code in my question doesn't work, the following code works:
// C#
using System.Runtime.InteropServices;
class Demo {
delegate int MyCallback1 (int a, int b);
[DllImport ("MyRuntime")]
extern static void RegisterCallback (MyCallback1 callback1);
static int Add (int a, int b) { return a + b; }
static int Sub (int a, int b) { return a - b; }
void Init ()
{
// This one registers the method "Add" to be invoked back by C code
RegisterCallback (Add);
}
}
// C
typedef int (*callback_t) (int a, int b);
static callback_t my_callback;
void RegisterCallback (callback_t cb)
{
my_callback = cb;
}
int InvokeManagedCode (int a, int b)
{
if (my_callback == NULL){
printf ("Managed code has not initialized this library yet");
abort ();
}
return (*my_callback) (a, b);
}
I didn't have to embed MonoRuntime as the tutorial suggests. Just the above two pieces of code solved my problem.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With