Zitat von
xZise:
Ah okay. Ist etwas verwirrend
Da muss man erstmal durchblicken
Was macht den genau TStreamReader?
TStreamReader implementiert die beiden Interfaces IInStrem und ISequentialInStream. Es muss ja irgendeine Schnittstelle geben über die dein Programm mit der
DLL kommunizieren kann, und da nicht alle Programme in C++ geschrieben werden (so wie die
DLL) muss diese Schnittstelle sprachenunabhängig sein - daher verwendet die
DLL eben
COM-Interfaces. Die ganze Kommunikation läuft folgendermaßen ab: du forderst ein Interface aus der
DLL an (über die Funktion CreateObject, welche von der
DLL exportiert wird). In meinem Fall (Packen) hab ich dazu eine IOutArchive-Instanz angefordert - du bräuchtest wohl eine IInArchive-Instanz. Ab dann läuft alles nur mehr über dieses Interface.
Zum Packen ruf ich die Methode IOutArchive.UpdateItems auf welche folgendermaßen ausschaut:
function UpdateItems(outStream: ISequentialOutStream; numItems: DWord; updateCallback: IArchiveUpdateCallback): HRESULT; stdcall;
Es werden also zwei Interfaces erwartet - die Implementierung dieser Interfaces muss man selbst zur Verfügung stellen! Der outStream wird zum schreiben des Archivs benötigt, ich hab daher folgendes gemacht:
Delphi-Quellcode:
outStream := TStreamWriter.Create(TFileStream.Create(FParams.Filename, fmCreate)); // TStreamWriter ist der Wrapper für den TFileStream
FOutArchive.UpdateItems(outStream, FParams.Items.Count, callback);
Nachdem TStreamWriter das ISequentialOutStream Interface implementiert, kann eine TStreamWriter-Instanz als ISequentialOutStream verwendet werden (Delphi führt eine implizite Typumwandlung durch). Wenn die
DLL jetzt Daten in das Archiv schreiben muss, so wird die Write-Methode des ISequentialOutStream Interfaces aufgerufen. Die Implementierung dieser Methode schaut bei mir so aus:
Delphi-Quellcode:
function TStreamWriter.Write(const data: Pointer; Size: DWord; processedSize: PDWord): HRESULT;
var
writeCount: Integer;
begin
try
writeCount := FStream.Write(data^, Size);
if Assigned(processedSize) then
processedSize^ := writeCount;
Result := S_OK;
except
Result := S_FALSE;
end;
end;
TStreamWriter macht jetzt also nichts anderes als diese Write-Aufrufe an die Write-Methoden der internen TStream-Instanz weiter zu delegieren. In meinem Fall also an die TFileStream-Instanz die dem Constructor mitgegeben wurde, theroretisch kann man auch einen TMemoryStream, TBlobStream, ... verwenden (ob es sinnvoll ist ist zwar fraglich, es ist aber auf jeden Fall möglich).
Dasselbe gilt für das Callback-Interface - man muss eine eigene Implementierung dieses Interfaces zur Verfügung stellen, deren Methoden dann von der
DLL aufgerufen werden. Den ganzen Ablauf im Detail zu erklären wäre jetzt zuviel, aber vielleicht hast du das Konzept jetzt verstanden und kannst dir den Rest alleine zusammensuchen.
Gruß, Motzi