13,230
回編集
細 (Wiki がページ「C Sharpの基礎 - C++DLL」を「ライブラリの基礎 - C++DLL」に、リダイレクトを残さずに移動しました) |
|||
| 397行目: | 397行目: | ||
</source> | </source> | ||
<br> | <br> | ||
==== | ==== 文字列のマーシャリング ==== | ||
C++ DLLの作成方法は[[ライブラリの基礎 - DLLの作成(C/C++/MFC)|ライブラリの基礎 - DLLの作成(C/C++/MFC)]]を参照する。<br> | C++ DLLの作成方法は[[ライブラリの基礎 - DLLの作成(C/C++/MFC)|ライブラリの基礎 - DLLの作成(C/C++/MFC)]]を参照する。<br> | ||
<br> | <br> | ||
下記にもC++ DLLを記述する。<br> | 下記にもC++ DLLを記述する。<br> | ||
< | <syntaxhighlight lang="c++"> | ||
SampleDLL.h | // SampleDLL.h | ||
double __stdcall SampleFunc01(int a); | double __stdcall SampleFunc01(int a); | ||
void __stdcall SampleFunc02(int a, char *pstr) | void __stdcall SampleFunc02(int a, char *pstr) | ||
void __stdcall SampleFunc03(int a, char *pstr) | void __stdcall SampleFunc03(int a, char *pstr) | ||
</syntaxhighlight> | |||
</ | |||
<br> | <br> | ||
< | <syntaxhighlight lang="c++"> | ||
SampleDll.cpp | // SampleDll.cpp | ||
#include <stdio.h> | #include <stdio.h> | ||
#include <string.h> | #include <string.h> | ||
#include "SampleDll.h" | #include "SampleDll.h" | ||
double __stdcall SampleFunc01(int a) | double __stdcall SampleFunc01(int a) | ||
| 454行目: | 439行目: | ||
printf("------------------------\r\n"); | printf("------------------------\r\n"); | ||
} | } | ||
</syntaxhighlight> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
// SampleDll.def // モジュール定義ファイル | |||
LIBRARY SampleDll | |||
EXPORTS | |||
; 公開する関数名をリストアップ | |||
SampleFunc01 @1 | |||
SampleFunc02 @2 | |||
SampleFunc03 @3 | |||
</syntaxhighlight> | |||
<br> | |||
次に、C# EXEからC++ DLLを呼び出す方法を記述する。<br> | |||
<br> | |||
文字列をC++ DLL側に渡す場合は、<code>string</code>型を使用する。<br> | |||
文字列をC++ DLL側から返す場合は、<code>StringBuilder</code>クラスを使用する。<br> | |||
<u><code>StringBuilder</code>クラスは受け渡しの両方が可能なので、文字列は全て<code>StringBuilder</code>クラスを使用すべきである。</u><br> | |||
<br> | |||
<syntaxhighlight lang="c#"> | |||
using System; | |||
using System.Text; | |||
using System.Runtime.InteropServices; | |||
namespace SampleEXE | |||
{ | { | ||
printf("--<SampleDll: | class Program | ||
{ | |||
/// <summary> | |||
/// 最も基本的な関数のインポート例 | |||
/// </summary> | |||
/// <param name="a">4 バイト符号付き整数を指定します。</param> | |||
/// <returns>倍精度浮動小数を返します。</returns> | |||
[DllImport("SampleDLL.dll")] | |||
private static extern double SampleFunc01(int a); | |||
[DllImport("SampleDLL.dll", CharSet = CharSet.Unicode)] | |||
// C++ DLL側の文字コードがUnicodeの場合は"CharSet = CharSet.Unicode"と明示的に指定する | |||
private static extern void SampleFunc02(int a, string str); | |||
[DllImport("SampleDLL.dll", CharSet = CharSet.Unicode)] | |||
// C++ DLL側の文字コードがUnicodeの場合は"CharSet = CharSet.Unicode"と明示的に指定する | |||
private static extern void SampleFunc03(int a, StringBuilder str); | |||
static void Main(string[] args) | |||
{ | |||
var dRet= SampleFunc01(1); | |||
Console.WriteLine(dRet); | |||
Console.WriteLine(); | |||
var str = "string型で文字列を渡すことができます。"; | |||
SampleFunc02(2, str); | |||
var strb = new System.Text.StringBuilder(256); | |||
strb.Append("文字列のバッファを渡す場合は StringBuilder クラスで受け渡します。"); | |||
SampleFunc03(3, strb); | |||
Console.WriteLine(strb); | |||
Console.ReadKey(); | |||
} | |||
} | |||
} | |||
</syntaxhighlight> | |||
<br> | |||
==== 構造体のマーシャリング ==== | |||
C++ DLLの作成方法は[[ライブラリの基礎 - DLLの作成(C/C++/MFC)|ライブラリの基礎 - DLLの作成(C/C++/MFC)]]を参照する。<br> | |||
<br> | |||
下記にもC++ DLLを記述する。<br> | |||
<syntaxhighlight lang="c++"> | |||
// SampleDLL.h | |||
void __stdcall SampleFunc01(SampleStruct st) | |||
void __stdcall SampleFunc02(SampleStruct *pStructure) | |||
</syntaxhighlight> | |||
<br> | |||
<syntaxhighlight lang="c++"> | |||
// SampleDll.cpp | |||
#include <stdio.h> | |||
#include <string.h> | |||
#include "SampleDll.h" | |||
typedef struct tagSampleStruct | |||
{ | |||
int index; | |||
char name[128]; | |||
int data[50]; | |||
} SampleStruct, *pSampleStruct; | |||
typedef struct tagSampleStruct2 | |||
{ | |||
int length; | |||
double *data; | |||
} SampleStruct2, *pSampleStruct2; | |||
void __stdcall SampleFunc01(SampleStruct st) | |||
{ | |||
printf("--<SampleDll:Sample01>--\r\n"); | |||
printf("index = %d\r\n", st.index); | printf("index = %d\r\n", st.index); | ||
printf("name = %s\r\n", st.name); | printf("name = %s\r\n", st.name); | ||
| 464行目: | 544行目: | ||
} | } | ||
void __stdcall | void __stdcall SampleFunc02(SampleStruct2 *pStructure) | ||
{ | { | ||
dData[256] = {0}; | dData[256] = {0}; | ||
printf("--<SampleDll: | printf("--<SampleDll:Sample02>--\r\n"); | ||
memset(pStructure, 0, sizeof(SampleStruct2)); | memset(pStructure, 0, sizeof(SampleStruct2)); | ||
pStructure->length = 10; | pStructure->length = 10; | ||
| 477行目: | 557行目: | ||
printf("------------------------\r\n"); | printf("------------------------\r\n"); | ||
} | } | ||
</ | </syntaxhighlight> | ||
< | <br> | ||
SampleDll.def // モジュール定義ファイル | <syntaxhighlight lang="c++"> | ||
// SampleDll.def // モジュール定義ファイル | |||
LIBRARY SampleDll | LIBRARY SampleDll | ||
| 487行目: | 568行目: | ||
SampleFunc01 @1 | SampleFunc01 @1 | ||
SampleFunc02 @2 | SampleFunc02 @2 | ||
</syntaxhighlight> | |||
</ | |||
<br> | <br> | ||
次に、C# EXEからC++ DLLを呼び出す方法を記述する。<br> | 次に、C# EXEからC++ DLLを呼び出す方法を記述する。<br> | ||
<br> | <br> | ||
C++では構造体のサイズはコンパイル時に決定されるが、C#では実行時に決定される。<br> | C++では構造体のサイズはコンパイル時に決定されるが、C#では実行時に決定される。<br> | ||
したがって、C#側で構造体のサイズを予め指定する必要がある。<br> | したがって、C#側で構造体のサイズを予め指定する必要がある。<br> | ||
この時、構造体は固定長サイズとなるため、配列等を定義する場合は異なるサイズの配列を後からインスタンス化することができなくなる。<br> | |||
<br> | <br> | ||
構造体をC++ | 構造体をC++ DLL側から返す場合、<code>IntPtr</code>型から<code>double</code>型の配列を取得する時は、<code>Int64</code>型へ変換した後、<code>BitConverter.Int64BitsToDouble</code>メソッドで<code>double</code>型に変換する。<br> | ||
< | <syntaxhighlight lang="c#"> | ||
using System; | using System; | ||
using System.Text; | using System.Text; | ||
| 511行目: | 586行目: | ||
class Program | class Program | ||
{ | { | ||
/// <summary> | /// <summary> | ||
/// 構造体を引数に持つ関数のインポート例 | /// 構造体を引数に持つ関数のインポート例 | ||
| 532行目: | 591行目: | ||
/// <param name="st">DLL 側に渡す構造体を指定します</param> | /// <param name="st">DLL 側に渡す構造体を指定します</param> | ||
[DllImport("SampleDLL.dll")] | [DllImport("SampleDLL.dll")] | ||
private static extern void | private static extern void SampleFunc01(SampleStruct st); | ||
/// <summary> | /// <summary> | ||
| 539行目: | 598行目: | ||
/// <param name="pst">受け渡す構造体の先頭アドレスを示すポインタを指定する</param> | /// <param name="pst">受け渡す構造体の先頭アドレスを示すポインタを指定する</param> | ||
[DllImport("SampleDLL.dll")] | [DllImport("SampleDLL.dll")] | ||
private static extern void | private static extern void SampleFunc02(IntPtr pst); | ||
/// <summary> | /// <summary> | ||
| 580行目: | 639行目: | ||
static void Main(string[] args) | static void Main(string[] args) | ||
{ | { | ||
var structHoge = new SampleStruct() | var structHoge = new SampleStruct() | ||
{ | { | ||
| 602行目: | 649行目: | ||
structHoge.data[1] = 22; | structHoge.data[1] = 22; | ||
structHoge.data[2] = 33; | structHoge.data[2] = 33; | ||
SampleFunc01(structHoge); | |||
// SampleStruct2構造体のサイズを取得する | // SampleStruct2構造体のサイズを取得する | ||
| 609行目: | 656行目: | ||
try | try | ||
{ | { | ||
SampleFunc02(structPiyo); | |||
// 受け取ったstructPiyoからSampleStruct2構造体の情報に構築し直す | // 受け取ったstructPiyoからSampleStruct2構造体の情報に構築し直す | ||
var structFuga = (SampleStruct2)Marshal.PtrToStructure(structPiyo, typeof(SampleStruct2)); | var structFuga = (SampleStruct2)Marshal.PtrToStructure(structPiyo, typeof(SampleStruct2)); | ||
| 633行目: | 680行目: | ||
} | } | ||
} | } | ||
</ | </syntaxhighlight> | ||
<br> | <br> | ||
==== 関数ポインタのマーシャリング ==== | ==== 関数ポインタのマーシャリング ==== | ||
このセクションでは、C# EXEからC++ DLLへコールバック関数を渡す方法を記載する。<br> | このセクションでは、C# EXEからC++ DLLへコールバック関数を渡す方法を記載する。<br> | ||