以前从服务器上读取更新信息页面我都是用Clever的组件..
前两天看CNPACK的组件发现TCnInet这个类。
其调用形式非常简单。只是可惜,默认读取代理的方式是读取IE配置。
因此俺给CnInetUtils增加了两行代码,让其有设置UserAgent和Proxy的
功能
=====================================================
{******************************************************************************}
{                       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.