プログラムの事とか

お約束ですが「掲載内容は私個人の見解です」

.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...みたいなやつが出て落ちます。GCDelegateを消しているみたいですね

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);
}

まとめ

これは知らなきゃ気づかないよー、ゆるしてくださいよ~~