问题是这样的:
    有一个远程的URL下载地址列表,如:
    http://www.xxx.com/a.rar
    http://www.xxx.com/b.rar
    http://www.xxx.com/c.rar
    http://www.xxx.com/d.rar
    ......
    保存在一个Tstringlist中的.
    我要把远程的这些文件下载下来,保存到C盘下面的doc目录中(c:\doc)
    目前,远程下载函数已经写好了。我采用多线程下载。
    但前提是,当第一个线程下载完后才执行第二个线程。一直到最后一个线程结束。
    在写个TThread的时候我遇到了问题。
    就是线程不能同步,线程是一起在执行,影响了界面上的进度显示。
    (界面上有两个控件,一个进度条用来显示当前下载文件的进度,一个lable用来显示当前下载文件的字节/当前文件总字节)
    我把我的代码发出来。注意高手能帮我找出问题出在哪里。
    小弟出了送分外,就只有由心的感谢了。
      
    线程单元:
    ///////////////////////////////////////////////////////unit DownThreadUnit;
interfaceuses
  Windows, Messages, SysUtils, Classes, WinInet,extctrls,ComCtrls,Dialogs,
  StdCtrls,Gauges;Type
  DownThread = class(TThread)
  private
    FTAcceptTypes,
    FTAgent,
    FTURL,
    FTFileName,
    FTStringResult,
    FTUserName,
    FTPassword,
    FTPostQuery,
    FTReferer: String;
    FTBinaryData,
    FTUseCache: Boolean;
    
    FTResult: Boolean;    FTFileSize,
    FTPort  : Integer;
    FTToFile: Boolean;
    
    BytesToRead,
    BytesReaded: DWord;
    ProBar   : TGauge;
    pLabel   : TLabel;  protected
    procedure InitProBar;
    procedure ShowProBar;
    procedure DownFiles;
    procedure Execute; override;
  public
    constructor Create(aProBar : TGauge;aLabel : TLabel;RemoteUrl,aSaveFileName:String);
  end;implementationConstructor DownThread.Create(aProBar : TGauge;aLabel : TLabel;RemoteUrl,aSaveFileName:string);
// aProBar 进度条.aLabel 下载字节显示. RemoteUrl 下载地址 . aSaveFileName 保存的文件名
begin  inherited Create(False);
  FTAcceptTypes := '*/*';
  FTAgent := 'Blue Steel Update/1.1';    FTURL := RemoteUrl;                  //下载的URL地址.
    FTUserName := '';                    //用户名.
    FTPassword := '';                    //密码.
    FTPort := 80;                       //端口.
  ProBar := aProBar;
  pLabel := aLabel;
  FTFileName := aSaveFileName;             //保存的文件名.
  FTPostQuery := 'GET';
  FTReferer := '';
  FTBinaryData := False;
  FTUseCache := False;
  FTToFile := True;                     //下载文件.
  FreeOnTerminate := True;
  
end;procedure DownThread.InitProBar;
Begin
  ProBar.Progress := 0;
  ProBar.MinValue := 0;
  ProBar.MaxValue := 100; {文件总大小}
  pLabel.Caption := '0/'+IntTostr(FTFileSize);
End;Procedure DownThread.ShowProBar;
Begin
   ProBar.Progress := Trunc((BytesToRead / FTFileSize)*100);
   ProBar.Update;
   pLabel.Caption  := IntTostr(BytesReaded)+'/'+IntTostr(FTFileSize);
                 {更新下载显示.}
End;procedure DownThread.DownFiles; //下载函数. 
Var
  hSession, hConnect, hRequest: hInternet;
  HostName, FileName: String;
  f: File;
  Buf: Pointer;
  dwBufLen, dwIndex: DWord;
  Data: Array[0..$400] of Char;
  TempStr: String;
  RequestMethod: PChar;
  InternetFlag: DWord;
  TimeOut : Cardinal;
  AcceptType: LPStr;
  
  Procedure ParseURL(URL: String; var HostName, FileName: String);
  Var
    i: Integer;
  Begin
    if Pos('http://', LowerCase(URL)) <> 0 then
      System.Delete(URL, 1, 7);    i := Pos('/', URL);
    HostName := Copy(URL, 1, i);
    FileName := Copy(URL, i, Length(URL) - i + 1);
    if (Length(HostName) > 0) and (HostName[Length(HostName)] = '/') then
      SetLength(HostName, Length(HostName) - 1);
  End;  Procedure CloseHandles;
  begin
   InternetCloseHandle(hRequest);
   InternetCloseHandle(hConnect);
   InternetCloseHandle(hSession);
  end;
begin
  try
    TimeOut := 6000000; 
    ParseURL(FTURL, HostName, FileName);    if Terminated then
    begin
        FTResult := False;
        Exit;
    end;    if FTAgent <> '' then
      hSession := InternetOpen(PChar(FTAgent),
                  INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0)
    else
      hSession := InternetOpen(nil,
                  INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);    hConnect := InternetConnect(hSession, PChar(HostName),
                FTPort, PChar(FTUserName), PChar(FTPassword),
                INTERNET_SERVICE_HTTP, 0, 0);    RequestMethod := PChar(FTPostQuery); // 'GET'    If FTUseCache Then InternetFlag := 0
    Else InternetFlag := INTERNET_FLAG_RELOAD;    AcceptType := PChar('Accept: ' + FTAcceptTypes);
    hRequest := HttpOpenRequest(hConnect, RequestMethod, PChar(FileName), 'HTTP/1.1',
                PChar(FTReferer), @AcceptType, InternetFlag, 0);    InternetSetOption(hRequest, INTERNET_OPTION_CONNECT_TIMEOUT,
                                   @TimeOut, SizeOf(TimeOut));
    InternetSetOption(hRequest, INTERNET_OPTION_DATA_RECEIVE_TIMEOUT,
                                   @TimeOut, SizeOf(TimeOut));
    if FTPostQuery = '' then
      HttpSendRequest(hRequest, nil, 0, nil, 0)
    else
      HttpSendRequest(hRequest, 'Content-Type: application/x-www-form-urlencoded', 47,
                      PChar(FTPostQuery), Length(FTPostQuery));    if Terminated then
     begin
      CloseHandles;
      FTResult := False;
      Exit;
     end;    dwIndex  := 0;
    dwBufLen := 1024;
    GetMem(Buf, dwBufLen);    FTResult := HttpQueryInfo(hRequest, HTTP_QUERY_CONTENT_LENGTH,
                              Buf, dwBufLen, dwIndex);    if Terminated then
     begin
      FreeMem(Buf);
      CloseHandles;
      FTResult := False;
      Exit;
     end;     if FTResult or (not FTBinaryData) then
     begin      IF FTResult then begin
        FTFileSize := StrToInt(StrPas(Buf));
        synchronize(InitProBar);     // 初始化进度条.
      End;      BytesReaded := 0;      If FTToFile then
      Begin
        AssignFile(f, FTFileName);
        Rewrite(f, 1);
      End
      else FTStringResult := '';      while True do
      begin
         IF  not InternetReadFile(hRequest, @Data, SizeOf(Data), BytesToRead) then
           break
         Else
           IF BytesToRead = 0 then   Break
           Else begin
             if FTToFile then begin
                if Not FTResult then exit;
                BlockWrite(f, Data, BytesToRead);
             End
             else begin
               TempStr := Data;
               SetLength(TempStr, BytesToRead);
               FTStringResult := FTStringResult + Data;
             end;
           BytesReaded := BytesReaded + BytesToRead;
           synchronize(ShowProBar);  //显示进度条.
           end;
         End;        if FTToFile then
          FTResult := FTFileSize = Integer(BytesReaded)
        else begin
          SetLength(FTStringResult, BytesReaded);
          FTResult := BytesReaded <> 0;
        end;        if FTToFile then CloseFile(f);    End;   
      FreeMem(Buf);
      CloseHandles;
  Except
    CloseHandles;
  End;
  inherited Destroy;end;procedure DownThread.Execute;
Begin
  DownFiles;
End;end./////////////////////////////////////////////
    线程单元结束
线程在主表单中的调用过程
....
var  
  i : integer;
  Flist : TStringList;  
begin  FList := TStringList.Create;
  Flist.add('http://www.xxx.com/a.rar');
  Flist.add('http://www.xxx.com/b.rar');
  ......  For i:=0 to FList.Count-1 do Begin
    DownThread.Create(Gauge,Lprogress,FList.String[i],'C:\doc'+DateTimeToStr(Now())+'.rar' );     
  // Gauge 是进度条.
  // Lprogress 是一个label.
  End;  Flist.Free;
end;    
.....  程式编译完全没有问题。只是在运行的时候线程,不能同步(找了些资料修改了代码也不行.我笨.)
  希望大哥们,能帮我看看!  顶的朋友有分,大家一起学习! :)
  

解决方案 »

  1.   

    >>目前,远程下载函数已经写好了。我采用多线程下载。
    >>    但前提是,当第一个线程下载完后才执行第二个线程。一直到最后一个线程结束。這樣的多線程??有意義嗎??
      

  2.   

    如你的要求, 試下在一個新的線程中, 寫入你的主程序代碼:For i:=0 to FList.Count-1 do Begin
        DownThread := TDownThread.Create(Gauge,Lprogress,FList.String[i],'C:\doc'+DateTimeToStr(Now())+'.rar' );     
        DownThread.resume;
        DownThread.waitfor;
        
      // Gauge 是进度条.
      // Lprogress 是一个label.
      End;
    DownThread = class(TThread)
      

  3.   

    回复: aiirii(ari-爱的眼睛) 
       
       谢谢你的回复,因为在单线程中,下载的时候窗口被锁定了。
       不能移动窗口,不好意思我比较菜!
      

  4.   

    回复: aiirii(ari-爱的眼睛) 
      谢谢加入这两句后。
      程序正常了很感谢你。DownThread.resume;
    DownThread.waitfor;
    :)
    接分了。
      

  5.   

    >>因为在单线程中,下载的时候窗口被锁定了。
    一般, 如你這種情況, 應該在主線和處理進度條之類的更新
    或單獨用個線程來處理 UI ,
    其它後台線程, 只是postMessage一個消息給處理界面的線程而已
      

  6.   

    >>因为在单线程中,下载的时候窗口被锁定了。
    一般, 如你這種情況, 應該在主線和處理進度條之類的更新
    或單獨用個線程來處理 UI ,
    其它後台線程, 只是postMessage一個消息給處理界面的線程而已