-
Content Count
2998 -
Joined
-
Last visited
-
Days Won
135
Everything posted by Remy Lebeau
-
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.
-
FYI, it is generally not a good idea to use the TService.OnExecute event at all, since it requires you to take control of the message loop that processes SCM requests. If you mess up the loop, the service won't respond to the SCM correctly. When there is no OnExecute handler assigned at all, TService's default behavior is sufficient to let the service process and response to SCM requests correctly. You should instead spawn your own thread from the TService.OnStart event, and terminate that thread in the TService.OnStop and TService.OnShutdown events. Then you can do whatever you want inside of your thread.
-
Sending Email via GMail Using OAuth 2.0 via Indy
Remy Lebeau replied to Ugochukwu Mmaduekwe's topic in Indy
REST is just standard HTTP, usually with JSON data. Indy doesn't have any REST-specific components, but pretty much anything you can with other REST components can also be done manually with TIdHTTP. You use the token pretty much the same way you use any other SASL credentials with TIdSMTP: Add TIdSASLXOAuth2 to the TIdSMTP.SASLMechanisms collection, and set the TIdSMTP.AuthType property to satSASL. Assign a TIdUserPassProvider to the TIdSASLXOAuth2.UserPassProvider property, and then assign the retrieved token to the TIdUserPassProvider.Password property. Alternatively, use the TIdSASLXOAuth2.OnGetAccessToken event to retrieve the token on-demand. Use TIdMessage and TIdSMTP as needed (fill out email, configure Host/Port, UseTLS, etc, and then call TIdSMTP.Connect(), TIdSMTP.Send(), TIdSMTP.Disconnect(), etc). -
WideString.c_bstr() operation in 11.2
Remy Lebeau replied to Roger Cigol's topic in RTL and Delphi Object Pascal
So, the real problem is that the BSTR is empty inside of the actual CodeSoft COM object's Open() method, rather than the TLB wrapper's Open() method? If so, then that implies the problem is with either TAutoArgs or OleFunction() not passing the BSTR to the COM object correctly. If the BSTR is not empty inside of the TLB wrapper method, then WideString is working properly, and the problem is elsewhere. -
By default, (lib)curl uses OpenSSL for SSL/TLS. Guess what else uses OpenSSL by default? Indy, which is pre-installed in Delphi.
-
WideString.c_bstr() operation in 11.2
Remy Lebeau replied to Roger Cigol's topic in RTL and Delphi Object Pascal
You need to escape the '\' character in a string literal, eg: String LabelName = "C:\\FullPathToLabelFile.lab"; // <-- note the double slashes! /* NOTE: you really should be using the L"" prefix or _D() macro instead! String LabelName = L"C:\\FullPathToLabelFile.lab"; or: String LabelName = _D("C:\\FullPathToLabelFile.lab"); */ Or, when using a Clang compiler, you can use a raw string literal instead, which doesn't require escaping, eg: String LabelName = LR"(C:\FullPathToLabelFile.lab)"; /* Alternatively, using the _D() macro: String LabelName = _D(R"(C:\FullPathToLabelFile.lab)"); */ Other than that, the rest of that code snippet looks fine. So, whatever problem you are having is not in your code, but is in the RTL itself. Since Open() takes a raw BSTR pointer, the problem has to be at the call site, ie with the construction of the UnicodeString or WideString objects. You are using a narrow string literal when initializing the UnicodeString, instead of using a wide string literal. So, that will invoke a narrow-to-wide data conversion at runtime, which could cause the UnicodeString to end up empty if something goes wrong in the conversion. Did you check for that? The WideString constructor that takes a UnicodeString will set a null BSTR pointer if the UnicodeString is empty. Otherwise, it simply calls the Win32 SysAllocStringLen() function, which returns a null BSTR pointer on failure. Did you check for that? So, either the UnicodeString is empty to begin with (which it should not be in your case, given the code shown), or SysAllocStringLen() is failing due to insufficient system memory. Did you check for that? Try something like this to help narrow down the problem further: String LabelName = "C:\\FullPathToLabelFile.lab"; if (LabelName.IsEmpty()) { throw ...; } WideString wLabelName(LabelName); if (wLabelName.IsEmpty()) { throw ...; } ... CodeSoftDocument = CodeSoft->Documents->Open(wLabelName.c_bstr(), 0); ... -
https://www.indyproject.org/2021/02/10/links-to-old-indy-website-pages-are-currently-broken/
-
Permissions are just string values. The string value of EXTERNAL_MANAGE_STORAGE is 'android.permission.MANAGE_EXTERNAL_STORAGE'. However, granting that permission appears to be different than granting other permissions, per Android's documentation: In earlier versions, TPath.GetSharedDocumentsPath() used to call Android's Context.getExternalFilesDir() method, but nowadays it calls Environment.getExternalStoragePublicDirectory() instead. Maybe Google changed where that latter API's folder is located, compared to the former API? I don't know. One thing to note from the Context.getExternalFilesDir() documentation: So, you might want to check if your device is emulating shared storage or not. Also, Delphi's Androidapi.IOUtils unit has a public GetExternalDocumentsDir() function, which calls Android's Context.getExternalFilesDir() method. Maybe try using that function instead of using TPath.GetSharedDocumentsPath().
-
Use an emulator
-
Can the packages setup be updated for ICS in new versions?
Remy Lebeau replied to Geoffrey Smith's topic in ICS - Internet Component Suite
True, which is why they are not being auto-generated right now. Almost. There are some small differences between older and newer DPKs. -
I'm aware of that. Though, there are still environments that do use old versions. And Indy does still support old compilers for now. Indy 11 will drop the old compilers, so maybe at that time, or maybe in Indy 12, we'll drop old OpenSSL, too
-
In case you have to call RequestPermissions(), are you waiting for request_Result() to be called before you attempt to access the SD card? RequestPermissions() is asynchronous, so your code logic should look something like this: procedure TForm_Main.SaveZipFile; var iZipFile: TZipFile; begin iZipFile := TZipFile.Create; try iZipFile.Open(System.IOUtils.TPath.Combine(System.IOUtils.TPath.GetSharedDocumentsPath, 'Folder-Content.zip'), zmWrite); //... finally iZipFile.Free; end; end; procedure TForm_Main.request_Result(const aPermissions: TClassicStringDynArray; const aGrantResults: TClassicPermissionStatusDynArray); begin if (Length(aGrantResults) = 1) and (aGrantResults[0] = TPermissionStatus.Granted) then SaveZipFile; end; procedure TForm_Main.request_Permissions(aPermission: String); begin PermissionsService.RequestPermissions([aPermission], request_Result); end; ... sWriteExternalStorage := JStringToString(TJManifest_permission.JavaClass.WRITE_EXTERNAL_STORAGE); if PermissionsService.IsPermissionGranted(sWriteExternalStorage) then SaveZipFile else request_Permissions(sWriteExternalStorage); Though, I would probably want to generalize that a bit further, eg: procedure TForm_Main.SaveZipFile; var iZipFile: TZipFile; begin iZipFile := TZipFile.Create; try iZipFile.Open(System.IOUtils.TPath.Combine(System.IOUtils.TPath.GetSharedDocumentsPath, 'Folder-Content.zip'), zmWrite); // ... finally iZipFile.Free; end; end; procedure TForm_Main.doTask_withPermission(const aPermission: String; AProc: TProc); begin if PermissionsService.IsPermissionGranted(aPermission) then begin AProc; end else begin PermissionsService.RequestPermissions([aPermission], procedure(const aPermissions: TArray<String>; const aGrantResults: TArray<TPermissionStatus>); begin if (Length(aGrantResults) = 1) and (aGrantResults[0] = TPermissionStatus.Granted) then begin AProc; end; end ); end; end; ... doTask_withPermission( JStringToString(TJManifest_permission.JavaClass.WRITE_EXTERNAL_STORAGE), SaveZipFile ); No. It is a permission like any other. The user has to grant access to it. Are you getting any kind of runtime error about the file not being created? If not, have you tried looking through the device to see if the file is getting created somewhere else that you are not expecting? On Android, TPath.GetSharedDocumentsPath() attempts 2 different folder paths - first, it tries to retrieve the user's Documents folder, and if that fails then it retrieves the user's Downloads folder and replaces the last subfolder in the path with a hard-coded 'Documents'.
-
What problem are you having with it, exactly? Can you be more specific? What does your code look like that is not working? Did you grant permission to your app to access the external SD card? Do you have code that prompts the user if permission has not been granted yet?
-
Can the packages setup be updated for ICS in new versions?
Remy Lebeau replied to Geoffrey Smith's topic in ICS - Internet Component Suite
That is the approach that Indy took a long time ago. It has a master database of its units and their characteristics, and then there is a Package Generator app that reads in that database and spits out DPK files (no DPROJ, CBPROJ, or GROUPPROJ files at this time) for all of the supported compiler versions (well, not all of them, as the app hasn't been updated in a long time - packages for modern compiler versions have largely just been copied from earlier versions and edited by hand). -
Yes. Unfortunately, it still would have been a big update, since OpenSSL basically redesigned their API in v1.1.0. All of the structures were changed, and many functions were either renamed or dropped. So, while making the existing SSLIOHandler component be more version-aware to support both pre-1.1.0 and post-1.1.0 libraries would have been ideal, the API changes really warranted new SSLIOHandler components to keep the two API designs separate. But, to be fair, I wasn't involved in the development of the new components, so I couldn't say if the new design is actually overkill or not.