-
Content Count
1090 -
Joined
-
Last visited
-
Days Won
23
Posts posted by aehimself
-
-
Hello,
I am in the process of verifying if we can update our environment to use Delphi 11.2 instead of the current 10.4.2. However compilation was successful, even the very basic tests failed because of an incorrect date format detected by Delphi.
Reproduction is really easy, just execute a single line:
TFormatSettings.Create(1038);
Result on Delphi 11.2:
On 10.4.2:
So 11.2 correctly detects the date separator as "." in the locale, however the very next line will call this method, which will replace all separators with a forward slash instead:
procedure FixDateSeparator(var DateFormat: string); var P: PChar; InsideLiteral: Boolean; begin InsideLiteral := False; P := PChar(DateFormat); if P = nil then Exit; while P^ <> #0 do begin if P^ = '''' then InsideLiteral := not InsideLiteral; if (P^ = Separator) and (not InsideLiteral) then P^ := '/'; Inc(P); end; end;
So because 10.4.2 could not detect the separator, it returns the correct date format. 11.2 detects the separator, ruining the date format instead. The WinAPi definition is the same, buffer is different in the implementation:
function GetLocaleInfo; external kernel32 name 'GetLocaleInfoW'; // Delphi 10.4.2 MSWindows implementation function GetLocaleChar(Locale, LocaleType: Integer; Default: Char): Char; var Buffer: array[0..1] of Char; begin if GetLocaleInfo(Locale, LocaleType, Buffer, 2) > 0 then Result := Buffer[0] else Result := Default; end; // Delphi 11.2 MSWindows implementation function GetLocaleChar(Locale, LocaleType: Integer; Default: Char): Char; var Buffer: array[0..2] of Char; begin if GetLocaleInfo(Locale, LocaleType, Buffer, 3) > 0 then Result := Buffer[0] else Result := Default; end;
I can not wrap my head around this. I believe it should be a faulty FixDateSeparator implementation, as it makes no sense to change the correct separators to incorrect ones based on the selected locale.
Is this an issue in Delphi and I should raise a ticket or maybe I'm missing something...?
-
MyFileSourceSize := MyFileStreamSource.Size;
Is unnecessary, MyFileSourceSize.Size - MyFileSourceSize.Position will always return the unprocessed bytes.
MyFileStreamSource.Read(MyBuffer[0], MyBufferSize); // read and put on the next position...
Make sure you also check if .Read returns MyBufferSize. Otherwise you will have "rouge" data what you will write back to the destination, effectively corrupting the output.
Also, the pseudocode above won't handle data, which is interrupted by the end of a buffer.
-
9 minutes ago, robertjohns said:It is 32 bit and the file size is 3GB
a 32 bit process can allocate a total of 2 GBs of RAM (or 3 if it's large address aware). Loading 3 GBs of data in the memory would use that up by itself, leaving no room for anything else (like the TMemoryStream class or any other variables). So it is expected.
As @PeterBelow advised, build a 64 bit executable, or use FileStreams instead of loading everything in the memory.
-
As a general rule of thumb, never call Application.ProcessMessages by yourself. Let your thread "ping" back with updates from time to time with TThread.Synchronize, you can even have a TTimer in your VCL thread to poll updates from the Thread via public properties. Just make sure you are using some king of locking (TCriticalSection, TMonitor, mutexes, events, etc.) when reading from and writing to these variables.
-
ccy's version works properly on ZIP archives with LZMA compression. 7-zip is using LZMA2 by default, for which I did not see a pure pascal implementation yet.
-
I discovered a trick. If you put SelStart before a link and set SelLength to 1, RichEdit will select the FULL link text... like
QuoteHYPERLINK "https://en.delphipraxis.net"Delphi Praxis
The good news in this is that we can optimize the checking cycle to use this feature:
Self.SelStart := Integer.MaxValue; max := Self.SelStart; a := 0; While a < max Do Begin Self.SelStart := a; Self.SelLength := 1; If Self.SelAttributes.Color = clWindowtext Then Self.SelAttributes.Color := TStyleManager.ActiveStyle.GetStyleFontColor(sfEditBoxTextNormal); a := Self.SelStart + Self.SelLength; End;
Instead of 3000+ msec, the cycle now finishes in 500!
Still not ideal, but a lot more bearable 🙂
-
1 hour ago, robertjohns said:How can I find all instances of a string in a file , replace all instance of the string and save the copy of the file in Delphi
TFile.WriteAllText('OutFileName.txt', TFile.ReadAllText('FileName.txt').Replace('Replace from', 'Replace To'));
-
Ok, I'm getting baffled. Time is lost in the space-time continuum.
I added a ton of measuring to the code, looks like this now:
Procedure TRichEdit.StreamIn(Var Msg: TMessage); Var a, b: Integer; ro: Boolean; sw, fsw: TStopWatch; needcolor: Boolean; sscount, slcount, clcount, gscount, nccount: Integer; ssdelay, sldelay, cldelay, gsdelay, lddelay, ulddelay, loading, rodelay, moddelay, ncdelay: Int64; s: String; Begin fsw := TStopWatch.StartNew; sscount := 0; ssdelay := 0; slcount := 0; sldelay := 0; clcount := 0; cldelay := 0; gscount := 0; gsdelay := 0; lddelay := 0; ulddelay := 0; rodelay := 0; moddelay := 0; nccount := 0; ncdelay := 0; sw := TStopWatch.StartNew; Self.LockDrawing; lddelay := sw.ElapsedMilliseconds; Try ro := Self.ReadOnly; Try sw := TStopWatch.StartNew; Self.ReadOnly := False; Inc(rodelay, sw.ElapsedMilliseconds); sw := TStopWatch.StartNew; inherited; loading := sw.ElapsedMilliseconds; Finally sw := TStopWatch.StartNew; Self.ReadOnly := ro; Inc(rodelay, sw.ElapsedMilliseconds); End; Inc(sscount); sw := TStopWatch.StartNew; Self.SelStart := Integer.MaxValue; Inc(ssdelay, sw.ElapsedMilliseconds); Inc(gscount); sw := TStopWatch.StartNew; b := Self.SelStart; Inc(gsdelay, sw.ElapsedMilliseconds); For a := 0 To b Do Begin Inc(sscount); sw := TStopWatch.StartNew; Self.SelStart := a; Inc(ssdelay, sw.ElapsedMilliseconds); Inc(gscount); sw := TStopWatch.StartNew; Try If Self.SelStart <> a Then Continue; Finally Inc(gsdelay, sw.ElapsedMilliseconds); End; Inc(slcount); sw := TStopWatch.StartNew; Self.SelLength := 1; Inc(sldelay, sw.ElapsedMilliseconds); Inc(nccount); sw := TStopWatch.StartNew; needcolor := Self.SelAttributes.Color = clWindowtext; Inc(ncdelay, sw.ElapsedMilliseconds); If needcolor Then Begin Inc(clcount); sw := TStopWatch.StartNew; Self.SelAttributes.Color := TStyleManager.ActiveStyle.GetStyleFontColor(sfEditBoxTextNormal); Inc(cldelay, sw.ElapsedMilliseconds); End; End; Inc(sscount); sw := TStopWatch.StartNew; Self.SelStart := 0; Inc(ssdelay, sw.ElapsedMilliseconds); sw := TStopWatch.StartNew; Self.Modified := False; moddelay := sw.ElapsedMilliseconds; Finally sw := TStopWatch.StartNew; Self.UnlockDrawing; ulddelay := sw.ElapsedMilliseconds; End; sw := TStopWatch.StartNew; s := 'SelStart count: ' + sscount.ToString + ', total time: ' + ssdelay.ToString + ' ms' + sLineBreak + 'SelLength count: ' + slcount.ToString + ', total time: ' + sldelay.ToString + ' ms' + sLineBreak + 'NeedColor count: ' + nccount.ToString + ', total time: ' + ncdelay.ToString + ' ms' + sLineBreak + 'Coloring count: ' + clcount.ToString + ', total time: ' + cldelay.ToString + ' ms' + sLineBreak + 'GetSelStart count: ' + gscount.ToString + ', total time: ' + gsdelay.ToString + ' ms' + sLineBreak + 'Locking: ' + lddelay.ToString + ' ms, unlocking: ' + ulddelay.ToString + ' ms, loading: ' + loading.ToString + ' ms, read-only: ' + rodelay.ToString + ' ms, modified: ' + moddelay.ToString + ' ms' + sLineBreak + 'Full cycle: ' + fsw.ElapsedMilliseconds.ToString + ' ms' + sLineBreak + 'Building message: ' + sw.ElapsedMilliseconds.ToString + ' ms'; ShowMessage(s); End;
Loading a 7 kb RTF file with no coloring, only links and a bulleted list results:
QuoteSelStart count: 2140, total time: 730 ms
SelLength count: 703, total time: 816 ms
NeedColor count: 703, total time: 0 ms
Coloring count: 85, total time: 5 ms
GetSelStart count: 2139, total time: 0 ms
Locking: 0 ms, unlocking: 0 ms, loading: 6 ms, read-only: 0 ms, modified: 0 ms
Full cycle: 3247 ms
Building message: 0 msSetting SelStarts took 730 ms, setting SelLengths took 816 ms, a total of 1546 ms. So how the full cycle is 3247 ms, which is more than double...?
Loading the same with no VCL styles active makes it even more visible:
QuoteSelStart count: 2140, total time: 11 ms
SelLength count: 703, total time: 111 ms
NeedColor count: 703, total time: 0 ms
Coloring count: 85, total time: 0 ms
GetSelStart count: 2139, total time: 0 ms
Locking: 0 ms, unlocking: 0 ms, loading: 5 ms, read-only: 0 ms, modified: 0 ms
Full cycle: 1847 ms
Building message: 0 msWhat I did not measure yet...?
I know TStopWatch is not the most precise system, but it can not be missing this much...
-
1 hour ago, PeterBelow said:Have you tried to just set DefAttributes.Color before calling the inherited StreamIn method? SelAttributes.ConsistentAttributes may also be of use if you really need to manually correct the font color.
Yes, and unfortunately loading the stream overwrites this setting; it has no effect in the new document being loaded.
My issue with ConsistentAttributes is that it needs a selection - and for that I need to reposition the cursor again, most probably ending up at the same slowdown.
I'm attempting to experiment with EM_GETTEXTRANGE but unfortunately it doesn't seem to care about formatting at all, just returns as many characters as I desire.
-
"During our analysis of the report, we realized that there were a few flaws within the architecture of Zeppelin that would open an opportunity for recovery."
So even malware writers are making mistakes *sighs in relief*
-
First of all, do a WriteLn('d.exe -b '+e1.Text+'d.exe -a '+e2.Text+'d.exe -c'+e3.Text+'d.exe -s'+e4.Text+'-d PATH_OF_DEVICE_A') and ensure that the command executes successfully.
Next, make sure ExtractFilePath(application.ExeName) + 'bin\' folder exists (I suppose this is the "working directory".
Finally, make sure that all the external files you reference in the command line are using ABSOLUTE paths, otherwise they must be present in the working directory.
As @FPiette mentioned, neither GetDosOutput or TMemoAppendStream exists in Delphi by default. While we can guess what they do, we cannot guess their implementation. It's possible that your call is correct, only these implementations are buggy.
-
If you create a StringStream from an input string, it uses TEncoding.Default. What if you override this by
TStringStream.Create(Json, TEncoding.UTF8, False);
?
-
1
-
-
15 hours ago, direktor05 said:Then I get to "animals":[{"id".... now here gets complicated. How do I parse further to get ID and name? Parse Json further or parse Json Array? Can someone help with some example code please?
Let's say you have a TJSONObject variable which holds the inmost object only (id and name) named innerjson:
if innerjson.GetValue('id') <> null then fid := (innerjson.GetValue('id') As TJSONNumber).AsLargeInt; if innerjson.GetValue('name') <> null then fname := (innerjson.GetValue('name') As TJSONString).Value;
if you are sure that these will always be present, you can discard the nullcheck.
-
I really do suspect that this is a bug. The color of uncolored text is clWindowText, it's just RichEdit is rendering it in a wrong color.
I'm not good with StyleHooks to actually fix it... I did find a workaround and however it works, it's painfully slow:
TMyRichEdit = Class(Vcl.ComCtrls.TRichEdit) strict private Procedure StreamIn(Var Msg: TMessage); Message EM_STREAMIN; End; Procedure TMyRichEdit.StreamIn(Var Msg: TMessage); Var a: Integer; Begin inherited; Self.LockDrawing; Try Self.SelStart := Integer.MaxValue; For a := 0 To Self.SelStart Do Begin Self.SelStart := a; If Self.SelStart <> a Then Continue; Self.SelLength := 1; If Self.SelAttributes.Color = clWindowtext Then Self.SelAttributes.Color := TStyleManager.ActiveStyle.GetStyleFontColor(sfEditBoxTextNormal); End; Self.SelStart := 0; Finally Self.UnlockDrawing; End; End;
The amount of .SelStart is causing the slowdown. Does anyone know how I can extract the start and end of consecutive blocks, where all formatting is the same? That should speed things up a LOT.
I'll look into how exactly RichEdit is setting the properties of SelAttributes - maybe I can extract the attribute at a specific location without having to move the cursor, that way the only SelStart - SelLength would be at blocks what I actually have to change.
-
The name is a little bit confusing: StyledSomething might make people think it's associated with VCL styles.
-
That makes a lot of sense, thanks for pointing it out! As it caused no issues until now I didn’t even notice :)
Maybe I’ll update it if I have to make a change in the component.
-
You can check the tab dragging in AE.Comp.PageControl, I'm handling the dragging of tabs almost the same way. The only difference I see is creating a DragObject in DoStartDrag but that shouldn't affect the check above as it's called from DragInitControl, which is called later.
-
I'd start by removing IDE extensions and/or component packages.
Exception handlers like MadExcept can be installed in the IDE to handle Delphi exceptions too. I'd give that a try too, a stack trace may point out what is the culprit.
-
Are you in control of both the data and the header? If yes, open the file for writing in your preferred method (AssignFile, TFiles, TFileStream) and write the header, then the data.
If you get a file from an external source and you need to add a header, the easiest solution is a stream. Write your header and then copy the data from said file, loaded in a TFileStream.
If you receive one header files and need to append data, all 3 methods (AssignFile, TFile, TFileStream) can append binary data to it.
-
I never checked, but isn’t the Delphi localization file a regular resource DLL, without code?
If this is the case (and your source is not IFDEF-ing resource stings) the same file can be used by 32 and 64 bit applications. Afaik a new DLL is only required if there is ANY code (including self-extracting, like UPX).
-
49 minutes ago, Fr0sT.Brutal said:Generics are with us since D2009 and you unlikely want to support something older as it will require too much manual job.
Impressive project! Glad to see my stack trace unit 🙂 you'll probably want to update its code from https://github.com/Fr0sT-Brutal/Delphi_StackTraces/blob/master/Ice.Debug.pas since it has an improvement of excluding non-relevant entries and better comments
There are lots of people who dislike Generics and would like to avoid having them in their projects. Using a standard TList and casting pointers can be an easy solution. In theory this whole thing could be D7 compatible if I'd invest enough free time in it. We'll see.
So the author of said stack trace unit was you? 🙂 I remember having it for ages without any sign of where / who it came from so I can give appropriate credit. There were also some cyrillic characters in it which threw me totally off. As it seems it grew a lot, and since the new version is on GitHub it's easier just to remove it from mine.
I don't like redundancy.
-
Came here to post the same. Better translation manager is working wonders.
-
All programs only show you the place the leaked object was created. It has no idea where you want to free it up.
What is the leaked object?
-
The whole thing started with this topic. Due to lack of possibilities, I wrote my own update mechanism which noes not rely on any advanced stuff but still should be versatile enough.
Since the initial version TAEUpdater got some improvements and things are looking great. Some more stuff was implemented like hash-based verification, messages, E-tag caching, separate internal, development and production channels, ability to downgrade to a previous version, etc. I'm running it in my main application for a while and it seems to do the job correctly.
Since not all of us might update from an unauthenticated web server, now 3 different file providers are shipped: HTTP, flatfile and custom. HTTP uses Delphi's TNetHTTPClient, flatfile reads the files from a local disk and custom has all necessary events exposed via events. I also got rid of some personal dependencies (like compressing the update file or using System.Zip2) and now everything is handed to the user for the solution to be more... generic. I still use my own version discovery and comparison method to be able to determine which published one is "newer" but that is going to be my next step. As a workaround, you can call .LoadUpdateFile, check the new version in each ActualProduct.Files and call .Update manually.What it needs:
- An update file containing the product, all its files and versions. You can build this with TAEUpdateFile.SaveToStream in AE.Updater.UpdateFile.pas
- Update packages, which can be zipped or encrypted, on FTP, HTTP, custom protocol - doesn't matter as events should be in place for performing all these actions
Plans for the future:
- Getting rid of more dependencies, maybe it'll become a standalone updater package with no extras
- By accomplishing the above the code will get closer and closer to be truly cross-platform (atm it's WIndows only)
- Get rid of modern stuff (like generics) and implement proper versioning conditionals so the package can be compiled and installed on anything other than D11.2
- Really, really basic documentation on how to use...
Disclaimer: further changes are on their way. I'll possibly add / remove events / splitting the component in multiple subcomponents which might make existing .DFMs failing to be streamed. Also, publish your new versions on the Internal channel if I might break the core functionality 😞
All words as one - I just wanted to give the existing Delphi community a chance to implement auto-updating feature to their applications without having to pay for the component or the backend. Feel free to check it out. And suggest ways of improvement of course 🙂
-
4
-
1
-
Delphi 11.2 vs 10.4.2 locale issue
in General Help
Posted
I don't know if I follow you here. Does it mean that I must never use FormatSettings.ShortDateFormat as it is, only FormatSettings.ShortDateFormat.Replace('/', FormatSettings.DateSeparator)?
The reason I'm asking is that 3rd-party controls (like DevExpress) started to show (and save) dates differently just because of compiling under D11. That makes me think that either the above statement is incorrect, or all 3rd-party controls handle this incorrectly.
To correct this I had to manually correct FormatSettings.ShortDateFormat but that immediately breaks all logic which relies on TFormatSettings.Create and StrToDate - which our tool is using a lot.
The reason Delphi 10.4.2 could not get it is because Embarcadero didn't provide a buffer big enough. As both versions are calling the same WinApi function, changing the buffer to array[0..1] retrieving will fail on D11 aswell; calling RaiseLastOSError will reveal the reason:
Maybe I should have been more precise. I personally don't care about the date separator alone, only the malformation of ShortDateFormat because of it, which seem to affect appearance and logic.