許可證編譯器 (Lc
exe) 的作用是讀取包含授權信息的文本文件
並產生一個可作為資源嵌入到公用語言運行庫可執行文件中的
licenses 文件
在使用第三方類庫時經常會看到它自帶的演示程序中包含有這樣的Demo許可文件
復制代碼 代碼如下:
Infragistics
Win
Misc
UltraButton
Infragistics
Win
Misc
v
Version=
Culture=neutral
PublicKeyToken=f
b
b
b
fdf
Infragistics
Win
Misc
UltraLabel
Infragistics
Win
Misc
v
Version=
Culture=neutral
PublicKeyToken=f
b
b
b
fdf
Infragistics
Win
Printing
UltraPrintPreviewDialog
Infragistics
Win
UltraWinPrintPreviewDialog
v
Version=
Culture=neutral
PublicKeyToken=f
b
b
b
fdf
Infragistics
Win
UltraWinDataSource
UltraDataSource
Infragistics
Win
UltraWinDataSource
v
Version=
Culture=neutral
PublicKeyToken=f
b
b
b
fdf
這個文件的格式是文本文件但要按照它的格式要求來寫
控件名稱 程序集全名稱
首先根據需要寫一個需要被授權的控件列表格式如上所示例如HostAppexe 的應用程序要引用SamplesDLL 中的授權控件 MyCompanySamplesLicControl則可以創建包含以下內容的 HostAppLictxt MyCompanySamplesLicControl SamplesDLL
再調用下面的命令創建名為 HostAppexelicenses 的 licenses 文件 lc /target:HostAppexe /complist:hostapplictxt /i:SamplesDLL /outdir:c:bindir
生成將 licenses 文件作為資源嵌入在HostAppexe的資源中如果生成的是 C# 應用程序則應使用下面的命令生成應用程序
csc /res:HostAppexelicenses /out:HostAppexe *cs
NET Framework SDK目錄中的LCEXE文件是由NET語言編寫的它的功能就是為了根據許可文件的內容生成資源文件在編譯的最後時刻由CSC編譯器把生成的資源文件嵌入到執行文件中
用NET Reflector載入LCEXE開始源代碼分析之旅
程序的入口處先是分析命令行參數根據參數的不同來執行指定的功能先看一個完整的參數列表代碼是下面三行
復制代碼 代碼如下:
if (!ProcessArgs(args))
{
return num;
}
MSDN有完整的解釋拷貝到下面方便您參考以減少因查找MSDN引起思路中斷
/complist:filename 指定包含授權組件列表的文件名這些授權組件要包括到 licenses 文件中每個組件用它的全名引用並且每行只有一個組件命令行用戶可為項目中的每個窗體指定一個單獨的文件Lcexe 接受多個輸入文件並產生一個 licenses 文件
/h[elp] 顯示該工具的命令語法和選項
/i:module 指定模塊這些模塊包含文件 /complist 中列出的組件若要指定多個模塊請使用多個 /i 標志
/nologo 取消顯示 Microsoft 啟動標題
/outdir:path 指定用來放置輸出 licenses 文件的目錄
/target:targetPE 指定為其生成 licenses 文件的可執行文件
/v 指定詳細模式顯示編譯進度信息
/? 顯示該工具的命令語法和選項
ProcessArgs方法的關鍵作用是分析出組件列表程序集列表如下面的代碼所示
復制代碼 代碼如下:
if ((!flag
&& (str
Length >
)) && str
Substring(
)
ToUpper(CultureInfo
InvariantCulture)
Equals("TARGET:"))
{
targetPE = str
Substring(
);
flag
= true;
}
if ((!flag
&& (str
Length >
)) && str
Substring(
)
ToUpper(CultureInfo
InvariantCulture)
Equals("COMPLIST:"))
{
string str
= str
Substring(
);
if ((str
!= null) && (str
Length >
))
{
if (compLists == null)
{
compLists = new ArrayList();
}
compLists
Add(str
);
flag
= true;
}
}
if ((!flag
&& (str
Length >
)) && str
Substring(
)
ToUpper(CultureInfo
InvariantCulture)
Equals("I:"))
{
string str
= str
Substring(
);
if (str
Length >
)
{
if (assemblies == null)
{
assemblies = new ArrayList();
}
assemblies
Add(str
);
}
flag
= true;
}
分 析出組件和程序集之後再來ResolveEventHandler 委托的含義如果運行庫類加載程序無法解析對程序集類型或資源的引用則將引發相應的事件從而使回調有機會通知運行庫引用的程序集類型或資源位於哪 個程序集中ResolveEventHandler 負責返回解析類型程序集或資源的程序集
復制代碼 代碼如下:
ResolveEventHandler handler = new ResolveEventHandler(LicenseCompiler
OnAssemblyResolve);
AppDomain
CurrentDomain
AssemblyResolve += handler;
對第一部參數分析出來的組件列表依次循環為它們產生授權許可
復制代碼 代碼如下:
DesigntimeLicenseContext creationContext = new DesigntimeLicenseContext();
foreach (string str in compLists)
{
key = reader
ReadLine(); hashtable[key] = Type
GetType(key); LicenseManager
CreateWithContext((Type) hashtable[key]
creationContext);
}
最後生成許可文件並保存到磁盤中等待CSC編譯器將它編譯成資源文件嵌入到程序集中
復制代碼 代碼如下:
string path = null;
if (outputDir != null)
{
path = outputDir + @"" + targetPE
ToLower(CultureInfo
InvariantCulture) + "
licenses";
}
else
{
path = targetPE
ToLower(CultureInfo
InvariantCulture) + "
licenses";
}
Stream o = null;
try
{
o = File
Create(path);
DesigntimeLicenseContextSerializer
Serialize(o
targetPE
ToUpper(CultureInfo
InvariantCulture)
creationContext);
}
finally
{
if (o != null)
{
o
Flush();
o
Close();
}
}
這種方式是NET Framework推薦的保護組件的方式與我們平時所討論的輸入序列號RSA簽名不同
來看一下商業的組件是如何應用這種技術保護組件的
復制代碼 代碼如下:
using System;
using System
Web;
using System
Web
UI;
using System
Web
UI
WebControls;
using System
ComponentModel;
namespace ComponentArt
Licensing
Providers
{
#region RedistributableLicenseProvider
public class RedistributableLicenseProvider : System
ComponentModel
LicenseProvider
{
const string strAppKey = "This edition of ComponentArt Web
UI is licensed for XYZ application only
";
public override System
ComponentModel
License GetLicense(LicenseContext context
Type type
object instance
bool allowExceptions)
{
if (context
UsageMode == LicenseUsageMode
Designtime)
{
// We are not going to worry about design time Issue a license
return new ComponentArt
Licensing
Providers
RedistributableLicense(this
"The App");
}
else
{
string strFoundAppKey;
// During runtime
we only want this control to run in the application
// that it was packaged with
HttpContext ctx = HttpContext
Current;
strFoundAppKey = (string)ctx
Application["ComponentArtWebUI_AppKey"];
if(strAppKey == strFoundAppKey)
return new ComponentArt
Licensing
Providers
RedistributableLicense(this
"The App");
else
return null;
}
}
}
#endregion
#region RedistributableLicense Class
public class RedistributableLicense : System
ComponentModel
License
{
private ComponentArt
Licensing
Providers
RedistributableLicenseProvider owner;
private string key;
public RedistributableLicense(ComponentArt
Licensing
Providers
RedistributableLicenseProvider owner
string key)
{
this
owner = owner;
this
key = key;
}
public override string LicenseKey
{
get
{
return key;
}
}
public override void Dispose()
{
}
}
#endregion
}
首 先要創建一個類型繼承於License類型再創建一個繼承於LicenseProvider的類型用於頒發許可證包含在設計時許可和運行時許可 從上面的例子中可以看到設計時沒有限制可以運行但是到運行時你必須有序列號它才會生成許可對象而不是返回null給NET Framework類型整個驗證過程由NET完成
你只需要像下面這樣應用這個許可保護機制
復制代碼 代碼如下:
[LicenseProvider(typeof(RedistributableLicenseProvider))]
public class MyControl : Control {
// Insert code here
protected override void Dispose(bool disposing) {
/* All components must dispose of the licenses they grant
* Insert code here to dispose of the license
*/
}
}
控件許可的驗證代碼(RedistributableLicenseProvider)與控件本身的邏輯完全分離分工協作保護組件的知識產權
From:http://tw.wingwit.com/Article/program/net/201311/14366.html