Jump to content

aehimself

Members
  • Content Count

    1089
  • Joined

  • Last visited

  • Days Won

    23

Posts posted by aehimself


  1. When experimenting with a new component I suggest a "barebone" example first. One control on the form, setting up and connecting in FormCreate.

    I'm not going to recreate your form layout and filter out the essentials I'm sorry... I already showed how I'm doing it and it works fine.

     

    Also keep in mind that by importing the MsTscAx control you are effectively using the current version available in your Windows setup: it can / might / surely will differ between versions, editions and even patch levels.


  2. The first window warns about "invalidity" of certificate and approval of access for a specific function (drive mapping maybe?). You will not be able to bypass this (you can ignore the certificate so the warning only comes back once the cert is renewed).

    The second one you can bypass by specifying the username and password.

    This is how my tabbed remote access application sets up MsTscAx controls for RDP connections:

      If Self.Credential <> nil Then
      Begin
        If Not Self.Credential.DomainName.IsEmpty Then
          _rdp.Domain := Self.Credential.DomainName;
    
        If Not Self.Credential.UserName.IsEmpty Then
          _rdp.UserName := Self.Credential.UserName;
    
        If Not Self.Credential.Password.IsEmpty Then
          _rdp.AdvancedSettings7.ClearTextPassword := Self.Credential.Password;
      End;

    I suggest you check all the .AdvancedSettingsxxx options. There are plenty of tasty settings there to fulfill your needs.


  3. The caption isn't truncated, only the display is clipped:

    procedure TForm1.FormCreate(Sender: TObject);
    Const
      MYTEXT = '<RHINOSTRING English="Exploding this mesh will create %d individual meshes.  This may be more than your system can safely manage using the available memory.  You can use Weld to make the mesh explode into fewer pieces, or see Help for more information.\n\nClick OK to proceed with Explode, or Cancel to leave the mesh as is.[[24836]]" Localized="Exploding this mesh will create %d individual meshes.  This may be more than your system can safely manage using the available memory.  You can use Weld to make the mesh explode into fewer pieces, or see Help for more information.\n\nClick OK to proceed with Explode, or Cancel to leave the mesh as is.[[24836]]" />';
    begin
      ListView1.Items.Add.Caption := MYTEXT;
    
      ShowMessage(MYTEXT.Length.ToString + sLineBreak + ListView1.Items[0].Caption.Length.ToString);
    end;

    Shows 661 and 661 respectively.

     

    The reason seems to be a WinApi limitation:

    https://stackoverflow.com/questions/19881409/tlistview-add-600-characters-on-item-caption


  4. For a while I used this unit to detect the OS version and edition. For a while it is unmaintained though and could use some refactoring for sure.

    As @David Heffernan mentioned you must include a mainfest file as a resource in your application, otherwise OS detection will return  false information due to compatibility modes.


  5. I read a tip here on DelphiPraxis back in 10.x that disabling the Welcome screen altogether greatly improves stability. Since then that's the first thing I do after a Delphi installation and the IDE is rock solid since then.

    You get an AV if you click on the Welcome screen settings in Options, but that's a sacrifice I'm willing to live with :)


  6. I'm using this code for alternating colors:

    Procedure TDBGrid.DrawColumnCell(Const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState);
    Var
      dataset: TDataSet;
      {$IFDEF HIDECOLLINESIFEMPTY}
      colline: Boolean;
      {$ENDIF}
      editcolor: TColor;
      hidefocus: Boolean;
    Begin
      dataset := Self.DataSource.DataSet;
    
      // This method is only being called on DATA cells, which only happens if there is a dataset connected. Therefore, no
      // need to perform an assigned check here.
    
      {$IFDEF HIDECOLLINESIFEMPTY}
      colline := True;
      {$ENDIF}
      hidefocus := Not (csDesigning In Self.ComponentState) And (gdSelected In State) And Not Self.Focused;
    
      If (dgMultiSelect In Self.Options) And (Self.SelectedRows.CurrentRowSelected) Then
      Begin
      End
      Else
      If dataset.IsEmpty Then
      Begin
        {$IFDEF HIDECOLLINESIFEMPTY}
        colline := False;
        {$ENDIF}
        editcolor := TStyleManager.ActiveStyle.GetStyleColor(scEdit);
        Self.Canvas.Brush.Color := editcolor;
        Self.Canvas.Font.Color := editcolor;
      End
      Else
    // This code imitates the highlight of the whole row even if RowSelect is disabled. Note that it needs MultiSelect to be enabled!
    //  If Not (gdSelected In State) And grid.SelectedRows.CurrentRowSelected Then
    //    grid.Canvas.Brush.Color := clHighLight
    //  Else
      If (dataset.RecNo Mod 2 = 0) And ((State = []) Or hidefocus) Then
        Self.Canvas.Brush.Color := TStyleManager.ActiveStyle.GetStyleColor(scButtonDisabled)
      Else If (dataset.RecNo Mod 2 = 1) And hidefocus Then
        Self.Canvas.Brush.Color := TStyleManager.ActiveStyle.GetStyleColor(scEdit);
    
      If hidefocus Then
        Self.Canvas.Brush.Color := TStyleManager.ActiveStyle.GetStyleColor(scCategoryButtonsGradientBase);
    
      {$IFDEF HIDECOLLINESIFEMPTY}
      If HIDECOLLINESIFEMPTY And colline And Not (dgColLines In Self.Options) Then
        Self.Options := Self.Options + [dgColLines]
      Else If HIDECOLLINESIFEMPTY And Not colline And (dgColLines In Self.Options) Then
        Self.Options := Self.Options - [dgColLines];
      {$ENDIF}
    
      inherited;
    
      Self.DefaultDrawColumnCell(Rect, DataCol, Column, State);
    End;

    Supports VCL styles and works fine for a couple of years now.

     

    I used the "lazy" technique. Save this as uDBGrid.pas, add is to the uses clause of your form and in the declaration change "grdMyDBGrid: TDBGrid;" to "grdMyDBGrid: uDBGrid.TDBGrid". Since the class name is the same no modification in the dfm is necessary.

    Drawback is, it only works runtime. And it's hacky.

    • Like 1

  7. 1 hour ago, bobD said:

    Because a TFDConnection connects very quickly, but takes a long time to fail, and it's annoying to sit and wait

    I never personally used FireDac, but doesn't it have a configurable timeout property?

    If no, what you can do is to attempt to connect in a background thread. Use your local connection until DB connection succeeded then simply swap them out and sync changes.


  8. 14 minutes ago, bobD said:

    So the connection attempt would fail and the program would fall over to the local db. It would just take longer.

    Why to have any additional checks then...? When you initiate a connection to a host name / fqdn, name resolution is done automatically by the DB client library.

     

    Just attempt a connection to your database server. If that fails for any reason, fall back to the local DB.


  9. 5 hours ago, Brian Evans said:

    There are network profiles in Windows which can be Private, Public or Domain. Normally your home network would be Private and anytime you go elsewhere it would be Public (discovery disabled) or Domain. You could check what the active connection is. Or just key off the active profile name for what network settings your application should use.

    This check will trigger on all networks, which are set to private which is probably not a desired behavior. While these will work, OP's solution will be a different design pattern.

     

    What if you put the code in a separate DLL, which you are not distributing; and lives only on your home dev PC?


  10. When you are trying to detect your home network, don't rely on a successful (reverse) DNS lookup. I usually ping my home router (using fqdn) but even better, attempt a connection to a well-known service. However I only use this method to decide if VPN should be fired up or not; it's better to set up your DNS properly so tools will work from inside and outside.

     

    If you are keen to go this way I found these two snipplets in my codebase:

    Function LookupHostName(inIP: String): String;
    Var
      host: PHostEnt;
      addr: Integer;
      dat: TWSAData;
    Begin
      Result := '';
      
      WSAStartup($0101, dat);
      Try
        addr := inet_addr(PAnsiChar(AnsiString(inIP)));
        host := GetHostByAddr(@addr, 4, PF_INET);
        If host <> nil Then
          Result := String(host.h_name);
      Finally
        WSACleanup;
      End;
    End;

    This one was abandoned halfway as no variables seem to be declared:

      Write('Attempting to resolve ' + HostName + '...');
    
      If WSAStartup($0101, wsdata) = 0 Then
      Try
        tmp := GetHostByName(PAnsiChar(HostName));
    
        If tmp <> nil Then
        Begin
          tmpin.sin_addr.S_addr := LongInt(PLongInt(tmp^.h_addr_list^)^);
          IPAddress := inet_ntoa(tmpin.sin_addr);
    
          WriteLn(IPAddress);
        End;
      Finally
        WSACleanup;
      End;

    May I ask why your program needs to behave different from a specific network? There might be a better way than relying on simple checks, which might trigger in places you don't want them to.


  11. Windows 11 moved further away from privacy, prefers "innovation" noone asked for over functionality and requires way too much hardware just to sit on the desktop, doing nothing.

     

    I'm eyeing Windows 10 IoT Enterprise LTSC. Price is not that high and you get a fully functional and debloated WIndows 10, supported until 2035.

    Until then I hope a Delphi IDE will be released for Linux :)


  12. I personally used MySQL for my projects and a bit of MsSQL server. I advise against FireBird and Oracle, my personal experience shows you'll have extra issues to keep an eye on.

    On Windows servers my suggestion is MsSQL, on Linux MariaDB. That way updates / patches are included in the regular process.


  13. 1 minute ago, maumsti said:

    That being said, if a malicious actor has already gained access to the network, their primary goal would likely not be just shutting down applications but rather compromising systems, exfiltrating data, or escalating privileges...

    With this I completely agree. Meaningful attacks (and their mitigation) are out of the scope of this project however (especially if we are somewhat "controlling" endpoints) we should do our part in cybersecurity :)


  14. The only benefit I see here is the usage of data aware controls.

    A Dataset descendant is never going to be as efficient in storage or manipulation as arrays are. Also keep in mind that you are doubling the resources used every time you are cloning a Dataset, which - by your own words - is already pretty large.

     

    To simplify/standardize I would create my custom data storage class with thread safe access and then look into DataBinding or writing my own helpers to display the data in this storage. If speed is not an issue you also can use an indexed TFileStream to cut back on memory requirements.

×