Jump to content

dummzeuch

Members
  • Content Count

    3019
  • Joined

  • Last visited

  • Days Won

    108

Posts posted by dummzeuch


  1. I usually don't prepare anything. I just run the update installer and expect it to simply work (which it mostly does). 

    Having said that, I don't use GetIt to install anything apart from patches and I always compile components and - if possible - plugins from source, so the possibilities for the installer to mess up are limited. Also, I am not using the current Delphi version for production work (apart from the obvious maintenance for GExperts and a few other version specific tools), so if an update goes wrong, it won't be a catastrophe, unless it breaks an older Delphi version too.

    • Like 2

  2. 18 hours ago, pyscripter said:

    This is just to say that pyscripter/Ssh-Pascal: Delphi ssh library wrapping libssh2 (github.com) includes binaries that do not require OpenSSL, but use Windows CNG instead.  It also includes scripts that make it very easy to update the binaries.

    Unfortunately the included dll did not work for me. I googled the error message (which I no longer recall) and found the advice to switch to the dlls from the PHP project. Those dlls worked fine with the same code and the same ssh server.


  3. 23 hours ago, tgbs said:

    Edit: A program can be written that performs something like this
    ssh user@Server-IP> 'sudo myscript.sh'

    That's so obvious that I just asked myself why I didn't think of it.

    So, thanks a lot!

     

    I could either call plink.exe (from Putty) or even easier, use libssh2 and the pascal bindings from @pyscripter.

    In fact I just got the sources, downloaded the libssh2 and openssl dlls from the PHP project page and changed the SshExec demo to bypass the password prompt and call a test script as root. Worked fine. And as a plus I don't even have to install anything on the server, just use the existing ssh server, create some scripts and allow the appropriate users to call them as root without password in the sudoers configuration.

    • Like 4

  4. 1 hour ago, tgbs said:

    There is an add-on in Cockpit for ZFS Storage.
    In the cockpit, you log in with the corresponding Linux user

    Sorry, my fault for not asking properly: I am not looking for a tool to replace Putty + the menu or the Linux shell, I am looking for a tool that allows a Delphi program to initiate starting those scripts, e.g. via a REST service.


  5. I have got a need to execute some simple Perl scripts on a Ubuntu Linux server on the LAN (no Internet involved).

    So far, I am executing them via Putty in an ssh session that shows a small menu written in Perl. But that's cumbersome and I would prefer to have a Delphi client that requests a service to execute them.

    As these commands require root privileges (*1) security is a big deal, so at least https and basic authentication should be used.

     

    I could probably install Apache or a different web server and execute these commands via cgi, but this feels way overblown.

    Some kind of REST API is what I am looking for, but I don't have any experience with the server side of that.

     

    Any suggestions?

     

    Just in case anybody wants to suggest that: We don't have a Delph license that allows writing Linux programs.

     

    (*1: It's about creating zfs datasets and snapshots and changing their mount points.)


  6. 10 minutes ago, Die Holländer said:

    Fortran on place 9.. Why or for what is Fortran so populair nowadays?

    1.8% rating is far from being popular. It's just marginally better than the 1.64% of SQL on place 11. Compare that to the ratings of the top 3!

    That's one of the problems with this "index". The differences between the rankings even some in the top 10 are lower than the error margins of the data source.

    • Like 4

  7. On 10/8/2024 at 3:36 AM, dmitrybv said:

    But if the developers of System.IniFiles.TIniFile implemented a limit of 2047, then why did they do it only for TIniFile.ReadString (without throwing an exception when exceeded), but not for TIniFile.WriteString.

    They probably thought that 2047 was "enough for everybody" and didn't think of it as a limit, so they didn't impose a limit on WriteString either.

    But we can only guess.

     

    OTOH nobody(*1) uses TIniFile any more but TMemIniFile because it overcomes all the limitations of Get/SetPrivateProfileString so that's a moot point.

     

    (*1 for suitable definitions of nobody )

    • Like 3

  8. 10 hours ago, Rollo62 said:

    But this would run fine too.

    
    procedure Test;
    begin
      Abort;
    end;

    It should be good enough to use fully qualified names only in cases of ambiguity, IMHO.
    The compiler shows such cases.

     

    But in the uses clause I always use fully qualified names.

    "Abort" is a popular name for procedures and methods, that's why it came to mind. I had to qualify it several times in my code because there was an ambiguity. I'm too lazy to use that qualifier without a good reason.

    Uwe's answer looks like a good solution for these cases. I hope I remember it the next time this comes up.


  9. You can have a lot of fun when starting to use namespaces.

     

    This compiles fine ...

    unit bla;
    
    uses
      SysUtils;
    
    interface
    
    implementation
    
    procedure Test;
    begin
      SysUtils.Abort;
    end;

    ... until you add the namespace to the unit name ...

    unit bla;
    
    uses
      System.SysUtils;
    
    interface
    
    implementation
    
    procedure Test;
    begin
      SysUtils.Abort;
    end;

    ... but do you really want to write System.SysUtils.Abort ?

     

    This is just an example. You don't of course need to qualify Abort, but if there are name clashes in different units you have to, or you can rely on the order of the units in the uses clause, which I think is a bad idea.


  10. Actually, the concept of namespaces was introduced with Delphi 2005, but the RTL and VCL started using them much later. A quick search in my installations found vcl.controls.pas appearing in Delphi XE2, before that it was just controls.pas


  11. You could have different desktops for these "modes", but they won't switch automatically either.

     

    Hm, maybe you could assign keyboard shortcuts to these menu entries using GExperts, but I'm not sure this is possible.

     

    Edit: It isn't. The menu entries for the configured desktops are added dynamically and don't show up in the GExperts IDE Menu Shortcuts expert. So you can't assign a keyboard shortcut to them. (At least not this way).


  12. Just in case anybody is still reading: I found some code in my program that didn't work once the 2 GB limit was reached. "Fortunately" it was where a DLL was loaded into memory near the start of the execution so it never happened until I configured Windows to start allocating memory from top using the registry:

    HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Memory Management
    AllocationPreference= 0x100000 

    Then all of a sudden it crashed.

     

    I fixed this problem now (I hope).

    It was in dzlib library, unit u_dzResourceDllLoader, btw. so if somebody else is actually using that library, you might want to update.


  13. The Win32 Delphi 2007 program below sets the PEFlag for IMAGE_FILE_LARGE_ADDRESS_AWARE, so I would expect it to have 3 GB of memory available.

    But it writes:

    TotalVirtual 2147352576 Bytes 2,000 GiB
    AvailVirtual 2093465600 Bytes 1,950 GiB

    So why does it say there are only 2 GB?

    The OS is Windows 10 pro 64 Bit with 16 GB of physical memory (from which a lot is available).

    I could have sworn that this has worked before.

     

    Edit: Duh! I forgot an 'or' between 'IMAGE_FILE_NET_RUN_FROM_SWAP' and 'IMAGE_FILE_LARGE_ADDRESS_AWARE'

    program Project1;
    
    {$APPTYPE CONSOLE}
    
    uses
      Windows,
      SysUtils;
    
    {$SETPEFLAGS IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP or IMAGE_FILE_NET_RUN_FROM_SWAP IMAGE_FILE_LARGE_ADDRESS_AWARE}
    
    procedure GetProcedureAddress(var P: Pointer; const ModuleName, ProcName: string);
    var
      ModuleHandle: HMODULE;
    begin
      if not Assigned(P) then begin
        ModuleHandle := GetModuleHandle(PChar(ModuleName));
        if ModuleHandle = 0 then begin
          ModuleHandle := SafeLoadLibrary(PChar(ModuleName));
          if ModuleHandle = 0 then
            raise Exception.CreateFmt('Library %s not found', [ModuleName]);
        end;
        P := GetProcAddress(ModuleHandle, PChar(ProcName));
        if not Assigned(P) then
          raise Exception.CreateFmt('Function %s not found in library %s', [ProcName, ModuleName]);
      end;
    end;
    
    type
      _MEMORYSTATUSEX = packed record
        dwLength: DWORD;
        dwMemoryLoad: DWORD;
        ullTotalPhys: Int64;
        ullAvailPhys: Int64;
        ullTotalPageFile: Int64;
        ullAvailPageFile: Int64;
        ullTotalVirtual: Int64;
        ullAvailVirtual: Int64;
        ullAvailExtendedVirtual: Int64;
      end;
    {$EXTERNALSYM _MEMORYSTATUSEX}
    
      MEMORYSTATUSEX = _MEMORYSTATUSEX;
    {$EXTERNALSYM MEMORYSTATUSEX}
      LPMEMORYSTATUSEX = ^_MEMORYSTATUSEX;
    {$EXTERNALSYM LPMEMORYSTATUSEX}
    
      TMemoryStatusEx = _MEMORYSTATUSEX;
    
    type
      TGlobalMemoryStatusEx = function(out lpBuffer: TMemoryStatusEx): BOOL; stdcall;
    
    var
      _GlobalMemoryStatusEx: TGlobalMemoryStatusEx = nil;
    
    function GlobalMemoryStatusEx(out lpBuffer: TMemoryStatusEx): BOOL; stdcall;
    begin
      GetProcedureAddress(Pointer(@_GlobalMemoryStatusEx), kernel32, 'GlobalMemoryStatusEx');
      Result := _GlobalMemoryStatusEx(lpBuffer);
    end;
    
    function GetTotalMemInfo: string;
    var
      MemStatusEx: TMemoryStatusEx;
    begin
      MemStatusEx.dwLength := SizeOf(MemStatusEx);
      if GlobalMemoryStatusEx(MemStatusEx) then begin
        Result := Format('TotalVirtual %d Bytes %.3f GiB',
          [MemStatusEx.ullTotalVirtual, MemStatusEx.ullTotalVirtual / 1024 / 1024 / 1024]);
        Result := Result + #13#10
          + Format('AvailVirtual %d Bytes %.3f GiB',
          [MemStatusEx.ullAvailVirtual, MemStatusEx.ullAvailVirtual / 1024 / 1024 / 1024]);
      end else begin
        Result := 'GlobalMemoryStatusEx call failed';
      end;
    end;
    
    begin
      try
        WriteLn(GetTotalMemInfo);
        Readln;
      except
        on E: Exception do
          WriteLn(E.ClassName, ': ', E.Message);
      end;
    end.

     


  14. Interesting concept. Thanks for sharing it.

     

    I have never heard about this unit before, but I found this page by googling for "TInputRecArray" "Delphi" which looks a lot like your unit. It's a blog post from 2013 on a Chinese site.

     

    I think the concept could be improved on by using fluid programming like this:

    var
      Value1, Value2, Value3: Variant;
    
    // ...
    
    Success := MultiInputBox(Self)
      .AddField('Enter your age.: ' , 3, ftNumber, 0, Value1)
      .AddField('Enter a hex value.: ', 4, ftHexNumber, 0, Value2)
      .AddField('Enter a float value.: ', 10, ftFloatNumber, Value3)
      .ShowModal;

    That could be done by having MultiInputBox return an interface with an AddField function that returns that interface and a ShowModal function that returns the boolean. That interface then internally declares and manages the TInputRecArray.

    This saves the boilerplate code of declaring and filling the TInputRecArray and make the code (in my opinion) a lot more readable.

    • Like 1
×