Manuel Mangual
Manuel Mangual

Reputation: 75

Writing C++ .dlls and access them Unity-3D

I have been writing a basic dll in c++ with the end-goal of accessing some of it's methods in Unity. I started this tutorial in : http://docs.unity3d.com/Documentation/Manual/Plugins.html which helped me understand the concept but after I write the class in Unity and access the .dll it throws me an entry point exception error when I hit play. And yes, I have a plugin folder where i keep my .dll file.

EntryPointNotFoundException: addition PluginImport.Start () (at Assets/Test/PluginImport.cs:20)

Here is my .dll class.

The Header File:

#ifndef MATHASSISTANT_ARITHMETICS_ARITHMETIC_H
#define MATHASSISTANT_ARITHMETICS_ARITHMETIC_H

namespace ma{
    extern "C"
    {
    class Arithmetic
    {
    public:
        Arithmetic();//ctor
    protected:
        virtual ~Arithmetic();//dtor
    public:

        static __declspec(dllexport) float addition(float& val_1, float& val_2);
        static __declspec(dllexport) float substraction(float& val_1, float& val_2);
        static __declspec(dllexport) float multiplication(float& val_1, float& val_2);
        static __declspec(dllexport) float division(float& val_1, float& val_2);
    };
    }
}

#endif

This is the source file:

#include "Arithmetic.h"
#include <stdexcept>

namespace ma{


    Arithmetic::Arithmetic(){
        //TODO: Initialize items here
    }
    Arithmetic::~Arithmetic(){
        //TODO: Release unused items here
    }

    //FUNCTION: adds two values
    float Arithmetic::addition(float& val_1, float& val_2){
        return val_1 + val_2;
    }
    //FUNCTION: substracts two values
    float Arithmetic::substraction(float& val_1, float& val_2){
        return val_1 - val_2;
    }
    //FUNCTION: multiplies two values
    float Arithmetic::multiplication(float& val_1, float& val_2){
        return val_1 * val_2;
    }
    //FUNCTION: divide two values
    float Arithmetic::division(float& val_1, float& val_2){
        if(val_2 == 0)
            throw new std::invalid_argument("denominator cannot be 0");
        return val_1 / val_2;
    }
}

This is the class I created in Unity3D:

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

public class PluginImport : MonoBehaviour
{
    //Lets make our calls from the Plugin
    [DllImport("Arithmetic")]
    private static extern float addition(float val_1, float val_2);
    [DllImport("Arithmetic")]
    private static extern float substraction(float val_1, float val_2);
    [DllImport("Arithmetic")]
    private static extern float multiplication(float val_1, float val_2);
    [DllImport("Arithmetic")]
    private static extern float division(float val_1, float val_2);

    void Start()
    {
        Debug.Log(addition(5, 5));
        Debug.Log(substraction(10, 5));
        Debug.Log(multiplication(2, 5));
        Debug.Log(division(10, 2));
    }
}

If anyone can help me find what I am doing wrong I will be most appreciative. Thanks in advance!

Upvotes: 2

Views: 7394

Answers (2)

S.Richmond
S.Richmond

Reputation: 11558

The reason you're getting this error and the reason why you've found that you can access it by using the obfuscated name of the method is because you forgot to correctly import each method on the C# side using the correct CallingConvention.

For example, your Addition method should look like this:

[DllImport("Arithmetic"), EntryPoint = "addition", CallingConvention = CallingConvention.Cdecl)]
private static extern float addition(float val_1, float val_2);

Upvotes: 3

Manuel Mangual
Manuel Mangual

Reputation: 75

I found the answer. I had to do some tweaking to the code but basically I will show you:

This is my MathHelper.dll

Header:

#ifndef MATHASSISTANT_ARITHMETICS_ARITHMETIC_H
#define MATHASSISTANT_ARITHMETICS_ARITHMETIC_H
#include <Windows.h>

#include <WbemCli.h>  
namespace ma{
    extern "C"
    {
    class Arithmetic
    {
    public:
        Arithmetic();//ctor
    protected:
        virtual ~Arithmetic();//dtor
    public:
        BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID);
        __declspec(dllexport) float addition(float val_1, float val_2);
        __declspec(dllexport) float substraction(float val_1, float val_2);
        __declspec(dllexport) float multiplication(float val_1, float val_2);
        __declspec(dllexport) float division(float val_1, float val_2);
    };
    }
}

#endif

The source file:

#include "Arithmetic.h"
#include <stdexcept>

namespace ma{


    Arithmetic::Arithmetic(){
        //TODO: Initialize items here
    }
    Arithmetic::~Arithmetic(){
        //TODO: Release unused items here
    }

    //FUNCTION: adds two values
    __declspec(dllexport) float addition(float val_1, float val_2){
        return val_1 + val_2;
    }
    //FUNCTION: substracts two values
    __declspec(dllexport) float substraction(float val_1, float val_2){
        return val_1 - val_2;
    }
    //FUNCTION: multiplies two values
    __declspec(dllexport) float multiplication(float val_1, float val_2){
        return val_1 * val_2;
    }
    //FUNCTION: divide two values
    __declspec(dllexport) float division(float val_1, float val_2){
        if(val_2 == 0)
            throw new std::invalid_argument("denominator cannot be 0");
        return val_1 / val_2;
    }
}

In Unity-3D here is the class:

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

public class PluginImport : MonoBehaviour
{
    //Lets make our calls from the Plugin
    [DllImport("MathAssistant", EntryPoint = "?addition@ma@@YAMMM@Z")]
    private static extern float addition(float val_1, float val_2);
    [DllImport("MathAssistant", EntryPoint = "?substraction@ma@@YAMMM@Z")]
    private static extern float substraction(float val_1, float val_2);
    [DllImport("MathAssistant", EntryPoint = "?multiplication@ma@@YAMMM@Z")]
    private static extern float multiplication(float val_1, float val_2);
    [DllImport("MathAssistant", EntryPoint = "?division@ma@@YAMMM@Z")]
    private static extern float division(float val_1, float val_2);

    void Start()
    {
        Debug.Log(addition(5, 5));
        Debug.Log(substraction(10, 5));
        Debug.Log(multiplication(2, 5));
        Debug.Log(division(10, 2));
    }
}

The error I was getting before was that the code was not recognizing my functions, addition, divide, etc. Even though I was declaring them correctly. However, when I created my .dll it somehow changed the name of my function, i.e: "addition" became: "?addition@ma@@YAMMM@Z". I went to this website and it made it clear: http://msdn.microsoft.com/en-us/library/system.entrypointnotfoundexception(v=vs.110).aspx and that is where I realized that the problem was not in my structure or the logic but in the actual function name once it was converted into .dll. If that is your case then what you need is a tool to help you find what your function name is. I used DependancyWalker.exe. Here is the is the site: http://dependency-walker.en.softonic.com/ That was my litle adventure trying to solve this issue. Hopefully this will help out anyone who has run into thi sisuue and has not resolved it yet. Power to the user!

Upvotes: 0

Related Questions