-
Content Count
3060 -
Joined
-
Last visited
-
Days Won
139
Everything posted by Remy Lebeau
-
All true. Understood. Because they bundle Indy pre-installed in every IDE release, and most users are more comfortable using the pre-installed version than going to SVN/GitHub to manually install a newer version. And because Embarcadero uses a private copy of Indy for their internal technologies that is not always separated properly from the public version, and so can cause conflicts with user-installed versions of Indy. And because Embarcadero does not update their shipped/private copies of Indy on every IDE release (although they did for 10.4). So making breaking interface changes (which I sometimes do, but I try to keep it minimal) in the public version of Indy is not always possible/feasible, without causing more trouble than it solves. That being said, my ultimate goal (which I have no ETA on) is to 1) get Indy 11 finished and released; 2) get Indy into GetIt; 3) maybe not have Embarcadero ship Indy with the IDE anymore, in favor of GetIt (if it works out). Once in awhile, Embarcadero contribute bug fixes (and occasionally ships breakages without me having reviewed their changes first). That is about it. Yes, of course Embarcadero, being the IDE/compiler vendor, doesn't have to care about their bundled 3rd party packages being backwards compatible, but of course Indy, as the 3rd party code, has to worry about that. Which sucks doubly so for me personally, because several times in the past few years, I have suffered total system losses (mostly due to hardware failures) that have lost me my main dev machine and backups, so most of my personal projects are gone, as well as most of my RADStudio VMs (and the ones that are left are expired betas). I borrowed a family member's laptop to carry on, but have no dev tools installed on it, So while I can make edits to source code in Notepad, I can't compile anything. And, to be quite frank, I just don't have the time or energy to try to setup a new dev environment right now. So, I do what I can with what I have to work with, but I know it is not good enough long term.
-
Have you tried saving the value of the Text property before changing the WordWrap property, and then re-assign the Text property afterwards?
-
Remove non-utf8 characters from a utf8 string
Remy Lebeau replied to borni69's topic in Algorithms, Data Structures and Class Design
What kind of crash exactly? This implies to me that you are not creating your JSON properly to begin with. Can you please show your actual code that is taking in user input and producing JSON from it? There is no way for us to tell you that, because you have not shown what you are actually doing yet. -
Indy is not the only 3rd party component suite that doesn’t. What you are referring to is the LIBSUFFIX feature. And yes, Indy has not been updated yet to use LIBSUFFIX. That is on the TODO list for Indy 11 (https://github.com/IndySockets/Indy/issues/133), which is planned to include other package improvements, like reorganizing the source folders, simplifying the installation process, etc. The main reason why Indy does not use LIBSUFFIX yet is that I simply don’t have the free time to update all of the existing packages for all of the supported IDE versions, and no way to test such a change is working properly across multiple IDE versions (I’m the only volunteer left writing code for Indy, and I don’t really appreciate your blog calling me sloppy over this issue). But also, because Indy 10 predates when LIBSUFFIX usage became common, and because Indy is bundled with the IDE, so changing the package names will break existing projects. That is why I’ve been waiting for Indy 11 (or at least for a time when I am able to slip this change in between major IDE releases, when Embarcaderom is open to ship such a breaking change).
-
Remove non-utf8 characters from a utf8 string
Remy Lebeau replied to borni69's topic in Algorithms, Data Structures and Class Design
Then it seems to me that you are approaching this from the wrong angle. If the frontend is UTF-8, then it doesn't matter what the client enters, it will get transmitted as UTF-8, and stored as-is in the DB as UTF-8, and converted between UTF-8<->UTF-16 where needed. Both UTFs handle the entire Unicode repertoire without any data loss. So your issue has to be somewhere else. Either you are not processing your JSON correctly, or you are not sending the JSON back to the client correctly. You really should not be filtering out ANY characters at all, especially since UTFs and JSON support ALL Unicode characters. So I suggest you take some more time to really debug the issue deeper and find out exactly where the REAL failure point is, because it is likely not what you think it is. Which is perfectly fine, if the UI frontend and communication/DB backends are all using UTF-8 properly. The issue has to be somewhere else. Don't remove any characters at all. -
Remove non-utf8 characters from a utf8 string
Remy Lebeau replied to borni69's topic in Algorithms, Data Structures and Class Design
Agreed, that is odd to allow that range but not allow 161..255 as well. Certainly in Unicode strings, characters in the 0..255 range are well-defined. But in ANSI/MBCS strings, characters in the 128..255 (Extended ASCII) range are locale-specific. The numeric values of characters in that range vary between what Unicode defines and what different locales/charsets define. Most locales/charsets agree with Unicode only for characters in the 0..127 (ASCII) range, then they define whatever they need for characters 128..255. Beyond character 255, you need Unicode instead. Unicode codepoints #127..#160 (U+007F..U+00A0) are certainly valid in UTF-16, yes. But locale-based characters in the #128..#255 ($80..$FF) range in ANSI/MBCS strings usually map to different numeric values as Unicode codepoints. -
Which is exactly why you shouldn't rely on it. It depends on internal implementation details that could change one day in the future. Better to be explicit about the calculations so that if the implementation ever does change then the result will still work as expected.
-
https://quality.embarcadero.com/browse/RSP-31118
-
Yes. This is clearly stated in the release notes: http://docwiki.embarcadero.com/RADStudio/Sydney/en/10.4_Sydney_-_Release_1
-
My app only deals with local files, not remote files. It accesses the file data using memory-mapped views, which are not coherent over remote connections. I hear what you are saying, but honestly that hasn't been an issue for my app yet. But I can see how PIDLs would not work for those.
-
In that case, yes, without some degree of parsing the path components and mapping them to something real to see if they map the same. Yes, it does. I've been using it for years. I have an app that displays files, tracking their PIDLs. If the user tells the app to open a new file, and its PIDL is already open, I jump to the existing display instead. It works just fine. It may not be the BEST approach, but it works. When I first wrote the code. the only approach I knew about was to convert both paths to their short 8.3 form and then do a simple string comparison. I later found the PIDL approach to be much more reliable, so that is what the app uses now. Later, I learned about the GetFileInformationByHandle() approach, but I never got a chance to update the code. So? The filesystem is part of that. Filesystem paths can be converted to PIDLs, the filesystem shell provider will map the folder and file components accordingly. Get the IShellFolder interface for the root Desktop namespace, pass both filesystem paths to its ParseDispayName() method (short paths, long paths, it doesn't matter), and it will ask the filesystem to parse them and provide absolute PIDLs, which will compare equal if they refer to the same file. Trust me, it works, I use it.
-
UCS4StringToWideString broken?
Remy Lebeau replied to A.M. Hoornweg's topic in RTL and Delphi Object Pascal
Not obvious to other people who are not familiar with UCS4String and how it works. It is not a common type most people work with. Agreed. Just like a lot of things in the documentation (or lack of). Sure, for purposes of just iterating and accessing characters, such as during conversions. I stated earlier why it exists at all - mainly so PUCS4Char() typecasts will be null-terminated. That allows the array to act more like a C-style string, just like native string types do. Of course, obviously. -
UCS4StringToWideString broken?
Remy Lebeau replied to A.M. Hoornweg's topic in RTL and Delphi Object Pascal
Yes, exactly. UCS4String predates Delphi 2009, it was first introduced in Delphi 6 alongside UTF8String, which at the time was just an alias for AnsiString. In Delphi 2009, when AnsiString became codepage-aware and UTF8String became a true UTF-8 string type, UCS4String did not become a true UCS-4 string type, it remained a plain dynamic array. Since the D2009+ version of the StrRec record supports characters of varying byte sizes, I've asked for UCS4String to be changed into a true string type using 4-byte chars, backed by the same RTL logic that handles AnsiString(N) and UnicodeString, but that never happened. -
UCS4StringToWideString broken?
Remy Lebeau replied to A.M. Hoornweg's topic in RTL and Delphi Object Pascal
That is not a bug, actually. That is intentional behavior. UCS4String is not a native RTL string type, like (Ansi|Unicode|UTF8|Wide)String are. It is just a plain ordinary dynamic array of UCS4Char: type UCS4Char = type LongWord; UCS4String = array of UCS4Char; So, for compatibility with APIs that take C-style strings, a UCS4String has an explicit #0 element at the end, so that PUCS4Char() typecasts are null-terminated the same way that P(Ansi|Wide)Char() typecasts on other string types are. As such, functions that output a UCS4String are required to allocate +1 for the null terminator, and functions that take a UCS4String as input are required to ignore the last element expecting it to be the null terminator. The code is pre-allocating the output WideString to the maximum number of UTF-16 codeunits that MAY be produced, which is the total number of UTF-32 codepoints minus the null terminator, multiplied by 2 (in case EVERY codepoint needs a UTF-16 surrogate pair). Then the code fills the WideString with actual UTF-16 codeunits, and then finally resizes the memory to the actual number of WideChars produced, not including a null terminator. -
Remove non-utf8 characters from a utf8 string
Remy Lebeau replied to borni69's topic in Algorithms, Data Structures and Class Design
That makes no sense, as JSON handles the entire Unicode repertoire. ANY Unicode character can appear in JSON. ALL Unicode characters except for the first 31 ASCII control characters (U+0000..U+001F), " (U+0022), and \ (U+005C) can appear in an unescaped form. ALL Unicode characters can appear in an escaped form. -
Yes, it is. In fact, there are several way to do exactly that. For example, parse the 2 paths into absolute PIDLs, and then see if they compare equal. Or, open the files, retrieve their volume serial numbers and file identifiers with GetFileInformationByHandle/Ex(), and see if they compare equal.
-
Actually, it doesn't, because as I said earlier, FormatDateTime() simply isn't intended to handle a duration between 2 date/time values like are you using it for. If you don't want to (or cannot) use TTimeSpan, then you should calculate the necessary components manually, eg: var // TS: TTimeSpan; StartDateTime, FinishDateTime: TDateTime; Days, Hours, Minutes, Seconds: Int64; begin StartDateTime := FieldByName('StartDateTime').AsDateTime; FinishDateTime := FieldByName('FinishDateTime').AsDateTime; { TS := TTimeSpan.Subtract(FinishDateTime, StartDateTime); FieldByName('Duration').AsString := Format('%.3d:%.2d:%.2d:%.2d', [TS.Days, TS.Hours, TS.Minutes, TS.Seconds]); } Seconds := SecondsBetween(FinishDateTime, StartDateTime); Days := Seconds div SecsPerDay; Seconds := Seconds mod SecsPerDay; Hours := Seconds div SecsPerHour; Seconds := Seconds mod SecsPerHour; Minutes := Seconds div SecsPerMin; Seconds := Seconds mod SecsPerMin; FieldByName('Duration').AsString := Format('%.3d:%.2d:%.2d:%.2d', [Days, Hours, Minutes, Seconds]); end;
-
FormatDateTime() and other related functions are meant for formatting a specific date/time, not formatting a duration between 2 date/times. You are going to have to format a duration manually, like Der showed using TTimeSpan.
-
Best way to prevent multiple instances? Mutex not working
Remy Lebeau replied to bilbo221's topic in VCL
No, it won't. SeCreateGlobalPrivilege applies only to file mapping objects, not to mutexes. Anyone can create a mutex in the Global namespace. See https://stackoverflow.com/a/41370046/65863 I see no mention of this anywhere in this discussion before your comment. -
Getting Stream read error on really simple program
Remy Lebeau replied to Mr. Daniel's topic in RTL and Delphi Object Pascal
You are not resetting the ms1.Position property back to 0 after calling ms1.CopyFrom(fs, fs.Size) and before calling ms2.CopyFrom(ms1, ms1.Size). After ms1.CopyFrom() is done reading from the TFileStream, ms1.Position is at the end of the stream, it is not reset back to 0 automatically. You are then asking ms2 to read ms1.Size bytes from the end of the ms1 stream, hence the error. Calling TStream.CopyFrom() with its Count parameter set to <= 0 will reset the source TStream.Position to 0 and read all of the source TStream's bytes. But you are not doing that, you are setting the Count parameter to the source TStream.Size instead, so CopyFrom() will read from the source TStream's current Position, and fail if the requested number if bytes is not read successfully.- 5 replies
-
- stream
- tmemorystream
-
(and 1 more)
Tagged with:
-
Correct. Andreas has already gone on record stating that he no longer has a license to paid versions of RADStudio and so will not be able to update IDEFixPack for new IDE versions without their Community Editions. And Embarcadero has already gone on record stating that releasing a 10.4 Community Edition has been delayed, with no ETA stated as of yet.
-
Best way to prevent multiple instances? Mutex not working
Remy Lebeau replied to bilbo221's topic in VCL
A simple mutex will work fine in those cases if you create the mutex in the 'Global\...' namespace so it exists across account/session boundaries. See Kernel Object Namespaces. -
What is the TApplication.MainFormOnTaskbar property set to? If MainFormOnTaskbar is True, then minimizing the MainForm will minimize the MainForm window to the Taskbar. In which case, checking TForm.WindowState or IsIconic(MainForm.Handle) should work. But if MainFormOnTaskbar is False, then minimizing the MainForm will hide the MainForm window and minimize the TApplication window to the Taskbar. In which case, checking IsIconic(Application.Handle) should work.
-
Help needed. Re-raising exception gives AV.
Remy Lebeau replied to a topic in RTL and Delphi Object Pascal
Sure, if you want code higher up on the call stack to catch and handle the original exception as-is. But there are use-cases where it makes sense to raise a new exception instead, in which case you should use the Exception.RaiseOuterException() method so that you can capture the original exception in the InnerException of the new exception so that it is not lost if the higher code needs it. -
Blocking the Windows Screen Saver in Delphi
Remy Lebeau replied to dummzeuch's topic in Tips / Blogs / Tutorials / Videos
That is because Win32 structures do not use 1-byte alignment, they use 8-byte alignment. See What structure packing do the Windows SDK header files expect?