2017-04-05 42 views
2

C++のdllで定義された機能は次のとおりです。関数ポインタをC#からC++のDLLに渡すには?

static double (*Func1)(double); 
EXTERN_C __declspec(dllexport) __stdcall double TestDelegate(double (*fun)(double)) 
{ 
    Func1 = fun; 
    return Func1(25.0); 
} 


void My_Real_purpose() 
{ 
    SomeClass a; 
    a.SetFunction(Func1);//Define behaviour of a by C# in runtime 
    a.DoSomething();//Even I want it runs in another thread! 
} 

そして、私はこのようなC#で、それを呼び出そうとしました:

class A 
    { 
     [DllImport("DllName.dll")] 
     public extern static double TestDelegate(IntPtr f); 

     public delegate double MyFuncDelegate(double x); 

     public static double MyFunc(double x) 
     { 
      return Math.Sqrt(x); 
     } 

     static MyFuncDelegate ff; 
     static GCHandle gch; 
     public static double Invoke() 
     { 
      ff = new MyFuncDelegate(MyFunc); 
      gch = GCHandle.Alloc(ff); 
      double c = TestDelegate(Marshal.GetFunctionPointerForDelegate(ff));//Error occurs this line 
      gch.Free(); 
      return c; 
     } 

    } 

それが実行されるとき、VS2012は、エラーを表示しerror.Butせずにコンパイルされています「アクセス違反例外」の

私は、IntPtrではなくデリゲートを渡すなど、多くの方法を検索して試しましたが、すべてが失敗していました。

したがって、関数ポインタを含むdllでAPI関数を使用する正しい方法は何ですか?または「My_Real_purpose」関数を実現する方法はありますか?

+0

可能な重複:

[DllImport("DllName.dll")] public extern static double TestDelegate(CallbackDelegate f); 

あなたは、このようにそれを呼び出すことができます - 関数の引数には、ワイド文字列(LPCWSTR)が含まれています](http://stackoverflow.com/questions/6282264/pass-a-function-pointer-from-c-to-be-called-by-c-sharp- arguments-of-function) –

+0

この質問はCOMとは関係がないため、COMタグを削除しました。 PInvokeタグがより適切です。 –

+1

デリゲートの宣言が間違っていますが、AVEを説明するには不十分です。このクラッシュを診断できるように、C++コードをデバッグする方法を理解しておいてください。スタックトレースを表示します。 –

答えて

2

あなたのデリゲートの使用:C#の側で

// Include the calling convention (__stdcall) for the Callback 
typedef double (__stdcall * Callback)(double); 

// Just use "Callback" here, instead of repeating 
// the above function prototype 
extern "C" __declspec(dllexport) __stdcall double TestDelegate(Callback func) 
{ 
    return func(25.0); 
} 

// BTW: Can export also using .DEF file to avoid __stdcall name mangling 

を、あなたはこのような何かを試すことができますcdecl呼び出し規約。 C#では、あなたがそれゆえ、このようなデリゲート宣言します:別の方法として

[UnmanagedFunctionPointer(CallingConvention.Cdecl)] 
public delegate double CallbackDelegate(double x); 

を、あなたはUnmanagedFunctionPointer属性を削除し、デフォルトの呼び出しに依存していると思われる場合には、__stdcallとしてC++で関数ポインタを宣言することを決定することもできます大会はCallingConvention.StdCallです。

はこのようにそれを実装します(GCに対する保護)生きているアンマネージ関数ポインタを保つために

public static double MyFunc(double x) 
{ 
    return Math.Sqrt(x); 
} 

、あなたは変数に、デリゲートのインスタンスを保持する必要があります。あなたがここに持っている簡単な例では

private static CallbackDelegate delegateInstance; 
.... 
delegateInstance = MyFunc; 

、C++ TestDelegate外のアンマネージ関数ポインタを使用していませんが、より複雑な例では、あなたが、そうすることがあり、その場合には、あなたが管理されていない機能を維持しなければならないコードポインタは生きている。インポート

関数は次のように宣言されている:C#と呼ばれ​​るようにC++から関数ポインタを渡し[の

double retval = TestDelegate(delegateInstance); 
0

C++側では、呼び出し規約をコールバックに明示的に指定します。 __stdcall(あなたのコードであることを行っていない、と私はデフォルトは__cdeclだと思う):

public delegate double CallbackDelegate(double x); 

// PInvoke declaration for the native DLL exported function 
[DllImport("YourDLL.dll", CallingConvention = CallingConvention.StdCall)] 
public static extern double TestDelegate(CallbackDelegate func); 

private double MyFunctionCallback(double x) 
{ 
    // ... Implement your C# callback code ... 
} 

CallbackDelegate managedDelegate = new CallbackDelegate(MyFunctionCallback); 

// Call into the native DLL, passing the managed callback 
TestDelegate(managedDelegate); 
関連する問題