Jump to content

Remy Lebeau

Members
  • Content Count

    2684
  • Joined

  • Last visited

  • Days Won

    113

Everything posted by Remy Lebeau

  1. Remy Lebeau

    TIdServerIOHandlerSSLOpenSSL root certficate error

    Duplicate of
  2. Remy Lebeau

    Threaded FTP and Timeouts

    Are you using TIdFTP in Active mode (TIdFTP.Passive=False, which is the default) or in Passive mode (TIdFTP.Passive=True)? Different modes use different timeouts, but since you are setting them all, you certainly should be getting a timeout error one way or the other. However, your try..except is catching only exceptions derived from EIdSocketError, but for instance EIdAcceptTimeout (which TIdFTP raises in Active mode if the server doesn't connect to TIdFTP within the ListenTimeout interval) is not derived from EIdSocketError. In the code you have shown, I don't really see a need to have the try..except differentiate which type of exception is raised. It should be catching all of them. You are also not synchronizing with the UI thread when accessing your UI controls. Try something more like this instead: constructor TLoadThread.Create; begin inherited Create(True); FreeOnTerminate := True; end; procedure TLoadThread.Execute; begin try Form2.FTP1.Connect; try Form2.Ftp1.Get('file1.txt', TPath.Combine(TPath.GetTempPath, 'file1.txt'), True, False); Form2.Ftp1.Get('file2.txt', TPath.Combine(TPath.GetTempPath, 'file2.txt'), True, False); finally Form2.FTP1.Disconnect; end; except on e: Exception do begin TThread.Synchronize(nil, procedure begin if e is EIdSocketError then Form2.AddToMemo('Error: ' + IntToStr(EIdSocketError(e).LastError) + ' ' + e.Message) else Form2.AddToMemo('Error: ' + e.Message); end ); end; end; end; procedure TForm2.ThreadTerminated(Sender: TObject); begin xThread := nil; Loading := False; AddToMemo('Thread Terminated'); end; procedure TForm2.FTP1Status(ASender: TObject; const AStatus: TIdStatus; const AStatusText: string); begin TThread.Queue(nil, procedure begin AddToMemo(AStatusText); end ); end; procedure TForm2.AddToMemo(const AMsg: string); begin Memo1.Lines.Add(DateTimeToStr(Now()) + ' ' + AMsg); end; Alternatively, you can move your exception logging to the thread's OnTerminate event handler instead, eg: constructor TLoadThread.Create; begin inherited Create(True); FreeOnTerminate := True; end; procedure TLoadThread.Execute; begin Form2.FTP1.Connect; try Form2.Ftp1.Get('file1.txt', TPath.Combine(TPath.GetTempPath, 'file1.txt'), True, False); Form2.Ftp1.Get('file2.txt', TPath.Combine(TPath.GetTempPath, 'file2.txt'), True, False); finally Form2.FTP1.Disconnect; end; end; procedure TForm2.ThreadTerminated(Sender: TObject); var exc: Exception; begin xThread := nil; Loading := False; if TThread(Sender).FatalException <> nil then begin exc := Exception(TThread(Sender).FatalException); if exc is EIdSocketError then AddToMemo('Error: ' + IntToStr(EIdSocketError(exc).LastError) + ' ' + e.Message) else AddToMemo('Error: ' + e.Message); end; AddToMemo('Thread Terminated'); end; procedure TForm2.FTP1Status(ASender: TObject; const AStatus: TIdStatus; const AStatusText: string); begin TThread.Queue(nil, procedure begin AddToMemo(AStatusText); end ); end; procedure TForm2.AddToMemo(const AMsg: string); begin Memo1.Lines.Add(DateTimeToStr(Now()) + ' ' + AMsg); end;
  3. Remy Lebeau

    Where I can find the SSL DLLs for Indy?

    Indy does have some binaries in its OpenSSL-binaries GitHub repo, but it currently has only .DLLs for Windows, .SO's for Android, and static .A's for iOS, there are no .DYLIB's for macOS, sorry.
  4. Remy Lebeau

    WideString.c_bstr() operation in 11.2

    What is the exact problem you are having? Can you provide an example? Passing a BSTR (which is already a pointer type to begin with) by value for an [in] parameter is very different than passing a pointer to a BSTR for an [in,out]/[out] parameter. The WideString::c_str() method will work fine for the former case, but you can't use it in the latter case, you would have to use WideString::operator& instead. Not without seeing the actual code you are having trouble with.
  5. Remy Lebeau

    Where I can find the SSL DLLs for Indy?

    It will not be available in 11.3, which is already in beta. It is too soon to speculate about 12.0.
  6. Remy Lebeau

    Where I can find the SSL DLLs for Indy?

    I don't know, as I'm not a macOS developer. However, TLS 1.2 was added to OpenSSL in v1.0.1, so v1.0.0 will not suit your needs. That is because Indy's default SSLIOHandler only supports OpenSSL up to v1.0.2. To use OpenSSL v1.1.0 or later, you will have to install and use the work-in-progress SSLIOHandler that is found on this Pull Request in Indy's GitHub repo (as it hasn't been reviewed and merged into the main code yet).
  7. Remy Lebeau

    Indy 11 ??

    There is no ETA on when Indy 11 will be released. Work on it has been slow for several years, but there has been work on it nonetheless. There is an Indy11-preparation branch in Indy 10's GitHub repo whose code is expected to eventually become Indy 11, but it is not quite ready for release yet.
  8. Remy Lebeau

    Close application during form create??

    In which case, I wouldn't even bother with calling Application.Terminate(), just skip calling Application.Run() instead: begin Application.Initialize; Application.ShowMainForm := False; Application.CreateForm(TfrmMainForm, frmMainForm); if frmMainForm.DoWeShowTheForm then begin Application.ShowMainForm := True; Application.Run; end; end.
  9. Remy Lebeau

    Close application during form create??

    Application.Terminate() calls PostQuitMessage() internally: // ----- Form1 ---- uses Unit2; procedure TForm1.FormCreate(Sender: TObject); begin Application.Terminate; end; procedure TForm1.Button1Click(Sender: TObject); begin Form2 := TForm2.Create(self); end; // ----- Form2 ---- procedure TForm2.FormCreate(Sender: TObject); begin Application.Terminate; end; No need for using OnClose/caFree when Form1 is the Owner of Form2, since Application.Terminate()/PostQuitMessage() is asynchronous, so the Form1 and Form2 objects will still be created, Form1 will take ownership of Form2, and then the Application object will destroy the Form1 object, and thus the Form2 object, when the Application object is destroyed after the quit message makes Application.Run() exit.
  10. Note that such usage is demonstrated in Embarcadero's documentation, though it is not explicitly called out as being a requirement: https://docwiki.embarcadero.com/RADStudio/en/Inline_Variable_Declaration procedure Test99; begin // some code if (something) then begin var Intf: IInterface = GetInterface; // Intf.AddRef // <-- HERE! var MRec: TManagedRecord = GetMRecValue; // MRec.Create + MRec.Assign UseIntf(Intf); UseMRec(MRec); end; // Intf.Release and MRec.Destroy are implicitly called at end of scope // more code end; // no additional cleanup
  11. Remy Lebeau

    Canvas.Font not equal Font?

    Only while the control is actively processing a paint operation invoked by the OS - ie, during a WM_PAINT or NM_CUSTOMDRAW or equivalent window message. Before the control's virtual Paint() method is called, or its public OnPaint/OnDraw... events are fired, both allowing user code to handle custom drawing, the relevant control properties are assigned to the Canvas. Outside of an active paint operation, the Canvas's properties are not guaranteed to match the control's properties, and likely will be defaults instead.
  12. AFAIK, yes, it is still the case.
  13. Remy Lebeau

    Check if database table string field is empty or NULL??

    IsNullOrEmpty() is a method of TStringHelper, so you have to call it on a string instance, eg: if MyTable.FieldByName('MyField').AsString.IsNullOrEmpty then Which is really no better than simply testing for an empty string (since AsString can't return a null string): if MyTable.FieldByName('MyField').AsString = '' then However, since Delphi strings don't differentiate between null and empty (they are both a nil pointer), if you really need to differentiate then you will have to use TField.IsNull instead, eg: if MyTable.FieldByName('MyField').IsNull then // is null ... else if MyTable.FieldByName('MyField').AsString = '' then // is empty ... else // is not null or empty ...
  14. Remy Lebeau

    New Installation of Rad Studio 10.2 (Tokyo)

    Are you using the Feature installer (Web) or the Offline installer (ISO)?
  15. Remy Lebeau

    Audio via TCP/IP

    Note that TCP is usually not a good choice for streaming media, due to delays caused by latency, integrity checks, acks, etc. TCP is good to use when you need to ensure the receiver actually gets everything that is sent. But since real-time streaming media doesn't usually require that, dropped packets here and there are usually tolerable, so UDP is used instead, typically with a streaming media protocol on top of it, like RTP, etc.
  16. Remy Lebeau

    How to Send HTTP data in Delphi

    Delphi ships with Indy pre-installed, which has a TIdHTTP component. Modern versions of Delphi also have native THTTPClient/TNetHTTPClient components, too. But either way, you can't just send arbitrary data to the ESP without understanding what it is actually expecting. Do you have any documentation on what exactly it actually wants clients to send it? What do the required URLs look like? What input parameters are they expecting? Are they query-string parameters, or post-body parameters? Etc
  17. Remy Lebeau

    Patch a private virtual method

    The OS is not involved in this process. Instantiating an object is simply a matter of allocating a memory block to hold the data members, and then calling the class constructor on that memory block to initialize the data members. Any methods called on an object (including the constructor and destructor) is simply a matter of making a normal function call with a pointer to the object as a (hidden) parameter so the code knows which object is being act on. There are no copies of the method instructions being made. There is only 1 copy in memory that all objects share. Calling the same method on multiple objects will execute the same code instructions just with a different object parameter. It will fail if the patched method tries to access any data members that don't actually belong to the actual object that the method is being called on.
  18. Remy Lebeau

    CreateProcess causing some strange Access Violations

    Using the Addr() intrinsic in that way will give you the memory address of the _TaskDialogIndirect variable itself, not the memory address that the variable holds. Try inspecting just _TaskDialogIndirect by itself, or at least cast it to a Pointer.
  19. Remy Lebeau

    CreateProcess causing some strange Access Violations

    It is not an implementation detail, it is documented behavior: https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessa https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessw
  20. Remy Lebeau

    CreateProcess causing some strange Access Violations

    That means you are trying to call a function through a nil function pointer. Did you check to see whether _TaskDialogIndirect is nil or not?
  21. Remy Lebeau

    CreateProcess causing some strange Access Violations

    Incorrect, it is the 2nd argument that must be writable. And only in the Unicode version.
  22. Remy Lebeau

    Centered message?

    There is also ShowMessagePos() for that purpose.
  23. Remy Lebeau

    DL a file from the web

    INVALID_HANDLE_VALUE is not null (0), it is -1. Some APIs return 0 on failure, some return -1 instead. Be careful mixing them up. See Why are HANDLE return values so inconsistent?
  24. Remy Lebeau

    DL a file from the web

    The point I was trying to make is that, if InternetOpen() fails, the value of HFile is left indeterminate, so calling InternetCloseHandle() on it is undefined behavior. Also, InternetCloseHandle() is not documented as accepting null handles, so if either InternetOpen() or InternetOpenUrl() fails, calling InternetCloseHandle() on the failed handle is also undefined behavior. So, best to call InternetCloseHandle() only on successfully opened handles. Which means, using multiple try..finally blocks. Calling GetLastError() multiple times mixed in other system calls risks having the error code wiped out in between the calls. Best to save the error code to a variable as soon as possible, and then use the variable where needed. Yes. Which is why one should generally use WriteBuffer() instead, which will raise if not all bytes are written.
  25. Remy Lebeau

    DL a file from the web

    This code has many small mistakes. Too many try's. Undefined behavior calling InternetCloseHandle() on invalid handles if either InternetOpen() or InternetOpenUrl() fail. Misuse of GetLastError(). Not reporting an error if InternetReadFile() fails. Not making sure FBuffer actually writes all of the bytes it is given.
×