Может ли CopyFileEx вызываться из вторичного потока? - PullRequest
6 голосов
/ 16 июня 2011

Можно и правильно ли вызывать функции CopyFileEx и CopyCallback / ProgressRoutine (ProgressBar.Position будет синхронизироваться) из потока?

Можно ли объявить функцию CopyCallback / ProgressRoutine в потоке?Я получаю сообщение об ошибке: «Требуется переменная» в CopyFileEx на @ ProgressRoutine.

1 Ответ

12 голосов
/ 16 июня 2011

Конечно, это возможно. Функция обратного вызова будет вызываться в контексте потока, который вызывает CopyFileEx. Если вам нужно синхронизировать некоторые команды пользовательского интерфейса, используйте обычный 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;
...