• <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>
            轉(zhuǎn)自http://www.imyaker.com/blog/article.asp?id=34
            插件系統(tǒng)-選擇GetProcAddress還是Interfaces(譯)
            原文:
            Plugin System – an alternative to GetProcAddress and interfaces
            下載文件 代碼下載
            [介紹]
            有很多文章描述如何實(shí)現(xiàn)一個(gè)簡(jiǎn)單的插件框架,比如后面的鏈接[1]和[2]。通常有兩種方法
            (1) 插件實(shí)現(xiàn)一組標(biāo)準(zhǔn)的(并且通常是小的)函數(shù)(方法)。宿主(host)知道這些函數(shù)的名字,并且可以通過(guò)使用GetProcAddress函數(shù)獲得這些函 數(shù)的地址。這并不合適,隨著函數(shù)數(shù)量的增長(zhǎng),維護(hù)變得越來(lái)越困難。你必須手動(dòng)通過(guò)函數(shù)名綁定函數(shù),這樣你就不得不做很多工作。
            (2)GetProcAddress所返回的函數(shù)被用來(lái)傳遞接口指針(Interface Pointer)給插件或者從插件里獲取接口指針。剩下的宿主和插件的通信通過(guò)接口完成。下面是一個(gè)例子

            我 們將使用一個(gè)簡(jiǎn)單的例子。宿主程序是一個(gè)圖片查看器。它實(shí)現(xiàn)了一個(gè)插件框架來(lái)增加對(duì)不同圖片格式的支持(在這個(gè)例子中就是24-bit的BMP圖象和24 -bit的TGA(Targa)圖象)。插件將被實(shí)現(xiàn)為DLLs并且將有.imp的擴(kuò)展名以便和普通dll文件區(qū)分開(kāi)來(lái)了.注意,盡管如此,可是這篇文章 是關(guān)于插件的,而不是關(guān)于圖象解解析器的。這里所提供的解析器非常基礎(chǔ)并且只是用來(lái)說(shuō)明的。

            [使用接口的方法]
            接口是所有函數(shù)都是公共的并且純虛的基類(lèi),并且沒(méi)有沒(méi)有數(shù)據(jù)成員。比如
            程序代碼 程序代碼
            // IImageParser is the interface that all image parsers
            // must implement
            class IImageParser
            {
                public:
                // parses the image file and reads it into a HBITMAP
                virtual HBITMAP ParseFile( const char *fname )=0;
                // returns true if the file type is supported
                virtual bool SupportsType( const char *type ) const=0;
            };

            實(shí)際的圖象解析器必須繼承自接口類(lèi)并且實(shí)現(xiàn)純虛函數(shù)。BMP文件解析器可能是這個(gè)樣子。
            程序代碼 程序代碼
            // CBMPParser implements the IImageParser interface
            class CBMPParser: public IImageParser
            {
                public:
                virtual HBITMAP ParseFile( const char *fname );
                virtual bool SupportsType( const char *type ) const;

            private:
                HBITMAP CreateBitmap( int width, int height, void **data );
            };

            static CBMPParser g_BMPParser;

            // The host calls this function to get access to the
            // image parser
            extern "C" __declspec(dllexport) IImageParser *GetParser( void )
            {
                return &g_BMPParser;
            }

            宿主將使用LoadLibrary函數(shù)來(lái)載入BmpParser.imp,然后使用GetProcAddress("GetParser")來(lái)得到GetParser函數(shù)的地址,然后調(diào)用它得到IImageParser類(lèi)的指針。
            宿主將保存了注冊(cè)了的解析器的鄰接表(list),它把GetParser函數(shù)返回的指針附加到那個(gè)鄰接表上去。
            當(dāng)宿主需要解析一個(gè)bmp文件的時(shí)候,它將調(diào)用每個(gè)解析器的SupportType(".BMP")。如果返回類(lèi)型是true,宿主將調(diào)用那個(gè)解析器并且使用完整文件名調(diào)用待解析文件,并將繪制HBITMAP句柄指向的位圖。

            基類(lèi)并不真的必須是純接口。在技術(shù)上這里的限制是所有的成員必須可以通過(guò)對(duì)象指針訪問(wèn)。所以你可以有:
            - 純虛成員函數(shù)(它們能通過(guò)虛表被間接訪問(wèn))
            - 數(shù)據(jù)成員(它們可以通過(guò)對(duì)象的指針直接訪問(wèn))
            - 內(nèi)聯(lián)成員函數(shù)(技術(shù)上它們不能通過(guò)指針訪問(wèn),但是它們的代碼又一次在插件里實(shí)例化。
            這樣就剩下了非內(nèi)聯(lián)和靜態(tài)成員函數(shù)。插件無(wú)法從宿主訪問(wèn)這樣的函數(shù),宿主也不能對(duì)插件進(jìn)行這樣的操作。不幸的是在一個(gè)大型系統(tǒng)之中,這樣的函數(shù)要占據(jù)代碼的大部分。

            例如所有的圖象解析器需要CreateFunction函數(shù)。有必要在基類(lèi)里聲明它并且在宿主端實(shí)現(xiàn)。否則每個(gè)插件都將有一份這個(gè)函數(shù)的拷貝。
            這個(gè)方法的另一個(gè)限制是你不能由宿主端暴露任何全局成員或者全局函數(shù)給插件端。
            我們?cè)趺锤倪M(jìn)呢?

            [把宿主分成Dll和Exe]
            讓 我們看一下USER32模塊,它有兩個(gè)部分 - user32.dll 和 user32.lib。真正的代碼和數(shù)據(jù)在dll中,lib僅僅提供調(diào)用dll函數(shù)的占位函數(shù)。最好的事情在于它是自動(dòng)發(fā)生的。當(dāng)你鏈接到 user32.lib你就自動(dòng)地獲得訪問(wèn)user32.dll函數(shù)的權(quán)利。(這里翻譯的不好)
            MFC 實(shí)現(xiàn)得更進(jìn)一步 - 它暴露你能直接使用和繼承的整個(gè)類(lèi)。它們沒(méi)有我們?cè)谏厦嬗懻摰募兲摻涌陬?lèi)的限制。
            我 們也能做同樣的事情。任何你想提供給插件的函數(shù)(我私下覺(jué)得原文functionality這個(gè)詞用得不好)都能放在一個(gè)單獨(dú)的Dll里。使用 /IMPLIB 鏈接器選項(xiàng)來(lái)創(chuàng)建相應(yīng)的 LIB 文件。插件能與那個(gè)靜態(tài)庫(kù)鏈接,并且所有導(dǎo)出函數(shù)都能提供給它們。你能按你喜歡的方式把代碼分成Dll 和 Exe。極限情況下,像在代碼里演示的那樣,Exe 工程里僅僅含有一行WinMain函數(shù),它僅僅用來(lái)啟動(dòng)Dll。
            任何你想要導(dǎo)出的全局?jǐn)?shù)據(jù),函數(shù),類(lèi),或者成員函數(shù)必須被標(biāo)記為 __declspec(dllexport) 在編譯插件時(shí)。一個(gè)常用的技巧是使用宏
            程序代碼 程序代碼

            #ifdef COMPILE_HOST
            // when the host is compiling
            #define HOSTAPI __declspec(dllexport)
            #else
            // when the plugins are compiling
            #define HOSTAPI __declspec(dllimport)
            #endif

            添加宏COMPILE_HOST的定義到Dll工程里,但是不加到插件工程里。

            在宿主Dll端:
            程序代碼 程序代碼

            // CImageParser is the base class that all image parsers
            // must inherit
            class CImageParser
            {
            public:
                // adds the parser to the parsers list
                HOSTAPI CImageParser( void );
                // parses the image file and reads it into a HBITMAP
                virtual HBITMAP ParseFile( const char *fname )=0;
                // returns true if the file type is supported
                virtual bool SupportsType( const char *type ) const=0;

            protected:
                HOSTAPI HBITMAP CreateBitmap( int width, int height,
                void **data );
            };

            現(xiàn)在基類(lèi)并不僅僅限于一個(gè)接口。我們能增加更多基本功能。CreateBitmap函數(shù)將被所有解析器共享。
            這次不再是宿主調(diào)用一個(gè)函數(shù)來(lái)獲取解析器并且將它添加到鄰接表中,這個(gè)功能被CImageParser的構(gòu)造函數(shù)取代。當(dāng)解析器對(duì)象被創(chuàng)建,它的構(gòu)造函數(shù)將自動(dòng)更新鄰接表。宿主不必再使用GetProcAddress函數(shù)來(lái)看看什么解析器在Dll里。

            在插件端:
            程序代碼 程序代碼
            // CBMPParser inherits from CImageParser
            class CBMPParser: public CImageParser
            {
            public:
                virtual HBITMAP ParseFile( const char *fname );
                virtual bool SupportsType( const char *type ) const;
            };

            static CBMPParser g_BMPParser;

            當(dāng)g_BMPParser被創(chuàng)建是它的構(gòu)造函數(shù) CBMPParser() 將被調(diào)用。那個(gè)構(gòu)造函數(shù)(在插件端實(shí)現(xiàn))將調(diào)用基類(lèi)的構(gòu)造函數(shù)CImageParser() (在宿主端實(shí)現(xiàn))。那是可能的因?yàn)闃?gòu)造函數(shù)被標(biāo)記為HOSTAPI。
            等等,還可以變得更好

            [把宿主Dll和Exe連接起來(lái)]
            (這一部分暫時(shí)沒(méi)翻譯)

            [鏈接]
            [1] Plug-In framework using DLLs by Mohit Khanna
            [2] ATL COM Based Addin / Plugin Framework With Dynamic Toolbars and Menus by thomas_tom99

            PS.我想,Interface方法,是在第一種方法之上加入了一個(gè)間接層。
            我現(xiàn)在到?jīng)]有太強(qiáng)的感覺(jué)非內(nèi)聯(lián)函數(shù)和靜態(tài)函數(shù)會(huì)成為這樣一個(gè)大型系統(tǒng)的主要部分,Interface的派生類(lèi)中的非內(nèi)聯(lián)函數(shù)應(yīng)該只被純虛接口函數(shù)調(diào)用,不然就是接口設(shè)計(jì)有問(wèn)題了。

            posts - 94, comments - 138, trackbacks - 0, articles - 94

            Copyright © RichardHe

            国产精品99久久久久久猫咪| 久久夜色精品国产欧美乱| 韩国三级大全久久网站| 久久成人影院精品777| 国产成人精品久久亚洲| 国产精品久久新婚兰兰| 7777久久亚洲中文字幕| 国产午夜免费高清久久影院| 国产99久久精品一区二区| 久久精品国产99国产精品| 97久久国产露脸精品国产| 国产呻吟久久久久久久92| 午夜人妻久久久久久久久| 久久久久亚洲精品中文字幕| 亚洲精品午夜国产VA久久成人| 久久久久四虎国产精品| 亚洲国产香蕉人人爽成AV片久久| 色综合久久无码中文字幕| 理论片午午伦夜理片久久 | 亚洲国产成人精品女人久久久 | 丁香久久婷婷国产午夜视频| 亚洲精品国产第一综合99久久| 久久久久人妻一区精品性色av| 国产精品成人无码久久久久久| 无码人妻精品一区二区三区久久久 | 久久久久亚洲AV无码麻豆| 尹人香蕉久久99天天拍| 久久久久久A亚洲欧洲AV冫| 国内精品九九久久久精品| 99久久国产综合精品女同图片 | 久久夜色精品国产亚洲| 中文字幕精品久久| 久久黄视频| 久久99精品国产麻豆婷婷| 久久99精品综合国产首页| 国产精品对白刺激久久久| 久久久一本精品99久久精品88| 亚洲人成网亚洲欧洲无码久久| 色综合久久中文字幕综合网| 久久综合九色欧美综合狠狠| 91久久国产视频|