こんにちは、Unityエンジニアのオオバです。
C#とC++間のデータやりとりを
実装したことありますか?
Unityが提供する機能を普通に使っているだけだと、
あまり出てこないシチュエーションかも知れません。
Unityが提供していない機能にアクセス といった
Unityの外へ一歩出ようとすると
C++や別の言語が必要になります。
今回はC#とC++間のデータのやり取りの第一歩として、
C#からC++へ文字列の送信を解説します。
C#からC++に文字列を渡す4つのポイント
![C#からC++に文字列を渡す方法_0](https://i.gyazo.com/a4270236c2a8d786c47147ca6adf0cf7.jpg#749__500)
- ① : C++は char型のポインタ で受け取る
- ② : C++のメソッドに
extern "C"
をつける - ③ : C#側は
DllImport
属性をつける - ④ : C#側に
static extern
を付与
やり方が分かれば意外と簡単です。
ざっくりした手順はコチラ
- C++からのTestDll.dllを生成
- TestDll.dllをC#から呼び出す
C#側から文字列を引き渡して、
C++側でログを出力してみます。
環境構築を含めて詳細を解説していきます。
👉DOTweenの教科書を読んでUnityアニメーションをプログラミングしてみよう!
【環境構築】 DLLプロジェクトを作成
Visual Studio Community 2017で開発を進めていきます。
![C#からC++に文字列を渡す方法_1](https://cdn-ak.f.st-hatena.com/images/fotolife/e/esakun/20190319/20190319094340.png#750__389)
新しいプロジェクトを作成し、
ダイナミックリンクライブラリ(DLL) を選びます。
![C#からC++に文字列を渡す方法_2](https://cdn-ak.f.st-hatena.com/images/fotolife/e/esakun/20190319/20190319094910.png#182__205)
プロジェクトを作ると
デフォルトでファイルが
いくつか作られますが気にせず進めます。
C#側に公開するC++の関数アトリビュートの定義
![C#からC++に文字列を渡す方法_3](https://i.gyazo.com/394e236b6c06b0b70b33e05a1acde02b.jpg#750__499)
まずはC#からC++を呼ぶための準備です。
extern "C"{
// C#から呼ばれたい関数を定義
}
C#から呼ばれる関数に↑の記述が必要になります。
今回はマクロを使って開発効率を上げます。
#define DllExport extern "C" __declspec(dllexport)
↑の1行をstdafx.h
に追加してマクロを作成。
// hoge()をC#から呼べるようになる
DllExport void hoge();
↑このようにDllExport
属性を
関数定義の先頭に記述することで
C#から呼べるように します。
さきほど登場したstdafx.h
は、
プロジェクト作成時に作られるヘッダファイルです。
このファイルの行末あたりに1行追加しておきます。
💻ソースコード : stdafx.h
#pragma once
#include "targetver.h"
// Windows ヘッダーからほとんど使用されていない部分を除外する
#define WIN32_LEAN_AND_MEAN
// Windows ヘッダー ファイル
#include <windows.h>
// プログラムに必要な追加ヘッダーをここで参照してください
#define DllExport extern "C" __declspec(dllexport)
なぜextern 'C'をつけるのか?
![C#からC++に文字列を渡す方法_4](https://i.gyazo.com/3638f4dc531c67ef1b82450a59761720.jpg#666__500)
そもそもなぜC#からC++を呼ぶ際に、
extern "C"
が必要のか?疑問ですよね。
理由はC++のコンパイルにあります。
C++はコンパイルのたびにメソッド名が変わります。
extern "C"
を記述することで、 メソッド名を固定 します、
つまりC#側から呼び出したときのリンクエラーを防ぐために必要なのです。
準備が完了したため、
C#からC++に文字列を送る実装を進めます。
C++側はcharのポインタで受け取る
![C#からC++に文字列を渡す方法_5](https://i.gyazo.com/9d9e68b0c0017f01753f9baa140dcd5a.jpg#750__421)
最初に悲報ですが、
C#からC++にstring型をそのまま送れません。
C++側はC#の文字列を
ポインタで受け取ります。
#include "stdafx.h"
#include <iostream>
// C#から呼ばれる関数の定義
DllExport void Test(const char* str);
void Test(const char* str)
{
if (str == NULL) {
std::cout << "str is null." << std::endl;
return;
}
std::cout << str << std::endl;
}
C++側はString型ではなく、
char型のポインタで定義します。
DllExport属性をTestメソッドにくっつけることで、
C#側から実行できるようになります。
C++のDLL化
C++の処理をC#から呼び出すために
dllファイルに固めます。
![C#からC++に文字列を渡す方法_6](https://cdn-ak.f.st-hatena.com/images/fotolife/e/esakun/20190319/20190319193749.png#344__90)
C++側の実装が完了したのでビルドします。
- プロジェクトを右クリック
- ビルド
すると TestDll.dll
が出来上がります。
このDLLをC#プロジェクトのexeと同階層に配置します。
C#側でDLLをインポートしてC++のメソッドを呼ぶ
![C#からC++に文字列を渡す方法_7](https://i.gyazo.com/321da3ad7cef59d54c52a0506d740bd1.jpg#750__499)
C#の実装に移ります。
まずはソースから見ていきましょう。
[DllImport("TestDll.dll", CallingConvention = CallingConvention.Cdecl)]
static extern void Test(string str);
static void Main()
{
Test("hogehoge");
}
ポイントは3点
- C++で定義した関数と同名の関数を定義
static extern
を付与[DllImport("DLLファイル名", CallingConvention = CallingConvention.Cdecl)]
属性付与
詳しいことはいったん置いておきます。
この状態でC#を実行してみます。
するとコンソールにhogehogeと出力されるでしょう。
まとめ : C#からC++(DLL)に文字列を渡す
![C#からC++に文字列を渡す方法_8](https://i.gyazo.com/3f9a7254af6fe60cceeaa3c27681da75.jpg#750__496)
C#からC++に文字列を送信する手順を紹介してきました。
- C++はchar型のポインタで受け取る
- C#側にC++のメソッドを公開するために
extern "C"
が必要 - C#側は
DllImport
属性が必要 - C#側にC++で定義したメソッドに
static extern
を付与して定義
以上のポイントを抑えておきましょう。
C#/C++間データやり取りの基礎となる情報です。
C++はchar型のポインタで受け取るという点以外は、
C#側からはString型をそのまま送れるため、
実装自体はシンプルだったのではないかと思います。
![](https://i.gyazo.com/02db7dc6a963d3e5d73ade1d1039985c.jpg#1280.0__851.0)
C#からC++にintを渡す方法
引き続きさまざまなデータの型をC#/C++間で
やり取りしていきます。
お楽しみに!
![](https://i.gyazo.com/5c52c3992353e2d2789df84387b6b07d.jpg#1280.0__800.0)
この記事が気に入ったらフォローしよう
- VisualStudioCommunity2017 v15.9.8
- Windows10