備忘録

備忘録

C#(EXE)からC++(DLL)の関数を呼び出す

Ⅰ. はじめに

C#(EXE)からC++(DLL)の関数を呼び出す方法です。
いわゆる P/Invoke です。

Win32 API の P/Invoke はこのサイトを利用してコピペしたほうが早いです。
http://www.pinvoke.net/

Ⅱ. サンプル


dllexport.def
EXPORTS 
  GetInt
  GetIntArray
  GetString
  GetStruct

MyDll.cpp

#define _CRT_SECURE_NO_WARNINGS

#include <Windows.h>

int GetInt()
{
  return 123;
}

void GetIntArray(int x[])
{
  x[0] = 1;
  x[1] = 2;
  x[2] = 3;
}

void GetString(char *str)
{
  strcpy(str, "あいうえお");
}

struct Data {
  int id;
  char name[512];
};

void GetStruct(Data *data)
{
  data->id = 1;
  strcpy(data->name, "名前1");
}

BOOL WINAPI DllMain(HINSTANCE hinstModule, DWORD dwReason, LPVOID lpvReserved)
{
  if (dwReason == DLL_PROCESS_ATTACH)
  {
    DisableThreadLibraryCalls(hinstModule);
  }

  return TRUE;
}

Program.cs

struct Data
{
  public int id;
  [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 512)]
  public string name;
}

[DllImport("Dll.dll", CallingConvention = CallingConvention.StdCall)]
static extern int GetInt();

[DllImport("Dll.dll", CallingConvention = CallingConvention.StdCall)]
static extern void GetIntArray([Out, MarshalAs(UnmanagedType.LPArray)] int[] data);

[DllImport("Dll.dll", CallingConvention = CallingConvention.StdCall)]
static extern void GetString(StringBuilder str);

[DllImport("Dll.dll", CallingConvention = CallingConvention.StdCall)]
static extern void GetStruct(ref Data data);

static void Main(string[] args)
{
  // int
  Console.WriteLine(GetInt());

  // int配列
  var intArray = new int[3];
  GetIntArray(intArray);
  Console.WriteLine(string.Join(",", intArray));

  // string
  var sb = new StringBuilder();
  GetString(sb);
  Console.WriteLine(sb);

  // 構造体
  var data = new Data();
  GetStruct(ref data);
  Console.WriteLine($"{data.id},{data.name}");
}

Ⅲ. 出力

f:id:kagasu:20170327221250p:plain

Ⅲ. DllImportについて

C#側のDllImportの呼び出し規約はデフォルトでCallingConvention.StdCallになります。
C++側の関数の呼び出し規約はデフォルトで__cdeclです。
スタック処理が異なる為不具合が発生する場合があります。
明示的に指定する事を心がけたほうが良いです。