ATL Internals: Working with ATL 8 (2nd Edition) DOWNLOAD

ATL Internals: Working with ATL 8 (2nd Edition) 

Four leading Windows programming experts systematically reveal ATL’s inner workings, explaining not just how ATL works, but why it works the way it does. Client-side developers will master ATL’s resources for windowing, COM control, MFC integration, web service proxy generation, and more. Server-side programmers will discover ATL’s full COM server and object services, and its extensive support for high-throughput, high-concurrency web applications, and services. Every Windows developer will learn powerful ways to increase flexibility, reduce overhead, and maximize transparency and control. *Discover ATL’s internals through diagrams, example code, and internal ATL implementation code *Walk through wizards that simplify ATL usage in common applications *Master string handling in C++, COM, and ATL *Leverage ATL smart types, including CComPtr, CComQIPtr, CComBSTR, and CComVariant *Understand and choose the right options for implementing IUnknown *Create glue code that exposes COM objects from COM servers *Use canned interface implementations to support object persistence, COM *collections, enumerators, and connection points *Build standalone applications and UI components with ATL window classes and controls *Use ATL Server to develop web applications that run on Microsoft IIS

這是ATL技術內幕第二版(2006年7月份出版的新書),不知道國內會有誰翻譯它,這幾年一直都沒有ATL/COM的新書或者譯作出版,希望潘老師能翻譯它哦。

網上已經有人在翻譯了,

翻譯:賴儀靈

download:

ATL Internals: Working with ATL 8 (2nd Edition) 

Table of Contents  | Index  

     Copyright
     The Addison-Wesley Object Technology Series
     Foreword to the Second Edition
     Foreword to the First Edition
     Preface
     Acknowledgments
     About the Authors
     Chapter 1.  Hello, ATL
        What Is ATL?
        Creating a COM Server
        Inserting a COM Class
        Adding Properties and Methods
        Implementing Additional Interfaces
        Support for Scripting
        Adding Persistence
        Adding and Firing Events
        Using a Window
        COM Controls
        Hosting a Control
        ATL Server Web Projects
        Summary
     Chapter 2.  Strings and Text
        String Data Types, Conversion Classes, and Helper Functions
        The CComBSTR Smart BSTR Class
        The CComBSTR Class
        The CString Class
        Summary
     Chapter 3.  ATL Smart Types
        VARIANTs, SAFEARRAYs, and Interface Pointers
        The CComVariant Smart VARIANT Class
        The CComSafeArray Smart SAFEARRAY Class
        The CComPtr and CComQIPtr Smart Pointer Classes
        The CAutoPtr and CAutoVectorPtr Smart Pointer Classes
        ATL Memory Managers
        Summary
     Chapter 4.  Objects in ATL
        Implementing IUnknown
        The Layers of ATL
        Threading Model Support
        The Core of IUnknown
        Your Class
        CComObject Et Al
        ATL Creators
        Debugging
        Summary
     Chapter 5.  COM Servers
        A Review of COM Servers
        The Object Map and the CAtlModule Class
        The Object Map
        Methods Required of an Object Map Class
        The CAtlModule Class
        CComCoClass Revisited
        ATL and the C Runtime Library
        Summary
     Chapter 6.  Interface Maps
        Recall: COM Identity
        Table-Driven QueryInterface
        Multiple Inheritance
        Tear-Off Interfaces
        Aggregation: The Controlling Outer
        Interface Map Chaining
        Just Say "No"
        Debugging
        Extensibility
        Summary
     Chapter 7.  Persistence in ATL
        A Review of COM Persistence
        ATL Persistence Implementation Classes
        The Property Map
        The Persistence Implementations
        Additional Persistence Implementations
        Adding Marshal-by-Value Semantics Using Persistence
        Summary
     Chapter 8.  Collections and Enumerators
        COM Collection and Enumeration Interfaces
        Enumerating Arrays
        Enumerating Standard C++ Collections
        Collections
        Standard C++ Collections of ATL Data Types
        ATL Collections
        Object Models
        Summary
     Chapter 9.  Connection Points
        A Review of Connection Points
        Creating an ATL-Based Connectable Object
        Creating an Object That Is an Event Recipient
        How It All Works: The Messy Implementation Details
        Summary
     Chapter 10.  Windowing
        The Structure of a Windows Application
        CWindow
        CWindowImpl
        CDialogImpl
        Window Control Wrappers
        CContainedWindow
        Summary
     Chapter 11.  ActiveX Controls
        A Review of ActiveX Controls
        The BullsEye Control Requirements
        Creating the Initial Control Using the ATL Wizard
        The Initial BullsEye Source Files
        Developing the BullsEye Control Step by Step
        Summary
     Chapter 12.  Control Containment
        How Controls Are Contained
        Basic Control Containment
        Hosting a Control in a Dialog
        Composite Controls
        HTML Controls
        ATL's Control Containment Limitations
        Summary
     Chapter 13.  Hello, ATL Server: A Modern C++ Web Platform
        The Microsoft Web Platform (Internet Information Services)
        The Simplest ISAPI Extension That Could Possibly Work
        Wrapping ISAPI
        ATL Server
        Web Services in ATL Server
        Summary
     Chapter 14.  ATL Server Internals
        Implementing ISAPI in ATL Server
        Server Response Files
        An Example Request Handler
        Handling Input
        Session Management
        Data Caching
        Summary
     Appendix A.  C++ Templates by Example
        The Need for Templates
        Template Basics
        A Different Kind of Polymorphism
        Function Templates
        Member Function Templates
        Summary
     Appendix B.  ATL Header Files
     Appendix C.  Moving to ATL 8
        Strings, Character Sets, and Conversions
        Shared Classes with MFC
        Implementing COM Servers
        ActiveX Controls and Control Hosting
        ATL_MIN_CRT Changes
        Summary
     Appendix D.  Attributed ATL
        Fundamentals of ATL Attributes
        The Future of Attributed ATL
        Summary
     Index

===================================================

潘老師關於這本書第一版的書評:

面對計算機圖書市場的繁榮景象,我經常感嘆今天學習計算機開發技術的同道們是多麼幸運。十年前,我們學習計算機語言非常不容易,要掌握各種開發工具只有靠自己的摸索和極少量的參考手冊。我記得,94年我學習Visual C++和MFC的時候,基本上只有靠軟件自帶的聯機幫助;現在情形大不同了,書店中的計算機圖書琳琅滿目,關於Visual C++和MFC的書籍尤其多。有幾位編輯朋友勸我寫一點這方面的書,我覺得不大有必要了,因爲Visual C++的好書已經不少了,適合各種讀者層次的書籍幾乎都可以買到,而且有一些書還相當不錯。不過,在98年的時候,我感覺關於COM書籍實在太少,幾乎沒有,於是我下定決心,自己寫一本關於COM的書籍,在99年底的時候由清華出版社出版。很快地,關於COM的書籍已經很多了,有些國外的名著也相繼引入國內。從這十多年的計算機開發技術歷史來看,一門技術只要有很多的書籍來介紹,那麼這項技術很快就會普及,否則就難以推廣。

說到COM,相信在Windows平臺上有過開發經驗的朋友一定接觸過,它是Windows操作系統的基本軟件模型,從93年建立以來,爲Windows平臺的推廣和發展做出了不可磨滅的貢獻,而且其自身還在不斷髮展。但是要真正開發COM組件並不是很輕鬆,在Visual C++中,我們既可以使用MFC也可以使用ATL。MFC完全面向Windows應用,它用C++的封裝技術建立了一套適合於開發Windows應用的C++類庫,雖然在後期的版本中MFC提供了大量的COM支持,但是從基本的設計結構上講,MFC不適合於開發專業的COM組件,它適合於在Windows應用的基礎上提供相應的COM支持。

ATL則不同於MFC,它完全面向COM組件,其技術路線也不同於MFC,MFC使用的是C++中的繼承、封裝、嵌套等常規技術,而ATL使用了C++中模板、多繼承等高級技術,甚至還用到了STL。所以學習和使用ATL要求我們必須熟悉這些C++高級特性。另一方面,ATL結構完全針對COM中的諸多規範,這就要求使用人員必須非常瞭解COM規範,纔有可能真正把ATL用好。

雖然目前關於MFC的書籍很多,但是完全介紹ATL的書籍非常少,甚至根本沒有,這不能不說是一個遺憾。我有幸在今年2月份看到一本ATL的英文原版書《ATL Internals》,本文將爲大家介紹這本書。

在看這本書之前,我對ATL已經有了基本的瞭解,98年底由於寫作的需要,我曾經讀過ATL的部分源碼,對於ATL的基本結構還算清楚。我剛開始看到這本書的時候,快速讀了一章,並沒有感覺這本書有多好,後來由於工作忙碌的原因,一直沒有得閒,直到最近,我才仔細把這本書讀了一遍,感覺這是一本不可多得的好書。以前我很少仔細閱讀開發技術類的書籍,一則是由於自己讀書太慢,二則是往往開發技術類的書籍不大值得精讀。但是這本書我讀得很仔細,因爲這本書把ATL的精華幾乎全表述出來了,ATL中的許多內容都能讓你爲之心動,作爲一個程序員,這也是一個學習和提高的機會。

我寫這篇文章的意圖不僅僅是向讀者介紹這本書,我也希望能夠把我在閱讀過程中的心得與大家分享。同時我還希望能夠按照這本書的路線,向大家介紹一下ATL的結構和機理。

準備閱讀

《ATL Internals》由Addison-Wesley出版社出版,作者爲Brent Rector和Chris Sells,出版時間爲1999年2月,全書600多頁。關於這本書的背景知識可能對於許多COM迷和ATL迷來說很有意思。首先,這本書的序言是由ATL的發明人Jim Springfield所撰寫,在序言中,Jim介紹了ATL的歷史,對於書中所介紹的內容大加讚賞,稱讚“閱讀此書可以學到許多閱讀源碼所不能掌握的內容”,在序言的最後,Jim還談到了ATL的將來。

其次,在作者寫的自序中,他們提到了ATL離不開COM,要想掌握ATL,就一定要先掌握COM。ATL是一個產生C++/COM代碼的框架,就如同C語言是一個產生彙編代碼的框架,這個觀點頗爲新穎,仔細想來,確是如此。作者特別推薦了Don Box的書《Essential COM》,其實在英文書中,COM書籍不少,這顯示出兩位作者與Don Box的關係非同一般。我記得Don Box也曾經推薦過《ATL Internals》這本書,如果讀者有機會到亞馬遜網上書店(www.amazon.com)看看本書的書評就可以知道他們之間有很親密的關係,其中作者之一Chris Sells與Don Box以及另外兩人合作寫了一本COM的書《Effective COM》(本書文中有多處推薦了這本書)。我相信他們的互薦是基於相互之間絕對了解的基礎之上的,他們都是COM頂尖高手,也是ATL頂尖高手,讀者經常可以在MSJ(Microsoft System Journal)雜誌上看到他們的文章。

誠如作者所言,閱讀此書需要極強的預備知識,按照我閱讀此書之後的理解,讀者在閱讀此書之前應該有以下幾方面的準備知識:

 

一定要懂COM。ATL完全針對COM,許多細節都是爲了更好地實現COM而設計。如果讀者僅僅看過《Inside COM》(清華大學出版社出版的《COM技術內幕》),那麼要想通篇閱讀《ATL Internals》還不夠,建議讀者再找其他的資料看一看。

 

 

一定要懂C++的模板技術。ATL充分發揮模板的優勢,其整個體系結構完全建立在模板的基礎之上,如果讀者不熟悉模板,那麼幾乎無法閱讀ATL。

 

 

基本瞭解STL(可選)。ATL的集合類和枚舉類用到了STL,當然,如果讀者不懂STL,基本不影響全局的理解,但是STL中容器的思想和COM集合對象的思想是相通的,ATL把兩者有機地統一起來了。

 

所以說,《ATL Internals》是一本起點很高的書,原因在於ATL是一門起點很高的技術。據我所知,現在有許多程序員已經在使用ATL了,這是好現象,說明我們國內的程序員水平相當高,雖然我們的資料信息還不夠豐富(至少對於ATL而言是這樣),但是我們仍然緊跟這些新的技術。儘管如此,要想真正用好ATL,一定要了解ATL的機理,這不同於MFC的情形。假如我們不懂MFC的機理,一樣可以做出很好的程序,利用MFC,在不懂OLE細節的情況下,一樣可以提供OLE的支持。ATL要求我們很細緻地調節它的類,根據需要選擇合適的模板類,必要時還要修正它的行爲。ATL儘管已經到了3.0版本,但是仍然有不少的錯誤,這本書已經指出了一些錯誤,但我相信肯定還會有更多的錯誤,這對程序員提出了更高的要求,確實是這樣,因此結論是:使用ATL一定要懂ATL!

儘管我這樣說,但我還是認爲ATL是一項好技術、是一個好的COM模板類庫。而且我也深感好書對於ATL程序員的重要性,有些東西是不能從源碼和參考手冊獲得的,既然我看到了這本好書,那我應該把這本書介紹出來,讓大家知道這本書。也讓大家分享我的體會。如果有那家出版社能夠引進這本書的話,則是我們廣大ATL程序員的福音了。

內容介紹

下面我按照《ATL Internals》的敘述順序,逐項介紹ATL的內容,希望讀者不僅能夠了解本書的內容,也能夠藉此瞭解ATL的機理。原書共包括十一章,我按照每一章所介紹的內容把這十一章分成四個部分。

 

第一部分 ATL的使用和功能展示

這一部分篇幅很小,只有短短的一章內容,讀起來非常輕鬆。初時我以爲整本書都是這樣的,所以感覺這也是一本指南性質的書,當時就沒有太重視。

在這一章裏,作者簡單介紹了ATL的概念,然後通過AppWizard和ATL Object Wizard創建COM服務程序和COM對象類的過程逐項介紹了Wizard中各個選項的含義。有了基本的工程框架和對象類框架之後,作者開始展示ATL的一些其他特性:

 

添加屬性和方法。

 

 

增加另外的接口。

 

 

提供腳本支持。

 

 

提供永久特性,增加永久接口。

 

 

加入事件支持,利用COM的可連接對象特性。

 

 

對窗口的支持。

 

 

實現組件類別(component category)支持。

 

 

增加用戶界面特性,用ATL開發ActiveX控制。

 

 

怎樣包容ActiveX控制。

 

作者介紹這些內容非常簡捷,但是能夠讓讀者有一些基本的印象,在閱讀後續內容之前對ATL有一個清晰的思路。如果讀者對COM比較熟悉而且曾經有過ATL開發經驗的話,讀這部分內容會非常輕鬆。

 

第二部分 ATL實現COM:基礎部分

這部分介紹了ATL實現COM的基本方法,包括四章內容,分別如下:ATL Smart Types、Objects in ATL、COM Servers、Interface Maps。這四章內容是ATL的精華所在,也是這本書的精華所在,如果說全書其他的內容都是可讀可不讀的話,那麼這部分的內容則是不可不讀的。

第二章介紹了ATL的智能類型(smart type),包括字符串類型、VARIANT類型以及接口指針類型。COM規範要求所有的字符必須用雙字節字符,不是我們常用的ANSI字符,所以對於字符串的處理往往是我們編程工作中所必須面對的任務,雖然談不上有多困難,但是往往要花掉我們不少時間來處理這些瑣事。作者在這一章首先介紹了與字符表達有關的許多概念以及多種轉換途徑,然後介紹了ATL的基本字符類型封裝類CComBSTR以及CComVariant。作者對於這兩個類的介紹非常細緻,指出了每個成員函數的一些細節,甚至個別缺陷。我在閱讀時,對這一部分很感興趣,雖然這些內容我基本上都知道,每個成員函數也可以通過ATL的源碼得到其細節知識,但是讀下來仍然感覺受益匪淺。反過來,這一章最後部分介紹的智能指針類,我的興趣並不大,大概是我對智能指針一直存有偏見的原因吧,不過智能指針在ATL中用得很廣泛,書中後面部分到處可見智能指針的應用。ATL的智能指針封裝類是一個比較典型的、功能全面的智能指針模板類,有興趣的讀者可以讀一讀這兩個類(CComPtr和CComQIPtr)的源碼。

第三章的開篇就是COM的套間(apartment)和COM的線程模型,雖然篇幅很短,但是這些內容很重要。因爲ATL是一個支持多線程模型的COM類庫,爲了支持多線程,代價是非常昂貴的,要求COM對象的每一個細節都要涉及到併發的可能性,ATL既要考慮到代碼的大小,又要考慮到代碼的運行效率,所以ATL用了許多技巧來保證其方案的有效性。介紹了線程模型之後,作者又講述了實現COM基本接口IUnknown的一些考慮要點。之後再給出ATL對象的層次圖,如果讀者對於ATL中類的結構還不瞭解的話,那麼這個層次圖可以讓你知道Wizard生成的類與其他的類有什麼樣的關係,這個圖可以指導你閱讀完後續的兩章。有了這些準備知識之後,作者詳述了ATL爲對象提供的線程模型支持,限於本文的篇幅,我不能詳細講述這些內容。

講述了線程模型之後,作者進一步介紹COM對象的基類CComObjectRootEx實現IUnknown相關的方法,有了線程模型的基礎後實現引用計數非常簡單,但是QueryInterface成員函數不是基類就能夠完成的,它需要用到CComObjectRootEx派生類也就是Wizard生成的類所提供的接口信息。ATL通過接口映射表的形式提供對象的接口信息,通過多繼承的方式實現多接口的支持。

COM對象的實例化非常與衆不同,因爲Wizard生成的類還只是一個抽象類,所以它不能夠直接被實例化,即我們不能用new操作符生成一個對象。真正的對象類應該是CComObject,它實現了IUnknown的所有方法,並提供了一個用於創建對象的函數。如果對象支持聚合模型的話,那麼最終的對象類應該是CComAggObject。爲了統一兩種情況以便減小最終的代碼量,ATL提供了CComPolyObject類作爲最終的對象類。

ATL的創建過程並不複雜,但是它提供了多階段構造(multiphase construction),允許我們在創建過程中加入更多的控制代碼,獲得更大的靈活性。作者對這一部分的介紹甚爲細緻,還解釋了ATL_NO_VTBL宏即novtbl編譯指示符的含義,如果一個類聲明瞭novtbl指示符,那麼編譯器在派生類的構造過程中不爲基類產生虛表(vtable)。

這一章的內容是ATL的基礎,讀起來並不難,但是一定要清楚ATL類的層次關係,否則很容易陷入ATL的複雜語法之中。

第四章介紹COM服務程序的ATL支持,作爲一個COM服務程序,它的主要任務是管理對象的註冊、爲每個對象提供一個類廠、以及自身的生存期管理。對於進程內組件和進程外組件還需要區別對待。ATL實現的對象分爲可通過類廠創建的對象和不可創建的對象,不可創建的對象不需要類廠的支持,往往爲服務程序中其他的對象所用。ATL實現這些功能主要通過對象映射表和CComModule類。

對象映射表是一個全局表,其中包括當前服務程序所實現的所有對象類,表中的每一項包括對象的CLSID、註冊該對象信息的函數、創建類廠的函數、創建對象的函數等等。有了這些信息,服務程序就可以管理它所支持的每一個對象類。回過頭來,爲了讓對象映射表管理好這些工作,每一個對象類也需要提供相應的函數或者信息,比如對象的註冊函數、創建函數等。ATL的註冊功能很強,除了標準對象的註冊支持之外,它可以提取出內嵌在資源中的註冊腳本文件(Registry Script File),實現更爲靈活、功能強大的註冊操作。對於使用者來說,只要編寫資源腳本再加上一個宏聲明即可。ATL對於類廠的支持在CComClassFactory類中實現,對象類從CComCoClass繼承一個類廠創建類的定義_ClassFactoryCreatorClass。CComClassFactory類的實現沒有用到模板參數,而是內嵌一個創建函數,由該函數完成實際的創建工作。這個過程並不複雜,書中講得很清楚,而且書中還介紹了ATL實現IClassFactory2的方法。

CComModule是COM服務程序的主線,當我們創建一個ATL工程的時候,Visual C++都會爲我們生成一個CComModule派生類,並且定義一個全局變量_Module,這就如同我們在MFC工程中使用CWinApp應用類一樣。CComModule類的許多成員函數都對應了它所應該完成的任務,比如更新註冊表的操作、獲取類廠對象、註冊類廠對象(對於進程外服務程序)等。

第四章介紹的內容對於我們理解ATL工程的總體思路非常有用,結合COM規範對COM實現中的所有細節要求,ATL給出了一種高效、針對小尺寸組件的實現方案。結合第三章的內容,就構成了ATL實現COM的基本技術框架。

第五章講述ATL的接口映射表,實際上這是對第三章內容的補充,但是因爲ATL的接口映射表比較靈活,而且多接口支持對於COM對象非常重要。所以作者單獨用一章的篇幅來講述接口映射表。對於多接口的對象,COM有很嚴格的規範來指示客戶程序調用這些接口成員函數,特別是IUnknown::QueryInterface。爲了遵循這些規範,並保持一定的靈活性,ATL使用了接口映射表的技術。接口映射表的原理非常簡單,它以表的形式記錄了每個接口的IID以及接口的vtable與對象類的this指針之間的偏移,但是ATL的接口映射表並沒有這麼簡單,它以函數的形式把這樣的邏輯封裝起來,從而允許用戶使用更爲靈活的接口查詢策略。

ATL用多繼承的方法實現多接口的支持,如果兩個接口的方法名和參數重合的話,這時就會產生問題,書中介紹了一種避免名字衝突的方法,方法並不複雜,但很有效。這一章還介紹了一種被稱爲“接口着色”的技術,其實很簡單,只不過是按照COM所要求的虛表結構另行構造而已,其好處是可以實現兩個接口語義完全相同但是IID卻不相同的接口。這也體現了COM接口實現的靈活性。

除了支持多繼承方式的接口之外,ATL有一個很強大的接口支持就是對於動態接口的支持,書中稱爲“tear-off interface”。每一個動態接口類都應該從CComTearOffObjectBase派生,以後當客戶向對象請求該接口的時候,對象類會調用接口映射表中指定的創建函數創建該接口對象。

除了動態接口技術應用了接口映射表這種結構之外,還有對象類對聚合接口的支持,實現形式與動態接口非常類似,ATL對聚合的支持分有計劃聚合(planned aggregation)和盲聚合(blind aggregation),可以說,ATL對聚合的支持比較全面,但是我們在使用的時候一定要謹慎,COM中的有些特性往往隱含着潛在的出錯可能性,比如說盲聚合就是這樣的一種特性。

這一章最後介紹了接口映射表的一些訣竅,包括接口映射表的鏈結構、拒絕支持某個接口、利用接口請求進行調試、對接口映射表的擴展(比如,利用接口映射表設置後門,通過後門得到對象類的this指針;以及基於對象實例的接口請求)。這一章所講述的內容非常細節,涉及到COM規範中的許多細微的地方,讀懂這一部分並不難,但是要求讀者具有有關的COM背景知識。

以上四章內容是ATL的基石,即使把這一部分獨立出來也可以構成一本書“ATL深入淺出”,如果讀者要依靠ATL來編寫COM組件的話,那麼認真讀懂這一部分就可以奠定工作的基礎。如果有人說ATL使用C++語法非常花哨的話,那麼他們一定是指這一部分所講述的內容。由於C++模板語法本身的複雜性,加上ATL在許多模板類的定義中使用了“typedef”,再加上ATL也使用了類似MFC的宏結構,所以讀起源碼來非常晦澀。儘管作者講述這一部分內容非常有條理,但我看這幾章的時候不免要前後翻動,偶爾還要查看一下ATL的源碼。但是一旦明白了ATL的思路,又不免爲它的設計所折服。

 

第三部分 ATL實現COM:擴展部分

ATL實現COM的擴展部分包括三章內容,分別爲:Persistence in ATL(ATL的永久特性支持)、Collections and Enumerators(集合對象和枚舉器對象)、Connection Points(連接點對象)。這三章是面向COM應用層面的三個大方向,也是我們比較常用的一些COM特徵。如果讀者要全面掌握ATL的話,那麼應該讀一讀這部分。

第六章介紹ATL對COM永久機制的支持,相對來說,這一章內容的介紹讀起來要輕鬆得多,只要讀者對COM永久模型比較熟悉即可。由於COM永久模型的複雜性主要位於客戶程序一方,在對象一方只需要實現有關的幾個永久接口,當然這些永久接口與對象本身的邏輯是密切相關的。這一章前面部分回顧了IPersistPropertyBag、IPersistStream[Init]、IPersistStorage永久接口的定義和實現,然後介紹ATL對這些永久接口的實現,重點介紹了屬性映射表(Property Map)。ATL提供的永久接口的實現能夠自動對屬性映射表中的屬性進行永久處理,即提供Load和Save支持。對於屬性映射表不支持的永久內容(比如說書中所舉的索引屬性的例子),我們可以在適當的地方進行重載處理,ATL允許我們在多個地方重載這套機制。

在介紹了這幾個常用的永久接口之後,作者還介紹了IPersistMemory接口,並細緻說明了幾個永久接口公共的成員函數GetSizeMax的重要性以及作者補充的實現方法。在這一章的最後,作者還給出了一個用永久特性實現自定義列集(marshaling)的一種方法,如果讀者對自定義列集有興趣的話,可以看一看這一章最後幾頁的介紹。

第七章介紹了COM集合對象和枚舉器對象(enumerator)的ATL實現。在講述集合和枚舉器對象之前,作者先介紹了STL中的容器和迭代器(iterator),這是STL中數據組織和數據訪問的基本形式,然後作者以一個類比,指出雖然STL不能直接用於COM,但是COM提供了類似的對象組織和訪問機制,這就是COM集合對象和枚舉器對象。

COM的集合對象是構成COM對象模型的基礎,爲了在客戶程序一方特別是VB(Visual Basic)或者VBA作爲客戶程序時,它能夠方便有效地訪問集合對象,COM制定了集合對象的接口規範以及枚舉對象的接口規範。ATL實現了這些規範,並且在ATL內部,還提供了多種途徑來管理這些成員數據或者成員對象。

ATL的集合對象實現起來比較簡單,只要按照COM規範,增加集合對象所特有的屬性:Count、Item、_NewEnum即可。_NewEnum屬性把集合對象和枚舉對象聯繫起來了。在ATL中,枚舉數組類爲CComEnum,它以數組的形式管理其成員數據,值得一提的是,ATL在實現枚舉接口的時候,爲了方便對於數據的拷貝操作,專門抽象出一個被稱爲“拷貝策略”的類,由該類的靜態成員函數實施成員拷貝操作。ATL真正實現枚舉接口的類爲CComEnumImpl,它是CComEnum的基類,CComEnumImpl的實現並不複雜,唯一值得注意的是CComEnumImpl內部保存數據的方式,既可以是快照方式,也可以引用集合對象中的數據。有了這些基礎,加上上一部分介紹的ATL對象類,實現枚舉對象就非常容易了,作者在書中用一個素數集合對象的例子講述了整個過程,最終通過素數集合對象的_NewEnum屬性把它與素數枚舉對象聯繫起來。

第七章的後半部分講述了以STL作爲數據組織方式來實現COM集合對象和枚舉對象,如果讀者對於STL不是很熟悉的話,可以把這部分內容跳過去而無關大局。用STL實現集合對象和枚舉對象與前面方法的主要不同在於對象的內部實現細節,基本的思路和模型仍然一致。對應於CComEnum的枚舉器類爲CComEnumOnSTL,對應於CComEnumImpl的枚舉接口實現類爲IEnumOnSTLImpl,這兩個類的用法可以非常靈活,書中舉例說明了這兩個類的用法。如果用STL實現枚舉對象,則集合類也需要提供相應的支持,比較好的做法是用STL來實現集合類。緊接着作者就介紹了ICollectionOnSTLImpl,它與CComEnumOnSTL配合起來實現集合對象和枚舉對象。

作者在這一章還介紹瞭如何把ATL的數據類型(也就是在第二章講述的一些類)封裝到STL的容器中,這部分內容對於那些STL迷來說可能非常有用,也非常有意思。在這一章的最後,作者用前面講到的內容構造了一個簡單的對象模型例子,讓讀者知道如何把集合對象和枚舉對象應用到對象模型中,起到一個全局指導的作用。

第八章講述可連接對象的ATL實現,作者首先回顧了COM的可連接對象機制,指出ATL利用兩個全局函數AtlAdvise和AtlUnadvise建立源對象和接收器對象之間的連接或者撤銷兩者之間的連接。可連接對象是COM的雙向通信機制,它並沒有應用複雜的技術,實際上就是COM的一個反向應用。

然後作者從一個例子開始講述ATL實現可連接對象的全過程(分爲七個步驟),包括如何實現IConnectionPointContainer接口、如何實現每個連接點對象、如何增加連接點映射表以及如何編寫事件激發函數或者讓Visual C++的集成環境產生事件激發函數。在介紹了源對象的實現過程之後,作者又介紹了客戶程序一方實現事件接收器對象的過程,相對而言,這個過程涉及到的細節要多一些,因爲ATL的模板類IDispatchImpl只支持雙接口,不支持dispinterface,源對象的出接口(outgoing interface)往往是dispinterface,所以接收器對象要通過其他的途徑來實現事件接口。ATL提供了兩個模板類IDispEventImpl和IDispEventSimpleImpl用於接收器對象的實現,IDispEventImpl要藉助於類型庫所提供的出接口類型信息,這是最簡單的實現方法,而IDispEventSimpleImpl不需要類型庫的支持,這是效率最高的方法。這兩種方法都需要用到事件接收器映射表(event sink map),程序員可以把具體的事件函數以及對應的dispid等信息通過ATL提供的一組宏提交給客戶類。配合前面給出的源對象例子,作者在講解過程中也提供了客戶端接收器對象的例子程序。

在介紹了ATL中可連接對象的用法之後,作者繼續講解這套機制的實現細節,包括以下一些要點:

 

源對象實現IConnectionPointContainer接口的原理,包括如何操縱連接點對象枚舉器、如何使用連接點映射表。

 

 

連接點對象實現類IConnectionPointImpl。包括如何管理多個連接、如何操縱連接枚舉器對象、如何在一個源對象上實現多個連接點對象等細節。

 

 

事件接收器對象所涉及到的多個類。包括_IDispEvent、_IDispEventLocator、IDispEventSimpleImpl,同時也討論了事件接收器映射表的基本原理。

 

這一章介紹的內容相對要簡單一些,如果上一部分的基礎打得比較好的話,這些內容可以輕鬆地讀下來。儘管內容比較簡單,但是對於我們熟練應用ATL的可連接對象機制非常有幫助,因爲在實際工作中,完全手工實現可連接對象機制非常繁瑣,即使ATL的Wizard中已經提供了連接點對象的支持,要讓可連接對象和接收器對象真正工作起來還需要許多手工工作。所以這部分內容很有實際意義。

以上三章內容是COM擴展的內容,但是我們在實際工作中經常會碰到這些內容,尤其是COM的永久特性和可連接對象特性,具有非常廣泛的應用背景,比如下一部分要講到的ActiveX控制就同時需要這兩種技術的支持,而集合對象和枚舉器對象則是VBA程序所非常依賴的對象組織手段。

 

第四部分 ATL對窗口和ActiveX控制的支持

我們知道,COM是一個平臺無關的組件規範,但是COM的應用幾乎都是與Windows平臺相關的,這是由COM的歷史背景所決定的。本書第四部分討論的內容是ATL如何實現與用戶界面有關的功能,特別是如何封裝窗口、如何支持ActiveX控制。

在Visual C++提供的兩套類庫中,MFC側重於對Windows平臺上界面特性的封裝,包括各種風格的窗口程序、對話框、大量的控制類等,而ATL則側重於對COM的封裝。但是,如同MFC也提供了COM支持一樣,ATL也提供了對用戶界面的支持,這就是第九章所要討論的ATL窗口封裝,當然封裝的基礎仍然是Win32 API。

第九章討論的內容不涉及到COM,完全是Windows平臺上的與窗口有關的許多細節,作者從Windows窗口應用的基本模式講起,講到了窗口的三大要素:窗口類(WNDCLASSEX結構)、窗口句柄(HWND)和窗口過程(WndProc),這也是封裝窗口類的幾個要點。ATL的窗口類層次結構比MFC要簡單得多,其中主要的類是CWindow、CWindowImpl、CDialogImpl和CContainedWindow,然後作者逐一介紹這些類。

CWindow類非常簡單,它只是對窗口句柄HWND的封裝,幾乎所有與窗口有關的API函數都有對應的CWindow成員函數。這些成員函數僅僅是個簡單封裝而已。

CWindowImpl是ATL窗口類中的關鍵類,它一方面繼承自CWindow,同時它解決了窗口的兩個關鍵問題:窗口類的註冊和窗口消息處理。窗口類的註冊是創建該類窗口的必要條件,CWindowImpl類把這個過程作了封裝,程序員只需使用簡單的宏就可以完成這些必要的任務。CWindowImpl類實現窗口過程則使用了一點技巧,因爲窗口過程是以HWND作爲窗口對象標識的,而CWindowImpl是以this指針作爲對象標識的,所以如何在HWND和this指針之間建立對應關係是關鍵所在。CWindowImpl的基類CWindowImplBaseT以StartWindowProc作爲窗口過程,在第一次被調用的過程中建立兩者的映射關係,它通過一個被稱爲“thunk”的對象在運行過程中建立起來的一組機器指令。每個窗口對象都有一個thunk對象。thunk的任務是在調用CWindowImpl類的靜態成員函數WindowProc處理消息之前先用this指針代替棧中的HWND。書中對這個過程作了詳細的說明,對於ATL的窗口底層封裝有興趣的讀者可以看一看這部分內容介紹,很有意思的。

完成了HWND到this指針的映射還只是一小步的工作,窗口過程的根本目標是處理窗口的消息,ATL的消息處理機制非常強大,首先它利用一組宏構造出ProcessWindowMessage成員函數,一旦把這些宏展開,其實就是一個規範的switch語句,以及每個case下的一大堆if語句。這種程序結構明顯不同於MFC的消息映射表,MFC消息映射表通過查表來處理每一個消息。ATL的消息支持非常靈活,我們可以按消息碼指定消息處理函數,也可以按消息碼的範圍值指定處理函數,對於命令消息和通知消息有專門的宏提供支持。更爲強大的是,ATL的消息表可以構成鏈,也就是把派生類和基類的消息錶鏈接起來,如果有多個基類的話,可以把所有這些消息表都鏈起來。而且在每個類中,消息表中的消息處理項又可以分組,有的用於派生類,有的用於自身,爲派生類提供了許多機會。

理解了CWindowImpl之後再來理解CDialogImpl則容易多了,同樣的thunk技術,同樣的消息鏈技術,所不同的是底層Win32 API有不同的處理,而且對話框分爲有模式對話框和無模式對話框。如果讀者用MFC編寫過對話框類的話,一定對其中的DDX/DDV函數有印象,Class Wizard產生的這些函數調用完成了對話框成員變量與對話框上控制之間的數據交換和數據有效性判斷,不幸的是,ATL沒有提供這樣的功能,我們只好自己解決,其實真要做起來並不難,而且自己實現可以更靈活。

我們知道MFC封裝了大量的控制類,而ATL的窗口類樹中並沒有這麼多的控制類,實際上,在ATL的atlcon例子中同樣給出了所有這些控制的封裝類,只是沒有正式的文檔而已,這些類用起來很簡單,源碼本身就是最好的文檔,我們可以充分利用這些資源。

這一章最後還介紹了CContainedWindow,它的特殊之處在於,它接收到消息之後交給父窗口處理這些消息,父窗口既可以直接創建這樣的子窗口,也可以對一個已經被創建的窗口對象利用“子類化”的技術截取其窗口過程。

第九章的內容與COM完全無關,但它是ATL庫中不同缺少的一部分,特別對於有用戶界面的ATL工程來說,更是非常重要。第十章則講述如何用ATL來建立ActiveX控制(大多數中文資料把“ActiveX control”稱爲ActiveX控件)。ActiveX控制是COM技術的大集成,也是OLE技術的大集成,如果純粹從技術角度來講的話,幾乎還沒有一本書能夠全面講述ActiveX控制的各項技術。ATL對ActiveX控制的支持比較全面,而且它的應用非常靈活,程序員可以有所選擇地選取某一部分。

第十章作者首先回顧了ActiveX控制的各項功能,然後從一個例子BullsEye的功能需求分析出發,利用ATL Wizard創建一個初始的ActiveX控制框架,對創建過程中涉及到的選項逐一作了說明。有了初始的控制代碼之後,接下去的任務是逐項完善BullsEye控制的功能,分別如下:

 

首先是增加BullsEye控制的屬性和方法,因爲ActiveX控制是自動化技術的超集,包容器(客戶)需要通過IDispatch接口或者雙接口與控制進行通信,所以控制的屬性和方法是基礎,屬性和方法分兩種:庫存的(stock)和自定義的(custom)。ATL支持庫存屬性的類爲CStockPropImpl,它繼承自IDispatchImpl類。而自定義的屬性和方法則可以通過VC集成環境提供的“Add Method”和“Add Property”加入,它會自動更新IDL接口定義文件和相應的源代碼.h文件。

 

 

加入事件支持。首先在IDL文件中加入出接口的事件定義,然後加入連接點支持以及IConnectionPointContainer接口的支持。ActiveX控制除了支持自定義的出接口之外,它還支持IPropertyNotifySink接口作爲出接口,專門用於向包容器程序提供屬性變化通知。ATL的類IPropertyNotifySinkCP實現了相應的連接點對象。實現連接點支持的基本機制如上一部分所介紹,只是ATL爲ActiveX控制提供了更多的便利。作爲與連接點相關的內容,一個ActiveX控制也應該支持IProvideClassInfo2接口,相應的ATL類爲IProvideClassInfo2Impl。

 

 

作爲ActiveX控制,在窗口中繪製必要的圖形信息是它的任務之一,ATL只提供了繪製的框架,具體的繪製任務由派生類完成,對於我們編寫ATL控制而言,就是一個OnDraw函數。

 

 

屬性的永久性。這是第六章內容的綜合應用,直接利用ATL提供的永久接口實現類,以及控制的屬性映射表即可。

 

 

一個客戶友好的ActiveX控制應該實現IQuickActivate接口,ATL想得很周到,它實現了這個接口,把有關的邏輯交給控制類的IQuickActivate_QuickActivate成員。

 

 

組件類別。利用ATL的類別映射表很容易實現控制的類別功能。

 

 

屬性分類的功能。ATL沒有提供支持,但是我們可以很方便地實現ICategorizeProperties接口。

 

 

針對屬性的瀏覽功能。這是接口IPerPropertyBrowsing的任務,ATL提供了接口實現IPerPropertyBrowsingImpl,我們只要重載有關的成員函數即可。

 

 

ActiveX控制的鍵盤處理。這是ActiveX控制與包容器之間的協作基礎,我們只要根據ActiveX控制的規範重載必要的函數即可。

 

這一章的內容覆蓋面比較廣,作者通過BullsEye例子程序展示了ATL實現全功能的ActiveX控制的諸多細節。有許多地方用到了前面講述的ATL類或者相應的各種支持,這個例子對於我們自己實現ActiveX控制很有啓發性。

最後第十一章介紹ActiveX被包容器程序使用的情況。作者首先介紹了ActiveX控制與包容器之間的協作概況,然後敘述ATL實現包容的基本技術。CAxHostWindow類是ATL實現包容控制的內部基本類。作者從ActiveX控制的創建過程解釋了CAxHostWindow類如何參與包容器窗口與控制之間的協作,我們知道,包容器程序通過控制站點對象來管理ActiveX控制,這裏的CAxHostWindow對象相當於控制的站點對象,它不是由客戶程序顯式創建,而是在包容器窗口創建控制的過程中被隱式創建,這個過程涉及到很多協作細節。作者花了很大的篇幅來講述這個過程,一旦這個過程講清楚了,那麼其他的細節就顯得非常簡明。

加入事件控制的過程很簡單,如第八章所述,利用IDispEventImpl類,加入接收器事件映射表,然後在適當的時候建立接收器與控制之間的連接即可。同樣地,我們可以在包容器上實現IPropertyNotifySink接口,並建立它與控制之間的連接,以便處理控制的屬性變化通知。對於屬性頁的處理也是包容器程序的一項任務,但處理起來比較簡單,只需調用OLE函數OleCreatePropertyFrame即可。控制的永久處理也不復雜,在包容器的保存和恢復操作中分別調用控制永久接口的Save和Load成員即可。

除了在一般的窗口中包容ActiveX控制之外,對話框作爲包容器窗口也是一種典型情況,對於客戶程序而言,在對話框中使用ActiveX控制更爲簡便。在程序設計階段,集成環境往往能夠爲我們做更多的事情,比如控制的初始狀態處理、控制的事件處理等。但是仍然有些工作需要我們在後期手工進行處理,如建立接收器對象與控制之間的連接、編寫事件函數等。

在實際應用中,用ActiveX控制或者Windows的標準控制構造新的控制是一項很有用的技術,這就是複合控制,ATL也支持複合控制,它把對話框的功能和ActiveX控制的功能結合起來。在構造複合控制的時候,我們可以指定一個對話框模板,把設計階段完成的界面模板引入到複合控制中,這是一個非常簡便的構造界面單元的方法。

另一個功能更爲強大的構造界面單元的方法是HTML控制,它利用Web瀏覽器控制直接把HTML頁面封裝成一個新的ActiveX控制。由於它把HTML頁面作爲界面內容,所以使用的時候非常靈活,我們可以在HTML頁面中嵌入腳本,可以使用多種字體,可以訪問HTML文檔的對象模型。

這一章的內容也比較廣泛,但是它把上一章介紹的ActiveX控制與實際的應用結合起來了。而且通過這些內容的介紹,我們可以拓寬視野把ActiveX控制應用得更加靈活,把Web引入到我們的桌面程序上來,或者把桌面程序的功能引入到Web當中去。這兩章的內容相對比較獨立,它們構成了用ATL開發和使用ActiveX控制的主體。如果讀者關注MSJ雜誌的話,可以在1999年的2、3、4月期上找到有關這些內容的一個連載,文章的名字爲:“Write ActiveX Controls Using Custom Interfaces Provided by ATL 3.0”。

第十一章是全書的最後一章,我們跟隨作者從基本的嚮導開發學起,經過深入淺出的分析,終於達到了一個歇腳點,可以輕鬆一下了。但這不等於我們學習ATL的任務已經完成了,ATL還有很多內容有待於我們去挖掘。

結束語

對於COM應用的開發,ATL無疑是首選的工具,與MFC相比,ATL的規模還不算大,但是從上述的介紹我們可以看出,ATL涉及到了COM的方方面面。實際上,ATL的內容還要多得多,比如OLE DB的支持、MTS的支持等,儘管如此,如果我們有了這本書中的內容爲基礎,那麼再去學習這些擴展的內容就會容易得多,結合ATL中實現COM的基本手段加上這些應用技術的背景知識,我們可以很容易地掌握這些開發技術。

但是如果我們要想熟練掌握甚至精通ATL的話,那麼這只是一個開頭,前面還有漫長的路要走。原因有多方面,一則COM本身異常複雜,不下苦功難窺全貌;二則ATL確實奧妙很多,它體現了C++語法的博大精深;三則ATL還存在很多錯誤,雖然本書作者指出了一些錯誤,但實際的錯誤肯定更多,這就對ATL使用者提出了更高的要求,如果使用過程中不能發現這些錯誤或者避開這些錯誤,那麼用ATL反而會阻礙我們的工作。

雖然ATL比較精深,但是這本書的講解非常通俗易懂,語言比較簡練,條理非常清楚。即使在讀完這本書之後,它仍然可以作爲參考書指導我們的開發和學習工作。我想,這就是好書的價值所在吧。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章