Sudėtingų delphi dll kūrimo pavyzdžiai. Įkeliamas DLL į delphi programą

Mieli kolegos!

Šiame straipsnyje pabandysiu atsakyti į klausimus: Kas yra DLL? Kam tai? Ir kaip sukurti ir naudoti DLL su pagalba Delphi.

Kas yra DLL?

Dinaminių nuorodų biblioteka arba trumpiau DLL yra biblioteka, kurioje yra duomenų arba funkcijų rinkinys, skirtas naudoti kitose programose.

Naudojimo sritys:

  • Išteklių saugojimas: piktogramos, garsai, žymekliai ir kt. Sutaupome vykdomųjų failų dydžio, sujungdami išteklius į vieną biblioteką.
  • Atskirų programos modulių ir sąsajų formų išdėstymas. Gauname galimybę dalinai atnaujinti aplikaciją, o esant dinaminiam ryšiui galima atnaujinti modulius neperkraunant pagrindinės programos.
  • Naudoti kaip papildinius (PlugIn). Suteikiame galimybę išplėsti aplikacijos funkcionalumą neperrašant pagrindinio programos kodo.
  • Biblioteka gali būti naudojama skirtingomis programavimo kalbomis, nepriklausomai nuo kalbos, kuria ji buvo parašyta.

Sukurkite savo DLL.

Norėdami sukurti biblioteką, eikite į meniu Failas -> Kita ir pasirinkti Delphi projektai -> Dinaminės nuorodos biblioteka.
Atsidarys kodo tekstas su bibliotekos kūrimo šablonu:

Bibliotekos projektas1; naudoja System.SysUtils, System.Classes; ($R *.res) pradžios pabaiga.

Išteklių išdėstymas

Pridėkime prie bibliotekos piktogramą, kurią vėliau naudosime pagrindinėje programoje.
Kaip pridėti išteklių prie projekto, išsamiai aprašyta straipsnyje.

Pridėkime formą „Apie programą“.
Spustelėkite Failas -> Nauja -> VCL forma. Pridėkime tekstą ir mygtuką „Gerai“:

Pridėkime funkciją, kuri parodys standartą Žinučių dėžutė su klausimu, mygtukais „Taip“, „Ne“ ir su rezultatu formoje Tiesa arba Netiesa.

Funkcija YesNoDlg(const Klausimas: PChar): loginis; stdcall; begin Rezultatas:= (MessageBox(0, Klausimas, "Patvirtinimas", MB_YESNO + MB_ICONQUESTION) = ID_YES); galas;

Atkreipkite dėmesį į raktinį žodį stdcall. Jis tiksliai nustato, kaip parametrai ir rezultatai bus perduodami iškviečiant funkcijas. Daugiau galite perskaityti skambinimo sutarties wiki puslapyje.

Taip pat pridėsime procedūrą, kuri bus naudojama kaip pagrindinės programos įskiepis. Prie pagrindinio programos meniu bus pridėtas mygtukas „Apie programą“, kad būtų atidarytas mūsų sukurtas langas.
Procedūros kodas:

Procedure PlugIn (Forma: TForm); stdcall; var i: sveikasis skaičius; mi: TMenuItem; Pradėti nuo i:= 0 iki Form.ComponentCount – 1 pradėkite if (Form.Components[i].ClassName = "TMenuItem") ir (Form.Components[i].Name = "miHelp"), tada pradėkite mi:= TMenuItem .Create(Form.Components[i]); mi.Caption:= "Apie programą"; mi.OnClick:= fmAbout.onAboutButtonClick; TMeniuItem(Form.Components[i]).Add(mi); Išeiti; galas; galas; galas;

Programos forma kaip parametras perduodama procedūrai. Mes patikriname, ar yra meniu elementas pavadinimu „ miHelp Ir jei meniu rastas, pridėkite prie jo mūsų mygtuką.

Dabar nurodysime, kurias funkcijas ir procedūras galima naudoti mūsų bibliotekoje.
Pridėkime eilutę:

Eksportuoja papildinį, YesNoDlg;

Sukompiliuokime funkciją Projektas -> Sukurti arba naudojant greitąjį klavišą Shift + F9.
Jei kode nėra klaidų, projekto aplanke turėtų pasirodyti failas su plėtiniu DLL.

Dabar pereikime prie programos, kuri naudos mūsų biblioteką, kūrimo.

Sukurkime formą programoje Pagrindinis kuriame pridėsime komponentą šiais mygtukais: Programa -> Exit and Help. Paskutinei nustatykime pavadinimą - miHelp:

Pereikime prie formos kodo.

Funkcijos iš bibliotekos DLL galima sujungti dviem būdais:
Statinis— biblioteka prijungiama paleidus programą. Jei bibliotekos arba funkcijos pavadinimas nerastas, programa sugeneruos klaidą ir nebus paleista.
Dinamiškas— biblioteka prijungiama prieš pat iškviečiant funkciją arba po konkretaus įvykio.

Panagrinėkime statinio ryšio būdą:

Įveskite TfmMain = class(TForm) Pagrindinis meniu: TMainMenu; miPrograma: TMenuItem; miExit: TMenuItem; miHelp: TMenuItem; procedūra FormCreate(Siuntėjas: TObject); procedūra miExitClick(Siuntėjas: TObject); privatus viešasis galas; procedūra PlugIn(Forma: TForm); stdcall; išorinis "SampleDLL.dll"; var...

raktinis žodis išorės rodo, kad ši funkcija prijungta iš išorinės bibliotekos.

Dėl renginio onCreate formą, pridėkite procedūros iškvietimą Prijungti:

Procedūra TfmMain.FormCreate(Siuntėjas: TObject); begin PlugIn(Self); galas;

Kaip parametras Forma dabartinę formą perduodame procedūrai (raktinis žodis Savarankiškai).

Pradedant programą, pagrindinio meniu skiltyje „Help“ turėtų būti elementas „Apie programą“.

Pereikime prie dinaminio ryšio metodo.

Mums reikės trijų funkcijų WinApi:

Įkelti biblioteką
Įkelia biblioteką į kompiuterio atmintį. Dėl to grąžina žymeklį į biblioteką atmintyje. Klaidos atveju jis grąžins 0.

Įkelti biblioteką(lpLibFileName: LPCWSTR): HMODULE;

lpLibFileName— bibliotekos failo pavadinimas.

GetProcAddress
Raskite funkciją bibliotekoje pagal pavadinimą. Rezultatas bus funkcijos rodyklė. Jei funkcija nerasta, ji grįš nulis.

GetProcAddress(hModule: HMODULE; lpProcName: LPCSTR): FARPROC;

hModulis
lpProcName— Funkcijos pavadinimas.

Nemokama biblioteka
Iškrauna biblioteką iš kompiuterio atminties. Sėkmės atveju rezultatas bus teisingas, o klaidos atveju - klaidingas.

FreeLibrary(hLibModule: HMODULE): BOOL;

hLibModule— Nukreipkite žymeklį į įkeltą biblioteką.

Dabar, naudodami dinaminį metodą, gausime išteklius, savo piktogramą ir pridėsime funkcijos iškvietimą prie mygtuko „Išeiti“. TaipNeDlg patvirtinkite, kad programa uždaryta.
Pridėkite kodą prie to paties onCreate įvykio:

Procedūra TfmMain.FormCreate(Siuntėjas: TObject); var DLLHandle: THandle; begin PlugIn(Self); DLLHandle:= LoadLibrary("SampleDLL.dll"); jei DLLHandle = 0, tada pakelkite Exception.Create("Nepavyko įtraukti bibliotekos 'SampleDLL'!"); pabandykite Self.Icon.LoadFromResourceName(DLLHandle, "my_icon"); pagaliau FreeLibrary(DLLHandle); galas; galas;

Ir dėl renginio paspaudus meniu punktas "Išeiti":

Procedūra TfmMain.miExitClick(Siuntėjas: TObject); var DLLHandle: THandle; Dlg: function(const) Klausimas: PChar: loginis; stdcall; begin DLLHandle:= LoadLibrary("SampleDLL.dll"); jei DLLHandle = 0, tada pakelkite Exception.Create("Nepavyko įtraukti bibliotekos 'SampleDLL'!"); try @Dlg:= GetProcAddress(DLLHandle, "YesNoDlg"); jei ne Assigned(@Dlg), tada pakelkite Exception.Create("Funkcija pavadinimu "YesNoDlg" nerasta bibliotekoje "SampleDLL"!"); if Dlg ("Išeiti iš programos?"), tada Uždaryti; pagaliau FreeLibrary(DLLHandle); galas; galas;

Jei viską parašėte teisingai, tada paleidus programą formos piktograma turėtų pasikeisti, reikia pridėti mygtuką "Apie programą", paspaudus ant jo pasirodys forma Apie ir kai paspausite išėjimo mygtuką, programa paprašys patvirtinimo: „Išeiti iš programos?

Tikiuosi, kad šis mažas funkcijų naudojimo pavyzdys jums bus naudingas. DLL bibliotekos.
Projekto šaltinius galima atsisiųsti.

Bent jau dauguma asmeninių kompiuterių vartotojų žino, kas yra DLL, ypač programuotojai, kuriais greičiausiai esate, jei skaitote šį straipsnį. Šiame straipsnyje pabandysiu peržvelgti visus bendruosius klausimus, susijusius su DLL.

Į ką tiksliai žiūrėsime:

  1. Kaip įprasta, iš „Hello World“ srities sukursime savo pirmąjį DLL.
  2. Išmokime naudotis šio DLL funkcijomis iš mūsų programų.
  3. Sužinokime, kaip peržiūrėti funkcijas, kurias eksportuoja konkretus DLL.
  4. Gali buti kas kita....

DLL kūrimo procesas

Pradėkime nuo paprasčiausio dalyko – savo pirmojo DLL parašymo, kuriame bus tik viena funkcija, rodanti pranešimą „Hello World“.

  1. Paleiskite Delphi (naudoju Delphi 6).
  2. Kitas: Failas -> Naujas ->Kita

Skirtuke Naujas dukart spustelėkite DLL vedlio objektą. Bus atidarytas naujas projektas. Pavyzdžiui, išsaugokite jį pavadinimu MyFirstDLL.

Grynas modulis turi kažką panašaus į tai:

biblioteka MyFirstDLL; naudoja SysUtils, Classes; ($R *.res) pradžios pabaiga.

Dabar parašykime tik vieną funkciją, kuri iš dialogų modulio iškvies ShowMessage(). Todėl prieš pradėdami procedūrą, į skyrių „Naudojimai“ įtraukime modulį Dialogai. Apytiksliai turėtumėte gauti:

biblioteka MyFirstDLL; naudoja dialogus; procedūra MyFirstFunc; stdcall; begin ShowMessage ("Sveikas pasaulis"); galas; eksportuoja MyFirstFunc; pradžia pabaiga.

Kaip matote, čia nėra nieko labai sudėtingo. Vienintelis dalykas, kurį pasakysiu, yra tai, kad funkcijas galite iškviesti tiek pavadinimu, tiek indeksu (skaičiumi), tam reikia parašyti taip:

Eksportuoja MyFirstFunc indeksą 1;

Jei šiame kode kas nors neaišku, pirmiausia pabandykite tai išsiaiškinti patys. Manau, kad dėl to problemų nebus... Bet jei kas yra, tai forumas.! Toliau, kaip dabar galite naudoti šią („MyFirstFunc“) funkciją iš kitų projektų?

DLL funkcijų naudojimas

Pirmas žingsnis žengtas, tik laiko klausimas... Kaip galime pasinaudoti šia funkcija?

Yra bent du atsisiuntimo būdai:

  1. Statinis
  2. Dinamiškas

Pirmenybė teikiama antrajam metodui, nes kraunant galime stebėti viską, kas vyksta, ir ištaisyti visas pakraunant įvykusias klaidas. Bet pirmiausia pažvelkime į pirmąjį metodą:

Sukuriame naują projektą, nuleidžiame vieną mygtuką ant formos ir šio mygtuko OnClick įvykyje įrašome taip:

Procedūra TForm1.Button1Click(Siuntėjas: TObject); pradėti MyProc(); galas;

Bet tai dar ne viskas! Projekto įgyvendinimo skiltyje rašykite:

Diegimo procedūra MyProc(); stdcall; išorinis „MyFirstDLL.dll“ pavadinimas „MyFirstFunc“;

Pasiruošę! Sudarykite projektą ir paspauskite mygtuką! Jei pasirodys jūsų pranešimas, tada viskas gerai!

Dabar pažvelkime į dinaminio įkėlimo metodą. Šiam metodui naudokite funkciją LoadLibrary() ir pabaigoje, norėdami iškrauti, naudokite FreeLibrary().

Pažvelkite į pavyzdį:

Procedūra TForm1.Button1Click(Siuntėjas: TObject); tipas TMyFunc = procedūra; var DLLInstance: THandle; MyFunc: TMyFunc; begin DLLInstance:= LoadLibrary(PChar("MyFirstDLL.dll")); if (DLLInstance = 0) then begin MessageDlg("Neįmanoma įkelti DLL", mtError, , 0); Išeiti; galas; pabandykite @MyFunc:= GetProcAddress(DLLInstance, "MyFirstFunc"); if Assigned(@MyFunc) then MyFunc() else MessageDlg("Reikalinga procedūra nerasta!.", mtError, , 0); galiausiai FreeLibrary (DLLInstance); galas; galas;

Sėkmingai įkėlus DLL su LoadLibrary() funkcija, naudodamiesi GetProcAddress() rasime savo funkcijos adresą, kuriuo iš DLL iškviesime savo procedūrą. Galų gale jums tikrai reikia atlikti FreeLibrary (). Tai taip svarbu, kad po sėkmingo atsisiuntimo įtraukiau visą kodą iki pat FreeLibrary(), bandydamas galiausiai blokuoti. Tai užtikrina, kad „FreeLibrary“ bus vykdoma, net jei įvyks netikėta išimtis vykdant veiksmus „try, išskyrus“ bloke.

Esmė ta, kad sėkmingi LoadLibrary ir FreeLibrary skambučiai turi būti susieti. Ir todėl. Sistema kiekvienai proceso įkeltai bibliotekai palaiko vidinį skaitiklį, kuris padidėja 1 kiekvieną kartą sėkmingai iškvietus LoadLibrary. Atitinkamai, kai vykdoma FreeLibrary, jis sumažina šį skaitiklį, o jei jis tampa lygus nuliui, tai reiškia, kad ši biblioteka šiam procesui nebereikalinga ir gali būti saugiai pašalinta iš atminties.

Jei nesilaikoma susiejimo taisyklės, tai gali sukelti priešlaikinį bibliotekos iškėlimą (jei yra papildoma FreeLibrary) iš atminties arba jos „įstrigimą“ (jei nepakanka FreeLibrary).

Jei laikysitės šios taisyklės, jums nereikės jaudintis dėl galimo LoadLibrary / FreeLibrary skambučių įdėjimo.

Konkretaus DLL funkcijų peržiūra

Dabar pažiūrėkime, kaip galime išgauti visus funkcijų pavadinimus iš PE formato failų, kuriuose yra DLL. Čia nenagrinėsime PE formato struktūros, todėl šaltinis bus be paaiškinimo.

Taigi, sukurkite naują projektą, į formą įmeskite ListBox, joje parodysime funkcijų pavadinimus.

Štai visas projektas:

Vienetas 1 vienetas; sąsaja naudoja „Windows“, „Messages“, „SysUtils“, „Variantai“, „Klasės“, „Grafika“, „Valdikliai“, „Formos“, „Dialogai“, „StdCtrl“; tipas TForm1 = class(TForm) lb: TListBox; procedūra FormCreate(Siuntėjas: TObject); privačios ( Privačios deklaracijos ) cmdline: String; ImageBase: DWord; DosHeader: PImageDosHeader; PeHeader: PImageNtHeaders; PEExport: PImageExportDirectory; pname:PDWord; pavadinimas: PChar; viešas ( Viešos deklaracijos ) pabaiga; var Form1: TForm1; įgyvendinimo ($R *.dfm) procedūra TForm1.FormCreate(Sender: TObject); procedūra FatalOsError; begin ShowMessage(SysErrorMessage(GetLastError())); Nutraukti; galas; Var i: sveikasis skaičius; pradėti bandyti if (ParamCount() IMAGE_DOS_SIGNATURE) then FatalOsError; PEHeader:= PImageNtHeaders(DWord(ImageBase) + DWord(DosHeader^._lfanew)); if (PEHeader^.Signature IMAGE_NT_SIGNATURE) then FatalOsError; PExport:= PImageExportDirectory(ImageBase + DWord(PEHeader^.OptionalHeader.DataDirectory.VirtualAddress)); pname:= PDWord(ImageBase + DWord(PExport^.AddressOfNames)); Jei i:= 0 iki PExport^.Vardų skaičius - 1 pradėkite pavadinimą:= PChar(PDWord(DWord(ImageBase) + PDword(pname)^)); lb.Items.Add(vardas); inc(pname); galas; pagaliau FreeLibrary(ImageBase); galas; išskyrus Application.ShowMainForm:= False; Paraiška. Nutraukti; galas; galas; galas.

Jei norite patys išsiaiškinti kodą ir kažkas jums netinka, mūsų forumas tikrai jums padės, užsukite!

Prie visų DLL pridedame savo peržiūros programą

Mes turime paruoštą DLL su funkcija ir funkcijų peržiūros programą. Belieka pridėti tam tikrą funkcionalumą tolesnio darbo patogumui. Padarykime tai... Atidarykite bet kurį aplanką „Explorer“. Eikite į Įrankiai -> Aplanko parinktys... Eikite į skirtuką "Failų tipai". Sąraše ieškome DLL formato. Jei tokio dalyko nėra, spustelėkite mygtuką „Sukurti“ ir lauke „Plėtinys“ parašykite - DLL. Spustelėkite Gerai. Randame savo sukurtą tipą – DLL. Pasirinkite jį ir spustelėkite „Išplėstinė“. Kitas „Sukurti“, lauke „Veiksmai“ rašome, kas bus rodoma kontekstiniame meniu, pavyzdžiui, „DLL Viewer“. Per peržiūrą ieškome savo programos.

Viskas paruošta!

Dabar, kai dešiniuoju pelės mygtuku spustelėsite DLL formato failą, mūsų DLL peržiūros programa pasirodys meniu. Pasirinkite jį ir pamatykite visas funkcijas!

Tai viskas, ačiū už dėmesį!

Atkreipiu jūsų dėmesį į kitą naujienlaiškio numerį, kuriame ir toliau aptarsiu
DLL kūrimo ir naudojimo Borland Delphi problemos. Naujiems prenumeratoriams pranešu,
kad jie galėtų peržiūrėti pirmąją straipsnio dalį pašto archyve, numerio 13 numeris.
Atsiprašau tų, kurie man parašė, bet negavo atsakymo. Artimiausiu metu pasistengsiu tai ištaisyti.
Taigi tęskime.

Prieš pradėdami naudoti bet kokią procedūrą ar funkciją, esančią dinaminėje bibliotekoje,
reikia įkelti DLL į RAM. Biblioteką galima įkelti
vienu iš dviejų būdų: statinio ir dinaminio.
Abu metodai turi ir privalumų, ir trūkumų.
Statinis įkėlimas reiškia, kad dinaminė biblioteka įkeliama automatiškai
kai paleidžiama ją naudojanti programa. Norėdami naudoti šį atsisiuntimo būdą,
apibūdindami, iš ko eksportuojama, turite naudoti išorinį raktinį žodį
dinaminės bibliotekos funkcija arba procedūra. DLL automatiškai įkeliamas, kai programa paleidžiama,
ir galite naudoti visas iš jos eksportuotas procedūras taip pat kaip
tarsi jie būtų aprašyti programų moduliuose.
Tai lengviausias būdas naudoti kodą, įdėtą į DLL.
Šio metodo trūkumas yra tas, kad jei bibliotekos failas, kuriame
programoje yra nuoroda, jei jos trūksta, programa atsisako įkelti.
Dinaminio metodo esmė ta, kad neįkeliate bibliotekos, kai programa paleidžiama,
ir tuo momentu, kai tau to tikrai reikia. Spręskite patys, nes jei aprašyta funkcija
dinaminėje bibliotekoje, naudojama tik 10% programų paleidimų, tada visiškai ne
Nėra prasmės naudoti statinio įkėlimo metodą. Šiuo atveju biblioteka iškraunama iš atminties
taip pat atliekama jums kontroliuojant. Kitas šio metodo privalumas
DLL įkėlimas reiškia, kad sutrumpėja (dėl akivaizdžių priežasčių) jūsų programos paleidimo laikas.
Kokie šio metodo trūkumai? Pagrindinis dalykas, man atrodo, yra naudojimas
Šis metodas yra sudėtingesnis nei aukščiau aptartas statinis apkrovimas.
Pirmiausia turite naudoti „Windows API LoadLibrary“ funkciją.
Norėdami gauti žymeklį į eksportuotą procedūrą arba funkciją, turite
naudokite funkciją GetProcAddress. Baigę naudoti DLL
turi būti iškrautas naudojant FreeLibrary.
Iš DLL įkeltos iškvietimo procedūros ir funkcijos.
Procedūrų ir funkcijų iškvietimo būdas priklauso nuo to, kaip įkėlėte dinaminę biblioteką,
kurioje yra šios paprogramės.
Iškviesti funkcijas ir procedūras iš statiškai įkeltų DLL yra gana paprasta. Iš pradžių programoje
turi būti eksportuojamos funkcijos (procedūros) aprašymas. Po to galėsite juos naudoti
taip, lyg jie būtų aprašyti viename iš jūsų programos modulių.
Norėdami importuoti funkciją ar procedūrą, esančią DLL, turite naudoti
išorinį modifikatorių savo deklaracijoje. Pavyzdžiui, „HelloWorld“ procedūrai, kurią aptarėme aukščiau
Skambinimo programoje turi būti ši eilutė:
procedūra SayHello(AFforma: TForm); išorinis myfirstdll.dll“;
Išorinis raktinis žodis nurodo kompiliatoriui, kad procedūrą galima rasti
dinaminė biblioteka (mūsų atveju - myfirstdll.dll).
Tada šios procedūros kvietimas atrodo taip:
...
HelloWorld(savęs);
...
Importuodami funkcijas ir procedūras būkite ypač atsargūs rašydami jų pavadinimus ir sąsajas!
Faktas yra tas, kad rengiant programą nėra tikrinamas objektų pavadinimų teisingumas,
eksportuotas iš DLL nebus įdiegtas, o jei neteisingai apibūdinote kurią nors funkciją,
tada išimtis bus taikoma tik programos vykdymo etape.
Importuoti iš DLL galima pagal procedūros (funkcijos) pavadinimą, eilės numerį arba
su kitu vardu.
Pirmuoju atveju tiesiog deklaruojate procedūros pavadinimą ir biblioteką, iš kurios ją importuojate
(žiūrėjome į tai šiek tiek aukščiau). Importuojant pagal eilės numerį reikia nurodyti būtent šį skaičių:
procedūra HelloWorld(AFforma: TForm); išorinis myfirstdll.dll indeksas 15;
Šiuo atveju pavadinimas, kurį suteikiate procedūrai importuodami, nebūtinai turi būti toks pat kaip
kuris jam buvo nurodytas pačiame DLL. Tie. aukščiau pateiktas įrašas reiškia,
kad importuojate iš dinaminės bibliotekos myfirstdll.dll joje eksportuotą procedūrą
penkioliktoji, o jūsų paraiškoje ši procedūra pavadinta SayHello.
Jei dėl kokių nors priežasčių nenaudojate aukščiau aprašyto importavimo metodo,
bet vis tiek norite pakeisti importuotos funkcijos pavadinimą (procedūra), galite naudoti trečiąjį metodą:
procedūra CoolProcedure; išorinis myfirstdll.dll pavadinimas „DoSomethingReallyCool“;
Čia importuota CoolProcedure procedūra pavadinta DoSomethingReallyCool.
Iškvietimo procedūros ir funkcijos, importuotos iš dinamiškai įkeltų bibliotekų
šiek tiek sudėtingesnis nei aukščiau aptartas metodas. Tokiu atveju reikia deklaruoti
rodyklė į funkciją ar procedūrą, kurią ketinate naudoti.
Prisimeni „HelloWorld“ procedūrą? Pažiūrėkime, ką reikia padaryti
iškviesti jį vykdyti, kai dinamiškai įkeliamas DLL. Visų pirma, tu
būtina deklaruoti tipą, kuris apibūdintų šią procedūrą:
tipo
THelloWorld = procedūra(AFforma: TForma);
Dabar turite įkelti dinaminę biblioteką naudodami GetProcAddress get
žymeklį į procedūrą, iškvieskite šią procedūrą vykdyti ir galiausiai iškelkite DLL iš atminties.
Žemiau yra kodas, rodantis, kaip tai galima padaryti:

DLLInstance: THandle ;

HelloWorld:THelloWorld;

pradėti

(įkelti DLL)

(gauname rodyklę)

(skambinti vykdymo procedūrą)

HelloWorld (Self) ;

(išimkite DLL iš RAM)

FreeLibrary(DLLInstance) ;

galas ;

Kaip minėta pirmiau, vienas iš statinio DLL įkėlimo trūkumų yra nesugebėjimas
programos veikimo tęsimas, kai nėra vienos ar kelių bibliotekų. Esant dinaminei
Atsisiųsdami turite galimybę programiškai valdyti tokias situacijas ir neleisti programai
iškrito“ pati. Remdamiesi reikšmėmis, kurias grąžino funkcijos LoadLibrary ir GetProcAddress, galite
nustatyti, ar biblioteka buvo sėkmingai įkelta ir ar joje rasta programai reikalinga procedūra.
Žemiau pateiktas kodas tai parodo.

procedūra TForm1.DynamicLoadBtnClick (Siuntėjas: TObject ) ;

tipo

THelloWorld = procedūra (AFforma: TForm);

DLLInstance: THandle ;

HelloWorld:THelloWorld;

pradėti

DLLInstance:= LoadLibrary("myfirstdll.dll") ;

jei DLLInstance = 0, tada pradėkite

MessageDlg( "Neįmanoma įkelti DLL", mtError, [ mbOK], 0 );

Išeiti;

galas ;

@HelloWorld:= GetProcAddress(DLLInstance, "HelloWorld" ) ;

jei @HelloWorld nulis tada

HelloWorld (savęs)

Kitas

MessageDlg( „Reikalinga procedūra nerasta!“., mtError, [ mbOK], 0 );

FreeLibrary(DLLInstance) ;

galas ;

DLL gali saugoti ne tik kodą, bet ir formas.
Be to, formų kūrimas ir talpinimas dinaminėje bibliotekoje per daug nesiskiria nuo darbo
su formomis įprastame projekte. Pirmiausia pažiūrėsime, kaip galima rašyti biblioteką,
su formomis, tada kalbėsime apie MDI technologijos naudojimą DLL.
Pademonstruosiu DLL su forma kūrimą naudodamas pavyzdį.
Taigi, pirmiausia sukurkime naują dinaminės bibliotekos projektą.
Norėdami tai padaryti, pasirinkite meniu elementą Failas|Naujas, tada dukart spustelėkite DLL piktogramą.
Po to pamatysite kodą, panašų į šį:

Išsaugokite gautą projektą. Pavadinkime tai DllForms.dpr.
Dabar reikia sukurti naują formą. Tai galima padaryti įvairiais būdais.
Pavyzdžiui, pasirinkus meniu punktą Failas|Nauja forma. Pridėkite kai kuriuos komponentus į formą.
Pavadinkime formą DllForm ir išsaugokime gautą modulį pavadinimu DllFormUnit.pas.
Grįžkime prie pagrindinio projekto modulio ir įdedame į jį funkciją ShowForm, kurios užduotis apims
sukurti formą ir parodyti ją ekrane. Tam naudokite žemiau esantį kodą.

Forma: TDLLForm;

pradėti

Rezultatas:= Form.ShowModal ;

Forma.Nemokama ;

galas ;

Atkreipkite dėmesį, kad norint, kad projektas būtų sudarytas be klaidų, prie naudojimo skilties reikia pridėti Formos modulį.
Eksportuojame savo funkciją naudodami eksportavimo raktinį žodį:
eksportas
ShowForm;
Sukompiliuojame projektą ir gauname dllforms.dll failą. Šie paprasti žingsniai yra viskas
ką reikia padaryti, kad pastebėtumėte, jog funkcija ShowForm deklaruojama naudojant stdcall raktinį žodį.
Tai signalizuoja kompiliatoriui, kad eksportuojant funkciją reikia naudoti susitarimą
pagal standartinį skambučio susitarimą. Eksportuojant funkciją tokiu būdu sukuriama
galimybė panaudoti sukurtą DLL ne tik Delphi sukurtose programose.
Iškvietimo susitarimai nustato, kaip argumentai perduodami iškviečiant funkciją.
Yra penkios pagrindinės sutartys: stdcall, cdecl, pascal, register ir safecall.
Daugiau apie tai galite sužinoti „Delphi“ žinyno failo skyriuje „Skambinimo susitarimai“.
Taip pat atkreipkite dėmesį, kad funkcijos ShowForm grąžinama reikšmė yra
atitinka ShowModal reikšmę. Tokiu būdu galite perduoti tam tikrą informaciją
apie formos būseną į skambinančią programą.
Žemiau yra du sąrašai, iš kurių pirmame yra visas failo kodas
DLL projektas (modulis su forma čia nerodomas), o antrasis yra iškvietimo programos modulis,
kuri naudoja ką tik sukurtą biblioteką.

bibliotekaDllForms;

naudoja

DllFormUnit „DllFormUnit.pas“ (DllForm) ;

($R *.RES)

funkcija ShowForm: Integer ; stdcall ;

Forma: TDLLForm;

pradėti

Forma:= TDLLForma.Sukurti(Application) ;

Rezultatas:= Form.ShowModal ;

Forma.Nemokama ;

galas ;

pradėti

galas.


vienetas TestAppUnit;

sąsaja

naudoja

„Windows“, „Messages“, „SysUtils“, „Klasės“, „Grafika“,

Valdikliai, Formos, Dialogai, StdCtrls;

tipo

TForm1 = klasė (TForm)

1 mygtukas: TButonas;

procedūra Button1Click(Siuntėjas: TOobjektas );

privatus

(Privačios deklaracijos)

viešas

(Viešieji pareiškimai)

galas ;

Forma1: TForm1;

funkcija ShowForm: Integer ; stdcall ;

Išorinis "dllforms.dll" ;

įgyvendinimas

($R *.DFM)

procedūra TForm1.Button1Click (Siuntėjas: TObject ) ;

pradėti

galas ;

galas.

Atkreipkite dėmesį, kad stdcall raktinis žodis taip pat buvo naudojamas eksportuojant funkciją.
Ypatingą dėmesį turėtumėte skirti darbui su antrinėmis formomis DLL. Jei pvz.
iškvietimo programoje pagrindinė forma turi FormStyle nuosavybės vertę, lygią MDIForm,
tada, kai bandote iš DLL iškviesti MDIChild-formą, ekrane pasirodo klaidos pranešimas,
kuri sakys, kad aktyvios MDI formos nėra.
Kai bandote parodyti vaikui langą, VCL patikrina, ar jis teisingas
Pagrindinės programos formos FormStyle ypatybės. Tačiau mūsų atveju atrodo, kad viskas yra tiesa.
Taigi koks reikalas? Problema ta, kad atliekant tokį patikrinimą, atsižvelgiama į programos objektą,
priklauso ne skambinančiajai programai, o pačiai dinaminei bibliotekai.
Na, natūralu, kadangi DLL neturi pagrindinės formos, patikrinimas išmeta klaidą.
Norėdami išvengti šios situacijos, turite priskirti dinaminės bibliotekos objektą Application
skambinančios programos objektas Programa. Natūralu, kad tai veiks tik tuo atveju, jei
kai skambinanti programa yra VCL programa. Be to, prieš iškraunant biblioteką iš atminties
būtina grąžinti bibliotekos Programos objekto reikšmę į pradinę būseną.
Tai leis atminties tvarkyklei išvalyti bibliotekos užimtą RAM.
Todėl turite išsaugoti žymeklį į bibliotekos vietinį programos objektą
globaliame kintamajame, kuris gali būti naudojamas jo vertei atkurti.
Taigi, grįžkime šiek tiek atgal ir išvardinkime veiksmus, su kuriais turime dirbti
DLL MDIChild formose.
Dinaminėje bibliotekoje sukuriame visuotinį TApplication tipo kintamąjį.
Mes saugome žymeklį į Application DLL objektą visuotiniame kintamajame.
Dinaminės bibliotekos objektui Application priskiriame žymeklį Application
skambinimo programa.
Sukuriame MDIChild formą ir su ja dirbame.
Mes grąžiname dinaminės bibliotekos objekto Application reikšmę į pradinę būseną
ir išimkite DLL iš atminties.
Pirmas žingsnis paprastas. Mes tiesiog įdedame šį kodą DLL modulio viršuje:
var
DllApp:TA programa;
Tada sukuriame procedūrą, kuri pakeis programos objekto vertę ir sukursime antrinę formą.
Procedūra gali atrodyti maždaug taip:

procedūra ShowMDIChild(MainApp: TApplication) ;

Vaikas: TMDIChild;

pradėti

jei nepriskirta (DllApp), tada pradėkite

DllApp:= Programa;

Taikymas:= MainApp;

galas ;

Child:= TMDIChild.Create(Application.MainForm) ;

Vaikas.Paroda ;

galas ;

Viskas, ką dabar turime padaryti, tai pateikti programos objekto grąžinimo vertę
į pradinę būseną. Tai darome naudodami MyDllProc procedūrą:

procedūra MyDLLProc(Priežastis: Integer ) ;

pradėti

jei Priežastis = DLL_PROCESS_DETACH, tada

(DLL iškraunamas. Atkurkite programos žymeklio reikšmę)

jei priskirta (DllApp), tada

Taikymas:= DllApp;

galas ;

Vietoj išvados.
Naudoti dinaminių nuorodų bibliotekas nėra taip sunku, kaip gali pasirodyti iš pirmo žvilgsnio.

Naudoti dinaminių nuorodų bibliotekas nėra taip sunku, kaip gali pasirodyti iš pirmo žvilgsnio.
DLL suteikia daug galimybių optimizuoti programos našumą,
kaip ir pačių programuotojų darbas. Naudokite DLL ir galbūt jūsų gyvenimas taps lengvesnis!
http://subscribe.ru/
El. paštas: [apsaugotas el. paštas] Paieška
į APORT per Subscribe.Ru

Delphi programavimo aplinka suteikia integruotus įrankius greitai sukurti DLL.

Sukurkime biblioteką, kurioje yra konkreti funkcija

GautiArea(a, b, c: REAL): REAL.

Ši funkcija kaip įvestį paima trikampio kraštinių ilgius. Funkcija grąžina nurodyto trikampio plotą:

p:=(a+b+c)/2;

Rezultatas:=SQRT(p*(p-a)*(p-b)*(p-c))

Paleisti Delphi, o tada elgiamės netradiciškai. Pasirinkite meniu elementus FileNvaOten, skirtuke N atidarytame langevaspustelėkite DLL W piktogramąizard. ( algoritmas priklauso nuo versijos)

Tai sukuria šablono DLL failą. Jis labai panašus į įprastą modulį (vienetas) Delphi, tik prasideda nuo operatoriausbiblioteka. Išsaugokite projektą pavadinimu, kuris DLL bus suteiktas ateityje, tarkimeGauti. vardasGaukAreanegali būti naudojamas – jis jau užimtas funkcijos pavadinimo.

Dabar po operatoriausNAUDOJIMASrašome savo funkcijos tekstą, bet su kai kuriais pavadinimo pakeitimais:

FUNKCIJA GautiArea (a, b, c: REAL): REAL;eksportuoti;

Raktinis žodis EXPORT nurodo, kad funkcija yra eksportuojama ir bus matoma iš išorinių programų.

Po funkcijos teksto pridėsime

GaukArea;

Teiginyje EXPORTS pateikiamos visos iš bibliotekos eksportuotos procedūros ir funkcijos. Tai savotiškas mūsų bibliotekos katalogas.

Bibliotekos valdyti neįmanoma; ją galima tik sudaryti. Norėdami tai padaryti, pasirinkite meniu punktą Projektas → Sukurti. Jei viskas buvo padaryta teisingai, dabartiniame kataloge esančiame diske bus sukurtas failas pavadinimu geta.dll. Tai mūsų biblioteka.

Svarbi pastaba: Perduodant STRING tipo parametrus bibliotekoje esančioms procedūroms ir funkcijoms, yra tam tikras subtilumas.

Kad galėtumėte perduoti STRING tipo parametrus, tiek bibliotekos, tiek ją iškviečiančios programos USES sakiniuose turėsite nurodyti ShareMem modulio ryšį ir netgi taip, kad šis modulis būtų pirmas sąraše. . Be to, kartu su biblioteka turėsite įtraukti failą borlndmm.dll (jis įtrauktas į Delphi platinimą). Šios situacijos lengva išvengti: teksto tipo parametrams turėtumėte naudoti duomenų tipus ShortString (tai įprasta eilutė, bet iki 255 simbolių ilgio) ir PChar (rodiklis į teksto eilutę).

Skambinti dll

Yra du būdai iškviesti procedūras ir funkcijas iš DLL. Pirmuoju atveju iš anksto, programos kūrimo etape, žinome, kurį DLL prie jo prijungsime (dažniausiai šį DLL kuriame patys). Antruoju atveju prisijungiame prie savavališkos bibliotekos, įskaitant „svetimą“.

Statinis susiejimas

Norėdami įgyvendinti pirmąjį metodą, vadinamas statinis susiejimas, sukurkite naują įprastą programą, formoje įdėkite tris įvesties laukus LabeledEdit1...LabeledEdit3, mygtuką ir Tlabel komponentą. Po sakinio IMPLEMENTATION pridėkite eilutę, kuri importuoja funkciją GetArea iš geta.dll bibliotekos:

Funkcija GetArea(a,b,c:real):REAL; FAR; IŠORINĖ "geta";

Žodis EXTERNAL rodo, kad šios funkcijos turinys yra bibliotekoje nurodytu pavadinimu, o žodis FAR nurodo „ilgų“ keturių baitų adresų naudojimą, kuris yra būtinas, nes skambinanti programa yra viename atminties puslapyje. , o DLL biblioteka yra kitoje. Žinoma, geta.dll failas turi būti patalpintas tame pačiame kataloge, kuriame yra visi dabartinės programos failai.

Mygtuko paspaudimo tvarkyklėje turite sukurti masyvą ir perduoti jį bibliotekos funkcijai, o rezultatą parodyti ekrane:

procedūra TForm1.Button1Click(Siuntėjas: TOobjektas);

Darbas su DLL

DLL- Dynamic Link Library yra dinaminių nuorodų biblioteka, leidžianti pakartotinai naudoti tas pačias funkcijas įvairiose programose. Tiesą sakant, tai gana patogus įrankis, juolab kad biblioteka, parašyta, gali būti naudojama daugelyje programų. Šiandienos pamokoje išmoksime dirbti su dll ir, žinoma, juos kurti!

Na, pradėkime!

Pirmiausia sukurkime savo pirmąją dinaminių nuorodų biblioteką! Einame į Delphi ir iškart einame į meniu Failas -> Naujas -> Kita.

Iš sąrašo pasirinkite Dynamic-Link Library (senesnėse nei Delphi 2009 versijose elementas vadinamas DLL vedliu).

Dėl to turime tik langą su kodu. Atminkite, kad čia nėra jokios formos!

Dabar linksmybės prasideda. Surašykime pirmąsias procedūras bibliotekoje.

bibliotekaProjektas2; //Turbūt jau pastebėjote, kad vietoj programos //kuriant dll, naudojamas žodis biblioteka. //Reiškia biblioteka. naudoja SysUtils, dialogus, klases; // Dėmesio! Nepamirškite nurodyti šių modulių, kitaip kodas neveiks ($R *.res) (ŠI DALIS YRA DLL KODAS) Procedūra FirstCall; stdcall; eksportuoti; //Stdcall – naudojant šį operatorių parametrai dedami į krūvą //iš dešinės į kairę ir suderinami su standartine verte //Eksportas iš esmės gali būti praleistas arba funkcija. Begin ShowMessage ("Mano pirmoji procedūra dll"); //Paskambinkite žinute ekrane Pabaiga; „DoubleCall“ procedūra; stdcall; eksportuoti; Begin ShowMessage ("Mano antroji procedūra"); //Paskambinkite žinute ekrane Pabaiga; Eksportuoja FirstCall, DoubleCall; //Eksportas yra eksportuotų elementų sąrašas. //Kurį vėliau importuos kokia nors programa. pradžia Pabaiga.

Kol kas čia sustosime, nes... paprastam pavyzdžiui to visiškai pakaks. Dabar mes išsaugome savo projektą, aš asmeniškai jį išsaugojau pavadinimu Project2.dll ir paspauskite klavišų kombinaciją CTRL + F9, kad sudarytumėte biblioteką. Aplanke, kuriame išsaugojote dpr failą, atsiras failas su plėtiniu dll, tai yra mūsų ką tik sukurta biblioteka. Turiu jį pavadinimu Project2.dll

Dabar pradėkime iškviesti procedūras iš šios bibliotekos. Sukuriame naują programą pagal standartinę schemą. Prieš mus nėra nieko neįprasto, tik forma. Išsaugokite naują programą kokiame nors aplanke. Ir nukopijuokite naujai sukurtą dll biblioteką į tą patį aplanką. Tie. šiame pavyzdyje Project2.dll

Dabar turite pasirinkti, kaip iškviesti funkcijas iš bibliotekos. Iš viso yra du skambinimo būdai.

1 metodas

Galbūt tai yra paprasčiausias bibliotekoje esančių procedūrų iškvietimo būdas.

Idealiai tinka darbui tik su viena biblioteka.

Štai mes...

Po įgyvendinimo raktinio žodžio parašykite šį kodą:

Čia, kaip tikriausiai jau atspėjote, mes pasakome programai savo procedūrų pavadinimus ir sakome, kad jos yra dll bibliotekoje, mano atveju pavadinimu Project2.dll

Dabar, norėdami iškviesti šias procedūras, turime tik įterpti jų pavadinimus bet kurioje kode, ką mes padarysime dabar. Numeskite 2 mygtukų komponentus iš skirtuko Standartinis į formą ir kiekviename sukurkite OnClick įvykių tvarkyklę

Pirmojo mygtuko paspaudimas:

Spustelėkite antrąjį mygtuką:

Tai viskas!

2 metodas:

Sudėtingesnis nei pirmasis, tačiau turi savo privalumų, o svarbiausia – idealiai tinka priedams.

Norėdami naudoti šį metodą, pirmiausia deklaruojame kelis pasaulinius kintamuosius:

Tada po įgyvendinimo raktinio žodžio parašysime procedūrą, kuri įkels mūsų biblioteką:

Procedūra LoadMyLibrary(failo pavadinimas: eilutė); Pradėkite LibHandle:= Įkelti biblioteką(PWideChar(failo pavadinimas));//Įkeliama biblioteka! // Dėmesio! PChar jaunesnėms nei 2009 m. Delphi versijoms Jei LibHandle = 0, tada pradėkite MessageBox(0," Nepavyko įkelti bibliotekos",0,0); Išeiti; Galas; FirstCall:= GetProcAddress(LibHandle,"FirstCall");//Gaukite žymeklį į objektą //1-oji parametro nuoroda į bibliotekos modulį //2-asis objekto parametro pavadinimas dll faile DoubleCall:= GetProcAddress(LibHandle,"DoubleCall"); Jei @FirstCall = nulis, tada pradėkite//Patikrinkite, ar ši funkcija yra bibliotekoje. MessageBox(0,"Nepavyko įkelti bibliotekos",0,0); Išeiti; Galas; Jei @DoubleCall = nulis, tada pradėkite//Patikrinkite, ar ši funkcija yra bibliotekoje. MessageBox(0,"Nepavyko įkelti bibliotekos",0,0); Išeiti; Galas; Galas

Tada formoje sukuriame OnCreate įvykių tvarkyklę, kurioje, naudodami ką tik sukurtą procedūrą, įkelsime savo biblioteką

Procedūra TForm1.FormCreate(Siuntėjas: TObject); Pradėkite LoadMyLibrary ("Project2.dll"); Galas;

Dabar vėlgi, norėdami iškviesti reikiamas procedūras iš mūsų bibliotekos, mums tereikia įterpti jų pavadinimus bet kurioje kode. Norėdami tai padaryti, numeskite 2 mygtukų komponentus iš skirtuko Standartinis į formą ir kiekviename sukurkite OnClick įvykių tvarkyklę.

Pirmojo mygtuko paspaudimas:

Procedūra TForm1.Button1Click(Siuntėjas: TObject); Pradėkite „FirstCall“; // Procedūros, esančios dll pabaigoje, pavadinimas;

Spustelėkite antrąjį mygtuką:

Procedūra TForm1.Button2Click(Siuntėjas: TObject); Pradėkite „DoubleCall“; // Procedūros, esančios dll pabaigoje, pavadinimas;

Ir galiausiai formoje sukuriame OnDestroy įvykių tvarkyklę, kurioje iš atminties iškrauname dll biblioteką

Tai viskas! Antrasis metodas pasirodė gana sudėtingas, tačiau jo pranašumas yra išsiaiškinti bibliotekoje saugomą objektą.