首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Mono.Cecil -更改私有属性

Mono.Cecil -更改私有属性
EN

Stack Overflow用户
提问于 2016-08-24 21:07:54
回答 1查看 1.3K关注 0票数 0

我有第三方动态链接库,我想在视觉上修改。我想更改表单上可用按钮的外观。使用dotPeek我找到了该按钮的名称,现在在form load事件处理程序中,我想使用以下几行代码来修改该按钮:

代码语言:javascript
复制
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加载和修改该程序集,如下所示:

代码语言:javascript
复制
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!")

我想将该方法从:

代码语言:javascript
复制
private void Main_Load(object sender, EventArgs e)
{
    SetupEverything();
}

至:

代码语言:javascript
复制
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的信息,所以我不知道如何获取属性(控件)和更改它们的属性(例如字体)。

EN

回答 1

Stack Overflow用户

发布于 2016-08-24 21:49:38

这应该是可行的

代码语言:javascript
复制
 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:

代码语言:javascript
复制
IL_0000: nop
IL_0001: ret

在此之后:

代码语言:javascript
复制
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: ret
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39124229

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档