Delphi-Quellcode:
procedure TfrmMain.btnLoadClick(Sender: TObject);
type
TLoadProc = procedure(out Person: IPerson); stdcall;
var
DLLHandle: NativeUInt;
PersonProc: TLoadProc;
Person: IPerson;
Item: TListItem;
begin
// ...
while not Person.Eof do
begin
Item := lvChildren.Items.Add;
Item.Caption := Person.Child.Name;
Item.SubItems.Add(DateToStr(Person.Child.Birthdate));
Person.Next;
// ...
finally
Person := nil;
FreeLibrary(DLLHandle);
end;
end;
Das Problem ist folgendes:
Person.Child liefert ein Interface (IChild). Das wird hier aber nicht in einer lokalen Variable gespeichert, sondern es wird gleich auf eine Eigenschaft zugegriffen (Name, Birthdate). Damit die automatische Referenzzählung funktioniert, muss Delphi aber trotzdem jede Interface-Instanz in einer unsichtbaren lokalen Variable speichern (hier also 2x IChild), die dann am Ende der Subroutine in einem impliziten "finally" Block freigegeben werden.
FreeLibrary wird aber vorher ausgeführt, d.h. es wird auf Ressourcen zugegriffen, die nicht mehr verfügbar sind. Daher die Zugriffsverletzung.
Lösung: Person.Child explizit in einer Variable speichern und die Referenz ebenfalls vor FreeLibrary freigeben.
Delphi-Quellcode:
procedure TfrmMain.btnLoadClick(Sender: TObject);
type
TLoadProc = procedure(out Person: IPerson); stdcall;
var
DLLHandle: NativeUInt;
PersonProc: TLoadProc;
Person: IPerson;
Child: IChild;
Item: TListItem;
begin
// ...
while not Person.Eof do
begin
Item := lvChildren.Items.Add;
Child := Person.Child;
Item.Caption := Child.Name;
Item.SubItems.Add(DateToStr(Child.Birthdate));
Person.Next;
// ...
finally
Person := nil;
Child := nil;
FreeLibrary(DLLHandle);
end;
end;
Falls die
DLL übrigens erkennen soll, wann sie geladen oder freigegeben wird,
dann geht das ungefähr so.