「ライブラリの基礎 - C++DLL」の版間の差分

ナビゲーションに移動 検索に移動
(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>
  <source lang="c++">
  <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)
void  __stdcall SampleFunc04(SampleStruct st)
  </syntaxhighlight>
void  __stdcall SampleFunc05(SampleStruct *pStructure)
  </source>
<br>
<br>
  <source lang="c++">
  <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"
typedef struct tagSampleStruct
{
    int index;
    char name[128];
    int data[50];
} SampleStruct, *pSampleStruct;
typedef struct tagSampleStruct2
{
    int length;
    double *data;
} SampleStruct2, *pSampleStruct2;
   
   
  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  // モジュール定義ファイル
   
   
  void __stdcall SampleFunc04(SampleStruct st)
  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:Sample04>--\r\n");
    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 SampleFunc05(SampleStruct2 *pStructure)
  void __stdcall SampleFunc02(SampleStruct2 *pStructure)
  {
  {
     dData[256] = {0};
     dData[256] = {0};
     printf("--<SampleDll:Sample05>--\r\n");
     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");
  }
  }
  </source>
  </syntaxhighlight>
  <source lang="c++">
<br>
  SampleDll.def  // モジュール定義ファイル
  <syntaxhighlight lang="c++">
  // SampleDll.def  // モジュール定義ファイル
   
   
  LIBRARY SampleDll
  LIBRARY SampleDll
487行目: 568行目:
           SampleFunc01  @1
           SampleFunc01  @1
           SampleFunc02  @2
           SampleFunc02  @2
          SampleFunc03  @3
  </syntaxhighlight>
          SampleFunc04  @4
          SampleFunc05  @5
  </source>
<br>
<br>
次に、C# EXEからC++ DLLを呼び出す方法を記述する。<br>
次に、C# EXEからC++ DLLを呼び出す方法を記述する。<br>
文字列をC++ DLL側に渡す場合は、string型を使用する。<br>
文字列をC++ DLL側から返す場合は、string型ではなくStringBuilderクラスを使用する必要がある。<br>
StringBuilderクラスは受け渡しの両方が可能なので、文字列はStringBuilderクラスを使用すべきである。<br>
<br>
<br>
C++では構造体のサイズはコンパイル時に決定されるが、C#では実行時に決定される。<br>
C++では構造体のサイズはコンパイル時に決定されるが、C#では実行時に決定される。<br>
したがって、C#側で構造体のサイズを予め指定する必要がある。<br>
したがって、C#側で構造体のサイズを予め指定する必要がある。<br>
この場合、構造体は固定長サイズとなるため、配列などを定義する場合は異なるサイズの配列を後からインスタンス化することができなくなる。<br>
この時、構造体は固定長サイズとなるため、配列等を定義する場合は異なるサイズの配列を後からインスタンス化することができなくなる。<br>
<br>
<br>
構造体をC++ DLL側から返す場合、IntPtr型からdouble型の配列を取得するときは、一度Int64型に変換し、これをBitConverter.Int64BitsToDouble()メソッドでdouble型に変換する。<br>
構造体をC++ DLL側から返す場合、<code>IntPtr</code>型から<code>double</code>型の配列を取得する時は、<code>Int64</code>型へ変換した後、<code>BitConverter.Int64BitsToDouble</code>メソッドで<code>double</code>型に変換する。<br>
  <source lang="c#">
  <syntaxhighlight lang="c#">
  using System;
  using System;
  using System.Text;
  using System.Text;
511行目: 586行目:
     class Program
     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);
       /// <summary>
       /// <summary>
       /// 構造体を引数に持つ関数のインポート例
       /// 構造体を引数に持つ関数のインポート例
532行目: 591行目:
       /// <param name="st">DLL 側に渡す構造体を指定します</param>
       /// <param name="st">DLL 側に渡す構造体を指定します</param>
       [DllImport("SampleDLL.dll")]
       [DllImport("SampleDLL.dll")]
       private static extern void SampleFunc04(SampleStruct st);
       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 SampleFunc05(IntPtr pst);
       private static extern void SampleFunc02(IntPtr pst);
   
   
       /// <summary>
       /// <summary>
580行目: 639行目:
       static void Main(string[] args)
       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);
           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;
           SampleFunc04(structHoge);
           SampleFunc01(structHoge);
   
   
           // SampleStruct2構造体のサイズを取得する
           // SampleStruct2構造体のサイズを取得する
609行目: 656行目:
           try
           try
           {
           {
             SampleFunc05(structPiyo);
             SampleFunc02(structPiyo);
             // 受け取ったstructPiyoからSampleStruct2構造体の情報に構築し直す
             // 受け取ったstructPiyoからSampleStruct2構造体の情報に構築し直す
             var structFuga = (SampleStruct2)Marshal.PtrToStructure(structPiyo, typeof(SampleStruct2));
             var structFuga = (SampleStruct2)Marshal.PtrToStructure(structPiyo, typeof(SampleStruct2));
633行目: 680行目:
     }
     }
  }
  }
  </source>
  </syntaxhighlight>
<br>
<br>
==== 関数ポインタのマーシャリング ====
==== 関数ポインタのマーシャリング ====
このセクションでは、C# EXEからC++ DLLへコールバック関数を渡す方法を記載する。<br>
このセクションでは、C# EXEからC++ DLLへコールバック関数を渡す方法を記載する。<br>

案内メニュー