使用WinINET通过代理服务器进行连接
要通过WinINET实现通过代理服务器连接,只要在连接前使用InternetSetOptions设置代理的信息即可。
下面的代码可以在登陆代理后直接下载一个文件:
function DownloadURL(AUrl, TargetFileName, ProxyName, ProxyBypass: PChar):
Boolean;
const
BUFFERSIZE = 4096;
var
hSession: HINTERNET;
hService: HINTERNET;
lpBuffer: array[0..BufferSize + 1] of Byte;
BufferLength: DWORD;
dwBytesRead: DWORD;
dwSizeOfRq, Reserved, dwByteToRead: DWORD;
localFile: file;
fsize: DWORD;
begin
Result := False;
{ Initialize the Win32 Internet functions. }
hSession := InternetOpen('MyApp', // Agent
INTERNET_OPEN_TYPE_PRECONFIG, // dwAccessType
PChar(ProxyName), // lpszProxyName (optional)
nil, // lpszProxyBypass (optional)
INTERNET_OPEN_TYPE_PROXY); // dwFlags
//InternetSetOption(hSession, INTERNET_OPTION_PROXY)
{
dwAccessType indicates the client machine's type of access to the
Internet,
with one of the following values:
INTERNET_OPEN_TYPE_DIRECT indicates client does not have to go through a
proxy server to access the Internet
INTERNET_OPEN_TYPE_PROXY indicates client must first pass through a proxy
server
to access the Internet.
INTERNET_OPEN_TYPE_PRECONFIG indicates client program should use whatever
value
is in the Registry to determine the type of
access.
dwFlags allows you to specify two options when the handle is created:
INTERNET_FLAG_OFFLINE indicates that all requests should be satisfied from
the cache.
INTERNET_FLAG_ASYNC indicates that requests should be satisfied using
asynchronous behavior.
}
// hSession := InternetOpen( 'MyApp', INTERNET_OPEN_TYPE_DIRECT, nil, nil, 0);
{ See if the session handle is valid }
if hSession = nil then
begin
ShowMessage('Internet session initialization failed!');
Exit;
end;
// Set options for the internet handle
// InternetSetOption(hSession, INTERNET_OPTION_CONNECT_TIMEOUT,@timeOutMS, sizeOf(timeOutMS));
{
InternetOpenUrl opens a handle to the Internet file using a URL.
The flags indicate that the file will always be read from the Internet
rather
than the cache.
}
hService := InternetOpenUrl(hSession,
PChar(AUrl),
nil,
0,
INTERNET_FLAG_DONT_CACHE or
INTERNET_FLAG_PRAGMA_NOCACHE or
INTERNET_FLAG_RELOAD,
0);
{
INTERNET_FLAG_RELOAD: causes the program to reload the URL even if a copy
exists in the cache.
INTERNET_FLAG_DONT_CACHE: indicates not to cache the file retrieved.
INTERNET_FLAG_RAW_DATA: returns raw data if specified.
For FTP and Gopher, this data will be placed in the appropriate
_FIND_DATA structure.
INTERNET_FLAG_SECURE: is for conducting secure HTTP transactions via
either SSL or PCT.
INTERNET_FLAG_EXISTING_CONNECT: instructs WinInet to attempt to use an
existing connection to the remote server.
}
{ See if the session handle is valid }
if hSession = nil then
begin
ShowMessage('Internet session initialization failed!');
InternetCloseHandle(hService);
Exit;
end;
HttpQueryInfo(hService, HTTP_QUERY_STATUS_CODE or HTTP_QUERY_FLAG_NUMBER,
@dwByteToRead,
dwSizeOfRq, Reserved);
{ if dwByteToRead >= HTTP_STATUS_AMBIGUOUS then
begin
InternetCloseHandle(hService);
ShowMessage('STATUS CODE : ' + IntToStr(filesize));
Exit;
end; }
AssignFile(localFile, TargetFileName);
{$I-}
Rewrite(localFile, 1);
{$I+}
if IOResult <> 0 then
begin
ShowMessage('Cannot create local file');
InternetCloseHandle(hService);
Exit;
end;
BufferLength := BUFFERSIZE;
{
These three variables will store the size of the file,
the size of the HttpQueryInfo content, and the number of bytes read in
total,
}
// determine the length of a file in bytes.
dwByteToRead := 0;
dwSizeOfRq := 4; // BufferLength
Reserved := 0;
{
With this call, an attempt is made to get the file's size.
If the attempt fails, the dwByteToRead variable is set to 0,
and no percentage or total size is displayed when the file is
downloaded.
}
if not HttpQueryInfo(hService,
HTTP_QUERY_CONTENT_LENGTH or HTTP_QUERY_FLAG_NUMBER,
@dwByteToRead,
dwSizeOfRq,
Reserved) then dwByteToRead := 0;
FSize := 0;
BufferLength := BUFFERSIZE;
while (BufferLength > 0) do
begin
// Read data from the hService handle
if not InternetReadFile(hService, @lpBuffer, BUFFERSIZE, BufferLength)
then Break;
if (BufferLength > 0) and (BufferLength <= BUFFERSIZE) then
BlockWrite(localFile, lpBuffer, BufferLength);
fsize := fsize + BufferLength;
// Application.ProcessMessages;
// Check the size of the remaining data. If it is zero, break.
if BufferLength > 0 then Result := True;
end; {while}
CloseFile(localFile);
Result := True;
// Close the Internet handle that the application has opened.
InternetCloseHandle(hService);
end;
procedure TForm1.btn1Click(Sender: TObject);
begin
DownloadURL('http://www.163.com/', 'C:\demo.htm', 'HTTP=HTTP://proxy:8080', nil);
end;
----------------------------------------
{******************************************************************************}
{ CnPack For Delphi/C++Builder }
{ 中国人自己的开放源码第三方开发包 }
{ (C)Copyright 2001-2005 CnPack 开发组 }
{ ------------------------------------ }
{ }
{ 本开发包是开源的自由软件,您可以遵照 CnPack 的发布协议来修 }
{ 改和重新发布这一程序。 }
{ }
{ 发布这一开发包的目的是希望它有用,但没有任何担保。甚至没有 }
{ 适合特定目的而隐含的担保。更详细的情况请参阅 CnPack 发布协议。 }
{ }
{ 您应该已经和开发包一起收到一份 CnPack 发布协议的副本。如果 }
{ 还没有,可访问我们的网站: }
{ }
{ 网站地址: http://www.cnpack.org }
{ 电子邮件:master@cnpack.org }
{ }
{******************************************************************************}
unit CnInetUtils;
{* |<PRE>
================================================================================
* 软件名称:网络通讯组件包
* 单元名称:使WinInet 封装单元
* 单元作者:周劲羽 (zjy@cnpack.org)
* 备 注:定义了 TCnHTTP,使用 WinInet 来读取 HTTP 数据
* 开发平台:PWin2000Pro + Delphi 5.01
* 兼容测试:PWin9X/2000/XP + Delphi 5/6/7 + C++Builder 5/6
* 本 地 化:该单元中的字符串均符合本地化处理方式
* 单元标识:$Id: CnInetUtils.pas,v 1.4 2005/05/27 13:32:42 zjy Exp $
* 修改记录:2003.03.09 V1.0
* 创建单元
================================================================================
|</PRE>}
interface
{$I CnPack.inc}
uses
Windows, SysUtils, Classes, WinInet, Forms, CnCommon;
type
//==============================================================================
// 使用 WinInet 读取 HTTP 文件的类
//==============================================================================
{ TCnInet }
TCnInetProgressEvent = procedure (Sender: TObject; TotalSize, CurrSize: Integer;
var Abort: Boolean) of object;
{* 数据下载进度事件
|<PRE>
Sender - 线程对象
TotalSize - 总字节数,如果为 -1,表示长度未知
CurrSize - 当前完成字节数
Abort - 是否中断
|</PRE>}
TCnURLInfo = record
Protocol: string;
Host: string;
Port: string;
PathName: string;
Username: string;
Password: string;
end;
TCnInet = class
{* 使用 WinInet 读取 HTTP/FTP 文件的类。}
private
hSession: HINTERNET;
FAborted: Boolean;
FGetDataFail: Boolean;
FOnProgress: TCnInetProgressEvent;
FProcMsg: Boolean;
FUserAgent:string;
FProxyServer:string;
FProxyUserName:string;
FProxyPassWord:string;
function ParseURL(URL: string; var Info: TCnURLInfo): Boolean;
protected
procedure DoProgress(TotalSize, CurrSize: Integer);
function InitInet: Boolean;
procedure CloseInet;
function GetStreamFromHandle(Handle: HINTERNET; TotalSize: Integer;
Stream: TStream): Boolean;
function GetHTTPStream(Info: TCnURLInfo; Stream: TStream): Boolean;
function GetFTPStream(Info: TCnURLInfo; Stream: TStream): Boolean;
public
constructor Create;
destructor Destroy; override;
procedure Abort;
{* 中断当前处理}
function GetStream(const AURL: string; Stream: TStream): Boolean;
{* 从 AURL 地址读取数据到流 Stream}
function GetString(const AURL: string): string;
{* 从 AURL 地址返回一个字符串}
function GetFile(const AURL, FileName: string): Boolean;
{* 从 AURL 地址读取数据保存到文件 FileName}
property OnProgress: TCnInetProgressEvent read FOnProgress write FOnProgress;
{* 数据进度事件}
property Aborted: Boolean read FAborted;
{* 是否已被中断}
property GetDataFail: Boolean read FGetDataFail;
{* 上一次的数据读取是否成功}
property ProcMsg: Boolean read FProcMsg write FProcMsg;
{* 设置UserAgent 浏览器识别标示}
property UserAgent: string read FUserAgent write FUserAgent;
{* 代理服务器设置: [协议=][协议://]服务器[:端口] 如 127.0.0.1:8080}
property ProxyServer: string read FProxyServer write FProxyServer;
{* 代理服务器用户名}
property ProxyUserName: string read FProxyUserName write FProxyUserName;
{* 代理服务器用户密码}
property ProxyPassWord: string read FProxyPassWord write FProxyPassWord;
end;
TCnHTTP = class(TCnInet);
TCnFTP = class(TCnInet);
function EncodeURL(URL: string): string;
{* 将 URL 中的特殊字符转换成 %XX 的形式}
implementation
const
csBufferSize = 4096;
function EncodeURL(URL: string): string;
const
UnsafeChars = ['*', '#', '%', '<', '>', '+', ' '];
var
i: Integer;
begin
Result := '';
for i := 1 to Length(URL) do begin
if (URL in UnsafeChars) or (URL >= #$80) or (URL[1] < #32) then
Result := Result + '%' + IntToHex(Ord(URL), 2)
else
Result := Result + URL;
end;
end;
//==============================================================================
// 使用 WinInet 读取 HTTP 文件的类
//==============================================================================
{ TCnInet }
constructor TCnInet.Create;
begin
inherited;
FUserAgent := 'CnPack Internet Utils';
FProcMsg := True;
end;
destructor TCnInet.Destroy;
begin
CloseInet;
inherited;
end;
procedure TCnInet.CloseInet;
begin
if hSession <> nil then
begin
InternetCloseHandle(hSession);
hSession := nil;
end;
end;
function TCnInet.InitInet: Boolean;
begin
if hSession = nil then
begin
if Length(FProxyServer) = 0 then
begin
hSession := InternetOpen(PChar(FUserAgent), INTERNET_OPEN_TYPE_PRECONFIG,
nil, nil, 0);
end else begin
hSession := InternetOpen(PChar(FUserAgent), INTERNET_OPEN_TYPE_PROXY,
PChar(FProxyServer), nil, 0);
if Length(FProxyUserName) > 0 then
InternetSetOption(hSession,INTERNET_OPTION_PROXY_USERNAME,PChar(FProxyUserName),Length(FProxyUserName));
if Length(FProxyPassWord) > 0 then
InternetSetOption(hSession,INTERNET_OPTION_PROXY_PASSWORD,PChar(FProxyPassWord),Length(FProxyPassWord));
end;
end;
Result := hSession <> nil;
end;
procedure TCnInet.Abort;
begin
FAborted := True;
end;
procedure TCnInet.DoProgress(TotalSize, CurrSize: Integer);
begin
if Assigned(FOnProgress) then
FOnProgress(Self, TotalSize, CurrSize, FAborted);
if ProcMsg then
Application.ProcessMessages;
end;
function TCnInet.ParseURL(URL: string; var Info: TCnURLInfo): Boolean;
var
Idx: Integer;
Buff: string;
function ExtractStr(var ASrc: string; ADelim: string;
ADelete: Boolean = True): string;
var
Idx: Integer;
begin
Idx := Pos(ADelim, ASrc);
if Idx = 0 then
begin
Result := ASrc;
if ADelete then
ASrc := '';
end
else
begin
Result := Copy(ASrc, 1, Idx - 1);
if ADelete then
ASrc := Copy(ASrc, Idx + Length(ADelim), MaxInt);
end;
end;
begin
Result := False;
URL := Trim(URL);
Idx := Pos('://', URL);
if Idx > 0 then
begin
Info.Protocol := Copy(URL, 1, Idx - 1);
Delete(URL, 1, Idx + 2);
if URL = '' then Exit;
Buff := ExtractStr(URL, '/');
Idx := Pos('@', Buff);
Info.Password := Copy(Buff, 1, Idx - 1);
if Idx > 0 then Delete(Buff, 1, Idx);
Info.UserName := ExtractStr(Info.Password, ':');
if Length(Info.UserName) = 0 then
Info.Password := '';
Info.Host := ExtractStr(Buff, ':');
Info.Port := Buff;
Info.PathName := URL;
Result := True;
end;
end;
function TCnInet.GetStream(const AURL: string; Stream: TStream): Boolean;
var
Info: TCnURLInfo;
begin
Result := False;
if not ParseURL(AURL, Info) then
Exit;
FAborted := False;
if not InitInet or FAborted then
Exit;
if SameText(Info.Protocol, 'http') then
Result := GetHTTPStream(Info, Stream)
else if SameText(Info.Protocol, 'ftp') then
Result := GetFTPStream(Info, Stream);
if FAborted then
Result := False;
FGetDataFail := not Result;
end;
function TCnInet.GetStreamFromHandle(Handle: HINTERNET; TotalSize: Integer;
Stream: TStream): Boolean;
var
CurrSize, Readed: DWORD;
Buf: array[0..csBufferSize - 1] of Byte;
begin
Result := False;
CurrSize := 0;
Readed := 0;
repeat
if not InternetReadFile(Handle, @Buf, csBufferSize, Readed) then
Exit;
if Readed > 0 then
begin
Stream.Write(Buf, Readed);
Inc(CurrSize, Readed);
DoProgress(TotalSize, CurrSize);
if Aborted then Exit;
end;
until Readed = 0;
Result := True;
end;
function TCnInet.GetFTPStream(Info: TCnURLInfo; Stream: TStream): Boolean;
var
hConnect, hFtp: HINTERNET;
FindData: TWin32FindData;
TotalSize: Integer;
begin
Result := False;
hConnect := nil;
hFtp := nil;
try
hConnect := InternetConnect(hSession, PChar(Info.Host),
StrToIntDef(Info.Port, INTERNET_DEFAULT_FTP_PORT),
PChar(Info.Username), PChar(Info.Password),
INTERNET_SERVICE_FTP, 0, 0);
if (hConnect = nil) or FAborted then
Exit;
hFtp := FtpFindFirstFile(hConnect, PChar(Info.PathName), FindData,
INTERNET_FLAG_NEED_FILE, 0);
if hFtp <> nil then
begin
InternetCloseHandle(hFtp);
TotalSize := FindData.nFileSizeLow;
end
else
TotalSize := -1;
hFtp := FtpOpenFile(hConnect, PChar(Info.PathName), GENERIC_READ,
FTP_TRANSFER_TYPE_BINARY, 0);
if (hFtp = nil) or FAborted then
Exit;
Result := GetStreamFromHandle(hFtp, TotalSize, Stream);
finally
if hFtp <> nil then InternetCloseHandle(hFtp);
if hConnect <> nil then InternetCloseHandle(hConnect);
end;
end;
function TCnInet.GetHTTPStream(Info: TCnURLInfo; Stream: TStream): Boolean;
var
hConnect, hRequest: HINTERNET;
SizeStr: array[0..63] of Char;
BufLen, Index: DWORD;
begin
Result := False;
hConnect := nil;
hRequest := nil;
try
hConnect := InternetConnect(hSession, PChar(Info.Host),
StrToIntDef(Info.Port, INTERNET_DEFAULT_HTTP_PORT), nil, nil,
INTERNET_SERVICE_HTTP, 0, 0);
if (hConnect = nil) or FAborted then
Exit;
hRequest := HttpOpenRequest(hConnect, 'GET', PChar(EncodeURL(Info.PathName)),
'HTTP/1.0', nil, nil, INTERNET_FLAG_RELOAD, 0);
if (hRequest = nil) or FAborted then
Exit;
if HttpSendRequest(hRequest, nil, 0, nil, 0) then
begin
if FAborted then Exit;
FillChar(SizeStr, SizeOf(SizeStr), 0);
BufLen := SizeOf(SizeStr);
Index := 0;
HttpQueryInfo(hRequest, HTTP_QUERY_CONTENT_LENGTH, @SizeStr, BufLen, Index);
if FAborted then Exit;
Result := GetStreamFromHandle(hRequest, StrToIntDef(SizeStr, -1), Stream);
end;
finally
if hRequest <> nil then InternetCloseHandle(hRequest);
if hConnect <> nil then InternetCloseHandle(hConnect);
end;
end;
function TCnInet.GetString(const AURL: string): string;
var
Stream: TMemoryStream;
begin
try
Stream := TMemoryStream.Create;
try
if GetStream(AURL, Stream) then
begin
SetLength(Result, Stream.Size);
Move(Stream.Memory^, PChar(Result)^, Stream.Size);
end
else
Result := '';
finally
Stream.Free;
end;
except
Result := '';
end;
end;
function TCnInet.GetFile(const AURL, FileName: string): Boolean;
var
Stream: TFileStream;
begin
try
Stream := TFileStream.Create(FileName, fmCreate or fmShareDenyWrite);
try
Stream.Size := 0;
Result := GetStream(AURL, Stream);
finally
Stream.Free;
end;
except
Result := False;
end;
end;
end.