bolaseal
asked on
Winsock - Downloading Binary File
Hello, does anyone know how to download a binary file in Delphi using Winsock? Thanks.
ASKER
This is just needed for downloading a GIF file. I'm pretty sure that this can be done by using Winsock to send a GET request, but I'm not sure how to receive back the data as binary data?
If you are download an image using an http get request, the image will come down in binary format. If you don't believe me, just try it. Personally, I suggest you use Indy TIdHTTP component, or the Window WinInet API functions, like this example: http://delphi.about.com/library/weekly/aa013001a.htm
The WinINet function reference is online at http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wininet/wininet/wininet_reference.asp.
The ms WinInet interface has function for ftp also. Indy has a separate ftp component.
If you don't want to use one of these methods (for http, etc), or a similar high level approach it must be because you want to learn how to do everything. In which case, get the RFC on http and dive in.
The WinINet function reference is online at http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wininet/wininet/wininet_reference.asp.
The ms WinInet interface has function for ftp also. Indy has a separate ftp component.
If you don't want to use one of these methods (for http, etc), or a similar high level approach it must be because you want to learn how to do everything. In which case, get the RFC on http and dive in.
ASKER
I know that the image comes in a binary format, but in VB you can send the request, then get the content and save it like:
Open strSaveFile For Binary As #1
Put #1, , GetHTTPInfo(alldata, HTTP_Data_Data)
Close #1
or something similar, but if this is not possible in Delphi then I will use INet...
Open strSaveFile For Binary As #1
Put #1, , GetHTTPInfo(alldata, HTTP_Data_Data)
Close #1
or something similar, but if this is not possible in Delphi then I will use INet...
ok do this..
Stick a button on your form
under the [ win32 ] tab k...
Stick a progress bar on your form
Function DownloadBFile(P: Pointer): Longint; Stdcall;
Const
CrLf: String = #$0d+#$0a;
Var
Fn: String;
F: File;
GetOut: Boolean;
WSAData: TWSAData;
hp: phostent;
a: tsockaddr;
IpAddress,Buffer: String;
Ts,Bs,Br,ContentLength,I: Integer;
MySock: TSocket;
Begin
Fn:=String(P^);
// ShowMessage('Attempting To Download File '+Fn);
WSAStartup($0101, WSAData);
mysock := socket(AF_INET, SOCK_stream, ipproto_tcp);
hp := gethostbyname('www.homepages.ihug.com.au');
Sleep(40);
if hp = nil then
begin
// ShowMessage('Could Not Resolve Name...');
exit;
end
else
begin
for i := 0 to hp^.h_length - 1 do
IPAddress:=IpAddress+IntTo Str(Ord(Hp .h_addr_li st^[i]))+' .';
SetLength(IPAddress,Length (IPaddress )-1);
end;
a.sin_family := AF_INET;
a.sin_port := htons(80);
A.sin_addr.S_addr:=inet_ad dr(Pchar(I pAddress)) ;
I:=connect(mysock, a, sizeof(a));
buffer:='GET /~cjdelphi/'+fn+' HTTP/1.0'+CrLF+'Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, application/msword, */*'+CrLF+'Accept-Language : en-au'+CrLF+'Accept-Encodi ng: gzip, deflate'+CrLF+'User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)'+CrLF+'Host: '+IpAddress+CrLF+'Cache-Co ntrol: no-cache'+CrLf+'Connection : Close'+CrLF+Crlf;
I:=send(mysock, Buffer[1], Length(buffer), 0);
Sleep(30);
System.Assign(F,'c:\ymlite aplha.gif' ); // your image to view
System.Rewrite(F,1);
ContentLength:=0;
SetLength(Buffer,5048);
FillChar(Buffer[1],Sizeof( Buffer),#0 );
BS:=recv(mysock, buffer[1], 5048,0);
If (BS=Socket_Error) Or (BS=0) Then
Exit;
TS:=0;
BS:=0;
If (Copy(Buffer,1,15)='HTTP/1 .1 200 OK') or (Copy(Buffer,1,15)='HTTP/1 .0 200 OK') Then
Begin
Delete(Buffer,1,Pos('Conte nt-Length: ',Buffer)+ 15);
ContentLength:=StrToInt(Co py(Buffer, 1,Pos(#$0d +#$0a,Buff er)-1));
Delete(Buffer,1,pos(#$0d+# $0a+#$0d+# $0a,Buffer )+3);
Form1.ProgressBar1.Max:=Co ntentLengt h div 1024;
If Trim(Buffer)<>'' Then
Begin
TS:=TS+Length(Buffer);
BlockWrite(F,Buffer[1],Len gth(Buffer ));
SetLength(Buffer,5048);
End;
End
else
Exit;
Repeat
SetLength(Buffer,5049);
BS:=recv(mysock, buffer[1], 5048,0);
TS:=TS+Bs;
Form1.ProgressBar1.Positio n:=TS div 1024;
BlockWrite(F,Buffer[1],BS) ;
Until (BS=0) OR (Socket_Error=BS) Or (GetOut=True);
System.Close(F);
// 'Finished Downloading File!';
End;
Add that as a normal function
//some button click
Var
Th: Thandle;
begin
F:='ymlitealpha.gif'; //test image i uploaded
CreateThread(Nil,0,@Downlo adBFile,@F ,0,Th);
End;
Whent the bar gets to the other end, look for c:\ymliteaplha.gif and open it, it should show a picture of my yahoo chat client i am developing...
Stick a button on your form
under the [ win32 ] tab k...
Stick a progress bar on your form
Function DownloadBFile(P: Pointer): Longint; Stdcall;
Const
CrLf: String = #$0d+#$0a;
Var
Fn: String;
F: File;
GetOut: Boolean;
WSAData: TWSAData;
hp: phostent;
a: tsockaddr;
IpAddress,Buffer: String;
Ts,Bs,Br,ContentLength,I: Integer;
MySock: TSocket;
Begin
Fn:=String(P^);
// ShowMessage('Attempting To Download File '+Fn);
WSAStartup($0101, WSAData);
mysock := socket(AF_INET, SOCK_stream, ipproto_tcp);
hp := gethostbyname('www.homepages.ihug.com.au');
Sleep(40);
if hp = nil then
begin
// ShowMessage('Could Not Resolve Name...');
exit;
end
else
begin
for i := 0 to hp^.h_length - 1 do
IPAddress:=IpAddress+IntTo
SetLength(IPAddress,Length
end;
a.sin_family := AF_INET;
a.sin_port := htons(80);
A.sin_addr.S_addr:=inet_ad
I:=connect(mysock, a, sizeof(a));
buffer:='GET /~cjdelphi/'+fn+' HTTP/1.0'+CrLF+'Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, application/msword, */*'+CrLF+'Accept-Language
I:=send(mysock, Buffer[1], Length(buffer), 0);
Sleep(30);
System.Assign(F,'c:\ymlite
System.Rewrite(F,1);
ContentLength:=0;
SetLength(Buffer,5048);
FillChar(Buffer[1],Sizeof(
BS:=recv(mysock, buffer[1], 5048,0);
If (BS=Socket_Error) Or (BS=0) Then
Exit;
TS:=0;
BS:=0;
If (Copy(Buffer,1,15)='HTTP/1
Begin
Delete(Buffer,1,Pos('Conte
ContentLength:=StrToInt(Co
Delete(Buffer,1,pos(#$0d+#
Form1.ProgressBar1.Max:=Co
If Trim(Buffer)<>'' Then
Begin
TS:=TS+Length(Buffer);
BlockWrite(F,Buffer[1],Len
SetLength(Buffer,5048);
End;
End
else
Exit;
Repeat
SetLength(Buffer,5049);
BS:=recv(mysock, buffer[1], 5048,0);
TS:=TS+Bs;
Form1.ProgressBar1.Positio
BlockWrite(F,Buffer[1],BS)
Until (BS=0) OR (Socket_Error=BS) Or (GetOut=True);
System.Close(F);
// 'Finished Downloading File!';
End;
Add that as a normal function
//some button click
Var
Th: Thandle;
begin
F:='ymlitealpha.gif'; //test image i uploaded
CreateThread(Nil,0,@Downlo
End;
Whent the bar gets to the other end, look for c:\ymliteaplha.gif and open it, it should show a picture of my yahoo chat client i am developing...
before someone comments that CloseSocket(MySock); is not in there, feel free to add it at the very end BUT the reason why i did not was simple, i told the webserver to close the connection after it finishes sending the file, but sure put it in after it closes of the file.
Hello
Try this function
uses URLMon;
function DownloadFile(SourceFile, DestFile: string): Boolean;
begin
try
Result := UrlDownloadToFile(nil, PChar(SourceFile), PChar(DestFile), 0,nil) = 0;
except
Result := False;
end;
end;
procedure TForm1.Button2Click(Sender : TObject);
begin
if DownloadFile('http://www.google.com/images/logo.gif'
,'c:\pic.gif') then
ShowMessage('Done')
else
ShowMessage('Errod downloading the file');
end;
Regards,
Mohammed
Try this function
uses URLMon;
function DownloadFile(SourceFile, DestFile: string): Boolean;
begin
try
Result := UrlDownloadToFile(nil, PChar(SourceFile), PChar(DestFile), 0,nil) = 0;
except
Result := False;
end;
end;
procedure TForm1.Button2Click(Sender
begin
if DownloadFile('http://www.google.com/images/logo.gif'
,'c:\pic.gif') then
ShowMessage('Done')
else
ShowMessage('Errod downloading the file');
end;
Regards,
Mohammed
ASKER
Oh, I forgot to mention...downloading from the cache is unacceptable.
look at the code i posted :|
buffer:='GET /~cjdelphi/'+fn+' HTTP/1.0'+CrLF+'Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, application/msword, */*'+CrLF+'Accept-Language : en-au'+CrLF+'Accept-Encodi ng: gzip, deflate'+CrLF+'User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)'+CrLF+'Host: '+IpAddress+CrLF+'Cache-Co ntrol: no-cache'+CrLf+'Connection : Close'+CrLF+Crlf
'Cache-Control: no-cache'+CrLf+
THAT EXPLICITLY SAYS NO CACHE that's how the webbrowsers do it.
oh well i guess you not actually tested the code then.
buffer:='GET /~cjdelphi/'+fn+' HTTP/1.0'+CrLF+'Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, application/msword, */*'+CrLF+'Accept-Language
'Cache-Control: no-cache'+CrLf+
THAT EXPLICITLY SAYS NO CACHE that's how the webbrowsers do it.
oh well i guess you not actually tested the code then.
ASKER
I tried it, but it came up with several errors about:
TWSAData
phostent
and a few others.
TWSAData
phostent
and a few others.
then at the top of the screen add uses Winsock;
jeez, if i spend all that time writing out code for it just to be ignored like that, why do i bother....
just added Winsock to the uses clause.
jeez, if i spend all that time writing out code for it just to be ignored like that, why do i bother....
just added Winsock to the uses clause.
function GetPage(URL: string): string;
var
NetHandle: HINTERNET;
UrlHandle: HINTERNET;
Buffer: array[0..1024] of Char;
BytesRead: DWORD;
begin
Result := '';
NetHandle := InternetOpen('MyWebbrowser Name', INTERNET_OPEN_TYPE_PRECONF IG, nil, nil, 0);
if Assigned(NetHandle) then
begin
UrlHandle := InternetOpenUrl(NetHandle, PChar(Url),
nil, 0, INTERNET_FLAG_RELOAD, 0);
if Assigned(UrlHandle) then
begin
FillChar(Buffer, SizeOf(Buffer), 0);
repeat
Result := Result + Buffer;
FillChar(Buffer, SizeOf(Buffer), 0);
InternetReadFile(UrlHandle , @Buffer, SizeOf(Buffer),
BytesRead);
until BytesRead = 0;
InternetCloseHandle(UrlHan dle);
end
else
begin
raise Exception.CreateFmt('Error while connecting with %s', [Url]);
end;
InternetCloseHandle(NetHan dle);
end
else raise Exception.Create('WinINET init error');
end;
...
Data := GetURL('www.blah.com/image.gif');
var
NetHandle: HINTERNET;
UrlHandle: HINTERNET;
Buffer: array[0..1024] of Char;
BytesRead: DWORD;
begin
Result := '';
NetHandle := InternetOpen('MyWebbrowser
if Assigned(NetHandle) then
begin
UrlHandle := InternetOpenUrl(NetHandle,
nil, 0, INTERNET_FLAG_RELOAD, 0);
if Assigned(UrlHandle) then
begin
FillChar(Buffer, SizeOf(Buffer), 0);
repeat
Result := Result + Buffer;
FillChar(Buffer, SizeOf(Buffer), 0);
InternetReadFile(UrlHandle
BytesRead);
until BytesRead = 0;
InternetCloseHandle(UrlHan
end
else
begin
raise Exception.CreateFmt('Error
end;
InternetCloseHandle(NetHan
end
else raise Exception.Create('WinINET init error');
end;
...
Data := GetURL('www.blah.com/image.gif');
ASKER
Ok, I tried your code again tobjectpascal and it gives me this error:
I:=connect(mysock, a, sizeof(a));
Incompatible types: 'TSockAddrIn' and 'PSockAddr'
I:=connect(mysock, a, sizeof(a));
Incompatible types: 'TSockAddrIn' and 'PSockAddr'
What version of Delphi you using?
I just compiled it succesfully under Delphi 2,3 and Delphi 5..
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,Winsock,
ComCtrls, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
ProgressBar1: TProgressBar;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
F: String;
implementation
{$R *.DFM}
Function DownloadBFile(P: Pointer): Longint; Stdcall;
Const
CrLf: String = #$0d+#$0a;
Var
Fn: String;
F: File;
GetOut: Boolean;
WSAData: TWSAData;
hp: phostent;
a: tsockaddr;
IpAddress,Buffer: String;
Ts,Bs,Br,ContentLength,I: Integer;
MySock: TSocket;
Begin
Fn:=String(P^);
// ShowMessage('Attempting To Download File '+Fn);
WSAStartup($0101, WSAData);
mysock := socket(AF_INET, SOCK_stream, ipproto_tcp);
hp := gethostbyname('www.homepages.ihug.com.au');
Sleep(40);
if hp = nil then
begin
// ShowMessage('Could Not Resolve Name...');
exit;
end
else
begin
for i := 0 to hp^.h_length - 1 do
IPAddress:=IpAddress+IntTo Str(Ord(Hp .h_addr_li st^[i]))+' .';
SetLength(IPAddress,Length (IPaddress )-1);
end;
a.sin_family := AF_INET;
a.sin_port := htons(80);
A.sin_addr.S_addr:=inet_ad dr(Pchar(I pAddress)) ;
I:=connect(mysock, a, sizeof(a));
buffer:='GET /~cjdelphi/'+fn+' HTTP/1.0'+CrLF+'Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, application/msword, */*'+CrLF+'Accept-Language : en-au'+CrLF+'Accept-Encodi ng: gzip, deflate'+CrLF+'User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)'+CrLF+'Host: '+IpAddress+CrLF+'Cache-Co ntrol: no-cache'+CrLf+'Connection : Close'+CrLF+Crlf;
I:=send(mysock, Buffer[1], Length(buffer), 0);
Sleep(30);
System.Assign(F,'c:\ymlite aplha.gif' ); // your image to view
System.Rewrite(F,1);
ContentLength:=0;
SetLength(Buffer,5048);
FillChar(Buffer[1],Sizeof( Buffer),#0 );
BS:=recv(mysock, buffer[1], 5048,0);
If (BS=Socket_Error) Or (BS=0) Then
Exit;
TS:=0;
BS:=0;
If (Copy(Buffer,1,15)='HTTP/1 .1 200 OK') or (Copy(Buffer,1,15)='HTTP/1 .0 200 OK') Then
Begin
Delete(Buffer,1,Pos('Conte nt-Length: ',Buffer)+ 15);
ContentLength:=StrToInt(Co py(Buffer, 1,Pos(#$0d +#$0a,Buff er)-1));
Delete(Buffer,1,pos(#$0d+# $0a+#$0d+# $0a,Buffer )+3);
Form1.ProgressBar1.Max:=Co ntentLengt h div 1024;
If Trim(Buffer)<>'' Then
Begin
TS:=TS+Length(Buffer);
BlockWrite(F,Buffer[1],Len gth(Buffer ));
SetLength(Buffer,5048);
End;
End
else
Exit;
Repeat
SetLength(Buffer,5049);
BS:=recv(mysock, buffer[1], 5048,0);
TS:=TS+Bs;
Form1.ProgressBar1.Positio n:=TS div 1024;
BlockWrite(F,Buffer[1],BS) ;
Until (BS=0) OR (Socket_Error=BS) Or (GetOut=True);
System.Close(F);
// 'Finished Downloading File!';
End;
procedure TForm1.Button1Click(Sender : TObject);
Var
Th: Thandle;
begin
F:='ymlitealpha.gif'; //test image i uploaded
CreateThread(Nil,0,@Downlo adBFile,@F ,0,Th);
end;
end.
I just compiled it succesfully under Delphi 2,3 and Delphi 5..
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,Winsock,
ComCtrls, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
ProgressBar1: TProgressBar;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
F: String;
implementation
{$R *.DFM}
Function DownloadBFile(P: Pointer): Longint; Stdcall;
Const
CrLf: String = #$0d+#$0a;
Var
Fn: String;
F: File;
GetOut: Boolean;
WSAData: TWSAData;
hp: phostent;
a: tsockaddr;
IpAddress,Buffer: String;
Ts,Bs,Br,ContentLength,I: Integer;
MySock: TSocket;
Begin
Fn:=String(P^);
// ShowMessage('Attempting To Download File '+Fn);
WSAStartup($0101, WSAData);
mysock := socket(AF_INET, SOCK_stream, ipproto_tcp);
hp := gethostbyname('www.homepages.ihug.com.au');
Sleep(40);
if hp = nil then
begin
// ShowMessage('Could Not Resolve Name...');
exit;
end
else
begin
for i := 0 to hp^.h_length - 1 do
IPAddress:=IpAddress+IntTo
SetLength(IPAddress,Length
end;
a.sin_family := AF_INET;
a.sin_port := htons(80);
A.sin_addr.S_addr:=inet_ad
I:=connect(mysock, a, sizeof(a));
buffer:='GET /~cjdelphi/'+fn+' HTTP/1.0'+CrLF+'Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, application/msword, */*'+CrLF+'Accept-Language
I:=send(mysock, Buffer[1], Length(buffer), 0);
Sleep(30);
System.Assign(F,'c:\ymlite
System.Rewrite(F,1);
ContentLength:=0;
SetLength(Buffer,5048);
FillChar(Buffer[1],Sizeof(
BS:=recv(mysock, buffer[1], 5048,0);
If (BS=Socket_Error) Or (BS=0) Then
Exit;
TS:=0;
BS:=0;
If (Copy(Buffer,1,15)='HTTP/1
Begin
Delete(Buffer,1,Pos('Conte
ContentLength:=StrToInt(Co
Delete(Buffer,1,pos(#$0d+#
Form1.ProgressBar1.Max:=Co
If Trim(Buffer)<>'' Then
Begin
TS:=TS+Length(Buffer);
BlockWrite(F,Buffer[1],Len
SetLength(Buffer,5048);
End;
End
else
Exit;
Repeat
SetLength(Buffer,5049);
BS:=recv(mysock, buffer[1], 5048,0);
TS:=TS+Bs;
Form1.ProgressBar1.Positio
BlockWrite(F,Buffer[1],BS)
Until (BS=0) OR (Socket_Error=BS) Or (GetOut=True);
System.Close(F);
// 'Finished Downloading File!';
End;
procedure TForm1.Button1Click(Sender
Var
Th: Thandle;
begin
F:='ymlitealpha.gif'; //test image i uploaded
CreateThread(Nil,0,@Downlo
end;
end.
ASKER
7
ASKER
Maybe it's a different version of the Winsock.pas file?
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Thanks tuqui, I tried that and it works well.
Also thanks tobjectpascal, but that code still didn't work... I give you points anyway for helping :)
Also thanks tobjectpascal, but that code still didn't work... I give you points anyway for helping :)
after changing that line what was the error message? look there's only 1 error IT CAN BE FIXED i just need to know which Version of Delphi you're using.
ASKER
It's Delphi 7, and after changing that line it was the same error as before:
Incompatible types: 'TSockAddrIn' and 'PSockAddr'
Incompatible types: 'TSockAddrIn' and 'PSockAddr'
i have Delphi 7 trial, i will install it in a bit, i can't see how it's a problem.
but with D7, you also have TClientSocket/TcpSocket which will do the job fine.
but with D7, you also have TClientSocket/TcpSocket which will do the job fine.
The socket interface itself is inherently binary, but to get file semantics, you need to recreate something similar to ftp. If you are using Delphi, I would recommend you consider a higher level component than the raw Winsock interface. The Indy components are a good choice for many programmers, primarily because they are free, include source, reasonable quality and support is available.
For example, Delphi 6 includes a sample client / server pair based on the Indy components (bundled with D6) named TCPStreamClient in Demos/Indy (assuming you've loaded the demos). You might also want to look at some of the Indy demos at http://www.atozed.com/indy/Demos/Indy10.iwp, in particular the Intro TCP Client should be quite educational.
If you are asking how you could download a file from a web server (for example), a more specific answer is possible. -- Of course, if all you want to do is download a file from a webserver (using winsock), it probably make more sense to use one of the higher level services available for http downloads such as using the Indy TIdHTTP component's get(url) or microsoft's api, etc.