【问题标题】:Can CopyFileEx be called from a secondary thread?可以从辅助线程调用 CopyFileEx 吗?
【发布时间】:2011-09-16 01:17:28
【问题描述】:

是否可以从线程调用 CopyFileEx 和 CopyCallback/ProgressRoutine 函数(ProgressBar.Position 将被同步)?

我可以在线程中声明 CopyCallback/ProgressRoutine 函数吗?我在 @ProgressRoutine 上的 CopyFileEx 中收到错误:“需要变量”。

【问题讨论】:

    标签: multithreading delphi winapi file-copying


    【解决方案1】:

    当然可以。回调函数将在调用CopyFileEx 的线程的上下文中调用。如果您需要同步一些 UI 命令,请使用 Delphi 常用的TThread.Synchronize,或者您想要的任何其他线程间同步技术。

    回调函数不能是线程类的方法。它需要与 API 规定的签名相匹配,因此它需要是一个独立的函数。正确声明后,将其传递给 CopyFileEx 时不需要使用 @ 运算符。

    function CopyProgressRoutine(TotalFileSize, TotalBytesTransferred: Int64;
      StreamSize, StreamBytesTransferred: Int64;
      dwStreamNumber, dwCallbackReason: DWord;
      hSourceFile, hDestinationFile: THandle;
      lpData: Pointer): DWord; stdcall;
    

    您可以使用lpData 参数让回调函数访问关联的线程对象。当您调用CopyFileEx 时,传递对该参数的线程对象的引用:

    procedure TCopyThread.Execute;
    begin
      ...
      CopyResult := CopyFileEx(CurrentName, NewName, CopyProgressRoutine, Self,
        @Cancel, CopyFlags);
      ...
    end;
    

    通过访问线程对象,您可以调用该对象上的方法,包括它自己的进度例程,因此以下内容可以构成独立函数的全部。它可以将其他所有内容委托给您的对象的方法。在这里,我假设该方法具有与独立函数相同的所有参数,只是它省略了 lpData 参数,因为它将作为 Self 参数隐式传递。

    function CopyProgressRoutine;
    var
      CopyThread: TCopyThread;
    begin
      CopyThread := lpData;
      Result := CopyThread.ProgressRoutine(TotalSize, TotalBytesTransferred,
        StreamSize, StreamBytesTransferred, dwStreamNumber,
        dwCallbackReason, hSourceFile, hDestinationFile);
    end;
    

    【讨论】:

    • 设置TProgressBar.Position 不需要TThread.Synchronize IMO。 TProgressBar.SetPosition 方法从不分配控件的句柄,并通过 SendMessage 调用自行切换线程上下文。
    • 从技术上讲,@Serg,存在竞争条件。 TProgressBar 在读取 Handle 属性之前检查 HandleAllocated。如果句柄已经分配,​​但在读取Handle 之前被销毁,则句柄将在错误的线程中重新分配。这不太可能发生,所以TProgressBar 可能是安全的。不过,一般来说,UI 更新应该与 UI 线程同步。
    • 我可以在线程中声明 CopyCallback/ProgressRoutine 函数吗?我在 @ProgressRoutine 上的 CopyFileEx 中收到错误:“需要变量”。
    • 不过,您可以排队而不是使用 TThread.Synchronize 完全锁定同步。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-05
    • 1970-01-01
    • 2011-05-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多