Windows 8 – The Language Projection

在歷經兩個版本後,Windows 8來到了Release Preview階段,在穩定性及完整性上也更加的成熟,對於我而言,相對於全新的UI界面,

核心架構更能引起我注意

/黃忠成

 

 

從架構圖開始

 

  在歷經兩個版本後,Windows 8來到了Release Preview階段,在穩定性及完整性上也更加的成熟,對於我而言,相對於全新的UI界面,

核心架構更能引起我注意,尤其是圖1的這張架構圖。

 

圖1

在這張圖中,Language Projection是我最好奇的部分,就目前所得到的資訊,Language Projection是Windows 8能同時支援

WinJS/.NET(CLR)/CRT(C++)開發的關鍵,Lanague Projection的主要功能可以簡化為圖2的架構。

圖2

簡略的說,透過Language Projection,程式語言能更容易與Windows Runtime API溝通,未來在Windows Runtime API有所更新時,

程式語言也能更快的反應這個更新。

 

不過,這些是字面上的說法,我很好奇這個Lanague Projection實際上是如何運作的,所以開始了一趟尋根之旅。

 

 

Windows API and Windows Runtime API

 

  有點年紀的開發者應該都知道,當開發Windows 應用程式時,不管是直接還是間接,實際上都是與從Windows初版便存在的Windows API打交道,

而這些API本身是以C語言開發的,例如送訊息給某個視窗是使用SendMessage,把視窗關掉是送WM_CLOSE之類的。

 

  隨著Windows的版本更迭,Windows API數量不停的增加,有些是功能的新增,有些則是因應新時代的變動(譬如因應Unicode的時代,而出現了

Unicode及非Unicode版本(SendMessageA、SendMessageW)),大量的API造成了維護的困難,也讓開發者的學習曲線更陡峭。所以,Microsoft的

RD不僅一次的想對Windows API做出改革的動作,第一次嘗試改革動作是在Vista,但後來因為相容性而作罷,第二次是WPF,只是結果大家都看到了,

Windows API難以撼動已是鐵的事實,至少在未來幾年都是如此。

 

  既然無法取代,那麼只好先循共存之路,Windows Runtime API便是這種情境下的產物,其完全以C++重新開發,充分應用了物件導向的特性,

例如介面、Namespace、類別等等,在掃除了原本C語言開發之Windows API缺點的同時也保留了Native Code的高效能特點。

  由於是重新設計,針對目前開發的潮流做出因應也是自然的,Windows Runtime API在設計之時即考慮到了如何適應多種語言,所以提出了

Lanaguage Projection的概念,其中有一個關鍵的設計就是Windows Metadata。

 

Windows Metadata

 

   與傳統Windows API以C Header file為主的API定義模式不同,Windows Runtime API的定義是放置於Windows Metadata中,所謂的Windows Metadata 

指的是一個個的.winmd檔案,位於Windows 8的Windows\System32\WinMetadata目錄中,其格式遵循了.NET Metadata定義,也就是Binary格式。

 

  這是為了解決以往Windows API以C Header file為主所帶來的多語言相容性問題,在以前,假如不是使用C/C++的話,語言的提供者必須自己由

C Header file轉換為該語言可以認得的格式,例如DELPHI就得由C Header file轉成.pas,不只是函式,還有結構,型別等問題需要處理。

 

   一旦變成一個可共通的Binary格式,語言的提供者只需要針對此檔案處理即可,比起處理文字檔來說,Binary反而更容易移轉及解讀。尤其

Windows Runtime Core還提供了相對的API,讓語言提供者可以在不需自行解析.winmd的情況下,列舉其中的類別及函式。

 

以Visual C++(C++/CX)來說,編譯器與Language Projection的關係如圖3。

圖3

在程式撰寫期間,IDE就直接將.winmd做為參考,解析其內部的類別定義,在執行時則交由RoActiveFactory 函式(Windows Runtime Core API之一)

來載入Windows Runtime API中的物件。

 

當使用Native C++(Visual C++ 11以外的C++,like C++ Builder….)時,情況有些不一樣,如圖4。

圖4

因為傳統的C++編譯器並不認得.winmd檔案,所以必須透過一個工具將Windows Metadata中的類別定義產生成C++ Header files及Wrapper類別

供編譯器編譯程式時使用,其中的Wrapper類別未來應該會由編譯器的Runtime代勞,也就是說,完美演化的狀態應該是想提供Windows RT支援的

C++編譯器最後都會變成如Visual C++(C++/CX)般直接於編譯時期動態參考.winmd來產生出Wrapper類別。

 

在CLR,也就是Managed code情況下與Visual C++(C++/CX)一樣可以直接參考.winmd,不同的是編譯器並不會編譯出呼叫RoActiveFactory的程式碼,

而是由CLR Runtime於執行時期處理。

圖005

WinJS這種直譯型語言則是交由Win JS Host(WWAHost)負責處理。

圖006

Delphi的話也是循Native C++途徑完成。

圖007

值得注意的是,Visual C++(C++/CX)/CLR/WinJS都是直接參考.winmd,這意味著未來Windows Runtime API有所變動的話,

Visual C++(C++/CX)/CLR都只要直接重新編譯即可得到新功能,而WinJS也只需要改動程式即可,不需像以往一樣需等待開發工具提供對應的

header file及Library了(當然,未來我想會直接支援WinRT的Native編譯器都會循Visual C++(C++/CX)的模式開發)。

 

Windows Metadata and COM/Windows API

 

  基本上,就一個由Windows API開始就接觸的開發者而言,很難不去想Windows Metadata到底為何而生的,因為如果是以Binary易讀(我指編譯器)為出發點的話,

其實舊有的COM也沒差到哪去,Type Library本身也是為了容易被編譯器認得而設計的檔案格式,那Windows Metadata究竟好在哪裡?

 

  事實上,舊有的COM有兩個缺點 ,不具備繼承及沒有Namespace(命名空間)的觀念,這兩者是誘發Windows Metadata誕生的主要條件。

  從COM角度來看,WinRT其實就是COM概念的另一個實作體,只是其提供了原本COM沒有的命名空間及繼承的能力,由Windows Metadata

取代了原來的Type Library地位。

 

  對COM熟悉的開發者可以使用原本COM的方式來呼叫Win RT Compnent,差別在於原本的CoInitialize被RoInitialize所取代,對此有興趣的開發者,

可參考Visual C++所提供的WRL(Windows Runtime Library),其大概是由Native/COM角度了解WinRT最快的途徑。 

Windows Runtime Library