static bool ReadPluginsData(string pluginFile) { modEntryList = new Dictionary <string, List <ModEntry> >(); modPluginList = new Dictionary <string, PluginEntry>(); Assembly pluginAssembly; print("[i] read plugin file: '" + pluginFile.Replace(assemblyFolder, ".\\") + "' ..."); try { pluginAssembly = Assembly.LoadFrom(pluginFile); // var hooksAssembly = typeof(GM).Assembly; } catch (System.Exception ex) { print(" ERROR: Can't load assembly (" + ex.Message + ")!"); return(false); } foreach (Type type in pluginAssembly.GetTypes()) { string pluginTag = ""; var pluginTagAttributes = Attribute.GetCustomAttributes(type) .Where(e => e.GetType().FullName == "dotNetMT.PluginTagAttribute").ToArray(); if (pluginTagAttributes.Length > 0) { pluginTag = type.FullName; var pta = (PluginTagAttribute)pluginTagAttributes[0]; if (pta.pluginName != "") { var entry = new PluginEntry(); entry.pluginTag = pluginTag; entry.pluginName = pta.pluginName; entry.pluginAuthor = pta.pluginAuthor; entry.pluginNote = pta.pluginNote; entry.pluginRequired = pta.pluginRequired; entry.active = true; modPluginList[pluginTag] = entry; } } foreach (MethodInfo method in type.GetMethods()) { foreach (var pma in Attribute.GetCustomAttributes(method)) { ModEntry entry; if (pma.GetType().FullName == "dotNetMT.PluginHookAttribute") { var a = (PluginHookAttribute)pma; entry = new ModEntry(); entry.entryType = ModEntryType.Hook; entry.method = method.Name; entry.type = type.Name; entry.method_ = method; entry.type_ = type; entry.assembly = a.assemblyName; entry.type2hook = a.typeName; entry.method2hook = a.methodName; entry.hookOnBegin = a.hookOnBegin; entry.parameterCount = a.parameterCount; } else if (pma.GetType().FullName == "dotNetMT.PluginPatchAttribute") { var a = (PluginPatchAttribute)pma; entry = new ModEntry(); entry.entryType = ModEntryType.Patch; entry.method = method.Name; entry.type = type.Name; entry.method_ = method; entry.type_ = type; entry.assembly = a.assemblyName; } else { continue; } entry.pluginTag = pluginTag; if (!modEntryList.ContainsKey(entry.assembly)) { modEntryList.Add(entry.assembly, new List <ModEntry>()); } modEntryList[entry.assembly].Add(entry); } } } foreach (var k in modPluginList.Keys) { modPluginList[k].active = DNMT.Config.Get("plugins", k, true); } return(true); }
//------------------------------------------------------------------------------------------------------------- static void InjectHook(ModuleDefinition module, MethodDefinition method, ModEntry entry) { if (entry.entryType != ModEntryType.Hook) { return; } var hookTypeRef = module.ImportReference(entry.type_); var hookMethodRef = module.ImportReference(entry.method_); // object[] interceptedArgs; // object hookResult; var interceptedArgs = new VariableDefinition(method.Module.TypeSystem.Object.MakeArrayType()); method.Body.Variables.Add(interceptedArgs); var hookResult = new VariableDefinition(method.Module.TypeSystem.Object); method.Body.Variables.Add(hookResult); var numArgs = method.Parameters.Count; var hook = new List <Instruction>(); // interceptedArgs = new object[numArgs]; hook.Add(Instruction.Create(OpCodes.Ldc_I4, numArgs)); hook.Add(Instruction.Create(OpCodes.Newarr, method.Module.TypeSystem.Object)); hook.Add(Instruction.Create(OpCodes.Stloc, interceptedArgs)); // rmh = methodof(this).MethodHandle; // hook.Add(Instruction.Create(OpCodes.Ldtoken, method)); if (entry.hookOnBegin || method.ReturnType.FullName.EndsWith("Void")) { hook.Add(Instruction.Create(OpCodes.Ldnull)); } else { hook.Add(Instruction.Create(OpCodes.Dup)); if (method.ReturnType.IsByReference) { // if the arg is a reference type, it must be copied and boxed var refType = (ByReferenceType)method.ReturnType; hook.Add(Instruction.Create(OpCodes.Ldobj, refType.ElementType)); hook.Add(Instruction.Create(OpCodes.Box, refType.ElementType)); } else if (method.ReturnType.IsValueType) { // if the arg descends from ValueType, it must be boxed to be converted to an object: hook.Add(Instruction.Create(OpCodes.Box, method.ReturnType)); } } // thisObj = static ? null : this; if (!method.IsStatic) { hook.Add(Instruction.Create(OpCodes.Ldarg_0)); } else { hook.Add(Instruction.Create(OpCodes.Ldnull)); } var i = 0; foreach (var param in method.Parameters) { // interceptedArgs[i] = (object)arg; hook.Add(Instruction.Create(OpCodes.Ldloc, interceptedArgs)); hook.Add(Instruction.Create(OpCodes.Ldc_I4, i)); hook.Add(Instruction.Create(OpCodes.Ldarg, param)); if (param.ParameterType.IsByReference) { // if the arg is a reference type, it must be copied and boxed var refType = (ByReferenceType)param.ParameterType; hook.Add(Instruction.Create(OpCodes.Ldobj, refType.ElementType)); hook.Add(Instruction.Create(OpCodes.Box, refType.ElementType)); } else if (param.ParameterType.IsValueType) { // if the arg descends from ValueType, it must be boxed to be converted to an object: hook.Add(Instruction.Create(OpCodes.Box, param.ParameterType)); } hook.Add(Instruction.Create(OpCodes.Stelem_Ref)); i++; } // hookResult = HookRegistry.OnCall(rmh, thisObj, interceptedArgs); hook.Add(Instruction.Create(OpCodes.Ldloc, interceptedArgs)); hook.Add(Instruction.Create(OpCodes.Call, hookMethodRef)); hook.Add(Instruction.Create(OpCodes.Stloc, hookResult)); // if (hookResult != null) { // return (ReturnType)hookResult; // } hook.Add(Instruction.Create(OpCodes.Ldloc, hookResult)); hook.Add(Instruction.Create(OpCodes.Ldnull)); hook.Add(Instruction.Create(OpCodes.Ceq)); if (entry.hookOnBegin) { hook.Add(Instruction.Create(OpCodes.Brtrue_S, method.Body.Instructions.First())); } else { // do not replace last instruction, as result you can get branches bug (note - change is possible) method.Body.Instructions[method.Body.Instructions.Count - 1].OpCode = OpCodes.Nop; method.Body.Instructions[method.Body.Instructions.Count - 1].Operand = null; method.Body.Instructions.Add(Instruction.Create(OpCodes.Ret)); hook.Add(Instruction.Create(OpCodes.Brtrue_S, method.Body.Instructions.Last())); } if (!method.ReturnType.FullName.EndsWith("Void")) { if (!entry.hookOnBegin) { hook.Add(Instruction.Create(OpCodes.Pop)); } hook.Add(Instruction.Create(OpCodes.Ldloc, hookResult)); hook.Add(Instruction.Create(OpCodes.Castclass, method.ReturnType)); hook.Add(Instruction.Create(OpCodes.Unbox_Any, method.ReturnType)); } hook.Add(Instruction.Create(OpCodes.Ret)); hook.Reverse(); method.Body.SimplifyMacros(); int index = entry.hookOnBegin ? 0 : method.Body.Instructions.Count - 1; foreach (var instruction in hook) { method.Body.Instructions.Insert(index, instruction); } method.Body.OptimizeMacros(); }