![]() |
7-zip Entpacker einbinden
Moin DP,
ich habe eine Frage zu 7-zip: Bisher habe ich nur exen gefunden, welche Entpacken, aber ich würde gerne das als Delphi Komponente haben, so dass ich einen Fortschrittsbalken anzeigen kann. Dabei muss diese Komponente mind. 7z, rar und zip entpacken können. MfG xZise |
Re: 7-zip Entpacker einbinden
Bei Meiner 7Zip Oberfläche die ich mit Lazarus erstellt habe, mache ich das einfach so:
Ich rufe zur Laufzeit einfach die Anwendung 7Z auf und Parse dann die Programm Ausgabe. Und das mache ich in einem Extra Thread... Hier sind einige Links für dich: ![]() ![]() und eine Komponente: ![]() dort musst du nach SevenZipVCL_074 suchen. |
Re: 7-zip Entpacker einbinden
Also ich habe mich mal dran versucht, und bin dran gescheitert :(
Und zwar habe ich folgendes Problem:
Delphi-Quellcode:
Wenn ich nun ".Extract" oder ".List" aufrufe, zeigt er einen OpenDialog an. kA warum?!
sevenZip := TSevenZip.Create(self);
try sevenZip.SFXCreate := False; sevenZip.SFXModule := '7z.sfx'; sevenZip.AddOptions := [AddRecurseDirs]; sevenZip.ExtractOptions := []; sevenZip.LZMACompressType := LZMA; sevenZip.LZMACompressStrength := NORMAL; sevenZip.LZMAStrength := 0; sevenZip.ExtrBaseDir := bufferPath; //sevenZip.LPPMDmem := 0; //sevenZip.LPPMDsize := 0; sevenZip.NumberOfFiles := -1; sevenZip.VolumeSize := 1000000; sevenZip.OnProgress := SevenZipProgress; sevenZip.SZFileName := FUpdateInformation[FArchiveIdx * 3]; sevenZip.Extract; finally FreeAndNil(sevenZip); end; MfG xZise |
Re: 7-zip Entpacker einbinden
ich habe damit nie was gemacht da es für Delphi ist....
Aber schau doch mal nach was sevenZip.SZFileName macht. Ich wette das ist eine Eigenschaft ein Property. Ich könnte mir vorstellen das er den Dateinamen nicht findet oder so. |
Re: 7-zip Entpacker einbinden
Hi mimi
Naja: Ich habe den Wert des Ausdrucks kopiert und im Windows Explorer kopiert, welcher das öffnen konnte. MfG xZise |
Re: 7-zip Entpacker einbinden
Also geht die Datei oder wie ? Also das Archiv was du entpacken möchtest ?
ich dachte an: sevenZip.SZFileName := FUpdateInformation[FArchiveIdx * 3]; evlt. musst du ganze Pfad angaben machen. lasse dir mal ausgeben was in FUpdateInformation[FArchiveIdx * 3] drin steht.... ob da eine ganze Pfad Angebe drin steht also: c:\testdir\testfile.txt |
Re: 7-zip Entpacker einbinden
Also darin steht genau die Datei die ich entpacken möchte.
Nun habe ich den Code debuggt, und komme da an diese Stelle:
Delphi-Quellcode:
Bei inA.Open zeigt er dann das Fenster an.
function TSevenZip.Extract( TestArchive:Boolean=False ): Integer;
var updateCallback: TMyArchiveExtractCallback; updateOpenCallback: TmyArchiveOpenCallback; ms: TMyStreamReader; filesDW: array of DWORD; Filestoex,w: DWORD; i,j,n: Integer; FMaxProgress:int64; size: PROPVARIANT; // fnameprop: PROPVARIANT; // fileInArchive, fileToExtract: WideString; begin try // 24.08.06 - Matteo Riso - Status: experimental // 25.08.06 Modified by rg // // If we loaded an .EXE file, we could start reading from offset 132096. // Also supported by newerdll // if FIsSFX then ms.Seek( FSFXOffset,0,@FSFXOffset ); // End - MR modification // Shadow 28.11.2006 if UppercaseW_( ExtractFileExtW( FSevenZipFileName ) ) = '.EXE' then begin if not SFXCheck( FSevenZipFileName ) then begin Result := -1; ErrCode:=FNoSFXarchive; //FHO 21.01.2007 if assigned( onMessage ) then onMessage( self, FNoSFXarchive, c7zipResMsg[FNoSFXarchive], Fsevenzipfilename ); Exit; end; end; ms := TMyStreamReader.Create( Self, FSevenZipFileName, TRUE ); inA.Close; updateOpenCallback := TMyArchiveOpenCallback.Create( self ); i := inA.Open( ms, nil, updateOpenCallback ); [...] Was genau er da macht ist ziemlich verwirrend dann ;) MfG xZise |
Re: 7-zip Entpacker einbinden
anscheind nimmst du die Falsche Methode. Das sieht für mich so aus als ob da so ein Open Dialog kommen soll. das ist also vorgesehen von den Entwicklern. Aber welche Funktion du noch nehmen kannst weiß ich nicht. es gibt noch noch extract Optionen hast du die schon probiert ?
schau doch mal nach was inA: IInArchive; Geanu IInArchive ist. könnte ein Interface sein. Ich habe auf meiner Platte auch noch SevenZip. Also ich weiß im Moment nicht weiter. edit
Delphi-Quellcode:
so machen die das im demoe... fürs Entpacken. Evlt. musst du erst eine liste mit Dateien füllen die du Entpacken möchtest !
procedure TForm1.extractarchiveClick(Sender: TObject);
var i : integer; begin //select extract dir sevenzip1.ExtrBaseDir := 'c:\7ztest'; //Overwrite existing files during extrect ? sevenzip1.ExtractOptions := sevenzip1.ExtractOptions + [ExtractOverwrite]; //Clear Extractlist - for all files do nothing else sevenzip1.Files.clear; if listview1.SelCount > 0 then for i := 0 to listview1.Items.Count -1 do if listview1.Items[i].Selected then sevenzip1.Files.AddString(listview1.Items[i].SubItems[6]); //extract files i := sevenzip1.Extract; // Show result label1.caption := inttostr(i); end; |
Re: 7-zip Entpacker einbinden
Naja, ich habe mir mal die Demo angesehen, und irgendwie ist diese Komponente so arg statisch!
Und zwar, wenn man ein Archiv öffnen möchte, muss man auf "List Archive" klicken. Diese ruft aber wiederrum ".List" auf, welche wiederrum einen OpenDialog anzeigt?! Und mithilfe von ".List" wird das Ereigniss "ListProgress" oder so aufgrufen, wo dann endlich die FileIndexes stehen, welche ich dann der FilesListe hinzufügen könnte. MfG xZise |
Re: 7-zip Entpacker einbinden
Dann bleibt dir nur eine Möglichkeit übrig: Du musst das Programm 7z mit Parametern Starten.
Ich meine für Windows sollte es auch eine Kommandozeilen Anwendung da sein. Dazu könntest du dir unter ![]() Evlt. Hilft das ja. Ist zwar nicht die schöne art, aber es geht und unter Linux habe ich gehört ist das die gäng ste "sache" einfach auf externe Programm zu zurückzugreifen. Für Windows zwar nicht, sollte aber auch gehen. Wenn du dort nicht angemeldet bist kann ich dir mein Projekt auch gerne per PM senden oder an mein nächsten Beitrag hängen. Es ist aber nur für Lazarus. Sollte aber Trotzdem zum nach schauen Hilfreich sein. Wenn du möchtest könnte ich auch draus ein Klasse erstellen, die auf das 7Z Programm zu zurückgreift. Ich hoffe du weißt wie ich das meine. |
Re: 7-zip Entpacker einbinden
Ich musste für mein letztes Projekt auch 7zip verwenden (die DLL, nicht das Programm) und hab mir dazu die besagte SevenZip Komponente von Torry angeschaut. Allerdings ist die IMHO absolut schlecht designed und teilweise auch fehlerhaft implementiert -> meiner Ansicht nach ist sie absolut unbrauchbar.
Ich hab mir dann im Endeffekt eine eigene Implementierung geschrieben, diese beschränkt sich bis jetzt allerdings nur auf das Packen - entpacken war bei dem Projekt nicht notwendig, daher hab ich das nicht implementiert. Wenn du willst kann ich dir die Unit trotzdem geben, ich denke es ist recht gut erkennbar wie die 7zip-Dll verwendet werden muss (das herauszufinden war schon ein Abenteuer für sich - der Code der Dll und auch des 7zip-Programms sind so gut wie überhaupt nicht dokumentiert). Gruß, Motzi |
Re: 7-zip Entpacker einbinden
OH ! Toll, könntest du sie für alle an dein nächsten Beitrag hängen ? ich würde sie mir gerne mal ansehen.
Evlt. kann ich sie für meine 7Zip Oberfläche verwenden das währe toll. Ich meinte einiges konnte die SevenZip Komponente leider auch nicht, darum habe ich sie nicht genommen. Aber zum nach schauen sollte das ausreichen. Gibt es denn schon eine Header Datei für "Object Pascal" von der 7z.dll/so Datei ? |
Re: 7-zip Entpacker einbinden
Hi Michael und Manuel,
ich habe mir mal den ![]()
Delphi-Quellcode:
Da die Komponente installiert war, fehlen natürlich die Initalisierungssachen.
Zip.ExtrBaseDir := Pfad;
Zip.AddRootDir :='c:\'; Zip.SZFileName := inttostr(LatestVersion) + '.7z'; Zip.Extract(); Aber aufgrund dessen ist mir aufgefallen, dass "SZFileName" ja ein Dateiname und nicht Dateiname + Pfad haben will. Also das geändert, und oh wunder ;) Keine OpenDialoge mehr. Aber was ist bzw. macht "AddRootDir" und "ExtrBaseDir"? Und Manuel, könntest du den Code mal anhängen? Im Grunde genommen möchte ich ja nur entpacken. MfG xZise |
Re: 7-zip Entpacker einbinden
Liste der Anhänge anzeigen (Anzahl: 2)
Im Anhang sind 2 Archive, einmal eines mit den Object Pascal Versionen der Headerfiles und eines mit meiner SevenZip-Klase inkl. Zubehör. Der Code ist nur teilweise kommentiert/dokumentiert, ich hoffe ihr kommt damit zurecht.
Wie gesagt beherrscht die SevenZip-Klasse bis jetzt nur Packen - dazu bekommt sie eine TCreateArchiveParams-Instanz die alle Parameter enthält. Unter anderem eine TArchiveItemList - eine Liste mit Files die in das Archiv rein sollen. Man kann jedes Element einzeln zu dieser Liste hinzufügen, oder aber (wenn ein ganzer Ordner und evnetuell Unterordner) reinsoll, dann kann man sich mit der TFileListing-Klasse ein komplettes Listing erstellen lassen (wobei TFileArchiveItem und TFolderArchiveItem als Parameter übergeben werden müssen). Bei Unklarheiten kann ich eventuell kann ich mal ein kleines Demo erstellen. Edit: die SevenZip-Komponente von Torry enthält zwar teilweise auch Übersetzungen der Headerfiles, allerdings von einer älteren Version und außerdem sind sie unvollständig und teilweise fehlerhaft. Die Übersetzungen im Anhang hab ich daher selbst gemacht, ich hoffe es ist alles korrekt... |
Re: 7-zip Entpacker einbinden
Vielen Dank ! Werde ich mir gleich mal ansehen.
|
Re: 7-zip Entpacker einbinden
Hmmm... Nicht gerade einfach der Code ^^
Zu der 7zVCL Komponente: Wenn ich das wie oben mache und nur den Dateinamen setzte, dann funktionierts immer noch nicht, weil i <> 0 ist :( Warum muss man das auch so benutzerunfreundlich machen.
Delphi-Quellcode:
(Extract-Prozedur)
[...]
updateOpenCallback := TMyArchiveOpenCallback.Create( self ); i := inA.Open( ms, nil, updateOpenCallback ); if i <> 0 then begin Result := -1; ErrCode:=FFileNotFound; //FHO 21.01.2007 if assigned( onMessage ) then onMessage( self,FFileNotFound, c7zipResMsg[FFileNotFound],FSevenZipFileName ); ms.Free; //FHO crash at wrong pw 25.01.2007 Exit; end; [...] MfG xZise |
Re: 7-zip Entpacker einbinden
Liste der Anhänge anzeigen (Anzahl: 1)
Ja, ich seh ein, dass er am Anfang nicht gerade einfach zu verstehen ist. Vor allem da es keine wirkliche Dokumentation dazu gibt. Aber wenn man ihn einmal durchschaut hat ist er sehr einfach zu verwenden und vor allem sehr flexibel (vor allem die FileListing-Unit - auf die bin ich besonders stolz! :))
Ich hab mal ein kurzes Demo zusammengeklickt, das zeigt wie man die einzelnen Klassen benutzt. Das komplette Projekt befindet sich im Anhang. Gruß, Motzi |
Re: 7-zip Entpacker einbinden
Hi,
ich denke du kannst was mit dem Code anfangen, aber ich blicke da nicht irgendwie da so richtig durch. Was macht z.B. TStreamReader? Im Endeffekt sieht es so aus, als würde sie... TStream imitieren ... oder nicht? Und warum nicht TStream nehmen? War wohl ein Fehler zu vermuten, dass OpenSource Systeme eher implementiert werden... Zu 7zipVCL, sollte wirklich jemand das benutzten und wissen was er tut, wie umgeht man das Problem, dass in der .dfm der Demo ungültige Werte stehen?
Delphi-Quellcode:
MfG
sevenZip.LPPMDmem := 0;
sevenZip.LPPMDsize := 0; xZise |
Re: 7-zip Entpacker einbinden
Zitat:
Man muss zuerst einmal das System der 7-zip DLL verstehen, aber leider ist das nicht so einfach da es überhaupt nicht dokumentiert ist. Ich hab auch sehr lang gebraucht bis ich es durchschaut hab. Gruß, Motzi |
Re: 7-zip Entpacker einbinden
Ah okay. Ist etwas verwirrend :) Da muss man erstmal durchblicken :(
Was macht den genau TStreamReader? Und wie würde man am besten ran gehen zu entpacken? An alle die 7zipVCL verwenden (scheint wohl <= 0 zu sein :cry: ): Wie habt ihr es hingekriegt, etwas zu entpacken? Das es geht, sieht man ja an einem Programm was hier in der DP steht. Aber dort steht eigentlich das was ich habe :| Aber ohne Erfolg. Ich habe erraten, dass wenn SZFilename existiert kommt der Opendialog ansonsten nicht. Wäre jetzt nur noch nett zu wissen, was ich dagegen mach muss. MfG xZise |
Re: 7-zip Entpacker einbinden
Zitat:
Zum Packen ruf ich die Methode IOutArchive.UpdateItems auf welche folgendermaßen ausschaut:
Delphi-Quellcode:
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:
function UpdateItems(outStream: ISequentialOutStream; numItems: DWord; updateCallback: IArchiveUpdateCallback): HRESULT; stdcall;
Delphi-Quellcode:
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:
outStream := TStreamWriter.Create(TFileStream.Create(FParams.Filename, fmCreate)); // TStreamWriter ist der Wrapper für den TFileStream
FOutArchive.UpdateItems(outStream, FParams.Items.Count, callback);
Delphi-Quellcode:
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).
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; 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 |
Re: 7-zip Entpacker einbinden
|
Re: 7-zip Entpacker einbinden
Zitat:
So sieht meine Testroutine aus:
Delphi-Quellcode:
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.
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; 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:
MfG
if (rep0 >= nowPos64) or (rep0 >= m_DictionarySizeCheck) then begin
m_OutWindow.Flush(); result:=false; exit; end; xZise |
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:
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:
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.
FInArchive.Open(FStream, <HIERHIERHIER>, Callback);
function Open(stream: IInStream; const maxCheckStartPosition: PInt64; openArchiveCallback: IArchiveOpenCallback): HRESULT; stdcall; 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 08:10 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