Jump to content

Remy Lebeau

Members
  • Content Count

    3000
  • Joined

  • Last visited

  • Days Won

    135

Posts posted by Remy Lebeau


  1. I can't answer your question.  But an alternative approach would be to create your own dialog however you want, and then write your own class that implements the IFMXDialogServiceAsync interface to show your dialog, and then register that class with FMX using TPlatformServices.Current.AddPlatformService() (be sure to unregister the default implementation using TPlatformServices.Current.RemovePlatformService() first).

    • Like 1

  2. Embarcadero doesn't want your location. This warning is starting to show up for a lot of network-enabled apps.  A recent Windows update is enforcing permission to Wifi info, as it CAN be used to reveal your location, which is a privacy concern.

     

    https://learn.microsoft.com/en-us/windows/whats-new/whats-new-windows-11-version-24h2#windows-location-improvements

     

    Quote

    A new prompt appears the first time an app attempts to access your location or Wi-Fi information.

     

    • Like 1
    • Thanks 1

  3. You are using the version of FormatDateTime() that relies on global variables initialized with your PC's locale settings. For instance, the '/' specifier is not a literal slash character, it is a placeholder that uses the global DateSeparator variable in the SysUtils unit. This is documented behavior.
     

    You can update those globals to customize things like the date/time separators, but this affects the whole app, and is not thread-safe. When you need custom formatting that is locale-agnostic, you should use the version of FormatDateTime() that takes a TFormatSettings parameter, eg:

    procedure TForm1.Button1Click(Sender: TObject);
    var
      lDate: TDateTime;
      lFmt: TFormatSettings;
    begin
      lFmt := TFormatSettings.Create;
      lFmt.DateSeparator := '/';
      lDate := EncodeDate(2025, 3, 26);
      Edit1.Text := FormatDateTime('dd/mm/yyyy', lDate, lFmt);
    end;

    The alternative is to wrap desired literal text with quotes in your format string, eg:

    procedure TForm1.Button1Click(Sender: TObject);
    var
      lDate: TDateTime;
    begin
      lDate := EncodeDate(2025, 3, 26);
      Edit1.Text := FormatDateTime('dd"/"mm"/"yyyy', lDate);
    end;
    • Like 5
    • Thanks 2

  4. 1 hour ago, JohnLM said:

    What I am thinking next, is how to add URL's to the combobox while the program is running.  That idea is tricky to me as I've never done that and don't know how, yet. Then, every time I copy/paste/[Go], the URL is to be checked if in the combobox list, and if not, add it, and if it is already there, ignore it.  Something like that, I guess.

    That is pretty trivial to implement, eg:

    procedure TMainForm.GoBtnClick(Sender: TObject);
    var
      url: string;
      idx: integer;
    begin               
    {
    change this https://www.youtube.com/watch?v=ZJhJILyS388
        to this https://www.youtube.com/embed/ZJhJILyS388
    }
      url := StringReplace(addresscb.Text, 'watch?v=', 'embed/', [rfIgnoreCase]);
      addressCb.Text := url;
      WVBrowser1.Navigate(url);
      idx := ComboBox1.Items.IndexOf(url);
      if idx = -1 then
        ComboBox1.Items.Add(url);
    end;

     

    • Like 2

  5. 6 hours ago, Lars Fosdal said:

    Several record types where I had to explicitly add a string length, resulting in numerous [dcc32 Warning]: W1057 Implicit string cast from 'ShortString' to 'string'

    That has nothing to do with Generics (the topic of this discussion).

     

    Specifying an explicit length on a string at compile-time will produce an AnsiChar-based ShortString, and always has. That's nothing new. Assigning an Ansi string to a Unicode string (or vice versa) requires a data conversion at runtime, which can potentially lose data, hence the warning. 


  6. 1 hour ago, FredS said:

    What I found when originally searching: https://stackoverflow.com/a/64526312

    That StackOverflow post is about the error on a Custom Managed Record, but the code shown above is not using a CMR.  It is just a regular Managed Record due to the string field (has nothing to do with the custom Attribute).  And according to RSS-3043 (which has been closed last week as "As Designed"):

    Quote

    This is actually as designed, managed records (including records with strings) cannot be use for generics restricted to records (where record is in fact traditional memory managed records). It's a restriction from the past, done to avoid bugs

     

    • Thanks 1

  7. Calling ReadBytes() with an AByteCount value greater than 0 will wait until the specified number of bytes have arrived in the InputBuffer. So, if you are expecting 7000 bytes then just call ReadBytes() 1 time with AByteCount set to 7000.

     

    But, if you don't know ahead of time how many bytes are coming, then you can call ReadBytes() with an AByteCount value less than 0 and it will return however many bytes are currently available in the InputBuffer (if it is empty, ReadBytes() will wait until any bytes arrive first).

     

    If you don't want to change your current logic, then you can simply catch the EIdReadTimeout exception and call ReadBytes() again with the AByteCount value set to the IOHandler's current InputBuffer.Size.


  8. 7 hours ago, Kas Ob. said:

    There is zero guarantee that DllMain will be called from the the Main Thread or even the the same thread that called LoadLibrary !

    DLL_PROCESS_ATTACH should be in the same thread that calls LoadLibrary(), but DLL_PROCESS_DETACH is not guaranteed to be in that same thread. Raymond Chen even blogged about this issue back in 2009 (emphasis added by me):

     

    The thread that gets the DLL_PROCESS_DETACH notification is not necessarily the one that got the DLL_PROCESS_ATTACH notification

     

    Quote

    The thread that gets the DLL_PROCESS_DETACH notification is not necessarily the one that got the DLL_PROCESS_ATTACH notification. This is obvious if you think about it, because the thread that got the DLL_PROCESS_ATTACH notification might not even exist any longer when the DLL is unloaded. How can something that doesn’t exist send a notification?

     

    Even so, many people fail to realize this. You can’t do anything with thread affinity in your DLL_PROCESS_ATTACH or DLL_PROCESS_DETACH handler since you have no guarantee about which thread will be called upon to handle these process notifications. Of course, you’re not supposed to be doing anything particularly interesting in your DLL_PROCESS_ATTACH handler anyway, but things with thread affinity are doubly bad.

     

    The classic example of this, which I’m told the Developer Support team run into with alarming frequency, is a DLL that creates a window in its DLL_PROCESS_ATTACH handler and destroys it in its DLL_PROCESS_DETACH handler. Now, creating a window in DllMain is already a horrifically bad idea since arbitrary code can run during the creation of a window (for example, there may be a global hook), but the lack of a thread guarantee makes it downright insane. The DLL calls DestroyWindow in its DLL_PROCESS_DETACH handler, but since that notification comes in on a thread different from the one that received the DLL_PROCESS_ATTACH notification, the attempt to destroy the window fails since you must call DestroyWindow from the same thread that created it.

     

    Result: The DLL’s attempt to destroy its window fails, a message comes in, and the process crashes since the window procedure no longer exists. 

     

    • Like 1

  9. 1 hour ago, alank2 said:

    The attach section works fine.  The Form1 is created and works great.

    Actually, no.  Creating and destroying windows is highly discouraged in DllEntryPoint(), see: Dynamic-Link Library Best Practices:

    Quote

    You should never perform the following tasks from within DllMain:

    • ...
    • Call functions in User32.dll or Gdi32.dll. Some functions load another DLL, which may not be initialized.
    • ...

    Guess where the CreateWindow/Ex() and DestroyWindow() functions reside - in user32.dll !

    1 hour ago, alank2 said:

    If I omit the cleanup in the detach section, no error, but if I include the above I get the 0x0eedfae exception when closing the application that uses the DLL.  Any ideas on why?

    0x0EEDFADE is the exception code when a Delphi exception escapes into the C++ runtime.  So, what exception type exactly is the TForm destructor actually throwing?  My guess is EOSError if DestroyWindow() fails.  But a TForm destruction does a lot of things, so there could be any number of reasons why it would fail while the DLL is in the process of being unloaded from memory.

    1 hour ago, alank2 said:

    Could the Form1 have already been deleted/cleaned up before the DllEntryPoint is called with DLL_PROCESS_DETACH?

    Perhaps, if your DLL's TApplication object were already destroyed (or in the process of being destroyed).  You should run your code in the debugger and verify that.  Your global Form1 variable would not be updated in that situation, so you would have a dangling pointer.  One way to handle that would be to assign NULL to your variable in your Form's destructor.

     

    But really, this is not the kind of stuff that you should be doing in your DllEntryPoint() to begin with.  It would be better to export a couple of functions from your DLL that the loading app can then call after loading the DLL and before unloading it.

    • Like 1

  10. 6 hours ago, MikeMon said:

    Exception Class: EEncodingError

    Exception Message: Invalid code page

    The TMBCSEncoding constructor calls the Win32 GetCPInfo() API to query information about a specified codepage to initialize the TEncoding.MaxCharSize and TEncoding.IsSingleByte properties.  The error means that the specified codepage is likely not installed on the PC.  Unfortunately, the call stack and the error message do not indicate which codepage is failing.  If you have the source code for IBX, have a look at which codepages the CreateEncodings() function is trying to initialize.  Or, maybe the API Monitor can tell you which codepage is being passed to GetCPInfo().

     


  11. 2 hours ago, PH-Bench said:

    Hi, thanks for the answer. I am sure this has to be enabled. Could you direct me to instructions to enable it? Thanks

    You can't just "enable" C++20 in C++Builder's current compilers, as it is NOT IMPLEMENTED in any of them at all - except for the BCC64X preview compiler, in which case the page I linked you to earlier tells you how to "enable" it. 


  12. 5 hours ago, Rollo62 said:

    That would mean, that this tool "compiles" the code and is able to calculate the contents of the variable "foo".

    Or, more simply, just detect a function call involving an "array of const" argument preceded by a string argument, and then warn if the string argument is not a literal.

    • Like 1

  13. 2 hours ago, Der schöne Günther said:

    Everything VCL related must happen in the main thread. Do not access VCL elements, don't even create and destroy something like a VCL Bitmap or Canvas in a thread.

    FYI, you can create and use a VCL TBitmap in a worker thread, you just have to lock the bitmap's Canvas to prevent the main thread from releasing the bitmap's GDI resources.

    38 minutes ago, Uwe Raabe said:

    Indeed there are: Set

    
    TControl.RaiseOnNonMainThreadUsage := True

    The new TControl.RaiseOnNonMainThreadUsage property was introduced in 11.0 Alexandria:

     

    https://docwiki.embarcadero.com/RADStudio/Alexandria/en/What's_New#Threading_safety_improvement

     

    However, it is currently only being used by the VCL when a TWinControl's window is created, not when it is accessed.  Fortunately, there is a new TControl.CheckNonMainThreadUsage() method that is public, so you can call it for your own purposes before you access a UI control's members.

    • Thanks 1

  14. 20 hours ago, PH-Bench said:

    can I update C++ Builder to use C++ 20 so that I can run lines like that without error?

    No, you cannot update the compiler. C++Builder simply does not support C++20 at this time, only up to C++17.  Although, the BCC64X 64bit preview compiler does have partial support due to using Clang 15, whereas the other compilers in C++Builder do not as they are still using older Clang versions:

     

    https://stackoverflow.com/questions/77456540/does-cbuilder-12-0-support-c20-modules

     

    However, you can use the 3rd party {fmt} library, which implements many of C++20's formatting capabilities in pre-20 versions of C++:

     

    https://fmt.dev

    https://github.com/fmtlib/fmt


  15. 5 hours ago, Attila Kovacs said:

    (On a side note, you also don't need a semicolon if the next word is "end". If it's known, just ignore me.)

    That is not a bug, but a feature of the Pascal language.

     

    More formally, inside a block ('begin..end' or 'repeat..until'), a semicolon is a statement separator, not a statement terminator, unlike with other languages. The last statement in a block is never terminated by a semicolon. If you write a semicolon, then the last statement will be an "empty" statement.

     

    Another quirk of Pascal requires a semicolon to be omitted when an 'if..else' is inside of a 'case of..else' to avoid ambiguity over which statement the 'else' belongs to:

     

    https://stackoverflow.com/questions/7574603/why-do-single-statement-blocks-require-not-using-semi-colons

    • Like 2

  16. On 3/18/2025 at 7:59 AM, FabDev said:

    Yes all updates are installed in Delphi 12.2 (Getit doesn't find anymore update).

    I asked Embarcadero about the error and they said this:

    Quote

    ... all installing patch1 did was to download the installer.

    So, "installing" the 12.2 Patch 1 from GetIt merely downloaded the installer, but did you actually run it?  The build version should have been updated from 29.0.53571.9782 -> 29.0.53982.0329 if the patch was actually installed.

     

    They also said:

    Quote

    ... when we compare System.Threading.pas from original/initial 12.2 w/ the version from the inline release of 12.2. The svn diff shows this:

    
    Index: System.Threading.pas
    ===================================================================
    --- System.Threading.pas	(.../RAD-Studio-Yukon-120-Update2/runtime/rtl/common/System.Threading.pas)	(revision 122139)
    +++ System.Threading.pas	(.../RAD-Studio-Yukon-120-Update2.inline/runtime/rtl/common/System.Threading.pas)	(revision 122139)
    @@ -862,7 +862,6 @@
         FForThreshold: NativeInt;
         FSortThreshold: NativeInt;
       private
    -    class constructor Create;
         class procedure CheckArrayRange(ALow, AHigh, AIndex, ACount: NativeInt); static;
         class function ForSlice(AValues: Pointer; AHigh: NativeInt; const AProc: TInternalForProc;
           AFrom, ATo: NativeInt; APool: TThreadPool): ITask; static;

    IOW, the original 12.2 had added the class constructor (which in itself was interface-breaking). The inline release of 12.2 eliminated that class constructor. So:

    1. Plugins built w/ the original 12.2 will refer to the class constructor.
    2. Plugins built w/ the inline 12.2 will not refer to the class constructor, as it was removed.

    Any plugin that’s looking for @system@Threading@TParallelArray@$bcctr$qqrv was built w/ the original 12.2 release (i.e. 29.0.53571.9782).

    The TParallelArray class constructor was added in the original 12.2 release, but was removed in the 12.2 inline patch.  So, if your package is referring to the constructor after installing 12.3 then it was compiled with the un-patched build of 12.2.


  17. 5 hours ago, CoeurdeLeon said:

    Can 12.2 and 12.3 exist on the same machine

    No. 12.3 is a minor point update in the 12.x series, so you have to remove 12.2 when installing 12.3. Only different major versions can coexist.


  18. 53 minutes ago, patmandin said:

    I came across code that may open both a TIdIMAP4 and a TIdSmtp at the same time, but that shares the same TIdSSLIOHandlerSocketOpenSSL component for dealing with SSL stuff.

     

    Is it something that works (i.e. each component that uses it will create and get its own SSL work context)

    No.  A single IOHandler object (of any type, SSL or otherwise) cannot be shared by multiple active connections at the same time.  Each connection needs its own unique (SSL)IOHandler object while it is connected to a peer.

    53 minutes ago, patmandin said:

    or is it a potential source of bugs (if each component that uses it overwrites what the other is doing) ?

    Yes.  Each (SSL)IOHandler is associated with a single data transport (such as a socket), and a single set of buffers for incoming and outgoing data.


  19. 2 hours ago, Squall_FF8 said:

    It is very strange to me, that Delphi doesnt support png. You can add ico, which is like png without compression.

    I didn't say Delphi doesn't support PNG.  I said TImageList doesn't support PNG.  Internally, TImageList is based on the Win32 IMAGELIST control, which supports only BMP and ICO images.

    2 hours ago, Squall_FF8 said:

    I hoped in latest version they will fix this, but alas, no (most likely never, no interest in it).

    They can't "fix this" as it is a Win32 limitation.  They worked around it (amongst other reasons) by creating TImageCollection and TVirtualImageList to replace the old TImageList:

     

    Supporting high-DPI images with the Image Collection and Virtual ImageList components

    2 hours ago, Squall_FF8 said:

    BTW by "floating", are you referring to "PngComponents" accessible trough Getit?

    Probably, yes.

×