该示例将在上例的基础上给UnityEditor.dll中的ConsoleWindow添加双击委托
Unity的Console窗口是查看日志的窗口,我们希望在Console窗口中双击某条日志时获得通知,该窗口对应的实现代码在UnityEditor.dll中的ConsoleWindow类
使用ILSpy反编译UnityEditor.dll中的ConsoleWindow类,可以看到其双击判断在OnGUI函数中,并在双击时调用了LogEntries.RowGotDoubleClicked函数。
我们可以使用Mono.Cecil给ConsoleWindow类添加一个静态委托
public static Action<int> onDoubleClick;
添加一个委托执行函数
void OnDoubleClick(int row)
{
if (ConsoleWindow.onDoubleClick != null)
{
ConsoleWindow.onDoubleClick(row);
}
}
并在OnGUI函数中调用LogEntries.RowGotDoubleClicked函数的后面调用OnDoubleClick函数
实现步骤
读取UnityEditor.dll程序集
在上例解决保存报错的基础上封装一个读取程序集的函数
public static AssemblyDefinition GetAssemblyDefination(string assemblyPath)
{
AssemblyDefinition ad = AssemblyDefinition.ReadAssembly(assemblyPath);
DefaultAssemblyResolver dar = ad.MainModule.AssemblyResolver as DefaultAssemblyResolver;
if (dar != null)
{
dar.AddSearchDirectory(Path.GetDirectoryName(assemblyPath));
}
return ad;
}
则读取UnityEditor.dll程序集的代码如下
string unityEditorPath = typeof(AssetDatabase).Module.FullyQualifiedName;
AssemblyDefinition ad = GetAssemblyDefination(unityEditorPath);
查找ConsoleWindow类
var type = ad.MainModule.Types.First(t => t.Name == "ConsoleWindow");
给ConsoleWindow类添加一个类型为Action<int>的静态公有委托onDoubleClick
var action = new FieldDefinition("onDoubleClick", Mono.Cecil.FieldAttributes.Public | Mono.Cecil.FieldAttributes.Static, ad.MainModule.Import(typeof(Action<int>)));
type.Fields.Add(action);
给ConsoleWindow类添加一个无返回值一个int类型形参row的函数OnDoubleClick
var method = new MethodDefinition("OnDoubleClick", Mono.Cecil.MethodAttributes.Public, ad.MainModule.TypeSystem.Void);
method.Parameters.Add(new ParameterDefinition("row", Mono.Cecil.ParameterAttributes.None, ad.MainModule.TypeSystem.Int32));
type.Methods.Add(method);
- 给OnDoubleClick函数添加函数体
var ilProcessor = method.Body.GetILProcessor();
var il1 = ilProcessor.Create(OpCodes.Ldsfld, action);
var il2 = ilProcessor.Create(OpCodes.Callvirt, ad.MainModule.Import(typeof(Action<int>).GetMethod("Invoke", BindingFlags.Instance | BindingFlags.Public)));
method.Body.Instructions.Add(il1);
method.Body.Instructions.Add(il1);
method.Body.Instructions.Add(ilProcessor.Create(OpCodes.Ldarg_1));
method.Body.Instructions.Add(il2);
method.Body.Instructions.Add(ilProcessor.Create(OpCodes.Ret));
ilProcessor.InsertAfter(method.Body.Instructions[1], ilProcessor.Create(OpCodes.Brfalse, method.Body.Instructions.Last()));
- 在OnGUI函数中调用LogEntries.RowGotDoubleClicked函数的后面添加对OnDoubleClick函数的调用
var ongui = type.Methods.First(m => m.Name == "OnGUI");
var onguiProcess = ongui.Body.GetILProcessor();
for (int i = 0; i < ongui.Body.Instructions.Count; i++)
{
if (ongui.Body.Instructions[i].ToString().Contains("RowGotDoubleClicked"))
{
onguiProcess.InsertAfter(ongui.Body.Instructions[i], onguiProcess.Create(OpCodes.Call, method));
onguiProcess.InsertAfter(ongui.Body.Instructions[i], ongui.Body.Instructions[i - 1]);
onguiProcess.InsertAfter(ongui.Body.Instructions[i], ongui.Body.Instructions[i - 2]);
onguiProcess.InsertAfter(ongui.Body.Instructions[i], ongui.Body.Instructions[i - 3]);
onguiProcess.InsertAfter(ongui.Body.Instructions[i], ongui.Body.Instructions[i - 3]);
i += 5;
}
}
- 保存修改后的程序集
ad.Write(Application.dataPath + "/../UnityEditor.dll");
其中第5,第6步骤中对IL代码的操作需要对C#编译为对应的IL代码非常熟悉,否则插错一条IL代码可能使整个程序集无法编译通过甚至使整个程序崩溃。但是如何保证5,6步骤中插入的IL代码的正确性呢
一般IL代码都是由.Net系的编程语言编译生成的,只要编译通过,IL代码一般不会发生错误,所以要保证对IL代码操作的正确性,也需要借助到编译器的编译
上述第5,第6步骤对IL代码的操作可以通过下面的步骤保证其正确性
保存反编译出来的ConsoleWindow类
将保存的类导进Unity中,修改使其可以通过编译
为修改后的类添加委托。委托执行函数,修改OnGUI函数等等
在工程目录\Library\ScriptAssemblies\下找到Assembly-CSharp-Editor.dll文件,在ILSpy中打开,反编译其中修改过的ConsoleWindow类为IL代码
反编译UnityEditor.dll中的ConsoleWindow类为IL代码,和第4步骤中的IL代码对比,就可以在关键部位逐条插入多出来的IL代码,或者直接替换对应的IL代码
如果在ILSpy中可以成功反编译修改后的程序集为C#代码,说明对IL代码的修改操作成功了
与上个示例一样,关掉Unity和vs,用修改后的UnityEditor替换工程目录\Library\UnityAssemblies\UnityEditor.dll和Unity安装目录\Editor\Data\Managed\UnityEditor.dll
再打开工程就会发现可以在代码中注册ConsoleWindow. onDoubleClick委托了
使用示例
public class ConsoleActionTest
{
[InitializeOnLoadMethod]
static void Init()
{
ConsoleWindow.onDoubleClick -= OnConsoleDoubleClick;
ConsoleWindow.onDoubleClick += OnConsoleDoubleClick;
}
static void OnConsoleDoubleClick(int row)
{
LogEntry log = new LogEntry();
LogEntries.GetEntryInternal(row, log);
Debug.Log(log.file);
Debug.Log(log.line);
}
}
Mono.Cecil使用示例之给UnityEditor.dll中的ConsoleWindow添加双击委托相关推荐
- Mono.Cecil使用示例之使指定程序集成为UnityEditor.dll的友元程序集
Mono.Cecil使用示例之使指定程序集成为UnityEditor.dll的友元程序集 Mono.Cecil是一个开源的库,使用Mono.Cecil可以非常方便的在代码中修改C#程序集.在Unity ...
- 使用Mono.Cecil辅助ASP.NET MVC使用dynamic类型Model
使用Mono.Cecil辅助ASP.NET MVC使用dynamic类型Model 2011-09-06 00:21 by 老赵, 8645 visits 这也是之前在珠三角技术沙龙上的示例之一,解决 ...
- 利用Mono.Cecil动态修改程序集来破解商业组件(仅用于研究学习)
原文:利用Mono.Cecil动态修改程序集来破解商业组件(仅用于研究学习) Mono.Cecil是一个强大的MSIL的注入工具,利用它可以实现动态创建程序集,也可以实现拦截器横向切入动态方法,甚至还 ...
- 巧用Mono.Cecil反射加载类型和方法信息
最近在做服务的细粒度治理,统一管理所有服务的方法.参数.返回值信息.方便后续的各个模块之间的对接和协作. 目前系统中所有的服务,管理到接口契约粒度,即服务接口声明和服务接口实现.要做服务的细粒度治理: ...
- 运用Mono.Cecil 反射读取.NET程序集元数据
CLR自带的反射机智和API可以很轻松的读取.NET程序集信息,但是不能对程序集进行修改.CLR提供的是只读的API,但是开源项目Mono.Cecil不仅仅可以读取.NET程序集的元数据,还可以进行修 ...
- 编译时MSIL注入--实践Mono Cecil(1)
紧接上两篇浅谈.NET编译时注入(C#-->IL)和浅谈VS编译自定义编译任务-MSBuild Task(csproject),在第一篇中我们简单研究了c#语法糖和PostSharp的MSIl注 ...
- Unity 修改UnityEditor.DLL
1:起因 大部分情况下是不需要修改unity的dll的,因为实力不允许,不bb了,我的unity版本2017.4.25 unity 2017推出spriteAtlas 新的图集方式,但是每次创建了新的 ...
- C#调用dll中的函数
C#调用dll中的函数 文章分类:操作系统 文章来源:http://blog.csdn.net/strmagic/archive/2007/11/02/1863462.aspx 大家在实际工作学习C# ...
- 天马行空W:在C++中调用DLL中的函数
1.dll的优点 代码复用是提高软件开发效率的重要途径.一般而言,只要某部分代码具有通用性,就可将它构造成相对独立的功能模块并在之后的项目中重复使用.比较常见的例子是各种应用程序框架,ATL.MFC等 ...
- 10.4.4 使用ctypes调用kernel32.dll中的函数
10.4.4 使用ctypes调用kernel32.dll中的函数 2007-10-17 14:41 孙广磊 人民邮电出版社 字号:T | T 综合评级: 想读(5) 在读(0) 已读(6) ...
最新文章
- 求逆元 - HNU 13412 Cookie Counter
- 10 年前被删的初恋,凌晨 1 点突然加我…
- 计算机右键功能总结,计算机基础知识:右键快捷菜单功能介绍
- C# 代码注释规范文档
- 不要轻信!那些说月过一万的图片!
- 十四、矩阵的快速转置算法
- MySQL之查询性能优化(四)
- 06.十分钟学会表达式语言EL
- LeetCode 239. Sliding Window Maximum
- docker 报错 Container is not running
- [导入]设计模式初学者系列-工厂方法
- python数字转字符串_python如何将字符转换为数字
- qt 在label上以光标位置进行缩放_缩放|位移|渐变简单动画
- 复合文档(Compound Document)读写栗子
- Linux工作笔记026---Centos7.3 yum提示Another app is currently holding the yum lock; waiting for it to exit.
- 配置quick-cocos2d-x-develop OpenGL version too old
- Python 导入通讯录:将.csv文件转换为.vcf文件
- 数据仓库ETL工具箱——简介
- matlab投资组合权重,Matlab做投资组合最优化
- 文娱干货丨如何体系化构建优质社区氛围?
热门文章
- tds3014 自动测试软件,TDS3014 Tektronix TDS3014C
- php手机验证码开发,php网站、手机验证码开发(手机注册验证)
- 微信H5页保存当前页面为图片踩坑
- 阅读 SICP 感想(0. 关于前言和序言)
- 如何配置我们的家用路由器
- 傅里叶分析之掐死教程(完整版)(转)
- java如何使用barcode4j生成条形码_JAVA条形码生成组件barcode4j使用
- kafka自动提交offset的设置理解
- Guawa的Splitter的工具类
- 路由器配置出现192.168.1.0 overlaps with Vlan2的解决方案