How to make C++ DLL and use it in Unity
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)
#endifclass 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.