Jump to content
Registration disabled at the moment Read more... ×

Remy Lebeau

Members
  • Content Count

    3031
  • Joined

  • Last visited

  • Days Won

    138

Posts posted by Remy Lebeau


  1. 3 hours ago, Rafael Dipold said:

    is there any way to force the connection only via IPv4 in this example?

    If you were using Indy's TIdHTTP, then it would automatically use IPv4 unless the requested URL is bracketed, eg: "http://[HostOrIPv6Address]/", which would force IPv6.

     

    For the RTL's THTTPClient, I have no idea how it behaves in regards to IPv4/IPv6.

    • Like 2

  2. 1 hour ago, Dwest said:

    My boss seems to think it may be some sort of security issue with the program communicating with the API since it works in the browser and throws errors in the program.

    If you can ensure the submitted data is absolutely identical in both browser and Indy, then the only thing I can think of is if the server is sensitive to the User-Agent that is making the request.  Some webservers change their behavior depending on which browser is asking, and it is not uncommon for webservers to behave weird/incorrect when encountering Indy's default User-Agent.  Try setting the TIdHTTP.Request.UserAgent property to mimic Chrome, see if that makes any difference.


  3. Did you make any changes to your setup recently?

     

    A search online suggests that Runtime Error 236 might be related to a mismatch between dependent package binaries.

     

    A search though the RTL source code suggests that Runtime Error 236 means the System.TMonitor class is crashing because its underlying support system is not initialized.

    • Like 1

  4. 2 hours ago, Dwest said:

    To accomplish this, it puts all of the coordinates of the 100 points into a URL

    Depending on the length of the data, and just how many points are being sent, I probably would not have used the URL for that.  WebServers tend to limit how much data can be sent in a URL query string.  A POST body might have made more sense.

    2 hours ago, Dwest said:

    For testing, we made it return the URL to a txt file, and then the output to a separate txt file. In 10.3.3, the output txt file returns coordinate sets for all of the mapped points. In 12, it returns errors. Originally, we thought it could be a mapping service API error, except when the Input URL (generated by Delphi 12) is entered in google chrome, it returns back correctly.

    Did you try comparing Chrome's raw HTTP request/response data to TIdHTTP's raw HTTP request/response data for differences?  You can use Chrome's built-in debugger to get the HTTP data it exchanges over the wire, and you can attach a TIdLog... component to the TIdHTTP.Intercept property to get the HTTP data it exchanges over the wire.

    2 hours ago, Dwest said:

    The code between the 2 versions is copy-paste. We are thinking it could be a version issue, so I am looking to see if the code for the HTTP component may have changed between version 10.3.3 and version 12 of Delphi.

    There were a handful of checkins for TIdHTTP between those 2 versions, but offhand I don't see anything that would affect what you describe.

    2 hours ago, Dwest said:

    The exact error message that is being received is....

    {"results":null,"errors":["Coordinate with id 0 is not valid. Please check separators. Error ID: 6d5d190c-5024-4152-9d81-bee145224322"],"processingTimeDesc":null,"responseCode":"400","warnings":null,"requestId":null}

    Offhand, the first thing that comes to mind is the formatting of {COORD1}, {COORD2}, etc.  What does that actually look like? (without revealing real numbers. Can you use fake numbers?) The error message says to check the separators, do the coordinates have their own separators in them?  If so, are you perhaps using locale-based separators in the formatting?

    • Like 1

  5. 8 hours ago, Brian Warner said:

    GetIt is down, so I can't get exact Indy version

    Indy is not in GetIt. It is preinstalled with Delphi itself.

    8 hours ago, Brian Warner said:

     As  my program starts, it checks the windows path and, if necessary, adds \AROOT\PROGRAMS\ to the path using Get/SetEnvironmentVariable.

    That is not the correct approach to take. If you need to control where the DLLs are loaded from at runtime, you should be using the Win32 SetDllDirectory() or AddDllDirectory() function instead.  Or, you can also use Indy's IdOpenSSLSetLibPath() function.

     

    In any case, whether you use SetEnvironmentVariable() or (Set|Add)DllDirectory(), this API-based path update only affects the calling process, not the user/system as a whole. So, any app not running in your folder will need to do the same API update for itself to look for the DLLs in your folder.  Unless you manually update the user/system config directly. 

    8 hours ago, Brian Warner said:

    it's not practical to have the pair in every directory with a program needing them.

    That's exactly how they are intended to be used, and should be used. Unless you have a group of related apps that need to use the same version of the DLLs, then they can be shared in a folder that all of the apps agree on.

    8 hours ago, Brian Warner said:

    Any thoughts on what might solve the problem?

    My guess is either:

     

    - there is another version of the DLLs present on the system, which is not compatible with the server in question, and the failing app is finding those DLLs instead of the ones you want. You should have the app log out the full paths of the DLLs it actually loaded into memory (not the paths it thinks it loaded).

     

    - the failing app is not configuring the DLLs properly to work with the server in question.

     

    There is not enough information provided to diagnose your problem one way or another.  We need to see your ACTUAL setup, and your ACTUAL code.


  6. 15 minutes ago, Kas Ob. said:

    Thread.Free is a blocking call and will not return until the Thread.Execute is finished and exited, so if an event is still holding the thread execution then fEvent.Free will not be reached until it is set/triggered, hence the the need to either trigger the event in the destructor by destroying/freeing it or trigger it explicitly before the inherited destructor then freeing it.

    The event is signaled when TerminatedSet() is called. TerminatedSet() is called by the Terminated property setter. If the thread is still running when the TThread object is being destroyed, the inherited destructor will set the Terminated property and wait for the thread to finish running. 

    • Like 3

  7. 8 hours ago, dormky said:

    Well, it seems that no matter what I do, the timer's callback is always executed in the main thread.

    That means you are creating the TTimer in the main thread to begin with, not in the background thread.

    8 hours ago, dormky said:

    Anyone have a recommendation for a TTimer equivalent that has its callback executed in the thread it was created in ?

    That's exactly how TTimer already works.  Its constructor creates a hidden window in the calling thread, which when activated will then receive timer messages from that same thread.  So the thread that creates the TTimer must have a message loop to receive and dispatch those timer messages.  So, you might think about moving the creation of the TTimer into the background thread's Execute() method, and that may work 99% of the time, but know that the creation of that hidden window is not done in a thread-safe manner, so you really should not be using TTimer in a background thread at all.

     

    If you really need a thread-based timer, you could just use the Win32 timeSetEvent() function, which is a multimedia timer that runs its callback in a background thread that the OS manages,

     

    If you really want to use a custom TThread class, then using TEvent is the simplest option that allows you to terminate the thread on demand, eg:

    uses
      ..., Classes, SyncObjs;
    
    type
      TTimerThread = class (TThread)
      private
        fEvent: TEvent;
        fInterval: LongWord;
        fOnElapsed: TNotifyEvent;
      protected
        procedure Execute; override;
        procedure TerminatedSet; override;
      public
        constructor Create(AInterval: LongWord; AOnElapsed: TNotifyEvent); reintroduce;
        destructor Destroy;
      end;
      
    constructor TTimerThread.Create(AInterval: LongWord; AOnTimer: TNotifyEvent);
    begin
      inherited Create(False);
      fInterval := AInterval;
      fOnElapsed := AOnElapsed;
      fEvent := TEvent.Create;
    end;
    
    destructor TTimerThread.Destroy;
    begin
      fEvent.Free;
      inherited Destroy;
    end;
    
    procedure TTimerThread.TerminatedSet;
    begin
      fEvent.SetEvent;
    end;
    
    procedure TTimerThread.Execute;
    begin
      while fEvent.WaitFor(fInterval) = wrTimeout do
        fOnElapsed(Self);
    end;

     

    • Like 2

  8. Their system went down late Friday night, multiple servers were affected, including DocWiki, Blogs, QualityPortal, etc.  Last I heard, they are still working on resolving the problem.


  9. 1 hour ago, Bart Kindt said:

    After re-installing my App, I no longer can open the database file. I can see it, it exists. But no matter what I try, I can no longer open the file.

    How exactly are you attempting to open the file? Are you getting an error? If so, what is it?

    1 hour ago, Bart Kindt said:

    How can I find ANY place on my Android device where I can read a file which is supplied by nother program

    I'm no Android expert, but outside of a public folder, I think Android does not allow two apps to share files with each other unless both apps cooperate with each other, ie the providing app has to grant access to the receiving app. And since the providing app in this case is no longer available, you might be SOL.

    1 hour ago, Bart Kindt said:

    How can I for example IMPORT the original files, and then copy them back in place?

    🤷


  10. 49 minutes ago, Attila Kovacs said:

    I'll consider it to be Nessie's droppings until someone can show me how to make Delphi spit out otareses.

    Why? What are you planning on doing with otares files if you could get them generated? Delphi doesn't use otares files anymore, it's a legacy thing only. 


  11. On 1/11/2024 at 10:19 AM, Ian Branch said:

    I allways thought that a Continue would have automatically caused Suppliers to move to the next record by virtue of the 'while not Suppliers.eof do'.

    Nope.  Eof simply evaluates the current record, it does not move to another record.  Hence the need to call Next() explicitly.

    On 1/11/2024 at 10:19 AM, Ian Branch said:

    Was my understand incorrect

    Yes.

    • Like 1

  12. 6 hours ago, msd said:

    Is it possible to extend the standard VCL component with some features (properties) without creating a new component?

    In a word, no.

     

    However, if you intend to use the extended component in just one form/project, and don't mind setting the new properties in code at runtime rather than with the Object Inspector at design-time, then you could use an interposer class to add the properties, and that way you don't have to make the extra effort of putting the new component in a new package and installing it into the IDE.

    6 hours ago, msd said:

    For example, I need to add two string properties to the CheckBox component (for auto-saving in an inifile

    For example:

    unit MyUnit;
    
    interface
    
    uses
      ..., Vcl.Forms, Vcl.StdCtrls, System.IniFiles, ...;
    
    type
      TCheckBox = class(Vcl.StdCtrls.TCheckBox)
      public
        IniSection: string;
        IniProperty: string; 
        procedure LoadFromIni(Ini: TCustomIniFile);
        procedure SaveToIni(Ini: TCustomIniFile);
      end;
    
      TMyForm = class(TForm)
        SomeCheckBox: TCheckBox;
        procedure FormCreate(Sender: TObject);
        ...
      private
        procedure LoadConfig;
        procedure SaveConfig;
      end;
    
    ...
    
    implementation
    
    ...
    
    procedure TCheckBox.LoadFromIni(Ini: TCustomIniFile);
    begin
      Checked := Ini.ReadBool(IniSection, IniProperty, False);
    end;
    
    procedure TCheckBox.SaveToIni(Ini: TCustomIniFile);
    begin
      Ini.WriteBool(IniSection, IniProperty, Checked);
    end;
    
    procedure TMyForm.FormCreate(Sender: TObject);
    begin
      SomeCheckBox.IniSection := ...;
      SomeCheckBox.IniProperty := ...;
    end;
    
    procedure TMyForm.LoadConfig;
    var
      Ini: TIniFile;
    begin
      ...
      SomeCheckBox.LoadFromIni(Ini);
      ...
    end;
    
    procedure TMyForm.SaveConfig;
    var
      Ini: TIniFile;
    begin
      ...
      SomeCheckBox.SaveToIni(Ini);
      ...
    end;

     

    • Like 1
    • Thanks 1

  13. 13 minutes ago, Geule said:

    I got this error Access violation KERNELBASE.dll

    I updated my earlier example.  Make sure CmdLine is not pointing at a string literal when passing it to CreateProcess(), as the 2nd parameter of the Unicode version of CreateProcess() (CreateProcessW) is not allowed to point at read-only memory.


  14. 3 hours ago, Geule said:

    how can I do this directly in Delphi.

    Use the Win32 CreateProcess() function.  Of course, a better option might be to NOT shell out to openssl.exe at all, but to use the OpenSSL API directly in your own code instead.  It really depends on what you are trying to accomplish exactly.

    3 hours ago, Geule said:

    MS-DOS commands run normally in Delphi.

    Only if you execute them as parameters to cmd.exe.

    3 hours ago, Geule said:

    But openssl commands don't.

    Then you are doing something wrong, but we can't see what you are actually doing. Please show your actual code you are having trouble with.

    3 hours ago, Geule said:

    Anyone who can help me with this?

    A simple example that I'm trying to run: "openssl version"

    For example:

    uses
      ..., Windows;
      
    procedure RunCommandLine(CmdLine: String);
    var
      si: TStartupInfo;
      pi: TProcessInformation;
    begin
      {$IFDEF UNICODE}UniqueString(CmdLine);{$ENDIF}
      ZeroMemory(@si, SizeOf(si));
      si.cb := SizeOf(si);
      if not CreateProcess(nil, PChar(CmdLine), nil, nil, False, 0, nil, nil, si, pi) then
        RaiseLastOSError;
      ...
      CloseHandle(pi.hThread);
      CloseHandle(pi.hProcess);
    end;
    
    ...
    
    RunCommandLine('C:\path\openssl.exe version');

    Just note that openssl.exe is a console app, so if you run this code in a non-console program, it will create a new console that will close when openssl.exe exits.  If you actually want to see the console window to read the output, or even to capture the output into your own code, requires more work than this code shows.


  15. 6 hours ago, Attila Kovacs said:

    Is there somewhere in the IDE something which would show me a list about the generated files after a build/compile?

    I would like to see the full path of every single files, also bpl's, dcp etc...

    There is no such list generated by the IDE/compiler.  And the only documentation that I know of which talks about generated files is:

    File Types Index

    File Extensions of Files Generated by RAD Studio

    • Like 2

  16. 4 hours ago, dormky said:

    And this is a metronome, so I need to be as exact as possible.

    Then TTimer is not a good choice, as it is not a real-time timer, it is a message-based timer, and so is subject to the speed of the message queue. And also, the WM_TIMER message is low-priority and only generated when there are no other messages pending.  You should use an actual multimedia timer instead.  And don't use PlaySound() when high performance is needed.  Pre-prepare the audio sample ahead of time and use a multimedia API to play the sample when needed.  Such as waveOutWrite(), or more modern audio APIs like WASAPI, DirectSound/XAudio2, etc.


  17. 11 minutes ago, alogrep said:
    Is there a manual way to ensure the unchecked package remains unchecked?

    You can update the "HKCU\SOFTWARE\Embarcadero\BDS\23.0\Known Packages" Registry key.  Find the entry for the package, and either:

    • modify the entry's Data value to prefix it with an underscore ("_").
    • remove the entry (optionally move it to the "HKCU\SOFTWARE\Embarcadero\BDS\23.0\Disabled Packages" key)

     

    • Like 1

  18. 1 hour ago, miguelandradebr said:

    I've fixed it changing the .exe file to admin permissions, thanks guys!

    If your app actually needs admin rights, then you should add an application manifest to your project to specify its requestedExecutionLevel at compile-time, not change the properties of the EXE file after the compile is finished.  Modern Delphi versions even have a project setting for that very purpose:

    http://docwiki.embarcadero.com/RADStudio/en/Manifest_File

    http://docwiki.embarcadero.com/RADStudio/en/Application_Manifest

    1 hour ago, miguelandradebr said:

    what do you mean with IDE elevated?

    Basically, what you did for your app, but for the IDE instead, so it runs as an admin, and then any project it runs will also run as an admin.


  19. You should NEVER stream pointers from one process' address space into another process' address space, unless both processes are running concurrently and one process needs to directly access the other process's memory via the ReadProcessMemory() and/or WriteProcessMemory() APIs (using shared memory would be better, though).

     

    Otherwise, just don't do it!  Stream offsets instead.  And in the example given, a linked list can certainly be streamed using offsets instead of pointers.  The actual pointers would only be meaningful in the memory of the process that originally creates the list, and in the process that loads the stream into a new list in it own memory.  Pointers are fairly meaningless when passed around from one process to another.

    • Thanks 1
×