5
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

C++からC#のDLLを呼び出す際の引数

Last updated at Posted at 2019-07-24

経緯

C#で作成したDLLをC++で呼び出そうとした場合、引数の受け渡しの部分で少しはまったので、まとめておきます。

DLLと呼び出し側の構成について

引数の型によって呼び出す構成が変わります。

引数の型 データ 渡し方
プリミティブ型 数値
(固定の)文字列
論理値
null
undefined
IntPtr
そのまま受け渡す事が可能
オブジェクト型 (可変の)文字列など IntPtrでポインタとして渡し、
受け取り後に変換

上述した通り、可変の文字列などは、普通の関数のように引数を受け渡す事ができない(もしかしたらできるかも・・・)ため、一旦ポインタで渡し、受け取り側で変換することが必要です。

プリミティブ型の引数の受け渡し方

DLLでの引数の受け取り方

ポインタ型の引数を受け取り、Marshal.PtrToStringAutostring型に変換します。

DLL側.cs
        [DllExport]
        public static bool hoGE(int iTmp)
        {
            ・・・//普通にiTmpを使える。
        }

呼び出し側の引数の渡し方

今回は以下のようにヘッダーを作成しました。
クラス内に関数ポインタ型の変数を宣言し、コンストラクタで変数に関数のポインタを格納します。

呼び出し側.h
auto dll = ::LoadLibrary("EM.dll");
typedef bool (*HOGE)(int);
class EM
{
public:
	EM();
	~EM();
	HOGE			hoge;
};
EM::EM()
{
	hoge = reinterpret_cast<HOGE>(::GetProcAddress(dll, "hoGE"));
}
EM::~EM()
{
	if (dll)
		::FreeLibrary(dll);
}

hogeの引数の型がintなので、プリミティブ型であり、直接受け渡すことが可能です。

呼び出し側.cpp
EM EMD;
void Check()
{
      int Tmp = 25;
      EMD.hoge(Tmp);
        ・・・
        }

プリミティブ型での直接受け渡し時に注意すること

C#とC++の型の違いに注意してください。
今回、自分がはまったのが、long型の受け渡しでした。
型名は同じなのに、C#とC++でバイト数が異なるため、意図していない値になっていました。
(整数型・文字型のサイズは自身の処理系に依存します。)

バイト数 C++ C#
1 char sbyte
2 wchar_t char
2 short short
4 int int
4 long ---
8 __int64(Microsoft固有) long
※コメントでご指摘頂いた点

C++にlong型は存在しません。整数型はintであり、short/long/long longは整数型のサイズを指定する修飾子です(unsigned/signedは符号の有無を指定する修飾子)。修飾子が使用されている場合にのみintを省略することができます。

オブジェクト型の引数の受け渡し方

DLLでの引数の受け取り方

ポインタ型の引数を受け取り、Marshal.PtrToStringAutostring型に変換します。

DLL側.cs
        [DllExport]
        public static bool hoGE(IntPtr pTmp)
        {
            var sTmp = Marshal.PtrToStringAuto(pTmp);
        ・・・
        }

呼び出し側の引数の渡し方

今回は以下のようにヘッダーを作成しました。
クラス内に関数ポインタ型の変数を宣言し、コンストラクタで変数に関数のポインタを格納します。

呼び出し側.h
auto dll = ::LoadLibrary("EM.dll");
typedef bool (*HOGE)(const wchar_t*);
class EM
{
public:
	EM();
	~EM();
	HOGE			hoge;
};
EM::EM()
{
	hoge = reinterpret_cast<HOGE>(::GetProcAddress(dll, "hoGE"));
}
EM::~EM()
{
	if (dll)
		::FreeLibrary(dll);
}

hogeの引数の型がconst wchar_t*なので、CString型をCStringWに変換し、GetString()を行うことでポインタを渡しています。

呼び出し側.cpp
EM EMD;
void Check(CString strFunc)
{
      CStringW Tmp = strFunc;
      EMD.hoge(Tmp.GetString());
        ・・・
        }

参考サイト

参考にさせていただいたサイトです。

C#とC++の型について
プリミティブ型とオブジェクト型

5
5
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?