-
Content Count
3055 -
Joined
-
Last visited
-
Days Won
139
Everything posted by Remy Lebeau
-
UniqueString() would have done the same thing with less code, eg: s := GetPluginName; UniqueString(s); To make things easier on the caller, that should be done inside of the package function instead, eg: function GetPluginName: string; begin Result := 'test'; UniqueString(result); end; That makes sense if you are letting the compiler clear "tmp" AFTER the package has been unloaded, since "tmp" will be pointing at unloaded memory when the RTL tries to access it for cleanup, Calling UniqueString()/Copy() BEFORE the package is unloaded addresses that problem. Of course, you could also solve the problem by simply not returning a string literal from the function in the first place, or by ensuring the caller is completely finished using any data from the package before unloading it from memory.
-
Using bold text in Listview
Remy Lebeau replied to Bart Verbakel's topic in Algorithms, Data Structures and Class Design
Rather than using a separate class in the TListItem.Data property, it would be safer and more efficient to derive a new class from TListItem and add whatever members you want to it, and then return that class type from the ListView's OnCreateItemClass event. You can then type-cast any TListItem in the ListView to your custom class type when needed, and you don't have to worry about freeing them manually. For example: type TMyListItem = class(TListItem) public BoldText: Boolean; end; procedure TForm8.ListView1CreateItemClass(Sender: TCustomListView; var ItemClass: TListItemClass); begin ItemClass := TMyListItem; end; procedure TForm8.ListView1AdvancedCustomDrawSubItem(Sender: TCustomListView; Item: TListItem; SubItem: Integer; State: TCustomDrawState; Stage: TCustomDrawStage; var DefaultDraw: Boolean); begin if TMyListItem(Item).BoldText then Sender.Canvas.Font.Style := [fsBold]; end; ... var li := ListView1.Items.Add; TMyListItem(li).BoldText := True; Of course, in this particular example, there is a much simpler solution - just look at the data being drawn and act accordingly, eg: procedure TForm8.ListView1AdvancedCustomDrawSubItem(Sender: TCustomListView; Item: TListItem; SubItem: Integer; State: TCustomDrawState; Stage: TCustomDrawStage; var DefaultDraw: Boolean); begin if (SubItem > 0) and (StrToInt(Item.SubItems[SubItem-1]) < 0) then Sender.Canvas.Font.Style := [fsBold]; end; -
FMX form called from VCL form doesn't apply Top Most style to its child windows.
Remy Lebeau replied to vhanla's topic in FMX
Have you tried making the FMX form override its CreateHandle() method to apply the WS_EX_TOPMOST style? -
Which UDP components, exactly? Indy's? Someone else's? Please be more specific. Please show your actual code on both sides. The only way that makes sense is if the server is actually sending a $00 byte, OR, if you have pre-sized your Buf beforehand and ReceiveBuffer() is not filling it in (ie, is ReceiveBuffer() returning 0 bytes read as its return value?). Not without seeing your actual code. UDP is connection-less. There is no connection to reset.
-
issue with phone send verification code to firebase
Remy Lebeau replied to xorpas's topic in Databases
According to this documentation, the request requires a JSON body containing a recaptchaToken, iosSecret, iosReceipt, and phoneNumber, are you sending those values? That being said, I think you are using an older URL, you should be using the latest Identity Toolkit API located at https://identitytoolkit.googleapis.com instead: https://cloud.google.com/identity-platform/docs/reference/rest https://cloud.google.com/blog/products/identity-security/getting-started-with-identity-platform https://developers.google.com/identity/toolkit/migrate-identityplatform -
Playing with Windows Fibers by emulating Python Generators
Remy Lebeau replied to darnocian's topic in I made this
There are plenty of C macros that are translated into Delphi's Window SDK units. More likely, they were not translated simply because fibers are just not used by most developers, not even Microsoft: Fibers aren’t useful for much any more; there’s just one corner of it that remains useful for a reason unrelated to fibers -
I'm sure either one will be fast enough for your needs. Chess isn't very computationally heavy. The only way to know for sure is to benchmark them yourself and see which one suits your needs better.
-
https://docwiki.embarcadero.com/RADStudio/en/E2217_Published_field_'%s'_not_a_class_or_interface_type_(Delphi)
-
The signature of the event is documented: https://docwiki.embarcadero.com/Libraries/en/Data.DB.TDataSet.AfterEdit property AfterEdit: TDataSetNotifyEvent read FAfterEdit write FAfterEdit; https://docwiki.embarcadero.com/Libraries/en/Data.DB.TDataSetNotifyEvent TDataSetNotifyEvent = procedure(DataSet: TDataSet) of object;
-
Strange problem skipping loop with tTask
Remy Lebeau replied to Jud's topic in RTL and Delphi Object Pascal
Wouldn't TParallel.For() be more appropriate in this situation? procedure TForm2.RunButtonClick(Sender: TObject); const NumberOfParts = 1; begin TParallel.For(0, NumberOfParts - 1, procedure(counter: Integer) begin RunWork(counter); end ); // or simply: // TParallel.For(0, NumberOfParts - 1, RunWork); end; -
Can I use managed C# DLL in unmanaged Delphi application ?
Remy Lebeau replied to AndrewHoward's topic in General Help
Or Atozed CrossTalk, too. -
What is the recommended method of obtaining my devices IP address?
Remy Lebeau replied to JohnLM's topic in Cross-platform
Not related to the 127.0.0.1 issue - note that the code above will leak the returned TStringList on mobile platforms in Delphi 10.4 and later, as ARC is no longer being used for object lifetime management, so you need to Free() the list when you are done using it on all platforms, eg: procedure TForm1.btnGetRemyClick(Sender: TObject); var IPs: TStringList; begin IPs := GetLocalIpList2(''); try m1.Lines := IPs; finally IPs.Free; end; end; A better option is to pass in the target TStrings as a parameter and let the function add to it as needed, eg: procedure GetLocalIpList2(Name: string; IPList: TStrings); var ... begin ... IPList.BeginUpdate; try ... IPList.Add(...); ... finally IPList.EndUpdate; end; ... end; procedure TForm1.btnGetRemyClick(Sender: TObject); begin GetLocalIpList2('', m1.Lines); end; -
What is the recommended method of obtaining my devices IP address?
Remy Lebeau replied to JohnLM's topic in Cross-platform
You didn't say which code you used for which scenario. Indy's GetLocalAddressList() has a known issue where it reports only 127.0.0.1 on Android. -
while TStream_TryRead() do
Remy Lebeau replied to dummzeuch's topic in Tips / Blogs / Tutorials / Videos
Sadly, not only is -1 not documented, but it's also not always implemented. For example, THandleStream.Read() returns 0 on failure and end-of-file. Which makes error handling practically impossible for some stream types. That is what the ReadXXX() methods are meant for. Read() is the lower level method that they all use internally. -
while TStream_TryRead() do
Remy Lebeau replied to dummzeuch's topic in Tips / Blogs / Tutorials / Videos
Read() is not guaranteed to return as many bytes as requested. The documentation even says so. Use other ReadXXX() methods for that purpose instead. Since Read() can return fewer bytes without actually failing, breaking the loop on a lesser return is wrong if the intent is to read the whole stream. Only a return of -1 (error) or 0 (end of stream) should be the actual breaking condition. I prefer using 'repeat ... until False' because it avoids having to test the return value twice, eg: repeat BytesRead := Stream.Read(Buffer, BufSize); if BytesRead > 0 then ... until BytesRead <= 0; -
while TStream_TryRead() do
Remy Lebeau replied to dummzeuch's topic in Tips / Blogs / Tutorials / Videos
repeat BytesRead := Stream.Read(Buffer, BufSize); if BytesRead <= 0 then Break; // .. until False; -
What is the recommended method of obtaining my devices IP address?
Remy Lebeau replied to JohnLM's topic in Cross-platform
What you describe gets the local IPs of the device that your code is running it. It does not get the IPs of other devices on the local network. You don't need to use the IdStackXXX units directly in this example, just the base IdStack unit by itself will suffice. The correct way to use TIdStack methods is to call them on the global GStack object. Indy can instantiate the correct derived class for you based on the local OS platform, eg: uses IdGlobal, IdStack; function GetLocalIpList(Name: string): TStringList; var Lista: TIdStackLocalAddressList; temp: TIdStackLocalAddress; I: Integer; begin Result := TStringList.Create; try TIdStack.IncUsage; // instantiates GStack if needed... try Lista := TIdStackLocalAddressList.Create; try GStack.GetLocalAddressList(Lista); for I := 0 to Lista.Count-1 do begin temp := Lista[I]; if temp.IPVersion = Id_IPv4 then Result.add(temp.IPAddress); end; finally Lista.Free; end; finally TIdStack.DecUsage; // frees GStack if needed... end; except Result.Free; raise; end; end; -
You can either: not assign the OnClick handler at design-time, but at runtime instead after you are done initializing the control. set a variable somewhere that the event handler can look at, and then clear that variable when finished.
-
I don't understand what you are describing. Please clarify. What EXACTLY is not working? What steps did you take to set it up, and what steps did you take to see that it is not working?
-
To elaborate, only the Unicode version of CreateProcess() requires the 2nd parameter to point at writable memory, as it may have to internally normalize/alter the Unicode string. This is documented behavior. In this example, sCommand is pointing at a string literal (ie, its RefCnt is -1), so the compiler won't allocate a block of writable memory for sCommand unless it is modified (ie, copy-on-write semantics), which this code doesn't do. So the UniqueString() is used to ensure that sCommand is pointing at a unique and writable string in memory (ie, its RefCnt is 1). If you use string variables to build up sCommand, then the UniqueString() won't be needed since the resulting string will be unique and writable, eg: var sProgram, sFilename, sCommand: string; sProgram := 'C:\PDF\pdftotext.exe'; sFilename := 'C:\PDF\ABC.PDF'; sCommand := '"' + sProgram + '" "' + sFilename + '"'; // or: sCommand := Format('"%s" "%s"', [sProgram, sFilename]); // etc...
-
Communication between Unicode and non-Unicode applications
Remy Lebeau replied to dummzeuch's topic in Indy
If you are using strictly ASCII characters only, then no. All of the default settings should suffice. But, if you are using any non-ASCII characters, then make sure both client and server agree on a common byte encoding on the wire, ie UTF-8. You can use the TIdIOHandler.DefStringEncoding property, or the AByteEncoding parameter on individual read/write methods. Indy will convert Unicode to wire encoding on writes, and from wire encoding to Unicode on reads. In the D2007 code, you should also tell Indy which encoding your AnsiString's are using, if different than the OS default. You can use the TIdIOHandler.DefAnsiEncoding property, or the ADestEncoding/ASrcEncoding parameter on individual read/write methods, respectively. Indy will convert ANSI to Unicode to wire encoding on writes, and from wire encoding to Unicode to ANSI on reads. -
Communication between Unicode and non-Unicode applications
Remy Lebeau replied to dummzeuch's topic in Indy
You don't need to use RawToBytes() in this case. The TIdIOHandler.Write(string) method has an optional ADestEncoding parameter to specify the byte encoding on the wire, such as UTF-8 (the default is ASCII). You can alternatively use the TIdIOHandler.DefStringEncoding property. And, in pre-Unicode versions, Write() also has an optional ASrcEncoding parameter to specify the byte encoding of the input AnsiString (the default is the user's OS default). Or, you can alternatively use the TIdIOHandler.DefAnsiEncoding property. -
Why are you using ShellExecute() to run pdftotext.exe indirectly via cmd.exe, instead of using CreateProcess() to run pdftotext.exe directly? Try something more like this: procedure TForm1.Button1Click(Sender: TObject); var sCommand: string; si: TStartupInfo; pi: TProcessInformation; begin sCommand := '"C:\PDF\pdftotext.exe" "C:\PDF\ABC.PDF"'; UniqueString(sCommand); ZeroMemory(@si, sizeof(si)); si.cb := sizeof(si); si.dwFlags := STARTF_USESHOWWINDOW; si.wShowWindow := SH_HIDE; if CreateProcess(nil, PChar(sCommand), nil, nil, False, CREATE_NO_WINDOW, nil, nil, si, pi) then begin CloseHandle(pi.hThread); CloseHandle(pi.hProcess); end; end;
-
Then try changing it from System.SysInit to just SysInit.
-
You have to analyze the certificate provided, and check whether or not its attributes match your desired criteria. Error 20 is X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: Error 21 is X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: See: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_verify.html https://www.openssl.org/docs/man1.0.2/man3/X509_STORE_CTX_get_error.html Sure, because you are telling OpenSSL that you deemed the certificate OK to use, even if OpenSSL thinks otherwise. Because OpenSSL pre-checks the certificate before letting you do your own checks on it. So, if OpenSSL doesn't think the certificate is OK, and you do nothing to override that decision, then the certificate is not usable and the handshake fails. Verifying the peer's identity is a separate operation from encryption. The peers have to trust each other before they exchange encryption keys with each other.