ArcGIS Engine 開發 (三)COM技術中的IUnknown介面和QueryInterface(介面查詢)
IUnknown 介面是元件物件模型(COM)中的基礎介面。COM規格書中規定COM物件至少要實現此一介面,而且其他所有的COM介面都需要派生自IUnknown介面。 IUnknown提供所有COM物件都支援的兩種基本特性:
- 利用引用計數來進行物件生命週期管理;(控制物件生命週期)
- 以及訪問許多事先定義的介面。(介面查詢)
IUnknown介面會包括一個指向虛擬方法表(英語:virtual method table)的指標,虛擬方法表是一個有許多函式指標的列表,函式指標會指向許多實現IUnknown介面所宣告的函式,以和介面中宣告順序相同的方式排列。而程序內呼叫產生的開銷(英語:Overhead (computing))大致和C++中呼叫虛擬方法的開銷相近。
方法
物件生存期由兩個方法控制,AddRef
和Release
,以及內部引用計數器。每個物件都必須具有IUnknown的實現來控制其生命週期。無論何時建立或複製介面指標,都會呼叫AddRef
方法,當客戶端不再需要此指標時,將呼叫相應的Release
方法。當引用計數達到零時,物件會自行銷燬。
客戶端還使用IUnknown獲取物件上的其他介面。QueryInterface
是客戶端在需要物件上的另一個介面時呼叫的方法。當客戶端呼叫QueryInterface
時,該物件提供一個介面並呼叫AddRef
。實際上,任何COM方法都有責任返回一個介面來代表呼叫者遞增物件的引用計數。當不再需要該介面時,客戶端必須呼叫Release
AddRef
。
IUnknown介面中有三個方法:QueryInterface
, AddRef
, and Release
:
[ComImport(), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("00000000-0000-0000-C000-000000000046")] public interface IUnknown { [PreserveSig] int QueryInterface(ref Guid riid, out IntPtr ppvObject); [PreserveSig] uint AddRef(); [PreserveSig] uint Release(); }
QueryInterface
可以讓呼叫此物件的程式可以確認此物件是否支援特定的介面,若是支援,則參考到此物件在特定介面下的實現。這個方法類似C++的dynamic_cast<>或是Java或是C#的casts。此方法在給定一個對應特定介面的全域性唯一識別符號(一般也稱為介面識別符號或是IID,如AE中GUID)時,可以提供一個指定特定介面的指標。若COM物件不支援此介面,會回覆E_NOINTERFACE錯誤。AddRef
是在新的客戶端程式要訪問此物件時,讓計數值加一,會回傳更新後的計數值。Release
是在客戶端程式已結束訪問此物件,讓計數值減一,會回傳更新後的計數值,若計數值已變為零,會自動刪除此一COM物件。
IUnknown本身的介面識別符號為{00000000-0000-0000-C000-000000000046},IUnknown的三個方法都是純虛擬方法(宣告時都有加上= 0),因此無法定義IUnknown類別的物件,需要由其他類別繼承IUnknown,才能定義對應類別的物件。
QueryInterface
QueryInterface方法通常用首字母縮寫詞 QI 表示。
在開發COM物件時,開發人員必須遵守QueryInterface的規則。這些規則規定物件的介面是對稱的,可傳遞的和反身的,並且在物件的生命週期中始終可用。對於客戶端,這意味著給定物件的有效介面,通過對QueryInterface的呼叫,詢問該物件對該物件(包括其自身)的任何其他介面始終是有效的。由於時間或安全性限制,不可能支援介面並隨後拒絕訪問該介面。
QueryInterface的規則規定物件的介面是自反的,對稱的和可傳遞的。始終可以在物件上保持有效的介面指標,以獲取該物件上的任何其他介面。
當請求特定介面時,QueryInterface方法可以為該請求的介面返回已分配的記憶體塊,或者它可以分配新的記憶體並返回該記憶體。必須返回同一塊記憶體的唯一情況是請求IUnknown介面。比較兩個介面指標以檢視它們是否指向同一個物件時,重要的是不執行簡單的比較。要正確比較兩個介面指標以檢視它們是否屬於同一物件,必須同時查詢它們的IUnknown介面,並且必須對IUnknown指標執行比較。通過這種方式,IUnknown介面被稱為定義COM物件的標識。
由於IUnknown是所有COM物件的基礎,因此通常在任何ArcObjects文件和類圖中都沒有對IUnknown的引用。
在AE中介面跳轉方法
IMap pMap;
IActiveView pActiveView;
pMap = axMapControl1.Map;
...
pActiveView = pMap as IActiveView;//方法一
// pActiveView = (IActiveView) pMap;//方法二