新的Interop
在Visual Studio .NET 2003的所有基於 .NET Framework的語言當中,Visual C++ 2005提供了最好的interop功能。它可不像是紙上談兵,如今具有了足夠的能力來實現真實世界中的情境,一個最好的例子就是把Quake II移植到 .NET Framework平台上,而Visual C++ 2005則更加擴充了這項功能。
在本地和託管世界中,.NET有四種主要的方法可進行interop。對COM的interop可使用RCW(Runtime Callable Wrappers)和CCW(COM Callable Wrappers),而CLR主要負責類型調度(除了在極少數情況下,使用了定製的調度器),但這些調用是開銷巨大的。因為介面極其複雜,所以必須加倍小心,否則將會導致嚴重的效能損失,而且還要保證這些封裝器的底層組件是最新版本的。這就是說,當你試圖引入大量本地COM代碼時,只有對一些簡單的情況而言,COM interop才非常有用。
第二種使用interop的方法是通過P/Invok,一般通過使用DLLImport屬性,對需要引入的函數,在方法聲明上指定此屬性,根據聲明是怎樣指定的,從而決定調度怎樣處理。然而,只有在一個DLL通過export屬性有輸出函數時,DLLImport才能起到作用。
如果想從本地代碼中調用Managed 程式碼,可選擇CLR宿主。在這種情況下,本地程式必須做好一切相關工作:設定宿主、綁定運行時、啟動宿主、取回相應的AppDomain、設定調用上下文、定位所需的程式集和類、在相應的類上叫用作業。這就是一個穩健的解決方案需要做的一切事情,很單調乏味,並且需要很多人工代碼。
第四種,也可能是最容易和高效的一種方法,就是使用C++中的interop,通過設定/clr,編譯器將產生MSIL代碼——而不是本地機器碼,其中包括了那些使用內聯彙編的函數和CPU特定指令集,如SSE;/clr正是Quake II移植到 .NET平台的關鍵之處。在此不需要加入其他任何二進位代碼,只是簡單地包含一些相應的標頭檔,託管C++就能和本地C++互相調用,對開發人員來說,不需做任何工作就能實現這一點,何樂而不為呢。實際上,編譯器處理了相應轉換器的建立,並在託管和本地兩個世界中來回奔波。
對C++開發人員來說,以上的結果還涉及到更多的方面,其中一個,就是在Visual Studio .NET 2002和Visual Studio .NET 2003中聲名狼藉的混合DLL載入問題。如果你在載入器鎖(loader lock)中運行本地代碼,但又引用了程式集中一個未被載入的託管類型,此時,CLR會調用LoadLibrary來載入這個程式集。LoadLibrary會試圖取得載入器鎖,在這一點上,造成了程式死結。而這個問題,在新版本的Visual Studio中,已經解決了。
雖然/clr給C++開發人員帶來了巨大的好處,但也有一些不利的方面。如之前所提到的,/clr會產生包含本地和Managed 程式碼的映像檔案,這在有些時候會帶來問題。首先,這些混合的映像檔案不遵從CLI,它們有本地進入點,當超出託管邊界時,會帶來嚴重的轉換效能損失。但最重要的是,本地進入點會對使用程式集和反射(reflection)的工具造成嚴重的影響。反射之前要先檢查一個映像檔案,此時必須先載入並運行程式集,只有在所有的初始化完成之後,反射才可能檢查中繼資料,而此時卻因為包含了本地進入點,造成反射不能正確地載入一個託管程式集。
此外,Visual Studio .NET 2003隻在極少數情況下,能產生可驗證代碼,即使產生了,也需花一大番氣力。然而,MSIL對不可驗證指令提供了第一類的支援(指標演算法、間接載入、訪問本地堆),可驗證代碼也使你可參與到可信賴計算中,反過來,也極大地豐富了Visual Studio 2005的功能。單擊部署基於局部可信賴計算,就像Managed 程式碼宿於SQL Server 2005中一樣。Visual C++ 2005開發小組一個主要目標,就是使編譯器可產生非混合及可驗證映像,為此引入了兩個新的編譯器選項:/clr:pure和/clr:safe,但在研究這兩個新選項之前,還需要弄清楚C++ interop是怎樣工作的。