📢 Webサイト閉鎖と移転のお知らせ
このWebサイトは2026年9月に閉鎖いたします。
新しい記事は移転先で追加しております。(旧サイトでは記事を追加しておりません)

文字列「__FORCETOC__」を「{{#seo: |title={{PAGENAME}} : Exploring Electronics and SUSE Linux | MochiuWiki |keywords=MochiuWiki,Mochiu,Wiki,Mochiu Wiki,Electric Circuit,Electric,pcb,Mathematics,AVR,TI,STMicro,AVR,ATmega,MSP430,STM,Arduino,Xilinx,FPGA,Verilog,HDL,PinePhone,Pine Phone,Raspberry,Raspberry Pi,C,C++,C#,Qt,Qml,MFC,Shell,Bash,Zsh,Fish,SUSE,SLE,Suse Enterprise,Suse Linux,openSUSE,open SUSE,Leap,Linux,uCLnux,Podman,電気回路,電子回路,基板,プリント基板 |description={{PAGENAME}} - 電子回路とSUSE Linuxに関する情報 | This pag…
 
(同じ利用者による、間の10版が非表示)
1行目: 1行目:
== 概要 ==
== 概要 ==
C++ EXEからC# DLLの関数を呼び出す方法は、幾つか方法が存在しており、各々にメリットとデメリットがある。<br>
C++からC#ライブラリの関数を呼び出す方法は、複数の方法が存在しており、各々にメリットおよびデメリットがある。<br>
下記の表1に代表的な4種類の方法を示す。<br><br>
下表に代表的な5種類の方法を示す。<br><br>
<center>
<center>
'''表1. C++ EXEからC# DLLの関数を呼び出す方法'''
{| class="wikitable" | style="background-color:#fefefe;"
{| class="wikitable" | style="background-color:#fefefe;"
|+ C++からC#ライブラリのメソッドを呼ぶ方法
|-
|-
! style="background-color:#66CCFF;" | 方法  
! style="background-color:#66CCFF;" | 方法  
10行目: 10行目:
! style="background-color:#66CCFF;" | デメリット
! style="background-color:#66CCFF;" | デメリット
|-
|-
| C++/CLIを使う || 最も簡単<br>VisualStudioのIntelliSenseも使用可能 || プロジェクトの設定で[CLIを使う]に変更する必要がある。
| C++のプロジェクトをC++/CLIに設定する || C++のプロジェクトの設定において、[CLIを使う]に変更する。<br>VisualStudioのIntelliSenseも使用可能。 || C++/CLIに関するドキュメントが少ない。<br><br><u>Windowsのみ使用可能。</u>
|-
|-
| .NET DLLExportを使用して、<br>C# DLLのメソッドをエクスポートする || [CLIを使う]に変更しなくてよい<br><code>GetProcAddress</code>関数が使用できるため、<br>よく知られた方法で関数を呼び出す事が出来る || C# DLL側のソースコードが無い場合は利用できない。
| [https://github.com/3F/DllExport .NET DLLExport]を使用して、<br>C#ライブラリのメソッドをエクスポートする || C++/CLIを使用する必要がない。<br><br><code>GetProcAddress</code>関数が使用できるため、<br>よく知られた方法で関数を呼び出す事が出来る || C#ライブラリのソースコードが無い場合は利用できない。<br><br><u>Windowsのみ使用可能。</u>
|-
|-
| C# DLLに対するC++/CLIのラッパーDLLを作成して、<br>C++ EXEから使う || [CLIを使う]に変更しなくてよい<br>COMを使用しない場合において、<br>元のプロジェクトの設定を変更したくない場合に使用可能 || やり方がスマートではない。
| C++からC#ライブラリを呼ぶための<br>C++/CLIのラッパーライブラリを開発する || COMを使用しなくてよい。<br>C++およびC#のプロジェクトの設定を変更しなくてよい。 || C#ライブラリ、および、C++/CLIライブラリの2つのライブラリを作成する必要がある。<br>C++/CLIに関するドキュメントが少ない。<br><br><u>Windowsのみ使用可能。</u>
|-
|-
| Monoを使う || C++実行ファイルとC#ライブラリの2つを作成するだけでよい。<br><u>Linux、MacOSでも使用可能である。ただし、デメリットも多い。</u><br><br>C++の実行ファイルにおいて、<br>Monoに関連するヘッダファイルをインクルードして、C#のライブラリを呼び出す。<br> || Linuxの場合は、.NET Standard (.NET Core / .NET 5以降ではない) またはMonoを使用して、C#のライブラリを作成する必要がある。<br>Windowsの場合は、.NET Frameworkを使用して、C#のライブラリを作成する必要がある。<br>したがって、Windowsの場合は.NET Core / .NET 5以降は使用することができない。<br><br>また、実行環境にもMonoをインストールする必要がある。
| Embedded Monoを使用する || C++およびC#ライブラリの2つのプロジェクトを作成するだけでよい。<br><u>Linux、MacOSでも使用可能である。</u><br><br><u>ただし、Linux上で使用する場合、</u><br><u><code>async, await</code>や他の様々なシンタックスが使用できない等の</u><br><u>デメリットも多い。</u><br><br>C++のプロジェクトにおいて、<br>Monoに関連するヘッダファイルをインクルードして、C#ライブラリを呼ぶ。<br> || Linuxの場合は、.NET Standard (.NET Core / .NET 5以降ではない) またはMonoを使用して、<br>C#ライブラリを作成する必要がある。<br><br>Windowsの場合は、.NET FrameworkまたはMonoを使用して、C#ライブラリを作成する必要がある。<br><br>したがって、.NET Core / .NET 5以降は使用することができない。<br><br>また、実行環境にもMonoをインストールする必要がある。
|-
|-
| C# DLLをCOM参照可能にする || [CLIを使う]に変更しなくてよい || C++ EXEのコード量が増えて面倒である。
| C#ライブラリをCOM参照可能にする || C++/CLIライブラリは不要である。 || C++のソースコード量が増えて設計が煩雑となる。<br><br>COM (Component Object Model) は、Windows独自の技術であり、<br><u>Linuxでは直接サポートされていないため、Windowsのみ使用可能である。</u><br><br>COMはWindowsのオブジェクト指向プログラミングモデルであり、<br>Microsoftの開発環境やWindows APIと密接に関連している。
|}
|}
</center>
</center>
<br>
<br>
上表1において、以下の手順を記載する。<br>
上表1において、以下の手順を記載する。<br>
* C++/CLIを使う
* C++のプロジェクトをC++/CLIに設定する
* C# DLL側で関数をエクスポートする
* [https://github.com/3F/DllExport .NET DLLExport]を使用して、C#ライブラリのメソッドをエクスポートする
* C++/CLIのラッパープロジェクトを作成する
* C++/CLIのラッパーライブラリを開発する
* C# DLLをCOM参照可能にする
* Embedded Monoを使用する
* C#ライブラリをCOM参照可能にする
<br><br>
<br><br>


446行目: 447行目:
     MonoString *excString  = mono_object_to_string(excObject, nullptr);
     MonoString *excString  = mono_object_to_string(excObject, nullptr);
     const char *excCString = mono_string_to_utf8(excString);
     const char *excCString = mono_string_to_utf8(excString);
     std::cout << "メソッドの実行時における例外 : " << "excCString" << std::endl;
     std::cout << "メソッドの実行時における例外 : " << excCString << std::endl;
   
   
     mono_jit_cleanup(domain);
     mono_jit_cleanup(domain);
532行目: 533行目:
     // メモリの解放
     // メモリの解放
     mono_free(stringValue);
     mono_free(stringValue);
}
</syntaxhighlight>
<br>
===== 戻り値が配列の場合 (非コレクション) =====
以下の例では、C#ライブラリのメソッドの戻り値はint型の配列であり、C++でそれを受け取っている。<br>
<br>
まず、<code>mono_runtime_invoke</code>関数でC#のメソッドを呼び出して、戻り値を<code>MonoObject*</code>型で受け取る。<br>
次に、<code>reinterpret_cast</code>を使用して<code>MonoObject*</code>型を<code>MonoArray*</code>に変換する。<br>
最後に、<code>mono_array_get</code>関数を使用して<code>int</code>型の配列の各要素を取得している。<br>
<br>
<syntaxhighlight lang="c#">
// C#ライブラリ
public int[] RetList()
{
    return [1, 2, 3];
}
</syntaxhighlight>
<br>
<syntaxhighlight lang="c++">
// C++
MonoObject *pResult = mono_runtime_invoke(method, instance, nullptr, &exc);
// エラーの確認
if (exc != nullptr) {
    // エラー情報の取得
    // ...略
}
else {
    // MonoObject*型をint型の配列に変換
    MonoArray* resultArray = reinterpret_cast<MonoArray*>(pResult);
    // 配列の長さを取得
    auto arrayLength = mono_array_length(resultArray);
    // int型の配列に変換
    std::vector<int> ivec(0, 0);
    for (auto i = 0; i < arrayLength; i++) {
      // MonoArray*型をint型に変換
      ivec.push_back(mono_array_get(resultArray, int, i));
    }
    for (auto i : ivec) {
      std::cout << i << std::endl;
    }
  }
  }
  </syntaxhighlight>
  </syntaxhighlight>
549行目: 596行目:
     MonoString* Field2;  // string型
     MonoString* Field2;  // string型
  };
  };
// ...略
   
   
  MonoObject *pResult = mono_runtime_invoke(method, instance, params, &exc);
  MonoObject *pResult = mono_runtime_invoke(method, instance, params, &exc);
557行目: 606行目:
     // ...略
     // ...略
  }
  }
  else
  else {
{
     // タプル型から個々の値を取得
     // タプル型から個々の値を取得
     TupleResult *tupleResult = static_cast<TupleResult*>(mono_object_unbox(pResult));
     TupleResult *tupleResult = static_cast<TupleResult*>(mono_object_unbox(pResult));
842行目: 890行目:
# [デバッガーの種類]項目を、[混合]または[自動]に設定して、[OK]ボタンを押下する。
# [デバッガーの種類]項目を、[混合]または[自動]に設定して、[OK]ボタンを押下する。
<br><br>
<br><br>
{{#seo:
|title={{PAGENAME}} : Exploring Electronics and SUSE Linux | MochiuWiki
|keywords=MochiuWiki,Mochiu,Wiki,Mochiu Wiki,Electric Circuit,Electric,pcb,Mathematics,AVR,TI,STMicro,AVR,ATmega,MSP430,STM,Arduino,Xilinx,FPGA,Verilog,HDL,PinePhone,Pine Phone,Raspberry,Raspberry Pi,C,C++,C#,Qt,Qml,MFC,Shell,Bash,Zsh,Fish,SUSE,SLE,Suse Enterprise,Suse Linux,openSUSE,open SUSE,Leap,Linux,uCLnux,Podman,電気回路,電子回路,基板,プリント基板
|description={{PAGENAME}} - 電子回路とSUSE Linuxに関する情報 | This page is {{PAGENAME}} in our wiki about electronic circuits and SUSE Linux
|image=/resources/assets/MochiuLogo_Single_Blue.png
}}


__FORCETOC__
__FORCETOC__
[[カテゴリ:C++]]
[[カテゴリ:C++]]