Dynamisk læsning af DLL

Tags:    delphi
Skrevet af Bruger #270 @ 20.08.2001
Dynamisk læsning af DLL

Introduktion

Tilgang og brugen af DLL'er er nemt i Delphi (se artiklen Tilføj en Form til en DLL), så i denne artikel ønsker jeg at belyse hvordan vi rent faktisk kontrollerer hvornår en DLL er læst ind i hukommelsen, samt at vi også selv er ansvarlige for at tillade systemet at fjerne den igen fra hukommelsen, når vi er færdige med at bruge den.

Fordele ved brugen af dynamisk læsning af DLL'er

Der er en række fordele ved ar bruge DLL'er på denne måde, hvor den hovedsaglige omkostning er noget ekstra kode. Ved dynamisk indlæsning af en DLL beslutter du ved runtime (godt dansk ord), hvilke DLL'er du ønsker at bruge og dermed opnås en større fleksibilitet. Det betyder at, afhængigt af hvilke DLL'er der er tilstede, kan du give dit program forskellig funktionalitet. Du kan på den måde foreksempel lave en freeware og en shareware version af dit program. Jeg har tidligere anvendt denne teknik til database programmer, hvor jeg så har lagt hver rapport i hver sin DLL, for så at scanne et biblioteket igennem (se evt. Implementering af Callback Procedurer for et eksempel på hvordan man gør det), og ud fra det danne en liste af tilgængelige rapporter.

Olie på fingerne

Det er nu tid til at få lidt olie på fingerne. Artiklen her tager udgangspunkt i den DLL der blev lavet i Tilføj en Form til en DLL artiklen. Den DLL eksporterer en funktion og en procedure, som var erklæret som følger:
procedure ShowDllForm; stdcall;
function ShowDllFormModal: integer; stdcall;
For at kunne kalde disse fra vores applikation er vi nødt til at erklære to nye datatyper, der modsvarer dem i DLL'en. De var erklæret således:
TShowForm = procedure;
TShowFormModal = function: integer;
Nu skal vi så have lavet nogle variabler af disse to datatyper, hvilke vi gør under den private del af vores "hovedklasse".
ShowForm: TShowForm;
ShowFormModal: TShowFormModal;
Hvis vi kaldte en af de to funktioner nu, ville det resultere i en access violation (igen et godt dansk udtryk), siden de ikke peger på noget. I den her forbindelse er det vigtigt at huske på at procedurer og funktioner basalt set kun er pointere, der peger på noget kode. Det næste skridt er derfor at indlæse vores DLL og få vores to funktioner til at pege på dem i DLL'en, det gøres sådan:
DLLHandle := LoadLibrary('Project1dll.dll');
if DLLHandle <> 0 then
begin
  @ShowForm := GetProcAddress(DLLHandle, 'ShowDllForm');
  @ShowFormModal := GetProcAddress(DLLHandle, 'ShowDllFormModal');
end;
Det eneste vi gør her er at læse DLL'en ind I hukommelsen (LoadLibrary), for så at skaffe os hukommelsesadressen, en pointer, GetProcAddress til de to funktioner vi ønsker at kalde. Nu kan vi kalde ShowForm og ShowFormModal som om de var almindelige procedurer/funktioner.

Oprydning!

Det specielle ved at læse DLL'er dynamisk var jo at vi selv have ansvaret for at ryde op efter os. Men ingen grund til panik det er gjort meget simpelt:
if DLLHandle <> 0 then
begin
  FreeLibrary(DLLHandle);
  DLLHandle := 0;
end;
Dermed frigives det handle, der tidligere er blevet tildelt, og operativsystemet har nu mulighed for at fjerne DLL'en fra systemet, hvis dette var det sidste handle i systemet, der henviste til DLL'en. Når handlet er nedlagt er det vigtigt at du ikke forsøger at kalde funktioner, som ligger i DLL'en, ellers vil du med 100% sikkerhed få en access violation.

Konklusion

Som du kan se udfra dette eksempel er der ingen ben i at læse DLL filer dynamisk ind i hukommelsen, når først du ved hvordan. Du kan hente fuld source kode her (420 kb). Koden har ingen praktisk anvendelse, men tjener udelukkende det formål at vise hvordan eksemplet ovenfor virker.


Hvad synes du om denne artikel? Giv din mening til kende ved at stemme via pilene til venstre og/eller lægge en kommentar herunder.

Del også gerne artiklen med dine Facebook venner:  

Kommentarer (0)

Du skal være logget ind for at skrive en kommentar.
t