-
Content Count
2684 -
Joined
-
Last visited
-
Days Won
113
Everything posted by Remy Lebeau
-
Delphi 11.1 with TidThreadComponent and TThread.Synchronize
Remy Lebeau replied to ChrisChuah's topic in Indy
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. -
Delphi 11.1 with TidThreadComponent and TThread.Synchronize
Remy Lebeau replied to ChrisChuah's topic in Indy
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. -
Thanks, I have checked it in.
-
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.
-
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.
-
Is there a way to use a platform specific win32/win64 DEF file?
Remy Lebeau replied to alank2's topic in General Help
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. -
Windows Notification in Exe2 when Exe2 started from Exe1
Remy Lebeau replied to NamoRamana's topic in Windows API
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. -
How to draw a semitransparent ellipse on a canvas?
Remy Lebeau replied to vshvetsov's topic in General Help
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). -
The VCL certainly does not install new keyboards.
-
Windows Notification in Exe2 when Exe2 started from Exe1
Remy Lebeau replied to NamoRamana's topic in Windows API
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. -
Windows Notification in Exe2 when Exe2 started from Exe1
Remy Lebeau replied to NamoRamana's topic in Windows API
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. -
Windows Notification in Exe2 when Exe2 started from Exe1
Remy Lebeau replied to NamoRamana's topic in Windows API
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. -
How to draw a semitransparent ellipse on a canvas?
Remy Lebeau replied to vshvetsov's topic in General Help
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. -
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;
-
Is there a way to use a platform specific win32/win64 DEF file?
Remy Lebeau replied to alank2's topic in General Help
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. -
Is there a way to use a platform specific win32/win64 DEF file?
Remy Lebeau replied to alank2's topic in General Help
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. -
Error on call esternal api Delphi XE6
Remy Lebeau replied to Zazhir's topic in Algorithms, Data Structures and Class Design
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. -
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.
-
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.
-
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.
-
Delete, Rename file functions with ICS FtpClient
Remy Lebeau replied to a topic in Network, Cloud and Web
Yes. -
Delete, Rename file functions with ICS FtpClient
Remy Lebeau replied to a topic in Network, Cloud and Web
If you are trying to delete/rename remote files on the FTP server, TFtpClient has methods for that purpose: -
Windows VCL application pauses when window is not focused...
Remy Lebeau replied to DavidJr.'s topic in VCL
Definitely not a good design choice. Long-running procedures should be moved to a worker thread. -
Invalid pointer operation when try to replace object in list
Remy Lebeau replied to RaelB's topic in VCL
Or, use TList<TMyFrame> instead, which doesn't try to own objects. -
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.