Jump to content

Remy Lebeau

Members
  • Content Count

    2333
  • Joined

  • Last visited

  • Days Won

    94

Everything posted by Remy Lebeau

  1. Remy Lebeau

    Tries to convert from D7 to D10

    Also have a look at Embarcadero's Migration and Upgrade Center
  2. Remy Lebeau

    THTTPCommandType - PATCH

    I have just now checked in an update for this.
  3. Remy Lebeau

    Got to last page of forum item ?

    I think most forums operate that way. Agreed. Personally, if I've already visited a particular discussion, I would prefer to be taken back to the last item of the previous visit. Not to the most recent item. Most forums know my last visit time, some even show a marker for it to delimit where new items begin since the last visit. So why not just take me right to that spot?
  4. You didn't address my question about the ProxyServer, do you really need that, and why is it being set to the same server as the BaseURL? It's possible that the HTTP server is redirecting the request to the HTTPS server, which the REST component is likely handling internally. I can't answer that. It is hard to diagnose without seeing the actual HTTP data on the network. That is debatable. TLS 1.1 is still fairly common. At a MINIMUM, don't go below TLS 1.0. Most servers have phased out TLS 1.0, and are phasing out TLS 1.1, but they still exist in the wild.
  5. There are a lot of things wrong with this code. The first thing that stands out to me is the BaseURL and ProxyServer are using the same Host/IP, why? That makes no sense to me. Also, if you are trying to *send* a request in 'multipart/form-data' format, you should be setting that in the 'Content-Type' request header, not in the 'Accept' request header. Also, 'UTF8' is not a valid content encoding for the 'Accept-Encoding' request header. Can you provide some details about what the REST API is actually expecting you to send to it?
  6. Remy Lebeau

    Indy problem with TIdTCPClient and IPv6

    "No address associated with hostname" is a system error, not an Indy error. Specifically, that error message comes from the gai_strerror() function when Indy calls the getaddrinfo() function and it returns an EAI_NODATA error code, meaning the hostname was found but did not map to an IP address. System networking configurations are outside the scope of Indy. I'm assuming you have the INTERNET permission enabled for your Android app, yes?
  7. Remy Lebeau

    THTTPCommandType - PATCH

    I imagine it is because PATCH is not in the official HTTP protocol RFCs, it is a non-official extension. But, since TIdHTTP supports PATCH, it makes sense that TIdHTTPServer should allow it, too. So I will consider adding it (https://github.com/IndySockets/Indy/issues/395). That being said, you can alternatively use the TIdHTTPRequestInfo.Command property instead, which is the original verb string before it is translated to the TIdHTTPRequestInfo.CommandType property. And because of that, I wonder if it would be better to just deprecate the TIdHTTPRequestInfo.CommandType property altogether? Because there is no official differentiation between them, so it is open to interpretation by implementations.
  8. Remy Lebeau

    Application Error

    The TIdMessage.DeleteTempFiles property was present in Indy 9. It initialized the TIdAttachment.DeleteTempFile property when parsing attachments. The TIdMessage.DeleteTempFiles property was removed in Indy 10, and the TIdAttachment.DeleteTempFile property was moved to TIdAttachmentFile and renamed to FileIsTempFile.
  9. Remy Lebeau

    Community edition form designer

    Yup. The Floating Designer was completely removed in 10.4.1: https://blogs.embarcadero.com/new-for-the-ide-in-rad-studio-10-4-1/
  10. IIRC, your application manifest needs to define an Intent Filter for each file extension/mime type you want to handle: https://developer.android.com/guide/components/intents-filters https://stackoverflow.com/questions/1733195/android-intent-filter-for-a-particular-file-extension Inside your code, you can use TAndroidHelper.Activity.getIntent() to get the JIntent that started your process.
  11. Remy Lebeau

    How does FMX check the printer status

    Please elaborate. What code did you try, and what error(s) did you get?
  12. That error comes from the VCL TImage.Canvas property getter, when the TImage.Picture.Graphic is holding a TGraphic object other than a TBitmap. The TImage.Canvas property is simply just a shortcut to the held TBitmap.Canvas. So you can't use it to draw/modify a non-bitmap graphic.
  13. Remy Lebeau

    how to respond on user drag of a column border in a listview

    Off the top of my head, something like this: private OldListViewWndProc: TWndMethod; procedure MyListViewWndProc(var Message: TMessage); ... uses ..., Winapi.CommCtrl, Winapi.Messages; procedure TMyForm.FormCreate(Sender: TObject); begin OldListViewWndProc := ListView1.WindowProc; ListView1.WindowProc := MyListViewWndProc; end; procedure TMyForm.MyListViewWndProc(var Message: TMessage); var pnmhdr: PHDNotifyW; begin if Message.Msg = WM_NOTIFY then begin case TWMNotify(Message).NMHdr^.code of HDN_BEGINTRACKW, HDN_ENDTRACKW, HDN_TRACKW: pnmhdr := PHDNotifyW(TWMNotify(Message).NMHdr); // use pnmhdr^ fields as needed: // - pnmhdr^.Item is the index of the column being tracked // - pnmhdr^.Button is the mouse button generating the message: 0=left, 1=right, 2=middle // - pnmhdr^.PItem is a pointer to a THDItemW describing the changes to the tracked column // // to block changes, set Message.Result := 1 and Exit here... end; end; OldListViewWndProc(Message); end;
  14. Remy Lebeau

    TJsonTextReader - extract object

    Using TJSONTextReader, you can parse the document like this: uses ..., System.Generics.Collections, System.JSON.Types, System.JSON.Readers; type TColumnNode = record Column: string; Caption: string; Width: string; end; TSearchNode = record Column: string; Rules: string; end; TColorNode = record Column: string; Rules: string; end; TReadState = ( None, InTopObject, InColumnsProp, InColumnsArray, InColumnObject, InSearchProp, InSearchArray, InSearchObject, InColorsProp, InColorsArray, InColorObject ); var JSON: string; Columns: TList<TColumnNode>; Search: TList<TSearchNode>; Colors: TList<TColorNode>; ColumnNode: TColumnNode; SearchNode: TSearchNode; ColorNode: TColorNode; TextReader: TTextReader; JSONReader: TJSONTextReader; State: TReadState; PropertyName: string; begin Columns := nil; Search := nil; Colors := nil; JSON := '...'; try Columns := TList<TColumnNode>.Create; Search := TList<TSearchNode>.Create; Colors := TList<TColorNode>.Create; TextReader := TStringReader.Create(JSON); try JSONReader := TJSONTextReader.Create(TextReader); try State := TReadState.None; while JSONReader.Read do begin case JSONReader.TokenType of TJsonToken.StartObject: begin case State of TReadState.None: State := TReadState.InTopObject; TReadState.InColumnsArray: begin ColumnNode := Default(TColumnNode); State := TReadState.InColumnObject; end; TReadState.InSearchArray: begin SearchNode := Default(TSearchNode); State := TReadState.InSearchObject; end; TReadState.InColorsArray: begin ColorNode := Default(TColorNode); State := TReadState.InColorObject; end; end; end; TJsonToken.EndObject: begin case State of TReadState.InTopObject: State := TReadState.None; TReadState.InColumnObject: begin Columns.Add(ColumnNode); State := TReadState.InColumnsArray; end; TReadState.InSearchObject: begin Search.Add(SearchNode); State := TReadState.InSearchArray; end; TReadState.InColorObject: begin Colors.Add(ColorNode); State := TReadState.InColorsArray; end; end; end; TJsonToken.StartArray: begin case State of TReadState.InColumnsProp: State := TReadState.InColumnsArray; TReadState.InSearchProp: State := TReadState.InSearchArray; TReadState.InSearchProp: State := TReadState.InColorsArray; end; end; TJsonToken.EndArray: begin case State of TReadState.InColumnsArray, TReadState.InSearchArray, TReadState.InColorsArray: State := TReadState.InTopObject; end; end; TJsonToken.PropertyName: begin PropertyName := JSONReader.Value.AsString; case State of TReadState.InTopObject: begin if PropertyName = 'columns' then State := TReadState.InColumnsProp end else if PropertyName = 'search' then State := TReadState.InSearchProp end else if PropertyName = 'colors' then State := TReadState.InColorsProp else JSONReader.Skip; end; TReadState.InColumnObject: begin if PropertyName = 'column' then CurrColumn.Column := JSONReader.ReadAsString else if PropertyName = 'caption' then CurrColumn.Caption := JSONReader.ReadAsString else if PropertyName = 'width' then CurrColumn.Width := JSONReader.ReadAsString else JSONReader.Skip; end; TReadState.InSearchObject: begin if PropertyName = 'column' then CurrSearch.Column := JSONReader.ReadAsString else if PropertyName = 'rules' then CurrSearch.Rules := JSONReader.ReadAsString else JSONReader.Skip; end; TReadState.InColorObject: begin if PropertyName = 'column' then CurrColor.Column := JSONReader.ReadAsString else if PropertyName = 'rules' then CurrColor.Rules := JSONReader.ReadAsString else JSONReader.Skip; end; else JSONReader.Skip; end; end; end; end; finally JSONReader.Free; end; finally TextReader.Free; end; // use Columns, Search, and Colors as needed... finally Columns.Free; Search.Free; Colors.Free; end; end; Obviously, take out whatever pieces you don't need. But needless to say, using a Reader can keep memory usage to a minimum, but at the cost of complicating the parsing logic. If your document is not very large, you might consider using a little extra memory in order to utilize the DOM-based framework instead, eg: uses ..., System.Generics.Collections, System.JSON; type TColumnNode = record Column: string; Caption: string; Width: string; end; TSearchNode = record Column: string; Rules: string; end; TColorNode = record Column: string; Rules: string; end; var JSON: string; Columns: TList<TColumnNode>; Search: TList<TSearchNode>; Colors: TList<TColorNode>; ColumnNode: TColumnNode; SearchNode: TSearchNode; ColorNode: TColorNode; JSONValue: TJSONValue; JSONObject: TJSONObject; JSONArray: TJSONArray; ArrElement: TJSONValue; begin Columns := nil; Search := nil; Colors := nil; JSON := '...'; try Columns := TList<TColumnNode>.Create; Search := TList<TSearchNode>.Create; Colors := TList<TColorNode>.Create; JSONValue := TJSONObject.ParseJSONValue(JSON); if JSONValue <> nil then try JSONObject := JSONValue as TJSONObject; JSONArray := JSONObject.GetValue('columns') as TJSONArray; for ArrElement in JSONArray do begin with ArrElement as JSONObject do begin ColumnNode.Column := GetValue('column').Value; ColumnNode.Caption := GetValue('caption').Value; ColumnNode.Width := GetValue('width').Value; Columns.Add(ColumnNode); end; end; JSONArray := JSONObject.GetValue('search') as TJSONArray; for ArrElement in JSONArray do begin with ArrElement as JSONObject do begin SearchNode.Column := GetValue('column').Value; SearchNode.Rules := GetValue('rules').Value; Search.Add(SearchNode); end; end; JSONArray := JSONObject.GetValue('colors') as TJSONArray; for ArrElement in JSONArray do begin with ArrElement as JSONObject do begin ColorNode.Column := GetValue('column').Value; ColorNode.Rules := GetValue('rules').Value; Colors.Add(ColorNode); end; end; finally JSONValue.Free; end; // use Columns, Search, and Colors as needed... finally Columns.Free; Search.Free; Colors.Free; end; end;
  15. Remy Lebeau

    How does FMX check the printer status

    Not really sure I understand the question. The only GetPrinter() I see in the FMX.Printer unit is the getter method for the TPrinter.Printers[] property. Are you looking for an FMX equivalent of the VCL TPrinter.GetPrinter() method, which outputs device info and a Handle to the currently active Printer? On Windows, the FMX.Printer.Win.TPrinterWin class has such a method. What status are you looking for exactly? Please clarify.
  16. Remy Lebeau

    Reading a binary file hangup without error

    I see several issues with that code: 1. your SetLength() is useless, because the subsequent ReadBytes() is completely replacing your allocated array with a different array allocates by ReadBytes(). 2. your SetString() is wrong, for two reasons: a. String is UnicodeString in D2009+, which you are clearly using due to TEncoding, which was also introduced in D2009. You are trying to populate the UnicodeString with AnsiChar data, but there is no overload of SetString() for that. You can only populate a UnicodeString with WideChar data. For AnsiChar data, you need to use AnsiString instead. b. You are advancing a PAnsiChar pointer through the byte array, but you are giving the array's whole length to SetString(), which means SetString() is going to read beyond the end of the array into surrounding memory after the 1st loop iteration. Since you are trying to convert each Byte into an (Ansi)String, you would need to use 1 for the SetString() length instead. 3. appending strings to the RichEdit1.Text property in a loop is VERY inefficient. It requires reading the RichEdit's entire content into a String in memory, then expanding that String in memory with appended data, then replacing the RichEdit's entire content with the new string. A much more efficient way to append strings to a RichEdit's content is to use its SelText property instead, eg: RichEdit1.SelStart := RichEdit1.GetTextLen; RichEdit1.SelLength := 0; RichEdit1.SelText := ...; But even that is not the best approach in this situation. Since you are trying to display a byte array as-is in the RichEdit as text, you may as well just assign the RichEdit.Text property 1 time with the entire array as 1 string, no loop needed at all, eg: var AFile: TFileStream; BR: TBinaryReader; MyByteArray: TBytes; mstr: AnsiString; begin AFile := TFileStream.Create(filename, fmOpenRead); BR := TBinaryReader.Create(AFile, TEncoding.Unicode, false); try // Get the whole file contents into the byte array MyByteArray := BR.ReadBytes(AFile.Size); SetString(mstr, PAnsiChar(@MyByteArray[0]), Length(MyByteArray)); RichEdit1.Text := mstr; // or: RichEdit1.Text := TEncoding.ANSI.GetString(MyByteArray); BR.Close; finally BR.Free; AFile.Free; end; end; In which case, you may as well just get rid of the TBinaryReader, as you can read bytes from the TFileStream directly: var AFile: TFileStream; MyByteArray: TBytes; mstr: AnsiString; begin AFile := TFileStream.Create(filename, fmOpenRead); try SetLength(MyByteArray, AFile.Size); // Get the whole file contents into the byte array AFile.ReadBuffer(MyByteArray[0], SetLength(MyByteArray)); SetString(mstr, PAnsiChar(@MyByteArray[0]), Length(MyByteArray)); RichEdit1.Text := mstr; // or: RichEdit1.Text := TEncoding.ANSI.GetString(MyByteArray); finally AFile.Free; end; end; In which case, you can just get rid of the TFileStream altogether, too: RichEdit1.Text := TFile.ReadAllText(filename, TEncoding.ANSI); Or RichEdit1.Lines.LoadFromFile(filename, TEncoding.ANSI);
  17. Remy Lebeau

    TNetHTTPRequest request_id

    For what, exactly? There is no request_id in the HTTP protocol. Perhaps you are working with a particular REST protocol instead that defines a request_id in its data, outside of HTTP?
  18. What kind of error? I've concatenated PNGs together before, but that was a long time ago, and IIRC I had to resort to a 3rd party PNG library to accomplish it (TPNGImage wasn't yet available in the VCL at the time). Copying the source PNGs to a temp bitmap, and then converting that bitmap back to a PNG, just didn't have the correct result for me (maybe it screwed up the alpha channels, I don't remember). So I had to drop down a layer and work with the raw PNG pixel data directly. The resulting PNGs were clean, but the effort was not.
  19. That is FMX code, but this question was posted in a VCL forum.
  20. Remy Lebeau

    Create an animated gif from a set of bitmaps?

    TGIFImage is a VCL class, AFAIK it is not available in FMX. Also, as I don't use FMX myself, my claim about its lack of support for animated GIFs is mainly based on the below post, which presents some 3rd party solutions for displaying animated GIFs in an FMX UI: https://stackoverflow.com/questions/45285599/how-to-use-animated-gif-in-firemonkey For displaying a series of bitmaps in a UI, one can use TBitmapListAnimation, but I don't know if that can also be used to create a GIF. Embarcadero's documentation only mentions that FMX's TBitmap supports GIF on all platforms except iOS, but doesn't mention what kinds of GIFs are supported.
  21. Remy Lebeau

    Create an animated gif from a set of bitmaps?

    AFAIK FireMonkey doesn't support animated GIFs. Use an 3rd party image library that does.
  22. Remy Lebeau

    AnsiString oddities

    Honestly, I have yet to try any of the Clang compilers at all, and while I would love to be able to use newer C++ language features in my code, this issue just reaffirms why I have no desire to EVER use the Clang compilers. They are just not supported properly in the IDE or the libraries. Too many problems that are "solved" by using the classic compiler instead.
  23. Remy Lebeau

    Opinions about Pascal vs C/C++ IDE

    There is no RAD Studio Community edition. There is a Delphi Community edition, and a C++Builder Community edition. They are separate products, and cannot be installed together. RAD Studio is the commercial bundle that includes both Delphi and C++Builder as a single product.
  24. Remy Lebeau

    Where I can find all implemented services documentation

    Perhaps you are looking for this? https://docwiki.embarcadero.com/RADStudio/en/FireMonkey_Platform_Services
  25. Remy Lebeau

    Using Resource in Email

    Ah. I see it now. I wonder why that message didn't show up on my feed earlier? Oh well.
×