曾经有一段时间,我纠结于.Net Framework的精简与XCOPY部署,为此研究了很久应用程序虚拟化,但没啥成果。曾尝试过Remotesoft的Linker(就网上广为流传的飞信用的那个),还尝试过Mono精简,Remotesoft的仅支持.NET 2.0,生成的文件也不小,Mono在Windows上的兼容性貌似还不是很好(当时,非现在),可能跟他们的跨平台战略有关吧,最后看了SSCLI2.0的代码,想从那里面精简出来一份能用的CLR,后来有事儿,就扔下了。

  Silverlight我从4开始使用,个人认做类似OA啊,内部的一些系统很好,但微软因为战略原因把Silverlight模糊化,导致现在我一提Silverlight就会被说已经被微软放弃了,不应该再使用,而且一直担心会不会有SL6。我从接触Silverlight的那天我就很奇怪,他安装包才7MB左右,而且国外的启动研究论坛(貌似叫911cd还是什么)研究它可以直接放在Firefox Portable版里运行,也就是俗称绿色软件,不依赖注册表,不依赖COM组件,根据微软一篇文章介绍,他和.NET 4的CLR源自同一份代码,JIT等行为可以说与.NET4的CLR具有一致性,那么他的兼容性是很好的,起码在Windows平台上,毕竟是微软自己的,而且他还跨平台支持Mac osx。

  Silverlight的核心部分就几个文件:npctrl.dll,agcore.dll,coreclr.dll。其中npctrl.dll在IE看来他是个ActiveX控件,在Chrome和Firefox看来他是个NP插件。agcore.dll由npctrl.dll加载,是SL的核心部分,实现了绘图等。coreclr.dll由npctrl.dll,agcore.dll加载,是本文重点核心部分,其就是CoreCLR的实现。

  CoreCLR就是那个与.NET4源自同一份代码的一个精简CLR,看下 CLR 全面透彻解析 使用 CoreCLR 编写 Silverlight 和 Silverlight CoreCLR结构浅析 有个大概的了解。自从SL5发布以来,他支持了OOB模式下对WIN32 API的调用,这让我产生了一些想法,直接用他做.NET 的运行时多好,当然,毕竟精简过,没有SYSTEM.WINDOWS.FORM这部分,没法做UI,但SL本身就是UI啊。带着这个想法,我到了墙外。。。有了下面的故事。

  首先说明,我研究的SL版本是5.1.10411.0,安装的是X64开发版(里面包含X86版),为什么不用最新的?因为最新版微软打过安全补丁,导致在微软的公共符号服务器上炸不到对应的PDB文件(.NET FRAMEWORK4参考源代码级调试失败的可以想办法把.NET4的一些补丁删除,降到RTM版本,这样就有了符号以及匹配的参考源代码),无法使用神器IDA6,这是仅次于最新的版本。我们要研究的是coreclr.dll,拿起IDA加载,等待符号下载完毕,分析完毕,看导出函数,

Name                    Address  Ordinal
----                      -------  -------
coreclr_1              79354D14 1     
g_CLREngineMetrics 7947E924 2     
coreclr_3          791964D7 3     
GetCLRRuntimeHost  7919B0B5 4     
CoreDllMain(x,x,x) 791963DB       

看名称就知道GetCLRRuntimeHost则个是重点,先把动词去掉,得到CLRRuntimeHost,放到墙外的google上,我们从MSDN上得到了ICLRRuntimeHost 这个接口,看介绍,是用来对CLR进行宿主的(在非托管程序中加载CLR并使用他加载托管代码的一种技术),再把动词Get加上,google下看看有没有人研究过,然后得到了三篇连载:

http://clrguru.blogspot.com/2009/01/taming-coreclr-part-1.html
http://clrguru.blogspot.com/2009/02/taming-coreclr-part-2.html
http://clrguru.blogspot.com/2009/02/taming-coreclr-concluding.html

(都是墙外的)

他提供了一些思想,但版本已经老了,不适合SL5。

根据我从IDA分析的结果,CLRRuntimeHost这个函数有两个参数,第一个是传入IID(GUID),第二个是输出的接口指针,其实就是直接调用了QueryInterface这个COM技术里的核心函数,第一个IID从IDA的结果来看是 :

EXTERN_GUID(IID_ICLRRuntimeHost2, 0x712AB73F, 0x2C22, 0x4807, 0xAD, 0x7E, 0xF5, 0x1, 0xD7, 0xB7, 0x2C, 0x2D);

既然他叫ICLRRuntimeHost2按照ms的命名习惯,他应该继承自ICLRRuntimeHost,根据上面的三个短文以及IDA分析我得到了他扩展了4个方法,

CreateAppDomainWithManager
CreateDelegate
Authenticate
UnknowMethod
那么我们根据上面三篇短文以及IDA的结果形成了一个idl文件:
ICLRRuntimeHost2.idl

  1 //#define MIDL_PASS
  2 //#include "mscoree.h"
  3 //import "ocidl.idl";
  4 //import "oleidl.idl";
  5 //import "oaidl.idl";
  6 import "Unknwn.Idl";
  7 
  8 
  9 //下面的接口是从sscli2.0 的 mscoree.idl 里面抠出来的
 10 
 11 typedef HRESULT (__stdcall *FExecuteInAppDomainCallback) (void* cookie);
 12 
 13 
 14 typedef struct _BucketParameters
 15 {
 16     BOOL  fInited;                  // Set to TRUE if the rest of this structure is valid.
 17     WCHAR pszEventTypeName[255];    // Name of the event type.
 18     WCHAR pszParams[10][255];       // Parameter strings.
 19 } BucketParameters;
 20 
 21 
 22 
 23 
 24 
 25 // {AD76A023-332D-4298-8001-07AA9350DCA4}
 26 cpp_quote("EXTERN_GUID(IID_IPrivateManagedExceptionReporting, 0xAD76A023,0x332D, 0x4298, 0x80, 0x01, 0x07, 0xAA, 0x93, 0x50, 0xDC, 0xA4);")
 27 [
 28     uuid(AD76A023-332D-4298-8001-07AA9350DCA4),
 29     version(1.0),
 30     helpstring("CLR error reporting manager"),
 31     pointer_default(unique),
 32     local
 33 ]
 34 interface IPrivateManagedExceptionReporting : IUnknown
 35 {
 36     // Get Watson bucket parameters for "current" exception (on calling thread).
 37     HRESULT GetBucketParametersForCurrentException([out] BucketParameters *pParams);
 38 }
 39 
 40 // {02CA073D-7079-4860-880A-C2F7A449C991}
 41 cpp_quote("EXTERN_GUID(IID_IHostControl, 0x02CA073C, 0x7079, 0x4860, 0x88, 0x0A, 0xC2, 0xF7, 0xA4, 0x49, 0xC9, 0x91);")
 42 [
 43     uuid(02CA073C-7079-4860-880A-C2F7A449C991),
 44     version(1.0),
 45     helpstring("Common Language Runtime Host Control Interface"),
 46     pointer_default(unique),
 47     local
 48 ]
 49 interface IHostControl : IUnknown
 50 {
 51     HRESULT GetHostManager(
 52         [in] REFIID riid,
 53         [out] void **ppObject);
 54 
 55     /* Notify Host with IUnknown with the pointer to AppDomainManager */
 56         HRESULT SetAppDomainManager(
 57         [in] DWORD dwAppDomainID,
 58         [in] IUnknown* pUnkAppDomainManager);
 59 }
 60 
 61 
 62 cpp_quote("EXTERN_GUID(IID_ICLRControl, 0x9065597E, 0xD1A1, 0x4fb2, 0xB6, 0xBA, 0x7E, 0x1F, 0xCE, 0x23, 0x0F, 0x61);")
 63 [
 64     uuid(9065597E-D1A1-4fb2-B6BA-7E1FCE230F61),
 65     version(1.0),
 66     helpstring("Common Language Runtime Control Interface"),
 67     pointer_default(unique),
 68     local
 69 ]
 70 interface ICLRControl : IUnknown
 71 {
 72     HRESULT GetCLRManager(
 73         [in] REFIID riid,
 74         [out] void **ppObject);
 75 
 76         HRESULT SetAppDomainManagerType(
 77                 [in] LPCWSTR pwzAppDomainManagerAssembly,
 78         [in] LPCWSTR pwzAppDomainManagerType);
 79 }
 80 
 81 
 82 
 83 
 84 [
 85     uuid(90F1A06C-7712-4762-86B5-7A5EBA6BDB02),
 86     version(1.0),
 87     helpstring("Common Language Runtime Hosting Interface"),
 88     pointer_default(unique),
 89     local
 90 ]
 91 interface ICLRRuntimeHost : IUnknown
 92 {
 93     // Starts the runtime. This is equivalent to CoInitializeCor().
 94     HRESULT Start();
 95 
 96     // Terminates the runtime, This is equivalent CoUninitializeCor();
 97     HRESULT Stop();
 98 
 99     // Returns an object for configuring runtime, e.g. threading, lock
100     // prior it starts.  If the runtime has been initialized this
101     // routine returns an error.  See IHostControl.
102     HRESULT SetHostControl([in] IHostControl* pHostControl);
103 
104     HRESULT GetCLRControl([out] ICLRControl** pCLRControl);
105 
106     HRESULT UnloadAppDomain([in] DWORD dwAppDomainId,
107                             [in] BOOL fWaitUntilDone);
108 
109     HRESULT ExecuteInAppDomain([in] DWORD dwAppDomainId,
110                                [in] FExecuteInAppDomainCallback pCallback,
111                                [in] void* cookie);
112 
113     HRESULT GetCurrentAppDomainId([out] DWORD *pdwAppDomainId);
114 
115     HRESULT ExecuteApplication([in] LPCWSTR   pwzAppFullName,
116                                [in] DWORD     dwManifestPaths,
117                                [in] LPCWSTR   *ppwzManifestPaths,   // optional
118                                [in] DWORD     dwActivationData,
119                                [in] LPCWSTR   *ppwzActivationData,  // optional
120                                [out] int      *pReturnValue);
121 
122     HRESULT ExecuteInDefaultAppDomain([in] LPCWSTR pwzAssemblyPath,
123                                       [in] LPCWSTR pwzTypeName,
124                                       [in] LPCWSTR pwzMethodName,
125                                       [in] LPCWSTR pwzArgument,
126                                       [out] DWORD  *pReturnValue);
127 };
128 
129 
130 //这个接口是根据IDA反汇编找到的
131 cpp_quote("EXTERN_GUID(IID_ICLRRuntimeHost2, 0x712AB73F, 0x2C22, 0x4807, 0xAD, 0x7E, 0xF5, 0x1, 0xD7, 0xB7, 0x2C, 0x2D);")
132 [
133 uuid(712AB73F-2C22-4807-AD7E-F501D7B72C2D),
134 version(1.0),
135 helpstring("Common Language Runtime Hosting Interface 2"),
136 pointer_default(unique),
137 local
138 ]
139 interface ICLRRuntimeHost2 : ICLRRuntimeHost
140 {
141     HRESULT CreateAppDomainWithManager(
142         [in]  LPCWSTR pwzAppDomainName,
143         [in]  DWORD appDomainCreateFlags,
144         [in]  LPCWSTR pwzManagerAssemblyName,
145         [in]  LPCWSTR pwzMAppdomainmanagerName,
146         [in]  DWORD appDomainSetupOptionsCount,
147         [in]  LPCWSTR* appDomainSetupOptions,
148         [in]  LPCWSTR* appDomainSetupValues,
149         [out] DWORD *retAppDomainID);
150 
151     HRESULT CreateDelegate(
152         [in]  DWORD appDomainID,
153         [in]  LPCWSTR assemblyName,
154         [in]  LPCWSTR className,
155         [in]  LPCWSTR methodName,
156         [out] void *pReturnDelegate);
157 
158     //此处应为为了方便分成两个值
159     //HRESULT Authenticate([in] unsigned __int64);
160     HRESULT Authenticate(
161         [in] DWORD auth1,
162         [in] DWORD auth2);
163 
164 
165     HRESULT UnknowMethod();
166 };
View Code

相关文章: