Downloading a file from the Internet while being able to abort the download any time
This works.
var DownloadAbort: boolean;procedure Download(const URL, FileName: string);var hInet: HINTERNET; hURL: HINTERNET; Buffer: array[0..1023] of AnsiChar; BufferLen, amt: cardinal; f: file;const UserAgent = 'Delphi Application'; // Change to whatever you wishbegin DownloadAbort := false; hInet := InternetOpen(PChar(UserAgent), INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0); try hURL := InternetOpenUrl(hInet, PChar(URL), nil, 0, 0, 0); try FileMode := fmOpenWrite; AssignFile(f, FileName); try Rewrite(f, 1); repeat InternetReadFile(hURL, @Buffer, SizeOf(Buffer), BufferLen); BlockWrite(f, Buffer[0], BufferLen, amt); if DownloadAbort then Exit; until BufferLen = 0; finally CloseFile(f); end; finally InternetCloseHandle(hURL); end; finally InternetCloseHandle(hInet); end;end;
In practice, the code above will be part of your thread's Execute
method, and you do not need DownloadAbort
; intead, you check
if Terminated then Exit;
TWinSocketStream
has a timeout. You basically create a blocking socket, and then create a TWinSocketStream using that socket for reading/writing. (sort of like a using a StreamWriter). Then you loop until the connection is closed, the thread is terminated, or you reach the number of expected bytes. There's a WaitForData() which allows you to check for incoming data w/ a timeout, so you're never 'locked' past that timeout value.
You would, though, have to handle the http process yourself. ie, send the 'GET', and then read the response header to determine how many bytes to expect, but thats not too difficult.
Thanks to GrandmasterB, here is the code I've managed to put together: (it's in my thread's Execute block)
var Buffer: array [0..1024 - 1] of Char; SocketStream: TWinSocketStream; RequestString: String; BytesRead: Integer;begin try ClientSocket.Active := true; DownloadedData := ''; FillChar(Buffer, SizeOf(Buffer), #0); if not Terminated then begin // Wait 10 seconds SocketStream := TWinSocketStream.Create(ClientSocket.Socket, 10000); try // Send the request to the webserver RequestString := 'GET /remotedir/remotefile.html HTTP/1.0'#13#10 + 'Host: www.someexamplehost.com'#13#10#13#10; SocketStream.Write(RequestString[1], Length(RequestString)); // We keep waiting for the data for 5 seconds if (not Terminated) and SocketStream.WaitForData(5000) then repeat // We store the data in our buffer BytesRead := SocketStream.Read(Buffer, SizeOf(Buffer)); if BytesRead = 0 then break else DownloadedData := DownloadedData + Buffer; until Terminated or (not SocketStream.WaitForData(2000)); finally // Close the connection SocketStream.Free; if ClientSocket.Active then ClientSocket.Active := false; end; end; except end;
You have to put this to the constructor of the thread:
ClientSocket := TClientSocket.Create(nil); ClientSocket.Host := 'www.someexamplehost.com'; ClientSocket.Port := 80; ClientSocket.ClientType := ctBlocking; inherited Create(false); // CreateSuspended := false;
And this to the desctructor:
ClientSocket.Free; inherited;