Delphi-PRAXiS
Seite 3 von 3     123   

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi 7-zip Entpacker einbinden (https://www.delphipraxis.net/108543-7-zip-entpacker-einbinden.html)

Motzi 15. Mär 2008 13:35

Re: 7-zip Entpacker einbinden
 
Zitat:

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:
Delphi-Quellcode:
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

MrKnogge 25. Mär 2008 02:37

Re: 7-zip Entpacker einbinden
 
xZise hast du dir das hier schon mal angeschaut ?

Grüße
Christian

xZise 20. Dez 2008 16:47

Re: 7-zip Entpacker einbinden
 
Zitat:

Zitat von MrKnogge
xZise hast du dir das hier schon mal angeschaut ?

Grüße
Christian

So ich habe es mir jetzt nochmal angeschaut, und naja es funktioniert nicht :D Woran es genau liegt weiß ich nicht.

So sieht meine Testroutine aus:
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
  outdir : string;
var
    dictionary:integer;
    inStream:TBufferedFS;
    outStream:TBufferedFS;
    filesize:int64;
    i:integer;
    properties:array[0..4] of byte;
    decoder:TLZMADecoder;
    outSize:int64;
    v:byte;
const propertiessize=5;
begin
  if (OpenDialog1.Execute) and (SelectDirectory('Ort zum Entpacken wählen', '', outdir)) then
  begin
    if outdir[Length(outdir)] <> '\' then
      outdir := outdir + '\';  

    inStream:=TBufferedFS.Create(OpenDialog1.FileName,fmOpenRead or fmsharedenynone);
    outStream:=TBufferedFS.Create(outdir + 'bla', fmcreate);

    if inStream.read(properties, propertiesSize) <> propertiesSize then
      raise Exception.Create('input .lzma file is too short');
    decoder := TLZMADecoder.Create;
    if not decoder.SetDecoderProperties(properties) then
      raise Exception.Create('Incorrect stream properties');
    outSize := 0;
    for i := 0 to 7 do begin
      v := {shortint}(ReadByte(inStream));
      if v < 0 then
        raise Exception.Create('Can''t read stream size');
      outSize := outSize or v shl (8 * i);
    end;
    if not decoder.Code(inStream, outStream, outSize) then
      raise Exception.Create('Error in data stream');
    decoder.Free;
    outStream.Free;
    inStream.Free;
  end;
end;
Erstmal ist komisch, warum der output eine Datei sein muss (ich entpacke DATEIEN oder einen ORDNER aber nicht immer EINE DATEI). Aber dann funktioniert "decoder.Code" nicht ganz. Als Input-Datei habe ich die Downloaddatei genommen.

Woran es genau liegt weiß ich nicht, da ich die Code-Routine einfach nicht verstehe (aufgrund der wunderbaren Dokumentation). Auf jeden Fall erreicht er folgende Bedingung (weshalb er abbricht) (ungefähr Z. 382):
Delphi-Quellcode:
if (rep0 >= nowPos64) or (rep0 >= m_DictionarySizeCheck) then begin
  m_OutWindow.Flush();
  result:=false;
  exit;
end;
MfG
xZise

xZise 4. Aug 2009 17:30

Re: 7-zip Entpacker einbinden
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo,
ich habe versucht das Entpacken zu implementieren. Und ich kann sogar ohne Änderung das nicht kompilieren, weil:
Zitat:

[DCC Fehler] Filelisting.pas(49): E2037 Deklaration von 'SetData' unterscheidet sich von vorheriger Deklaration
[DCC Fehler] Filelisting.pas(240): E2010 Inkompatible Typen: '_WIN32_FIND_DATAA' und '_WIN32_FIND_DATAW'
Meine Frage ist nun, soll Unicode oder Ansi verwendet werden?

Ich habe das einfach mal in Unicode bzw Nativ geändert (also bei D2k9 Unicode davor Ansi).

Nebenbei bin ich in der Implementation des Entpackers:
Es gibt schon die Möglichkeit ein geöffnetes Archiv zu schließen und so gut wie auch die Möglichkeit ein Archiv zu öffnen. Leider gibt es einen Parameter mit dem ich nichts anfangen kann:
Delphi-Quellcode:
FInArchive.Open(FStream, <HIERHIERHIER>, Callback);

function Open(stream: IInStream; const maxCheckStartPosition: PInt64; openArchiveCallback: IArchiveOpenCallback): HRESULT; stdcall;
Aber ansonsten habe ich das System ein bisschen umgestellt. Und zwar gibt es von fast allen einmal eine Basisklasse (z.B. TArchiveBase) von denen der Entpacker (z.B. TInArchive) und Packer (z.B. TOutArchive) abgeleitet sind. Ich hoffe das dies so sauber implementiert ist.

Ich habe mal eine Frage an dich, Motzi, und zwar warum hast du beim "TProgressEvent" den Fortschritt als DWord (also Integer) angibst, wenn es nur Werte zwischen 0 und 100 (= Byte ... eigentlich nur 7-Bit) gibt?

[edit]Ich hatte leider die falsche Version hoch geladen. Mit dieser geht es aktuell noch nicht, da muss ich mir noch was überlegen![/edit]

MfG
xZise


Alle Zeitangaben in WEZ +1. Es ist jetzt 22:10 Uhr.
Seite 3 von 3     123   

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz