我有第三方动态链接库,我想在视觉上修改。我想更改表单上可用按钮的外观。使用dotPeek我找到了该按钮的名称,现在在form load事件处理程序中,我想使用以下几行代码来修改该按钮:
this.cancelBtn.Enabled = true;
this.cancelBtn.ForeColor = Color.Red;
this.cancelBtn.Font = new Font(this.cancelBtn.Font.FontFamily, this.cancelBtn.Font.Size, FontStyle.Bold, GraphicsUnit.Pixel);我可以使用Mono.Cecil加载和修改该程序集,如下所示:
var assembly = AssemblyDefinition.ReadAssembly(source);
var module = assembly.MainModule;
var name = assembly.Name;
TypeDefinition type = assembly.MainModule.Types.First(t => t.FullName == "SimpleEditor.MainDialog");
MethodDefinition method = type.Methods.First(m => m.Name == "Main_Load");
ILProcessor procesor = method.Body.GetILProcessor();
var firstInstruction = procesor.Body.Instructions.First();
MethodInfo writeLineMethod = typeof (Debug).GetMethod("WriteLine", new Type[] {typeof (string)});
var writeLine = assembly.MainModule.Import(writeLineMethod);
var callWriteLine = procesor.Create(Mono.Cecil.Cil.OpCodes.Call, writeLine);
const string sentence = @"MONO.CECIL rocks!";
var insertSentence = procesor.Create(Mono.Cecil.Cil.OpCodes.Ldstr, sentence);
procesor.InsertBefore(firstInstruction, insertSentence);
procesor.InsertAfter(insertSentence, callWriteLine);
assembly.Write(source);但是我现在所能做的就是在Main_Load方法的开头添加Debug.WriteLine("MONO.CECIL rocks!")。
我想将该方法从:
private void Main_Load(object sender, EventArgs e)
{
SetupEverything();
}至:
private void Main_Load(object sender, EventArgs e)
{
this.cancelBtn.Enabled = true;
this.cancelBtn.ForeColor = Color.Red;
this.cancelBtn.Font = new Font(this.cancelBtn.Font.FontFamily, this.cancelBtn.Font.Size, FontStyle.Bold, GraphicsUnit.Pixel);
SetupEverything();
}我怎样才能用Mono.Cecil做到这一点?我找不到很多关于Mono.Cecil online的信息,所以我不知道如何获取属性(控件)和更改它们的属性(例如字体)。
发布于 2016-08-24 21:49:38
这应该是可行的
static void ChangeButtonProperties()
{
// Load the assembly and the main module
string assemblyPath = $"{Environment.CurrentDirectory}\\ClassLibrary1.dll";
var mainModule = AssemblyDefinition.ReadAssembly(assemblyPath).MainModule;
// Get the method to change
TypeDefinition type = mainModule.Types.First(t => t.Name == "Test");
MethodDefinition method = type.Methods.Single(m => m.Name == "Main_Load");
// Get the instance field of the button
FieldDefinition btnField = type.Fields.Single(f => f.Name == "_btn");
var controlType = mainModule.Import(typeof(Control));
// Import relevant types
var colorType = mainModule.Import(typeof(Color));
var fontType = mainModule.Import(typeof(Font));
var fonFamilyType = mainModule.Import(typeof(FontFamily));
// Get the setters of the requested properties
MethodDefinition setEnabled = controlType.Resolve().Methods.Single(m => m.Name == "set_Enabled");
MethodReference setEnabledRef = mainModule.Import(setEnabled);
MethodDefinition setForeColor = controlType.Resolve().Methods.Single(m => m.Name == "set_ForeColor");
MethodReference setForeColorRef = mainModule.Import(setForeColor);
MethodDefinition setFont = controlType.Resolve().Methods.Single(m => m.Name == "set_Font");
MethodReference setFontRef = mainModule.Import(setFont);
// Get the Font constructor. Maybe you can think of a better way
MethodDefinition fontCtor =
fontType.Resolve().Methods.Single(
m => m.IsConstructor &&
m.Parameters.Count == 4 &&
m.Parameters[0].ParameterType.Name == "FontFamily");
MethodReference fontCtorRef = mainModule.Import(fontCtor);
// Get the getters of the requested properties
var getRedColor = colorType.Resolve().Methods.Single(m => m.Name == "get_Red");
MethodReference getRedColorRef = mainModule.Import(getRedColor);
var getFont = controlType.Resolve().Methods.Single(m => m.Name == "get_Font");
MethodReference getFontRef = mainModule.Import(getFont);
var getFontSize = fontType.Resolve().Methods.Single(m => m.Name == "get_Size");
MethodReference getFontSizeRef = mainModule.Import(getFontSize);
var getFontFamily = fontType.Resolve().Methods.Single(m => m.Name == "get_FontFamily");
MethodReference getFontFamilyRef = mainModule.Import(getFontFamily);
// I clear just for the example.
// You can keep the instructions and enter the new one before\after
method.Body.Instructions.Clear();
ILProcessor processor = method.Body.GetILProcessor();
LoadInstanceField(processor, btnField);
// Set Enabled to true
processor.Emit(OpCodes.Ldc_I4_1);
processor.Emit(OpCodes.Callvirt, setEnabledRef);
LoadInstanceField(processor, btnField);
// Set color to red
processor.Emit(OpCodes.Call, getRedColorRef); // no need callvirt here because is static
processor.Emit(OpCodes.Callvirt, setForeColorRef);
LoadInstanceField(processor, btnField);
LoadInstanceField(processor, btnField);
// Get all parameters to create new Font object
processor.Emit(OpCodes.Callvirt, getFontRef);
processor.Emit(OpCodes.Callvirt, getFontFamilyRef);
LoadInstanceField(processor, btnField);
processor.Emit(OpCodes.Callvirt, getFontRef);
processor.Emit(OpCodes.Callvirt, getFontSizeRef);
processor.Emit(OpCodes.Ldc_I4_1); // Load 1. It's the enum value of FontStyle.Bold
processor.Emit(OpCodes.Ldc_I4_2); // Load 2. It's the enum value of GraphicsUnit.Pixel
// Call Font constructor
processor.Emit(OpCodes.Newobj, fontCtorRef);
// Set the font
processor.Emit(OpCodes.Callvirt, setFontRef);
processor.Emit(OpCodes.Ret); // Return from the method
method.Body.OptimizeMacros();
mainModule.Write(assemblyPath + ".new.dll"); // Save the new dll
}
static void LoadInstanceField(ILProcessor processor, FieldDefinition field)
{
processor.Emit(OpCodes.Ldarg_0); // Load this
processor.Emit(OpCodes.Ldfld, field); // Load button field
}Main_Load之前的IL:
IL_0000: nop
IL_0001: ret在此之后:
IL_0000: ldarg.0
IL_0001: ldfld class [System.Windows.Forms]System.Windows.Forms.Button ClassLibrary1.Test::_btn
IL_0006: ldc.i4.1
IL_0007: callvirt instance void [System.Windows.Forms]System.Windows.Forms.Control::set_Enabled(bool)
IL_000c: ldarg.0
IL_000d: ldfld class [System.Windows.Forms]System.Windows.Forms.Button ClassLibrary1.Test::_btn
IL_0012: call valuetype [System.Drawing]System.Drawing.Color [System.Drawing]System.Drawing.Color::get_Red()
IL_0017: callvirt instance void [System.Windows.Forms]System.Windows.Forms.Control::set_ForeColor(valuetype [System.Drawing]System.Drawing.Color)
IL_001c: ldarg.0
IL_001d: ldfld class [System.Windows.Forms]System.Windows.Forms.Button ClassLibrary1.Test::_btn
IL_0022: ldarg.0
IL_0023: ldfld class [System.Windows.Forms]System.Windows.Forms.Button ClassLibrary1.Test::_btn
IL_0028: callvirt instance class [System.Drawing]System.Drawing.Font [System.Windows.Forms]System.Windows.Forms.Control::get_Font()
IL_002d: callvirt instance class [System.Drawing]System.Drawing.FontFamily [System.Drawing]System.Drawing.Font::get_FontFamily()
IL_0032: ldarg.0
IL_0033: ldfld class [System.Windows.Forms]System.Windows.Forms.Button ClassLibrary1.Test::_btn
IL_0038: callvirt instance class [System.Drawing]System.Drawing.Font [System.Windows.Forms]System.Windows.Forms.Control::get_Font()
IL_003d: callvirt instance float32 [System.Drawing]System.Drawing.Font::get_Size()
IL_0042: ldc.i4.1
IL_0043: ldc.i4.2
IL_0044: newobj instance void [System.Drawing]System.Drawing.Font::.ctor(class [System.Drawing]System.Drawing.FontFamily, float32, valuetype [System.Drawing]System.Drawing.FontStyle, valuetype [System.Drawing]System.Drawing.GraphicsUnit)
IL_0049: callvirt instance void [System.Windows.Forms]System.Windows.Forms.Control::set_Font(class [System.Drawing]System.Drawing.Font)
IL_004e: rethttps://stackoverflow.com/questions/39124229
复制相似问题