Jump to content

aehimself

Members
  • Content Count

    1030
  • Joined

  • Last visited

  • Days Won

    22

Everything posted by aehimself

  1. aehimself

    TRichEdit with VCL styles

    I discovered a trick. If you put SelStart before a link and set SelLength to 1, RichEdit will select the FULL link text... like 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 πŸ™‚
  2. aehimself

    Find, Replace and Save

    TFile.WriteAllText('OutFileName.txt', TFile.ReadAllText('FileName.txt').Replace('Replace from', 'Replace To'));
  3. aehimself

    TRichEdit with VCL styles

    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: Setting 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: What I did not measure yet...? I know TStopWatch is not the most precise system, but it can not be missing this much...
  4. aehimself

    TRichEdit with VCL styles

    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.
  5. "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*
  6. aehimself

    write console code

    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.
  7. aehimself

    TIdHttp - incorrect UTF-8

    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); ?
  8. aehimself

    Parse Json again, complicated

    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.
  9. aehimself

    TRichEdit with VCL styles

    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.
  10. aehimself

    StyledButton and StyledDialog

    The name is a little bit confusing: StyledSomething might make people think it's associated with VCL styles.
  11. aehimself

    [solved] Dragging a control - TControl.BeginDrag oddity

    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.
  12. aehimself

    [solved] Dragging a control - TControl.BeginDrag oddity

    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.
  13. aehimself

    Should I be concerned about KERNELBASE.RaiseException + 0x62

    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.
  14. aehimself

    Adding a header to a bin file

    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.
  15. aehimself

    Looking for a localization tool

    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).
  16. 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 πŸ™‚
  17. aehimself

    Free & low maintenance update mechanism

    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.
  18. aehimself

    Looking for a localization tool

    Came here to post the same. Better translation manager is working wonders.
  19. 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?
  20. aehimself

    Custom component on a VCL frame

    Hello, Let's imagine the following scenario. I made a custom component which resides on a VCL frame. First of all, it's a lot easier to design something if you can see it (hence no TPanel) and some components require a form or a frame as a parent. It looks like this: Install it to the IDE and create a new application. Place this component on the form. Issue #1: You can not select individual components, any click with the mouse will select the whole frame instead. This is not a big thing, as you still can select its child components in the Structure pane. Now, save your project in an empty git repository and commit once, so you can compare the differences. Load up the project again, select the TEdit and enter something as it's Text property: Save your project again and check the differences in the DFM: Issue #2: All property changes in the components children are simply discarded. I can get around this one too by setting these in runtime, but it's less convenient that directly in the IDE. I suppose this is a limitation, I shouldn't design my custom component on a frame. How else can I achieve graphical designability in the IDE and how can I force for example a dxBarManager toolbars to stay within the components boundaries? I'm also interested about the reason why these things happen, if someone knows by heart. Cheers!
  21. aehimself

    Custom component on a VCL frame

    I'm experimenting with this but I can not seem to get it to work. procedure TMyTempComponent.HitTest(Var Msg: TCMDesignHitTest); begin // ShowMessage('Edit1.BoundsRect.Top: ' + Edit1.BoundsRect.Top.ToString + sLineBreak + // 'Edit1.BoundsRect.Left: ' + Edit1.BoundsRect.Left.ToString + sLineBreak + // 'Edit1.BoundsRect.Bottom: ' + Edit1.BoundsRect.Bottom.ToString + sLineBreak + // 'Edit1.BoundsRect.Right: ' + Edit1.BoundsRect.Right.ToString + sLineBreak + sLineBreak + // 'Msg.XPos: ' + Msg.XPos.ToString + sLineBreak + // 'Msg.YPos: ' + Msg.YPos.ToString); If PtInRect(Edit1.BoundsRect, Point(Msg.XPos, Msg.YPos)) Then Msg.Result := 1 Else Msg.Result := 0; end; The event does not fire at all if I move the cursor over any child component (Edit, button or radiogroup) only when it is over the frame itself. I also tried adding ControlStyle:= ControlStyle - [csDesignInteractive]; in the constructor. I'll keep trying, but am I on the right track here? Maybe frames are just work... different? πŸ™‚
  22. aehimself

    Custom component on a VCL frame

    This is why πŸ™‚
  23. aehimself

    Custom component on a VCL frame

    Sure. There is no code whatsoever: unit TempComponent; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls; type TMyTempComponent = class(TFrame) Edit1: TEdit; Button1: TButton; RadioGroup1: TRadioGroup; private { Private declarations } public { Public declarations } end; Procedure Register; implementation Procedure Register; Begin RegisterComponents('Temp component', [TMyTempComponent]); End; {$R *.dfm} end.
  24. Hello, I'm using TurboPack SynEdit latest version, fresh from GitHub. I have an editor where the user can enter multiple SQL commands, like: SELECT * FROM MYTABLE SELECT * FROM OTHERTABLE o [...] Is there a way SynEdt can return the full block, but the current command only? So, if the cursor is staying in line 1 just return "SELECT * FROM MYTABLE" but at line 2 it would "SELECT * FROM OTHERTABLE o"? Keep in mind that commands can be split across several lines, so simply returning the current line is not a good solution. Summoning @pyscripter πŸ™‚
  25. aehimself

    SynEdit - Get current SQL command block

    For anyone interested I solved this without writing an actual interpreter, it parses all select aliases. The backdraw is that it offers aliases to use in statements where there is no such alias therefore executing the statement will throw an exception. This annoyance is perfectly acceptable by me, so probably I'll just leave it as it is. It derives a new analyzer from Zeos's generic analyzer, and it looks like this: Unit uAEGenericSqlAnalyser; Interface Uses ZGenericSqlAnalyser, ZTokenizer, ZSelectSchema; Type TAEGenericSqlAnalyser = Class(TZGenericStatementAnalyser) public Function DefineAllSelectSchemaFromQuery(const Tokenizer: IZTokenizer; const SQL: string): TArray<IZSelectSchema>; End; Implementation Uses System.Contnrs, System.Classes; Function TAEGenericSqlAnalyser.DefineAllSelectSchemaFromQuery(Const Tokenizer: IZTokenizer; Const SQL: string): TArray<IZSelectSchema>; Var Tokens: TZTokenList; sections: TObjectList; ss: IZSelectSchema; FromTokens: TZTokenList; deleted: Boolean; Begin SetLength(Result, 0); Tokens := TokenizeQuery(Tokenizer, SQL, True); Sections := SplitSections(Tokens); Try Repeat ss := DefineSelectSchemaFromSections(Sections); If Assigned(ss) Then Begin SetLength(Result, Length(Result) + 1); Result[High(Result)] := ss; FromTokens := FindSectionTokens(Sections, 'FROM'); deleted := False; While (Sections.Count > 0) And Not deleted Do Begin deleted := TZStatementSection(sections[0]).Tokens = FromTokens; Sections.Delete(0); End; End; Until ss = nil; Finally Tokens.Free; Sections.Free; End; End; End. To use it: Procedure TForm1.GetTableName(Var inNameOrAlias: String); Var sa: TAEGenericSqlAnalyser; sch: IZSelectSchema; a: Integer; Begin sa := TAEGenericSqlAnalyser.Create; Try For sch In sa.DefineAllSelectSchemaFromQuery(SQLConnection.DbcConnection.GetTokenizer, SQLCommand) Do For a := 0 To sch.TableCount - 1 Do If sch.Tables[a].Table.ToLower = inNameOrAlias.ToLower Then Exit Else If sch.Tables[a].Alias.ToLower = inNameOrAlias.ToLower Then Begin inNameOrAlias := sch.Tables[a].Table; Exit; End; Finally FreeAndNil(sa); End; End; SQLConnection is a TZConnection object (can be replaced with TZTokenizer.Create if no connection is available), SQLCommand is the string containing all the statements. Simply call this method to "convert" an alias to a table name. It can be optimized but since it's already pretty quick, I didn't really bother. Yeah, extracting the current block would be more elegant. In 1 hours with minimal personal code, this is what I could achieve πŸ™‚
Γ—