MochiuWiki : SUSE, EC, PCB
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
検索
個人用ツール
ログイン
Toggle dark mode
名前空間
ページ
議論
表示
閲覧
ソースを閲覧
履歴を表示
ライブラリの基礎 - C++DLLのソースを表示
提供: MochiuWiki : SUSE, EC, PCB
←
ライブラリの基礎 - C++DLL
あなたには「このページの編集」を行う権限がありません。理由は以下の通りです:
この操作は、次のグループのいずれかに属する利用者のみが実行できます:
管理者
、new-group。
このページのソースの閲覧やコピーができます。
== 概要 == C# EXEからC++ DLLへ様々なデータ型の変数を渡したいときがある。<br> <br> 例えば、C++ DLLから次のような関数がエクスポートされているとする。<br> <source lang="c++"> void WINAPI ConvertToShort(char *pstr, short *pret); </source> <br> 上記の関数において、C# EXEから使用するときは、char*型は文字列なのでstring型を渡す。<br> short*型はIntPtr型を渡す。(IntPtr型は汎用ポインタを表す型であり、void*型とほぼ同義)<br> <br> 但し、C#は厳しい型付け言語なので、曖昧さを解決するために変換メソッドを経由する必要がある。<br> 具体的には、IntPtr型の変数にMarshal.AllocHGlobal関数で必要なサイズのメモリを確保して、それをC++ DLLに渡した後、<br> Marshal.ReadInt16関数(型によって異なる)等で変換した後、確保したメモリをMarshal.FreeHGlobal関数で解放するというプロセスを経る必要がある。<br> <br><br> == サンプルコード == 下記に、C++ DLLを呼ぶC# EXEのソースコードを記載する。<br> <br> <source lang="c#"> // DllImportを使用するために必要 using System.Runtime.InteropServices; [DllImport("DrsUtil.dll", EntryPoint = "ConvertToShort")] extern static void _ConvertToShort(string pstr, IntPtr pret); //呼び出し元の名前変えちゃう public static short ConvertToShort(string str) { IntPtr buffer = new IntPtr(); buffer = Marshal.AllocHGlobal(2); // 2バイトのメモリ確保 _ConvertToShort(str, buffer); // C++/DLLの関数を呼ぶ short sval = Marshal.ReadInt16(buffer); // 変換 Marshal.FreeHGlobal(buffer); // メモリ開放 return sval; } </source> <br> IntPtr型の変数は様々なものが入るので、例えば、構造体を取得することも可能だが、C# EXEで構造体を定義しなければいけない。<br> WindowsのDLL(Win32 API)と.NET Frameworkでは型の管理方法が違うため、実際には型の相互変換(マーシャリング)が行われる。<br> 尚、BOOL型の実体はLONG型と同じなので、boolの代わりにintを指定することも可能である。<br> <br> <center>'''表1. Win32 APIでの型名と対応するC#の型'''</center> <center> {| class="wikitable" |- ! APIの型名<br>(括弧内は対応するC言語の型) !! 対応するC#の型<br>(括弧内は.NET Frameworkでの型名) !! 備考 |- | HANDLE (void *) || System.IntPtr<br>System.UIntPtr || x86は4バイト<br>x64は8バイト |- | BYTE (unsigned char) || byte (System.Byte) || |- | SHORT (short) || short (System.Int16) || |- | WORD (unsigned short) || ushort (System.UInt16) || |- | INT (int)<br>LONG (long) || int (System.Int32) || |- | UINT (unsigned int)<br>DWORD, ULONG (unsigned long) || uint (System.UInt32) || |- | BOOL (long) || bool (System.Boolean) || |- | CHAR (char) || 文字を渡すとき<br>char (System.Char)<br>文字を受け取るとき<br>StringBuilder || |- | WCHAR(wchar_t) || 文字を渡すとき<br>char (System.Char)<br>文字を受け取るとき<br>StringBuilder || |- | LPSTR (char *, char[])<br>LPWSTR (wchar_t *, wchar_t[]) || 文字を渡すとき<br>string (System.String)<br>文字を受け取るとき<br>System.Text.StringBuilder || |- | LPCSTR (const char *, const char[])<br>LPCWSTR (const wchar_t *, const wchar_t[]) || 文字を渡すとき<br>string (System.String)<br>文字を受け取るとき<br>System.Text.StringBuilder || |- | FLOAT (float) || float (System.Single) || |- | DOUBLE (double) || double (System.Double) || |} </center> <br><br> == サンプルコード == C++ DLLの作成方法は[[DLLを作成する(MFC)|コチラを参照]]する。<br> 念のため、下記にもC++ DLLを記述する。<br> <source lang="c++"> SampleDLL.h double __stdcall SampleFunc01(int a); void __stdcall SampleFunc02(int a, char *pstr) void __stdcall SampleFunc03(int a, char *pstr) </source> <source lang="c++"> SampleDll.cpp #include <stdio.h> #include <string.h> #include "SampleDll.h" double __stdcall SampleFunc01(int a) { printf(--<SampleDll:SampleFunc01>--\r\n"); printf("a = %d\r\n", a); printf("---------------------------\r\n"); return 3.14; } void __stdcall Sample02(int a, char *pstr) { printf("--<SampleDll:SampleFunc02>--\r\n"); printf("[%d] %s\r\n", a, str); printf("-----------------------------\r\n"); } void __stdcall SampleFunc03(int a, char *pstr) { printf("--<SampleDll:SampleFunc03>--\r\n"); printf("[%d] %s\r\n", a, str); sprintf_s(str, 256, "C++ DLL側から文字列を返す場合は、StringBuilderクラスを使用する"); printf("------------------------\r\n"); } </source> <source lang="c++"> SampleDll.def // モジュール定義ファイル LIBRARY SampleDll EXPORTS ; 公開する関数名をリストアップ SampleFunc01 @1 SampleFunc02 @2 SampleFunc03 @3 </source> <br><br> 次に、C# EXE側でC++ DLLを呼び出す方法を記述する。 文字列をC++ DLL側に渡す場合は、string型を使用する。 文字列をC++ DLL側から返す場合は、string型ではなくStringBuilderクラスを使用する必要がある。 StringBuilderクラスは受け渡しの両方が可能なので、文字列はStringBuilderクラスを使用すべきである。 <source lang="c#"> using System; using System.Runtime.InteropServices; namespace SampleEXE { 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(); } } } </source> <br> DllImport属性には、DLLファイルのパスを指定する以外に次のような引数を与えることもできる。<br> これ他にも細かい設定をするための引数が用意されているので、DllImportAttributeクラスで検索すること。<br> {| class="wikitable" |- ! 名称 !! 説明 |- | CallingConvention || エントリポイントの呼び出し規約を明示的に指定できる。<br>指定なしの場合は__stdcallとなる。 |- | CharSet || 文字列パラメータをメソッドにマーシャリングし、名前マングルを制御する方法を指定する。<br>文字コードの相互変換する時に指定する。 |- | EntryPoint || 呼び出すDLLエントリポイントの名前または序数を指定する。<br>DLLの関数名とC#上で使用する関数名を異なる名前にする時に指定する。 |} <br><br> __FORCETOC__ [[カテゴリ:C_Sharp]]
ライブラリの基礎 - C++DLL
に戻る。
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
Collapse