可以从辅助线程调用CopyFileEx吗?

max*_*fax 6 delphi winapi multithreading file-copying

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

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

Rob*_*edy 12

当然有可能.回调函数将在调用的线程的上下文中调用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;
Run Code Online (Sandbox Code Playgroud)

您可以使用lpData参数为回调函数提供对关联线程对象的访问权限.在调用时传递对该参数的线程对象的引用CopyFileEx:

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

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

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

  • 从技术上讲,@ Serg,有竞争条件.`TProgressBar`在读取`Handle`属性之前检查`HandleAllocated`.如果句柄已经被分配,但是在读取`Handle`之前它被销毁了,那么句柄将在错误的线程中重新分配.这不可能发生,所以`TProgressBar`可能是安全的.但是,一般而言,UI更新应与UI线程同步. (7认同)