• .NETZ 原理分析


    .NETZ - .NET Executables Compressor

    .NETZ compresses the Microsoft .NET Framework executable files in order to make them smaller. Smaller executables consume less disk space and load faster because of fewer disk accesses.

    Unlike binary executable packers .NETZ uses a pure .NET solution and it is written in C#. It can be used to pack .NET executables written in any .NET language.

    .NETZ supports both .NET EXE and non-shared DLL files. The compressed applications can be used the in same way as the uncompressed ones, transparently to the end user. .NETZ relies on the open source #ZipLib compression library for .NET to compress the executable data.

    The technique .NETZ uses does not work for .NET Compact Framework.

    ----------------------

    压缩过程分析:

    1. 将命令行参数中的EXE、DLL文件压缩,并写入资源文件 app.resource。
    2. 载入 starter.resources 中的data资源,获取start模版,并做一些替换。该模版是一个cs源文件,主要用来构造压缩后程序的starter。
    3. 使用CodeDom创建目标程序(编译时会根据目标程序类型来编译对应的Console或Winexe格式文件)。

    (.NETZ 提供源码,你可自行分析细节。)

    运行时解压缩过程分析:

    1. starter会从资源中载入主 exe 文件数据,解压缩后构造成Assembly对象。
    2. 利用反射技术调用该Assembly.EntryPoint方法执行目标程序集。(Assembly.EntryPoint 就是目标程序集的 static Main() 入口方法。)
    3. 为正确释放执行DLL,starter增加了一个AppDomain.CurrentDomain.AssemblyResolve事件方法,当目标程序集找不到引用的DLL时会触发该事件,从而让starter有机会从资源文件释放DLL,并创建相应的DLL Assembly。达到整个目标程序的正确执行的目的。

    当然.NETZ在细节上处理得很好,创建的压缩程序集可以包含Version和Icon等信息,仔细分析.NetZ对于了解CodeDom、AppDomain、Assembly等知识是很有帮助的。

    ---------------------------------------------------------------------

    以下,我们编写一个例子来印证我们的分析。

    创建一个Console程序,该程序调用另一个类库中的方法。

    Console test.exe
    using System;

    namespace Example
    {
      class Program
      {
        static void Main()
        {
          new Class1().Test();
          Console.WriteLine("Press Enter key to exit...");
          Console.ReadLine();
        }
      }
    }

    Library Test.dll
    using System;

    namespace Example
    {
      public class Class1
      {
        public void Test()
        {
          Console.WriteLine(DateTime.Now);
        }
      }
    }

    编译这两个Project,并确保正确执行。
    接下来,我们编写Starter。创建一个新的Console Project,将上面编译的test.exe和test.dll拷贝到该项目目录,设置为嵌入式资源。
    修改Starter代码如下:
    using System;
    using System.Resources;
    using System.Reflection;
    using System.IO;

    namespace MyNamespace
    {
      public class Starter
      {
        [STAThread]
        static void Main(string[] args)
        {
          AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);

          Assembly asm = GetAssembly("MyNamespace.Test.exe");
          MethodInfo info = asm.EntryPoint;
          ParameterInfo[] parameters = info.GetParameters();
          if ((parameters != null) && (parameters.Length > 0))
            info.Invoke(null, (object[])args);
          else
            info.Invoke(null, null);
          
        }

        private static Assembly GetAssembly(string resName)
        {
          Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resName);
          byte[] bs = new byte[stream.Length];
          stream.Read(bs, 0, (int)stream.Length);
          Assembly asm = Assembly.Load(bs);

          return asm;
        }

        private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
        {
          return GetAssembly("MyNamespace.Test.dll");
        }
      }
    }

    编译执行,印证了我们的分析正确。
  • 相关阅读:
    2018-12-25-dot-net-double-数组转-float-数组
    2018-12-25-dot-net-double-数组转-float-数组
    2019-10-24-dotnet-列表-Linq-的-Take-用法
    2019-10-24-dotnet-列表-Linq-的-Take-用法
    2018-8-10-C#-代码占用的空间
    2018-8-10-C#-代码占用的空间
    2018-4-29-C#-金额转中文大写
    2018-4-29-C#-金额转中文大写
    Java实现 LeetCode 630 课程表 III(大小堆)
    Java实现洛谷 P1072 Hankson 的趣味题
  • 原文地址:https://www.cnblogs.com/Safe3/p/1312704.html
Copyright © 2020-2023  润新知