Jump to content

Leaderboard


Popular Content

Showing content with the highest reputation on 10/27/20 in all areas

  1. Remy Lebeau

    Need help with IDhttp and Thread

    Try something like this: procedure TForm1.Button1Click(Sender: TObject); var i: integer; lPaths: array of string; begin SetLength(lPaths, ListBox1.Items.Count); for i := 0 to ListBox1.Items.Count-1 do begin lPaths[i] := ListBox1.Items.Strings[i]; end; TParallel.&For(0, ListBox1.Items.Count-1, procedure(AIndex: Integer) var lPath: string; lHTTP: TIdHTTP; IdSSL: TIdSSLIOHandlerSocketOpenSSL; URI: TIdURI; begin lPath := lPaths[AIndex]; lHTTP := TIdHTTP.Create(nil); try lHTTP.ReadTimeout := 30000; lHTTP.HandleRedirects := True; IdSSL := TIdSSLIOHandlerSocketOpenSSL.Create(lHTTP); IdSSL.SSLOptions.SSLVersions := [sslvTLSv1, sslvTLSv1_1, sslvTLSv1_2]; IdSSL.SSLOptions.Mode := sslmClient; lHTTP.IOHandler := IdSSL; lHTTP.AllowCookies := True; lHTTP.Request.UserAgent := 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.0 Safari/537.36'; lHTTP.Request.Accept := 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'; lHTTP.Request.AcceptLanguage := 'en-GB,en;q=0.5'; lHTTP.Get(lPath); except on E: EIdHTTPProtocolException do begin if E.ErrorCode = 404 then begin TThread.Queue(nil, procedure begin Form1.ListBox2.Items.Add(lPath); end ); end; Exit; end; end; TThread.Queue(nil, procedure begin Form1.Memo1.Lines.Add(lPath); end ); end ); end; Alternatively: function TForm1.Download(lPath: string): ITask; begin Result := TTask.Run( procedure var lHTTP: TIdHTTP; IdSSL: TIdSSLIOHandlerSocketOpenSSL; URI: TIdURI; begin lHTTP := TIdHTTP.Create(nil); try lHTTP.ReadTimeout := 30000; lHTTP.HandleRedirects := True; IdSSL := TIdSSLIOHandlerSocketOpenSSL.Create(lHTTP); IdSSL.SSLOptions.SSLVersions := [sslvTLSv1, sslvTLSv1_1, sslvTLSv1_2]; IdSSL.SSLOptions.Mode := sslmClient; lHTTP.IOHandler := IdSSL; lHTTP.AllowCookies := True; lHTTP.Request.UserAgent := 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.0 Safari/537.36'; lHTTP.Request.Accept := 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'; lHTTP.Request.AcceptLanguage := 'en-GB,en;q=0.5'; lHTTP.Get(lPath); except on E: EIdHTTPProtocolException do begin if E.ErrorCode = 404 then begin TThread.Queue(nil, // or Synchronize() procedure begin ListBox2.Items.Add(lPath); end ); end; Exit; end; end; TThread.Queue(nil, // or Synchronize() procedure begin Memo1.Lines.Add(lPath); end ); end ); end; procedure TForm1.Button1Click(Sender: TObject); var i: integer; TaskList: TList<ITask>; T: ITask; begin TaskList := TList<ITask>.Create; try for i := 0 to ListBox1.Items.Count-1 do begin T := Download(ListBox1.Items.Strings[i]); TaskList.Add(T); end; while not TTask.WaitForAll(TaskList.ToArray, 500) do begin CheckSynchronize(); Update; end; finally TaskList.Free; end; end; TThread.Synchronize() is synchronous. It sends a request to the main UI thread and waits for it to be processed before exiting back to the calling thread. But the main UI thread is blocked waiting for the TParallel.For() loop to finish running, and so it cannot process TThread.Synchronize() requests in the meantime. Deadlock occurs. See Freeze when use TThread.Synchronize with TParallel or TTask.WaitForAll. TThread.Queue() is asynchronous. It posts a request to an internal queue and then exits immediately, allowing the calling code to continue running. The main UI thread will process the queue at a later time, in this case after the TParallel.For() loop has finished. That won't work, because TThread.Queue() is asynchronous. When you issue the request to read the ListBox string, it won't be retrieved in time for your TIdHTTP to actually use it. What you could do instead is copy the ListBox strings to a local array before starting the TParallel.For() loop, and then you can access that array directly in your anonymous procedure without needing to synchronize access to it. See the example above. Otherwise, don't use TParallel.For() when you need to perform actions synchronously in the main UI thread. See Using TThread.Synchronize with TTask.WaitForAll and the example above. That is because your lPath variable has not been assigned a value yet when you pass it to TIdHTTP.Get().
  2. Stefan Glienke

    Having fun with Delphi

    Fluent API with records containing managed fields (such as strings) unfortunately produces terrible code because the compiler produces an implicit variable for each method call.
  3. I have been using WordPress for this blog for several years and always thought my setup was reasonably secure. Turns out that there is something called the WordPress REST API which allows to get quite a lot information about the installation without any security at all. Read on in the blog post.
  4. mvanrijnen

    Having fun with Delphi

    Something like: tmp := THSUri.HTTPS .UserName('yourname') .Password('andpassword') .Host('www.website.com') .Port(1234) .Path('chapter') .Path('subchapter') .Path('subsubchaper') .Parameter('showall') .Parameter('yearstart', '1990') .Fragment('startreadinghere'); tmp.AsString Reults in: 'https://yourname:andpassword@www.website.com:1234/chapter/subchapter/subsubchaper?showall&yearstart=1990#startreadinghere' I'm using the scheme (HTTP, HTTPS) as the record constructor/initializer. .... public class function Scheme(const AScheme : THSURIScheme) : THSUri; static; class function HTTP : THSURI; static; class function HTTPS : THSURI; static; ..... implementation class function THSURI.Scheme(const AScheme: THSURIScheme): THSUri; begin // some needed and needless inits. Result.FScheme := AScheme; Result.FPort := 0; Result.FHost := string.Empty; Result.FUserName := string.Empty; Result.FPassword := string.Empty; Result.FPath := string.Empty; Result.FQuery := string.Empty; Result.FFragment := string.Empty; end; class function THSURI.HTTP: THSURI; begin Result := THSURI.Scheme(usHTTP); end; class function THSURI.HTTPS: THSURI; begin Result := THSURI.Scheme(usHTTPS); end;
  5. Install WordFence (the are free and paid version) and keep the number of plug-ins to a minimum.
  6. Another option I can think of is to delay showing the secondary Form until after the Main Form is done fully showing itself. For instance, via TThread.ForceQueue(), eg: procedure TMainForm.FormShow(Sender: TObject); begin SetScreensLang; if MustSignIn then begin TabControl1.ActiveTab := PersonalTabItem; TThread.ForceQueue(SignForm.Show); // <-- end else begin CheckAlerts; TabControl1.ActiveTab := AlertsTabItem; AlertsTabItemClick(nil); end; end;
  7. FPiette

    Common callback functions, or not?

    Your are right: an event is a kind of callback. But not all callbacks are events. In Delphi there is a pattern for the events. I explained that pattern in a few previous messages and @Fr0sT.Brutal expressed it again using different words.
  8. Mahdi Safsafi

    Detecting update versions in defines

    The path must be fully qualified (includes full unit). {$IF declared(System.TObject.Foo)} foo {$ENDIF}
  9. Stefan Glienke

    Delphi 10.4.1 and the IDE FIx Pack

    tbh not having IDEFixPack being available is good in the long run - with the existence of it nobody (or very few) actually cared to report issues and put some pressure on Embarcadero to address these things. Now that there is no solution available the pressure on Embarcadero has raised and I can confirm that they are working on it - will they suddenly implement all fixes and optimizations from Andreas? No, but better they do slowly than relying on the third party no matter how incredible.
  10. haentschman

    Delphi 10.4 (.1) Welcome Page

    Hi... the solution ist here... https://www.danielwolf.eu/blog/2015/1668-meine-vorstellung-einer-willkommens-seite ...slim and effective
×