Heya, Thanks for visiting!

Unity and DLLs: C# (managed) and C++ (unmanaged)

  • unity-3d
  • windows
  • c++
  • c#

With Unity 5, there is no difference in terms of engine features between Personal/Free and Professional editions. This means that "Native Code Plugin Support" is not a problem anymore and there are no restrictions with DLLs and C++(unmanaged) code.

This guide really only applies to Unity 4 and below

When dealing with unmanaged and managed code, verbiage like P/Invoke, marshaling, interoperability get thrown around. The whole ordeal can be a bit daunting.

This guide will go over dealing with DLLs in Unity Free/Standard and Unity Pro. Even with the native(unmanaged) code barrier in Unity Free, it is still possible to use unmanaged code.

Overview

Specifically, we will be making a C# managed DLL which relies on/references a C++ unmanaged DLL and then use those functions in Unity.

TLDR; For Unity 4 Pro and Unity 5:

  • Add all code/DLLs to the Plugins folder: UnityProject->Plugins

TLDR; For Unity Free:

  • Add unmanaged code to the Unity Project Root: UnityProject
  • Add managed code to the Plugins folder: UnityProject->Plugins
  • When you build a project, copy the unmanaged code to BuildRoot->Data->Plugins

Create a C++ DLL (Unmanaged)

To start, lets create the unmanaged DLL which the other pieces rely on.

  • In Visual Studio, Create a New Project: Visual C++->Win32->Win32 Console Application
  • Name it TestCPPLibrary
  • On the Application Settings Wizard that pops up after you press OK: change the Application Type to DLL
  • Check the Empty Project box on the same page
    Create Win32 C++ Console Application Application Settings Wizard: DLL and Empty Project
  • Create the following two files and paste in the contents

TestCPPLibrary.h

// TestCPPLibrary.h

#ifdef TESTFUNCDLL_EXPORT
#define TESTFUNCDLL_API __declspec(dllexport)
#else
#define TESTFUNCDLL_API __declspec(dllimport)
#endif

extern "C" {
    TESTFUNCDLL_API float TestMultiply(float a, float b);
	TESTFUNCDLL_API float TestDivide(float a, float b);
}

TestCPPLibrary.cpp

// TestCPPLibrary.cpp : Defines the exported functions for the DLL application.
//

#include "TestCPPLibrary.h"

extern "C" {
	float TestMultiply(float a, float b)
	{
		return a * b;
	}

	float TestDivide(float a, float b)
	{
		if (b == 0) {
			return 0;
			//throw invalid_argument("b cannot be zero!");
		}

		return a / b;
	}
}

Create a C# DLL (Managed)

  • In Visual Studio, Create a New Project: Visual C#->Windows->Class Library
  • Name it TestCSharpLibrary
  • Add the C++ Dll to your C# Solution
    • Right-click the solution in your C# project and goto Add->Existing Item
      Add existing project
    • Browse and choose your TestCPPLibrary project.
  • Right click on your C# project and go to Properties
  • In the Application tab, change the Target Framework to .NET Framework 3.5
    C# Project Context Menu: Properties C# Project Properties->Application->Target Framework (.net version)
  • Create the following file and paste in the contents

TestCSharpLibrary.cs

using System;
using System.Runtime.InteropServices;

namespace TestCSharpLibrary
{
    public class TestCSharpLibrary
    {
        // From c++ Dll (unmanaged)
        [DllImport("TestCPPLibrary")]
        public static extern float TestMultiply(float a, float b);

        // From c++ Dll (unmanaged)
        [DllImport("TestCPPLibrary")]
        public static extern float TestDivide(float a, float b);


        public static float SharpMultiply(float a, float b) {
            return (a * b);
        }

        public static float SharpDivide(float a, float b) {
            if (b == 0)
            {
                return 0;
            }

            return (a / b);
        }
    }
}

Build (Make the DLLs)

Right click the solution and press Build (F7). It should run until you see:
========== Build: 2 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========

You should be able to find both DLLs in the C# project folder:

  • TestCSharpDll\TestCSharpLibrary\Debug\TestCPPLibrary.dll
  • TestCSharpDll\TestCSharpLibrary\TestCSharpLibrary\bin\Debug\TestCSharpLibrary.dll

Add the DLLs to your Unity Project

Since native(unmanaged, the c++ DLL in our case) is a Pro/Mobile-only feature, it is quite easy to get this running in Unity Pro, but a bit more involved for Unity Free/Standard/Indie.

Unity Pro and any Unity 5

If you are using Unity Pro,

  • Copy both DLLs(TestCSharpLibrary.dll, TestCPPLibrary.dll) into UnityProject->Plugins

The project will work in the Unity Editor and when you make a Build

Unity (Free/Standard/Indie)

If you are using the standard version of Unity:

  • Copy TestCSharpLibrary.dll, the C# managed DLL, into UnityProject->Plugins
  • Copy TestCPPLibrary.dll, the C++ unmanaged DLL, into the UnityProject root.

This will allow the project to run in the Unity Editor but will not work in a build.

To get your project working in a build... After you build your project:

  • Copy TestCPPLibrary.dll, into your Build Root->Data->Plugins, alongside your other DLL

Using the DLL in Unity

Here is a simple script utilizing the DLLs:

UseDLL.cs

using UnityEngine;
using System.Collections;
using System.Runtime.InteropServices;
using System.IO;

public class UseDll : MonoBehaviour {

	// Straight From the c++ Dll (unmanaged)
	[DllImport("TestCPPLibrary", EntryPoint="TestDivide")]
	public static extern float StraightFromDllTestDivide(float a, float b);

	// Use this for initialization
	void Start () {

		/* */
		// Call the C# DLL SharpMultiply function
		float multiplyResult = TestCSharpLibrary.TestCSharpLibrary.SharpMultiply(3, 5);

		// Call the C# DLL TestDivide function which relies on the C++ DLL for this functionality
		float divideResult = TestCSharpLibrary.TestCSharpLibrary.TestDivide(15, 3);

		float straightFromDllDivideResult = StraightFromDllTestDivide(20, 5);

		// Print it out to the console
		Debug.Log(multiplyResult);
		Debug.Log(divideResult);
		Debug.Log(straightFromDllDivideResult);

		// Write the result into a file, so we can even see it working in a build
		using(StreamWriter writer = new StreamWriter("debug.txt", true))
		{
			writer.WriteLine(multiplyResult);
			writer.WriteLine(divideResult);
			writer.WriteLine(straightFromDllDivideResult);
		}
		/* */

	}

	// Update is called once per frame
	void Update () {

	}
}

Running the script, should output to the console and write to debug.txt:

Unity console logs showing the script above running '15 from SharpMultiply(3, 5)', '5 from TestDivide(15, 3)', and '4 from StraightFromDllTestDivide(20, 5)'


Running into Issues?:

Internal compiler error ... System.Reflection.ReflectionTypeLoadException

If you are getting an error similar to Internal compiler error. System.Reflection.ReflectionTypeLoadException in Unity when trying to build your project; You need to change the targeted .NET version of your C# file to something like .NET 3.5.

  • Right click on your C# project and go to Properties
  • In the Application tab, change the Target Framework to .NET Framework 3.5
    C# Project Context Menu: Properties C# Project Properties->Application->Target Framework (.net version)

Failed to load ... expected 64 bit architecture (IMAGE_FILE_MACHINE_AMD64), but was IMAGE_FILE_MACHINE_I386.

If you are getting this error, you probably need to recompile your libraries for x64 platform (64 bit).

In Visual Studio, go to the properties of your project, then at the top click the "Configuration Manager..." button. In the table, under the Platform column, change it to "x64" then recompile your project.