Windows Store Apps Plugin - Calling C# back from native code

Creating plugins for Android and iOS there is a possibility to call C# method from our plugin through UnitySendMessage method.
Is there any possibilty to do the same with Windows plugin?

Isn’t UnitySendMessage a native method, is your Windows plugin native as well?

Yes my plugin is native. I use it to support Bluetooth. I am able to call native WSA methods through it. What I need to do now is to call managed methods thorugh my plugin.
Im looking for substitute for UnitySendMessage for iOS:

There’s no such method in Windows Store Apps

If it’s a native WinRT component, you could always setup the necessary delegates and call them that way.
For ex.,
from MainPage.xaml.cs call into your native plugin:
Plugin.SetDelegate(GameObjectName1.MethodName1);

and then when you need - invoke that delegate from native plugin.

Yea, passing delegates to native code is your best bet. You could even make a wrapper that works the same way.

In your C# script:

#if UNITY_WINRT

public delegate void UnitySendMessageDelegate([MarshalAs(UnmanagedType.LPStr)]string gameObjectName, [MarshalAs(UnmanagedType.LPStr)]string methodName, [MarshalAs(UnmanagedType.LPStr)]string message);

private static UnitySendMessageDelegate s_SendMessageDelegate;

[DllImport("plugin.dll")]
private static extern void SetUnitySendMessageCallback(UnitySendMessageDelegate sendMessage);

private void Awake()
{
    s_SendMessageDelegate = UnitySendMessageWrapper;
    SetUnitySendMessageCallback(s_SendMessageDelegate);
}

private static void UnitySendMessageWrapper(string gameObjectName, string methodName, string message)
{
    var gameObject = GameObject.Find(gameObjectName);
    if (gameObject != null)
    {
        gameObject.SendMessage(methodName, message);
    }
}

#endif

On C++ side:

#if UNITY_WINRT

typedef void (__stdcall* UnitySendMessageFunc)(const char* gameObjectName, const char* methodName, const char* message);

UnitySendMessageFunc UnitySendMessage = nullptr;

extern "C" __declspec(dllexport) void __stdcall SetUnitySendMessageCallback(UnitySendMessage sendMessageCallback)
{
    UnitySendMessage = sendMessageCallback;
}

#endif

And then you could use UnitySendMessage identically to what you’re using on iOS.

Note: I wrote this code straight to the forum post, it might contain syntax mistakes.

Thanks!
@Tautvydas-Zilys can I do the same if you use C# on both sides?

Sure, you can. But then with that, you could call Unity Engine APIs directly if your plugin is in C#.

Thanks for help! I made it so:

In my C# plugin:

        public delegate void UnitySendMessageFunc(string gameObjectName, string methodName, string message);
        static UnitySendMessageFunc UnitySendMessage;
        public static void SetDelegate(UnitySendMessageFunc func)
        {
            UnitySendMessage += func;
        }

In MainPage.xaml.cs

        private UnityEngine.GameObject gameObject;

        public void _UnitySendMessage(string gameObjectName, string methodName, string message)
        {
            if (gameObject == null)
            {
                gameObject = UnityEngine.GameObject.Find("BluetoothLEReceiver");
            }
            gameObject.SendMessage(methodName, message);
        }
        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            (...)
            WSABluetoothLE.WSABluetooth.SetDelegate(_UnitySendMessage);
        }

If I deploy app in Master mode everything works great. But there is some strange error in Debug mode:

Any suggestion on how to solve this problem?

You’re calling SendMessage from incorrect thread. It should be something like this:

public void _UnitySendMessage(string gameObjectName, string methodName, string message)
{
    AppCallbacks::Instance.InvokeOnAppThread(()=>
    {
        if (gameObject == null)
        {
            gameObject = UnityEngine.GameObject.Find("BluetoothLEReceiver");
        }
        gameObject.SendMessage(methodName, message);
    }, false);
}

You also don’t have to set delegate from mainpage.xaml.cs - you can do it directly from your script.

@Tomas1856 Thanks, it works great.

@Tautvydas-Zilys Which UnityEngine.dll and UnityPlayer.dll reference should I use to be able to build my plugin project with any CPU option?

UnityEngine.dll: Editor\Data\PlaybackEngines\metrosupport\Managed<SDK>\UnityEngine.dll
UnityPlayer: Editor\Data\PlaybackEngines\metrosupport\Players<SDK><CPU><Config>\UnityPlayer.winmd.

is the SDK that you’re building plugin against. The UnityEngine.dlls are identical between SDKs, but VS might complain if it doesn’t match target SDK.

For UnityPlayer.winmd, all of them are identical for all CPUs and Configs, so pick any of them.

Hi guys, my Unity and c++ test app both share the same plugin DLL and I’m trying to send messages from the test app to Unity. When ever I try to use UnitySendMessage shown in Tautvydas-Zilys’s Code above I get an Access Violation, but if Unity uses UnitySendMessag then it work. Does anyone know why the external program can’t do this?

Thanks

You’re trying to call Unity’s APIs from non-Unity application? That will not work as Unity won’t be initialized.