目次

第1章 はじめに

1.1 対象読者
1.2 なぜ マーシャリングが必要になるのか
1.3 前提条件
1.4 動作環境
1.5 免責事項
1.6 参考文献

第2章 マーシャリング基礎

2.1 マーシャリングとは
2.2 マーシャリングの基本動作
2.3 Blittableと非Blittable
2.4 ネイティブ関数を呼び出す方法
2.5 方向属性(In/Outアトリビュート)
2.6 呼び出し規約
2.7 インターフェースの形式
2.8 大まかな指針

第3章 簡単なマーシャリング

3.1 プリミティブ型:引数にセットして関数呼び出し
3.2 プリミティブ型:引数で結果を受け取る場合
3.3 プリミティブ型:関数戻り値の場合

第4章 構造体のマーシャリング

4.1 構造体の定義
4.2 BOOL/bool型の注意点
4.3 構造体:引数にセットして関数呼び出し
4.4 構造体:引数にセットして関数呼び出し(2)
4.5 構造体:引数で結果を受け取る場合
4.6 構造体:関数戻り値の場合
4.7 構造体:関数戻り値(ポインタ)の場合
4.8 共用体

第5章 配列のマーシャリング

5.1 プリミティブ型:引数関数呼び出し
5.2 プリミティブ型:呼び出し先で配列内容を変更
5.3 プリミティブ型:戻り値の場合
5.4 構造体配列:引数関数呼び出し
5.5 構造体配列:呼び出し先で配列内容を変更

第6章 文字列の表現

6.1 Windows開発環境の文字エンコーディング
6.2 LinuxやAndroid、iPhoneの場合
6.3 .NET FrameworkとMonoの実行系による違い
6.4 Monoによる文字列引数の呼び出しを観察する
6.5 実行ランタイム違いへの対策
6.6 Win32APIの呼び出しについて

第7章 文字列の変換

7.1 文字列をShift-JISのバイト列へ変換
7.2 Shift-JISのバイト列から文字列へ変換
7.3 文字列をUTF-8のバイト列へ変換する場合
7.4 文字列をUTF-16のバイト列へ変換する場合
7.5 文字列をUTF-32のバイト列へ変換する場合
7.6 UTF-32のバイト列から文字列へ変換
7.7 IntPtrのデータ先の長さを求める
7.8 IntPtr(UTF-8バイト列)からの文字列化
7.9 IntPtr(UTF-16バイト列)からの文字列化
7.10 IntPtr(Shift-JISバイト列)からの文字列化
7.11 IntPtr(UTF-32バイト列)からの文字列化
7.12 メモリーの割り当てに関する注意事項

第8章 文字列のマーシャリング

8.1 文字列型:引数にセットして関数呼び出し
8.2 文字列型:引数で結果を受け取る場合
8.3 文字列型:引数で結果を受け取る場合(2)
8.4 文字列型:関数戻り値の場合
8.5 文字列配列型:引数関数呼び出し
8.6 文字列配列型:呼び出し先で配列内容を変更

第9章 上級マーシャリング

9.1 ビットフィールドを使用している場合
9.2 プリミティブ型の2次元配列の場合
9.3 構造体中に構造体がある場合
9.4 構造体中に配列(固定長)がある場合
9.5 構造体中に配列(可変長)がある場合
9.6 構造体中に文字列(固定長)がある場合
9.7 構造体中に文字列(固定長)がある場合(2)
9.8 構造体中に文字列(可変長)がある場合
9.9 構造体中に文字配列がある場合
9.10 C#の関数をDLLに渡す場合
9.11 DLL関数から関数ポインタが返る場合
9.12 DLL関数から関数ポインタが返る場合(2)
9.13 構造体中に関数ポインタがある場合

あとがき

謝辞

第1章 はじめに

 この本を手に取っていただきありがとうございます。技術書典9に向けて作成した「Unityで使うC#/DLL マーシャリング事典」をベースに説明を加えたものです。ネイティブライブラリーを呼び出す際に必要になる「マーシャリング」について、Unity という条件を加えて説明した文献は非常に数が少ないか、現状この本が唯一となるのではないかと考えております。あなたのネイティブライブラリー呼び出しに悩む時間を、少しでも短縮できれば幸いです。

1.1 対象読者

 本書は以下に挙げるような読者を想定しています。

 ・Unity におけるマーシャリング入門者

 ・毎回マーシャリングのコード・記述に悩む方

 ・ちょっと複雑なマーシャリングで悩んでいる方

 ・マーシャリングについてまとまった情報を求めている方

 ・.NET Framework(CLR)とUnityのマーシャリングの差違に困っている方

 多少の C/C++ の知識や、 Windows DLL に関する知識などを持っていると理解の助けになります。

1.2 なぜ マーシャリングが必要になるのか

 ここで「いつ,なぜマーシャリングが必要になるのか」という問いがあります。Unity ではネイティブプラグインと呼ばれる DLL/so/dylib ファイルを呼び出して使用することができます。ネイティブプラグインは名前の通り、ネイティブで実装されています。ここでネイティブというのは、主に C/C++ やAndroidであればJavaを用いて実装されている(プラットフォームに合った実装)という意味合いです。これらの機能を呼び出す際にマネージドコードとネイティブコードの間でデータ型を変換するプロセス=「マーシャリング」が必要になります。


 これが必要になる場面としては以下の状況が挙げられます。

 ・Unity が機能を公開していない何らかの機能を使いたいとき

 ・サードパーティー製のモジュールやライブラリーを、Unity で使いたい(しかし、Unity向けに提供はされていない)

 ・処理速度を求めて機能をネイティブ実装することになった場合

 ・Unity の GC の対象から逃れたい

 いずれにしても標準の機能からは1歩先に進んだときに必要となってくるものでしょう。

1.3 前提条件

 この本は「マーシャリング」を取り扱ったものです。Unity でネイティブプラグインというと Android の Java によるネイティブプラグインも対象に含まれますが、この本ではそれを考慮しません。C/C++ で実装されたネイティブプラグインを対象とします。

 ネイティブプラグインを扱うときのお作法についても本書ではほとんど触れません。この本では ネイティブプラグインの作り方ではなく、ネイティブプラグインの関数の呼び出し方がわかる、に限定されます。

 ご存じの方もいると思いますが、unsafe ブロックを用いることで C# ではポインタをそのまま扱えます。しかし本書では可能な限り unsafe を使用せず、C#コードではポインタを出現させないことを趣旨にしております。またネイティブメソッドの呼び出し定義は NativeMethodsというスタティッククラスに定義したものとして話を進めております。

Unity 環境下であるということ

 一般的に C# で実装したアプリケーションはコンパイラによって共通中間言語(Common Intermediate Language:CIL) にコンパイルされます1。マイクロソフトの .NET Framework では共通言語ランタイム(Common Language Runtime :CLR) によってコードが実行されます。

 一方 Unity では、 CIL を実行するのは CLR ではありません。Mono もしくは IL2CPP という別のランタイムによって C# のコードが実行されます。

 このような実行されるエンジンの違いにより動作の異なる部分が出てきます。Webを検索すると多くのマーシャリングに関連する情報が見つかりますが、この差違を考慮して読み解く必要があります。この本では「Unity C# から使ったときのマーシャリング」に焦点を当てて説明していきます。CLR でのマーシャリングに慣れている方にとっても新発見があるかもしれません。

1.4 動作環境

 本書は以下の動作環境を対象としています。場合により Android や iPhone を対象とする補足を行います。

 ・Unity 2019.4.12f1

 ・Windows10 64ビット

 以下の環境については対象外としています。

 ・非Windows 環境での Unity エディターおよびスタンドアロン動作

1.5 免責事項

 この本に記載された内容は、情報の提供のみを目的としています。内容について注意を払って記述しておりますが、間違いなどが含まれている可能性もございます。したがって、書かれた情報(コード例を含む)を使用することで生じた結果に対して、著者及び出版社はいかなる責任も負いません。その点はあらかじめご了承ください。

1.6 参考文献

 ・Mono / Interop with Native Libraries

  ─https://www.mono-project.com/docs/advanced/pinvoke/

 ・Microsoft / Charsets and marshaling

  ─https://docs.microsoft.com/en-us/dotnet/standard/native-interop/charset

 ・Microsoft / Native interoperability best practices

  ─https://docs.microsoft.com/en-us/dotnet/standard/native-interop/best-practices

1. ひと昔前には、Microsoft Intermediate Language (MSIL) と呼ばれていました。

試し読みはここまでです。
この続きは、製品版でお楽しみください。