Jump to content

Remy Lebeau

Members
  • Content Count

    2684
  • Joined

  • Last visited

  • Days Won

    113

Everything posted by Remy Lebeau

  1. Remy Lebeau

    Delphi 11.1 with TidThreadComponent and TThread.Synchronize

    If you are doing a lot of syncing with the main UI thread, you are likely overwhelming the main thread with too many requests, leaving it with less opportunity to handle UI messages. Every time you call TThread.Synchronize() or TThread.Queue(), it puts the synced method into a list and then posts a message to the main thread to let the RTL know that the list is pending. Once the main thread processes that message, it runs through the entire list, calling each method in order, and doesn't process new messages again until after the list is empty. If you are syncing often, you are going to fill the main thread's message queue with pending requests, and so the main thread is going to spend its time checking and rechecking that list instead of doing other things. So, try to reduce how often you sync with the main thread. For instance, batch up your synced data and then sync the whole batch after X updates are cached, or after N seconds have elapsed, etc. Or, save off just your latest data and use a UI timer in the main thread to grab that data periodically. That means the main UI thread is doing too much work and is not processing UI messages often enough. You need to relieve the pressure on the main thread. No, this would affect VCL in much the same way, as most of the functionality for TThread.Synchronize()/TThread.Queue() is common RTL code that is shared by both frameworks.
  2. Remy Lebeau

    Delphi 11.1 with TidThreadComponent and TThread.Synchronize

    Correct, because your event is being fired in a worker thread, so any access to UI controls must be synchronized with the main UI thread. TThread.Synchronize() runs synchronously. It will not return to the caller until the synched method has been called and exited. That means your worker thread will be blocked waiting on the main UI thread to call the method. TThread.Queue() runs asynchronously. It will return to the caller immediately, and the synched method will run in the background at some unspecified time when the main UI thread gets around to calling it. That means your worker thread will not be blocked waiting on the main UI thread, it will be free to do other things while the synched method waits to be called. Yes, because your worker thread can't do anything while TThread.Synchronize() is blocked waiting. You don't have that issue with TThread.Queue(). What do you mean? Please elaborate.
  3. Remy Lebeau

    Indy 9.0.18 on Delphi 6. Where can i get 9.0.50?

    Thanks, I have checked it in.
  4. Remy Lebeau

    OpenSSL fails to Load

    Unfortunately, when Indy fails to load an OpenSSL library into memory on a non-Windows platform, it does not report WHY the library failed to load. Sounds plausible, given that ARMv7 is 32bit whereas ARMv8 is 64bit. However, ARMv8 can run ARMv7 code, but only when running in ARMv7 mode. You will likely have to search around for (or compile yourself) OpenSSL 1.0.2 binaries for ARMv8. I don't have such binaries available (or else they would have already been checked in to Indy's GitHub repo) Indy isn't coded to support using OpenSSL statically except on iOS. You could try modifying the IdCompilerDefines.inc and IdSSLOpenSSLHeaders_static.pas files to support static OpenSSL on Android. But even then, you would still need suitable binaries for each CPU architecture that your app is targeting.
  5. Remy Lebeau

    old BCB6 question about wmain

    You would be correct. There is no "TCHAR maps to" option (or equivalent) in BCB6. Although you can manually define UNICODE to swap TCHAR between char and wchar_t during compiling, that has no effect on the linker or the startup code.
  6. Then why did you post this in a Delphi forum? There is a separate forum for C++Builder: https://en.delphipraxis.net/forum/41-general-help/ Even in C++, what I stated earlier still applies. .DEF files are not pre-processed, so unless you preprocess the file yourself, you will need to use separate .DEF files for 32bit and 64bit compilations.
  7. Remy Lebeau

    Windows Notification in Exe2 when Exe2 started from Exe1

    Then you will run into problems running your code on Windows 8.1 and later, since GetVersionEx() will report as Windows 8.0 in them. Modern Delphi versions can handle that privilege for you, as you can enable and configure the manifest in the Project Options: https://docwiki.embarcadero.com/RADStudio/en/Application_Options#Manifest_File_.28Windows_Only.29 But, why do you think you need "requireAdministrator"? You don't need admin rights to send notifications. Does Exe2 do other things that require admin rights? However, you will need a custom manifest in order to specify the Windows versions that your code supports, as the IDE does not currently provide options for configuring that list: https://learn.microsoft.com/en-us/windows/win32/sysinfo/targeting-your-application-at-windows-8-1 Only if Exe1 is doing other things that need admin rights. You do not need admin rights to launch Exe2 from Exe1. What about it, exactly, are you asking about? Why? If your code was already supporting them, there is no reason to remove them.
  8. Remy Lebeau

    How to draw a semitransparent ellipse on a canvas?

    I was thinking more along the lines of creating a 32bit Bitmap with an alpha channel and then using the Win32 AlphaBlend() API to draw the bitmap onto the Canvas (I forgot that TCanvas.Draw() has an opacity parameter).
  9. Remy Lebeau

    ENG-US keyboard automatically added on app start

    The VCL certainly does not install new keyboards.
  10. Remy Lebeau

    Windows Notification in Exe2 when Exe2 started from Exe1

    TPlatformNotificationCenter is looking for Windows Windows 8 and higher, yes. Does Exe2 have an app manifest that specifies your code supports Windows 8 and higher? TOSVersion uses the Win32 GetVersionEx() function internally when initializing its Major and Minor properties. GetVersionEx() provides accurate values regardless of app manifest only up to Windows 8.0, but from Windows 8.1 onward, it lies if you do not manifest your app those versions, per Microsoft's documentation: Your screenshots are suggesting that you are running your app on Windows 10 or higher, and your app is manifested only up to Windows 7, not for Windows 8 or higher. When running Exe2 directly in Explorer, or via CreateProcess() in Exe1, GetVersionEx() should be reporting what your app is actually manifested for. But, when launching Exe2 directly from the IDE, its would seem that GetVersionEx() is picking up the IDE's manifest rather than your app's manifest, which is odd. In any case, if you want to use TNotificationCenter, make sure you specify support for Windows 8 in your app manifest.
  11. Remy Lebeau

    Windows Notification in Exe2 when Exe2 started from Exe1

    Is Exe2 a console app or a GUI app? Does it initialize the COM library before creating the TNotificationCenter object? Internally, your Exe2 code is basically doing the following: The TNotificationCenter.Supported property returns False when the TCustomNotificationCenter.FPlatformNotificationCenter member is nil. TCustomNotificationCenter.FPlatformNotificationCenter is initialized in the TCustomNotificationCenter constructor using a call to TBaseNotificationCenter.InternalGetInstance(). On Windows, TBaseNotificationCenter.InternalGetInstance() calls System.Win.Notification.TPlatformNotificationCenter.GetInstance(). TPlatformNotificationCenter.GetInstance() returns the TNotificationCenterWinRT.NotificationCenter property. The NotificationCenterWinRT.NotificationCenter property getter attempts to create a TNotificationCenterWinRT singleton object, returning nil if it fails to be created. TNotificationCenterWinRT's constructor calls TToastNotificationManager.Statics.CreateToastNotifier(). The TToastNotificationManager.Statics property getter imports WinRT's Windows.UI.Notifications.ToastNotificationManager class, raising an exception if it fails. Then calls ToastNotificationManager.CreateToastNotifier() So, it sounds like Exe2 is unable to import WinRT's ToastNotificationManager class, which ultimately causes TNotificationCenter.Supported to return False. The WinRT API returns HRESULT error codes when things fail, unfortunately the RTL does not capture those error codes when bubbling WinRT failures up the call chain. However, the exceptions do have error messages on them, so if you attach the IDE's debugger to the Exe2 process before it creates the TNotificationCenter object, then you should be able to see those error messages (as well as step into the RTL's source code directly). For instance, have Exe1 pass a command-line argument to Exe2, such as '/debug', and then have Exe2's startup code check for that argument and if present then run a short wait loop that breaks once the Win32 IsDebuggerPresent() function returns True. That will give you an opportunity to debug Exe2 when it is launched by Exe1.
  12. Remy Lebeau

    Windows Notification in Exe2 when Exe2 started from Exe1

    The function is also leaking the ProcessInfo.hThread handle. Since that handle is not being returned to the caller, it needs to be closed before the function exits.
  13. Remy Lebeau

    How to draw a semitransparent ellipse on a canvas?

    You can't, well not directly anyway. You can draw it opaquely onto an in-memory bitmap first, and then draw that bitmap onto your target Canvas with alpha/transparency applied to it as needed.
  14. Remy Lebeau

    Desktop path crossplatform?

    Small nitpicks.. you can't use {$ELSEIF} with {$IFDEF}, you would need to use {$ELSE}{$IFDEF} instead. Otherwise, use {$IF} in order to use {$ELSEIF}. I would suggest using RTL functions to handle the path delimiters. function OSGetUserDesktopPath: string; begin {$if defined(MSWINDOWS)} winApiUtils.GetFolderPath(CSIDL_DESKTOPDIRECTORY, Result); Result := InclueTrailingPathDelimiter(Result); {$elseif defined(OSX)} Result := TPath.Combine(TPath.GetHomePath, 'Desktop'); Result := IncludeTrailingPathDelimiter(Result); {$elseif defined(IOS)} Assert(false, 'OSGetUserDesktopPath not implemented on IOS'); Result := ''; {$elseif defined(ANDROID)} Assert(false, 'OSGetUserDesktopPath not implemented on ANDROID'); Result := ''; {$else} {$Message Error 'Missing Target'} {$ifend} end;
  15. Delphi doesn't use .DEF files to begin with. But even if it did, .DEF files are simply not preprocessed files, so they cannot have directives to generate different code for different compilation setups. To do what you are asking, the project setup must use a separate .DEF file for each platform.
  16. Why? What exactly is different between them? For that matter, why are you using .DEF files in Delphi at all? That should not be necessary. You need to use separate projects if you need to include a different set of files. Not really, except maybe making/finding a preprocessor for .DEF files, or using the project's Build Events to automate the swapping of the .DEF file.
  17. I was able to connect to your specified URL using a web browser with TLS 1.2, and it received a response just fine. So you should be able to get a similar response using Indy with TLS 1.2, too. Have you tried using a packet sniffer, like Wireshark, to look at the actual TLS handshake that TIdSSLIOHandlerSocketOpenSSL is sending, to make sure it is really attempting to use TLS 1.2, and not say TLS 1.0 instead? Which version of the OpenSSL DLLs are you using, exactly? Does Indy's IsOpenSSL_TLSv1_2_Available() function in the IdSSLOpenSSLHeaders unit return True or False when the error occurs? Offhand, that code looks ok, as far as setting up the SSLIOHandler, though I do have a few comments (not related to the TLS error) about the rest of the code: Why are you setting the Request.ContentType and Request.ContentLength properties when you are not sending any data to the server? Why are you setting the Request.Accept property, instead of using the default? Both values include '*/*', so you are not really gaining anything, especially since the server's response is JSON, which is not specified in either value, so caught by '*/*' anyway. Why are you setting the Request.Host property to a different hostname than is specified in the URL? Do not set the Request.AcceptEncoding manually, let TIdHTTP manage that for you. If you want to support compressed responses, you need to assign a compressor component to the TIdHTTP.Compressor property, in which case TIdHTTP will then set the Request.AcceptEncoding property based on the compressor's actual capabilities.
  18. Remy Lebeau

    Indy 9.0.18 on Delphi 6. Where can i get 9.0.50?

    Be sure to read https://github.com/IndySockets/Indy/wiki/Updating-Indy (though, it doesn't appear to cover how to uninstall Indy 9, so you'll have to work that out for yourself). Is there a problem with it? Can you be more specific? If you have recompiled Computil.exe and it works on XP as well as up to Win11, then can you send it to me so I can check it back into Indy's GitHub repo? Thanks. Make sure you compile IndySystem60.dpk first. You need to uninstall the earlier Indy from the IDE before you can install Indy 10. Same issue. Same issue. That is the Indy package that came pre-installed in the IDE. You should be able to find it in the IDE's "Install Packages" dialog. Yeah! Sounds about right. Indy 10 has a different directory structure than Indy 9, yes. This will be cleaned up in Indy 11. Yes.
  19. Remy Lebeau

    Using a C++ Class in Delphi

    You can't avoid implementing the C++ class in a DLL or BPL, unfortunately. However, Delphi can use the C++ object directly if it is derived from a Delphi class (ie, TObject or descendant), or is accessible using an abstract interface that is also defined on the Delphi side, or is accessible via/as a COM object. Otherwise, you are stuck using plain C-style wrapper functions, as you already have.
  20. Remy Lebeau

    TLS v1.3

    Delphi releases ship with the latest Indy available at the time. 10.6.2.0 is actually newer than 10.6.2.5520, it is just that the build number got lost and reset back to 0 when Indy migrated from SVN to GitHub (see https://github.com/IndySockets/Indy/issues/292). I think so, yes. Though, I have now merged just those two files into the main code, so the PR should now be able to contain only the new units (once the author updates his branch). So, in theory, you can download the latest main code, and then download the new units on top of it. You will need the updated OpenSSL 1.1x/3.x DLLs. Indy doesn't provide downloads for those at this time, so you'll have to get them from elsewhere.
  21. If you are trying to delete/rename remote files on the FTP server, TFtpClient has methods for that purpose:
  22. Remy Lebeau

    Windows VCL application pauses when window is not focused...

    Definitely not a good design choice. Long-running procedures should be moved to a worker thread.
  23. Or, use TList<TMyFrame> instead, which doesn't try to own objects.
  24. Remy Lebeau

    Exception catching in a service

    You signal the thread to terminate, and then you wait for the thread to actually terminate right then and there, before you exit from the OnStop/OnShutdown event handler. The service enters a StopPending state before triggering the event, and then it enters the Stopped state once the event exits (or, in the case of the OnStop event, it enters back into the Running state if you set the event's Stopped parameter to False). Note that using TThread.WaitFor() in this situation is not a good idea, since the service still needs to report status back to the SCM at regular intervals while the SCM is waiting for the service to stop itself. If the thread takes a long time to terminate, the SCM will fail after some time if the service doesn't actively tell the SCM that the stop is taking a long time. What I do instead is use TThread.Handle with WaitForSingleObject() (or equivalent) in a loop, using a timeout calculated from the TService.WaitHint property (usually WaitHint-100). When WFSO reports the thread has fully terminated, I break the loop and move on. When WFSO times out, I call TService.ReportStatus() and keep looping.
×