Jump to content

Remy Lebeau

Members
  • Content Count

    2312
  • Joined

  • Last visited

  • Days Won

    94

Posts posted by Remy Lebeau


  1. 23 minutes ago, Uwe Raabe said:

    Another approach is to wrap the code into some TThread.ForceQueue construct...

    ...

    All the code is still executed in the main thread, but there is no loop blocking anything.

    It also has the added benefit that it has an optional Delay parameter, if you need a longer sleep between steps, similar to a timer.

    • Like 1

  2. On 4/18/2024 at 8:40 AM, Khorkhe said:

    according to the Embarcadero docs, these class operators are supposed to return a Boolean.

    Where do you see that documented?  According to this documentation, the return type of the LogicalAnd and LocicalOr operators is simply specified as "resultType", nothing says it is required to be Boolean, so it can be whatever type the implementation wants.


  3. On 4/18/2024 at 1:32 AM, Tommi Prami said:

    Last problem I had was that TryISO8601ToDate will raise exception on string it can't parse. Will handle/eat the exception but not most optimal solution I think.

    By definition, a TryXXX() function does not raise an exception into user code.  TryISO8601ToDate() is no different.

     

    Now, it may be that it generates an internal exception on failure, but that is merely an implementation detail, such an exception will certainly not escape into user code.  If you don't want to see the exception inside the debugger, you can configure it to ignore EDateTimeException and EConvertError exceptions.

     

    Regarding that exception, TryISO8601ToDate() is implemented backwards than other TryXXX() functions.  In most RTL functions, DoX() calls TryDoX() to do the actual work, and then raises an exception if TryDoX() fails.  But TryISO8601ToDate() is different - it calls ISO8601ToDate() to do the actual work, and then suppresses any exception that ISO8601ToDate() raises.

     

    What they SHOULD have done instead is move ISO8601ToDate()'s logic into TryISO8601ToDate(), and then make ISO8601ToDate() raise if TryISO8601ToDate() fails.  But, it turns out that ISO8601ToDate() raises a different exception message depending on why it fails.  Perhaps they could have created a new internal function do perform the actual work and have it report the failure reason to the caller, then TryISO8601ToDate() could ignore the reason, and ISO8601ToDate() could raise an exception based on the reason.  Oh well...

    • Like 1

  4. 14 hours ago, baka0815 said:

    Wouldn't that be something that could be automated in the CI of the Indy project (the creation of the cmd, without the txt file I mean)?

    Indy doesn't have a real CI system.  But yes, generation of the cmd script could be automated in some way using information that Indy already has (there is already some automation in place to generate the Package projects themselves).  To reduce duplication, I could auto-generate a separate cmd script that just deletes the known Indy files in the current directory, and then have Clean_IDE.cmd call that script where needed.

    9 hours ago, DelphiUdIT said:

    In the Embarcadero release, Indy packages, components and other stuffs may be differ from GitHub maintained release. For example IndyIPServer, IndyIPClient and others are not present in the GitHub version.

    Those files are not part of Indy itself, they are part of an internal wrapper on top of Indy which Embarcadero uses to separate its use of Indy from other Embarcadero code.  But, there are other differences Embarcadero does make to Indy itself - most notably, the Packages are changed to use LIBSUFFIX, etc.


  5. 13 hours ago, baka0815 said:

    What I'm currently doing is to implement OnQuerySSLPort(APort: TIdPort; var VUseSSL: Boolean) ans set VUseSLL to True, so SSL/TLS is forced and connections without TLS are not possible.

    That is not the correct way to handle this.

    13 hours ago, baka0815 said:

    How am I supposed to implement a redirect to the correct HTTPS-URL (or raise an error that TLS is required or something along those lines=?

    You need to accept non-TLS connections on the HTTP port, and for any request that is received on that port, send an HTTP redirect response specifying the desired HTTPS port.  That way, the client can then retry the same HTTP request on the HTTPS port using TLS.

    9 hours ago, DelphiUdIT said:

    You must use the "TIdSSLIOHandlerSocketBase.PassThrough" property ... if you set it to FALSE then TLS is required, if you set to TRUE only clear connection (NO TLS) are managed.

    You don't need to handle that manually in TIdHTTPServer.  Use the OnQuerySSLPort event instead, and let TIdHTTPServer handle the PassThrough for you.  Any port that OnQuerySSLPort returns VUseSSL=True for will use PassThrough=False, and vice versa.

    1 hour ago, DelphiUdIT said:

    Look this article of @Remy Lebeau to redirect the connection from "http" to "https": https://www.atozed.com/forums/thread-367-post-834.html#pid834

    ☝️☝️☝️ This is the way!


  6. 6 hours ago, sp0987 said:

    with httpserver do begin

      HTTPServer.DefaultPort := 8080;
      HTTPServer.Bindings.Clear;
      HTTPServer.Bindings.Add.port := 8080;

      if active then stop else active.

    end

    There is no reason to assign a value to DefaultPort if you are creating only 1 Binding and setting its Port, thus overwriting what the DefaultPort already assigned.  On the other hand, there is no point in assigning the Binding's Port if you are assigning it the same value as DefaultPort.  The whole point of DefaultPort is it is the initial Port that is assigned by Add().

    6 hours ago, sp0987 said:

     log(req.httpcommand); --// If i remove this then am getting EInvalidPointer : Invalid pointer operation

    17:01:23.675 - /images/RuleCOMPILEDSCRIPT.png : /images/RuleCOMPILEDSCRIPT.png for all types of files

    Such weird behavior is typically a classic symptom of "Undefined Behavior" being invoked elsewhere in your code, and this code is likely just an unexpecting victim of it.  For instance, if random memory were being corrupted, and then this code tries to access that memory.

    6 hours ago, sp0987 said:

    // if the req.documet is other than .png/.jpg 

         Data := LoadDataFromFile(doc);

         res.ContentType := fMIMEMap.GetFileMIMEType(doc);
          res.ContentStream := TStringStream.Create(Data);

    Why are you using a TStringStream for raw file data?  If you really need to load the file data into a String (ie, the file is textual), then you could simply use ContentText instead of ContentStream, no need to use a TStream.

    6 hours ago, sp0987 said:

     except

        on E: Exception do
        begin
          Log(req.URI + ' : ' + req.Document + sLineBreak + E.ClassName + ' : '  + E.Message);
         
        end;

    As I mentioned earlier in this thread, if you catch exception, you should RE-RAISE any Indy exceptions that are caught, eg:

    except
      on E: Exception do
      begin
        Log(req.URI + ' : ' + req.Document + sLineBreak + E.ClassName + ' : '  + E.Message);
        if E is EIdException then raise; // <-- ADD THIS
      end;

  7. 17 hours ago, JohnLM said:

    I have this routine that lists all running processes in a listbox under Windows 7.

    As Anders mentioned, you likely don't have permissions to retrieve all processes for other users.  That being said, you might consider trying EnumProcesses() and see if it returns more entries.

     

    That being said, there are quite a number of issues with the code you have shown:

    • You are leaking the THandle returned by CreateToolhelp32Snapshot().
    • GetName() is over-complicated.  The data.szExeFile value is guaranteed to be null-terminated, so your loop is completely unnecessary (not to mention your use of a Byte for the loop counter means you might potentially truncate long filenames). You can simply assign the data.szExeFile value as-is to the Result without concatenating Char-by-Char (also, your comparison of a single Char to a blank string makes no sense at all).  For that matter, you could just get rid of GetName() altogether and simply add data.szExeName as-is to your TStrings.

    • You are not protecting your code from unexpected exceptions, which will cause several leaks if something goes wrong.  There are several places in your code where you should be using try..finally blocks to free/release resources properly.

    • You don't need to use the global Form1 variable inside of TForm1's own methods.  Use each method's Self pointer instead.

     

     

     


  8. On 3/20/2023 at 12:16 PM, programmerdelphi2k said:

    I'm not intimate with the depths of MSWindows, but I think the TLabel might respond to the "CM_TEXTCHANDED" message, so you can do some checking by redrawing the control (invalidating it and resetting to the new text)

    CM_TEXTCHANGED is a VCL message, it doesn't exist in FMX.  When the TLabel.Text property is changed in FMX, there is no window message issued back to the TLabel, but there are virtual methods called instead, such as DoChanged() and DoTextChanged().  It should also be mentioned that the Text setter already calls Repaint() after calling the virtual methods.


  9. 8 hours ago, Lainkes said:

    I have a DBCheckbox where the user can indicate if more info is needed. (check or uncheck)

    See screenshot.

    When the DBCheckbox is not checked, the datetimepicker component must be unvisible. And the date in the database must be set to a value that is not usable (like 30/12/1899).

    If checked, the datetimepicker must be visible and the selected date must be saved. 

    Then there is no point in enabling the CheckBox on the DateTimePicker itself.


  10. 8 hours ago, weabow said:

    TThread.Synchronize is made to display something in the gui, surely. But I often prefer TThread.ForceQueue.

    TThread.Synchronize() is not limited to just GUI work, though that is what it is commonly used for.  It just serializes threads to run code though the main UI thread, nothing more.

     

    TThread.ForceQueue() is meant to be used in the main UI thread only, worker threads should use TThread.Queue() (or TThread.Synchronize()) instead.  TThread.Synchronize() and TThread.Queue() bypass the internal queue when they are called in the main UI thread.  TThread.ForceQueue() was added so the main UI thread can queue things up, too.

    8 hours ago, weabow said:

    Also, if you have a variable in the main thread, and you want to change its value from Anonymous, you have to do it in a Synchronyse, from th Anonymous.

    Or, simply wrap the variable behind a thread-synchronization object, such as TCriticalSection, TEvent, TConditionalVariableCS, TMREWSync, TInterlock, etc.  Many different ways to protect a variable from concurrent access across multiple threads.

    8 hours ago, weabow said:

    And to finish, be careful of Android, which threads are a little bit differnet from the other plateforms.

    Not really.  Android runs on top of Linux, so its base threading is pretty similar to other platforms.  However, there are restrictions on what can and cannot be executed on the UI thread, for instance, but that is artificially enforced by Android's implementation of Java, not Linux itself.

    • Like 2

  11. A DateTimePicker does not have a concept of a NULL date/time.  That is why it has an optional checkbox instead.  If you need the date/time value to be optional, then enable the check box, and if checked then use the date/time otherwise ignore it.  You can't assign a NULL date/time value, so just uncheck the box and set a default value if needed.


  12. 6 hours ago, cecarnicom said:

    My source images are all about 600 pixels on a side... My original images are jpgs

    Given that your images are large, and not even bitmaps to begin with, I would suggest an alternative approach - get rid of the TImageList altogether. Instead, create an array/TList of TJPGImage objects, and then owner-draw them onto your ListView/ListBox items as needed.


  13. 2 hours ago, MarkShark said:

    I'm looking for something analogous to AnsiCompareStr.

    The System.AnsiStrings.AnsiCompareStr() function uses the Win32 CompareStringA() function on Windows (the System.SysUtils.AnsiCompareStr() function uses CompareStringW() instead).  But, CompareStringA() assumes the input strings are in the ANSI encoding of the specified locale.  The MSDN documentation says:

    Quote

    If your application is calling the ANSI version of CompareString, the function converts parameters via the default code page of the supplied locale. Thus, an application can never use CompareString to handle UTF-8 text.

     


  14. On 4/9/2024 at 7:44 AM, David P said:

    It is possible to drag to a smaller width than MinWidth but upon release it springs to MinWidth width.  I'm now wondering if I was just fixating on the dragging and not when the mouse was released.

    Interesting.  I just tested that in 12.0 Patch 1 and sure enough the springing works.  However, removing the 'else' does prevent the dragging from going smaller than the MinWidth to begin with.


  15. As I said, I confirmed the bug does not exist in 10.3, but does exist in 12.0, so it's possible that it does not exist in 11.3 either. I don't have that version to check with. If you look in your IDE's copy of the Vcl.ComCtrls.pas source file, do you see the code I showed earlier?


  16. 13 hours ago, balabuev said:

    I see the topic is old already, but anyway, I'm searching for something faster. So, here is my try:

    
    procedure TAncestor.DoSomething;
    type
      TProcX = procedure of object;
    var
      md: TProcX;
    begin
      md := Self.ProcX;
      if TMethod(md).Code <> @TAncestor.ProcX then
        // Overridden.
      else
        // Not overridden.
    end;

     

    Tested, works fine (also, you don't need to use "Self.").  You can also use an inline variable to simplify your example further:

    procedure TAncestor.DoSomething;
    begin
      var md := ProcX;
      if TMethod(md).Code <> @TAncestor.ProcX then
        // Overridden.
      else
        // Not overridden.
    end;

    Do note that in the original TStream code, using @TStream.Seek like above won't work since Seek() is overloaded, so the compiler wouldn't know which overload to compare with.  Hence the original code's use of a typed variable to resolve the ambiguity, eg:

    procedure TAncestor.DoSomething;
    type
      TProcX = procedure of object;
    var
      Impl, Base: TProcX;
      ClassTAncestor: TClass;
    begin
      ClassTAncestor := TAncestor;
      Impl := ProcX;
      Base := TAncestor(@ClassTAncestor).ProcX;
      if TMethod(Impl).Code <> TMethod(Base).Code then
        // Overridden.
      else
        // Not overridden.
    end;

    This works for both overloaded and non-overloaded methods.

     

    I have reported this enhancement to Embarcadero now:

    https://embt.atlassian.net/servicedesk/customer/portal/1/RSS-548

     

    As for the invalid cast errors, they are probably the compiler trying to CALL the method first, and then cast the (lack of a) return value.  You have to do the comparisons through the TMethod record, and that requires a variable which you can type-cast.

     


  17. On 4/6/2024 at 5:26 AM, DelphiUdIT said:

    In the batch "clean..." there was an error ... "ren" cmd is not working if the destination file name has a path. In the normal condition (without extension options) this is an error. So I change the cmd file, including the new directories for Athens12.1 in the zip file attached.

    I have now merged in your changes.  For consistency, I re-arranged the order of the new directories that you had added.

    • Thanks 1

  18. 6 hours ago, Ian Branch said:

    Does Clean_<version>.cmd install 32 & 64 bit or is it selectable?

    I only do 32 bit.

    The cleanup scripts don't INSTALL anything. They REMOVE the pre-installed copy of Indy they ships with the IDE. Nothing more. You have to then compile Indy yourself. By default, the projects are setup for Win32 only. You would have to configure the desired platforms as needed.


  19. 58 minutes ago, DelphiUdIT said:

    in my system (with standard installation of Rad Studio, so in "c:\program files (x86)\....") and of course with admin priviledge the files indicated where not backuped ("cannot backup xxx" was the message, the rename did't work ???) ... the files were deleted.

    Hmm, it worked fine for me when I tested it on my system.

    58 minutes ago, DelphiUdIT said:

    Another thing about this topic: in that "cmd files" some changes are needed cause new distribution of the files in Athens 12.1 (some bpl in bin64, new "MODERN" compiler, IOS simulator) . I already adjusted the file, but I should test it (and look for backup issue).

    I don't have 12.1 installed yet.  Feel free to submit a Pull Request or email with any changes needed.


  20. 6 hours ago, DelphiUdIT said:

    One for all: don't use the automatic procedure !!!😞

    After the changes of Indy "clear cmd" about some files that should not be deleted, in my system they are deleted instead ... use manual mode like I indicated in my posts.

    I already fixed that issue a month ago, and I told you that at the time:

     

×