TCopyInfo = packed record Source: String[255]; Dest: String[255]; Handle: THandle; end; PCopyInfo = ^TCopyInfo;
const
//사용자정의 메시지 COPY_CANCEL = WM_USER + 1; COPY_CONTINUE = WM_USER + 2; COPY_MAXBYTES = WM_USER + 3; COPY_FAIL = WM_USER + 4;
var bCancel : Boolean = False;
function CopyFileProgress(TotalFileSize, TotalBytesTransferred, StreamSize, StreamBytesTransferred: LARGE_INTEGER; dwStreamNumber, dwCallbackReason, hSourceFile, hDestinationFile: DWORD; lpData: Pointer): DWORD; stdcall; begin if bCancel then //Cancel Message begin SendMessage(THandle(lpData), COPY_CANCEL, 0, 0); Result := PROGRESS_CANCEL; Exit; end;
case dwCallbackReason of CALLBACK_CHUNK_FINISHED: //Continue Message begin SendMessage(THandle(lpData), COPY_CONTINUE, TotalBytesTransferred.LowPart, TotalBytesTransferred.HighPart); Result := PROGRESS_CONTINUE; end; CALLBACK_STREAM_SWITCH: //Max Message begin SendMessage(THandle(lpData), COPY_MAXBYTES, TotalFileSize.LowPart, TotalFileSize.HighPart); Result := PROGRESS_CONTINUE; end; else Result := PROGRESS_CONTINUE; //Continue Message end; end;
function CopyExThread(p: PCopyInfo): Integer; var Source: String; Dest: String; Handle: THandle; Cancel : PBool; begin Source := p.Source; Dest := p.Dest; Handle := p.Handle; Cancel := PBOOL(False); if not CopyFileEx(PChar(Source), PChar(Dest), @CopyFileProgress, Pointer(Handle), Cancel, COPY_FILE_FAIL_IF_EXISTS) then begin PostMessage(Handle, CEXM_FAIL, 0 , 0); ShowMessage('중복된 파일이 존재합니다.'); end; Dispose(p); Result := 0; end;
function FormatFileSize(Size: extended): string; begin
//파일사이즈 변환해서 보여주기 if Size = 0 then Result := '0 B' else if Size < 1000 then Result := FormatFloat('0', Size) + ' B' else begin Size := Size / 1024; if (Size < 1000) then Result := FormatFloat('0.0', Size) + ' KB' else begin Size := Size / 1024; if (Size < 1000) then Result := FormatFloat('0.00', Size) + ' MB' else begin Size := Size / 1024; if (Size < 1000) then Result := FormatFloat('0.00', Size) + ' GB' else begin Size := Size / 1024; if (Size < 1024) then Result := FormatFloat('0.00', Size) + ' TB'; end; end; end; end; end;
사용방법
type
TForm1 = class(TForm)
..
Label1 : TLabel;
ProgressBar : TProgressBar;
procedure btnDownLoadClick(Sender: TObject);
private
public
procedure WndProc(var Msg: TMessage); override;
end;
procedure TForm1.WndProc(var Msg: TMessage); begin inherited;
case Msg.Msg of COPY_MAXBYTES: begin ProgressBar.Max := (Int64(Msg.LParam) shl 32) + Msg.WParam;
ProgressBar.Visible := True; end; COPY_CONTINUE: begin Progressbar.Position := (Int64(Msg.LParam) shl 32) + Msg.WParam; Label1.Caption := '복사 중 : ' + FormatFileSize(Msg.WParam + Msg.LParam);
if ProgressBar.Max <= ProgressBar.Position then begin
ShowMessage('복사 완료!'); ProgressBar.Visible := False;
end; end; COPY_CANCEL: begin
ShowMessage('복사 취소!');
ProgressBar.Visible := False;
end; COPY_FAIL: begin
ShowMessage('복사 실패!'); ProgressBar.Visible := False;
end; end; end;
procedure TForm1.btnDownLoadClick(Sender: TObject); var CopyInfo : PCopyInfo; ThreadID : Cardinal; begin bCancel := False;
New(CopyInfo); CopyInfo.Source := '원본파일 경로'; CopyInfo.Dest := '저장파일 경로'; CopyInfo.Handle := Handle; CloseHandle(BeginThread(nil, 0, @CopyExThread, CopyInfo, 0, ThreadID)); end;