Mono.Cecil无法解析System.Reflection.BindingFlags

时间:2018-06-14 17:22:46

标签: c# mono.cecil

这是一个围绕游戏服务器环绕Eco的项目。

只有在尝试在Eco.Core程序集上运行AssemblyDefinition.Write()时才会发生此异常。

我也找不到依赖版本,文件版本等方面的任何差异。 Eco.Core组件和其他组件之间。

使用Costura将所有游戏程序集压缩为资源到实际的启动器文件中。

其他信息:

  • .NET 4.6环境
  • 使用.NET 4.6
  • 构建有问题的程序集和另外40个已加载的程序集

项目链接:https://github.com/RocketMod/Rocket.Eco/tree/dev/Rocket.Eco.Launcher

Unhandled Exception: Mono.Cecil.ResolutionException: Failed to resolve 
System.Reflection.BindingFlags
   at Mono.Cecil.Mixin.CheckedResolve(TypeReference self)
   at Mono.Cecil.MetadataBuilder.GetConstantType(TypeReference constant_type, Object constant)
   at Mono.Cecil.MetadataBuilder.AddConstant(IConstantProvider owner, TypeReference type)
   at Mono.Cecil.MetadataBuilder.AddField(FieldDefinition field)
   at Mono.Cecil.MetadataBuilder.AddFields(TypeDefinition type)
   at Mono.Cecil.MetadataBuilder.AddType(TypeDefinition type)
   at Mono.Cecil.MetadataBuilder.AddTypes()
   at Mono.Cecil.MetadataBuilder.BuildTypes()
   at Mono.Cecil.MetadataBuilder.BuildModule()
   at Mono.Cecil.MetadataBuilder.BuildMetadata()
   at Mono.Cecil.ModuleWriter.<>c.<BuildMetadata>b__2_0(MetadataBuilder builder, MetadataReader _)
   at Mono.Cecil.ModuleDefinition.Read[TItem,TRet](TItem item, Func`3 read)
   at Mono.Cecil.ModuleWriter.Write(ModuleDefinition module, Disposable`1 stream, WriterParameters parameters)
   at Mono.Cecil.ModuleWriter.WriteModule(ModuleDefinition module, Disposable`1 stream, WriterParameters parameters)
   at Mono.Cecil.ModuleDefinition.Write(Stream stream, WriterParameters parameters)
   at Rocket.Eco.Launcher.Program.LoadAssemblyFromDefinition(AssemblyDefinition definition)
   at System.Collections.Generic.List`1.ForEach(Action`1 action)
   at Rocket.Eco.Launcher.Program.Main(String[] args)

以下是可能涉及的所有代码段:(是的,它对于StackOverflow问题很多,但您也可以使用顶部的项目链接通过GitHub查看它。)

//This is inside the implementation of IPatchingService.
public IEnumerable<AssemblyDefinition> Patch()
{
    lock (lockObj)
    {
        foreach (AssemblyDefinition asmDef in assemblies)
        {
            foreach (IAssemblyPatch patch in patches)
            {
                foreach (ModuleDefinition modDef in asmDef.Modules)
                {
                    TypeDefinition typeDef = modDef.Types.FirstOrDefault(x => x.FullName.Equals(patch.TargetType, StringComparison.InvariantCultureIgnoreCase));

                    if (typeDef == null)
                        continue;

                    patch.Patch(typeDef);

                    break;
                }
            }
        }

            //I hope this kills the Stream...
        assemblies.ForEach(x => x.Dispose());

        AssemblyDefinition[] asmArray = assemblies.ToArray();

        assemblies.Clear();
        patches.Clear();

        return asmArray;
    }
}

public sealed class CosturaAssemblyResolver : BaseAssemblyResolver
{
    public override AssemblyDefinition Resolve(AssemblyNameReference name)
    {
        string actName = name.Name;

        if (!CosturaHelper.Assemblies.TryGetValue(actName, out CosturaHelper.AssemblyData result))
            return null;

        if (result.Assembly != null)
            return result.Assembly;

        result.Stream.Position = 0;

        try
        {
            AssemblyDefinition defn = AssemblyDefinition.ReadAssembly(result.Stream, new ReaderParameters()
            {
                AssemblyResolver = this
            });

            result.Assembly = defn;

            return defn;
        }
        catch (ResolutionException e)
        {
            return null;
        }
    }
}

public static class CosturaHelper
{
    internal static Dictionary<string, AssemblyData> Assemblies = new Dictionary<string, AssemblyData>(StringComparer.InvariantCultureIgnoreCase);

    public static IEnumerable<AssemblyDefinition> ExtractCosturaAssemblies(AssemblyDefinition definition)
    {
        List<AssemblyDefinition> definitions = new List<AssemblyDefinition>();

        definition.MainModule.Resources.Where(x => x.ResourceType == ResourceType.Embedded).Cast<EmbeddedResource>().Where(x => x.Name.EndsWith(".compressed") && x.Name.StartsWith("costura")).ForEach(x =>
        {
            using (Stream stream = x.GetResourceStream())
            {
                using (DeflateStream deflateStream = new DeflateStream(stream, CompressionMode.Decompress))
                {
                    MemoryStream memStream = new MemoryStream();

                    byte[] array = new byte[81920];

                    int count;
                    while ((count = deflateStream.Read(array, 0, array.Length)) != 0)
                    {
                        memStream.Write(array, 0, count);
                    }

                    Assemblies[x.Name.Replace(".dll.compressed", "").Replace("costura.", "")] = new AssemblyData(memStream, null);
                }
            }
        });

        CosturaAssemblyResolver resolver = new CosturaAssemblyResolver();
        ReaderParameters parameters = new ReaderParameters()
        {
            AssemblyResolver = resolver
        };

        Assemblies.Keys.ForEach(x =>
        {
            AssemblyData asm = Assemblies[x];

            if (asm.Assembly != null)
            {
                definitions.Add(asm.Assembly);
            }
            else
            {
                asm.Stream.Position = 0;
                asm.Assembly = AssemblyDefinition.ReadAssembly(asm.Stream, parameters);

                definitions.Add(asm.Assembly);
            }
        });

        return definitions;
    }

    public static void DisposeStreams() => Assemblies.ForEach(x => x.Value.Stream.Dispose());

    //plz add data classes like in Kotlin
    public class AssemblyData
    {
        public AssemblyDefinition Assembly;
        public Stream Stream;

        public AssemblyData(Stream stream, AssemblyDefinition admdef)
        {
            Assembly = admdef;
            Stream = stream;
        }
    }
}

public static void Main(string[] args)
{
    IPatchingService patchingService = new PatchingService();

    FileStream stream = File.OpenRead("EcoServer.exe");

    AssemblyDefinition defn = AssemblyDefinition.ReadAssembly(stream);

    CosturaHelper.ExtractCosturaAssemblies(defn).ForEach(x => patchingService.RegisterAssembly(x));

    patchingService.RegisterPatch<UserPatch>();
    patchingService.RegisterPatch<ChatManagerPatch>();

    List<AssemblyDefinition> patches = patchingService.Patch().ToList();

    patches.ForEach(x => Console.WriteLine(x.Name.Name));

        //This fixes only ONE of the errors.
    AssemblyDefinition ecoShared = patches.First(x => x.Name.Name.Equals("Eco.Shared", StringComparison.InvariantCultureIgnoreCase));

    patches.Remove(ecoShared);

    LoadAssemblyFromDefinition(ecoShared);

    patches.ForEach(LoadAssemblyFromDefinition);

    CosturaHelper.DisposeStreams();

    patchingService.RegisterAssembly(defn);
    patchingService.RegisterPatch<StartupPatch>();

    patchingService.Patch().ForEach(LoadAssemblyFromDefinition);

    stream.Dispose();

#if DEBUG
    AppDomain.CurrentDomain.GetAssemblies().ForEach(x => Console.WriteLine(x.FullName));
#endif

    AppDomain.CurrentDomain.AssemblyResolve -= GatherRocketDependencies;

    AppDomain.CurrentDomain.GetAssemblies()
             .First(x => x.GetName().Name.Equals("EcoServer"))
             .GetType("Eco.Server.Startup")
             .GetMethod("Start", BindingFlags.Static | BindingFlags.Public)
             .Invoke(null, new object[]
                 {args.Where(x => !x.Equals("-extract", StringComparison.InvariantCultureIgnoreCase)).ToArray()});

    Console.WriteLine("Houston, we have control!");

    //Runtime.Bootstrap();
}

private static void LoadAssemblyFromDefinition(AssemblyDefinition definition)
{
    using (MemoryStream stream = new MemoryStream())
    {
        //definition.MainModule.ImportReference(typeof(BindingFlags)); //Failed attempt to resolve System.Reflection.BindingFlags that it keeps complaining about.
        definition.Write(stream);

        stream.Position = 0; //Is this needed?

        byte[] buffer = new byte[stream.Length];

        stream.Read(buffer, 0, buffer.Length);

        Assembly.Load(buffer);
    }
}

0 个答案:

没有答案