在 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