-
Content Count
2684 -
Joined
-
Last visited
-
Days Won
113
Everything posted by Remy Lebeau
-
Use of dynamic control names
Remy Lebeau replied to Bart Verbakel's topic in Algorithms, Data Structures and Class Design
That "works" but may be overkill, as you would potentially be iterating through a lot of other controls that you are not interested in. -
Use of dynamic control names
Remy Lebeau replied to Bart Verbakel's topic in Algorithms, Data Structures and Class Design
Don't do that! You are invoking undefined behavior. You can only iterate using a pointer like that if the values are in an array, Otherwise, you can't be sure the compiler is not adding padding between them inside the class. If you want to use a pointer to iterate the members, you have to put them into an array first and iterate that instead. -
Searching Edit component with autocomplete for Directory/Files
Remy Lebeau replied to Carlo Barazzetta's topic in VCL
Ah. No, it does not. In that case, you would indeed need a custom enumerator. -
I would just stick with using the <pshpack#.h>/<poppack.h> headers, since they support multiple compilers, and will use #pragma pack(push) if the compiler supports it. I have never seen that warning before when using #pragma pack directly. But then, I don't ever wrap the standard Win32 headers with it, either. I doubt it, but anything is possible, I guess. You will have to review the headers for yourself.
-
Searching Edit component with autocomplete for Directory/Files
Remy Lebeau replied to Carlo Barazzetta's topic in VCL
Why implement a custom IEnumStrings class for directories/files? There is already a pre-made data source provided by the OS for that exact purpose - CLSID_ACListISF, which can be created with CoCreateInstance(), configured via IACList2::SetOptions(), and then passed to IAutoComplete::Init(). -
Register COM Object for create process/Fightiing AntiVirus
Remy Lebeau replied to RTollison's topic in General Help
Creating a COM object to run a process won't bypass the AV if it is looking for process creations. That will just add more overhead to the app that is wanting to create the processes. Unless the AV ignores COM objects that run elevated, which would be pretty risky. Besides, it's not really possible for an AV to determine whether a process creation is occurring inside a COM object vs an application anyway. I think your IT is acting stupid, but that is just my opinion. Do you really need to run an external process on every file? What is the new process doing exactly that you can't do directly inside your own app with an equivalent library? -
My example assigns the TIdSMTP object as the Owner of the SSLIOHandler object. When the TIdSMTP object is freed, it will free the SSLIOHandler object for you. This is a memory management mechanism that is implemented by all TComponent descendants. If you want to free the object yourself, you certainly can do so, eg: procedure SendTestEmail2; var SMTP: TIdSMTP; SSLHandler: TIdSSLIOHandlerSocketOpenSSL; Message: TIdMessage; begin try SMTP := TIdSMTP.Create(nil); try SSLHandler := TIdSSLIOHandlerSocketOpenSSL.Create(nil); try SSLHandler.SSLOptions.SSLVersions := [sslvTLSv1_2]; // and/or sslvTLSv1, sslvTLSv1_1, etc. SSLHandler.SSLOptions.Mode := sslmClient; SMTP.IOHandler := SSLHandler; SMTP.Host := 'smtp.gmail.com'; SMTP.Port := 465; // or 587, depending on your server SMTP.UseTLS := utUseImplicitTLS; // or utUseExplicitTLS, depending on your server SMTP.Username := 'UserName'; SMTP.Password := 'Pass'; Message := TIdMessage.Create(nil); try Message.From.Address := 'men@gmail.com'; Message.Recipients.EMailAddresses := 'grantful@yahoo.com'; Message.Subject := 'Test Subject'; Message.Body.Add('Test message.'); SMTP.Connect; try SMTP.Send(Message); finally SMTP.Disconnect; end; finally Message.Free; end; finally SSLHandler.Free; end; finally SMTP.Free; end; except on E: Exception do begin ShowMessage('Error: ' + E.Message); end; end; end; It is customary to assign a nil Owner when you want to free an object yourself. But it is safe to manually free an object that has an Owner assigned, as the freed object will simply remove itself from its Owner to avoid being freed again. Are you debugging your app on those platforms to see what is actually going on? Which line of code is actually raising those errors?
-
On 32bit systems, as well. Using the Windows Headers What structure packing do the Windows SDK header files expect?
-
Yes - 8 bytes Because the Windows SDK is old and predates those headers? I don't know. Not sure if the original SDK headers do this, but In Embarcadero's copy of windows.h and other SDK headers, there are actually #pragma statements to setup 8-byte alignment, eg: #pragma option push -b -a8 -pc -A- /*P_O_Push*/ ... #pragma option pop /*P_O_Pop*/ The -a8 parameter is the alignment. Yes, and most VCL headers have #pragma statements for that purpose, eg: #pragma pack(push,8) ... #pragma pack(pop)
-
Look at that code very carefully. You have commented out the creation of an SSLHandler object, but then are accessing its members. Crash. And, if that one line were not commented out, you would then be creating a 2nd SSLHandler object and assigning it to the same variable, leaking the 1st object. You need to fix your object creation. This is not specific to Indy, this is a fundamental issue to how Pascal/OOP programming works in general. You have to create an object before you can use it. Now, after fixing that, your code has another problem - SMTP port 465 is an implicit TLS port, but you are setting the TIdSMTP.UseTLS property to utUseExplicitTLS. SMTP port 587 is the explicit TLS port. Use utUseImplicitTLS for port 465, and utUseExplicitTLS for port 587 (and optionally 25). Try this: procedure SendTestEmail2; var SMTP: TIdSMTP; SSLHandler: TIdSSLIOHandlerSocketOpenSSL; Message: TIdMessage; begin try SMTP := TIdSMTP.Create(nil); try SSLHandler := TIdSSLIOHandlerSocketOpenSSL.Create(SMTP); SSLHandler.SSLOptions.SSLVersions := [sslvTLSv1_2]; // and/or sslvTLSv1, sslvTLSv1_1, etc. SSLHandler.SSLOptions.Mode := sslmClient; SMTP.IOHandler := SSLHandler; SMTP.Host := 'smtp.gmail.com'; SMTP.Port := 465; // or 587, depending on your server SMTP.UseTLS := utUseImplicitTLS; // or utUseExplicitTLS, depending on your server SMTP.Username := 'UserName'; SMTP.Password := 'Pass'; Message := TIdMessage.Create(nil); try Message.From.Address := 'men@gmail.com'; Message.Recipients.EMailAddresses := 'grantful@yahoo.com'; Message.Subject := 'Test Subject'; Message.Body.Add('Test message.'); SMTP.Connect; try SMTP.Send(Message); finally SMTP.Disconnect; end; finally Message.Free; end; finally SMTP.Free; end; except on E: Exception do begin ShowMessage('Error: ' + E.Message); end; end; end;
-
That is not a good idea. Store them outside of the exe (config file, database, etc), and secure them with encryption, etc in case they need to be changed over time. If a hacker has access to your exe, all bets are off. Nothing stops a competent hacker from discovering the memory blocks your app is using and just pull the login values directly from that memory as soon as your app uses it.
-
That is what the WM_APP range, and RegisterWindowMessage(), are meant for instead. Yes, it is perfectly safe to use the WM_USER range for your own messages within your own window.
-
FYI, your manual setting is not guaranteed to be persistent. The Form's Handle CAN be recreated dynamically during the Form's s lifetime, which would lose your manual setting. If you want to customize the Form's owner window, you need to override the Form's CreateParams() method so your manual value takes affect on every HWND that the Form creates, eg: type TMyContestForm = class(TForm) ... protected procedure CreateParams(var params: TCreateParams); override; ... end; procedure TMyContestForm.CreateParams(var params: TCreateParams); begin inherited CreateParams(params); params.WndParent := 0; // or GetDesktopWindow() end;
-
A VCL owner and an API owner are two completely different things. The VCL's owner manages object lifetime. The API's owner manages window display and Z-ordering. Did you perhaps forget the 'override' directive on the declaration of CreateParams() in the TMyContest class? type TMyContest = class(TForm) ... protected procedure CreateParams(var params: TCreateParams); override; ^^^^^^^^^ ... end; The Create() and CreateNew() constructors are just to create the TForm object. The CreateParams() method is called by the TWinControl.Handle property getter whenever the HWND window is being created at the API level. TForm object construction and HWND window creation are two different things.
-
It is a bit more complicated than that. The owner window that is used at the API level depends on many factors, like if the TForm has a Parent or PopupParent assigned, or the MainForm window or the currently active TForm window may be used depending on the TForm's PopupMode. If the VCL decides the MainForm should be used, it will do so only if TApplication.MainFormOnTaskbar is True and the MainForm window has already been allocated, otherwise the TApplication window is used instead. Even then, there are TApplication.OnGetActiveFormHandle and TApplication.OnGetMainFormHandle events which allow the app to override the VCL's decision and use a different window of the app's choosing. See the implementation of TCustomForm.CreateParams(), there is a lot of decision-making going on in that method to decide which owner window to use.
-
curl-example for POST works, Delphi code throws an 404
Remy Lebeau replied to philipp.hofmann's topic in Network, Cloud and Web
On a side note, you are leaking the SSLIOHandler object. You are not assigning it an Owner, so you need to Free() it. Otherwise, I suggest assigning the TIdHTTP at its Owner, eg: var HTTP := TIdHTTP.Create(nil); try var SSL := TIdSSLIOHandlerSocketOpenSSL.Create(HTTP); SSL.SSLOptions.SSLVersions := [sslvTLSv1_2]; HTTP.IOHandler := SSL; HTTP.Request.CustomHeaders.Values['Authorization'] := 'Bearer ' + bearer; var Params := TIdMultiPartFormDataStream.Create; try filename := StringReplace(Training.filename, '.ictt', '.fit', [rfIgnoreCase]); params.AddFile('file', filename); ResponseStr := HTTP.Post('https://pushinglimits.club/api/oauth/upload_single_fit_file', Params); finally Params.Free; end; finally HTTP.Free; end; -
curl-example for POST works, Delphi code throws an 404
Remy Lebeau replied to philipp.hofmann's topic in Network, Cloud and Web
Did you notice the URL is different in the response HTML? The leading /api was removed. That implies to me (without proof to the contrary - does TNetHTTPClient offer any kind of debug output?) that the server probably didn't like something about the initial request and issued an HTTP redirect to a new URL that happens to not exist. Sounds like a problem with the way the server is processing TNetHTTPClient's reequest, considering the same request in TIdHTTP works. -
Using inline variables inside loops
Remy Lebeau replied to havrlisan's topic in RTL and Delphi Object Pascal
You probably nailed it right. It would make sense to have each loop iteration create a separate instance of the anonymous method and let it capture the inline variables that are local to its containing loop body. But as Dalija explained, that is not what happens. Probably a left-over from when anonymous procedures were introduced and inline variables didn't exist yet, so they just captured variables from the top of the containing function. Now inline variables need more stack frame management, and anonymous procedures haven't caught up to that reality yet. -
Using inline variables inside loops
Remy Lebeau replied to havrlisan's topic in RTL and Delphi Object Pascal
FYI, the code shown is declaring two separate LPair variables. Get rid of the 1st one, its not being used. The code shown will not work, because of the way anonymous procedures capture variables not values: Anonymous Methods in Delphi: Anonymous Methods Variable Binding Yes, that would be the solution, eg: procedure AddToList(AKey: string); begin FList.Add( procedure begin FDict.Remove(AKey); end); end; for var LPair in FDict do begin AddToList(LPair.Key); end; -
And, what if the LAN configuration has to be changed in the future? Why not simply have a field in the app's configuration to specify the location?
-
Do you have the source code for TFoldPanel? If so, why not simply update it to support Styles?
-
I use the "Attach to Process" approach when debugging my services. Also, if I want to debug the service's startup logic, I pass in a particular startup parameter via the SCM, and then add code in the service's OnStart event to look for that parameter and if present then hold the service in csStartPending state until the debugger attaches.
-
Load DLL from resource, bypassing a file?
Remy Lebeau replied to Angus Robertson's topic in Windows API
That is correct. That is simply how Windows operates. Correct, and it would not really be much faster anyway. You can't just use a DLL as-is in memory, as there are fixups and relocations and such that have to be performed during the load process to make sure the DLL can actually function correctly. There are 3rd party DLL loaders that can operate on a memory block, but they are dangerous to use, and can't operate on a read-only resource anyway, so you would have to extract the DLL to writable memory first. So you are better off just using a disk file and letting Windows do its job normally. That is another reason not to use in-memory DLL loaders. Do you really need to store the DLLs in your EXE to begin with? That is just going to bloat the EXE and make more work for Windows when it is loading the EXE. Why can't you just deploy the DLLs alongside your EXE instead? If you need to distribute a single file, use an installer or self-extracting zip archive or similar. -
Ok FYI, the whole point of setting the IOHandler.DefStringEncoding property is so you don't need to keep specifying an encoding on every subsequent read/write string operation on the IOHandler, like you are doing. That said, where is your call to Connect()? You don't need to call CreateIOHandler() if you set the DefStringEncoding after Connect() exits successfully. In any case, the code shown is fine as far as encodings are concerned, so the error has to be caused by an underlying failure of the newer OS, or a bug in the RTL. Either way, try using the charset name via IndyTextEncoding('Windows-1251') or GetCharsetEncoding('Windows-1251') instead of using the codepage number via IndyTextEncoding(1251). If those still fail, then the latter one provides a GIdEncodingNeeded event so you can provide Indy with your own class that implements the IIdTextEncoding interface, so you can do your own encoding/decoding of the CP1251 data (which is fairly trivial using a simple lookup table via https://en.m.wikipedia.org/wiki/Windows-1251)
-
What does the call stack look like when the error occurs? What is your code doing that it is trying to instantiate an Indy encoding that is not working correctly with CP1251?