かなり大きな C API 用の .NET (c#) ラッパーがあります。このラッパーでは、ユーザーはネイティブ コードから繰り返し呼び出されるコールバックを提供できます。
コールバックは次のようになります。
[UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
public delegate void LogCallBack(SlmStream str, string wtsr, IntPtr handle);
ユーザーは次の方法でコールバックを入力できます。
public void SetLoggingCallback(LogCallBack lcallback,
IntPtr handle)
{
SlmReturn ret = (SlmReturn)Native.SlmSetLoggingCallbackW(ModelPtr,
lcallback,
handle);
if( ret != SlmReturn.SlmRetOk )
{
throw new SlmException(ret,ret.ToString());
}
}
最終的に呼び出している:
[DllImport("sulum20.dll",CallingConvention = CallingConvention.StdCall , CharSet = CharSet.Unicode)]
public static extern int SlmSetLoggingCallbackW(IntPtr ModelPtr,
LogCallBack lcallback,
IntPtr handle);
あるユーザーは、次の方法でコールバック ルーチンを呼び出しました (簡略化)。
string temp;
SetLoggingCallback((str, wtsr, handle) => { temp = wtsr; Console.WriteLine(temp); }, IntPtr.Zero);
これにより、一部のプラットフォームではアプリケーションがクラッシュし、他のプラットフォームではクラッシュしません。
だから私の質問は残っています、これは有効ですか?
C/C++ の世界から来て、1 つのことが私を困惑させます。
コールバックの範囲外で作成されたクラスのインスタンスにアクセスするコードは有効ですか (つまり、「string temp」)? 私の推測では、マーシャリングを制御できるようにするには、マーシャリングがそれらを入力/出力パラメーターとして持つ必要があるということです。handle パラメーターを使用して自分でマーシャリングを試みることを検討しましたが、やり過ぎかどうかはわかりません。
更新 1:
多分これは私がGCHandleを必要とするものですか?
更新 2:
コールバックは、ネイティブ コード ala から呼び出されます。
if( logcallback_ != NULL )
{
(logcallback_)(cstream_,chbuf_,logcallbackhandle_);
}
更新 3:
と
string temp;
LogCallBack logCallback = (str, wtsr, handle) =>
{
temp = "Hello";
};
smodel.SetLoggingCallback(logCallback, IntPtr.Zero);
同じクラッシュが発生します。
更新 4:
typedef void (ISLMCALL *SlmLogCallBackW)(enum SlmStream,const wchar_t*, void *handle);
更新 5
また、試行して失敗しました:
var logCallback = new LogCallBack(TargetMethod);
smodel.SetLoggingCallback(logCallback, IntPtr.Zero);
private string _test;
private void TargetMethod(SlmStream str, IntPtr wtsr, IntPtr handle)
{
_test = "Hello";
}
解決 :
GCHandler を使用してデリゲートを存続させ、ガベージ コレクションが行われないようにします。