はじめに
Unityに依存しているManaged DLLを外部の.NETプロジェクトで動かそうとしたときに、以下のようなエラーが出ることがあります。
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.Security.SecurityException: ECall methods must be packaged into a system module. at UnityEngine.DebugLogHandler.Internal_Log(LogType level, LogOption options, String msg, Object obj) at UnityEngine.DebugLogHandler.LogFormat(LogType logType, Object context, String format, Object[] args) at UnityEngine.Logger.Log(LogType logType, Object message) at UnityEngine.Debug.Log(Object message) ...このエラーは、Unityのネイティブコードと連携する関数(例えばUnityEngine.Debug.Logなど)を、Unityのランタイム環境外で呼び出そうとした場合に発生します。
UnityのLog関数などはUnityのネイティブコードと連携して動作するため、Unityのランタイム環境外でこれらの関数を呼び出すと、System.Security.SecurityExceptionがスローされます。
対処法
一般的な対処法としては、Harmonyなどのライブラリを使用して、UnityのLog関数を無効化するパッチを当てる方法があります。
static void PatchUnityDebug(Harmony harmony){ // Get UnityEngine.Debug type var debugType = Type.GetType("UnityEngine.Debug, UnityEngine.CoreModule") ?? Type.GetType("UnityEngine.Debug, UnityEngine") ?? AppDomain.CurrentDomain .GetAssemblies() .Select(a => a.GetType("UnityEngine.Debug")) .FirstOrDefault(t => t != null);
if (debugType == null) throw new Exception("UnityEngine.Debug not found!");
// Patch all methods starting with Log var methods = debugType.GetMethods(BindingFlags.Public | BindingFlags.Static) .Where(m => m.Name.StartsWith("Log", StringComparison.Ordinal));
var prefix = new HarmonyMethod(typeof(Program).GetMethod(nameof(Prefix), BindingFlags.Static | BindingFlags.Public));
foreach (var m in methods) { harmony.Patch(m, prefix: prefix); }}
public static bool Prefix(MethodBase __originalMethod, object[] __args){ try { var args = (__args == null || __args.Length == 0) ? "" : string.Join(", ", __args.Select(a => a is Array ar ? $"[{string.Join(", ", ar.Cast<object>())}]" : a?.ToString())); Console.WriteLine($"[Unity LOG] {__originalMethod.Name}({args})"); } catch {}
return false; // Skip original method}