• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            最近看公司的一些新產(chǎn)品和框架 , 發(fā)現(xiàn)清一色的“COM思想架構(gòu) ”, 這里說(shuō)的“COM思想架構(gòu)”是指不完全是標(biāo)準(zhǔn)COM組件的方式,而是指在設(shè)計(jì)上用到了COM思想。
            COM組件技術(shù)大概在1993年產(chǎn)生, 20年了, 為什么還有這么多人使用? 
            我們先來(lái)看看標(biāo)準(zhǔn)COM組件:
            標(biāo)準(zhǔn)COM組件(DLL方式)需要實(shí)現(xiàn)如下4個(gè)導(dǎo)出函數(shù):
            DllRegisterServer 將組件信息寫(xiě)入注冊(cè)表
            DllUnregisterServer 取消注冊(cè)
            DllCanUnloadNow判斷組件是否可以從內(nèi)存中卸載
            DllGetClassObject返回IClassFactory指針,然后我們就可以通過(guò)該接口的CreateInstance方法創(chuàng)建對(duì)象并取得所需的接口。
            采用標(biāo)準(zhǔn)COM組件,有很多好處:
            面向接口和對(duì)象編程
            語(yǔ)言無(wú)關(guān)性, 采用二進(jìn)制標(biāo)準(zhǔn),可以實(shí)現(xiàn)跨語(yǔ)言調(diào)用
            版本升級(jí)方便,增加新接口, 組件升級(jí)后老客戶程序不用重新編譯
            位置透明, 客戶程序不用關(guān)心組件的位置
            重用方便, 通過(guò)包容和聚合可以快速重用已有組件
            我們可以看到標(biāo)準(zhǔn)COM組件非常強(qiáng)大, 但是很多時(shí)候我們并不需要標(biāo)準(zhǔn)COM組件的所有特性,比如我們不希望引入注冊(cè)表, 也不希望引入COM運(yùn)行庫(kù),我們希望我們的程序是完全“綠色”的。這時(shí)我們就會(huì)采用“COM思想架構(gòu)“開(kāi)發(fā)非標(biāo)準(zhǔn)的COM組件。
            實(shí)際上微軟本身已經(jīng)有很多API采用這種設(shè)計(jì)方案了,我們來(lái)看一些例子:
            XmlLite
            繼msxml之后微軟提供的另 一款高效的XML解析器, 它本身只有一個(gè)綠色DLL XmlLite.dll, 關(guān)于它的接口和使用方法可以參考XmlLite Introduction用于本機(jī) C++ 的小巧快捷的 XML 分析器
            我們可以用depends.exe看看該DLL的導(dǎo)出函數(shù):


            調(diào)用這些導(dǎo)出的CreateXXX函數(shù)返回返回一個(gè)繼承于IUnknown的接口, 然后我們就可以調(diào)用接口提供的方法了, 可以看下IXmlReader的方法:
                IXmlReader : public IUnknown
                {
                
            public:
                    
            virtual HRESULT STDMETHODCALLTYPE SetInput( 
                        
            /* [annotation] */ 
                        __in_opt  IUnknown 
            *pInput) = 0;
                    
                    
            virtual HRESULT STDMETHODCALLTYPE GetProperty( 
                        
            /* [annotation] */ 
                        __in  UINT nProperty,
                        
            /* [annotation] */ 
                        __out  LONG_PTR 
            *ppValue) = 0;
                    
                    
            virtual HRESULT STDMETHODCALLTYPE SetProperty( 
                        
            /* [annotation] */ 
                        __in  UINT nProperty,
                        
            /* [annotation] */ 
                        __in_opt  LONG_PTR pValue) 
            = 0;
                    
                    
            virtual HRESULT STDMETHODCALLTYPE Read( 
                        
            /* [annotation] */ 
                        __out_opt  XmlNodeType 
            *pNodeType) = 0;
                    
                    
            virtual HRESULT STDMETHODCALLTYPE GetNodeType( 
                        
            /* [annotation] */ 
                        __out  XmlNodeType 
            *pNodeType) = 0;
                    
                    
            virtual HRESULT STDMETHODCALLTYPE MoveToFirstAttribute( void= 0;
                    
                    
            virtual HRESULT STDMETHODCALLTYPE MoveToNextAttribute( void= 0;
                    

                    .......

                    
                };
            Direct2D
            關(guān)于是微軟下一代2D渲染接口, 關(guān)于它的詳情參考Direct2D, 我們同樣分析一下它的導(dǎo)出函數(shù):

            實(shí)際看到這里也用了COM思想的方法,我們可以看看D2D1CreateFactory返回的ID2D1Factory的接口:
            interface DX_DECLARE_INTERFACE("06152247-6f50-465a-9245-118bfd3b6007") ID2D1Factory  : public IUnknown
            {
                
            //
                
            // Cause the factory to refresh any system metrics that it might have been snapped
                
            // on factory creation.
                
            //
                STDMETHOD(ReloadSystemMetrics)(
                    ) PURE;
                
                
            //
                
            // Retrieves the current desktop DPI. To refresh this, call ReloadSystemMetrics.
                
            //
                STDMETHOD_(void, GetDesktopDpi)(
                    _Out_ FLOAT 
            *dpiX,
                    _Out_ FLOAT 
            *dpiY 
                    ) PURE;
                
                STDMETHOD(CreateRectangleGeometry)(
                    _In_ CONST D2D1_RECT_F 
            *rectangle,
                    _Outptr_ ID2D1RectangleGeometry 
            **rectangleGeometry 
                    ) PURE;
                
                STDMETHOD(CreateRoundedRectangleGeometry)(
                    _In_ CONST D2D1_ROUNDED_RECT 
            *roundedRectangle,
                    _Outptr_ ID2D1RoundedRectangleGeometry 
            **roundedRectangleGeometry 
                    ) PURE;
                
                STDMETHOD(CreateEllipseGeometry)(
                    _In_ CONST D2D1_ELLIPSE 
            *ellipse,
                    _Outptr_ ID2D1EllipseGeometry 
            **ellipseGeometry 
                    ) PURE;
                
                ......

            }; 
            // interface ID2D1Factory

            思考為什么會(huì)有越來(lái)越多的新程序采用這種”COM思想架構(gòu)“, 這個(gè)要回到COM的根 ---- IUnknown接口:

                IUnknown
                {
                
            public:
                    BEGIN_INTERFACE
                    
            virtual HRESULT STDMETHODCALLTYPE QueryInterface( 
                        
            /* [in] */ REFIID riid,
                        
            /* [annotation][iid_is][out] */ 
                        __RPC__deref_out  
            void **ppvObject) = 0;
                    
                    
            virtual ULONG STDMETHODCALLTYPE AddRef( void= 0;
                    
                    
            virtual ULONG STDMETHODCALLTYPE Release( void= 0;
                    
                    END_INTERFACE
                };

            IUnknow接口是個(gè)偉大的創(chuàng)造!
             IUnknow的AddRef和Release實(shí)現(xiàn)對(duì)象的引用計(jì)數(shù)管理, 引用計(jì)數(shù)用來(lái)管理對(duì)象的生存周期。
            通過(guò)引用計(jì)數(shù)一來(lái)可以很方便的共享對(duì)象, 另外也能確保對(duì)象被正確釋放(確保對(duì)象的new和delete在同一模塊中)。
            QueryInterface實(shí)現(xiàn)接口查詢, 通過(guò)這種方式可以很方便的對(duì)現(xiàn)有組件進(jìn)行升級(jí), 只要接口不改 ,可以隨意修改內(nèi)部實(shí)現(xiàn)而不用客戶程序重新編譯。
            另外也可以直接增加新接口, 只要在QueryInterface內(nèi)增加并可以查詢到該新接口, 我們就可以調(diào)用該新接口。
            我們可以看到QueryInterface讓C++這種靜態(tài)語(yǔ)言有了某些動(dòng)態(tài)語(yǔ)言的特性, 在C# 中我們可以通過(guò)反射查詢到某個(gè)類(lèi)的成員函數(shù)和成員變量, Objective-C中我們也可以根據(jù)函數(shù)名動(dòng)態(tài)調(diào)用某個(gè)函數(shù), 在腳本語(yǔ)言中,我們可以在運(yùn)行時(shí)動(dòng)態(tài)查詢和修改某個(gè)類(lèi)的信息。通過(guò)COM的QueryInterface, 我們可以動(dòng)態(tài)查詢某個(gè)組件類(lèi)實(shí)現(xiàn)哪些接口(函數(shù))。當(dāng)然他們之間有本質(zhì)的區(qū)別, 動(dòng)態(tài)語(yǔ)言運(yùn)行時(shí)內(nèi)存中保存有類(lèi)信息, 而C++的QueryInterface通過(guò)switch case, 返回的是存有虛表指針的對(duì)象指針。
            最后再簡(jiǎn)單談下IUnknown的升級(jí)版IDispatch和IInspectable。

            先看IDispatch:
                IDispatch : public IUnknown
                {
                
            public:
                    
            virtual HRESULT STDMETHODCALLTYPE GetTypeInfoCount( 
                        
            /* [out] */ __RPC__out UINT *pctinfo) = 0;
                    
                    
            virtual HRESULT STDMETHODCALLTYPE GetTypeInfo( 
                        
            /* [in] */ UINT iTInfo,
                        
            /* [in] */ LCID lcid,
                        
            /* [out] */ __RPC__deref_out_opt ITypeInfo **ppTInfo) = 0;
                    
                    
            virtual HRESULT STDMETHODCALLTYPE GetIDsOfNames( 
                        
            /* [in] */ __RPC__in REFIID riid,
                        
            /* [size_is][in] */ __RPC__in_ecount_full(cNames) LPOLESTR *rgszNames,
                        
            /* [range][in] */ UINT cNames,
                        
            /* [in] */ LCID lcid,
                        
            /* [size_is][out] */ __RPC__out_ecount_full(cNames) DISPID *rgDispId) = 0;
                    
                    
            virtual /* [local] */ HRESULT STDMETHODCALLTYPE Invoke( 
                        
            /* [in] */ DISPID dispIdMember,
                        
            /* [in] */ REFIID riid,
                        
            /* [in] */ LCID lcid,
                        
            /* [in] */ WORD wFlags,
                        
            /* [out][in] */ DISPPARAMS *pDispParams,
                        
            /* [out] */ VARIANT *pVarResult,
                        
            /* [out] */ EXCEPINFO *pExcepInfo,
                        
            /* [out] */ UINT *puArgErr) = 0;
                    
                };

            IDispatch繼承于IUnknown, 通過(guò)IDispatch, 我們可以實(shí)現(xiàn)腳本語(yǔ)言對(duì)COM組件的調(diào)用,我們可以通過(guò)GetTypeInfo獲取對(duì)象的類(lèi)型信息, 通過(guò)GetIDsOfNames函數(shù)以字符串的方式獲取函數(shù)的DISPID, 通過(guò)Invoke動(dòng)態(tài)調(diào)用某個(gè)函數(shù)。IE的DOM對(duì)象與JS的交互全部是通過(guò)IDispatch(Ex)接口實(shí)現(xiàn)的。當(dāng)然,除非你的組件要與腳本語(yǔ)言交互, 否者一般不用實(shí)現(xiàn)該接口。
            再看IInspectable:
                IInspectable : public IUnknown
                {
                
            public:
                    
            virtual HRESULT STDMETHODCALLTYPE GetIids( 
                        
            /* [out] */ __RPC__out ULONG *iidCount,
                        
            /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*iidCount) IID **iids) = 0;
                    
                    
            virtual HRESULT STDMETHODCALLTYPE GetRuntimeClassName( 
                        
            /* [out] */ __RPC__deref_out_opt HSTRING *className) = 0;
                    
                    
            virtual HRESULT STDMETHODCALLTYPE GetTrustLevel( 
                        
            /* [out] */ __RPC__out TrustLevel *trustLevel) = 0;
                    
                };

            IInspectable也繼承于IUnknown, 它是WinRT所有對(duì)象的基接口, 所以WinRT還是基于COM技術(shù)。
            其中GetTrustLevel返回信任等級(jí), GetRuntimeClassName返回類(lèi)名, 而GetIids返回當(dāng)前類(lèi)對(duì)象實(shí)現(xiàn)了哪些接口(所有接口的iid), 得到接口的iid后, 我們就可以通過(guò)QueryInterface查詢我們需要的接口了, 得到接口指針就可以調(diào)用內(nèi)部函數(shù)了。
            最后總結(jié)下,回答下文章開(kāi)頭的問(wèn)題, 很多人說(shuō)COM過(guò)時(shí)了, 也許”純正的標(biāo)準(zhǔn)COM“確實(shí)是使用的人越來(lái)越少了, 但是COM的思想?yún)s一直在后續(xù)的軟件開(kāi)發(fā)中被使用和發(fā)揚(yáng), 可以說(shuō)COM技術(shù)是微軟技術(shù)框架的“根”(之一)。
            posted on 2013-07-20 16:59 Richard Wei 閱讀(4671) 評(píng)論(6)  編輯 收藏 引用 所屬分類(lèi): COM

            FeedBack:
            # re: COM思想的背后
            2013-07-20 17:16 | WXX
            個(gè)人以為COM是從技術(shù)框架層面實(shí)踐了一些設(shè)計(jì)模式,而設(shè)計(jì)模式是相對(duì)穩(wěn)定的東西,所以COM背后的思想也相對(duì)穩(wěn)定。COM思想中也有很多不好的東西或者說(shuō)不好理解的東西,比如:套件、Marshaling等完全可以用其它技術(shù)或者框架去替代。至于自動(dòng)化、類(lèi)型庫(kù)這些,可能微軟自己都不在推崇了,包括基于ATL框架的AX制作慢慢封死了。
            COM是思想體現(xiàn)在ABI,以及對(duì)象模型的組織上,他自身提供了一些優(yōu)秀的實(shí)踐。  回復(fù)  更多評(píng)論
              
            # re: COM思想的背后
            2013-07-20 17:52 | Richard Wei
            @WXX
            同意, 關(guān)于套間、列集/散集, 內(nèi)部涉及到LPC/RPC技術(shù),微軟隱藏了太多東西,盡管Windows操作系統(tǒng)本身用了不少這方面的技術(shù), 但是外部開(kāi)發(fā)人員卻因?yàn)椴缓谜瓶囟M量不用。  回復(fù)  更多評(píng)論
              
            # re: COM思想的背后
            2013-07-22 09:25 | 永遇樂(lè)
            微軟通過(guò)修改VC編譯器(提供新的關(guān)鍵字),讓C++的對(duì)象之間擁了有一定的通信能力,這里面關(guān)鍵的就是這個(gè)iid,通過(guò)iid可以在運(yùn)行時(shí)獲取某個(gè)對(duì)象的成員函數(shù)指針,然后調(diào)用之,這就相當(dāng)于對(duì)象與對(duì)象之間通信了。
            這也達(dá)到了Object C中對(duì)象之間通信的效果(一個(gè)對(duì)象A給另一個(gè)對(duì)象B發(fā)消息M,B收到消息M后,能處理就處理,不能處理就算了)。
            而在COM中,A對(duì)象要先看B對(duì)象能不能處理消息M,即A先查一下,B對(duì)象有沒(méi)有處理M消息的那個(gè)成員函數(shù)HandleM() (即B對(duì)象中有沒(méi)有哪個(gè)接口中有HandleM()方法),如果有(查到了),則調(diào)用HandleM(M)。沒(méi)查到嘛,當(dāng)然就算了。  回復(fù)  更多評(píng)論
              
            # re: COM思想的背后
            2013-07-23 16:58 | tb
            嗯 是的 有很多還是比較實(shí)用的  回復(fù)  更多評(píng)論
              
            # re: COM思想的背后
            2013-07-27 00:35 | rain
            這玩意最主要的一點(diǎn)是 太復(fù)雜了 套間 Marshaling這些概念把整個(gè) com 原來(lái)一個(gè)很優(yōu)秀簡(jiǎn)單的架構(gòu)搞得很復(fù)雜,讓人理解起來(lái)很晦澀!  回復(fù)  更多評(píng)論
              
            # re: COM思想的背后
            2013-10-24 03:52 | Archie
            使用boost的shared_ptr以及C++的RTTI (dynamic_cast)可以輕易實(shí)現(xiàn)類(lèi)似COM IUnknown的框架,并且更簡(jiǎn)單  回復(fù)  更多評(píng)論
              

            只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問(wèn)   Chat2DB   管理


            亚洲成色www久久网站夜月| 欧美精品九九99久久在观看| 国产精品99久久久久久人| 久久狠狠色狠狠色综合| 国内精品久久久久影院网站| 亚洲国产日韩欧美综合久久| 伊人久久综合成人网| 狠狠色丁香婷婷久久综合不卡| 久久91精品综合国产首页| 国内精品伊人久久久久妇| 97久久超碰国产精品旧版| 久久精品国产国产精品四凭| 久久久久久久精品妇女99| 97久久久精品综合88久久| 久久综合一区二区无码| 亚洲国产精品18久久久久久| 国产成人香蕉久久久久| 人妻无码精品久久亚瑟影视 | 91久久福利国产成人精品| 免费一级欧美大片久久网| 蜜臀久久99精品久久久久久小说| 亚洲精品高清久久| 综合久久国产九一剧情麻豆 | 99久久精品免费观看国产| 久久亚洲日韩看片无码| 久久精品无码一区二区三区| 精品国产99久久久久久麻豆| 国产69精品久久久久9999| 无码精品久久久天天影视| 伊人久久精品影院| 国内精品久久久久久不卡影院| 新狼窝色AV性久久久久久| 性高朝久久久久久久久久| 青青青青久久精品国产h| 色88久久久久高潮综合影院 | 伊人精品久久久久7777| 国产精品嫩草影院久久| 99久久成人国产精品免费| 久久精品一本到99热免费| 亚洲国产精品综合久久一线| 激情久久久久久久久久|