/////////////////////////////////////// // Purpose: FTP Component // Project: Unleash.dpk // Copyright (c) 2001 by hjb // unit Ftp1;{------------------------------------------------------------------------------ This is an FTP component that supports file transfers to and from a server. You can also delete files, add and remove directories, and of course query the machine to see what files are on it. The original version used GetFile and SendFile1, and return a list of files with FindFiles. This version uses GetFile2 and SendFile2, and returns a list of TFileInfo records via the FindFileRecs method. I've also added OnTransfer and OnStatus events. The OnTransfer event notifies you of the progress a file transfer is making, in 1024 byte increments (FileChunkSize). OnStatus just shows how to do the callbacks, but I don't really do much with that feature. if you call GetFile though, you will get incremental feedback on the file transfer at what appears to be 4096 byte boundaries. The advantage of the first version is that it is very easy to use. The advantage of the second version is it lets you build a nicer user interface with better control over the details. ----- ----- ----- ----- Via the Version 1 system, you might Respond to OnNewDir events as follows: procedure TForm1.FTP1NewDir(Sender: TObject); begin ListBox1.Items := MyFtp1.FindFiles; // Get the directory list end;------------------------------------------------------------------------------}interfaceuses Windows, Classes, WinINet,SysUtils;const FileChunkSize = 1024; ContextNum = 255; CR = #13#10; MaxStrLen = 250;type PFileInfo = ^TFileInfo; TFileInfo = record Attribute:PChar; FileName: PChar; FileSize: Int64; FileTime: TDateTime; end; PFileNameDate=^TFileNameDate; TFileNameDate=record FName:PCHAR; FCreateDate:TFiletime; FAccessDate:TFiletime; FWriteDate:TFiletime; end; FtpException = class(Exception); TStatusEvent = procedure(Sender: TObject; Context: DWord;Status: string; Info: Pointer; StatLen: DWord) of object; TTransferEvent =procedure(Sender: TObject; BytesSent: Integer;TotalSent: Int64) of Object; TCCFtp = class(TComponent) private FContext: Integer; FINet: HInternet; FFtpHandle: HInternet; FCurFiles: TStringList; FFileList: TList; FFileDateList:TList; FServer: string; FOnNewDir: TNotifyEvent; FOnStatus: TStatusEvent; FOnTransfer: TTransferEvent; FCurDir: string; FUserID: string; FPassword: string; function GetCurrentDirectory: string; procedure SetUpNewDir; procedure EmptyList(var L: TList); procedure EmptyList1(var L: TList); public function BackOneDir: Boolean; constructor Create(AOwner: TComponent); override; procedure Connect(AppName: string); function CustomToFileName(S: string): string; function ChangeDirExact(S: string): Boolean; function ChangeDirCustom(S: string): Boolean; procedure CreateDirectory(S: string); procedure DeleteFile(S: string); procedure DeleteDirectory(S: string); destructor Destroy; override; function FindFileRecs: TList; function FindFileDate:Tlist; // function FindFiles: TStringList; function GetFile(FTPFile, NewFile: string): Boolean; function GetFile2(FTPFile: string; NewFile: string): Boolean; function SendFile1(FTPFile, NewFile: string): Boolean; function SendFile2(RemoteFile, LocalFile: string): Boolean; published property CurFiles: TStringList read FCurFiles; property CurDir: string read FCurDir; property OnNewDir: TNotifyEvent read FOnNewDir write FOnNewDir; property OnStatus: TStatusEvent read FOnStatus write FOnStatus; property OnTransfer: TTransferEvent read FOnTransfer write FOnTransfer; property Password: string read FPassword write FPassword; property Server: string read FServer write FServer; property UserID: string read FUserID write FUserID; end;procedure Register;implementationuses Dialogs; var Instance: TCCFtp;procedure Register; begin RegisterComponents('Unleash', [TCCFtp]); end;function ReverseStr(S: string): string; var Len: Integer; Temp: String; i,j: Integer; begin Len := StrLen(PChar(S)); // Length returns allocation, not length SetLength(Temp, Len); j := Len; for i := 1 to Len do begin Temp[i] := S[j]; dec(j); end; ReverseStr := Temp; end;function StripLastToken(S: string; Token: Char): string; var Temp: string; Index: INteger; begin S := ReverseStr(S); Index := Pos(Token, S); Inc(Index); Temp := Copy(S, Index, Length(S) - (Index - 1)); StripLastToken := ReverseStr(Temp); end;
function GetFirstToken(S: string; Token: Char): string; var Temp: string; Index: INteger; begin Index := Pos(Token, S); if Index < 1 then begin GetFirstToken := ''; Exit; end; Dec(Index); SetLength(Temp, Index); Move(S[1], Temp[1], Index); GetFirstToken := Temp; end;function GetDots(NumDots: Integer): string; var S: string; i: Integer; begin S := ''; for i := 1 to NumDots do S := S + ' '; Result := S; end;function GetFindDataRec(FindData: TWin32FindData): PFileInfo; var S: string; LocalFileTime: TFileTime; DosTime: Integer; FileInfo: PFileInfo; FileSize1: Int64; begin GetMem(FileInfo, SizeOf(TFileInfo)); case FindData.dwFileAttributes of FILE_ATTRIBUTE_ARCHIVE: S := 'A'; FILE_ATTRIBUTE_COMPRESSED: S := 'C'; FILE_ATTRIBUTE_DIRECTORY: S := 'D'; FILE_ATTRIBUTE_HIDDEN: S := 'H'; FILE_ATTRIBUTE_NORMAL: S := 'N'; FILE_ATTRIBUTE_READONLY: S := 'R'; FILE_ATTRIBUTE_SYSTEM: S := 'S'; FILE_ATTRIBUTE_TEMPORARY: S := 'T'; else S := IntToStr(FindData.dwFileAttributes); end; GetMem(FileInfo.Attribute, Length(S) + 1); StrCopy(FileInfo.Attribute, PChar(S)); GetMem(FileInfo.FileName, StrLen(FindData.CFileName) + 1); StrCopy(FileInfo^.FileName, FindData.CFileName); Int64Rec(FileSize1).Lo := FindData.nFileSizeLow; Int64Rec(FileSize1).Hi := FindData.nFileSizeHigh; FileInfo^.FileSize:=FileSize1; if FileTimeToLocalFileTime(FindData.ftLastWriteTime, LocalFileTime) then FileTimeToDosDateTime(LocalFileTime, LongRec(DosTime).Hi,LongRec(DosTime).Lo); FileInfo^.FileTime := FileDateToDateTime(DosTime); Result := FileInfo; end;function GetFindDataDate(FindData: TWin32FindData): PFileNameDate; var // S: string; // LocalFileTime: TFileTime; // DosTime: Integer; FileInfo: PFileNameDate; // FileSize1: Int64; begin GetMem(FileInfo, SizeOf(TFileNameDate)); { case FindData.dwFileAttributes of FILE_ATTRIBUTE_ARCHIVE: S := 'A'; FILE_ATTRIBUTE_COMPRESSED: S := 'C'; FILE_ATTRIBUTE_DIRECTORY: S := 'D'; FILE_ATTRIBUTE_HIDDEN: S := 'H'; FILE_ATTRIBUTE_NORMAL: S := 'N'; FILE_ATTRIBUTE_READONLY: S := 'R'; FILE_ATTRIBUTE_SYSTEM: S := 'S'; FILE_ATTRIBUTE_TEMPORARY: S := 'T'; else S := IntToStr(FindData.dwFileAttributes); end; } // GetMem(FileInfo.Attribute, Length(S) + 1); //StrCopy(FileInfo.Attribute, PChar(S)); GetMem(FileInfo.FName, StrLen(FindData.CFileName) + 1); StrCopy(FileInfo^.FName, FindData.CFileName); // FileInfo^.FName:=string(FindData.CFileName); // Int64Rec(FileSize1).Lo := FindData.nFileSizeLow; // Int64Rec(FileSize1).Hi := FindData.nFileSizeHigh; // FileInfo^.FileSize:=FileSize1; // if FileTimeToLocalFileTime(FindData.ftLastWriteTime, LocalFileTime) then // FileTimeToDosDateTime(LocalFileTime, LongRec(DosTime).Hi, // LongRec(DosTime).Lo); // FileInfo^.FileTime := FileDateToDateTime(DosTime); FileInfo^.FWriteDate:=FindData.ftLastWriteTime; FileInfo^.FCreateDate:=FindData.ftCreationTime ; FileInfo^.FAccessDate:=FindData.ftLastAccessTime; Result := FileInfo; end;function GetFindDataStr(FindData: TWin32FindData): string; var S: string; Temp: string; LocalFileTime: TFileTime; DosTime: Integer; DateTime: TDateTime; FileTimeStr: string; FileSize: Int64; begin case FindData.dwFileAttributes of FILE_ATTRIBUTE_ARCHIVE: S := 'A'; FILE_ATTRIBUTE_COMPRESSED: S := 'C'; FILE_ATTRIBUTE_DIRECTORY: S := 'D'; FILE_ATTRIBUTE_HIDDEN: S := 'H'; FILE_ATTRIBUTE_NORMAL: S := 'N'; FILE_ATTRIBUTE_READONLY: S := 'R'; FILE_ATTRIBUTE_SYSTEM: S := 'S'; FILE_ATTRIBUTE_TEMPORARY: S := 'T'; else S := IntToStr(FindData.dwFileAttributes); end; S := S + GetDots(75); Move(FindData.CFilename[0], S[6], StrLen(FindData.CFileName)); Int64Rec(FileSize).Lo := FindData.nFileSizeLow; Int64Rec(FileSize).Hi := FindData.nFileSizeHigh; Temp := IntToStr(FileSize); Move(Temp[1], S[25], Length(Temp)); FileTimeToLocalFileTime(FindData.ftLastWriteTime, LocalFileTime); FileTimeToDosDateTime(LocalFileTime, LongRec(DosTime).Hi,LongRec(DosTime).Lo); DateTime := FileDateToDateTime(DosTime); FileTimeStr := DateTimeToStr(DateTime); Move(FileTimeStr[1], S[45], Length(FileTimeStr)); Result := S; end;procedure MyCallBack(Handle: HInternet; Context: DWord; Status: DWord; Info: Pointer; StatLen: DWord); stdcall; var S: string; begin case Status of INTERNET_STATUS_RESOLVING_NAME: S := 'Resolving'; INTERNET_STATUS_NAME_RESOLVED: S := 'Resolved'; INTERNET_STATUS_CONNECTING_TO_SERVER: S := 'Connecting to server'; INTERNET_STATUS_CONNECTED_TO_SERVER: S:= 'Connected'; INTERNET_STATUS_SENDING_REQUEST: S := 'Sending Request'; INTERNET_STATUS_REQUEST_SENT: S := 'Request sent'; INTERNET_STATUS_RECEIVING_RESPONSE: S := 'Receiving response'; INTERNET_STATUS_RESPONSE_RECEIVED: S := 'Response received'; INTERNET_STATUS_CTL_RESPONSE_RECEIVED: S := 'CTL Response received'; INTERNET_STATUS_PREFETCH: S := 'Prefetch'; INTERNET_STATUS_CLOSING_CONNECTION: S := 'Closing connection'; INTERNET_STATUS_CONNECTION_CLOSED: S := 'Connection closed'; INTERNET_STATUS_HANDLE_CREATED: S := 'Handle created'; INTERNET_STATUS_HANDLE_CLOSING: S := 'Handle closing'; INTERNET_STATUS_REQUEST_COMPLETE: S := 'Request complete'; INTERNET_STATUS_REDIRECT: S := 'Status redirect'; INTERNET_STATUS_INTERMEDIATE_RESPONSE: S := 'Intermediate response'; INTERNET_STATUS_STATE_CHANGE: S := 'State change'; else S := 'Unknown status'; end; if Assigned(Instance) then if Assigned (Instance.OnStatus) then Instance.OnStatus(Instance, Context, S, Info, StatLen); end;{--- TCCFTP -----------------------------------------------------------------} function TCCFtp.BackOneDir: Boolean; var S: string; begin S := FCurDir; S := StripLastToken(S, '/'); if S = '/' then begin Result := False; Exit; end; if S <> '' then begin ChangeDirExact(S); Result := True; end else begin ChangeDirExact('/'); Result := True; end; end;// Changes to specific directory in S function TCCFtp.ChangeDirExact(S: string): Boolean; begin if S <> '' then FtpSetCurrentDirectory(FFTPHandle, PChar(S)); Result := True; FindFiles; SetUpNewDir; end;// Assumes S has been returned by GetFindDataString; function TCCFtp.ChangeDirCustom(S: string): Boolean; begin S := CustomToFileName(S); if S <> '' then FtpSetCurrentDirectory(FFTPHandle, PChar(S)); Result := True; FindFiles; SetUpNewDir; end;
procedure TCCFtp.Connect(AppName: string); var S: string; begin FContext := ContextNum; FINet := InternetOpen(PChar(AppName), 0, nil, nil, 0); FftpHandle := InternetConnect(FINet, PChar(FServer), 0,PChar(FUserID), PChar(FPassWord), Internet_Service_Ftp, 0, FContext); if FFtpHandle = nil then begin S := 'Connection failed' + CR + 'Server: ' + FServer + CR + 'UserID: ' + FUserID + CR + 'Password: ' + FPassword; raise Exception.Create(S) end else begin SetUpNewDir; end; end;constructor TCCFtp.Create(AOwner: TComponent); begin inherited Create(AOwner); FCurFiles := TStringList.Create; FFileList := TList.Create; FFileDateList:=TList.Create ; Instance := Self; end;procedure TCCFtp.CreateDirectory(S: string); begin if not FtpCreateDirectory(FFtpHandle, PChar(S)) then raise FtpException.Create('Could not create directory'); end;function TCCFtp.CustomToFileName(S: string): string; const PreSize = 6; var Temp: string; TempSize: Integer; begin Temp := ''; TempSize := Length(S) - PreSize; SetLength(Temp, TempSize); Move(S[PreSize], Temp[1], TempSize); Temp := GetFirstToken(Temp, ' '); Result := Temp; end;procedure TCCFtp.DeleteDirectory(S: string); begin if not FtpRemoveDirectory(FFtpHandle, PChar(S)) then raise Exception.Create('Could not remove directory'); end;procedure TCCFtp.DeleteFile(S: string); begin if not FtpDeleteFile(FFtpHandle, PChar(S)) then raise FtpException.Create('Could not delete file'); end;destructor TCCFtp.Destroy; begin EmptyList(FFileList); FFileList.Free; EmptyList1(FFileDateList); FFileDateList.FREE; if FINet <> nil then InternetCloseHandle(FINet); if FFtpHandle <> nil then InternetCloseHandle(FFtpHandle); Instance := nil; inherited Destroy; end;procedure TCCFtp.EmptyList1(var L: TList); var i: integer; Item: PFileNameDate; begin for i := 0 to L.Count - 1 do begin Item := L.Items[i]; if Item.FName <> nil then FreeMem(Item.FName, StrLen(Item.FName) + 1); FreeMem(Item, SizeOf(Item)); end; L.Clear; end;procedure TCCFtp.EmptyList(var L: TList); var i: integer; Item: PFileInfo; begin for i := 0 to L.Count - 1 do begin Item := L.Items[i]; if Item.Attribute <> nil then FreeMem(Item.Attribute, StrLen(Item.Attribute) + 1); if Item.FileName <> nil then FreeMem(Item.FileName, StrLen(Item.FileName) + 1); FreeMem(Item, SizeOf(Item)); end; L.Clear; end;function TCCFtp.FindFileRecs: TList; var FindData: TWin32FindData; FindHandle: HInternet; begin FindHandle := FtpFindFirstFile(FFtphandle, '*.*', FindData, 0, 0); EmptyList(FFileList); if FindHandle <> nil then begin FFileList.Add(GetFindDataRec(FindData)); while InternetFindnextFile(FindHandle, @FindData) do FFileList.Add(GetFindDataRec(FindData)); InternetCloseHandle(Findhandle); GetCurrentDirectory; end; Result := FFileList; end;function TCCFtp.FindFileDate: TList; var FindData: TWin32FindData; FindHandle: HInternet; begin FindHandle := FtpFindFirstFile(FFtphandle, '*.*', FindData, 0, 0); EmptyList(FFileDateList); // FFileDateList:TList; if FindHandle <> nil then begin FFileDateList.Add(GetFindDataDate(FindData)); while InternetFindnextFile(FindHandle, @FindData) do FFileDateList.Add(GetFindDataDate(FindData)); InternetCloseHandle(Findhandle); GetCurrentDirectory; end; Result :=FFileDateList; end; function TCCFtp.FindFiles: TStringList; var FindData: TWin32FindData; FindHandle: HInternet; begin FCurFiles.Clear; FindHandle := FtpFindFirstFile(FFtphandle, '*.*', FindData, 0, 0); if FindHandle <> nil then begin FCurFiles.Add(GetFindDataStr(FindData)); while InternetFindnextFile(FindHandle, @FindData) do FCurFiles.Add(GetFindDataStr(FindData)); InternetCloseHandle(Findhandle); GetCurrentDirectory; end; Result := FCurFiles; end;function TCCFtp.GetCurrentDirectory: string; var Len: DWord; S: string; begin Len := 0; ftpGetCurrentDirectory(FFTPHandle, PChar(S), Len); SetLength(S, Len); ftpGetCurrentDirectory(FFTPHandle, PChar(S), Len); Result := S; end;function TCCFtp.GetFile(FTPFile, NewFile: string): Boolean; var P: Pointer; begin P := InternetSetStatusCallback(FFtpHandle, @MyCallBack); if P = Pointer(INTERNET_INVALID_STATUS_CALLBACK) then ShowMessage('No callback'); Result := FtpGetFile(FFTPHandle, PChar(FTPFile), PChar(NewFile), False, File_Attribute_Normal, Ftp_Transfer_Type_Binary, ContextNum); if Result = False then raise FtpException.Create('Copy Failed: ' + FtpFile); InternetSetStatusCallBack(FFtpHandle, nil); end;function TCCFtp.GetFile2(FTPFile: string; NewFile: string): Boolean; const BufSize = FileChunkSize; var FHandle: HInternet; Buffer: Pointer; NumRead: Cardinal; FileStream: TFileStream; TotalSent: Int64; begin TotalSent := 0; FileStream := TFileStream.Create(NewFile, fmCreate); FHandle := FtpOpenFile(FFTPHandle, PChar(FTPFile), GENERIC_READ,FTP_TRANSFER_TYPE_BINARY, 0); GetMem(Buffer, BufSize); if FHandle <> nil then begin repeat InternetReadFile(FHandle, Buffer, Bufsize, NumRead); if NumRead > 0 then FileStream.Write(Buffer^, NumRead); if Assigned(FOnTransfer) then begin TotalSent := TotalSent + NumRead; FOnTransfer(Self, NumRead, TotalSent); end; until NumRead < BufSize; end else ShowMessage('ÏÂÔØÎļþʧ°Ü'); InternetCloseHandle(FHandle); FreeMem(Buffer, BufSize); FileStream.Free; Result := True; end;procedure TCCFtp.SetUpNewDir; begin FCurDir := GetCurrentDirectory; if Assigned(FOnNewDir) then FOnNewDir(Self); end;function TCCFtp.SendFile1(FTPFile, NewFile: string): Boolean; const Size:DWord = 3000; var Transfer: Bool; Error: DWord; S: string; begin Transfer := FtpPutFile(FFTPHandle, PChar(FTPFile), PChar(NewFile), Ftp_Transfer_Type_Binary, 0); if not Transfer then begin Error := GetLastError; ShowMessage(Format('Error Number: %d. Hex: %x', [Error, Error])); SetLength(S, Size); if not InternetGetLastResponseInfo(Error, PChar(S), Size) then begin Error := GetLastError; ShowMessage(Format('Error Number: %d. Hex: %x', [Error, Error])); end; ShowMessage(Format('Error Number: %d. Hex: %x Info: %s', [Error, Error, S])); end else ShowMessage('Success'); Result := Transfer; end;function TCCFtp.SendFile2(RemoteFile, LocalFile: string): Boolean; const BufSize = FileChunkSize; var FHandle: HInternet; Buffer: Pointer; NumWritten, NumRead: Cardinal; FileStream: TFileStream; TotalSent: Int64; begin TotalSent := 0; GetMem(Buffer, BufSize); FileStream := TFileStream.Create(LocalFile, fmOpenRead); FHandle := FtpOpenFile(FFTPHandle, PChar(RemoteFile), GENERIC_WRITE, FTP_TRANSFER_TYPE_BINARY, 0); if FHandle <> nil then begin repeat NumRead := FileStream.Read(Buffer^, BufSize); if NumRead > 0 then InternetWriteFile(FHandle, Buffer, NumRead, NumWritten); if Assigned(FOnTransfer) then begin TotalSent := TotalSent + NumWritten; FOnTransfer(Self, NumWritten, TotalSent); end; until NumRead < BufSize; InternetCloseHandle(FHandle) end else ShowMessage('Failed'); Result := True; FileStream.Free; FreeMem(Buffer, BufSize); end;end.
unit FtpFile;interfaceuses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,Ftp1,Buttons, ExtCtrls; type TFtpFile= class(TObject) private { Private declarations } FOnGetFtpFile: TNotifyEvent; public { Public declarations } CCFtp1: TCCFtp; ListFileName:TStringList; ListFileAttr:TStringList; ListFileSize:TStringlist; ListFileDate:TStringlist; constructor Create(AOwner: TComponent); destructor Destroy; override; procedure Connect(Server:string;UserID:string;PassWord:string); procedure MyFtp1NewDir(Sender: TObject); published property OnGetFtpFile: TNotifyEvent read FOnGetFtpFile write FOnGetFtpFile; end;implementationprocedure TFtpFile.Connect(Server:string;UserID:string;PassWord:string); begin Application.ProcessMessages; Screen.Cursor := crHourGlass; CCFtp1.Server :=Server; CCFtp1.UserID :=UserID; CCFtp1.Password :=Password; CCFTP1.Connect(Application.ExeName); Screen.Cursor := crDefault; end;procedure TFtpFile.MyFtp1NewDir(Sender: TObject); var L: TList; i: Integer; FileInfo: PFileInfo; begin ListFileName.Clear; ListFileAttr.Clear; ListFileSize.Clear; ListFileDate.Clear; L := CCFTP1.FindFileRecs; for i := 0 to L.Count - 1 do begin FileInfo := L.Items[i]; ListFileName.Add(FileInfo.FileName); ListFileAttr.Add(FileInfo.Attribute); ListFileSize.Add(IntToStr(FileInfo.FileSize)); ListFileDate.Add(DateTimeToStr(FileInfo.FileTime)); end; if Assigned(FOnGetFtpFile) then FOnGetFtpFile(Self); end;constructor TFtpFile.Create(AOwner: TComponent); begin CCFtp1:=TCCFtp.Create(AOwner); CCFtp1.OnNewDir :=MyFtp1NewDir; ListFileName:=TStringList.Create ; ListFileAttr:=TStringList.Create; ListFileSize:=TStringlist.Create; ListFileDate:=TStringlist.Create; end;destructor TFtpFile.Destroy; begin CCFtp1.free; ListFileName.Free; ListFileAttr.Free; ListFileSize.Free; ListFileDate.Free; end;end.
// Purpose: FTP Component
// Project: Unleash.dpk
// Copyright (c) 2001 by hjb
//
unit Ftp1;{------------------------------------------------------------------------------
This is an FTP component that supports file transfers to and from a server.
You can also delete files, add and remove directories, and of course
query the machine to see what files are on it. The original version used GetFile and SendFile1, and return a list of
files with FindFiles. This version uses GetFile2 and SendFile2, and
returns a list of TFileInfo records via the FindFileRecs method. I've also added OnTransfer and OnStatus events. The OnTransfer event
notifies you of the progress a file transfer is making, in 1024 byte
increments (FileChunkSize). OnStatus just shows how to do the
callbacks, but I don't really do much with that feature. if you call
GetFile though, you will get incremental feedback on the file transfer
at what appears to be 4096 byte boundaries. The advantage of the first version is that it is very easy to use. The
advantage of the second version is it lets you build a nicer user
interface with better control over the details. ----- ----- ----- ----- Via the Version 1 system, you might Respond to OnNewDir events as follows: procedure TForm1.FTP1NewDir(Sender: TObject);
begin
ListBox1.Items := MyFtp1.FindFiles; // Get the directory list
end;------------------------------------------------------------------------------}interfaceuses
Windows, Classes, WinINet,SysUtils;const
FileChunkSize = 1024;
ContextNum = 255;
CR = #13#10;
MaxStrLen = 250;type
PFileInfo = ^TFileInfo;
TFileInfo = record
Attribute:PChar;
FileName: PChar;
FileSize: Int64;
FileTime: TDateTime;
end; PFileNameDate=^TFileNameDate;
TFileNameDate=record
FName:PCHAR;
FCreateDate:TFiletime;
FAccessDate:TFiletime;
FWriteDate:TFiletime;
end; FtpException = class(Exception);
TStatusEvent = procedure(Sender: TObject; Context: DWord;Status: string; Info: Pointer; StatLen: DWord) of object;
TTransferEvent =procedure(Sender: TObject; BytesSent: Integer;TotalSent: Int64) of Object; TCCFtp = class(TComponent)
private
FContext: Integer;
FINet: HInternet;
FFtpHandle: HInternet;
FCurFiles: TStringList;
FFileList: TList;
FFileDateList:TList;
FServer: string;
FOnNewDir: TNotifyEvent;
FOnStatus: TStatusEvent;
FOnTransfer: TTransferEvent;
FCurDir: string;
FUserID: string;
FPassword: string;
function GetCurrentDirectory: string;
procedure SetUpNewDir;
procedure EmptyList(var L: TList);
procedure EmptyList1(var L: TList);
public
function BackOneDir: Boolean;
constructor Create(AOwner: TComponent); override;
procedure Connect(AppName: string);
function CustomToFileName(S: string): string;
function ChangeDirExact(S: string): Boolean;
function ChangeDirCustom(S: string): Boolean;
procedure CreateDirectory(S: string);
procedure DeleteFile(S: string);
procedure DeleteDirectory(S: string);
destructor Destroy; override;
function FindFileRecs: TList;
function FindFileDate:Tlist; //
function FindFiles: TStringList;
function GetFile(FTPFile, NewFile: string): Boolean;
function GetFile2(FTPFile: string; NewFile: string): Boolean;
function SendFile1(FTPFile, NewFile: string): Boolean;
function SendFile2(RemoteFile, LocalFile: string): Boolean;
published
property CurFiles: TStringList read FCurFiles;
property CurDir: string read FCurDir;
property OnNewDir: TNotifyEvent read FOnNewDir write FOnNewDir;
property OnStatus: TStatusEvent read FOnStatus write FOnStatus;
property OnTransfer: TTransferEvent read FOnTransfer write FOnTransfer;
property Password: string read FPassword write FPassword;
property Server: string read FServer write FServer;
property UserID: string read FUserID write FUserID;
end;procedure Register;implementationuses
Dialogs;
var
Instance: TCCFtp;procedure Register;
begin
RegisterComponents('Unleash', [TCCFtp]);
end;function ReverseStr(S: string): string;
var
Len: Integer;
Temp: String;
i,j: Integer;
begin
Len := StrLen(PChar(S)); // Length returns allocation, not length
SetLength(Temp, Len);
j := Len;
for i := 1 to Len do begin
Temp[i] := S[j];
dec(j);
end;
ReverseStr := Temp;
end;function StripLastToken(S: string; Token: Char): string;
var
Temp: string;
Index: INteger;
begin
S := ReverseStr(S);
Index := Pos(Token, S);
Inc(Index);
Temp := Copy(S, Index, Length(S) - (Index - 1));
StripLastToken := ReverseStr(Temp);
end;
var
Temp: string;
Index: INteger;
begin
Index := Pos(Token, S);
if Index < 1 then begin
GetFirstToken := '';
Exit;
end;
Dec(Index);
SetLength(Temp, Index);
Move(S[1], Temp[1], Index);
GetFirstToken := Temp;
end;function GetDots(NumDots: Integer): string;
var
S: string;
i: Integer;
begin
S := '';
for i := 1 to NumDots do S := S + ' ';
Result := S;
end;function GetFindDataRec(FindData: TWin32FindData): PFileInfo;
var
S: string;
LocalFileTime: TFileTime;
DosTime: Integer;
FileInfo: PFileInfo;
FileSize1: Int64;
begin
GetMem(FileInfo, SizeOf(TFileInfo));
case FindData.dwFileAttributes of
FILE_ATTRIBUTE_ARCHIVE: S := 'A';
FILE_ATTRIBUTE_COMPRESSED: S := 'C';
FILE_ATTRIBUTE_DIRECTORY: S := 'D';
FILE_ATTRIBUTE_HIDDEN: S := 'H';
FILE_ATTRIBUTE_NORMAL: S := 'N';
FILE_ATTRIBUTE_READONLY: S := 'R';
FILE_ATTRIBUTE_SYSTEM: S := 'S';
FILE_ATTRIBUTE_TEMPORARY: S := 'T';
else
S := IntToStr(FindData.dwFileAttributes);
end;
GetMem(FileInfo.Attribute, Length(S) + 1);
StrCopy(FileInfo.Attribute, PChar(S));
GetMem(FileInfo.FileName, StrLen(FindData.CFileName) + 1);
StrCopy(FileInfo^.FileName, FindData.CFileName);
Int64Rec(FileSize1).Lo := FindData.nFileSizeLow;
Int64Rec(FileSize1).Hi := FindData.nFileSizeHigh;
FileInfo^.FileSize:=FileSize1; if FileTimeToLocalFileTime(FindData.ftLastWriteTime, LocalFileTime) then
FileTimeToDosDateTime(LocalFileTime, LongRec(DosTime).Hi,LongRec(DosTime).Lo);
FileInfo^.FileTime := FileDateToDateTime(DosTime);
Result := FileInfo;
end;function GetFindDataDate(FindData: TWin32FindData): PFileNameDate;
var
// S: string;
// LocalFileTime: TFileTime;
// DosTime: Integer;
FileInfo: PFileNameDate;
// FileSize1: Int64;
begin
GetMem(FileInfo, SizeOf(TFileNameDate));
{ case FindData.dwFileAttributes of
FILE_ATTRIBUTE_ARCHIVE: S := 'A';
FILE_ATTRIBUTE_COMPRESSED: S := 'C';
FILE_ATTRIBUTE_DIRECTORY: S := 'D';
FILE_ATTRIBUTE_HIDDEN: S := 'H';
FILE_ATTRIBUTE_NORMAL: S := 'N';
FILE_ATTRIBUTE_READONLY: S := 'R';
FILE_ATTRIBUTE_SYSTEM: S := 'S';
FILE_ATTRIBUTE_TEMPORARY: S := 'T';
else
S := IntToStr(FindData.dwFileAttributes);
end; }
// GetMem(FileInfo.Attribute, Length(S) + 1);
//StrCopy(FileInfo.Attribute, PChar(S));
GetMem(FileInfo.FName, StrLen(FindData.CFileName) + 1);
StrCopy(FileInfo^.FName, FindData.CFileName);
// FileInfo^.FName:=string(FindData.CFileName);
// Int64Rec(FileSize1).Lo := FindData.nFileSizeLow;
// Int64Rec(FileSize1).Hi := FindData.nFileSizeHigh;
// FileInfo^.FileSize:=FileSize1;
// if FileTimeToLocalFileTime(FindData.ftLastWriteTime, LocalFileTime) then
// FileTimeToDosDateTime(LocalFileTime, LongRec(DosTime).Hi,
// LongRec(DosTime).Lo);
// FileInfo^.FileTime := FileDateToDateTime(DosTime);
FileInfo^.FWriteDate:=FindData.ftLastWriteTime;
FileInfo^.FCreateDate:=FindData.ftCreationTime ;
FileInfo^.FAccessDate:=FindData.ftLastAccessTime;
Result := FileInfo;
end;function GetFindDataStr(FindData: TWin32FindData): string;
var
S: string;
Temp: string;
LocalFileTime: TFileTime;
DosTime: Integer;
DateTime: TDateTime;
FileTimeStr: string;
FileSize: Int64;
begin
case FindData.dwFileAttributes of
FILE_ATTRIBUTE_ARCHIVE: S := 'A';
FILE_ATTRIBUTE_COMPRESSED: S := 'C';
FILE_ATTRIBUTE_DIRECTORY: S := 'D';
FILE_ATTRIBUTE_HIDDEN: S := 'H';
FILE_ATTRIBUTE_NORMAL: S := 'N';
FILE_ATTRIBUTE_READONLY: S := 'R';
FILE_ATTRIBUTE_SYSTEM: S := 'S';
FILE_ATTRIBUTE_TEMPORARY: S := 'T';
else
S := IntToStr(FindData.dwFileAttributes);
end;
S := S + GetDots(75);
Move(FindData.CFilename[0], S[6], StrLen(FindData.CFileName));
Int64Rec(FileSize).Lo := FindData.nFileSizeLow;
Int64Rec(FileSize).Hi := FindData.nFileSizeHigh;
Temp := IntToStr(FileSize);
Move(Temp[1], S[25], Length(Temp));
FileTimeToLocalFileTime(FindData.ftLastWriteTime, LocalFileTime);
FileTimeToDosDateTime(LocalFileTime, LongRec(DosTime).Hi,LongRec(DosTime).Lo);
DateTime := FileDateToDateTime(DosTime);
FileTimeStr := DateTimeToStr(DateTime);
Move(FileTimeStr[1], S[45], Length(FileTimeStr));
Result := S;
end;procedure MyCallBack(Handle: HInternet; Context: DWord; Status: DWord; Info: Pointer; StatLen: DWord); stdcall;
var
S: string;
begin
case Status of
INTERNET_STATUS_RESOLVING_NAME: S := 'Resolving';
INTERNET_STATUS_NAME_RESOLVED: S := 'Resolved';
INTERNET_STATUS_CONNECTING_TO_SERVER: S := 'Connecting to server';
INTERNET_STATUS_CONNECTED_TO_SERVER: S:= 'Connected';
INTERNET_STATUS_SENDING_REQUEST: S := 'Sending Request';
INTERNET_STATUS_REQUEST_SENT: S := 'Request sent';
INTERNET_STATUS_RECEIVING_RESPONSE: S := 'Receiving response';
INTERNET_STATUS_RESPONSE_RECEIVED: S := 'Response received';
INTERNET_STATUS_CTL_RESPONSE_RECEIVED: S := 'CTL Response received';
INTERNET_STATUS_PREFETCH: S := 'Prefetch';
INTERNET_STATUS_CLOSING_CONNECTION: S := 'Closing connection';
INTERNET_STATUS_CONNECTION_CLOSED: S := 'Connection closed';
INTERNET_STATUS_HANDLE_CREATED: S := 'Handle created';
INTERNET_STATUS_HANDLE_CLOSING: S := 'Handle closing';
INTERNET_STATUS_REQUEST_COMPLETE: S := 'Request complete';
INTERNET_STATUS_REDIRECT: S := 'Status redirect';
INTERNET_STATUS_INTERMEDIATE_RESPONSE: S := 'Intermediate response';
INTERNET_STATUS_STATE_CHANGE: S := 'State change';
else
S := 'Unknown status';
end;
if Assigned(Instance) then
if Assigned (Instance.OnStatus) then Instance.OnStatus(Instance, Context, S, Info, StatLen);
end;{--- TCCFTP -----------------------------------------------------------------}
function TCCFtp.BackOneDir: Boolean;
var
S: string;
begin
S := FCurDir;
S := StripLastToken(S, '/');
if S = '/' then begin
Result := False;
Exit;
end;
if S <> '' then begin
ChangeDirExact(S);
Result := True;
end else begin
ChangeDirExact('/');
Result := True;
end;
end;// Changes to specific directory in S
function TCCFtp.ChangeDirExact(S: string): Boolean;
begin
if S <> '' then FtpSetCurrentDirectory(FFTPHandle, PChar(S));
Result := True;
FindFiles;
SetUpNewDir;
end;// Assumes S has been returned by GetFindDataString;
function TCCFtp.ChangeDirCustom(S: string): Boolean;
begin
S := CustomToFileName(S);
if S <> '' then FtpSetCurrentDirectory(FFTPHandle, PChar(S));
Result := True;
FindFiles;
SetUpNewDir;
end;
var
S: string;
begin
FContext := ContextNum;
FINet := InternetOpen(PChar(AppName), 0, nil, nil, 0);
FftpHandle := InternetConnect(FINet, PChar(FServer), 0,PChar(FUserID), PChar(FPassWord), Internet_Service_Ftp, 0, FContext);
if FFtpHandle = nil then begin
S := 'Connection failed' + CR + 'Server: ' + FServer + CR + 'UserID: ' + FUserID + CR + 'Password: ' + FPassword;
raise Exception.Create(S)
end else begin
SetUpNewDir;
end;
end;constructor TCCFtp.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FCurFiles := TStringList.Create;
FFileList := TList.Create;
FFileDateList:=TList.Create ;
Instance := Self;
end;procedure TCCFtp.CreateDirectory(S: string);
begin
if not FtpCreateDirectory(FFtpHandle, PChar(S)) then
raise FtpException.Create('Could not create directory');
end;function TCCFtp.CustomToFileName(S: string): string;
const
PreSize = 6;
var
Temp: string;
TempSize: Integer;
begin
Temp := '';
TempSize := Length(S) - PreSize;
SetLength(Temp, TempSize);
Move(S[PreSize], Temp[1], TempSize);
Temp := GetFirstToken(Temp, ' ');
Result := Temp;
end;procedure TCCFtp.DeleteDirectory(S: string);
begin
if not FtpRemoveDirectory(FFtpHandle, PChar(S)) then
raise Exception.Create('Could not remove directory');
end;procedure TCCFtp.DeleteFile(S: string);
begin
if not FtpDeleteFile(FFtpHandle, PChar(S)) then
raise FtpException.Create('Could not delete file');
end;destructor TCCFtp.Destroy;
begin
EmptyList(FFileList);
FFileList.Free;
EmptyList1(FFileDateList);
FFileDateList.FREE;
if FINet <> nil then InternetCloseHandle(FINet);
if FFtpHandle <> nil then InternetCloseHandle(FFtpHandle);
Instance := nil;
inherited Destroy;
end;procedure TCCFtp.EmptyList1(var L: TList);
var
i: integer;
Item: PFileNameDate;
begin
for i := 0 to L.Count - 1 do begin
Item := L.Items[i];
if Item.FName <> nil then FreeMem(Item.FName, StrLen(Item.FName) + 1);
FreeMem(Item, SizeOf(Item));
end;
L.Clear;
end;procedure TCCFtp.EmptyList(var L: TList);
var
i: integer;
Item: PFileInfo;
begin
for i := 0 to L.Count - 1 do begin
Item := L.Items[i];
if Item.Attribute <> nil then FreeMem(Item.Attribute, StrLen(Item.Attribute) + 1);
if Item.FileName <> nil then FreeMem(Item.FileName, StrLen(Item.FileName) + 1);
FreeMem(Item, SizeOf(Item));
end;
L.Clear;
end;function TCCFtp.FindFileRecs: TList;
var
FindData: TWin32FindData;
FindHandle: HInternet;
begin
FindHandle := FtpFindFirstFile(FFtphandle, '*.*', FindData, 0, 0);
EmptyList(FFileList);
if FindHandle <> nil then begin
FFileList.Add(GetFindDataRec(FindData));
while InternetFindnextFile(FindHandle, @FindData) do FFileList.Add(GetFindDataRec(FindData));
InternetCloseHandle(Findhandle);
GetCurrentDirectory;
end;
Result := FFileList;
end;function TCCFtp.FindFileDate: TList;
var
FindData: TWin32FindData;
FindHandle: HInternet;
begin
FindHandle := FtpFindFirstFile(FFtphandle, '*.*', FindData, 0, 0);
EmptyList(FFileDateList); // FFileDateList:TList;
if FindHandle <> nil then begin
FFileDateList.Add(GetFindDataDate(FindData));
while InternetFindnextFile(FindHandle, @FindData) do FFileDateList.Add(GetFindDataDate(FindData));
InternetCloseHandle(Findhandle);
GetCurrentDirectory;
end;
Result :=FFileDateList;
end; function TCCFtp.FindFiles: TStringList;
var
FindData: TWin32FindData;
FindHandle: HInternet;
begin
FCurFiles.Clear;
FindHandle := FtpFindFirstFile(FFtphandle, '*.*', FindData, 0, 0);
if FindHandle <> nil then begin
FCurFiles.Add(GetFindDataStr(FindData));
while InternetFindnextFile(FindHandle, @FindData) do
FCurFiles.Add(GetFindDataStr(FindData));
InternetCloseHandle(Findhandle);
GetCurrentDirectory;
end;
Result := FCurFiles;
end;function TCCFtp.GetCurrentDirectory: string;
var
Len: DWord;
S: string;
begin
Len := 0;
ftpGetCurrentDirectory(FFTPHandle, PChar(S), Len);
SetLength(S, Len);
ftpGetCurrentDirectory(FFTPHandle, PChar(S), Len);
Result := S;
end;function TCCFtp.GetFile(FTPFile, NewFile: string): Boolean;
var
P: Pointer;
begin
P := InternetSetStatusCallback(FFtpHandle, @MyCallBack);
if P = Pointer(INTERNET_INVALID_STATUS_CALLBACK) then
ShowMessage('No callback');
Result := FtpGetFile(FFTPHandle, PChar(FTPFile), PChar(NewFile), False, File_Attribute_Normal, Ftp_Transfer_Type_Binary, ContextNum);
if Result = False then
raise FtpException.Create('Copy Failed: ' + FtpFile);
InternetSetStatusCallBack(FFtpHandle, nil);
end;function TCCFtp.GetFile2(FTPFile: string; NewFile: string): Boolean;
const
BufSize = FileChunkSize;
var
FHandle: HInternet;
Buffer: Pointer;
NumRead: Cardinal;
FileStream: TFileStream;
TotalSent: Int64;
begin
TotalSent := 0;
FileStream := TFileStream.Create(NewFile, fmCreate);
FHandle := FtpOpenFile(FFTPHandle, PChar(FTPFile), GENERIC_READ,FTP_TRANSFER_TYPE_BINARY, 0);
GetMem(Buffer, BufSize);
if FHandle <> nil then begin
repeat
InternetReadFile(FHandle, Buffer, Bufsize, NumRead);
if NumRead > 0 then
FileStream.Write(Buffer^, NumRead);
if Assigned(FOnTransfer) then begin
TotalSent := TotalSent + NumRead;
FOnTransfer(Self, NumRead, TotalSent);
end;
until NumRead < BufSize;
end else ShowMessage('ÏÂÔØÎļþʧ°Ü');
InternetCloseHandle(FHandle);
FreeMem(Buffer, BufSize);
FileStream.Free;
Result := True;
end;procedure TCCFtp.SetUpNewDir;
begin
FCurDir := GetCurrentDirectory;
if Assigned(FOnNewDir) then FOnNewDir(Self);
end;function TCCFtp.SendFile1(FTPFile, NewFile: string): Boolean;
const
Size:DWord = 3000;
var
Transfer: Bool;
Error: DWord;
S: string;
begin
Transfer := FtpPutFile(FFTPHandle, PChar(FTPFile), PChar(NewFile), Ftp_Transfer_Type_Binary, 0);
if not Transfer then begin
Error := GetLastError;
ShowMessage(Format('Error Number: %d. Hex: %x', [Error, Error]));
SetLength(S, Size);
if not InternetGetLastResponseInfo(Error, PChar(S), Size) then begin
Error := GetLastError;
ShowMessage(Format('Error Number: %d. Hex: %x', [Error, Error]));
end;
ShowMessage(Format('Error Number: %d. Hex: %x Info: %s', [Error, Error, S]));
end else
ShowMessage('Success');
Result := Transfer;
end;function TCCFtp.SendFile2(RemoteFile, LocalFile: string): Boolean;
const
BufSize = FileChunkSize;
var
FHandle: HInternet;
Buffer: Pointer;
NumWritten, NumRead: Cardinal;
FileStream: TFileStream;
TotalSent: Int64;
begin
TotalSent := 0;
GetMem(Buffer, BufSize);
FileStream := TFileStream.Create(LocalFile, fmOpenRead);
FHandle := FtpOpenFile(FFTPHandle, PChar(RemoteFile), GENERIC_WRITE,
FTP_TRANSFER_TYPE_BINARY, 0);
if FHandle <> nil then begin
repeat
NumRead := FileStream.Read(Buffer^, BufSize);
if NumRead > 0 then InternetWriteFile(FHandle, Buffer, NumRead, NumWritten);
if Assigned(FOnTransfer) then begin
TotalSent := TotalSent + NumWritten;
FOnTransfer(Self, NumWritten, TotalSent);
end;
until NumRead < BufSize;
InternetCloseHandle(FHandle)
end else
ShowMessage('Failed');
Result := True;
FileStream.Free;
FreeMem(Buffer, BufSize);
end;end.
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,Ftp1,Buttons, ExtCtrls;
type
TFtpFile= class(TObject)
private { Private declarations }
FOnGetFtpFile: TNotifyEvent;
public { Public declarations }
CCFtp1: TCCFtp;
ListFileName:TStringList;
ListFileAttr:TStringList;
ListFileSize:TStringlist;
ListFileDate:TStringlist;
constructor Create(AOwner: TComponent);
destructor Destroy; override;
procedure Connect(Server:string;UserID:string;PassWord:string);
procedure MyFtp1NewDir(Sender: TObject);
published
property OnGetFtpFile: TNotifyEvent read FOnGetFtpFile write FOnGetFtpFile;
end;implementationprocedure TFtpFile.Connect(Server:string;UserID:string;PassWord:string);
begin
Application.ProcessMessages;
Screen.Cursor := crHourGlass;
CCFtp1.Server :=Server;
CCFtp1.UserID :=UserID;
CCFtp1.Password :=Password;
CCFTP1.Connect(Application.ExeName);
Screen.Cursor := crDefault;
end;procedure TFtpFile.MyFtp1NewDir(Sender: TObject);
var
L: TList;
i: Integer;
FileInfo: PFileInfo;
begin
ListFileName.Clear;
ListFileAttr.Clear;
ListFileSize.Clear;
ListFileDate.Clear;
L := CCFTP1.FindFileRecs;
for i := 0 to L.Count - 1 do begin
FileInfo := L.Items[i];
ListFileName.Add(FileInfo.FileName);
ListFileAttr.Add(FileInfo.Attribute);
ListFileSize.Add(IntToStr(FileInfo.FileSize));
ListFileDate.Add(DateTimeToStr(FileInfo.FileTime));
end;
if Assigned(FOnGetFtpFile) then FOnGetFtpFile(Self);
end;constructor TFtpFile.Create(AOwner: TComponent);
begin
CCFtp1:=TCCFtp.Create(AOwner);
CCFtp1.OnNewDir :=MyFtp1NewDir;
ListFileName:=TStringList.Create ;
ListFileAttr:=TStringList.Create;
ListFileSize:=TStringlist.Create;
ListFileDate:=TStringlist.Create;
end;destructor TFtpFile.Destroy;
begin
CCFtp1.free;
ListFileName.Free;
ListFileAttr.Free;
ListFileSize.Free;
ListFileDate.Free;
end;end.