Betölthető modulok (pluginek) Delphi
Borg a két cég fűrészelt. Most az egyik teszi a termékek, és a második lesz tőlük javításokat.
Amikor először felmerült annak a feladatnak a RunTime betölthető modulok (pluginek) Delphi-program, a kérdésre a választ elég gyors. Ahogy néha előfordul az ilyen helyzetekben, én nem igazán gondolkodtam, hogy hogyan lehet megoldani egy hasonló probléma más razrabtochiki.
Pontosabban, rájöttem, hogy sok ember használja nyilvánvaló módszert - hivatkozással a DLL funkciók betöltődnek a megadott neveket. Ez a megközelítés tűnhet nyilvánvaló és egyszerű, ha a feladatot bízzák a plugin egyszerű. Tipikus példák - vnieshnie kodekek, csomagkapcsolt értelmezők, stb
Azonban az ismertetett megoldásnak számos hátránya van, gyakran igen jelentős. Fogom leírni őket a következő részben.
Ugyanakkor, Gyakran kérdezik tőlem, hogyan lehet létrehozni egy kényelmes mechanizmust plugin'ov és leírtam a módszert. A javasolt módszer általam használatán alapuló mechanizmus, amely felhasználja nagyon Delphi - csomagok (csomagok).
Probléma (DLL-plugin'ov hátrányok)
- Minden modul felhasznált fordított DLL.
Képzeljük el, hogy meg kell, hogy a plug-in, amely megjeleníti egy űrlapot a beállításokat. Amint belép a DLL kifejezést használ Forms. Forms modul és az összes modult, Forms modul használható lesz kapcsolódik be a DLL, ami jelentősen növeli a méretét. Képzeld, most, hogy be kell kapcsolódni több plugin'ov, amelyek mindegyike biztosítja a formában, vagy lap, hogy módosítsa a paramétereket. Mint írta a klasszikus, szívszorító látvány.
Előző hátránya kvantitatív, azaz egyszerűen méretének növelése a projekt. De ez azt jelenti, hiányzik a minőség. Tekintsük a példa erre. Tegyük fel, hogy létre kell hozni egy betölthető csomag elemzőt. Ön határozza meg egy absztrakt osztály TParser UParser modul és szeretnénk, ha minden elemzőt örökli tőle. De ahhoz, hogy írják le a DLL leszármazottja TParser, oda kell UParser egységet a felhasználási listáját a DLL. És a fő program képes kezelni TParser és utódai, akkor is be kell vonni használ UParses. A baj az, hogy ezek a modulok lesznek a memóriában, és kétszer a TParser, amely ismeri a fő program nem ugyanaz, mint az, amelyik ismeri a plugin.
A probléma (amit szeretnénk)
Ez egyszerű. Szeretnénk, hogy a fő program lehet anélkül, hogy speciális trükkök dolgozni a külső modulok, mint például a leszármazottai egy absztrakt osztály, és bár nem volt kód redundancia. Ezért kívánatos, hogy módosítsa a főprogram kellett fizetni a lehető legkisebb, még egy nagyon fejlett funkcionalitást plugin'a.
Eszközt (csomagok és funkciók dolgozni velük)
Csomagok megjelent a harmadik változat a Delphi. Mi a csomag? Csomag - egy sor lefordított modulok kombinációja egyetlen fájlban. A kezdeti batch szöveg tárolása I .dpk fájl csak azt jelzik, hogy mely modulok tartalmazzák (a tartalmazza) a csomag (itt a „szabad” azt is jelenti, „ad”), és Kaie más csomagok is hivatkozik (szükséges). Amikor komptlyatsii csomagot kap két fájlt - * .dcp és * .dpl. Az első használjuk egyszerűen modulként könyvtár. Mi jobban érdekli a második.
A fő jellemzője a csomag, hogy nem tartalmazza a kódot, amelyet használnak. Ie ha egyes modulok az egy nagy könyvtár funkciók és osztályok, akkor a kereslet a jelenlétüket, de nem tartalmazza a csomagban. Azt kérdezed, mi mást is új, hiszen a hagyományos modulok is, nem tartalmaznak .dcu-fájl minden a kódot? Egy új dolog, hogy a DPL-csomag egy teljes DLL konkrét formában (azaz a jóváhagyott eljárásokkal, a fejlesztők a Delphi exportált nevek). Betöltésekor csomag memóriába automatikusan egy már letöltött csomag, és ha a letölthető csomagot igényel még néhány csomagot betöltött vannak. Ezen túlmenően, ellentétben a hagyományos modulok, a program modul használunk a külső csomagolás szintén nem szükséges, hogy tartalmazza a kódot. Így tudjuk írni EXE-program mérete több tíz Kbyte (természetesen az szükséges, hogy a lemez megfelelő csomag, amelyet azután a betöltése).
Lehetőségek a csomagokat koncentrálódik a SysUtils egységet. Mi érdekli a következők:
- letölti a csomagot a megadott fájlt a memóriában, teljesen előkészíti a műveletet.
- eltávolítja az adott csomag a memóriából.
Amellett, hogy ezek a funkciók a SysUtils egység le packet header szerkezet, funkció, információkat tartalmaz a csomag és néhány más hasznos függvényt, kezelni, hogy a leolvasó.
Ingyen ebéd, mint tudjuk, ez történik, csak egy egérfogó. Ezért, miután megvizsgálta az érvek és ellenérvek figyelembe kell vennie ezt a megközelítést. Nézzük meg őket növekvő fontossági sorrendben.
- Ezzel szemben a dll-plugin'ov, akkor kap csatlakozik a Delphi és C ++ Builder'u (és ez egy plusz.)).
- Persze, van néhány általános szoftver interfész csomag - a legkisebb csomag nulla hossza. Ezen túlmenően, a Delphi intelligens kapcsoló nem lesz képes, hogy dobja ki a felesleges eljárások megosztott csomagok - sőt, bármilyen módszerrel lehet kérni később valamilyen más külső csomagoláson. Ezért lehetséges, hogy növelje a teljes mérete a program kódját. Ez a növekedés szinte elhanyagolható, ha a csomag csak a megosztott interfészt plugin'a és sokkal többet, ha szeretné osztani a standard VCL csomagokat. Ez azonban könnyen megtérül, ha plugin'ov sok. Ezen túlmenően, a standard csomagokat lehet használni a különböző programokat.
- Talán a legjelentősebb hátránya eredő előzőt. A csomag oszthatatlan, mert nem ismert, hogy milyen eljárásainak szüksége, ezért betöltődik a memóriába. Még ha egyetlen elem a csomag, nem okoz a másik, és nem utal más források csomagot, a csomag betöltődik a memóriába. Ez megint nem nagyon észrevehető, ha a csomag csak a csupasz felületet kisszámú eljárásokat. De ha ez néhány szabványos csomagok VCL, részt vesz a program memória növelhető igen jelentősen (több megabájt). Azonban ez kifizetődik egyszer, ha használ nagyszámú plugin'ov - ha már kiadott formájában dll, akkor mindegyikük tartalmaz egy jó része a standard modulok és ők tartják a memóriában egyszerre. Tény, hogy a javasolt módszer jobban skálázható, azaz a költségek csökkenni kezd, mint a több plugin'ov.
Módszer (amit csinálunk, és amit kapunk)
Predlagemaya alkalmazások építése közben a szerkezet a következő: filc kód = Major Program Interface plugin'ov + + plugin. Mindhárom összetevőknek kell külön fájlokban (a program - a EXE, a többi - a BPL csomagok). A program képes betölteni csomagokat a memóriába, és hozzáférést biztosít a feltöltött absztrakt plugin'a leszármazottai. Plugin leszármazottja az absztrakt osztály deklarált interfész modul. Program és használata bővítmény interfész modul, de ez egy külön csomagot, és a memória lesz jelen egy ekzemplyare.
Egyetlen megmaradt kérdés - mint a fő program utal tárgyak vagy osztályokat (class hivatkozásokat) a megfelelő típusú? Erre plugin'ov diszpécser tárolja az interfész modul, illetve a legegyszerűbb esetben csak TList lépő, az egyes modulok válnak elérhetővé osztályok. A fejlettebb esetben osztályok diszpécser olyan keresési letöltött osztályok, amelyek leszármazottai a megadott prioritások betöltésekor, stb
Egyértelmű, hogy elértük ezt a célt - nincs redundancia kód (feltéve, hogy az összes könyvtárat, beleértve a szabványos VCL könyvtár csomagokban használható), írásban plugin'a egyszerűsíteni a határ. Mit lehet elérni?
És meg tudod csinálni még izgalmasabb dolgokat. Ha teszünk az összes alapvető programa a csomagot, és EXE-fájl között csak a teremtés és megnyitja a fő formája eljárás, külső plugin teljes hozzáférést kap az összes modul a program, beleértve a fő formája. Így tudunk írni egy plugin, ami a saját, erőlködés nélkül a részét a fejét a programot, majd helyezze az elemet a főmenüben, és egy gombot az eszköztáron a csapat, amely fogják hívni egy külső kód. Érdemes gondolni a javasolt módszer - amivel egy adott könyvtár kicsi (csak a kódot) modult, add, hogy a program a következő lehetőséget, újrafordítás nélkül a fő program.
A modulok (pluginek) Delphi: 1. példa
Az első példa bizonyítja a lehetőséget felismerve plugin'a leszármazottja az adott osztályban. Tükrözik a tény, hogy egy példát ne legyen se túl nehéz, sem túl erőltetett, úgy döntöttem, hogy a megfelelő jelölt lesz egy osztály, amely megjeleníti egy sornyi szöveget valamilyen formában. Egy hasonló technika hasznos lehet, például ha írsz az e-mail kliens, és azt szeretnék, hogy lehetővé adatokat exportálni, hogy a különböző formátumok, vagy egy másik ügyfél.
Létrehozunk egy előre definiált osztályt, amely a kivitel összhangban tekstvy fájlt, és egy külső bővítmény, amely egy osztály, amely képes exportálni a vonalat. Nos, mondjuk, HTML. Exportálás Excel vagy adatbázis fog nekünk egy szép példája a határon.
Így figyelembe vesszük a meghatározása az absztrakt osztály:
Remélem, senki sem fog vádolni túlzott bonyolultsága például :). És azok, akik olvassák ezt a kódrészletet, kiáltás hangosan: „Meg lehet csinálni a dll!” Utalok a reflexió a dll méretben. Miután TExporter leszármazottai BeginExport módszert könnyen megjelenítheti export beállítások formában.
A következő napirendi pont a programunk menedzser betöltött osztályok. Mint mondtam, ez lehet, hogy csak TList:
Ebben a kódot, azt hiszem, hogy magyarázni semmit.
Export egy egyszerű szöveges fájl
Most írunk a standard leszármazottja TExporter, biztosítva a visszavonását sorokat egy szöveges fájlt.
Úgy gondoljuk, hogy korrestnost hívja BeginExport módszerek és EndExport biztosít szülő programot, és nem gondol a lehetséges bajok a megnyitott fájlt. Továbbá meg kell jegyezni, hogy a modul használ ablakokat használó Forms, stb Végül, figyeljen szakaszok a modul inicializálása és véglegesítése - használjuk a lehetőséget, hogy Delphi kifejezések olyan, mint egy tárgy.
A főprogram én csak néhányat említsünk a módszerek, amelyek szemléltetik a külső csomagok, valamint a teljes szöveg megtalálható az archívumban, hogy kíséri a cikket.
Ez az eljárás megy át a lista a regisztrált osztályok (feltételezve, hogy csak leszármazottai TExporter), és megjeleníti őket „olvasható” nevek a ListBox.
Ez az eljárás letölti a csomagot a „vezetékes” a neve (na jó, ez csak egy példa :)), és tárolja a fogantyúja. Ezt követően, akkor frissíti a listát, így biztos lehet benne, hogy az új osztály van jegyezve.
Nos, azt hiszem, minden világos.
Ez az eljárás export vonalak segítségével a regisztrált Class plugin'a. Mi használjuk a tény, hogy tisztában vagyunk egy absztrakt osztály, ezért nyugodtan hívja a megfelelő módszereket. Itt meg kell figyelni, hogy a létrehozásának folyamatában például az osztály plugin'a.
Nagyítás az archív néhány könyvtárat (például c: \ bebebe :)) és nyitott Demo1ProjectGroup.bpg projekt csoport. Csoportok használata hasznos, mert gyakran kell váltani a fő program, és két csomag - ezek a különböző projektek. Remélem, hogy ha megnyomja a „Build All Projects” minden sikeres összeállítani.
Nézzük a fejét a projekt lehetőséget, látni fogja, hogy az oldalon csomagok jelzi, hogy melyik a csomagok felhasznált nem köthető az exe-fájlt. Meg kell jegyezni, hogy ha bekapcsolja csak PluginInterfaceProject, a gép figyelembe kell venni a külső, és az összes csomagot általa használt - ebben az esetben Vcl5.dpl. De ha fel az alapforma bármely komponensének dolgozik BDE, a csomag lehet VclDB5.bpl prikompilirovan (optimalizálással, természetesen), hogy az EXE-fájlt.
Mi mást mondhatnék? Talán érdemes megjegyezni, hogy a „felhajtás” a csomagok gyakran unalmas és tele van „megmagyarázhatatlan hibák”, amíg lefagy Delphi. Ezek azonban mind végül kiderül, hogy az eredmény a figyelmetlenség Fejlesztő -, mert a kötődés futási időben nem könnyű dolog. Így néz hol van összeállítása egy csomagot, akkor újra kell fordítanunk a megfelelő időben plugin'ov ha megváltozott absztrakt osztály, győződjön meg róla, hogy ne forgassa a gépen 10 kópia DPL-csomag, mert azt gondolhatja, hogy a program betölti valahol és rossz.