program testmthd; {$IFDEF FPC}{$MODE DELPHI}{$ENDIF} uses curlobj; {$I-} // <<-- Let threads share stdout ( ignore errors when they block ) var AddCount: LongInt = 0; DoneCount: LongInt = 0; const NULL_FILE = {$IFDEF WIN32}'NUL'{$ELSE}'/dev/null'{$ENDIF}; function ProgressMeter( clientp: pointer; dltotal, dlnow, ultotal, ulnow: double ): LongInt; cdecl; begin WriteLn( tCurl(clientp).Tag, '. Receiving ', dlnow:0:0, '/', dltotal:0:0, ' from ', tCurl(clientp).Url); if (tCurl(clientp).Tag = AddCount) then WriteLn; Result:=0; end; procedure AddOne(m:tCurlMulti; url:pChar); var c:tCurl; begin inc(AddCount); if m.Busy then WriteLn('ADD WHILE RUNNING: ', url); c:=tCurl.Create(nil); c.URL:=url; c.FollowLocation:=True; c.OutputFile:=NULL_FILE; c.NoProgress:=False; c.ProgressFunction:=ProgressMeter; c.ProgressData:=c; c.Timeout:=60; c.Tag:=AddCount; m.AddObject(c); end; procedure OneDone(which:tCurl; data:pointer); cdecl; begin Write( which.Tag, ': DONE [ ',which.EffectiveURL,' ] '); if ( which.ResultCode = CURLE_OK ) then WriteLn( which.SizeDownload, ' bytes (OK)') else WriteLn(which.ErrorString); case which.Tag of 3: AddOne(tCurlMulti(data) , 'http://news.yahoo.com/'); 4: AddOne(tCurlMulti(data) , 'http://news.google.com/'); end; which.Free; inc(DoneCount); end; procedure Waiting(p:pointer); cdecl; begin // A GUI app could call ProcessMessages() here... WriteLn('**** WAITING ****'); end; const URLs:array[0..7] of pChar = ( 'http://abc.go.com/', 'http://bbc.co.uk/', 'http://cbs.com/', 'http://cnn.com/', 'http://fox.com/home.htm', 'http://msnbc.msn.com/', 'http://nbc.com/', 'http://www.pbs.org/' ); var m:tCurlMulti; i:LongInt; begin m:=tCurlMulti.Create(nil); m.Threaded:=True; m.WaitInterval:=2000; m.WaitCallback:=Waiting; m.WaitData:=m; m.DoneData:=m; m.SingleDoneCallback:=OneDone; for i:=low(URLs) to high(URLs) do AddOne(m, URLs[i]) ; m.Perform(); m.Free; WriteLn('Requested: ', AddCount, ' Completed: ', DoneCount); end.