从直接 c# 和 jslib 回调 c# 调用事件时调用不同的函数签名

Different function signature is called when invoking a event from direct c# and jslib callback c#

我正在做一个 Unity 项目,处理 WebGL 插件,它被 Unity 称为 "jslib"。

当jslib与c#交互时unity推荐使用UnitySendMessage,我更喜欢使用delegate作为回调。在一个小的测试代码中它起作用了。但是当它运行到触发事件代码时,出现奇怪的错误。

c#:

public class Test : MonoBehaviour {

    public void Start()
    {
        UserLoginDispatcher.GetInstance ().onLoginOver += onLoginOver;
    }

    public void OnDestroy()
    {
        UserLoginDispatcher.GetInstance ().onLoginOver -= onLoginOver;
    }

    //[MonoPInvokeCallback(typeof(System.Action<string, string, SDKError>))]
    public static void onLoginOver(string context, string pluginId, SDKError err)
    {
        string errmsg = err == null ? "" : err.errmsg;
        LogFormat ("Login Over with context " + context + ", pluginId " + pluginId + ", errmsg:" + errmsg);
    }

    static void LogFormat(string format, params object[] param)
    {
         string log = string.Format (format, param);
        Debug.Log (log);
    }
}

public class UserLoginDispatcher {
    private static UserLoginDispatcher s_Instance = new UserLoginDispatcher ();
    public static UserLoginDispatcher GetInstance()
    {
        return s_Instance;
    }

    public delegate void UserLoginCallback(string context, string pluginId, SDKError error);

    public event UserLoginCallback onLoginOver;

    public void ProcessLoginOver(string context, string pluginId, SDKError error)
    {
        onLoginOver (context, pluginId, error);
    }
}

public class WebGLPluginManager
{
    [DllImport("__Internal")]
    private static extern int Plugin_addLoginOverCB (LoginCBDelegate nativeCb);
    private delegate void LoginCBDelegate(string context, string pluginId, int errno, int channelerrno, string errmsg);

    [MonoPInvokeCallback(typeof(LoginCBDelegate))]
    private static void OnLoginOver(string context, string pluginId, int errno, int channelerrno, string errmsg)
    {
        SDK.GetInstance ().loginDispatcher.ProcessLoginOver (context, pluginId, new SDKError (errno, channelerrno, errmsg));
    }

    public void Init()
    {
        Plugin_addLoginOverCB(OnLoginOver);
    }
}

在 jslib 中:

...//login succeed:
Runtime.dynCall("viiiii", .....);

调用UserLoginDispatcher中的ProcessLoginOver时,test中的onLoginOver报错:

使用签名 'viiii' 调用的函数指针无效。也许这是一个无效值(例如,由在 NULL 指针上调用虚方法引起的)?或者调用类型不正确的函数会失败? (值得使用 -Werror 构建源文件(警告是错误),因为警告可以指示可能导致此问题的未定义行为)

但是如果我尝试在c#代码中直接调用这个事件,是可以成功触发的。

错误调用堆栈:

Uncaught abort(68) at Error
at jsStackTrace (blob:http://localhost:60912/134eecaa-92a2-4615-b5b2-0a2ab6d2ed73:23794:12)
at stackTrace (blob:http://localhost:60912/134eecaa-92a2-4615-b5b2-0a2ab6d2ed73:23808:11)
at abort (blob:http://localhost:60912/134eecaa-92a2-4615-b5b2-0a2ab6d2ed73:464638:43)
at nullFunc_viiii (blob:http://localhost:60912/134eecaa-92a2-4615-b5b2-0a2ab6d2ed73:50912:2)
at Array.b68 (blob:http://localhost:60912/134eecaa-92a2-4615-b5b2-0a2ab6d2ed73:455121:2)
at ftCall_viiii (eval at loadDynamicLibrary (blob:http://localhost:60912/134eecaa-92a2-4615-b5b2-0a2ab6d2ed73:23235:19), <anonymous>:6602:49)
at mftCall_viiii (eval at loadDynamicLibrary (blob:http://localhost:60912/134eecaa-92a2-4615-b5b2-0a2ab6d2ed73:23235:19), <anonymous>:732323:2)
at _UserLoginCallback_Invoke_m2599958513 (eval at loadDynamicLibrary (blob:http://localhost:60912/134eecaa-92a2-4615-b5b2-0a2ab6d2ed73:23235:19), <anonymous>:533179:4)
at _UserLoginCallback_Invoke_m2599958513 (eval at loadDynamicLibrary (blob:http://localhost:60912/134eecaa-92a2-4615-b5b2-0a2ab6d2ed73:23235:19), <anonymous>:533170:14)
at _UserLoginDispatcher_ProcessLoginOver_m2254139378 (eval at loadDynamicLibrary (blob:http://localhost:60912/134eecaa-92a2-4615-b5b2-0a2ab6d2ed73:23235:19), <anonymous>:562185:2)
at _WebGLPluginManager_OnLoginOver_m1528063286 (eval at loadDynamicLibrary (blob:http://localhost:60912/134eecaa-92a2-4615-b5b2-0a2ab6d2ed73:23235:19), <anonymous>:548824:2)
at Array.asm._WebGLPluginManager_OnLoginOver_m1528063286 (eval at loadDynamicLibrary (blob:http://localhost:60912/134eecaa-92a2-4615-b5b2-0a2ab6d2ed73:23235:19), <anonymous>:921460:59)
....

直接c#调用的栈

Login Over with context a test session 12:13:28, pluginId DefaultUserLogin, errmsg:
at __Z13GetStacktracei [GetStacktrace(int)] (blob:http://localhost:60912/6467252d-2f87-4a2c-9967-31868825bff3:2275897:2)
at __Z17DebugStringToFileRK21DebugStringToFileData [DebugStringToFile(DebugStringToFileData const&)] (blob:http://localhost:60912/6467252d-2f87-4a2c-9967-31868825bff3:1247009:5)
at __Z17DebugStringToFilePKciS0_i15LogMessageFlagsiiPFvRK11CppLogEntryE [DebugStringToFile(char const*, int, char const*, int, LogMessageFlags, int, int, void (*)(CppLogEntry const&))] (blob:http://localhost:60912/6467252d-2f87-4a2c-9967-31868825bff3:2562904:2)
at __Z35DebugLogHandler_CUSTOM_Internal_Log7LogTypeP12Il2CppStringP12Il2CppObject [DebugLogHandler_CUSTOM_Internal_Log(LogType, Il2CppString*, Il2CppObject*)] (blob:http://localhost:60912/6467252d-2f87-4a2c-9967-31868825bff3:2126846:2)
at Array.UnityLoader.d9fd6255ccad354c9cc5ad72abf13dcc.asm.__Z35DebugLogHandler_CUSTOM_Internal_Log7LogTypeP12Il2CppStringP12Il2CppObject [DebugLogHandler_CUSTOM_Internal_Log(LogType, Il2CppString*, Il2CppObject*)] (blob:http://localhost:60912/134eecaa-92a2-4615-b5b2-0a2ab6d2ed73:145057:93)
at ftCall_viii (eval at loadDynamicLibrary (blob:http://localhost:60912/134eecaa-92a2-4615-b5b2-0a2ab6d2ed73:23235:19), <anonymous>:7197:48)
at mftCall_viii (eval at loadDynamicLibrary (blob:http://localhost:60912/134eecaa-92a2-4615-b5b2-0a2ab6d2ed73:23235:19), <anonymous>:747533:2)
at _DebugLogHandler_Internal_Log_m1116757358 (eval at loadDynamicLibrary (blob:http://localhost:60912/134eecaa-92a2-4615-b5b2-0a2ab6d2ed73:23235:19), <anonymous>:719622:2)
at Array._DebugLogHandler_LogFormat_m2613962716 (eval at loadDynamicLibrary (blob:http://localhost:60912/134eecaa-92a2-4615-b5b2-0a2ab6d2ed73:23235:19), <anonymous>:620933:2)
at mftCall_viiiiii (eval at loadDynamicLibrary (blob:http://localhost:60912/134eecaa-92a2-4615-b5b2-0a2ab6d2ed73:23235:19), <anonymous>:708880:40)
at __ZN23InterfaceActionInvoker4IiP18Object_t3753624189P8String_tP24ObjectU5BU5D_t2405707486E6InvokeEjP11Il2CppClassP12Il2CppObjectiS1_S3_S5_ [InterfaceActionInvoker4<int, Object_t3753624189*, String_t*, ObjectU5BU5D_t2405707486*>::Invoke(unsigned int, Il2CppClass*, Il2CppObject*, int, Object_t3753624189*, String_t*, ObjectU5BU5D_t2405707486*)] (eval at loadDynamicLibrary (blob:http://localhost:60912/134eecaa-92a2-4615-b5b2-0a2ab6d2ed73:23235:19), <anonymous>:394923:2)
at Array._Logger_Log_m314997607 (eval at loadDynamicLibrary (blob:http://localhost:60912/134eecaa-92a2-4615-b5b2-0a2ab6d2ed73:23235:19), <anonymous>:564686:3)
at mftCall_viiii (eval at loadDynamicLibrary (blob:http://localhost:60912/134eecaa-92a2-4615-b5b2-0a2ab6d2ed73:23235:19), <anonymous>:732320:39)
at __ZN23InterfaceActionInvoker2IiP12Il2CppObjectE6InvokeEjP11Il2CppClassS1_iS1_ [InterfaceActionInvoker2<int, Il2CppObject*>::Invoke(unsigned int, Il2CppClass*, Il2CppObject*, int, Il2CppObject*)] (eval at loadDynamicLibrary (blob:http://localhost:60912/134eecaa-92a2-4615-b5b2-0a2ab6d2ed73:23235:19), <anonymous>:412747:2)
at _Debug_Log_m2324883804 (eval at loadDynamicLibrary (blob:http://localhost:60912/134eecaa-92a2-4615-b5b2-0a2ab6d2ed73:23235:19), <anonymous>:619913:2)
at _Test_LogFormat_m983122927 (eval at loadDynamicLibrary (blob:http://localhost:60912/134eecaa-92a2-4615-b5b2-0a2ab6d2ed73:23235:19), <anonymous>:579589:2)
at Array._Test_onLoginOver_m2512123873 (eval at loadDynamicLibrary (blob:http://localhost:60912/134eecaa-92a2-4615-b5b2-0a2ab6d2ed73:23235:19), <anonymous>:383768:2)
at mftCall_viiiii (eval at loadDynamicLibrary (blob:http://localhost:60912/134eecaa-92a2-4615-b5b2-0a2ab6d2ed73:23235:19), <anonymous>:720078:40)
at _UserLoginCallback_Invoke_m2599958513 (eval at loadDynamicLibrary (blob:http://localhost:60912/134eecaa-92a2-4615-b5b2-0a2ab6d2ed73:23235:19), <anonymous>:533182:4)
at _UserLoginDispatcher_ProcessLoginOver_m2254139378 (eval at loadDynamicLibrary (blob:http://localhost:60912/134eecaa-92a2-4615-b5b2-0a2ab6d2ed73:23235:19), <anonymous>:562185:2)
....

我注意到在直接c#调用中,dynCall使用mftCall_viiiii,而在jslib调用中,dynCall使用mftCall_viiii,可能这就是函数调用失败的原因。奇怪,为什么会这样?

自己修好了!

其实这是我的一个小错误:我只是忘记了初始化loginDispatcher,所以进入loginDispatcher时这个ptr是0,然后行为很混乱。

当"this"为0时代码没有抛出任何异常,因为它是从c代码翻译过来的。它继续 运行,直到事件调用函数,最后函数 table 没有这个函数并抱怨,所以我看到了非常混乱的错误报告!

ps: asm.js 中的c# delegate 作用如下: 如果这个ptr 为0,则委托被视为静态函数,如果此ptr 不为0,则委托被视为一个成员函数。这就是为什么当这个 ptr 为 0 时,会调用 mftCall_viiii 而不是 mftCall_viiiii