Borg la cele doua firme retezate. Acum se va face produsele, iar a doua va fi pentru ei de a face patch-uri.
Când m-am întâlnit prima dată cu sarcina de a organiza în timpul rulării module încărcabile (plugins) pentru Delphi-program, răspunsul este găsit destul de repede. Așa cum se întâmplă uneori, în astfel de situații, nu mă gândesc cu adevărat despre cum să rezolve o problemă similară alte razrabtochiki.
Mai precis, am dat seama că mulți oameni folosesc metoda destul de evident - referire la funcțiile DLL sunt reîncărcate cu nume specificate. Această abordare poate părea evidentă și simplu, în cazul în care sarcina este încredințată plugin-ul este simplu. Exemple tipice - codecurile vnieshnie, interpretoare de pachete, etc.
Cu toate acestea, abordarea descrisă are mai multe dezavantaje, de multe ori destul de substanțiale. Le voi descrie în secțiunea următoare.
În același timp, sunt adesea întrebat cum de a crea un mecanism de plugin'ov convenabil și am descris metoda lui. Metoda propusă de mine, bazată pe utilizarea mecanismului, care foloseste foarte Delphi IDE - pachete (pachete).
Problemă (dezavantaje DLL-plugin'ov)
- Toate modulele utilizate sunt compilate în DLL.
Imaginați-vă că aveți nevoie pentru a face un plug-in care afișează un formular cu setările. De îndată ce veți intra într-o expresie DLL utilizează formulare. Modul de formulare și toate modulele, Forms modulul utilizat va fi legat în DLL-ul, care crește în mod dramatic dimensiunea sa. Imaginați-vă acum că trebuie să conectați mai multe plugin'ov, fiecare dintre care va oferi forma sau filă pentru a modifica parametrii. După cum a scris vederea clasic, sfasietoare.
dezavantaj anterioare este cantitativ, adică pur și simplu creșterea dimensiunii proiectului. Dar implică o lipsă de calitate. Luați în considerare exemplul de ea. Să presupunem că aveți nevoie pentru a crea un descărcabile Derivatoare pachete. Puteți defini o clasă abstractă în modulul TParser UParser și doriți toate Derivatoare moștenesc de la el. Dar, pentru ca să descrie într-un descendent al DLL TParser, trebuie să includă unitatea de UParser la lista de utilizări pentru DLL. Iar pentru programul principal ar putea ocupa TParser și descendenții săi, ar trebui, de asemenea, incluse utilizează UParses. Problema este că aceste module vor fi în memorie și de două ori TParser, care cunoaște programul principal nu este același cu cel care cunoaște plugin-ul.
Problema (pe care am dori)
Este simplu. Ne-ar dori să vadă programul principal ar putea, fără trucuri speciale pentru a lucra cu module externe, cum ar fi descendenți ai unei clase abstracte, și în timp ce nu au nici o redundanță cod. Astfel, este de dorit să se schimbe programul principal a trebuit să plătească cât mai puțin posibil, chiar și la o plugin'a foarte avansată funcționalitate.
Mijloace (pachete și funcții pentru a lucra cu ei)
Pachetele au apărut în a treia versiune a Delphi. Care este pachetul? Pachetul - un set de module compilate combinate într-un singur fișier. Stocarea inițială de text lot I .dpk fișier conține doar modulele care indică conțin (con ine) pachetul (aici, „liber“ înseamnă, de asemenea „da“) și kaie alte pachete care face referire (necesită). Când pachetul komptlyatsii devine două fișiere - * .dcp și * .dpl. Primul este folosit pur și simplu ca o bibliotecă modul. Suntem mai interesați în al doilea.
Caracteristica principală a pachetului este că acesta nu include codul, care este utilizat. Ie în cazul în care unele module folosesc o bibliotecă mare de funcții și clase, puteți cere prezența lor, dar nu include în pachet. Tu întrebi, ce altceva este nou, deoarece modulele convenționale, de asemenea, nu includ .dcu-fișier tot codul? Un lucru nou este că RDP-pack este un format specific DLL completă (de exemplu, cu procedurile convenite, dezvoltatorii Delphi exportat nume). Atunci când încărcați un pachet în memorie setat automat un pachet deja descărcat, iar în cazul în care pachetul de descărcare necesită chiar unele pachete care sunt încărcate acestea sunt. În plus, spre deosebire de modulele convenționale, un modul de program este folosit din ambalajul exterior este, de asemenea, nu este necesar să se includă codul. Astfel, putem scrie dimensiunea EXE-program de mai multe zeci Kbyte (desigur, va cere ca pachetul de disc corespunzător, care este apoi să se încarce).
Opțiunile pentru pachetele sunt concentrate în unitatea SysUtils. Suntem interesați de cele următoarele:
- descarcă pachetul cu numele de fișier specificat în memorie, pregătindu-l complet pentru funcționare.
- un pachet dat descarcă din memorie.
În plus față de aceste funcții în unitatea SysUtils descrisă ca structura antet de pachet, funcția, informații despre conținutul ambalajului și alte câteva funcții utile, se ocupă de acel cititor.
masa de prânz gratuit, după cum știți, se întâmplă numai într-o cursă de șoareci. Prin urmare, după examinarea argumentelor pro și contra ar trebui să ia în considerare această abordare. Ne vom uita la ei, în ordinea importanței lor ascendentă.
- Spre deosebire de dll-plugin'ov, te atașat la Delphi și C ++ Builder'u (și asta e un plus.)).
- Desigur, există unele pachet de interfață software deasupra capului - cel mai mic pachet are o lungime de zero. În plus, Delphi linker inteligent nu va fi în măsură să arunce procedurile inutile de pachete partajate - de fapt, orice metodă poate fi solicitat mai târziu, într-un alt ambalaj exterior. Prin urmare, este posibil pentru a mări dimensiunea totală a codului de program. Această creștere este aproape neglijabilă în cazul în care pachetul conține numai interfața comună pentru plugin'a și mult mai mult, dacă doriți să împartă pachetele standard de VCL. Cu toate acestea, este ușor de a plăti în cazul în care plugin'ov mult. În plus, pachetele standard pot fi utilizate de către diferite programe.
- Poate cel mai important dezavantaj care rezultă din cea anterioară. Pachetul este indivizibilă, deoarece nu se știe ce nevoie procedurile sale, prin urmare, acesta este încărcat în memorie. Chiar dacă folosiți o singură caracteristică a pachetului, nu cauzează cealaltă, și să nu se refere la alt pachet de resurse, pachetul este încărcat în memorie. Acest lucru, din nou, nu este foarte vizibil, în cazul în care pachetul este doar interfata goale cu un număr mic de proceduri. Dar dacă este un standard de câteva pachete VCL, este angajat în memoria program poate fi mărit foarte substanțial (mai multe megaocteți). Cu toate acestea, se amortizează din nou, dacă utilizați un număr mare de plugin'ov - în cazul în care au fost emise sub forma unui dll, atunci fiecare dintre ele ar conține o bună parte din module standard și vor fi păstrate în memorie simultan. De fapt, metoda propusă este mai scalabil, de exemplu, Costurile încep să scadă pe măsură ce numărul de plugin'ov.
Metoda (ceea ce facem, și ceea ce primim)
aplicatii Predlagemaya in timp ce construirea unei structuri, după cum urmează: pâslă este codul = program major Interfață plugin'ov + + plug. Toate cele trei dintre aceste componente trebuie să fie în fișiere separate (programul - în EXE, restul - în pachetele BPL). Programul poate încărca pachete în memorie și accesul la descendenții plugin'a încărcate abstracte. Plugin-ul este un descendent al clasei abstracte declarate în modulul de interfață. Program și utilizarea plugin-ul modulul de interfata, dar este într-un pachet și de memorie separat, va fi prezentă într-o singură ekzemplyare.
O întrebare rămasă - ca programul principal se va referi la obiecte sau clase (trimiteri la clasa) tipul corect? Pentru acest dispecer plugin'ov este stocată în modulul de interfață sau, în cel mai simplu caz, doar TList, care intră în fiecare modul clase disponibile devin. În cazurile mai avansate de clase dispecer poate oferi căutare au fost descărcate clase care sunt descendenți ai priorităților specificate, atunci când încărcarea, etc.
Este clar că ne-am atins acest obiectiv - nici un cod de redundanță (cu condiția ca toate bibliotecile, inclusiv biblioteca VCL standard utilizat în pachete), scris plugin'a simplificat la limita. Ce poate fi realizat mai mult?
Și tu poți face lucruri chiar mai interesant. Dacă am pus toate PROGRAMA de bază în pachet, și EXE-fișier va include doar crearea și deschiderea principala formă de procedură, un plugin extern poate avea acces deplin la toate modulele programului, inclusiv o formă principală. Deci, putem scrie un plugin, care pe cont propriu, fără nici un efort din partea șefului programului, va plasa elementul în meniul principal și un buton în bara de instrumente pe echipa care va fi numit un cod extern. Merită să ne gândim la utilizarea metodei propuse - punerea unui anumit director mic (acesta doar codul) plugin-ul, adăugați programul la următoarea oportunitate, fără a recompilarea programul principal.
Modulele încărcabile (plugins) în Delphi: EXEMPLUL 1
Primul exemplu demonstrează posibilitatea plugin'a realizarea descendent dintr-o anumită clasă. Reflectați asupra faptului că, de exemplu, ar trebui să fie nici prea greu, nici prea îndepărtat, am decis că un candidat adecvat va fi o clasă care afișează o linie de text într-o formă. O tehnică similară poate fi utilă, de exemplu, dacă scrieți clientul de e-mail și doriți să facă posibilă pentru a exporta datele din ea în diferite formate de fișiere sau un alt client.
Vom crea o clasă predefinită care exportă în linie de fișiere tekstvy și un plugin extern, care conține o clasă care este capabil să exporte linia. Ei bine, să zicem, în HTML. Export în Excel sau o bază de date ne va lua un exemplu al frontierei.
Astfel, considerăm definiția clasă abstractă:
Sper că nimeni nu mă va acuza de exemplu excesiva complexitate :). Iar cei care citesc această bucată de cod, striga cu glas tare: „Ar putea fi făcut în dll!“ Mă refer la reflecția privind dimensiunile dll. După descendenții TExporter BeginExport metodă poate afișa cu ușurință forma setările de export.
Următorul punct de managerul programului nostru este de clase încărcate. Așa cum am spus, poate fi doar TList:
În acest cod, cred că, pentru a explica nimic.
Export într-un fișier text simplu
Acum vom scrie descendentul standard TExporter, asigurând retragerea liniilor într-un fișier text.
Noi credem că korrestnost numesc metode BeginExport și EndExport oferă programul părinte și nu cred că despre posibilele probleme cu fișierul deschis. Mai mult, trebuie remarcat faptul că modulul utilizează Dialoguri care utilizează Forms etc. În cele din urmă, să acorde o atenție la secțiunile inițializarea modulului și finalizarea - vom folosi oportunitatea de a Delphi se referă la o clasă ca un obiect.
Din programul principal, voi menționa doar câteva metode care ilustrează utilizarea ambalajelor externe, iar textul integral poate fi găsit în arhiva care însoțește articolul.
Această procedură trece prin lista de clase înregistrate (presupunând că există doar descendenții TExporter) și le afișează numele de „ușor de citit“ în ListBox.
Această procedură descarcă pachetul de „hard-wired“ în numele (bine, acesta este doar un exemplu :)) și stochează mânerul său. După aceea, se actualizează lista, astfel încât să puteți fi siguri că noua clasă este înregistrată.
Ei bine, atunci, cred că totul este clar.
Această procedură produce linii de export utilizând plugin'a Clasa înregistrată. Noi folosim faptul că suntem conștienți de o clasă abstractă, astfel încât să putem apela în siguranță metodele adecvate. Aici ar trebui să acorde o atenție la procesul de creare a unei instanțe a plugin'a de clasă.
Extindeți arhiva într-o anumită director (cum ar fi c: \ bebebe :)) și Demo1ProjectGroup.bpg deschis de grup de proiect. Utilizarea grupurilor este utilă, pentru că de multe ori trebuie pentru a comuta între programul principal și două pachete - acestea sunt proiecte diferite. Sper că dacă apăsați „Build All Projects“ toate compilat cu succes.
Privind în fruntea opțiunilor de proiect, veți vedea că pe pagina de pachete indicați care dintre pachetele utilizate nu sunt corelate la exe-fișier. Trebuie remarcat faptul că, chiar dacă la rândul său, numai PluginInterfaceProject, aparatul va fi considerat ca având, și toate pachetele utilizate de acesta - în acest caz Vcl5.dpl. Dar dacă pui pe forma de bază a oricărei componente de a lucra cu BDE, pachetul poate fi VclDB5.bpl prikompilirovan (cu optimizarea, desigur) pentru a EXE fișiere.
Ce altceva pot să spun? Poate că este de remarcat faptul că „tam-tam“ cu pachete este adesea obositoare și plină de „erori inexplicabile“ până se blochează Delphi. Cu toate acestea, ei tot rândul său, în cele din urmă să fie rezultatul neglijenței Developer - pentru că legarea la rulare nu este un lucru ușor. Deci, în cazul în care ceas compilați un pachet, trebuie să recompilați plugin'ov în timp util în cazul în care sa schimbat de clasă abstractă, asigurați-vă că nu se rostogolească pe masina 10 copii DPL-pack, deoarece ați putea crede că programul va încărca minciuni undeva și greșit.