自从开始使用DotNet做网站以来便顺手开发一个自己的技术论坛,倒没有别的目的,只是想检验一下自己对DotNet的掌握程度。整个论坛的帖子作为叶片绑定在Web树控件上,树控件使用的是微软的Microsoft.Web.UI.WebControls组件中的TreeView,由于Microsoft.Web.UI.WebControls的资源是指向IIS主目录的,当服务商未装载Microsoft.Web.UI.WebControls组件时,这棵树便成了一堆干柴,无奈之下,便下载了Microsoft.Web.UI.WebControls的源码啃了一阵,将资源指向了站点的虚拟目录,编译成自己的版本。论坛终于在局域网中建起来了,我给他起名就叫 “好大一棵树论坛”。朋友给我找了个免费空间让我测试,我便用那只56K的老猫灌起水来,运行当然是正常,但速度实在是不理想,闪烁问题虽然可以通过关闭回传来避免,但这是以牺牲论坛的实时性和其他重要功能为代价的。改用宽带再试,效果果然好了许多,但我的论坛便也就被同事戏称为“好大一棵树论坛 DotNet宽带版”了。由于一时找不到轻巧好用的Web树控件,这棵大树也就一直锁在深闺。
前几日在CSDN看到大家在对微软的TreeView大贬一通的同时,极力推崇r.a.d.treeview ,这便又一次勾起了我对那个论坛改换“树种”的想法。到r.a.d.treeview的老家http://www.telerik.com 上看了一下,果然响应速度和视觉效果都十分可心,便顺手下载了一个最新的2.5版。装入本机后,其演示画面如下:
由于是30天的免费试用版,我把计算机的日期向后调整了一年,结果随机的出现了如下过期提示。
由于两天前刚探究过DotNetTextBox1.3的授权方式(也顺便写了一篇破解手记,可惜这里不便发表),便直接用Reflector打开了RadTreeView.DLL,并直奔控件重载的渲染方法Render()。
反汇编得出如下代码:
VB代码
对应的IL汇编代码
Protected Overrides Sub Render(ByVal output As HtmlTextWriter)
Me.licenseMessage = String.Empty
If (Not Me.licenseMessage Is String.Empty) Then
output.Write(Me.licenseMessage)
Else
Me.Page.VerifyRenderingInServerForm(Me)
Dim text1 As String = String.Format("", Me.UniqueID, "trigger")
Dim objArray1 As Object() = New Object() { String.Concat(Me.UniqueID, "_expanded"), String.Concat(Me.UniqueID, "_expanded"), Me.UniqueID, "trigger" }
Dim text2 As String = String.Format("", objArray1)
objArray1 = New Object() { String.Concat(Me.UniqueID, "_checked"), String.Concat(Me.UniqueID, "_checked"), Me.UniqueID, "trigger" }
Dim text3 As String = String.Format("", objArray1)
objArray1 = New Object() { String.Concat(Me.UniqueID, "_selected"), String.Concat(Me.UniqueID, "_selected"), Me.UniqueID, "trigger" }
Dim text4 As String = String.Format("", objArray1)
output.Write(text1)
output.Write(text2)
output.Write(text3)
output.Write(text4)
End If
End Sub.method family virtual instance void Render([System.Web]System.Web.UI.HtmlTextWriter output) cil managed
{
// Code Size: 344 byte(s)
.maxstack 5
.locals (
string text1,
string text2,
string text3,
string text4,
object[] objArray1)
L_0000: ldarg.0
L_0001: ldsfld string [mscorlib]System.String::Empty
L_0006: stfld string WebControlLibrary1.WebCustomControl1::licenseMessage
L_000b: ldarg.0
L_000c: ldfld string WebControlLibrary1.WebCustomControl1::licenseMessage
L_0011: ldsfld string [mscorlib]System.String::Empty
L_0016: beq.s L_0029
L_0018: ldarg.1
L_0019: ldarg.0
……中间无关代码略
L_0150: ldarg.1
L_0151: ldloc.3
L_0152: callvirt instance void [System.Web]System.Web.UI.HtmlTextWriter::Write(string)
L_0157: ret }
与RadTreeView.DLL的Render方法的反汇编代码相对照,在WebControlLibrary1中得出如下对应关系
VB
对应的IL汇编代码
Me.licenseMessage = String.EmptyL_0000: ldarg.0
L_0001: ldsfld string [mscorlib]System.String::Empty
L_0006: stfld string Telerik.WebControls.RadTreeView::licenseMessage
现在,可以添加IL代码了。打开Visual Studio .NET 2003 命令提示
键入ILDASM 打开RadTreeView.DLL
然后转储IL反汇编代码,保存RadTreeView.IL,附属文件也一并出现在文件夹中
用记事本打开RadTreeView.IL文件,现取消强名称验证。在文件头部找到如下代码将其删除:
.publickey =(00 24 00 00 04 80 00 00 94 00 00 00 06 02 00 00 // .$..............
00 24 00 00 52 53 41 31 00 04 00 00 01 00 01 00 // .$..RSA1........
CD 62 12 05 0E 7C CD 6F 51 AF 2C 41 FD CC 65 44 // .b...|.oQ.,A..eD
AC E3 CF 79 6A 19 49 C5 80 C3 FF 52 7C AC 91 1D // ...yj.I....R|...
9B E0 5F AD 28 47 CE F4 E7 E5 EC 87 9F C9 4B E4 // .._.(G........K.
9E 31 C7 97 C2 B8 39 25 C4 ED F6 AA 83 FA 78 A3 // .1....9%......x.
5A 47 C0 F4 7B 44 A8 F9 3F D1 44 A9 B7 96 BF 74 // ZG..{D..?.D....t
9E 8D FC B3 99 82 11 52 A9 5C 7A 37 EB A3 82 B6 // .......R.\z7....
9D A5 8B 7A 1C 87 DA 5C ED 0B 7A 72 BA B1 3F 12 // ...z...\..zr..?.
52 C6 2F 50 DD 35 44 06 E6 F3 B0 4B AF F4 19 BD ) // R./P.5D....K....查找Render方法,可见到其代码片断如下:
.method family hidebysig virtual instance void
Render(class [System.Web]System.Web.UI.HtmlTextWriter output) cil managed
{
// 代码大小 313 (0x139)
.maxstack 4
.locals init (class Telerik.WebControls.RadTreeViewHtmlRenderer V_0,
string V_1,
string V_2,
string V_3,
string V_4)
IL_0000: ldarg.0
IL_0001: ldfld string Telerik.WebControls.RadTreeView::licenseMessage
IL_0006: ldsfld string [mscorlib]System.String::Empty
IL_000b: call bool [mscorlib]System.String::op_Inequality(string,
string)
IL_0010: brfalse.s IL_001f
……中间无关代码略
IL_0124: callvirt instance void [mscorlib]System.IO.TextWriter::Write(string)
IL_0129: ldarg.1
IL_012a: ldloc.3
IL_012b: callvirt instance void [mscorlib]System.IO.TextWriter::Write(string)
IL_0130: ldarg.1
IL_0131: ldloc.s V_4
IL_0133: callvirt instance void [mscorlib]System.IO.TextWriter::Write(string)
IL_0138: ret
} // end of method RadTreeView::Render将“仿真”的IL代码插入Render方法的最前面,见如下加粗代码。
.method family hidebysig virtual instance void
Render(class [System.Web]System.Web.UI.HtmlTextWriter output) cil managed
{
// 代码大小 313 (0x139)
.maxstack 4
.locals init (class Telerik.WebControls.RadTreeViewHtmlRenderer V_0,
string V_1,
string V_2,
string V_3,
string V_4)
L_0000: ldarg.0
L_0001: ldsfld string [mscorlib]System.String::Empty
L_0006: stfld string Telerik.WebControls.RadTreeView::licenseMessage
IL_0000: ldarg.0
IL_0001: ldfld string Telerik.WebControls.RadTreeView::licenseMessage
IL_0006: ldsfld string [mscorlib]System.String::Empty
IL_000b: call bool [mscorlib]System.String::op_Inequality(string,
string)
IL_0010: brfalse.s IL_001f
……中间无关代码略
IL_0133: callvirt instance void [mscorlib]System.IO.TextWriter::Write(string)
IL_0138: ret
} // end of method RadTreeView::Render
保存RadTreeView.IL准备使用ilasm重新编译,为应对编译出现反复,用记事本再做一个批处理文件Myasm.bat保存在同一目录中,内容如下:
ilasm /dll /resource: RadTreeView.res /output: RadTreeView.dll RadTreeView.IL
在Visual Studio .NET 2003 命令提示行运行Myasm,几秒钟后,新的RadTreeView.dll出现了。
为检查添加的IL指令的正确性,用Reflector打开破解后的RadTreeView.dll,反编译Render方法为VB代码,可惜的一幕出现了,Me.licenseMessage = String.Empty
指令准确地出现在我们预定的位置上,可见“仿真”的IL代码是正确的。见下图:
进入Microsoft Visual .NET 开发环境,将新的RadTreeView.dll添加到工具箱。仿照示例代码建立一测试页面WebForm1.aspx,将RadTreeView所需的资源TreeViewImages目录考入测试站点的虚拟目录中。
本文地址:http://com.8s8s.com/it/it8621.htm