C#から自作のC++DLLのクラスを呼び出す方法


UnityC#にて重たい処理をDLLにやってもらおうと思い、  
ViusalStudioを用いてC++のDLLを[こちらを参考に](http://ericeastwood.com/blog/17/unity-and-
dlls-c-managed-and-c-unmanaged)作成しました。

メソッドを呼び出すことはできたので、  
今度はクラス経由で呼び出してみようと思い  
C++側のクラスの定義をMSDNの[ここ](https://msdn.microsoft.com/ja-
jp/library/81h27t8c.aspx)を参考にクラスを作成したのですが  
C#側からどのように呼び出せばいいのかがわかりません。

* * *

C#側

[code]

    using UnityEngine;
    using System.Collections;
    
    // Must Need DLL Import 
    using System.Runtime.InteropServices;
    
    public class CallDlls : MonoBehaviour {
    
        // From c++ Dll (unmanaged)
        [DllImport("MathFuncsDll")]
        public static extern float TestMultiply(float a, float b);
    
        // From c++ Dll (unmanaged)
        [DllImport("MathFuncsDll")]
        public static extern float TestDivide(float a, float b);
    
        public float multiply(float a,float b)
        {
            return TestMultiply(a, b);
        }
    }
    
[/code]

* * *

C++DLL側

**// MathFuncsDll.cpp**

[code]

    #include "stdafx.h"
    #include "MathFuncsDll.h"
    #include <stdexcept>
    
    using namespace std;
    
    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;
        }
    }
    
[/code]

**// MathFuncsDll.h**

[code]

    #ifdef MATHFUNCSDLL_EXPORTS
    #define MATHFUNCSDLL_API __declspec(dllexport) 
    #else
    #define MATHFUNCSDLL_API __declspec(dllimport) 
    #endif
    
    extern "C" {
        class MATHFUNCSDLL_API TestClass {
            float TestMultiply(float a, float b);
            float TestDivide(float a, float b);
            //MATHFUNCSDLL_API float TestMultiply(float a, float b);
            //MATHFUNCSDLL_API float TestDivide(float a, float b);
        };
    }
    
[/code]




技術的にはC#コードから直接C++クラスのメンバ関数を呼ぶことも可能です。ただし、幾つかの理由からお薦めできません。@時計屋さん回答にある解決策を採用したほうがよいと思います。

DLL/C++クラスのメンバ関数はthiscall呼出し規約(calling
convention)をもちますので、`DllImport`属性で[`CallingConvention.ThisCall`](https://msdn.microsoft.com/ja-
jp/library/system.runtime.interopservices.callingconvention.aspx)を指定し、`EntryPoint`には"マングリングされた関数名"を指定する必要があります。詳細は記事
[How to Marshal a C++ Class](http://www.codeproject.com/Articles/18032/How-to-
Marshal-a-C-Class) が参考になります。

お薦めできない理由：

  * DLL/C++側クラスのコンストラクタ/デストラクタを、C#側から直呼び出すことはできません。少なくともC++クラスオブジェクトの`new`/`delete`操作を行うC++側にヘルパー関数が必要です。
  * DLL/C++側でエクスポートされる"マングリングされた関数名"に、C#側では常に追従させる必要があるためメンテナンスコストが高くなります。




DllImport属性を使うことで、ネイティブコードを呼び出すことはできますが、  
C++で作成したクラスをDllImport属性を使って、.NET Frameworkで利用することはできません。

解決策としては、

  1. 関数ベースのインターフェースを別途用意して、管理する
  2. C++/CLI等を利用してラッパーを作成する

等が考えられると思います。

