You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

调用带返回值的C#回调时触发Crash "at <unknown> <0xffffffff>"问题排查

带返回值的C#回调在Unity中调用崩溃问题

我用Go和C编写了原生库(C作为轻量封装层),并编写了C#互操作代码。目前可以成功将无返回值的C#方法注册为回调并从C中调用,但调用带返回值的回调时会触发崩溃。该库编译为Windows DLL,在Unity游戏中调用时生成的堆栈跟踪如下:

=================================================================
    Native Crash Reporting
=================================================================
Got a UNKNOWN while executing native code. This usually indicates
a fatal error in the mono runtime or one of the native libraries 
used by your application.
=================================================================

=================================================================
    Managed Stacktrace:
=================================================================
      at <unknown> <0xffffffff>
      at MyLib.Interop:TestCallGetIntCb <0x000cd>
      at MyLib.Test:TestCallGetIntCb <0x0007a>
      at Multiplayer:Update <0x000ea>
      at System.Object:runtime_invoke_void__this__ <0x00187>
=================================================================

注释掉C代码中的回调调用即可消除错误。

触发崩溃的代码

原生库

callback.h

typedef int (*GetIntCallback)();

void SubscribeGetIntCallback(GetIntCallback cb);
int GetInt();

callback.c

static GetIntCallback testGetIntCallback = 0;

void SubscribeGetIntCallback(GetIntCallback cb)
{
    testGetIntCallback = cb;
}

int GetInt()
{
    if (testGetIntCallback != 0)
    {
        return testGetIntCallback();
    }

    return 0;
}

C#代码

Interop.cs

public class Interop
{
    // 为简化已移除其他代码...

    public delegate int GetIntCallback();

    [DllImport("mylibrary")]
    public static extern void SubscribeGetIntCallback(GetIntCallback intCb);
}

Test.cs

public class Test
{
    // 为简化已移除其他代码...

    public Test()
    {
        Interop.SubscribeGetIntCallback(TestIntCb);
    }

    [MonoPInvokeCallback(typeof(Interop.GetIntCallback))]
    private int TestIntCb()
    {
        return 100;
    }
}

可正常运行的无返回值回调代码(对比用)

原生库

callback.h

typedef void (*StringCallback)(const char *message, int size);

void SubscribeLogInfo(StringCallback cb);
void LogInfo(const char *message);

callback.c

static StringCallback logInfoCallback = 0;

void SubscribeLogInfo(StringCallback cb)
{
    logInfoCallback = cb;
}

void LogInfo(const char *message)
{
    if (logInfoCallback != 0)
    {
        logInfoCallback(message, (int)strlen(message));
    }
}

C#代码

Interop.cs

public class Interop
{
    // 为简化已移除其他代码...

    public delegate void StringCallback(IntPtr ptr, int size);

    [DllImport("mylibrary")]
    public static extern void SubscribeLogInfo(StringCallback cb);
}

Events.cs

public static class Events
{
    // 为简化已移除其他代码...

    public delegate void MessageEventHandler(object sender, MessageEventArgs args);
    public static event MessageEventHandler LogInfoEvent;

    static Events()
    {
        Interop.SubscribeLogInfo(OnLogInfo);
    }

    [MonoPInvokeCallback(typeof(Interop.StringCallback))]
    private static void OnLogInfo(IntPtr messagePtr, int size)
    {
        string message = Marshal.PtrToStringAnsi(messagePtr, size);
        LogInfoEvent?.Invoke(typeof(Events), new MessageEventArgs(message));
    }
}

疑问点

  • 是否存在方法签名问题?
  • 是否因为Test类不是静态类?
  • 是否因为TestIntCb()方法不是静态方法?
  • 是否因为TestIntCb()的返回值位于托管内存,返回时未复制到非托管内存?
  • 是否存在类型兼容性问题?int是 blittable 类型,难道不需要转换直接复制吗?

内容的提问来源于stack exchange,提问作者Daniel Vernall

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 00:37:47