在 Delphi 中使用 TJclZipCompressArchive 阻塞主 VCL 线程
Using TJclZipCompressArchive blocks the main VCL thread in Delphi
我使用 Jedi JCL 的 TJclZipCompressArchive 和 7zip.dll 将多个文件添加到 ZIP 存档,如下所示:
arch := TJclZipCompressArchive.Create(_ZipFn);
arch.OnProgress := HandleOnProgress;
for i := 0 to Files.Count - 1 do begin
fn := Files[i];
arch.AddFile(ExtractFileName(fn), fn);
end;
arch.Compress;
arch.CheckOperationSuccess;
(此代码在 VCL 主线程中调用。)
虽然这有效,但我在显示进度和选择性地允许用户中止操作时遇到了问题。为此,我添加了一个 OnProgress 处理程序:
procedure Tf_ZipMeasurement.HandleOnProgress(Sender: TObject; const Value, MaxValue: Int64);
begin
// originally this called Application.ProcessMessages
TThread.Synchronize(nil, SyncHandleProgress);
if FAborted then
TJclZipCompressArchive(Sender).CancelCurrentOperation := True;
end;
最初,我只是更新了用户界面并调用了Application.ProcessMessages。这没有用,因为调用此事件的线程不是主 VCL 线程,所以我将其改为调用 TThread.Synchronize。
不幸的是,这会导致死锁,因为显然主线程正忙于在 7zip.dll 中做某事。 (因为 documentation on TJclZipCompressArchive 不存在,我在这里猜测。)
据我所知,为了让它工作,我必须在后台线程中调用 arch.Compress,这样主线程就可以进行消息处理了。
有人有使用 TJclZipCompressArchive 或 7zip.dll 的经验吗?是正确的做法吗?或者有更好/更简单的选择吗?
您的分析是正确的。如果 ZIP 库在不同的线程上调用您的进度事件处理程序,那么从该线程调用 Synchronize
就是一个死锁。你说:
apparently the main thread is busy doing something within the 7zip.dll
嗯,它做的就是你告诉它做的!即压缩存档。由于 ZIP 库不是 Delphi 原生的,它不会发送 Synchronize
个请求。
前进的方向是从工作线程调用 Compress
。
我使用 Jedi JCL 的 TJclZipCompressArchive 和 7zip.dll 将多个文件添加到 ZIP 存档,如下所示:
arch := TJclZipCompressArchive.Create(_ZipFn);
arch.OnProgress := HandleOnProgress;
for i := 0 to Files.Count - 1 do begin
fn := Files[i];
arch.AddFile(ExtractFileName(fn), fn);
end;
arch.Compress;
arch.CheckOperationSuccess;
(此代码在 VCL 主线程中调用。) 虽然这有效,但我在显示进度和选择性地允许用户中止操作时遇到了问题。为此,我添加了一个 OnProgress 处理程序:
procedure Tf_ZipMeasurement.HandleOnProgress(Sender: TObject; const Value, MaxValue: Int64);
begin
// originally this called Application.ProcessMessages
TThread.Synchronize(nil, SyncHandleProgress);
if FAborted then
TJclZipCompressArchive(Sender).CancelCurrentOperation := True;
end;
最初,我只是更新了用户界面并调用了Application.ProcessMessages。这没有用,因为调用此事件的线程不是主 VCL 线程,所以我将其改为调用 TThread.Synchronize。
不幸的是,这会导致死锁,因为显然主线程正忙于在 7zip.dll 中做某事。 (因为 documentation on TJclZipCompressArchive 不存在,我在这里猜测。)
据我所知,为了让它工作,我必须在后台线程中调用 arch.Compress,这样主线程就可以进行消息处理了。
有人有使用 TJclZipCompressArchive 或 7zip.dll 的经验吗?是正确的做法吗?或者有更好/更简单的选择吗?
您的分析是正确的。如果 ZIP 库在不同的线程上调用您的进度事件处理程序,那么从该线程调用 Synchronize
就是一个死锁。你说:
apparently the main thread is busy doing something within the 7zip.dll
嗯,它做的就是你告诉它做的!即压缩存档。由于 ZIP 库不是 Delphi 原生的,它不会发送 Synchronize
个请求。
前进的方向是从工作线程调用 Compress
。