• <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

            国产A级毛片久久久精品毛片| 国产精品丝袜久久久久久不卡| 久久久久久精品免费免费自慰| 亚洲va国产va天堂va久久| 国产精品一久久香蕉国产线看| 精品人妻伦一二三区久久| 欧美黑人激情性久久| 久久综合狠狠综合久久激情 | 久久无码中文字幕东京热| av国内精品久久久久影院| 久久无码一区二区三区少妇| 99久久夜色精品国产网站| 国产精品久久久久久久午夜片| 久久综合噜噜激激的五月天| 久久久久久久综合综合狠狠| 久久久久久夜精品精品免费啦| 久久久黄片| 久久综合久久久| 国内精品久久久久久99| 亚洲国产成人精品久久久国产成人一区二区三区综 | 久久99久久99小草精品免视看| 亚洲欧美成人久久综合中文网 | 成人a毛片久久免费播放| 久久久久亚洲AV成人网人人网站 | 伊人久久精品线影院| 久久夜色精品国产欧美乱| 国产精品久久久久久久人人看| 国产一区二区精品久久岳 | 久久婷婷色香五月综合激情 | 婷婷久久久亚洲欧洲日产国码AV| 理论片午午伦夜理片久久 | 久久99精品国产麻豆婷婷| 99re这里只有精品热久久| 久久亚洲美女精品国产精品| 一本大道久久东京热无码AV| 久久精品?ⅴ无码中文字幕| 亚洲国产成人久久综合碰碰动漫3d| 99久久精品日本一区二区免费| 久久久久国产精品熟女影院| 少妇高潮惨叫久久久久久| 久久综合给合久久狠狠狠97色|