【.Net Framework 体积大?】不安装.net framework 也能运行!?原理简介-2(补充)

看完点推荐,推荐数目超过100,打包脚本+工具+运行时 所有分享哈。。。。。(无公司争议,请放心)html

 

接上一篇前端

【.Net Framework 体积大?】不安装.net framework 也能运行!?开篇叙述-1node

 

下一篇编程

【.Net Framework 体积大?】不安装.net framework 也能运行!?原理补充-3小程序

 

  昨天写了一个引子,仍是有读者对这套“小把戏”感兴趣。那么不辜负你们的但愿,争取博主不作太监........设计模式

  注意:笔者不想谈Link的方式,虽然很爽,可是不靠谱。毕竟解析翻译到原生的应用,微软到如今也就敢在Xaml系的应用作尝试,不知道是微软的策略,仍是自身都信心不大......api

  至于Mono项目,笔者就不说它了,BUG真的多的一个接一个的,甚至2.0都过去了,3.0尚未修复。虽然它能够支持Link ,mkbundle 工具,可是bug太多,不当心就是一个雷......服务器

 

  开篇先谈下原生的应用和虚机应用。架构

  Native的程序,大多基于特定的平台硬件系统的,这里的系统 咱们就说三大主流系统中的Win/Mac/Linux。硬件部分嘛,主要是CPU的类型...原生应用跟随操做系统的兼容性,能够相似插入内存条同样,直接跟系统集成,运行速度快,处理数据速度效率高。开发语言:C/C++  汇编?(呵呵,这都上个世纪的东东)  。基于C/C++ 衍生出来 主流的 QT VC .....VC 里有衍生出个MFC。。。。。。。app

  虚机应用,这类应用大可能是基于虚机运行时,也就是将运行时 Run time SDK 安装到适配的操做系统后,SDK将硬件 操做系统的不一样 进行了自适应。应用开发者,只须要关注程序的运行效果。就好像坑坑哇哇的石头墙,摸了一层水泥,而后上面能够搭载各类形状的石头,而不是特定形状的石头(去适应石头缝大小形状)。特色是:平台适应强 开发速度快 迭代周期缩短...。开发语言:Python Java .net Framework node.js .......

  虚机应用,又各自有各自的特定。有的是基于脚本执行,有的是强类型的编译执行。不过大同小异。都离不开运行时!!!

  其余语言的运行时,咱们不谈,有兴趣,本身研究。咱们专门谈一下.net 的运行时 .net Framework. 

  特色:微软开发,大品牌。体积大,不能说大,简直是巨大!前面说了,从2.0 的几十兆 到3.5的几百兆 到4.0又回到几十兆(可是安装速度真慢的要命,由于要先自解压)。前面说了,十分佩服微软的 cab 压缩,愣是把一个几百兆的.net 4.0  压缩到了几十兆!!!4.5 4.6也都是4系列的。主版本号不变,改变次版本号,说明只是基于4的补丁,可是要亲命的是 4.5 抛弃了XP!!!!XP 啊,提到XP 就好像前端开发者对着IE6那个时代!!! 虽然痛苦恐怖,可是,XP在国内的使用群体依然大的离谱。

 

虽然 Win7普及的效果不错,可是那毕竟是XP 啊  XP 啊 ............泪奔。

因此,笔者认为 .net 4到目前为止 是兼容最全面的Win 系列的系统。对于开发者来讲 4版本无疑是一个划时代的东东,各类应用框架都有,并且性能比3.5好,并且体积小了好多。可是仅仅是相对小了。笔者认为,它依然巨大。相比较 Python Ruby Node.js Lua的运行时,都小巧,安装速度快,运行速度也能够。凭啥.net 这个鬼 体积那么大!??

实际上是有缘由的。如图:

 C:\WINDOWS\Microsoft.NET

 

 

 这个基本就是.net 的运行时集中营了(虽然在System目录也打入了其余的dll,后面说)

看到这里,咱们就须要回忆下,.net 的自身的架构

2.0

 

3.5

 

4.0

 

上图来自:http://www.cnblogs.com/xiaopin/archive/2011/01/07/1929467.html

是否是相似搭积木的方式,一块块的耦合上去的?确实,一个完整的.net framework安装包,须要把整个积木架构搭建起来。可是大多数状况下,咱们只须要积木的台子,也就是到 第一个图中的程序集那一层就完事,有GAC  有运行时 ,就足够咱们把程序集经过系统引导到 CLR 运行时解析 IL 中间语言到当前平台的原生代码,并执行原生代码。至关于,咱们只须要雇佣一个翻译,会翻译其余语言便可,不必长得高大威猛帅。。。。

  那么咱们能把上面的枝枝叶叶修建掉么?笔者测试是能够的。

  咱们只须要把GAC 的相关程序集,还有运行时便可。而后就是特定的引导目录+注册表。

  笔者没有找到.net 程序引导的顺序,不过从笔者实验的结果来看。微软打包的程序的时候,给程序集打上了特殊的标识。而后由系统注册表注册的特定应用去解析程序集。相似指定默认程序同样的效果(不知道表述是否正确,欢迎你们指正)。

  好,既然是指定的注册表来注册引导程序,那么哪一个才是The One? 不卖关子,直接给答案!

  注册表:SOFTWARE\Microsoft\.NETFramework\

  这个注册表项,有一个安装路径的项,指定到.net的运行时目录。笔者的机器是64位机器,x86的机器就没有64.

 

 

 而后,注册完路径后,还有它下面的一个注册表键值对:policy

注意其中的键值对:

 

这个支持策略,相似设计模式中的策略模式。根据特定的场景,使用特定的策略支撑。咱们注册4.0后,天然也就支持.net 4.0。

  好,注册表关键就这2个,接下来还有关键的一个步骤,在系统目录 

一个是箭头指向的dll  还有一个

 

100那个是4.0的 120那个是笔者安装了 VC 分布包的 VC++2013的。咱们须要的是上面的那个哈。。。

 

好,把这两个程序集 在特定的机器上,也打入进去后,好,咱们的精简版本的.net framework就完成了!!

而后,还能够在运行时程序集 目录下,裁剪不须要的程序集 好比什么 exe的小工具啊 WCF 啊 WPF啊什么的。最终就能够粗来一个体积小巧,性能不错,支持.net 4.0的运行时了。

也就是上面的3步走,有兴趣本身尝试,有疑问,请评论留言。笔者不会发布完整的小安装包。版权的问题很蛋痛 呵呵,Congratulations..............

  啰嗦一下,为何添加注册表就能访问策略进行引导,跟.net的历史有关系吧,由于XP系统上面,就已经集成了1.X的.net framework.后续系统Vista win7 server03 08 等等也同样。因此,注册个版本号,也就能够识别粗来了。。。。。

   注册表献上:

 

 

Root: HKLM; Subkey: "SOFTWARE\Microsoft\.NETFramework";Permissions:admins-full; ValueType: string; ValueName: "InstallRoot"; ValueData: "{win}\Microsoft.NET\Framework\";Check:WebServerRuntimeNotInstall


Root: HKLM; Subkey: "SOFTWARE\Microsoft\.NETFramework\policy\v4.0";Permissions:admins-full;Check:WebServerRuntimeNotInstall


Root: HKLM; Subkey: "SOFTWARE\Microsoft\.NETFramework\policy\v4.0"; Permissions:admins-full; ValueType: string; ValueName: "30319"; ValueData: "30319-30319";Check:WebServerRuntimeHasNotV4SubKey

不要问我,上面是什么鬼,inno setup 又是什么鬼。尽情享用吧.........

 

 

 

 

  ---------------------延伸:mscoree.dll-----------------------------

 

.NET中的幕后英雄:MSCOREE.DLL

如今作.NET Framework的开发的朋友应该是愈来愈多了,可是可能并不是人人都对MSCOREE.DLL很是了解。而事实上,绝不夸张地说,MSCOREE.DLL是.NET Framework中最为核心的DLL之一,没有这个DLL,托管程序根本没法开始执行起来,可是因为这个DLL藏在System32目录下,根本无人问津,能够说是有点委屈了这位.NET Framework中的幕后英雄。本文主要讨论MSCOREE.DLL的几大做用,以及MSCOREE.DLL的兼容性问题。

MSCOREE是托管程序的入口点
让咱们来作一个小实验:

首先写一个最最简单的Hello World程序,用csc编译(固然你用VS我也没意见):

public class Program
{

       public static void Main(string[] args)

       {

              System.Console.WriteLine("Hello World!");

       }
}
 
而后,在命令行中键入:
 

C:/Windows/System32> ren mscoree.dll mscoree_.dll

 
请注意在Vista系统上需提高权限,不然重命名失败。
以后,运行刚才编译出来的EXE程序。Windows直接报错:

而后,再把mscoree.dll名字改回去,再次运行A.EXE,此次正确打印出了Hello World。

那么为何一旦没有MSCOREE.DLL,就算是最简单的Hello World也没法运行呢?

有在Windows用C/C++编程的朋友们应该熟悉上面那个出错对话框的意思,这个对话框一般在程序找不到所需的DLL的时候出现。咱们能够经过运行Visual Studio中自带的Depends.exe来查看A.EXE的对于DLL的依赖关系:

能够看到A.EXE只对一个DLL有依赖关系,也就是MSCOREE.DLL。而且A.EXE只用到了MSCOREE.DLL中的一个函数,即_CorExeMain。而MSCOREE.DLL自己却输出了137个函数之多。从这个函数的名字你们能够猜出,这个函数是EXE的一个入口点。为了证明这一点,咱们能够用DumpBin看看内容:

Microsoft (R) COFF/PE Dumper Version 8.00.50727.762

Copyright (C) Microsoft Corporation. All rights reserved.

 
 
Dump of file a.exe
 
PE signature found
 
File Type: EXECUTABLE IMAGE
 
FILE HEADER VALUES
             14C machine (x86)
               3 number of sections

        46C83E12 time date stamp Sun Aug 19 20:56:50 2007

               0 file pointer to symbol table
               0 number of symbols
              E0 size of optional header
             10E characteristics
                   Executable
                   Line numbers stripped

                   Symbols stripped

                   32 bit word machine
 
OPTIONAL HEADER VALUES
             10B magic # (PE32)
            8.00 linker version
             400 size of code
             600 size of initialized data
               0 size of uninitialized data

            23DE entry point (004023DE)

            2000 base of code
            4000 base of data
          400000 image base (00400000 to 00407FFF)
 
 
注意这个EXE的入口点的RVA是23DE。
再使用Windbg加载A.EXE,使用lmm (list module match)命令查看A.EXE加载的首地址:
 
0:000> lmm a

start    end        module name

00de0000 00de8000   a          (deferred) 

 
 
能够看到是0x00de0000,那么再加上23DE这个RVA值,就是程序的入口点。用u命令反汇编看一下:
 
0:000> u de23de
a+0x23de:

00de23de ff250020de00    jmp     dword ptr [a+0x2000 (00de2000)]

 
能够看到这就是一个简单的JUMP指令,跳转到0x00de2000所指向的位置,那么这个位置是什么函数呢?咱们能够经过dds命令查看:
 
0:000> dds 2000+de0000
00de2000 5b034e50 mscoree!_CorExeMain
 
 
到此事实就很是清楚了,任何托管的EXE程序中的入口点都是一条JMP指令直接跳转到MSCOREE.DLL的_CorExeMain函数执行。而这个_CorExeMain的地址(也就是00de2000所保存的0x5b034e50)则是由OS Loader填入,由于这个位置正是Import Table的位置。
对于一个托管的DLL而言,状况也很是相似,入口点则是_CorDllMain:

能够想象的到,假如你的系统中没有安装.NET Framework,那么执行托管程序也会马上一样的对话框。显然根据这个信息用户自己很难推断出发生了什么问题。一个可行的方案是Windows老是自带一个MSCOREE.DLL,这个MSCOREE.DLL若是发现没有.NET Framework则会给出比较清晰的报错信息。不过因为从Windows 2003以后(包括Vista)的全部Windows版本都会自带.Net Framework,那么这个问题基本上不会出现了。

MSCOREE负责选择.NET Framework版本

MSCOREE.DLL有个很是特殊的地方,也就是它位于C:/Windows/System32目录下,换句话说,无论你的系统上面安装了多少个不一样的.NET Framework版本,这个DLL都最多只可能有2份(32位/64位各一份),而在C:/Windows/Microsoft.NET/Framework 或者C:/Windows/Microsoft.NET/Framework64下面,则会有多份不一样的.NET Framework同时存在。那么,这个MSCOREE.DLL又是如何对应不一样版本的.NET Framework呢?答案很简单:MSCOREE.DLL经过注册表信息肯定系统上面安装的.NET Framework版本号码,而后根据应用程序自己的所要求的版原本选择一个合适的.NET Framework版原本执行。真正的工做则是交给实际的某个版本的 .NET的DLL执行,在一般状况下,这个DLL是Work Station版本的CLR,名为MSCORWKS.DLL,而服务器版本的CLR则对应MSCORSVR.DLL

程序能够经过MSCOREE调用CLR的提供的功能或者定制CLR

MSCOREE.DLL导出了大量的函数,那么这些函数是否公开而且能够调用呢?答案是确定的。几乎全部这些函数在MSDN中均可以查到对应的文档,而且在.NET Framework SDK的Include目录中有一个对应的mscoree.h,提供了这些函数的Prototype。应用程序经过这些函数,能够访问CLR提供的各项功能,好比:

函数名
用途
GetCORSystemDirectory
得到进程中加载的CLR的安装目录
GetCORVersion
得到进程中加载的CLR的版本西nxi 
GetFileVersion
得到指定文件的CLR版本信息
GetRequestedRuntimeInfo
得到指定版本CLR的相关信息
GetRequestedRuntimeVersion
得到应用程序运行所须要的CLR版本信息
ClrCreateManagedInstance
建立一个.NET对象并返回指定的接口,使用此函数能够访问大量的.NET Framework的已有功能
CorBindToRuntime
加载指定版本CLR
CorBindToRuntimeHost
在Host中加载指定版本CLR,Hosting时候使用
CreateDebuggingInterfaceFromVersion
得到对应版本CLR的ICorDebug接口,用于编写调试器(好比Visual Studio)
CorLaunchApplication
以指定参数启动托管程序

除此以外还有不少,这里只是列了一些比较经常使用的功能而已。能够看到这些功能都很是有用,特别值得提出的是CorBindToRuntimeHost和CreateDebuggingInterfaceFromVersion。前者提供了对CLR各个方面的定制功能,功能很是强大,有兴趣的朋友能够参考MSDN或者Customizing the Common Language Runtime一书。然后者则提供了对托管程序的调试支持,经过ICorDebug接口。

MSCOREE提供对COM支持

非托管代码能够经过COM直接调用.NET的Assembly中的托管对象。如下面这个对象为例,该对象CLSID为{0029598F-26Fa-46F7-953B-86E2947AB19F},类型为Microsoft.SqlServer.Replication.ComErrorRecord,线程模型为Both,Assembly名称为Microsoft.SqlServer.Replication, Version=9.0.242.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91,所需CLR版本为v2.0.50727 (2.0 RTM)。最值得注意的是,入口点为mscoree.dll。

 

对于COM来讲,COM只知道CLSID=0029598F-26Fa-46F7-953B-86E2947AB19F}的COM对象位于MSCOREE.DLL中。而事实上,这个类型位于Microsoft.SqlServer.Replication.dll之中,可是COM并不知道,COM只须要知道从MSCOREE.DLL中能够得到对应的ClassFactory就能够了,而后COM会经过IClassFactory接口建立这个托管对象的实例,并返回对应的接口。假定一个非托管程序尝试经过COM建立这样一个对象,那么会发生下面这些事情:
1.     程序调用CoCreateInstance通知COM须要建立这样一个对象,CLSID=0029598F-26Fa-46F7-953B-86E2947AB19F,须要返回IDispatch接口
2.     COM调用CoGetClassObject函数查找对应的入口DLL
3.     COM找到对应的注册表,发现对应的DLL为MSCOREE.DLL
4.     COM加载MSCOREE.DLL,调用DllGetClassObject函数,传入CLSID
5.     MSCOREE.DLL中的DllGetClassObject函数读入CLSID,找到对应的注册表,获取对象的类型名称,Assembly名称,CLR版本等信息
6.     DllGetClassObject加载对应版本的CLR
7.     DllGetClassObject返回一个临时Class Factory对象的IClassFactory接口
8.     COM调用这个Class Factory对象的IClassFactory::CreateInstance方法
9.     这个Class Factory加载对应的CLR,并建立对象,返回一个对象的CCW (Com Callable Wrapper),并该CCW的返回指定的IDispatch接口
能够看到,这个状况下起到最关键做用的是MSCOREE.DLL所提供的DllGetClassObject函数。

除了对用户自定义的托管对象提供COM支持以外,MSCOREE.DLL本身也支持少许COM对象,所以MSCOREE.dll支持DllGetClassObject, DllRegisterServer, DllUnregisterServer, DllCanUnloadNow这些COM DLL所须要支持的标准函数。

MSCOREE.DLL的兼容性问题

咱们能够考虑一下,假如咱们如今有了.NET Framework 1.0,而后安装了.NET Framework 2.0,那么MSCOREE.DLL会发生变化吗。答案是可能会,若是到2.0到1.0发生了改变须要修改MSCOREE.DLL(好比多加了一个函数),那么确定要更新MSCOREE.DLL,可是这个MSCOREE.DLL必须彻底支持全部.NET Framework 1.0中的MSCOREE.DLL中的函数,不然能够想象全部依赖于这些变化的MSCOREE.DLL中的函数程序都会出错。所以MSCOREE.DLL必需要作到彻底向前兼容。

再考虑卸载的状况,假如这个时候.NET Framework 2.0被卸载,那么MSCOREE.DLL会被还原成.NET Framework 1.0的吗?此次答案则是不会。由于2.0的MSCOREE.DLL自己支持.NET Framework 1.0,所以无须替换。这样最为简单。

事实上是,CLR Team通常不多改动MSCOREE.DLL,避免出现兼容性问题,所以能够预见,MSCOREE.DLL将会是.NET Framework/CLR中变化最少的DLL。换句话说,这篇文章的内容,在能够预见的将来几个版本基本上不会过期。OK,对于MSCOREE.DLL的讨论到这里就告一段落,有兴趣的朋友能够本身动手写一些小程序,实际体会一下MSCOREE.DLL所提供的各项功能。

 

https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/deprecated-clr-hosting-functions

https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/cordllmain-function

_CorDllMain Function

 

 

Initializes the common language runtime (CLR), locates the managed entry point in the DLL assembly's CLR header, and begins execution.

Syntax

BOOL STDMETHODCALLTYPE _CorDllMain (  
   [in] HINSTANCE hInst,  
   [in] DWORD     dwReason,  
   [in] LPVOID    lpReserved  
);

Parameters

hInst
[in] The instance handle of the loaded module.

dwReason
[in]Indicates why the DLL entry-point function is being called. This parameter can be one of the following values: DLL_PROCESS_ATTACH, DLL_THREAD_ATTACH, DLL_THREAD_ATTACH, or DLL_PROCESS_DETACH. For descriptions of these values, see the DllMain documentation in the Platform SDK.

lpReserved
[in] Unused.

Return Value

This method returns true for success and false if an error occurs.

Remarks

This function is called by the operating system loader for DLL assemblies. For executable assemblies, the loader calls the _CorExeMain function instead.

The operating system loader calls this method regardless of the entry point specified in the DLL file.

In Windows 98, Windows ME, Windows NT, and Windows 2000, the _CorDllMain function is called indirectly through a fixupin the operating system loader. In all other versions of Windows, it is called directly by the operating system loader.

For additional information, see the Remarks section in the _CorValidateImage topic.

Requirements

Platforms: See System Requirements.

Header: Cor.h

Library: Included as a resource in MsCorEE.dll

.NET Framework Versions: Available since 1.0

See Also

Metadata Global Static Functions

Feedback

 

_CorExeMain Function

Initializes the common language runtime (CLR), locates the managed entry point in the executable assembly's CLR header, and begins execution.

Syntax

__int32 STDMETHODCALLTYPE _CorExeMain ();

Remarks

This function is called by the loader in processes created from managed executable assemblies. For DLL assemblies, the loader calls the _CorDllMain function instead.

The operating system loader calls this method regardless of the entry point specified in the image file.

In Windows 98, Windows ME, Windows NT, and Windows 2000, the _CorExeMain function is called indirectly through a fixup in the operating system loader. In all other versions of Windows, it is called directly by the operating system loader.

For additional information, see the Remarks section in the _CorValidateImage topic.

Requirements

Platforms: See System Requirements.

Header: Cor.h

Library: Included as a resource in MsCorEE.dll

.NET Framework Versions: Available since 1.0

See Also

Metadata Global Static Functions

相关文章
相关标签/搜索