C++のDLLの中に、関数ポインタを取る関数が外部に公開されている。
これをC#から使いたい。
どういうわけか、以下コードのCallFunctionに渡す関数ポインタの型をtypedefした関数ポインタ型(CallFP)にしたところランタイムエラーが起こる。
仕方がないので、void*で受け取って呼び出し直前にキャストするようにしたところうまくいった。今のところ、意味が分からない。
ちなみに、DLLDefs.hはDLL作成時に使用するヘッダで使っているもの。
dlltest.h
#include "DLLDefs.h" #include <cstdint> /////////////////////////////////// /// C++側 (ヘッダ) ///////////////// /////////////////////////////////// int APIENTRY DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved); typedef void(WINAPI *CallFP)(std::int32_t a, std::int32_t b); __DLL_PORT void WINAPI CallFunction(void* p,std::int32_t in1,std::int32_t in2);
dlltest.cpp
#include <Windows.h> #include "dlltest.h" /////////////////////////////////// /// C++側 (cpp) ///////////////// /////////////////////////////////// int APIENTRY DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) { switch (dwReason) { case DLL_PROCESS_ATTACH: //初期処理 break; case DLL_PROCESS_DETACH: //終了処理 break; } return 1; // OK }; void WINAPI CallFunction(void* p, std::int32_t in1, std::int32_t in2) { CallFP cp = static_cast<CallFP>(p); (*cp)(in1, in2); }
using System; using System.Runtime.InteropServices;//Marshal用 /////////////////////////////////// /// C#側 (呼び出し)///////////////// /////////////////////////////////// namespace ConsoleApplication1 { //コールバック関数の型を宣言 [UnmanagedFunctionPointer(CallingConvention.StdCall)] delegate void TypeOfCallBack_t(System.Int32 a, System.Int32 b); class Program { //DLLの中の関数を宣言 [DllImport("Project1.dll",EntryPoint = "CallFunction") ] public static extern void CallFunction(IntPtr callbk,Int32 in1,Int32 in2); //コールバック関数本体。この関数がDLL経由で呼び出される static public void CallBackMain(Int32 a, Int32 b) { Console.Write(a + b + "\n"); } static TypeOfCallBack_t delgobj; static GCHandle gch; //エントリポイント public static void Main(string[] args) { delgobj = CallBackMain; IntPtr ptr = System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate( delgobj ); gch = GCHandle.Alloc(delgobj); //関数を呼び出す CallFunction( ptr ,10,15); Console.Read(); gch.Free(); } } }
DLLを扱う際にimport,exportを分けるファイル。
DLLを作るプロジェクトへ読み込んだ場合は、プロジェクトの設定などでDLL_EXPORT_DOを定義しておけば、関数宣言時に__DLL_PORTを付けると公開関数となる
DLLを使うプロジェクトへ読み込んだ場合は、libをリンクするだけで関数を使えるようになる。
#ifdef DLL_EXPORT_DO /* DLLを作る場合 */ #define __DLL_PORT extern "C" __declspec(dllexport) #else /* DLLを使う場合 */ #define __DLL_PORT extern "C" __declspec(dllimport) #endif