![]() |
Delphi-Version: 2010
Zugriffsverletzung beim 2. Aufruf von Interface Methode
Hallo,
ich habe folgendes Interface:
Delphi-Quellcode:
Es wird mit Init initialisiert, dort wird auch ein anderes Interface übergeben, von dem das Plugin auch Methoden ausführt. IDownloadPlugin ist in einer DLL, IDownload im Host.
TFileInfo = packed record
Name: WideString; Size: Integer; end; PFileInfo = ^TFileInfo; PFileInfos = array of PFileInfo; WideStrings = array of WideString; IDownloadPlugin = interface(ILoadPlugin) ['{30DABA9A-6B0B-44BB-8552-816DB0C68FD8}'] procedure Init(Ifc: IDownload); stdcall; function GetFileInfo(Link: WideString): TFileInfo; stdcall; function GetFileInfoMulti(Links: WideStrings): PFileInfos; stdcall; procedure Download(Link: WideString); stdcall; procedure Premium(Link, Username, Password: WideString); stdcall; function GetAccountInfo(Username, Password: WideString): TAccountInfo; stdcall; function CheckFile(Contents: WideString): Boolean; stdcall; end; Nun rufe ich GetFileInfoMulti auf und bekomme beim ersten Mal auch die Zeiger auf die Datei-Informationen als Array wieder, verarbeite sie entsprechend und führe Dispose für alle Zeiger aus. "Links" und das zurückgegebene PFileInfos wird dann auf nil gesetzt. Wenn ich die Methode dann ein zweites Mal mit einem anderen Array aufrufen will, gibt es beim Aufruf in der DLL eine A/V. Der erste Befehl der Methode wird nicht mehr erreicht, er hängt irgendwo dazwischen. Dies ist der Code im Host, der 2. Aufruf (der fehlschlägt) findet statt wenn mehr als 40 Links verarbeitet werden müssen und es somit mehrere Durchläufe in der Schleife gibt.
Delphi-Quellcode:
Ich habe herausgefunden, dass wenn ich die Zeile wo InfoSplit := nil gesetzt wird rausnehme, alles geht. Warum ist das so?
var
i, Loops, j: Integer; Infos, InfoSplit: PFileInfos; LinkList, Split: WideStrings; Hoster: string; begin .... Loops := Ceil(Length(LinkList) / 40); for i := 0 to Loops - 1 do begin Split := Copy(LinkList, i * 40, 40); // Da eh alle das selbe Plugin haben, verwenden wir einfach mal das vom 1. Link in der Liste TData(FHosterLinks[Hoster][0]).Load; // hier wird das Interface erstellt try InfoSplit := TData(FHosterLinks[Hoster][0]).PlgInstance.GetFileInfoMulti(Split); finally TData(FHosterLinks[Hoster][0]).Unload(True); Split := nil; end; // InfoSplit an die richtige Stelle im Infos array kopieren for j := 0 to High(InfoSplit) do begin SetLength(Infos, Length(Infos) + 1); Infos[High(Infos)] := InfoSplit[j]; end; InfoSplit := nil; // Interessant: Wenn ich diese Zeile herausnehme geht alles einwandfrei end; |
AW: Zugriffsverletzung beim 2. Aufruf von Interface Methode
Was passiert den bei Load, PlgInstance und Unload?
Das Interfaceobject darf bei Unload noch nicht freigegeben werden. Innerhalb von Prozeduren/Methoden verwendete Interfaces werden möglicherweise erst beim Verlassen oder bei erneuter Zuweisung eines anderen Interfaceobject freigegeben. Meine Vermutung, der Compiler erzeugt daraus im Prinzip das:
Delphi-Quellcode:
DummyInterfaceVariable := nil;
{Schleife begin} Load; // hier wird das Interface erstellt try if Assigned(DummyInterfaceVariable) then DummyInterfaceVariable._Release; // <- hier knallts beim 2.Durchlauf DummyInterfaceVariable := PlgInstance; if Assigned(DummyInterfaceVariable) then DummyInterfaceVariable._AddRef; InfoSplit := DummyInterfaceVariable.GetFileInfoMulti(Split); finally Unload(True); // <- hier wird das Object vermutlich unzulässig freigegeben Split := nil; end; {Schleife end} if Assigned(DummyInterfaceVariable) then DummyInterfaceVariable._Release; // <- hier könnte es schon bei nur einem Durchlauf |
AW: Zugriffsverletzung beim 2. Aufruf von Interface Methode
Was ist TData?
|
AW: Zugriffsverletzung beim 2. Aufruf von Interface Methode
In Load() wird nur das Interface geholt
FPlgInstance := FHosterPlg.CreateInstance(Link); CreateInstance wird auf die DLL weitergeleitet, wo einfach Result := TPlugin.Create gemacht wird. In Unload wird anders als man denken könnte das Interface nicht freigegeben sondern es passieren andere Dinge die hier nicht von Bedeutung sind. PlgInstance implementiert IDownload und leitet alle Aufrufe (z.B. GetFileInfoMulti) letztendlich auf IDownloadPlugin weiter. Zitat:
|
AW: Zugriffsverletzung beim 2. Aufruf von Interface Methode
Um den Fehler einzugrenzen würde ich erst mal so ändern:
Delphi-Quellcode:
Beim "Kopieren" der Infos werden ja nur neue Zeiger auf die jeweiligen TFileInfo-Strukturen angelegt. Ist sichergestellt das diese Daten auch über die gesamte Gültigkeit von "Infos" existieren und nicht überschrieben werden?
var
plugin: IDownloadPlugin; {...} plugin := TData(FHosterLinks[Hoster][0]).PlgInstance; InfoSplit := plugin.GetFileInfoMulti(Split); plugin := nil; |
AW: Zugriffsverletzung beim 2. Aufruf von Interface Methode
Zitat:
|
AW: Zugriffsverletzung beim 2. Aufruf von Interface Methode
Delphi-Quellcode:
ist nicht wirklich ActiveX/COM kompatibel.
Array of Irgendwas
Die geladene DLL verwendet nicht zwingend die gleiche Instanz des Memory-Managers wie die Hauptanwendung. Auch der Record TFileInfo ist nicht so schön bzw ziemlich problematisch. Stattdessen sollte es ein Interface IFileInfo und eine Klasse die das Interface implementiert geben. Wenn man nur mit Objekten über ein Interface arbeitet, dann braucht man auch kein _AddRef oder _Release. |
AW: Zugriffsverletzung beim 2. Aufruf von Interface Methode
Mhmh das ist natürlich unschön. Durch was ersetze ich denn am besten Arrays?
Mir würde nur sowas einfallen:
Delphi-Quellcode:
Und dasselbe nochmal um die WideString arrays zu ersetzen:
IFileInfo = interface(IInterface)
function Name: WideString; function Size: Integer; function Next: IFileInfo; end;
Delphi-Quellcode:
Würde es so gehen? :/
IString = interface(IInterface)
function Get: WideString; function Next: IString; end; Zitat:
|
AW: Zugriffsverletzung beim 2. Aufruf von Interface Methode
habe ein ähnliches Problem,
ich hole mir das Interface von einem externen Treiber (*.ax) vcap.QueryInterface(Aguid, AFilter); MyFilter := AFilter as TMyFilter; MyFilter.SetShutterSpeed(v); ... geht gut, ein weiterer Aufruf liefert einen Systemfehler außerdem kriege ich unter 64bit keinen Pointer auf das Interface (AFilter), nur unter 32bit. gruss lukas |
AW: Zugriffsverletzung beim 2. Aufruf von Interface Methode
Ich würd's so machen:
Delphi-Quellcode:
Als Ersatz für Array of Widestring würde ich das Interface IStrings (aus Unit StdVCL) verwenden.
IFileInfo = interface(IInterface)
['{C7... '] // GUID nicht vergessen function Name: WideString; function Size: Integer; end; IFileInfoList = interface(IInterface) ['{C7... '] // GUID nicht vergessen function Get_Count:integer; function Get_Item(idx:integer):IFileInfo; property Count:integer read Get_Count; property Item[idx:integer] read Get_Item; end; Mit der Funktion GetOleStrings() kannst du aus einem TString-Objekt ein IStrings-Objekt erzeugen. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 03:17 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz