How to Call C# Method from C++ Like Unity's Internal Use of NativeHeader and RequiredByNativeCode Attributes?

In my Unity project, I need to call a C# method from C++ code, similar to how Unity internally uses attributes like [NativeHeader] and [RequiredByNativeCode] to bridge the gap between managed and unmanaged code. Since these attributes are internal to Unity and not accessible for custom use, I’m looking for guidance on how to achieve similar functionality.

Has anyone had experience with this or can point me in the right direction?

Platform: macOS

Answer can be found in this very old thread that still holds true today.

1 Like

I have multiple methods that need to be called from C++. Passing them individually is inefficient. Would it be possible to call C# methods using Mono? Any guidance would be appreciated. Thanks!

Bridging language barriers always requires you to set up each individual method. That’s just the way it is.

Thank you for your reply. ChatGPT provided a solution using the Mono API to facilitate interaction between C# and my plugin. I have created a new post for it:

I am waiting for a response on this post to see if there is a solution for my plugin to call the Mono API. If not, I will try passing a function pointer to my native plugin as a workaround.

Calling C# from C++ may differ depending on platform. Specify the platform(s).

1 Like

Currently, I’m using macOS, and in the future, I need the project to be compatible with Windows and Linux as well.

The recommendation is to use reverse P/Invoke, as that will work the same on il2cpp too. There has to be a good reason to use Mono API, as that makes your code less portable (and is harder to set up).

I use Mono as my backend and have no plans to switch to IL2CPP or support other mobile platforms such as Android.

With the Mono API, besides calling C# code, I can perform tasks such as returning a C# array or updating a List and many other types exist in the C# ecosystem from C++. which is more convenient. Since I haven’t started writing the native plugin yet, I expect to discover more advantages of using the Mono API.

Regarding the setup, I found the Mono header file at /Applications/Unity/Hub/Editor/Version2022.3/Unity.app/Contents/il2cpp/external/mono. However, when I compile my native plugin, it throws the following error:

FAILED: libNativePlugin.dylib 
: && /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++ -O3 -DNDEBUG -O3 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.0.sdk -dynamiclib -Wl,-headerpad_max_install_names  -o libNativePlugin.dylib -install_name @rpath/libNativePlugin.dylib CMakeFiles/NativePlugin.dir/Main.cpp.o CMakeFiles/NativePlugin.dir/Util.cpp.o   && :
Undefined symbols for architecture x86_64:
  "_mono_get_root_domain", referenced from:
      _LogToUnity in Util.cpp.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
ninja: build stopped: subcommand failed.
#include "Util.h"
#include <mono/metadata/object.h>
#include <mono/metadata/assembly.h>
#include <mono/metadata/attrdefs.h>
#include <mono/metadata/debug-helpers.h>
#include <mono/metadata/mono-config.h>
#include <mono/metadata/appdomain.h>
#include <mono/metadata/threads.h>


extern "C" void LogToUnity(const char *message) {
    MonoDomain* domain = mono_get_root_domain();
}
cmake_minimum_required(VERSION 3.10)

project(NativePlugin)

set(CMAKE_CXX_STANDARD 11)

set(CMAKE_BUILD_TYPE Release)

include_directories("/Applications/Unity/Hub/Editor/Version2022.3/Unity.app/Contents/il2cpp/external/mono")
file(GLOB SOURCES "*.cpp")
file(GLOB HEADERS "*.h")
add_library(NativePlugin SHARED ${SOURCES})

target_include_directories(NativePlugin PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

add_executable(Main Main.cpp)
target_link_libraries(Main NativePlugin)

Based on the error log and the GPT response, it seems I just need to find the correct *.dylib compiled by Unity for my native plugin to link. Could you help check it? I might be just one step away from getting the native plugin to work.

I found the correct dylib, /Applications/Unity/Hub/Editor/Version2022.3/Unity.app/Contents/Frameworks/MonoBleedingEdge/MonoEmbedRuntime/osx/libmonobdwgc-2.0.dylib, and successfully compiled my native plugin by linking it to the library.

However, when I enter play mode, I encounter the following error:

Error occurred in running static constructor: System.TypeInitializationException: The type initializer for 'Common.Native.NativePlugin' threw an exception. ---> System.DllNotFoundException: NativePlugin assembly:<unknown assembly> type:<unknown type> member:(null)
  at (wrapper managed-to-native) Common.Native.NativePlugin.LogToUnity(string)
cmake_minimum_required(VERSION 3.10)

project(NativePlugin)

set(CMAKE_CXX_STANDARD 11)

set(CMAKE_BUILD_TYPE Release)

include_directories("/Applications/Unity/Hub/Editor/Version2022.3/Unity.app/Contents/il2cpp/external/mono")
file(GLOB SOURCES "*.cpp")
file(GLOB HEADERS "*.h")
add_library(NativePlugin SHARED ${SOURCES})

target_include_directories(NativePlugin PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

target_link_libraries(NativePlugin  /Applications/Unity/Hub/Editor/Version2022.3/Unity.app/Contents/Frameworks/MonoBleedingEdge/MonoEmbedRuntime/osx/libmonobdwgc-2.0.dylib)

if (CMAKE_BUILD_TYPE STREQUAL "Release")
    set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3")
endif ()

I managed to get it working. When compiling my native plugin, it used the wrong relative path to link the libmonobdwgc-2.0.dylib. I replaced it with an absolute path, and successfully invoked the C# method using the Mono API.

Just to confirm, is the Mono API available on macOS, Windows, and Linux? I currently use macOS and don’t have access to other platforms for testing."