Jump to content

Remy Lebeau

Members
  • Content Count

    2322
  • Joined

  • Last visited

  • Days Won

    94

Everything posted by Remy Lebeau

  1. Remy Lebeau

    Not Threadsafe??

    Blocking the app does not require blocking the UI thread. Your code should not sit there blocking the main UI thread waiting until the worker thread ends. Let the code in the UI thread return control back to the VCL's main message loop. Have the thread notify your code when it has finished its work. Simply prevent the user from interacting with your UI in the meantime, if that is what you need to do. Both of the solutions presented to you above will accomplish that for you. You should read the following article: Modality, part 1: UI-modality vs code-modality It is written from the perspective of the Win32 API, but since the VCL is based on Win32, the same concept applies in this case. That requires message handling. Of course, you will get that with an Application.ProcessMessages() loop, but that opens up your code to a host of issues, which have already been pointed out earlier. If you are going to process messages anyway, you may as well let the VCL do it for you. Don't block your UI thread.
  2. Remy Lebeau

    Why does CoInitializeEx returns 1 or $80010106 ?

    Unfortunately, as I already pointed out earlier, the VCL's TApplication constructor calls OleInitialize() before the ComObj unit has a chance to call CoInitialize/Ex(), and OleInitialize() internally calls CoInitialize(nil), so if you require CoInitializeEx() with any mode other than COINIT_APARTMENTTHREADED then you will have to do your COM work in a separate worker thread instead of in the UI thread. The ComObj unit is not the only unit that uses InitProc. InitProc is a chained list of initialization procedures, so you can't use Assigned(InitProc) alone as an indicator of whether you should call CoInitializeEx() or not. If you need CoInitializeEx() called, then just call it yourself unconditionally, and just be sure to pay attention to whether it fails or not. Returning S_FALSE is NOT a failure condition! A thread cannot change its COM threading mode once it has been set. That is what the RPC_E_CHANGED_MODE error code tells you. That IS a failure condition! If you need to use a different COM threading model than the calling thread has already been set to, you will have to move your COM work to another thread that is able to be set to the desired COM model. Typically, but not necessarily always. It really depends on each app's particular requirements.
  3. Remy Lebeau

    Not Threadsafe??

    In that kind of example, I would probably opt to use the TThread.OnTerminate event instead, eg: type TMainForm = class(TForm) private ProcessingThread: TThread; procedure EnableUI; procedure DisableUI; procedure ThreadFinished(Sender: TObject); procedure ThreadTerminated(Sender: TObject); ... end; procedure TMainForm.BtnClick(Sender: TObject); begin if Assigned(ProcessingThread) then Exit; DisableUI; try ProcessingThread := TThread.CreateAnonymousThread( procedure begin // do work here end ); ProcessingThread.OnTerminate := ThreadFinished; try ProcessingThread.Start; except FreeAndNil(ProcessingThread); raise; end; except EnableUI; end; end; procedure TMainForm.ThreadFinished(Sender: TObject); begin ProcessingThread := nil; EnableUI; end; procedure TMainForm.ThreadTerminated(Sender: TObject); begin ProcessingThread := nil; Close; end; procedure TMainForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean); begin CanClose := not Assigned(ProcessingThread); if not CanClose then begin ProcessingThread.OnTerminate := ThreadTerminated; ProcessingThread.Terminate; // display a "Please wait" UI ... end; end;
  4. Remy Lebeau

    SSL not found when using idHttp in docker image

    When loading OpenSSL, Indy checks for a whole list of different filenames, including the 4 you have shown above. The order in which that list is attempted can be influenced by setting Indy's CanLoadSymLinks and LoadSymLinksFirst settings before the libs are loaded. By default, it will attempt to load the unversioned files first, so if that is problematic (because they map to a newer unsupported version of OpenSSL) then you should turn off the CanLoadSymLinks or LoadSymLinksFirst setting so the version-specific libs are attempted first/solely. There are public IdOpenSSLSetCanLoadSymLinks() and IdOpenSSLSetLoadSymLinksFirst() functions in the IdSSLOpenSSLHeaders unit for that purpose. See https://www.indyproject.org/2018/05/04/changes-for-how-openssl-is-loaded-on-nix-platforms/
  5. Remy Lebeau

    SSL not found when using idHttp in docker image

    What does Indy's IdSSLOpenSSLHeaders.WhichFailedToLoad() function return after the error has occurred? Indy's default TIdSSLIOHandlerSocketOpenSSL component supports up to OpenSSL 1.0.2, it cannot use OpenSSL 1.1.x+, so you need to use this work-in-progress SSLIOHandler instead for newer OpenSSL versions.
  6. Remy Lebeau

    Passing data between sockets

    You are probably thinking of the TIdTCPStream class. You can assign a target TIdTCPConnection to it, and then pass it to the IOHandler.ReadStream() method of a source TIdTCPConnection. You can then tell ReadStream() to either read a specific number of bytes, or to read endlessly until the source socket disconnects. Any bytes read in from the source will be written out to the target.
  7. Remy Lebeau

    Why does CoInitializeEx returns 1 or $80010106 ?

    Can you be more specific?
  8. Remy Lebeau

    Why does CoInitializeEx returns 1 or $80010106 ?

    Per https://stackoverflow.com/a/20019023/65863: And also: https://learn.microsoft.com/en-us/windows/win32/api/ole2/nf-ole2-oleinitialize So, there you go. If your project uses the ComObj unit, it will call CoInitialize/Ex() when Vcl.Forms.TApplication.Initialize() is called, which won't matter since the constructor of Vcl.Forms.TApplication will have already called OleInitialize() beforehand, which calls CoInitializeEx(): constructor TApplication.Create(AOwner: TComponent); var ... begin inherited Create(AOwner); if not IsLibrary then FNeedToUninitialize := Succeeded(OleInitialize(nil)); ... end;
  9. Remy Lebeau

    Why does CoInitializeEx returns 1 or $80010106 ?

    That is S_FALSE. That is RPC_E_CHANGED_MODE. Per the documentation: https://learn.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-coinitializeex This means that you are calling CoInitializeEx() on a thread that has already called CoInitialize/Ex() successfully, where S_FALSE means you are trying to set the same concurrency model that has already been assigned to the thread, whereas RPC_E_CHANGED_MODE means you are specifying a concurrency model that is not compatible with the thread's current concurrency model. For instance, are you calling CoInitializeEx() in the main UI thread? The RTL's System.Win.ComObj unit initializes COM in the main UI thread during program startup, using the global CoInitFlags variable to decide whether to use CoInitialize() or CoInitializeEx().
  10. Remy Lebeau

    COM: OleCheck() in polling

    1 is S_FALSE. Per the documentation: https://learn.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-coinitializeex This means that you are calling CoInitializeEx() on a thread that has already called CoInitialize/Ex() successfully, and you are specifying the same concurrency model that has already been assigned to the thread. For instance, are you calling CoInitializeEx() in the main UI thread? The RTL's System.Win.ComObj unit initializes COM in the main UI thread during program startup, using the global CoInitFlags variable to decide whether to use CoInitialize() or CoInitializeEx().
  11. Put the raw data into a separate binary file, and then add an .rc script to your project (or use the Resources and Images dialog) to compile the data file as an RCDATA resource in your final executable's resources. Then, in your code, you can use a TResourceStream whenever you want to access the resource data at runtime. See Resource Files Support (just ignore the part about using a Multi-Device project, this works in a VCL project, too).
  12. Remy Lebeau

    [Very unsure] Indy vs sgcIndy

    No recent updates, still pending review: https://github.com/indySockets/indy/pull/299 Correct. It is just built on top of Indy. Their website says: https://www.esegece.com/products/indy/features-overview I agree. As already pointed out, Indy's license does allow them to sell their derivative work. However, I don't like that their website is advertising their product as "Indy", it really should be advertised as "sgcIndy" instead. @esegece I would really appreciate it if you changed the product naming on your website accordingly, and actually explain on it what your product actually is. It is not Indy itself, it is a modification/addon to Indy. Also, your "Quick Start" guide suggests that you have made custom modifications to Indy's default OpenSSL SSLIOHandler, rather than introducing a new SSLIOHandler, as the pending pull request is doing. I would be interested in knowing what kind of modifications you have made to enable that in the default SSLIOHandler, given the extensive and breaking API changes that were introduced in OpenSSL 1.1.x.
  13. Remy Lebeau

    How to force update to label during a loop

    Can to elaborate more?
  14. You forgot to add an OnKeyUp event handler to reset the direction. procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin case Key of Ord('W'): fdirection := diup; Ord('A'): fDirection := diLeft; Ord('D'): fDirection := diRight; Ord('X'): fDirection := diDown; end; end; procedure TForm1.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); begin case Key of Ord('W'), Ord('A'), Ord('D'), Ord('X'): fDirection := diNone; end; end;
  15. Remy Lebeau

    Protected TCP/IP Client/Server connection

    That is exactly what TLS is meant for. It handles ALL of that stuff for you. Clients can validate that they are connected to the official server and not another server (especially a man-in-the-middle). And the server can validate that only trusted clients are connecting to it. And ALL communication is encrypted back and forth.
  16. Remy Lebeau

    OpenSSL fails to Load

    OpenSSL is an external 3rd party library written in C, so of course it can't use a Delphi unit. Also, OpenSSL uses 2 lib binaries that are LINKED together when they are compiled, the filenames are not hard-coded in code, they are established during the compile/link stages (ie, 1 lib statically imports functions from the other lib), hence why you would have to recompile OpenSSL in order to change its lib filenames.
  17. Remy Lebeau

    Creating FMX controls in a background thread

    Create() is just a class constructor. In runs in the context of whatever thread calls it, like any other class method. And it does not create any OS window, that happens later. For VCL, all TWinControl-derived UI controls have their own window handle that is created by calling into the OS, and all TGraphicControl-derived UI controls use their parent TWinControl's window. The creation of that window happens in the context of whatever thread is first to access the window. IOW the control creates its OS window on an as-needed basis. However, once it has been created, it is bound to the thread context that created it. There is no OS thread transferring ownership to a Delphi thread. So, for example, if you create a VCL UI control in the context of the main thread, but the first use of its window is in the context of a worker thread, then the window is bound to the worker thread, not to the main thread. As such, only the worker thread can receive and dispatch messages for the window, even though the Delphi object that owns the window is in the main thread. For FMX, by default child UI controls do not have their own OS windows at all, only the parent TForm has an OS window. Child UI controls are designed to act upon, and render themselves inside of, the parent Form's window. However, this is complicated in recent Delphi versions by the introduction of the ControlType property on various controls, like TEdit. In which case, it is possible for some child UI controls to have a native OS window of their own, which runs on top of the parent Form's window, similar to VCL controls.
  18. Remy Lebeau

    OpenSSL fails to Load

    That would require recompiling the OpenSSL libs so could can still find each other using the new filenames. I think this may be device-specific. I've had some reports that OpenSSL libs couldn't be loaded if they were using the same filenames as the BoringSSL libs, and at the time (I don't know if this is still true) BoringSSL did use the original OpenSSL filenames. And I've had some reports of users successfully loading OpenSSL libs even on BoringSSL systems. The OpenSSL filenames are hard-coded in Indy. I would have to add a new API to the IdSSLOpenSSLHeaders unit to allow loading of user-defined filenames.
  19. Remy Lebeau

    OpenSSL fails to Load

    It used to, but Google dropped support for OpenSSL in favor of BoringSSL (their own customized fork of OpenSSL) in Android 6. See this answer on StackOverflow, which I posted about this issue at the time.
  20. Why are you using MaxInt for the timeout, and not simply using Infinite instead? Then you can get rid of the while loop. // now the server is processing requests // wait for terminate signal MyEvent.WaitFor(Infinite);
  21. Remy Lebeau

    How to draw a semitransparent ellipse on a canvas?

    TColor is an enum representing an integer, and so it is subject to endian. TRGBQuad is not. You should be using the ColorToRGB() function to convert an TColor value into an integer value, and then using the Get(R|G|B)Value() functions to obtain the individual R/G/B values of that integer. The PremultiplyAlpha() function is operating on a bitmap's raw R/G/B pixel bytes directly, it is not going through TColor at all.
  22. Remy Lebeau

    SHGetSpecialFolderLocation in FireMonkey

    Correct, since FMX is cross-platform, but you are trying to use platform-specific code. So, you will have to #ifdef your code for Windows, and then #include the relevant header files, in this case <windows.h> and <shlobj.h> (NOT <shlobj_core.h> directly). Also, FYI, SHGetSpecialFolderLocation() is very old, so you should be using SHGetFolderPathW() instead, or even SHGetKnownFolderPath(). That is just a warning. Ignore it, and or turn it off in the compiler settings. SHGetFolderPath() was introduced in Windows 2000. Any old compiler that doesn't recognize it is too old to support FireMonkey anyway.
  23. Just a thought - have you tried using SysInternals Process Monitor yet to see all of the Registry activity that Explorer invokes on Windows7 vs Windows 10/11 while registering the property handler and while loading the .arw file?
  24. That is a very good point, I completely forgot about that! It has been a long time since I last worked with Shell Extension handlers.
  25. The scanner app does not need to know the local device IP just to send data to another device. It only needs to know the receiver's IP. Probably best to use DNS/mDNS or other local network discovery protocol to discover the receiver's IP dynamically at runtime. The Android server app does not need to know the local device IP just to connect to another server. And it does not need to know the local device IP to accept connections, for that matter. So, I'm still wondering why you actually need to query the device IP at all.
×