は、あなたがコピーをキャンセルする任意の時点でTRUE
に設定することができBOOL
変数のアドレスを渡しています。 CopyFileEx()
はその変数を監視しますが、変数が設定されているときにコールバックからPROGRESS_CANCEL
を手動で返す必要はありません(戻り値PROGRESS_CANCEL
、コールバックにコピー自体に関連しないエラーが発生し、結果としてコピーを中断したい場合エラーの)。しかし、私はグローバル変数を使用しません。私はコピーを実行しているフォームにローカルな変数を使用します。 - あなたがスレッドにTForm.Handle
プロパティからHWND
を渡していると述べたことで
type
TFormMain = class(TForm)
...
private
CancelCopy: BOOL; // <-- BOOL, not Boolean
...
end;
...
type
TCopyEx = record
Source: String;
Dest: String;
Handle: HWND;
PCancelCopy: PBOOL;
end;
PCopyEx = ^TCopyEx;
const
CFEX_CANCEL = WM_USER + 1;
function CopyFileProgress(TotalFileSize, TotalBytesTransferred, StreamSize,
StreamBytesTransferred: LARGE_INTEGER; dwStreamNumber, dwCallbackReason: DWORD;
hSourceFile, hDestinationFile: THandle; lpData: Pointer): DWORD; stdcall;
begin
// no need to watch CancelCopy here...
// do normal status handling here as needed...
// use PCopyEx(lpData)^ as needed...
end;
function CopyExThread(p: PCopyEx): Integer;
begin
try
if not CopyFileEx(PChar(p.Source), PChar(p.Dest), @CopyFileProgress, p, p.PCancelCopy, COPY_FILE_NO_BUFFERING) then
begin
if GetLastError() = ERROR_REQUEST_ABORTED then
SendMessage(p.Handle, CFEX_CANCEL, 0, 0);
end;
finally
Dispose(p);
end;
Result := 0;
end;
procedure TFormMain.ButtonCopyClick(Sender: TObject);
var
Params: PCopyEx;
ThreadID: Cardinal;
begin
New(Params);
Params.Source := EditOriginal.Text;
Params.Dest := EditCopied.Text;
Params.Handle := Handle;
Params.PCancelCopy := @CancelCopy; // <-- pass address of CancelCopy here...
CancelCopy := FALSE;
CloseHandle(BeginThread(nil, 0, @CopyExThread, Params, 0, ThreadID));
end;
procedure TFormMain.ButtonCancelClick(Sender: TObject);
begin
CancelCopy := TRUE;
end;
、に注意する何か他のもの:
は、より多くの代わりにこのような何かを試してみてください。 TForm
が何らかの理由でHWND
を破壊/再作成すると、スレッドがまだ実行されている間に、TCopyEx.Handle
の値が無効なウィンドウを指し示すことになります(または悪いことに古いものを再利用する新しいウィンドウHWND
値)。一般的に
、TWinControl.Handle
プロパティは、スレッドセーフではありません、そのためだけではその理由、あなたが保証HWND
をすることができない限り、ワーカースレッドにTWinControl
オブジェクトのHWND
を渡すために良いアイデアではありませんスレッドが実行されている間は破棄されません(この例では保証されません)。
この例では、私は、このようなTApplication.Handle
ウィンドウ(このウィンドウに送信されたメッセージがTApplication.HookMainWindow()
を介して処理することができます)、または呼び出しの結果として、スレッドの生活のための永続性が保証された別のHWND
を使用しますAllocateHWnd()
。例えば
:
type
TFormMain = class(TForm)
procedure FormDestroy(Sender: TObject);
...
private
CancelCopy: BOOL; // <-- BOOL, not Boolean
CopyFileExWnd: HWND;
procedure CopyFileExWndProc(var Message: TMessage);
...
end;
...
type
TCopyEx = record
Source: String;
Dest: String;
Handle: HWND;
PCancelCopy: PBOOL;
end;
PCopyEx = ^TCopyEx;
const
CFEX_CANCEL = WM_USER + 1;
function CopyFileProgress(TotalFileSize, TotalBytesTransferred, StreamSize,
StreamBytesTransferred: LARGE_INTEGER; dwStreamNumber, dwCallbackReason: DWORD;
hSourceFile, hDestinationFile: THandle; lpData: Pointer): DWORD; stdcall;
begin
...
end;
function CopyExThread(p: PCopyEx): Integer;
begin
try
if not CopyFileEx(
PChar(p.Source), PChar(p.Dest), @CopyFileProgress, p, p.PCancelCopy, COPY_FILE_NO_BUFFERING) then
begin
if GetLastError() = ERROR_REQUEST_ABORTED then
SendMessage(p.Handle, CFEX_CANCEL, 0, 0);
end;
finally
Dispose(p);
end;
Result := 0;
end;
procedure TFormMain.FormDestroy(Sender: TObject);
begin
if CopyFileExWnd <> 0 then
DeallocateHWnd(CopyFileExWnd);
end;
procedure TFormMain.ButtonCopyClick(Sender: TObject);
var
Params: PCopyEx;
ThreadID: Cardinal;
begin
if CopyFileExWnd = 0 then
CopyFileExWnd := AllocateHWnd(CopyFileExWndProc);
New(Params);
Params.Source := EditOriginal.Text;
Params.Dest := EditCopied.Text;
Params.Handle := CopyFileExWnd;
Params.PCancelCopy := @CancelCopy;
CancelCopy := FALSE;
CloseHandle(BeginThread(nil, 0, @CopyExThread, Params, 0, ThreadID));
end;
procedure TFormMain.ButtonCancelClick(Sender: TObject);
begin
CancelCopy := TRUE;
end;
procedure TFormMain.CopyFileExWndProc(var Message: TMessage);
begin
case Message.Msg of
CFEX_CANCEL: begin
...
end;
...
else
Message.Result := DefWindowProc(CopyFileExWnd, Message.Msg, Message.WParam, Message.LParam);
end;
end;
それは結構です。データ競争の可能性がありますが、それは良性です。 –
スレッドは読んでいるだけなので、 –
あなたは「スレッド」と言っていますが、2つのスレッドがあります。あなたがメインであることを知っているかもしれないし、ワーカーであることを知っているかもしれないが、システムはただ2つのスレッドを見る。 1つのスレッドがその変数を読み取り、もう1つのスレッドがその変数を書き込みます。それはデータ競争です。しかし、レースは良性です。 –