在沒有介面的情況下正常降級
因為控件可能不支援 IUnknown 以外的任何介面,所以容器在遇到任何特定介面時,必須正常降級。
人們可能會質疑控件的實用性,只不過是IUnknown。 但請考慮當容器將對象辨識為控件時,控件從容器的視覺程序設計環境 (例如 VB) 接收的優點:
- 物件的按鈕會出現在工具箱中。
- 您可以將物件從工具箱拖曳至表單,以建立物件。
- 您可以為物件提供可視化程式設計環境中可辨識的名稱。
- 上述的相同名稱可以立即用於撰寫相同窗體上控件的任何其他程式碼(甚至是不同的表單)。
- 容器可以針對該物件中可用的任何事件,自動提供程式代碼進入點。
- 容器會針對任何可用的屬性提供自己的屬性流覽 UI。
當對象無法辨識為控件時,它可能會失去所有這些非常強大且有益的整合功能。 例如,在 Visual Basic 4.0 中,很難真正整合一些不是完全意義上控件的隨機物件,但仍可能有屬性和事件。 由於 Visual Basic 4 對控件的想法非常嚴格,因此物件不會取得上述任何整合功能。 但即使是具有 IUnknown 的控件,其中控件的存留期會決定某些資源是否存在,應該能夠取得上述的整合功能。
由於目前的工具需要一組大型控件介面來取得任何優點,因此控件通常會導致過度實作,因此它們包含的程式代碼比真正需要的還要多。 可能為 7K 的控件最終可能是 25K,這是因特網等領域的重大效能問題。 這也導致人們認為,由於實作所有介面的複雜度,人們只能使用像CDK這樣的工具實作控件,而且當這類控件需要大型 DLL OC30.DLL時,這會影響提高工作集。 如果不需要所有介面,這可讓許多開發人員撰寫非常小且輕量型的控件,並直接使用 OLE 或其他工具,將每個控件的額外負荷降到最低。
這就是為什麼本附錄會將控件辨識為任何具有 CLSID 和 IUnknown 介面的物件。 即使只有 IUnknown,具有程式設計環境的容器也應該能夠提供至少功能 #3 和 ) 登錄專案,它也會取得 #1 和 #2。 如果物件為某些事件集提供 I 連線 ionPointContainer (和 IProvideClassInfo 一般),則會取得 #5,如果它支持屬性和方法的 IDispatch,則會取得 #6,以及在容器中取得更好的程式代碼整合。
簡言之,對象應該能夠實作與 IDispatch 一樣少,以及透過 I 連線 ionPointContainer 公開的一個事件集,以取得上述所有視覺功能。
考慮到這一點,下表描述容器在沒有任何可能介面的情況下可能執行的動作。 請注意,只有這些介面會列出容器會直接透過 QueryInterface取得。 其他介面,例如 IOleInPlaceActiveObject,是透過其他方法取得。
介面 | 介面不存在的意義 |
---|---|
IViewObject2 |
控件沒有繪製本身的視覺效果,因此沒有明確的提供範圍。 在運行時間中,當這個介面不存在時,容器不會嘗試繪製任何專案。 在設計時間中,容器至少必須針對這類控件繪製某種名稱的預設矩形,因此可視化程式設計環境中的使用者可以選取物件,並查看其存在的屬性、方法和事件。 處理 IViewObject2 的缺席對於良好的視覺程式設計支持至關重要。 |
IOleObject |
控件不需要月臺,也不需要參與任何內嵌物件配置交涉。 容器可能預期來自此介面的任何資訊(例如控制範圍)都應該填入容器提供的預設值。 |
IOleInPlaceObject |
控件不會就地使用中 (例如標籤),因此絕不會嘗試以這種方式啟用。 其唯一的啟用可能是其屬性頁。 |
IOleControl |
控件沒有助記鍵,也不會使用環境屬性,而且不會在意容器是否忽略事件。 如果沒有這個介面,容器就不會呼叫其方法。 |
IDataObject |
控件不會提供任何屬性集,也不會提供任何可快取的視覺轉譯,因此容器會選擇在此介面缺席的情況下快取某些默認簡報(特別是支援CF_METAFILEPICT),並停用任何屬性集相關功能。 |
IDispatch |
控件沒有自定義屬性或方法。 容器不需要嘗試在此案例中顯示任何控件屬性,而且應該不允許容器無法辨識為屬於其本身擴充控件的任何自定義方法呼叫(可能支援方法和屬性)。 由於擴充控件通常會將特定 IDispatch 呼叫委派給控件,因此延伸控件完全不應該預期控件具有 IDispatch 。 |
I 連線 ionPointContainer |
控件沒有事件,因此容器不需要考慮處理任何事件。 |
IProvideClassInfo IProvideClassInfo2 |
控件沒有類型資訊或事件,或容器必須透過控件的登錄專案進入控件的類型資訊。 這個介面的存在是優化。 |
ISpecifyPropertyPages |
控件沒有屬性頁,因此如果容器有任何UI會叫用它們,容器應該停用該UI。 |
IPerPropertyBrowsing |
控件本身沒有顯示名稱、沒有預先決定的字串和值,也沒有頁面對應的屬性。 此介面幾乎一律用於產生容器使用者介面,因此如果沒有此介面,就會停用這類UI元素。 |
IPersist* |
控件沒有可說的持續性狀態,因此容器不需要擔心儲存任何控件特定的數據。 當然,容器會以自己的窗體或文件儲存控件的相關信息,但控件本身沒有任何可參與該信息的資訊。 |
IOleCache IOleCache2 |
物件不支援快取。 容器仍然可以只使用 CreateDataCache 建立數據快取本身來支援快取。 |