Jump to content

Remy Lebeau

Members
  • Content Count

    2633
  • Joined

  • Last visited

  • Days Won

    109

Everything posted by Remy Lebeau

  1. Remy Lebeau

    Possible bug in debugger for Delphi 10.3.1

    Because this is NOT a change in the debugger itself! It is a change in the implementation of the class that you are trying to debug. TWO DIFFERENT THINGS. Just because you can't see the data anymore doesn't mean it is "broken". It just means the data is abstracted away and hidden from you.
  2. Remy Lebeau

    A directory translate

    Like I said, use the Shell Library API for that. See Windows Libraries and Using Libraries in your Program for more details. You don't need to repeat yourself. You made yourself perfectly clear the first time you said that.
  3. Remy Lebeau

    A directory translate

    When working with Libraries, you should use the IShellLibrary interface to query them. However, in this particular example, the correct way to get the path to the user's Pictures folder is to use SHGetFolderPath(CSIDL_MYPICTURES) or SHGetKnownFolderPath(FOLDERID_Pictures) instead. LShellItem can't be nil if SHCreateItemFromParsingName() returns success.
  4. Remy Lebeau

    Check for override

    Perhaps. It was so long ago, we don't know what their actual thinking was. Such a change would break existing implementations, forcing rewrites. It was probably the lesser of two evils at the time to introduce the overload to maintain compatibility rather than force people to update their code. Of course, the issue wasn't helped when a 3rd Seek overload was added in XE4, causing ambiguity errors under OSX/iOS 64bit for user code that was never updated to use the original overload added in D6. Speaking from experience, I'm in a similar boat right now, where I have to update a legacy product with a huge codebase to migrate it from using 32bit ints to 64bit ints, and it is going to be a MAJOR undertaking, affecting databases and external APIs, and requiring rewrites of internal logic in various places. Who would have thought 20 years ago that our customer data would ever need to exceed the limits of 10 digit integers, but it has for some time now and we have worked around the problem over the years by truncating data in various ways to maintain compatibility, instead of redesign the system. We finally looked at a redesign awhile ago, but all of our team members have been let go or moved to other teams before it was viable. Now a redesign is being looked at again and I'm the only one left to work on it. So, it is not always an easy task to replace code rather than overload code.
  5. Remy Lebeau

    Check for override

    It was done this way for backwards compatibility when TStream was first updated to support 64bit streams. Since all implementations and uses of TStream were based on 32bit operations at the time (to this day, some TStream implementations are still 32bit only - ahem, TMemoryStream), when the new 64bit Seek was added, nobody overrode it yet, so it would call the 32bit Seek by default so existing implementations would still work. Once a stream class was updated to override the 64bit Seek instead of the 32bit Seek, the 32bit Seek would then call the 64bit Seek by default, thus still maintaining compatibility with existing code. The 32bit Seek checking if the 64bit Seek is overriden before calling it is just a safety catch to avoid a recursive loop should an implementation make the mistake of not overriding either version of Seek correctly.
  6. Remy Lebeau

    Check for override

    The Spring4D approach uses roughly the same principle - comparing the base method and derived method to see if they are located at the same memory address or not - but it goes about doing so in a very different and more intrusive manner. It manually looks for the base method address in the base class's vtable to get the method's index within the vtable, and then it retrieves the address stored in the vtable of the derived class at the same index, and then compares the two addresses. The Seek() approach is cleaner in that it lets the compiler deal with the vtable details.
  7. Remy Lebeau

    Check for override

    To expand on Anders' comment - the TStream.Seek() method has two overloads, one for 32-bit seeks and one for 64-bit seeks. By default, the 32-bit Seek() calls the 64-bit Seek() and vice versa. Descendants must override one of the Seek() methods and the override must not call the inherited method. To avoid an endless recursive loop, the 32-bit Seek() validates that the 64-bit Seek() method has been overridden before calling it. This is the technique that it uses for that validation: procedure TAncestor.Do(); type TMethodXType = procedure of object; // must match the signature of MethodX... var Impl: TMethodXType; Base: TMethodXType; ClassTAncestor: TClass; begin Impl := MethodX; // points to descendant's implementation of MethodX... ClassTAncestor := Self.ClassType; // get object's actual class type... while (ClassTAncestor <> nil) and (ClassTAncestor <> TAncestor) do // find the TAncestor base class... ClassTAncestor := ClassTAncestor.ClassParent; Base := TAncestor(@ClassTAncestor).MethodX; // points to TAncestor's implementation of MethodX... if TMethod(Impl).Code = TMethod(Base).Code then // which MethodX implementation is the object actually using? begin // MethodX is NOT overriden... end else begin // MethodX IS overriden... end; end;
  8. Remy Lebeau

    Using dxgettext on Windows 10

    I also find that annoying. If you click on the quote, an X appears in the top-left corner, then click on that and hit backspace or delete, and SOMETIMES that works, but rarely. In fact, I'm not very impressed with how this site behaves in a mobile browser overall, which sucks because I spend more time lately using mobile browsers than desktop browsers when visiting various support forums. If I try to select more than a few words of text at a time, the selection jumps all over the place, which makes quoting and copy/pasting near impossible. And I can't insert code blocks, there is no option for that in the editor toolbar, like there is in a desktop browser. And it took me forever to find the "Mark site read" option in the mobile site, I finally found it in the top-level menu bar, but think it would make more sense for it to be in the "Activity" section next to "Unread content", not in the "Account" section.
  9. Remy Lebeau

    Compiling code originally for VS in C++Builder

    Works fine for me. The extern "C" has nothing to do with the exporting itself, that is handled by the __declspec. The extern "C" simply disables name mangling on the exported name. I've never had to resort to that. But then again, I've never tried linking to 3rd party static .lib files that are not already compatible with C++Builder, and import .lib files for DLLs are easy to regenerate using C++Builder's implib.exe.
  10. Remy Lebeau

    Using dxgettext on Windows 10

    I can think of one reason: System.UTF8ToUnicode(), and its companion System.UnicodeToUTF8(), were broken or more accurately incomplete in Delphi 6-2007, as they did not support 4-byte UTF-8 sequences (Unicode codepoints outside of the BMP), only 1-3 byte sequences (Unicode codepoints in the BMP) . That was not fixed until Delphi 2009, when they were rewritten to use platform conversions instead of manual conversions. Now granted, at the time, 4-byte UTF-8 sequences were pretty rare, typically only seen in strings using Eastern Asian languages. But in modern Unicode, they are much more common now, especially with the popularity of emojis on the rise, most of which use high codepoint values outside the BMP.
  11. UTF8String was first introduced in Delphi 6 (but it did not become a true UTF-8 string until Delphi 2009). Delphi 6 has the following UTF8 <-> UTF16 functions in the System unit: function UnicodeToUtf8(Dest: PChar; Source: PWideChar; MaxBytes: Integer): Integer; overload; deprecated; function Utf8ToUnicode(Dest: PWideChar; Source: PChar; MaxChars: Integer): Integer; overload; deprecated; function UnicodeToUtf8(Dest: PChar; MaxDestBytes: Cardinal; Source: PWideChar; SourceChars: Cardinal): Cardinal; overload; function Utf8ToUnicode(Dest: PWideChar; MaxDestChars: Cardinal; Source: PChar; SourceBytes: Cardinal): Cardinal; overload; function UTF8Encode(const WS: WideString): UTF8String; function UTF8Decode(const S: UTF8String): WideString; Do note, however, that these functions did not support 4-byte UTF-8 sequences (Unicode codepoints outside of the BMP), only 1-3 byte sequences (Unicode codepoints in the BMP). That was not fixed until Delphi 2009, when they were rewritten to use platform conversions instead of manual conversions. Now granted, at the time, 4-byte UTF-8 sequences were pretty rare, typically only seen in strings using Eastern Asian languages. But in modern Unicode, they are much more common now, especially with the popularity of emojis on the rise, most of which use high codepoint values outside the BMP.
  12. Like the events of most other components, the events of Indy components expect class methods, not standalone functions. You could go the way that others have recommended, where creating a TDataModule at design-time and using it at run-time would be the easiest. But, even if you were to simply write a class in code to wrap the events, note that you don't actually need to instantiate such a class at run-time, you can declare its methods with the class directive instead, eg: program IndyConsoleApp; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, IdContext, IdBaseComponent, IdComponent, IdCustomTCPServer, IdTCPServer, IdGlobal; var IdTCPServer1: TIdTCPServer; procedure ShowStartServerdMessage; begin WriteLn('START SERVER @' + TimeToStr(now)); end; procedure StopStartServerdMessage; begin WriteLn('STOP SERVER @' + TimeToStr(now)); end; type TCPServerEvents = class class procedure OnExecute(AContext: TIdContext); end; class procedure TCPServerEvents.OnExecute(AContext: TIdContext); var LLine: String; begin LLine := AContext.Connection.IOHandler.ReadLn(); writeln(LLine); AContext.Connection.IOHandler.WriteLn('OK'); end; begin try IdTCPServer1 := TIdTCPServer.Create; try with IdTCPServer1.Bindings.Add do begin IP := '127.0.0.1'; Port := 6000; end; IdTCPServer1.OnExecute := TCPServerEvents.OnExecute; IdTCPServer1.Active := True; try ShowStartServerdMessage; Readln; finally IdTCPServer1.Active := False; StopStartServerdMessage; end; finally IdTCPServer1.Free; end; except on E: Exception do WriteLn(E.ClassName, ': ', E.Message); end; end. However, there IS actually a way to use a standalone function instead, but it involves a little trickery using Delphi's TMethod record: program IndyConsoleApp; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, IdContext, IdBaseComponent, IdComponent, IdCustomTCPServer, IdTCPServer, IdGlobal; var IdTCPServer1: TIdTCPServer; procedure ShowStartServerdMessage; begin WriteLn('START SERVER @' + TimeToStr(now)); end; procedure StopStartServerdMessage; begin WriteLn('STOP SERVER @' + TimeToStr(now)); end; procedure TCPServerExecute(ASelf: Pointer; AContext: TIdContext); // NOTE THE EXTRA PARAMETER! var LLine: String; begin LLine := AContext.Connection.IOHandler.ReadLn(); WriteLn(LLine); AContext.Connection.IOHandler.WriteLn('OK'); end; var ExecuteFct: TMethod; begin try IdTCPServer1 := TIdTCPServer.Create; try with IdTCPServer1.Bindings.Add do begin IP := '127.0.0.1'; Port := 6000; end; ExecuteFct.Data := nil; // or anything you want to pass to the ASelf parameter... ExecuteFct.Code := @TCPServerExecute; IdTCPServer1.OnExecute := TIdServerThreadEvent(ExecuteFct); IdTCPServer1.Active := True; try ShowStartServerdMessage; Readln; finally IdTCPServer1.Active := False; StopStartServerdMessage; end; finally IdTCPServer1.Free; end; except on E: Exception do WriteLn(E.ClassName, ': ', E.Message); end; end.
  13. Remy Lebeau

    Who is doing MacOS app with RadStudio for clients ?

    Yes. The OSX 64bit compiler is still in development and is scheduled to be released sometime in a future 10.3.x update.
  14. Remy Lebeau

    best practise sharing : 2 buttons with mrOK on a form

    There is no way to differentiate which control set the ModalResult if they both set it to the same value. ShowModal() will close the Form when any non-zero value is assigned to ModalResult, you are not limited to the handful of constants that the RTL defines, use whatever values you want.
  15. Remy Lebeau

    Compiling code originally for VS in C++Builder

    You appear to be mixing C/C++ and Delphi syntaxes. It should be: extern "C" __declspec(dllexport) int Load(PDLLLINK pLink); Or: extern "C" int __declspec(dllexport) Load(PDLLLINK pLink);
  16. Remy Lebeau

    Compiling code originally for VS in C++Builder

    Those modifiers can be applied directly to the function declaration. But, are you referring to a VS static library that you want to link inside your C++Builder DLL? Or are you referring to the import lib that the C++Builder compiler outputs in addition to the DLL? I'm confused about your setup and what you are trying to accomplish exactly.
  17. Remy Lebeau

    Compiling code originally for VS in C++Builder

    I rarely use .DEF files in my C++Builder DLLs, I prefer to use 'extern "C"' and __declspec(dllexport) in the DLL's source code instead. .DEF files are good when you need custom control over how exports are name-mangled and/or assigned ordinal values. In most cases, that is not necessary. I have never seen that error before, and the only reference to it I find online is this: https://stackoverflow.com/questions/5707046/ However, I have never upgraded my C++Builder to a version that is based on MSBuild, either. I still use C++Builder 6.
  18. Remy Lebeau

    Compiling code originally for VS in C++Builder

    bcc32c is the CLang-based Windows 32bit compiler. What you are seeing is a CLang error message. See Stricter C++ Compilers (Clang-enhanced C++ Compilers): Token Pasting in Embarcadero's documentation. Also, I don't think __VA_ARGS__ will work in this situation, as that would pass FuncName as the first parameter to FuncName(). I'm sure Hpc_Trace_AddClassId() does not expect Hpc_Trace_AddClassId as its first parameter value. In the Project Options, in the C++ Compiler section, there is a "Use 'classic' Borland compiler" option.
  19. Remy Lebeau

    Delphi inline and function evaluation

    Why does that surprise you? ANY compiler worth its salt will perform optimizations, especially when dealing with inline functions, and would be smart enough to recognize when basic arithmetic operations are being performed on compile-time literals and just output code for the result of those operations at compile-time instead of generating code to perform those operations at runtime. "5 > 9" is ALWAYS false, so the compiler can just output False instead of outputting code to compare 5 to 9. And "if False Then" will ALWAYS skip the IF block and jump to the ELSE block. so the compiler can ignore any of the code in the IF block. As such, your call to Max(5, 9) gets optimized to simply "Result := 9" when inlined, and so the compiler can simply replace the entire call to Max(5, 9) with just the literal 9.
  20. Remy Lebeau

    Compiling code originally for VS in C++Builder

    What kind of errors exactly? Also, which version of C++Builder are you using? Which of its many C++ compilers specifically are you using? Are you using a compiler that is compatible with the C++ version that the VS code is targeting? That would imply that the .lib file is probably a static library instead of an import lib for a DLL. If the VS project is for a static library rather than a DLL, then compiling it as a DLL may not be helpful since its code would likely not be setup to export symbols that IMPLIB could find.
  21. Remy Lebeau

    OverbyteIcscryptuiapi.h what is it for?

    I think such an HPPEMIT statement should not be needed at all. Delphi .PAS files output .HPP files, not .H files, when compiled for C++Builder, and there is no need for a .PAS file to ever HPPEMIT a reference to its own .HPP file.
  22. I can confirm the semicolons are required, in ALL C++ versions and compilers. Typedef statements need to be terminated by a semicolon, just like any other statement in C++.
  23. Indy has a similar issue, having dozens of packages that have to be updated whenever units are added/removed, and new packages that have to be created when new compilers are released. To help with this task, we created an internal project that has a database of active units and flags to dictate their behavior, and it can generate the various package files, resource files, etc for each compiler version we support. This way, when we do make changes to the units, we simply update the database and regenerate the packages. And when a new compiler is released, we can generate new package files for it. Indy works in C++Builder, but doesn't have any C++ project files, only Delphi project files. For C++, we simply compile the Delphi projects configured with C++ output enabled.
  24. Remy Lebeau

    Communication between processes (IPC)

    Another alternative for IPC on a single computer is the WM_COPYDATA message, see Using Data Copy. Network DDE across multiple computers is no longer supported, but Local DDE on a single computer is still supported.
  25. Remy Lebeau

    TIdSSLIOHandlerSocketOpenSSL and TLS 1.3 ?

    The link that Lars provided is a year old, but the answer is still the same. Indy does not yet support OpenSSL 1.1+, and so does not yet support TLS 1.3. It is in the planning stage, no code has been written yet: https://github.com/IndySockets/Indy/issues/183
×