How to make C++ DLL and use it in Unity

Hiruma Kazuya
3 min readJun 9, 2021

--

Overview

This article shows you how to make C++ DLL using classes and use it in Unity. This might help you to understand how the DLL is made and what happened in Unity.

Define a C++ class

Let’s start to define a C++ class normally.

#pragma once#ifdef DLLPROJECT_EXPORTS
# define EXPORT __declspec(dllexport)
#else
# define EXPORT __declspec(dllimport)
#endif
class Hoge
{
public:
int Foo(int a);
};
extern "C" EXPORT Hoge* createHoge();
extern "C" EXPORT void freeHoge(Hoge* instance);
extern "C" EXPORT int getResult(Hoge* instance, int a);

What are __declspec(dllexport) and __declspec(dllimport) ?

You can export functions with __declspec(dllexport) in before function name. On the other hand, __declspec(dllimport) can import functions from DLL. As you can see #ifdef switches export or import. DLLPROJECT_EXPORTS is defined in the DLL project.

What is extern “C”?

extern "C" means functions export as C like function. I’ll skip to explain what C like function is but you can find out that google with a word “mangling”. I’ll explain these externed functions later.

Implement the C++ class

Secondly, let’s implement the class. Hoge class is simple class that has one method. As you can see this .cpp file has 2 functions. These functions are exported with EXPORT preprocesser macro. These can be used in C#.

#include "pch.h"
#include "Hoge.h"
int Hoge::Foo(int a)
{
return a + 5;
}
EXPORT Hoge* createHoge() {
return new Hoge();
}
EXPORT void freeHoge(Hoge* instance) {
delete instance;
}
EXPORT int getResult(Hoge* instance, int a) {
return instance->Foo(a);
}

Build the class with VisualStudio

The class can be built with VisualStudio but I’ll skip it here. Please check it out from MS documents. The link below might help you.

Let’s use the class in Unity

Now, we are ready to use the DLL. let’s use it in Unity. Let’s implement a class that uses the DLL.

using System;
using System.Runtime.InteropServices;
using UnityEngine;
public class DLLTest : MonoBehaviour
{
[DllImport("DLL-Sample.dll")]
private static extern IntPtr createHoge();

[DllImport("DLL-Sample.dll")]
private static extern void freeHoge(IntPtr instance);

[DllImport("DLL-Sample.dll")]
private static extern int getResult(IntPtr instance, int a);

private void Start()
{
IntPtr hoge = createHoge();
Debug.Log(hoge); // => Show the pointer address.
int result = getResult(hoge, 10);
Debug.Log(result); // => 15
freeHoge(hoge);
}
}

Most important thing of the code is DLLImport attribute. A method that has the attribute can load a implementation from a DLL then you can access it as a normal C# method. Please see the Start method, the one tells you how to use these methods.

Note that a function that returns a C++ class instance returns IntPtr . It seems like a void* object.

The point here is that we have to pass an instance pointer to a C++ function to perform something. Please see getResult method, it takes a pointer as first argument.

How to use a struct between C++ and C#?

If you want to use a struct between C++ and C#, let me show how to use it.

Firstly, let’s define a struct in C++.

typedef struct _Person
{
int id;
int age;
} Person;

You might feel it looks like a little bit weird because the Person struct don’t have a name field. I’m sorry it’s a little bit complicated, then I’ll add these things one day.

Let’s add a method that updates a Person struct.

EXPORT void createPerson(Hoge* instance, Person* person)
{
(*person).age = 15;
}

Lastly, let’s add the method in C# side.

[DllImport("DLL-Sample.dll")]
private static extern void createPerson(IntPtr instance, ref Person person);
private void Start()
{
IntPtr instance = createHoge();
Person person = new Person();
createPerson(instance, ref person);
Debug.Log(person.age); // => 15
}

You can make a struct in C# side and pass it to C++ side like above.

Conclusion

We can’t use C++ class instance methods as a normal way. So we have to pass class instances to functions that we need perform. But it’s not problem because there is little case to use the instance methods frequency.

--

--