/////////////////////////////////////////////////////////// // EiEdit // // Редактор части ресурсов Проклятых Земель // // Copyright (C) 2002 Gipat Group // // Распространяется на условиях // // Gipat Group's opened EI-editor-utility license // // версии 1.0 // // // // www.gipatgroup.org // /////////////////////////////////////////////////////////// //К работе над данным файлом приложили руки, ноги.... короче аффтары: // 1) Sagrer (sagrer@yandex.ru) //////////////////////////////////////////////////////////////////////// unit CopyFileUnit; interface uses Windows, messages, KOL, ComCtrls; type RFileCopyInfo = record CopyFrom : string; CopyTo : string; UseBar : boolean; Result : boolean; end; LongRec = packed record //Стянуто из SysUtils case Integer of 0: (Lo, Hi: Word); 1: (Words: array [0..1] of Word); 2: (Bytes: array [0..3] of Byte); end; var BarMax, BarPos, BarMaxThr, BarPosThr, BarPosOld, BarMaxOld : int64; FileCopyThread : PThread; CopySynMethod : TThreadMethod; FileCopyInfo : RFileCopyInfo; BarUpdated, BarUpdatedThr, BarReseted, BarResetedThr : boolean; Function FileCopyThr(const CopyFrom, CopyTo : string; UseBar : boolean): boolean; Function FileCopy(Dummy:Pointer; Sender: PThread): Integer; Procedure CopySyn; //Function PathMinusDir(const Path : string) : string; function FileGetDate(Handle: Integer): Integer; //Стянуто из SysUtils function FileSetDate(Handle: Integer; Age: Integer): Integer; //Стянуто из SysUtils Function VCLCopyFile(const CopyFrom, CopyTo : string; DoReplace, UseBar : boolean; PointToBar : TProgressBar) : boolean; implementation const RazmBuf: Longint = 8192; var FileOldStream, FileNewStream : PStream; function FileGetDate(Handle: Integer): Integer; //Функа взята из SysUtils {$IFDEF MSWINDOWS} var FileTime, LocalFileTime: TFileTime; begin if GetFileTime(THandle(Handle), nil, nil, @FileTime) and FileTimeToLocalFileTime(FileTime, LocalFileTime) and FileTimeToDosDateTime(LocalFileTime, LongRec(Result).Hi, LongRec(Result).Lo) then Exit; Result := -1; end; {$ENDIF} {$IFDEF LINUX} var st: TStatBuf; begin if fstat(Handle, st) = 0 then Result := st.st_mtime else Result := -1; end; {$ENDIF} function FileSetDate(Handle: Integer; Age: Integer): Integer; //Функа взята из SysUtils var LocalFileTime, FileTime: TFileTime; begin Result := 0; if DosDateTimeToFileTime(LongRec(Age).Hi, LongRec(Age).Lo, LocalFileTime) and LocalFileTimeToFileTime(LocalFileTime, FileTime) and SetFileTime(Handle, nil, nil, @FileTime) then Exit; Result := GetLastError; end; Function VCLCopyFile(const CopyFrom, CopyTo : string; DoReplace, UseBar : boolean; PointToBar : TProgressBar) : boolean; begin //Собсно начальная функа для копирования. Result := false; //Типа по умолчанию провал... //Теперь - проверить, надо ли удалить старую версию конечного файла. If FileExists(CopyTo) = true then begin If DoReplace = true then begin DeleteFile(PChar(CopyTo)); end; end; //Теперь - подготовить поток, ну и остальную инфу... If UseBar = true then begin //Настройка бара... PointToBar.Position := 0; PointToBar.Max := 1; BarPosOld := 0; BarMaxOld := 1; end; FileCopyInfo.CopyFrom := CopyFrom; FileCopyInfo.CopyTo := CopyTo; FileCopyInfo.UseBar := UseBar; FileCopyThread := NewThread; FileCopyThread.AutoFree := true; FileCopyThread.OnExecute := TOnThreadExecute(MakeMethod(nil, @FileCopy)); //Теперь - собсно запускать поток, копировать и обновлять бар. FileCopyThread.Resume; repeat If BarMaxOld <> BarMax then begin PointToBar.Max := BarMax; PointToBar.Position := BarPos; BarPosOld := BarPos; BarMaxOld := BarMax; end else begin If BarPosOld < BarPos then begin BarPosOld := BarPos; PointToBar.Position := BarPos; end; end; Applet.ProcessMessages; until WaitForSingleObject(FileCopyThread.Handle,0) <> Wait_Timeout; end; Function FileCopy(Dummy:Pointer; Sender: PThread): Integer; var CopyFrom : string; CopyTo : string; UseBar : boolean; begin //Готовлю инфу. Чтоб процедура собсно в потоке, не лезла в запись //с инфой. CopyFrom := FileCopyInfo.CopyFrom; CopyTo := FileCopyInfo.CopyTo; UseBar := FileCopyInfo.UseBar; //Готовлю синхр-метод CopySynMethod := TThreadMethod(MakeMethod(nil,@CopySyn)); FileCopyInfo.Result := FileCopyThr(CopyFrom,CopyTo,UseBar); Result := 1; end; Procedure CopySyn; begin BarMax := BarMaxThr; BarPos := BarPosThr; end; Function FileCopyThr(const CopyFrom, CopyTo : string; UseBar : boolean): boolean; var BytesCopied : int64; CopyBuffer : pointer; sch : integer; begin //Собсно копирование файла в потоке. //Выделить память под буффер... GetMem(CopyBuffer,RazmBuf); try try FileNewStream := NewWriteFileStream(CopyTo); //На запись FileOldStream := NewReadFileStream(CopyFrom); //На чтение //Подготовить переменные. sch := 0; Result := false; //BytesCopied := 0; //TotalCopied := 0; BarPosThr := 0; BarMaxThr := FileOldStream.Size; //Обновить инфу бара. FileCopyThread.Synchronize(CopySynMethod); //начать репит... repeat BytesCopied := FileOldStream.Read(CopyBuffer^,RazmBuf); If BytesCopied = -1 then begin MsgOK('ReAd ErRoR!!!!'); //Ошибка чтения end; //TotallCopied := TotallCopied+BytesCopied; if BytesCopied > 0 then begin //Если чето всеже прочиталось... If (FileNewStream.Write(CopyBuffer^,BytesCopied) <> BytesCopied) then begin //Ошибка записи... MsgOK('WrItE eRrOr!!!'); end; //Если надо - обновить инфу бара. If UseBar = true then begin Sch := Sch+1; BarPosThr := BarPosThr+BytesCopied; If Sch = 100 then begin Sch := 0; //BarUpdatedThr := true; //Обновить инфу бара. FileCopyThread.Synchronize(CopySynMethod); end; end; end; until BytesCopied < RazmBuf; //Скопировать времена файла... FileSetDate(FileNewStream.Handle, FileGetDate(FileOldStream.Handle)); //Скопировать атрибуты файла... SetFileAttributes(PChar(CopyTo),GetFileAttributes(PChar(CopyFrom))); //Типа ок. Result := true; BarPosThr := BarMaxThr; FileCopyThread.Synchronize(CopySynMethod); except Result := false; end; finally //Обязательно убить созданные потоки (закрыть файлы). FileNewStream.Free; FileOldStream.Free; //И освободить выделенную память. FreeMem(CopyBuffer,RazmBuf); end; end; end.