Mastering C# and Unity3D

C++ Scripting: Part 2 – Update C++ Without Restarting the Editor

Last week we began the series by establishing two-way communication between C# and C++. We used object handles to pass class instances between the two languages. Everything was going great, but then there was a major productivity problem: we had to restart the Unity editor every time we changed the C++ plugin. Today’s article is all about how to overcome that obstacle so you can iterate on your code just like with C#.

The issue we ran into last week was related to using the [DllImport] attribute to allow C# to call C++ functions. It turns out that the Unity editor will only load the C++ plugin library once, even if it changes. So when we make changes to our C++ code and rebuild the plugin, we had to restart the Unity editor so it would load the plugin again. As programmers, we’re constantly changing the code and really don’t want to wait for the Unity editor to restart every single time.

The solution is to do things a little more manually than just using the [DllImport] attribute. Instead, we’ll use some functions that the OS provides to load, use, and close C++ libraries. This can be done easily on Mac, Windows, and Linux editors with the following function families:

Mac

Windows

Linux

Open a DLL

dlopen

LoadLibrary

dlopen

Get a Function Pointer

dlsym

GetProcAddress

dlsym

Close a DLL

dlclose

FreeLibrary

dlclose

To access these, we use [DllImport] just like we did with our C++ plugin. This time, however, we import from the __Internal library on Mac and Linux and kernel32 on Windows instead of our NativeScript plugin library. Since these functions are part of the OS, we don’t have to worry about them changing and needing to restart the Unity editor.

This means there is one more step to initializing the C++ plugin. We can’t just call Init anymore because we don’t have the delegate for Init. So we insert some conditionally-compiled code with #if UNITY_EDITOR to open the plugin library then get a delegate for each C++ function we want to call. We store the delegates as fields with the same name as the functions we would have declared with [DllImport] when not in the Unity editor. Finally, when OnApplicationQuit is called, we close the plugin library.

The C++ doesn’t need to change at all from the last article to keep working on Mac and Linux. We’ve only changed how C# makes use of the C++ plugin library. For Windows, however, we need to add __declspec(dllexport) before each function that C# calls. A DLLEXPORT macro makes that easy:

Comments

Great article!
I see many other topics that could be covered in your c++/Unity serie:
-debugging c++ & Unity on mac and windows, and debugging on game/app running on Device
-stdout (printf) from c++ and UnityEngine.Debug.Log
-managing Textures from c++ (thanks to Unity API CreateExternalTexture, GetNativeTexturePtr, …), to for example compress or decompress textures from c++
-Do graphics GLES rendering calls from c++…
-c++ multithreading & Unity.
– I would also mention the Trampoline code for iOS in Unity (c++/objective C source)

These are some great ideas. For the purposes of this series, I’m trying to restrict the articles to just the setup for scripting in C++. What you can actually do once you’re in C++ (e.g. graphics calls) is quite interesting, but won’t be part of this series. Future articles about that will reference back to this series for how to do all the setup work to get you to a point where you can start making those graphics calls, threads, etc.