更新:程式員的思維模式都差不多,Kerem Kusmezer 和 John Robbin 發布了一個類似的工具.NET Mass Downloader。既然有的用我就不重新發明輪子了,下面那個項目停止維護,有需求的朋友直接用那個工具好了,具體使用說明可以參考
Download All the .NET Reference Source Code at Once with Net Mass Downloader
更新:在 sourceforge 上申請了一個項目,有興趣的朋友可以上去下載代碼,或者提交bug和改進建議。不過我估計也就年後才有時間繼續處理,暫且挖個坑反正這裡吧,呵呵
從去年MS就開始喊著要開放.NET原始碼,如今終於在一個含糊不清的授權協議下,通過Source Server的方式放了出來。雖然是如願開源,但目前只提供幾個核心模組,而且還限制必須在VS2008裡面線上訪問。
其實既然決定開放,何必搞那麼多限制出來,讓偶等用著不爽還得自己動手豐衣足食,寫個程式直接類比VS2008擷取源碼的行為,一次性全部拖回來備用。
空口無憑,上傳一個 System.Xml 的源碼包,和一個理論上能跑的程式原型,有興趣的朋友可以試試。回頭有時間了把相關代碼整理一下再放出來,下面先大概說一下思路。
首先,VS2008雖然要打個補丁才能用源碼調試,但這並不是下載源碼的必要條件。MS發布源碼所依賴的Source Server的機制,很早就通過 WinDbg 的發布包引入了。有興趣的朋友可以使用 WinDbg 工具自己架設 Source Server,具體步驟請參考 %Debugging Tools for Windows%\sdk\srcsrv\ 目錄下文檔和指令碼。
而這個 Source Server 說白就是從 .pdb 偵錯符號檔案裡面,擷取被綁定的已索引檔案清單,然後根據系統_NT_SOURCE_PATH環境變數指定的伺服器,拼接出一個 URL 然後通過http下載。具體這塊的配置,可以參考
Configuring Visual Studio to Debug .NET Framework Source Code
討厭的是MS在dbghelp.dll裡面做了一些手腳,直接通過url去下載偵錯符號和源碼是不被允許的。剛好scz前面研究過symbol server的行為,基本確定ms服務端是根據user agent來進行判斷的。也就是說在發起請求時,把當前http的user agent改成ms認可的方式,就能夠類比dbghelp.dll通過srcsrv.dll完成的工作,具體代碼類似
public const string DefaultUserAgent = "Microsoft-Symbol-Server/9.9.9.9 (C; V; ;)";
public void Restart(Uri uri)
{
_request = (HttpWebRequest)WebRequest.Create(uri);
_request.UserAgent = DefaultUserAgent;
IAsyncResult result = (IAsyncResult)_request.BeginGetResponse(
new AsyncCallback(ResponseCallback), this);
ThreadPool.RegisterWaitForSingleObject(result.AsyncWaitHandle,
new WaitOrTimerCallback(TimeoutCallback), this, _timeout, true);
}
另外一個羅嗦的事情,是每個連結建立後,MS伺服器會先返回一個羅嗦的license聲明,srcsrv.dll會彈出一個對話方塊讓你Accept才能繼續下載。
例如你通過命令列去下載一個檔案wget --user-agent=Microsoft-Symbol-Server/9.9.9.9
Http://ReferenceSource.microsoft.com/source/.net/8.0/DEVDIV/
depot/DevDiv/releases/whidbey/REDBITS/ndp/fx/src/Misc/
InvariantComparer.cs/1/InvariantComparer.cs
會直接返回一對垃圾資訊,類似SYMSRVCOMMAND:
YESNODIALOG:
IDYES:Accept:Accept=0cf80f849aa7449e9d064ade971bd887
IDNO:Decline:Decline=0cf80f849aa7449e9d064ade971bd887
TITLE:End User License Agreement
BUTTONDESCRIPTION:Please read carefully and understand the license agreement above.
If you want to accept the license agreement, please click the “Accept” button.
TEXT:This license applies to the .NET Framework components that Microsoft makes available to you
in source code form. To print these terms, select the contents of this area and copy then paste
into an application that can print text.
MICROSOFT .NET FRAMEWORK REFERENCE LICENSE
.NET FRAMEWORK REFERENCE SOURCE CODE
This license governs use of the accompanying software. If you use the software, you accept this license.
If you do not accept the license, do not use the software.
1. Definitions
The terms "reproduce," "reproduction" and "distribution" have the same meaning here as under U.S. copyright law.
解決方案很簡單,直接用Regex找到裡面一個隨機產生的id,然後程式自動Accept即可,代碼類似
private static Regex _accept = new Regex(@"IDYES:Accept:Accept=(\w*)");
if (task._auth)
{
}
else
{
string license = Encoding.Unicode.GetString(task._buf, 0, read);
Match m = _accept.Match(license);
if (m.Success)
{
task._auth = true;
string id = m.Groups[1].Value;
_logger.DebugFormat("Accept license id {0} for {1}", id, task._request.Address);
Uri uri = new Uri(string.Format("{0}?Accept={1}", task._uri.ToString(), id));
task.Restart(uri);
}
}
其他的基本上沒什麼需要說明的,就是很基本的http請求調用啥的,呵呵
至於從.pdb裡面擷取檔案名稱列表,需要調用dbghelp.dll裡面的一組api
SymInitializeW/SymCleanup用來初始化和析構symbol engine
SymLoadModuleExW/SymUnloadModule64用來載入要便利原始碼的模組
SymEnumSourceFilesW用來遍曆一個有.pdb符號且包含已索引源碼的列表
SymGetSourceFileW和SymGetSourceFileTokenW/SymGetSourceFileFromToken兩套API,都可以用來獲得特定源碼的下載URL,然後把這個地址用上面兩個方法處理一下即可。
注意:目前的實現只是個原型,需要手動下載和配置.pdb檔案,並且直接發起大量的非同步http請求,對網速慢的朋友,可能需要用 -i 參數增加逾時時間(確實15分鐘)