.NET側からP/Invokeで関数ポインターを渡したら落ちた話
不定期更新のやらかし投稿です。7Pay報道みて笑っている場合じゃなかった
やりたいこと
C#側(今回は.Net Core)からVC++のdllに関数ポインターを渡してdll側から呼んでもらう
実装
P/Invokeの具体的なのはググってください
ということでC#
class TestClass { [UnmanagedFunctionPointer(CallingConvention.Cdecl)] delegate void TestFunctionDelegate(); [DllImport("test.dll", EntryPoint = "SetFunction", CallingConvention = CallingConvention.Cdecl)] static extern void SetFunction(TestFunctionDelegate function); public TestClass() { SetFunction(this.A); } private void A() { } }
SetFunction
って関数でTestClass.A()
のポインターを渡しているつもりです
何の問題もないと思うんですよねー、見た目ねー。これでしばらくしてからdll側から渡された関数ポインターを実行すると・・・
A callback was made on a garbage collected delegate...
みたいなやつが出て落ちます。GCがDelegateを消しているみたいですね
dnSpyで見てみる
ビルドしたアセンブリをdnSpyに突っ込んで上のコンストラクタ部分を見てみます
public TestClass() { TestClass.SetFunction(new TestClass.TestFunctionDelegate(this.A)); }
そりゃGCで消されますよねー、ですよねー。Delegateわたしが楽ちんちんに書けるもSyntax sugarの一つだったのか
ということで修正
コンストラクタのあたりだけ
private TestFunctionDelegate _testFunctionDelegate; public TestClass() { _testFunctionDelegate = this.A; SetFunction(_testFunctionDelegate); }
まとめ
これは知らなきゃ気づかないよー、ゆるしてくださいよ~~