Calling UnityPluginLoad manually

I’m calling functions in a native rendering plugin manually using LoadLibrary, GetProcAddress etc. This is to avoid the problem of having to restart Unity every time I recompile the native plugin.

The problem with this approach is that UnityPluginLoad is never called. Is there a way make this happen manually?

It’s a bit late but I came across the same issue today. As long as a plugin is not loaded via DllImport attributes, Unity doesn’t call the function UnityPluginLoad (basically Unity knows nothing about your plugin if your loading it manually).

But actually all unity does is passing a pointer to a IUnityInterfaces* via the UnityPluginLoad.

So to make it my main plugin (loaded manually work), I just made another plugin (the binder), which is loaded via a DllImport (but it’s fine because we don’t need to iterate other this one) which stores the pointer to the IUnityInterfaces and expose a single function that returns that pointer as a ulong (to C#)

In C# you simply need to get the pointer and pass it to you main plugin.

Here is the code of the binder plugin:

#include "unity/IUnityInterface.h"
#include <cstdint>

static IUnityInterfaces* s_UnityInterfaces = nullptr;

extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API UnityPluginLoad(IUnityInterfaces* unityInterfaces)
{
	s_UnityInterfaces = unityInterfaces;	
}

extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API UnityPluginUnload()
{
	s_UnityInterfaces = nullptr;
}

extern "C" uint64_t UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API GetUnityInterfacePtr()
{
	return reinterpret_cast<uint64_t>(s_UnityInterfaces);
}

The C# code

// Delegate for the ManualUnityPluginLoad function of the Main Plugin
private delegate void ManualUnityPluginLoadDelegate(ulong interfacePtr);
private ManualUnityPluginLoadDelegate ManualUnityPluginLoad;

[DllImport("kernel32")]
public static extern IntPtr LoadLibrary(string path);

// Binding for the 
[System.Runtime.InteropServices.DllImport("PluginBinder")]
private static extern ulong GetUnityInterfacePtr();

protected virtual void Awake()
{
    // Load the main plugin
    IntPtr lib = LoadLibrary("MainPlugin");
    
    // Bind the function ManualUnityPluginLoad of your main plugin 
    // to the corresponding delegate
    IntPtr symbol = GetProcAddress(this.lib, "ManualUnityPluginLoad");  
    ManualUnityPluginLoad = Marshal.GetDelegateForFunctionPointer(
        symbol,
        typeof(ManualUnityPluginLoadDelegate)) as ManualUnityPluginLoadDelegate;

    // Load the PluginBinder and fetch the pointer to the IUnityInterfaces
    ulong interfacePtr = GetUnityInterfacePtr();

    // Send the pointer to IUnityInterfaces to your main plugin
    ManualUnityPluginLoad(interfacePtr);
}

And add a definition for ManualUnityPluginLoad in the main plugin

// This is basically unity's example for Low Level Native Plugin
// Provided here:
// https://docs.unity3d.com/Manual/NativePluginInterface.html

static IUnityInterfaces* s_UnityInterfaces = nullptr;
static IUnityGraphics* s_Graphics = nullptr;

//--------------------------------------------------------------------------
// Insert this method to unity's example code
// It basically convert the raw pointer back to a IUnityInterfaces
// and call UnityPluginLoad as if Unity was calling
//--------------------------------------------------------------------------
extern "C" void VOXL_API ManualUnityPluginLoad(uint64_t unityInterfacesPtr)
{
	IUnityInterfaces* unityInterfaces = reinterpret_cast<IUnityInterfaces*>(unityInterfacesPtr);
	if (unityInterfaces != nullptr)
	{
		UnityPluginLoad(unityInterfaces);
	}
}

//--------------------------------------------------------------------------

extern "C" void	UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API UnityPluginLoad(IUnityInterfaces* unityInterfaces)
{
	s_UnityInterfaces = unityInterfaces;
	s_Graphics = s_UnityInterfaces->Get<IUnityGraphics>();
	s_Graphics->RegisterDeviceEventCallback(OnGraphicsDeviceEvent);

    // Rest of Unity's example code
    // ...
}

I know this is a bit late but for other people who Google this, here’s what I did:

1.) Create a library with a single function that is loaded the traditional way at Unity startup, where we can define UnityPluginLoad and get the information out of it that we want (interfaces, etc.)

2.) Relay the information from the one-function library, to Unity C#, then to our runtime library whenever our runtime library is setup.

Trying to do this with the Nativerenderplugin only works for Metal unfortunately. If I use OpenGL (which I have to for a while still) this crashes in the “CreateResources” function:

Assertion failed: (status == GL_TRUE), function CreateResources, file /Users/arth/Development/TESTING/NativeRenderingPlugin/PluginSource/source/RenderAPI_OpenGLCoreES.cpp, line 172.
Stacktrace:

  at (wrapper managed-to-native) object.wrapper_native_0x141f36af0 (ulong) <IL 0x0000e, 0x000bb>
  at (wrapper managed-to-native) object.wrapper_native_0x141f36af0 (ulong) <IL 0x0000e, 0x000bb>
  at UseRenderingPlugin.InitPlugin () [0x00105] in 

Any Idea how to fix this?