【C++】【C#】C++でDLLを作成してC#から呼ぶ

C++C#から呼べるdllを作成する方法です。

DLLプロジェクトを作成する

Visual Studioを開き、新しいプロジェクトからVisual C++ > Windows デスクトップ > ダイナミック リンク ライブラリを選択します。

もし選択肢がない場合はインストーラーを開いて更新します。

f:id:halya_11:20190303184459p:plain

C++によるデスクトップ開発を選択してインストールします。

f:id:halya_11:20190303184652p:plain

インストールが完了したら改めてDLLプロジェクトを作成します。

f:id:halya_11:20190303201204p:plain

C++プロジェクトのビルドまで

プロジェクトを作ったら次にヘッダファイルを追加します。
ソリューションエクスプローラー > ヘッダーファイル > 追加 >クラス を選択します

f:id:halya_11:20190303202237p:plain

クラスの追加ウィンドウが表示されるのでプロジェクト名と同じ名前のヘッダーファイルを作成します。

f:id:halya_11:20190303202339p:plain

これで.hファイルと.cppファイルが生成されます。 .hファイルには次のように記述します。

#pragma once

extern "C" int __stdcall Example();

cppファイルには次のように記述します。

#include "stdafx.h"
#include "ExampleDll.h"

extern "C" int __stdcall Example()
{
    return 5;
}

これで関数は作成できました。
最後にこれをdllの外から呼ぶための設定をします。

ソリューションエクスプローラー > プロジェクト名 > 追加 > 新しい項目 を選択します。

f:id:halya_11:20190303202744p:plain

Visual C++ > コード > モジュール定義ファイルを選択します。
プロジェクト名と同じ命名でdefファイルを作成します。

f:id:halya_11:20190303202958p:plain

作成したdefファイルに次のように記述します。

LIBRARY ExampleDll
EXPORTS
    Example @1

ライブラリ名と関数名を指定しています。
@以下の数字は連番です。

ここまでできたらビルド > ソリューションのビルドからビルドを行います。

f:id:halya_11:20190303203325p:plain

ビルド出力先フォルダに次のようなファイルができていればOKです。

f:id:halya_11:20190303203457p:plain

C#から呼ぶ

次に作ったDLLをC#のプロジェクトから呼びます。
まず適当にコンソールアプリのプロジェクトを作ります。

f:id:halya_11:20190303203744p:plain

最初から存在するProgramクラスを下記のように書き換えます。

using System;
using System.Runtime.InteropServices;

namespace ExampleApp
{
    class Program
    {
        [DllImport("ExampleDll.dll")]
        private static extern int Example();

        static void Main(string[] args)
        {
            Console.WriteLine(Example());
        }
    }
}

次に、このC#プロジェクトのビルドの出力先フォルダに前節でビルドしたDLLをコピーします。
ひとまずこの時点ではdebug用のフォルダにのみコピーしています。

f:id:halya_11:20190303204109p:plain

あとはC#プロジェクトをCtrl + F5でビルドします。

f:id:halya_11:20190303204421p:plain

「5」と出力されれば正常です。

DLLの出力先をコピー先に設定する & 32bit/64bit両対応する

前節ではDLLをビルドしたあとにDLLをコピー&ペーストしていました。
これは作業効率が悪いので、出力先を変更してしまいます。
またそのついでに32bit / 64bitの両対応をしてしまいます。

まずソリューションエクスプローラーからプロジェクト名を右クリック > プロパティを選択します。

f:id:halya_11:20190303234327p:plain

するとプロパティの設定画面が開かれます。
ここで構成(Debug / Release)とプラットフォーム(32bit/ 64bit)を切り替えながら、それぞれ下記のように設定していきます。

f:id:halya_11:20190303234831p:plain

設定が終わったらビルド > バッチビルドからバッチビルドウィンドウを開きます。
そしてすべての「ビルド」チェックボックスにチェックを入れてビルドボタンを押します。

f:id:halya_11:20190303235352p:plain

指定した出力先にDLLが作られていればOKです。
次にDLLを使う側のアプリケーションを32bit/64bit両対応にしてみます。
ソースコードを次のように書き換えます。

using System;
using System.Runtime.InteropServices;

namespace ExampleApp
{
    class Program
    {
        [DllImport("ExampleDll32.dll", EntryPoint = "Example")]
        private static extern int Example32();

        [DllImport("ExampleDll64.dll", EntryPoint = "Example")]
        private static extern int Example64();

        static void Main(string[] args)
        {
            if (Environment.Is64BitProcess) {
                Console.WriteLine(Example64());
            }
            else {
                Console.WriteLine(Example32());
            }
        }
    }
}

仕組みとしてはシンプルで、読み込むDLLを分けているだけです。
EntryPointとしてメソッド名を指定するのがポイントです。

Ctrl+F5で実行して正常に結果が表示されればOKです。

f:id:halya_11:20190304000048p:plain

参考

qiita.com

qiita.com

others2.blog.so-net.ne.jp