Dynamische linkbibliotheek
Dynamische linkbibliotheek | |
---|---|
Bestandsextensie : | .dll, .DLL |
MIME-type : | applicatie / vnd.microsoft.portable-executable, applicatie / x-msdownload, applicatie / octet-stream |
Ontwikkeld door: | Microsoft |
Type: | dynamische bibliotheek |
Dynamic Link Library ( DLL ) verwijst in het algemeen naar een dynamische programmabibliotheek ; Echter, de term verwijst meestal naar de variant die voor de Microsoft Windows en OS / 2 besturingssystemen .
DLL- bestanden gebruiken het bestandsformaat dat ook wordt gebruikt voor uitvoerbare EXE- bestanden, het nieuwe uitvoerbare formaat (NE) in 16-bits programma's, [1] het lineaire uitvoerbare formaat (LE of LX, OS / 2) evenals de draagbaar uitvoerbaar formaat (PE, Windows) in 32- en 64-bits programma's. Deze bestanden kunnen programmacode ( machinecode ), gegevens en bronnen in elke combinatie bevatten.
De bestandsnaamextensie van Windows voor dergelijke bibliotheken is meestal DLL
, maar het kunnen ook andere bestandsextensies zijn zoals OCX
(voor bibliotheken met ActiveX- besturingselementen), DRV
of CPL
(voor systeembesturing ).
achtergrond
Het belangrijkste doel van DLL-bestanden is om de schijfruimte en geheugenruimte die nodig is voor toepassingen te verminderen. Code en gegevens die nodig kunnen zijn voor meer dan één toepassing, worden daarom in één bestand op de harde schijf opgeslagen en slechts één keer in het hoofdgeheugen geladen wanneer verschillende programma's dezelfde programmabibliotheek nodig hebben.
Extra voordelen
Als een stukje programmacode is verbeterd, is het niet nodig om alle programma's die deze code gebruiken te wijzigen; het is voldoende om het in de DLL bij te werken. In dit geval hebben alle programma's toegang tot de bijgewerkte versie. Hierdoor kunnen softwareontwikkelaars relatief kleine patches uitgeven voor grotere softwarepakketten, bijvoorbeeld voor hele besturingssystemen. Een heel pakket kan worden bijgewerkt door afzonderlijke DLL's bij te werken.
In de vorm van plug-ins kunnen DLL's worden gebruikt om nieuwe programmaonderdelen voor een bestaand programma te maken en deze naadloos te integreren zonder wijzigingen in het bestaande programma aan te brengen. Dit idee van dynamische "integratie" is bijvoorbeeld geïmplementeerd onder Windows met behulp van ActiveX .
Een dergelijke modulaire opbouw maakt het ook mogelijk om functies die niet nodig zijn eenvoudig te deactiveren.
zwakke punten
Een probleem dat in Windows een DLL-conflict wordt genoemd , doet zich voor wanneer meerdere toepassingen verschillende versies van dezelfde DLL nodig hebben. Als een programma de vereiste versie mist, kan dit leiden tot problemen zoals foutieve installaties. Dit conflict kan vaak worden opgelost door de juiste versie van de programmabibliotheek naar de programmamap van het betreffende programma te kopiëren. Het effect van geheugenbesparing wordt hierdoor echter weer teniet gedaan. Met Microsoft .NET is het mogelijk om versieconflicten in DLL-bestanden te omzeilen door meerdere versies van een programmabibliotheek tegelijkertijd te laten bestaan. Dit is echter alleen mogelijk voor DLL-bestanden die zijn ontwikkeld met .NET.
In bepaalde gevallen is DLL-kaping of kwaadwillig gebruik van DLL-injectie mogelijk.
Bediening binnen het besturingssysteem
Laden van DLL's bij het starten van een programma
Wanneer een programma moet worden uitgevoerd, wordt het door de loader van het besturingssysteem in het geheugen geladen en wordt de importtabel van het programma uitgelezen. Deze tabel bevat alle DLL-opdrachtnamen of de rangtelwoorden van de DLL-opdrachten die door dit programma zijn vereist. De loader laadt nu de ontbrekende DLL's in het geheugen en voegt de invoeradressen van de afzonderlijke commando's in de importtabel van het programma in.
DLL-bestandsstructuur
Een DLL heeft (na de MZ-header ) dezelfde NE-, LE- of PE-header als een normaal uitvoerbaar bestand, alleen in het geval van een NE is de DWORD-vlag op het adres 0C hex in de NE-header ingesteld op 8000 hex ( Library Module flag) [1] of de IMAGE_FILE_DLL- bit die is ingesteld in de karakteristiekenwaarde in de PE-header. Hoewel zowel DLL's als uitvoerbare bestanden een exporttabel kunnen hebben, wordt deze laatste zelden gebruikt. Deze "exporttabel" vermeldt alle namen van de functies en variabelen die de DLL beschikbaar stelt aan externe software. Deze namen moeten alfabetisch worden gesorteerd, zodat de lader ze kan vinden.
Een DLL-opdracht aanroepen door een programma
Eerst worden de over te dragen waarden op de stack opgeslagen - op dezelfde manier als bij andere subroutines - dan wordt er indirect een sprong gemaakt naar de waarde van het DLL-adres dat door de loader in de importtabel is opgeslagen.
DLL's in het geheugen
Er zijn twee verschillende manieren waarop DLL's door het besturingssysteem in het geheugen kunnen worden geladen. Er zijn statische DLL's die maar één keer worden geladen. Alle programma's hebben dan toegang tot dit ene exemplaar van de DLL. Deze DLL heeft dan slechts één globaal geheugengebied. De Windows-kernel-DLL's zijn zulke statische DLL's, waarmee ze het hele systeem kunnen beheren (bijvoorbeeld alle geopende bestanden controleren). Een andere manier om DLL's in het geheugen te beheren, is dat elke keer dat een nieuw programma een DLL nodig heeft, er een nieuwe instantie van in het geheugen wordt geladen.
Een andere vlag in de kop van de DLL bepaalt of een DLL statisch is of niet.
Teller voor DLL-instanties
Elke keer dat een DLL door een programma wordt geladen, wordt een interne instantieteller voor deze DLL verhoogd. Het systeem kan deze teller gebruiken om te herkennen of een DLL nog in gebruik is of kan worden gelost. Dit laatste gebeurt wanneer de instantieteller nul bereikt, aangezien het laatst lopende programma dat de DLL heeft gebruikt, de DLL heeft verwijderd en deze niet langer in het geheugen hoeft te worden bewaard.
Programmeervoorbeelden voor 32-bits Windows
Werken met DLL's in Visual C ++
Maak een DLL met een functie
De DLL-interface wordt gedefinieerd met behulp van de exportfunctie __declspec(dllexport)
.
Dit wordt gedemonstreerd in het volgende voorbeeld:
// De "DLL"-macro heeft alleen een functie onder Microsoft Visual C++.
// Op Linux is de "DLL"-macro bijvoorbeeld leeg.
#indien gedefinieerd (_MSC_VER)
#include <windows.h>
#define DLL extern "C" __declspec (dllexport)
#anders
#define DLL
#stop als
// De functie die beschikbaar moet worden gemaakt voor andere programma's
// (in dit voorbeeld: twee getallen optellen)
DLL dubbele AddNumbers ( dubbel a , dubbel b )
{
retourneer a + b ;
}
In dit voorbeeld wordt tijdens het compileren zowel een DLL
als een LIB
bestand gemaakt.
Voeg een DLL toe en roep deze functie aan
DLL-functies kunnen eenvoudig worden aangeroepen nadat ze zijn geïmporteerd met de functie __declspec(dllimport)
.
#include <windows.h>
#include <stdio.h>
// Importeer de functie uit de DLL die hierboven is gemaakt
extern "C" __declspec ( dllimport ) dubbele AddNumbers ( dubbele a , dubbele b ) ;
int hoofd ( nietig )
{
// Roep de externe functie op
dubbel resultaat = AddNumbers ( 1 , 2 ) ;
printf ( "Het resultaat is:% f \ n " , resultaat ) ;
retourneer 0 ;
}
Opgemerkt moet worden dat de linker het LIB-bestand nodig heeft en dat het DLL-bestand zich in dezelfde map moet bevinden als het programma dat het moet aanroepen. Het LIB-bestand is vereist door de linker, zodat het "placeholders" kan bevatten voor de functies die later vanuit de DLL worden aangeroepen.
Voeg tijdens runtime een DLL toe en roep deze functie aan
DLL-bibliotheken kunnen op twee verschillende manieren in een toepassing worden geladen: ofwel wanneer het programma wordt gestart (zoals beschreven in de bovenstaande voorbeelden) of later tijdens runtime met behulp van de API- functies LoadLibrary
, GetProcAddress
en FreeLibrary
. De manier waarop DLL's tijdens runtime moeten worden geïntegreerd, is in elke programmeertaal hetzelfde, zolang u maar een Windows API- functie wilt importeren. De volgende code laat dit zien aan de hand van een VC++ voorbeeld:
#include <windows.h>
#include <stdio.h>
// Definitie van het type DLL-functie dat moet worden gebruikt
typedef dubbel ( * BinaryFunction_t ) ( dubbel , dubbel ) ;
int hoofd ( nietig )
{
BinaryFunction_t AddNumbers ;
dubbel resultaat ;
BOOL fFreeResultaat ;
// Laad het DLL-bestand
HINSTANCE hinstLib = LoadLibrary ( "MijnDll.dll" ) ;
if ( hinstLib ! = NULL )
{
// Haal het invoeradres op
AddNumbers = ( BinaryFunction_t ) GetProcAddress ( hinstLib , "AddNumbers" ) ;
// Roep de functie aan
if ( Nummers toevoegen ! = NULL )
resultaat = ( * Nummers toevoegen ) ( 1 , 2 ) ;
// Verwijder het DLL-bestand opnieuw
fFreeResult = FreeLibrary ( hinstLib ) ;
}
// toon het resultaat
if ( hinstLib == NULL || AddNumbers == NULL )
printf ( "Fout: kon de functie niet oproepen \ n " ) ;
anders
printf ( "Het resultaat is:% f \ n " , resultaat ) ;
retourneer 0 ;
}
Het LIB
bestand is in dit geval niet vereist. Het DLL
bestand moet zich nog steeds in een map bevinden waartoe het programma toegang heeft.
Houd er ook rekening mee dat als u bij het starten van het programma automatisch een niet-bestaande DLL probeert te laden, het besturingssysteem een foutmelding weergeeft en het programma wordt beëindigd zonder dat de programmeur deze fout kan onderscheppen. Bij het integreren van DLL's tijdens runtime kunnen echter laadfouten worden opgevangen.
DLL's gebruiken in Object Pascal
Bouw een DLL
In de kop van de broncode, het zoekwoord library
worden gebruikt in plaats van het program
. Aan het einde van het bestand worden de te exporteren functies weergegeven in het exports
:
bibliotheek voorbeeld ;
// De functie die beschikbaar moet worden gemaakt voor andere programma's
// (in dit voorbeeld: twee getallen optellen)
functie Nummers toevoegen ( a , b : Dubbel ) : Dubbel ; cdecl ;
beginnen
Resultaat : = a + b ;
einde ;
// Exporteer de functie
exporteert
AddNummers ;
// In dit geval hoeft er geen speciale initialisatiebroncode te worden opgegeven
beginnen
einde .
Een DLL opnemen/aanroepen
Delphi heeft geen LIB
bestanden nodig om een functie correct te importeren. Om een DLL te integreren, external
alleen het trefwoord external
te worden gebruikt:
programma voorbeeld ;
{$ APPTYPE-CONSOLE}
// Importeer de functie van een externe DLL
functie Nummers toevoegen ( a , b : Dubbel ) : Dubbel ; cdecl ; extern 'voorbeeld.dll' ;
var resultaat : Dubbel ;
beginnen
resultaat : = Nummers toevoegen ( 1 , 2 ) ;
Writeln ( 'Het resultaat is:' , resultaat )
einde .
DLL's gebruiken in Visual Basic Classic
Van VB tot versie 6 wordt alleen het laden van DLL's tijdens runtime ondersteund. Naast het gebruik van de API-functies LoadLibrary
en GetProcAddress
, is het in Visual Basic mogelijk om externe DLL-functies te declareren , wat dit werk voor de ontwikkelaar een stuk eenvoudiger maakt:
Optie Expliciet Aan
Declareer functie AddNumbers Lib "Example.dll" ( ByVal a As Double , ByVal b As Double ) As Double
Sub Hoofd ()
Dim resultaat als dubbel
Resultaat = Nummers toevoegen ( 1 , 2 )
Debuggen . Print "Het resultaat is:" & Resultaat
Einde sub
Als er een fout optreedt tijdens het laden van de DLL-functie, geeft VB een runtime-fout. Dit kan echter worden onderschept en behandeld. U moet ook de aanroepconventie van de geëxporteerde functie in acht nemen: Visual Basic gaat ervan uit dat de functie _stdcall is . Daarom was de import van _cdecl- functies tot VB7 alleen mogelijk via een tussenliggende wrapper- DLL.
Gebruik Win32 DLL's in .NET
In .NET worden DLL's geïntegreerd met het kenmerk DllImport. Hiervoor is de naamruimte "System.Runtime.InteropServices" vereist. Het functie-prototype wordt in C # gespecificeerd als "extern", wat niet nodig is in VB.NET , dan kan de functie als elke andere worden aangesproken:
C #
-stelsel;
met behulp van System.Runtime.InteropServices ;
naamruimte DllImportExample
{
klas programma
{
[DllImport ("Voorbeeld.dll")]
statisch extern dubbel AddNumbers ( dubbel a , dubbel b );
statische leegte Hoofd ()
{
console . WriteLine ( Nummers toevoegen ( 1 , 2 ) );
}
}
}
VB.NET
Importeert System.Runtime.InteropServices
Klasse Programma
< DllImport ( "Voorbeeld.dll" ) > _
Privé gedeelde functie AddNumbers ( a als dubbel , b als dubbel ) als dubbel
Functie beëindigen
Privé Gedeeld Sub Hoofd ()
console . WriteLine ( Nummers toevoegen ( 1 , 2 ))
Einde sub
Einde les
Directe integratie van DLL's in Visual Studio
Als er echter meerdere methoden of functies van een DLL moeten worden benaderd, kan deze ook rechtstreeks worden geïntegreerd via de Projectverkenner van Visual Studio . De functies van de DLL kunnen vervolgens worden gebruikt door ofwel de volledige naamruimte voor de methodeklasse in de code op te geven, of door de naamruimte rechtstreeks te integreren met (C #) of Imports (VB.Net). De naamruimte System.Runtime.InteropServices is bij deze benadering niet vereist.
Het volgende voorbeeld toont de direct geïntegreerde DLL (de naamruimte komt hier overeen met de naam van de DLL):
C #
met behulp van Voorbeeld ;
klas programma
{
statische leegte Hoofd ()
{
console . WriteLine ( Nummers toevoegen ( 1 , 2 ));
}
}
VB.Net
Voorbeeld import
Klasse Programma
Privé Gedeeld Sub Hoofd ()
console . WriteLine ( Nummers toevoegen ( 1 , 2 ))
Einde sub
Einde les
Zie ook
- Dependency Walker , onderdeel van Microsoft Visual Studio tot versie 2005, waarmee functies die een programma exporteert en importeert hiërarchisch weergegeven kunnen worden.
Individueel bewijs
- ↑ a b KB Microsoft: Koptekstindeling uitvoerbaar bestand
web links
- _declspec (dllimport) en _declspec (dllexport) gebruiken met MSDN-bibliotheek
- Win32 DLL - Instructies voor het maken en aanroepen van DLL's in C++ met Visual Studio
- Beschrijving van de Windows-bibliotheken die worden ondersteund door afbeeldingen en video's. Statische bibliotheken en DLL's.
- Creatie en aanroepen van Windows-bibliotheken, DLL's. Nader onderzoek van de processen.