![]() |
Schwierigkeiten mit 7-zip und Events
Ich habe vor Kurzem die SevenZIPVCL-Komponente (
![]() Ich benutze die Version 0.7.6 und so sieht mein Button der Demo aus
Delphi-Quellcode:
Das funktioniert einwandfrei.
procedure TForm1.Button1Click(Sender: TObject);
var aSevenZip: TSevenZip; begin Caption := 'Compressing ...'; aSevenZip := TSevenZip.Create(Self); try // aSevenZip.OnProgress := SevenZipOnProgress; // aSevenZip.OnAddfile := SevenZipOnAddFile; aSevenZip.AddRootDir := 'E:\7ztest\'; aSevenZip.SZFileName := ExtractFilePath(Application.ExeName) + 'Test.7z'; // aSevenZip.Password := '123456'; aSevenZip.LZMACompressType := LZMA; // LZMA, PPMD aSevenZip.LZMACompressStrength := NORMAL; // SAVE, FAST, NORMAL, MAXIMUM, ULTRA aSevenZip.AddOptions := []; // AddRecurseDirs, AddSolid, AddStoreOnlyFilename, AddIncludeDriveLetter, AddEncryptFilename aSevenZip.Files.Clear; aSevenZip.Files.AddString('E:\7ztest\249MB.123'); aSevenZip.Files.AddString('E:\7ztest\123\456.txt'); aSevenZip.Files.AddString('E:\7ztest\456'); // aSevenZip.SevenZipComment := 'Comment!'; aSevenZip.add; finally aSevenZip.Free; end; Caption := 'Done'; end; Nur sobald ich OnProgress, OnAddfile oder beides verwende, scheint mein Demo-Programm (welches nur diesen Button und eine ProgressBar hat) zu hängen. Die Event-Prozeduren sehen so aus
Delphi-Quellcode:
Ist das ein Bug? Denn egal was in den Event-Prozeduren steht, es führt immer zum Stillstand der Demo.
procedure TForm1.SevenZipOnProgress(Sender: TObject; Filename: WideString; FilePosArc, FilePosFile: Int64);
begin ProgressBar1.Position := FilePosArc; Application.ProcessMessages; end; procedure TForm1.SevenZipOnAddFile(Sender: TObject; Filename: WideString; Filesize: Int64); begin Caption := Filename; ProgressBar1.Position := 0; ProgressBar1.Max := Filesize; end; Es scheint so, als ob die Demo nur hängt, wenn in den Events irgendwas steht was mit der VCL zu tun hat. Wenn ich dort reinschreibe i:=123; hängt sich nichts auf. |
AW: Schwierigkeiten mit 7-zip und Events
..."Es scheint so, als ob die Demo nur hängt, wenn in den Events irgendwas steht was mit der VCL zu tun hat."...
Wenn man die Callbackquelle innerhalb von 7Zip nicht kennt, gehe man davon aus, das es dort in/durch einen Thread aufgerufen wird. -> Also hier NIX mit VCL und KEIN Application.ProcessMessages... besser im Event nur irgendetwas einfaches ala PostMessage, Syncronize, CallInMainTread oä. |
AW: Schwierigkeiten mit 7-zip und Events
Zitat:
Wie würde das denn im Mainthread mit Postmessage funktionieren? Ich benutze der Einfachheit halber jetzt die JEDI-Komponenten. Es wird aber dieselbe DLL verwendet. Folgendes scheint scheinbar nicht zu funktionieren (GUI wird nicht aktualisiert)
Delphi-Quellcode:
const
WM_UPDATE_PB = WM_USER; procedure UpdateMessage(Value: Int64); begin PostMessage(Form1.Handle, WM_UPDATE_PB, Value, 0); end; procedure TForm1.WMUpdatePB(var msg: TMessage); begin ProgressBar1.Position := msg.WParam; Application.ProcessMessages; end; procedure TForm1.JclOnProgress(Sender: TObject; const Value, MaxValue: Int64); begin UpdateMessage(Value); // ProgressBar1.Position := Value; // Application.ProcessMessages; end; |
AW: Schwierigkeiten mit 7-zip und Events
![]() es fehlt dir wohl noch der "MessageMap" im Form
Delphi-Quellcode:
(und ich würde statt "Application.ProcessMessages;" lieber "ProgressBar1 .Update .Repaint .Invalidate" verwenden wenn es das gibt. Wenn etwas nur mit "ProcessMessages" geht, ist meist das Konzept nicht so wirklich gut)
protected
procedure UserMsgProc(var Message: TMessage); message WM_USER; end; |
AW: Schwierigkeiten mit 7-zip und Events
Hallo,
wenn intern ein Thread benutzt wird, fehlt vielleicht nur Synchronize beim Upate der GUI im Hauptprogramm. |
AW: Schwierigkeiten mit 7-zip und Events
Zitat:
Zitat:
Ich habe mal ein bisschen rumgespielt und den Code im Button in Folgendes gepackt
Delphi-Quellcode:
Dann funktioniert es. Aber warum nicht schon mit PostMessage usw.? Damit habe ich es ja auch versucht.
TThread.CreateAnonymousThread(
procedure begin end).Start: |
AW: Schwierigkeiten mit 7-zip und Events
Jaja.....nur die DLL, die nutzt sehr wohl Threads.
|
AW: Schwierigkeiten mit 7-zip und Events
wenn du magst, hänge das gezippte Projekt deines "MiniTestProg" mal hier an eine Antwort an. Wenn ich am WE dazu komme kann ich mal schaun was mein PC dazu sagt;)
Bei deinem "TThread.CreateAnonymousThread" ist es mir nicht ganz wohl, du entkoppelst dich zwar von dem externen DLL Thread, aber echt sauber im MainThread der VCL bist du so auch noch nicht. Das PostMessage mit einer "selbst gemappten" MessageProc oder einer Komponente ala "AppMessage" wo man sich seine Message im Event raussucht wäre mir hier für alles was ich sonst noch in der GUI vor hätte die sicherste und einfachste Lösung. Man kann das sicher auch mit eigenen (Async)Threads oder Synchronize hinbekommen, aber als fauler Mensch fehlt mir dazu der Elan. |
AW: Schwierigkeiten mit 7-zip und Events
Ich poste hier mal meine erste halbwegs funktionierende Lösung.
Aktuell funktioniert ZIP und 7z. GZip warum auch immer noch nicht.
Delphi-Quellcode:
const
WM_SYNC_ARCHIVE_PROGRESS = WM_USER + 153; procedure TForm1.WMSyncArchiveProgress(var Message: TMessage); begin ProgressBar1.Max := Message.LParam; ProgressBar1.Position := Message.WParam; end; procedure TForm1.JclCompressionArchiveProgress(Sender: TObject; const Value, MaxValue: Int64); var MyValue, MyMaxValue: Int64; begin MyValue := Value; MyMaxValue := MaxValue; while MyMaxValue > High(Byte) do begin MyMaxValue := MyMaxValue shr 8; MyValue := MyValue shr 8; end; PostMessage(Handle, WM_SYNC_ARCHIVE_PROGRESS, MyValue, MyMaxValue); end; procedure TForm1.Button2Click(Sender: TObject); var aFile: string; aCompressArchive: TJclCompressionArchive; aCompressFormat: TJclCompressArchiveClass; begin TThread.CreateAnonymousThread( procedure begin aFile := ExtractFilePath(Application.ExeName) + Edit1.Text; // Edit1 z.B. "Test.7z" oder "Test.zip" aCompressFormat := GetArchiveFormats.FindUpdateFormat(aFile); if aCompressFormat <> nil then begin Caption := 'Compressing ...'; aCompressArchive := aCompressFormat.Create(aFile); try aCompressArchive.OnProgress := JclCompressionArchiveProgress; aCompressArchive.Password := '123456'; (aCompressArchive as TJclCompressArchive).AddFile('249MB.123', 'E:\7ztest\249MB.123'); (aCompressArchive as TJclCompressArchive).AddFile('456.txt', 'E:\7ztest\123\456.txt'); (aCompressArchive as TJclCompressArchive).AddFile('456', 'E:\7ztest\456'); if (aCompressArchive.ClassType = JCLCompression.TJcl7zCompressArchive) or (aCompressArchive.ClassType = JCLCompression.TJcl7zUpdateArchive) then begin ShowMessage('7z'); // - SetEncryptionMethod for 7z not available (aCompressArchive as TJcl7zUpdateArchive).SetCompressionLevel(6); // 0 .. 9 (aCompressArchive as TJcl7zUpdateArchive).SetCompressHeader(True); if aCompressArchive.Password <> '' then (aCompressArchive as TJcl7zUpdateArchive).SetEncryptHeader(True); end else if (aCompressArchive.ClassType = JCLCompression.TJclZIPCompressArchive) or (aCompressArchive.ClassType = JCLCompression.TJclZipUpdateArchive) then begin ShowMessage('zip'); // - SetEncryptHeader/SetCompressHeader for zip not available (aCompressArchive as TJclZipUpdateArchive).SetNumberOfPasses(3); (aCompressArchive as TJclZipUpdateArchive).SetCompressionLevel(7); // 0 .. 9 (aCompressArchive as TJclZipUpdateArchive).SetCompressionMethod(TJclCompressionMethod.cmDeflate); if aCompressArchive.Password <> '' then (aCompressArchive as TJclZipUpdateArchive).SetEncryptionMethod(emAES256); // emNone, emAES128, emAES192, emAES256, emZipCrypto end else if (aCompressArchive.ClassType = JCLCompression.TJclGZipCompressArchive) or (aCompressArchive.ClassType = JCLCompression.TJclGZipUpdateArchive) then begin ShowMessage('Gzip'); (aCompressArchive as TJclGZipUpdateArchive).SetCompressionLevel(7); // 0 .. 9 (aCompressArchive as TJclGZipUpdateArchive).SetNumberOfPasses(3); end else FreeAndNil(aCompressArchive); if aCompressArchive <> nil then (aCompressArchive as TJclCompressArchive).Compress; // Funktioniert bei Gzip noch nicht finally FreeAndNil(aCompressArchive); Caption := 'Done'; end; end; end).Start; end; Zitat:
|
AW: Schwierigkeiten mit 7-zip und Events
"Caption := " und "ShowMessage" wieder/noch einfach so in einem (Anonymous)Thread... auch wenn nur zum schnellen Test... das geht so nicht auf Dauer gut
|
AW: Schwierigkeiten mit 7-zip und Events
Mein viel größeres Problem besteht darin festzustellen, wann eine Datei fertig komprimiert wurde. Dafür bietet JCL leider kein Event.
Meine behilfsmäßige Lösung ist sehr kompliziert und funktioniert nur bei größeren Dateien und das ist ja nicht Sinn der Sache :( Sinn dahinter ist, dass ich zählen möchte wie viele Dateien vollständig komprimiert wurden + deren Dateigrößen möchte ich auch festhalten. Mit einem vernünftigen Event wie "OnProgressFileFinished" oder so wär das alles kein Problem.
Delphi-Quellcode:
Edit
var
iFileSizeOld, iFileSizeCompressed: Int64; iFilesCompressed, iCurrentItem: Integer; procedure TForm1.JclCompressionArchiveProgress(Sender: TObject; const Value, MaxValue: Int64); function getPercent(const aBase, aValue: Extended): ShortInt; begin if (aValue > 0) and (aBase > 0) then Result := Trunc((aValue / aBase * 100) + 0.5) else Result := 0; end; var iTmpPos, iTmp: Integer; begin iTmpPos := getPercent(MaxValue, Value); if (iTmpPos <> ProgressBar1.Position) or (iTmpPos = ProgressBar1.Max) then begin if ((Sender as TJclCompressionArchive).ItemCount > iFilesCompressed) then begin ProgressBar1.Position := iTmpPos; iFileSizeOld := (Sender as TJclCompressionArchive).Items[iFilesCompressed].FileSize; iTmp := getPercent(iFileSizeOld, Value - iFileSizeCompressed); if iTmp >= 100 then // bei größeren Dateien kann man hier davon ausgehen, dass sie fertig komprimiert wurde begin inc(iFileSizeCompressed, iFileSizeOld); if iFilesCompressed < (Sender as TJclCompressionArchive).ItemCount then begin ShowMessage('Datei fertig'); inc(iFilesCompressed); end; end; end; end; end; ich habe das Ganze jetzt mal etwas gekürzt und nun funktioniert es auch mit sehr kleinen Dateien (< 10 Byte etc).
Delphi-Quellcode:
var
iFileCount, iFileSizeOld, iFileSizeCompressed: Int64; iFilesCompressed: Integer; // ... Button der das Archiv erzeugt... // ... iFileCount := 2; // Nur Dateien werden hier gezählt. Leere Verzeichnisse werden von JCL anders erstellt (aCompressArchive as TJclCompressArchive).AddFile('kleinedatei 1.txt', 'E:\7ztest\kleinedatei 1.txt'); (aCompressArchive as TJclCompressArchive).AddFile('kleinedatei 2.txt', 'E:\7ztest\kleinedatei 2.txt'); // ... procedure TForm1.JclCompressionArchiveProgress(Sender: TObject; const Value, MaxValue: Int64); function getPercent(const aBase, aValue: Extended): ShortInt; begin if (aValue > 0) and (aBase > 0) then Result := Trunc((aValue / aBase * 100) + 0.5) else Result := 0; end; begin if (iFilesCompressed < iFileCount) then begin ProgressBar1.Position := getPercent(MaxValue, Value); iFileSizeOld := (Sender as TJclCompressionArchive).Items[iFilesCompressed].FileSize; if (Value >= (iFileSizeOld + iFileSizeCompressed)) then begin inc(iFilesCompressed); inc(iFileSizeCompressed, iFileSizeOld); end; end; end; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 16:55 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