Jump to content

aehimself

Members
  • Content Count

    1090
  • Joined

  • Last visited

  • Days Won

    23

Posts posted by aehimself


  1. You simply can iterate through the members of the array, like:

     

    Var

      jval: TJsonValue;

      jarr: TJsonArray;

    begin

      // jarr := myJson.GetValue(‘drinks’) As TJsonArray;

      for jval in jarr do

         // …

    end;

     

    p.s.: sorry, I can not find how to format as code from my phone 😞


  2. On 7/31/2023 at 2:31 PM, 3ddark said:

    Can you explain with an example?

    Instead of “SELECT * FROM MyTable WHERE ID = 99” use “SELECT * FROM MyTable WHERE ID = :pID”, then assign the value 99 for the parameter named pID.

    • Like 1

  3. Minimum code I used is:

    procedure TForm1.FormCreate(Sender: TObject);
    Var
     windowstyle: Integer;
     appthreadid: Cardinal;
     cmdhandle: THandle;
    Begin
     cmdhandle := FindWindow('ConsoleWindowClass', 'Command Prompt');
    
     // Hide title bars and borders of launched application
     windowstyle := GetWindowLong(cmdhandle, GWL_STYLE);
     windowstyle := windowstyle - WS_CAPTION - WS_BORDER - WS_OVERLAPPED - WS_THICKFRAME;
     SetWindowLong(cmdhandle,GWL_STYLE,windowstyle);
    
     // Attach the container applications input thread to the launched ones, so that we receive user input
     appthreadid := GetWindowThreadProcessId(cmdhandle, nil);
     AttachThreadInput(GetCurrentThreadId, appthreadid, True);
    
     // Docking. Change the parent of the launched application
     WinApi.Windows.SetParent(cmdhandle, Self.Handle);
     SendMessage(Self.Handle, WM_UPDATEUISTATE, UIS_INITIALIZE, 0);
     UpdateWindow(cmdhandle);
    
     // Make the docked window fill all the client area of the container
     SetWindowPos(cmdhandle, 0, 0, 0, Self.ClientWidth, Self.ClientHeight, SWP_NOZORDER);
    
     // This prevents the parent control to redraw on the area of its child windows (the launched application)
     SetWindowLong(Self.Handle, GWL_STYLE, GetWindowLong(Self.Handle, GWL_STYLE) Or WS_CLIPCHILDREN);
    
    // SetForegroundWindow(WindowHandle);
    // SetFocus(WindowHandle);
    End;

    This does not take care of resizing the docked window if the form resizes and you also have to keep an eye on if / when your docked application closes. Also it includes no error checking / handling.

    The result is as expected:

     

    image.thumb.png.545c0e051c6aeed1e88584f4ff7d77ac.png

    • Like 1

  4. PING -t will continue to ping until you manually terminate it (usually Ctrl-C in your window). The code above does what it is told - read until the process ends; but the process will never die due to the -t switch.

    As your main thread is stuck in this loop you have but a handful of options:

    - Introduce a counter in the cycle. Exit the repeat-until cycle when the counter reaches a specific amount

    - Start a secondary thread before the loop, passing the process handle to it. The secondary thread can then kill the process at any time, causing the loop to break

    - You also can use a timer but you have to inject a message pump in your inner loop

    - Move this method to a thread and spam it across with "If Self.Terminated Then Exit". Start your thread and kill it any time from your main application with mythread.Terminate

     

    I'd go with option 4 as that is going to leave the UI useable during execution.


  5. SMComponents does that and their grid comes with many other interesting features while being as simple as possible. It's even free...!

    I almost ended up replacing my own DBGrid descendant with these when I had enough of tinkering around trying to fix it's issues 🙂


  6. 20 hours ago, Dave Nottage said:

    You'd need to typecast it to a TMemoryStream in order to do that, e.g:

    
    if LResponse.ContentStream is TMemoryStream then
      TMemoryStream(LResponse.ContentStream).SaveToFile(LFileName)
    // else the implementation has changed ;-)

     

    Yes, it is exposed as TStream, but internally it's a TMemoryStream if I recall correctly. So yes, typecasting is needed.


  7. 3 hours ago, egnew said:

    I am using a TNetHttpRequest component to retrieve text from a secure website.  I use the associated TNetHttpClient's OnAuthEvent to set the username and password.  This allows me to retrieve text into a string using IHTTPResponse.ContentasString.

     

    I need to retrieve files from the same secured website.  When I request the file using the same code, the IHTTPResponse.ContentStream seems to contain the requested file content since the IHTTPResponse.ContentLength appears to be correct.

     

    How can I save the content of IHTTPResponse.ContentStream to a file?

     

    Thanks

    AFFAIK it's a TMemoryStream, so you simply can call ContentStream.SaveToFile. You also can create a separate TFileStream and use .CopyFrom(ContentStream). just make sure position is 0 before calling .CopyFrom.

    • Like 1

  8. On 6/25/2023 at 10:43 AM, Angus Robertson said:

    Because ICS does not have a native SHA-256 implementation, it now uses OpenSSL for digest operation.

    In later Delphi versions there's a build in record for this, System.Hash.THashSHA2. If available, you also can use this so it doesn't depend on a DLL.

    Maybe v10+, I'm not sure though.


  9. 9 minutes ago, hackbrew said:

    I have set up some test databases in AWS RDS (MySQL, PostgreSQL, and MariaDB). Assuming I have the proper user permissions for basic CRUD operations, am I able to connect to the databases with Delphi Professional (v10.4)? If so, what if any advantage would upgrading to Delphi Enterprise provide me for this task?    

    As far as I know FireDac is present in Professional but you only get the sources in Enterprise. Having the sources can help you to debug issues or easily create your own descendants of it's components in case you need to extend functionality.

    If you need the sources but can not / don't want to upgrade to Enterprise you always can install a 3rd party library like Zeos.

    • Like 1

  10. If StrToInt says a string is not a number thus it can not be converted, trust it, it's true.

    If you are really interested, you can use the function "Val" which will even tell you which character is causing it to fail.

    You might want to sanitize your input first for spaces or other non-printable characters which get there easily if you copy-paste from documents / websites.

    Also, consider what @Remy Lebeau said, and use a TSpinEdit or TNumberBox instead (you can check NumbersOnly in TEdit as well). This way the input won't even be accepted if the pasted string / typed character is not a number.


  11. On 3/29/2023 at 9:59 AM, balabuev said:

    Do I understand correctly that a control, which is not a TWinControl (for example, TLabel), has no way to implement flicker free drawing with VCL Styles turned on?

     

    It seems that the parent form erases its own background via TFormStyleHook.PaintBackground not excluding child controls. This happens in both: Form.DoubleBuffered = False and Form.DoubleBuffered = True modes.

    I had extreme flickering of controls which were placed on TPanels. The solution was to enable ParentBackground of the TPanel when the current is the system style, otherwise set it to false.

    Flickering gone down with a huge margin.


  12. I just would like to add one more thing to the list, VCL styles renders TRichView.CreateParented unusable.

    Microsoft advises to create a rich text editor for RTF manipulation. Imagine that you have a thread:

      TTransformatorThread = Class(TThread)
      strict private
        _document: TStream;
      protected
        Procedure Execute; Override;
      public
        Constructor Create(Const inDocument: TStream); ReIntroduce;
      End;
    
    constructor TTransformatorThread.Create(const inDocument: TStream);
    begin
      inherited Create(False);
    
      _document := inDocument;
    end;
    
    procedure TTransformatorThread.Execute;
    Var
      rtf: TRichEdit;
      wnd: HWND;
      a, max: Integer;
    begin
      inherited;
    
      _document.Position := 0;
    
      wnd := AllocateHwnd(nil);
      Try
        rtf := TRichEdit.CreateParented(wnd);
        Try
          rtf.Lines.LoadFromStream(_document);
    
          rtf.SelStart := Integer.MaxValue;
    
          max := rtf.SelStart;
    
          a := 0;
    
          While a < max Do
          Begin
            rtf.SelStart := a;
            rtf.SelLength := 1;
    
            rtf.SelAttributes.Color := clRed;
    
            a := rtf.SelStart + rtf.SelLength;
          End;
    
          _document.Size := 0;
    
          rtf.Lines.SaveToStream(_document);
    
          _document.Position := 0;
        Finally
          FreeAndNil(rtf);
        End;
      Finally
        DeAllocateHwnd(wnd);
      End;
    end;

    It recolors all sections text to red, but it's only for demonstration. Now, have the following code:

      TForm1 = class(TForm)
        ThreadWatchTimer: TTimer;
        RichEdit1: TRichEdit;
        procedure FormCreate(Sender: TObject);
        procedure ThreadWatchTimerTimer(Sender: TObject);
      strict private
        _doc: TMemoryStream;
        _thd: TTransformatorThread;
      end;
    
    procedure TForm1.FormCreate(Sender: TObject);
    begin
      _doc := TMemoryStream.Create;
      _doc.LoadFromFile('C:\Temp\MyDocument.rtf');
    
      _thd := TTransformatorThread.Create(_doc);
    
      ThreadWatchTimer.Enabled := True;
    end;
    
    procedure TForm1.ThreadWatchTimerTimer(Sender: TObject);
    begin
      ThreadWatchTImer.Enabled := Assigned(_thd) And Not _thd.Finished;
    
      If Not Assigned(_thd) Then
        Exit;
    
      If _thd.Finished Then
      Begin
        RichEdit1.Lines.LoadFromStream(_doc);
      End;
    end;

    The theory is easy. You load the document in a stream, pass it to the thread to process and modify it, and when the thread finishes you load the modified content in the rich edit on the form. I know, passing a TStream screams of thread safety but it's simple enough for this demonstration.

     

    If you run this without any VCL style active, all works fine. If you set any style... it will load the document but the program will freeze. I suppose the StyleHook is attempting to stylize the hidden rich editor in a background thread, thus causing the lockup.

     

    Tested with D11.3, so I suppose previous installations are also affected.

     

    Edit: Added test project

    richeditstyle.7z


  13. I wrote a small method to convert any text (even multiple lines) to a "Delphi source file string". I'm sure there are limitations but does it's job just fine for me:

    Function ToDelphiString(Const outString: String): String;
    Const
      ADDITION = #39' + '#39;
      BREAKAT = 80;
    Var
      line, a, max: Integer;
      sb: TStringBuilder;
      strarr: TArray<String>;
    Begin
      sb := TStringBuilder.Create;
      Try
        sb.Append(#39);
    
        strarr := AdjustLineBreaks(outString).Split([sLineBreak]);
    
        For line := Low(strarr) To High(strarr) Do
        Begin
          max := strarr[line].Length Div BREAKAT;
    
          For a := 0 To max Do
          Begin
            sb.Append(strarr[line].Substring(a * BREAKAT, BREAKAT).Replace(#39, #39#39));
    
            sb.Append(#39);
    
            If a <> max Then
              sb.Append(' +' + sLineBreak + #39);
          End;
    
          If line <> High(strarr) Then
            sb.Append(' + sLineBreak +' + sLineBreak + #39);
        End;
    
        Result := sb.ToString;
      Finally
        FreeAndNil(sb);
      End;
    End;

    You can use it to overcome the 255 character limitation.


  14. You can also rearrange visible controls by setting the .Left property to the previous control's Left + 1. That way, it will be placed immediately after it.

    You might also want to wrap everything in Container.DiableAlign and .EnableAlign so you get the results you want to see.


  15. TJSONObject(TJSONObject(TArrayElement).GetValue('type')).GetValue<String>(message, messagestring);
    TJSONObject(TArrayElement).GetValue<Integer>('time', timeinteger);
    TJSONObject(TArrayElement).GetValue<String>('flex', flexboolean);

     

    Also, don't forget to wrap the inner code in a Try...Finally block so you free JSONValue no matter what.


  16. You probably need to include ATBinHex and Vcl.Forms in your uses (include) list.

    Being a Delphi-only guy I'm afraid I'll not be able to give you the exact code for C++ projects 😞


  17. 7 hours ago, CyberPeter said:

    Could you share the changed *.pas file where this change is made ?

    I didn't change the component source, just cloned the repo from GitHub and installed it in Delphi. All the code I mentioned is in my application.

    It's a good thing because it's completely detached from the component. It's bad, because those have to be included in each application you use ATBinHex in.

     

    You can make a class helper with a public .Recolor method so you easily can recolor each instance after the style changed. You also can take it one step further, create your own ATBinHex descandant, and use AllocHWND to listen for CM_STYLECHANGED and recolor automatically.

    You still have to register the style hook somewhere else though. I continuously got AVs if I included it in the helper class constructor / unit initialization section.

    8 hours ago, CyberPeter said:

    I looked it up and it appears TATBinHex needs to inherit from TStyleHook

    You need ScrollingStyleHook, otherwise scrollbars won't be themed AFAIK.


  18. The first one is in my "uFixVCLStyles" unit initialization section. The second block is in the window / form constructor.

    Unfortunately coloring won't change if a different style is selected runtime and an ATBinHex component is already visible, but you can solve this by handling the CM_STYLECHANGED message and put the recoloring code in there.


  19. VCL styling issue can easily be fixed:

      TStyleManager.Engine.RegisterStyleHook(TATBinHEX, TScrollingStyleHook);

    And of course:

          ATBinHex.Color := TStyleManager.ActiveStyle.GetStyleColor(scEdit);
          ATBinHex.TextColorHexBack := TStyleManager.ActiveStyle.GetStyleColor(scEdit);
          ATBinHex.Font.Color := TStyleManager.ActiveStyle.GetStyleFontColor(sfEditBoxTextNormal);
          ATBinHex.TextColorHex := TStyleManager.ActiveStyle.GetStyleFontColor(sfEditBoxTextNormal);
          ATBinHex.TextColorHex2 := TStyleManager.ActiveStyle.GetStyleFontColor(sfEditBoxTextNormal);

    image.thumb.png.2724ae59e34ffcbd668283f6b64cbc54.png

     


  20. You can use WIndows messages via PostMessage to notify the owner.

     

    With that said, if a third component is controlling the lifecycle of said form it's better to review your program design. E.g. have a class which is showing / hiding forms, and create your forms with (nil) as owner.

    • Like 1
×