C/C++で実装したDLLをC#から呼び出す(3)
構造体の授受
どもです。
C#からVC++のDLLを呼び出す内容を、以下のエントリで書いています。
これらのエントリでは、C#からVC++のDLLに値を渡す場合の例を示しています。VC++からC#に対して値を返す、ということはしていません。そこで今回は、C#とVC++の間で構造体を介してデータの受け渡しをしてみたので、その内容について書いてみます。
1. 開発環境
毎度ですが、開発環境です。
項目 | 内容 |
---|---|
OS | Windows10 Pro(22H2) |
CPU | i7-8700 |
メモリ | 16GB |
IDE | Visual Studio Community 2019 Version 17.7.6 |
.NET | .NET 7.0 |
Windows SDK | 10.0.22621.0 ※設定上は「10.0(最新のインストールされているバージョン)」を指定。 |
2. やってみた内容
今回やってみた内奥は、以下のような内容になります。
- 整数型のメンバーを3つ持つ構造体を定義する。(C#/VC++ともに)
- C#側で、構造体の変数を宣言、領域を確保、テキトーな値をメンバーにセットする。
- C#から、構造体を引数に持つVC++の関数を呼び出す。
- VC++側で、構造体のメンバーの和を計算して、もう1つのメンバーに値をセットする。
- C#側で、セットされた和の値を表示する。
またこの時、VC++の関数はDLLとして実装し、C#側でこのDLLの関数を呼び出せるようにしています。
3. やってみよう
それでは、実際にやってみます。
3.1. 構造体
今回は、以下のような構造体を太陽、定義します。
public struct SAMPLE_STRUCT
{
public short ParamA { get; set; }
public short ParamB { get; set; }
public int Result { get; set; }
};
これは、C#の場合の構造体定義になります。VC++の場合のコードは、少し異なります。構造体のメンバを示すことが目的であるため、詳細は省略します。
この構造体のメンバーのうち、ParamA、ParamBを入力とし、Resultに計算結果(今回は2つの値の「和」)を入力します。
3.2. C#の実装
C#側の実装、即ちVC++の関数の呼び出しは、以下のようになります。
SAMPLE_STRUCT sampleData = new SAMPLE_STRUCT();
sampleData.ParamA = 10;
sampleData.ParamB = 23;
sampleData.Result = -1;
long res = CppSideIF.CppSideSampleIF(ref sampleData);
Console.WriteLine($" res = {res}");
Console.WriteLine($"Result = {sampleData.Result}");
ここで「CppSideSampleIF」が、その名前の通りVC++で実装したライブラリのI/Fになります。VC++で構造体の内容を変更、VC++からC#側に返せるようにするために、参照を渡しています。
3.3. VC++側の実装
VC++の実装です。VC++側で構造体の内容を変更するため、引数で渡された構造体の要素の和を、構造体の別のメンバーにセットします。
typedef struct _SAMPLE_STRUCT_DATA
{
SHORT paramA;
SHORT paramB;
LONG result;
} SAMPLE_STRUCT;
SHORT
WINAPI
CppSideSampleIF(SAMPLE_STRUCT* input)
{
LONG result = input->paramA + input->paramB;
input->result = result;
return result;
}
この実装は、過去の記事とは少し異なり、DLLのエクスポートについての記述がありません。このDLLのエクスポートは、簡略化のために「.defファイル」に任せています。
処理の実装は、標準的なC++/VC++の実装です。特筆すべきことはありません。
3.4. C#側での宣言
最後に、C#からVC++で実装されたDLLの関数を呼び出すための実装です。これは、以下のように実装します。
namespace CsSideSampleProgram
{
public static class CppSideIF
{
[DllImport("CppSideSampleDll.dll")]
public static extern short CppSideSampleIF(ref SAMPLE_STRUCT input);
}
}
この実装は、過去の記事で「定石」とした方法です。ただ今回は、VC++側の引数がポインタとなっているため、C#側での宣言は参照を渡すことを示す「ref」を付与しています。
3.5. 実行結果
これまで紹介したコードを実装、実行すると下図のようになります。
実装した通り、ParamAとParamBの和がResultにセットされていることが確認できます。
4. まとめ
今回は、C#とVC++の間で、構造体を介してデータの受け渡しを行う方法について書きました。C#側でのDLLの宣言においてrefを付与することで、VC++のDLLのポインタ引数に対してアドレスを渡すことができます。これによりVC++側では、C#から渡された構造体のメンバーの値の参照、および値の変更ができます。
今回紹介した内容は、基本的な内容のみです。より厳密には、マネージド領域、アンマネージド領域についても考慮する必要があります。そういった内容については、別の機会に書こうと思います。
今回の内容が誰かの助けになれば幸いです。ではっ!
Ex. 公開しています
今回のエントリの全コードを、GitHubにて公開しています。より詳細に内容を確認したい場合には、コチラを参照してください。
ディスカッション
コメント一覧
まだ、コメントがありません