Jump to content

Lars Fosdal

Administrators
  • Content Count

    3525
  • Joined

  • Last visited

  • Days Won

    116

Posts posted by Lars Fosdal


  1. We went from ADO to FireDAC and significantly improved the performance.

    However - we do NOT use db aware components and inserts and updates are done through stored procedures.

     

    We systematically use
       FetchOptions.Mode := fmAll;
       FetchOptions.Unidirectional := Unidirectional;
     

    For stored procs, we add

      FetchOptions.Items := FetchOptions.Items - [fiMeta];

     

    We also avoid MARS concurrency by ensuring that every query gets a connection of its own.


  2. 8 minutes ago, Davide Angeli said:

    I'm compiling it both 32bit and 64bit and they work both here.

    I'm on Windows 10 64bit with Delphi 11.2.

     

    The 64bit compiled exe I've tested also on Win11 (22H1) and on WinServer 2019 and Winserver 2022 and it works everywhere.

    The 64-bit simply refuses to run, unless I run it elevated.

    Then I get

    /--- Started ---
    hres = 0
    dwRead = 35
    dwTotal = 712
    hres = 3608717696
    EAccessViolation: Access violation at address 00007FFBCE7CB0EC in module 'SAMCLI.DLL'. Read of address 00000000D718A9A8
    Press Enter:

    Perhaps there are further access rights that come into play?

     


  3. Check out unit web.win.AdsTypes:

    Here is some code I wrote to find out if a user had an AD membership.

    unit ActiveDSUtil;
    
    /// Written by Lars Fosdal, 16 DEC 2014
    /// Note that calling AD functions is slow.
    
    interface
    uses
      Classes, SysUtils, ActiveX, ActiveDS_tlb, web.win.adstypes;
    
    type
      TADGroupList = array of String;
      TAnonParamFunc<TA,TR> = reference to function (const v:TA):TR;
    
      /// <summary> Enumerates the group memberships of an AD user </summary>
      function EnumADUserGroupMemberships(const aDomain, aUser: String; EnumHandler: TAnonParamFunc<IAdsGroup, Boolean>):Boolean;
    
      /// <summary> Returns a list of all AD groups for an AD user </summary>
      function GetADUserGroupMemberships(const aDomain, aUser: String):TStringList;
    
      /// <summary> Checks if an AD user is member of one or more specific groups</summary>
      function UserHasADGroupMembership(const aDomain, aUser: String; const GroupList: TAdGroupList): Boolean;
    
    
    implementation
    
    function EnumADUserGroupMemberships(const aDomain, aUser: String; EnumHandler: TAnonParamFunc<IADsGroup, Boolean>):Boolean;
    var
      hr: HREsult;
      User: IADsUser;
      Enum: IEnumVariant;
      varGroup: OleVariant;
      EnumHelper: LongWord;
    begin
      Result := False;
      CoInitialize(nil);
      try
        hr := ADsGetObject('WinNT://'+aDomain+'/'+aUser+',user',IID_IADsUser3 , User);
        if not Failed(hr)
        then begin
          try
            Enum := User.Groups._NewEnum as IEnumVariant;
            while Assigned(Enum) and (Enum.Next(1, varGroup, EnumHelper) = S_OK)
            do begin
              try
                if EnumHandler(IDispatch(varGroup) as IADsGroup)
                 then EXIT(True);
              finally
                VariantClear(varGroup);
              end;
            end;
          finally
            User := nil;
          end;
        end;
      finally
        CoUninitialize;
      end;
    end;
    
    function GetADUserGroupMemberships(const aDomain, aUser: String):TStringList;
    var
      List: TStringList;
    begin
      List := TStringList.Create;
      List.BeginUpdate;
      try
        EnumADUserGroupMemberships(aDomain, aUser,
          function(const Group: IAdsGroup):Boolean
          begin
            Result := False;
            List.Add(Group.Name + ' ' + Group.Class_);
          end);
      finally
        List.Sort;
        List.Insert(0, aDomain +'\'+ aUser);
        List.EndUpdate;
        Result := List;
      end;
    end;
    
    function UserHasADGroupMembership(const aDomain, aUser: String; const GroupList: TAdGroupList): Boolean;
    begin
      Result := EnumADUserGroupMemberships(aDomain, aUser,
          function(const Group: IAdsGroup):Boolean
          var
            GroupName: String;
          begin
            Result := False;
            for GroupName in GroupList
            do begin
              Result := CompareText(GroupName, Group.Name) = 0;
              if Result
               then Break; // Return true for first match
            end;
          end);
    end;
    
    end.

     

    • Thanks 1

  4. 8 hours ago, zsleo said:

    Also, the app that controls that data is unfortunately installed in that location.

    I'd complain loudly to the company that wrote that app.  These folders have been forbidden for the last 15 years - at least.

    Dynamic data should go to user folders for user specific data, or AppData for system wide data.

     


  5. I'd forgo all PowerBuilder UI related things and focus on the function of the app - what does it need to do.

     

    Analyse the code (a "screen" here is a reference to a window or combination of windows/controls)

    - how do you navigate it

    - what does each screen do

    - where does it get its data

    - how does it treat and display the data

    - what can you do within that screen
     

    You would only need to focus on bringing the content and functionality over, without dwelling too much on the old-school PowerBuilder UI code.
    It would be more of a rewrite than a migration.


  6. 27 minutes ago, Fr0sT.Brutal said:

    Nope on your nope 😉 That was more or less actual when the question was asked (12 yr ago) but now, according to your estimations, it's 3x legacy. IE8 in 22 is hardly a something to consider

    So, TNetEncoding.HTML.Decode needs to be updated to support HTML5...

    Edit: Looks like a significant expansion of named entities.

    HTML5: https://www.w3.org/TR/2011/WD-html5-20110525/named-character-references.html
    HTML4: https://www.w3.org/TR/html4/sgml/entities.html

     

     

×