Jump to content

Remy Lebeau

  • Content Count

  • Joined

  • Last visited

  • Days Won


Everything posted by Remy Lebeau

  1. Remy Lebeau

    JSON string value

    Um, yes it can. It has a full JSON library built-in.
  2. Remy Lebeau

    Undocumented "Interface flag" for IInvokable?

    Yes, sorry, that is what I meant.
  3. Remy Lebeau

    How to log raw data on Android?

    That is not what I was referring to. It takes multiple writes to the socket to send a web request, and multiple reads to receive a complete response. Those writes and reads get logged individually by Indy's Intercept components. They are not going to log a complete request in one go, or a complete response in one go. No, that is not the cause of the error. And besides, the TIdHTTP.Intercept gets assigned to the IOHandler.Intercept internally. So assigning the TIdHTTP.Intercept is just a shortcut. Make sure you DO NOT have multiple conflicting versions of Indy on your machine. If you do, then it is likely that the compiler is finding an old file that does not match the latest interface. That is perfectly fine, especially if you are only seeing it in the debugger. It just means the web server closed the connection on its end while TIdHTTP was still reading from the socket. Which is one possible way (not the preferred way, but still possible) for a web server to signal the end of a response. TIdHTTP should be handled such an error internally. You can configure your debugger to ignore that particular exception. Make sure you set the Active property of the TIdLog... component to True. Then those PHP devs don't really understand what they are doing. You can't post JSON using 'application/x-www.form-urlencoded'. If they are enforcing that, they are doing something wrong on their end. Makes sense, since you can't post JSON using 'application/x-www-form-urlencoded'.
  4. Remy Lebeau

    Undocumented "Interface flag" for IInvokable?

    OK. https://quality.embarcadero.com/browse/RSP-24631 I'm aware of that. But that is not the exact text you originally showed, which is why I questioned it.
  5. Remy Lebeau

    How to log raw data on Android?

    TIdLogEvent is not an abstract class, as it does implement all of the abstract methods of TIdLogBase. There is also TIdLogFile, which is not abstract, either. TIdInterceptSimLog and TIdLogFile are completely different file loggers. They write data in different formats. TIdLogFile is more "raw", logging data as-is, with optional timestamp and text replacements of CR and LF bytes. While TIdInterceptSimLog prefixes each read/write with a summary line describes whether the data is textual with a EOL present, or is raw bytes and what the byte size is, and appends a line break after each data.
  6. Remy Lebeau

    How to log raw data on Android?

    Why not TIdLogFile instead? Especially since you are saving data to files. For debugging purposes, you DON'T want individual reads/writes to be logged to separate files. It makes more sense to keep them in a single file. Even if you use TIdLogEvent with separate files for input and output, you are creating filenames based on timestamps with seconds precision, so you are likely to end up with multiple files that contain smaller pieces of the overall data. At the very least, I would suggest either dropping the seconds from the filename, or use the timestamp at the very beginning of the initial request rather than the timestamps of the individual reads/writes. Also FYI, TFile.WriteAllText() overwrites an existing file. You need TFile.AppendAllText() instead. Even if it were secured with HTTPS, the TIdLog... components would be able to log the unencrypted HTTP data, as they log outgoing data before it is encrypted, and log incoming data after it is decrypted. I see nothing in your code that would cause an Abstract error, as there are no abstract classes being used. That being said, you don't need to instantiate an IOHandler manually in this case, since you are not using HTTPS. TIdHTTP has its own Intercept property, and will create an IOHandler internally for you: var NewsRec: TGetNewsRequest; Json: string; SS: TStringStream; Http: TIdHTTP; LogEvent: TIdLogEvent; Response: string; ResponseRec: TGetNewsResponse; begin // some non-relevant code for json preperation, etc. deleted SS := TStringStream.Create(Json); try LogEvent := TIdLogEvent.Create(nil); try LogEvent.OnSent := frmMain.IdLogEvent1Sent; LogEvent.OnReceived := frmMain.IdLogEvent1Received; Http := TIdHTTP.Create(nil); try Http.Intercept := LogEvent; Http.Request.ContentType := 'application/x-www-form-urlencoded'; Response := Http.Post(GetNewsURL, SS); // try..except removed to simplify code finally Http.Free; end; finally LogEvent.Free; end; finally SS.Free; end; // some non-relevant code to deal with result deleted end; On a side note, 'application/x-www-form-urlencoded' is the wrong ContentType to use for JSON data, use 'application/json' instead. If you really want to send an 'application/x-www-form-urlencoded' post, you need to use the overloaded version of TIdHTTP.Post() that takes a TStrings as input, not a TStream.
  7. Remy Lebeau

    Undocumented "Interface flag" for IInvokable?

    Are you saying the returned IntfFlags *contains* a bit that *represents* an enum value of 3? Or that the IntfFlags *itself* is a numeric value of 3? In the former case, I have seen something similar before: https://stackoverflow.com/questions/49950534/strange-behaviour-of-typeinfo-by-anonymous-methods In the latter case, the TRttiInterfaceType.IntfFlags property returns a TIntfFlags Set, and a Set is implemented as a bitmask, where each bit represents a specific enum value. A bitmask value of 3 means the 1st 2 bits in the bitmask are set. And since TIntfFlags contains all of the TIntfFlag values, that would mean a bitmask value of 3 has the ifHasGuid and ifDispInterface flags enabled. Which, I guess the latter does not make sense in this situation, because IInvokable is not a dispinterface. So, it must be the former.
  8. Remy Lebeau

    Good design for "file was just saved" message

    When I display filenames in Task Dialogs, I like to put them in the ExpandedText section, so they are hidden initially but the user can choose to see them if desired.
  9. InitInstance() fills the allocated memory with zeros and inserts a pointer to the class's vtable at the front of the memory You should not need the type cast. ANY pointer can be assigned as-is to an untyped Pointer variable/parameter.
  10. Remy Lebeau

    Good design for "file was just saved" message

    What about using a single TButton with its Style set to bsSplitButton and a DropDownMenu assigned? The button could default to "Open", but the drop-down menu could have other actions for the user to choose from. Here is rough mockup of it (I don't have access to a working IDE at the moment):
  11. Remy Lebeau

    converting a C enum to Delphi

    In both C/C++ and Delphi, enums begin at 0, and values are sequential, unless explicitly otherwise stated. Since VmbPixelLayoutYCbYCr422 and VmbPixelLayoutYCbCr444 do not have explicit values, they are implicitly +1 from the values they immediately follow. Thus: VmbPixelLayoutYCbYCr422 = VmbPixelLayoutCbYYCrYY411 (= VmbPixelLayoutYUV411 = 8 ) + 1 = 9 VmbPixelLayoutYCbCr444 = VmbPixelLayoutCbYCrY422 (= VmbPixelLayoutYUV422 = 9 ) + 1 = 10
  12. Remy Lebeau

    converting a C enum to Delphi

    Embarcadero's documentation says otherwise: Enumerated Types with Explicitly Assigned Ordinality
  13. Remy Lebeau

    Login Form - 3 tries.

    Double check to make sure that you don't have a ModalResult assigned to btnOK itself. You should be able to click on btnOK and call DoLogin() as many times as you want without closing the Form until the Form's ModalResult is assigned when the Fail counter reaches the desired limit.
  14. In addition, in XE7+ the compiler has an (undocumented) GetTypeKind() intrinsic function: function GetTypeKind(T: TypeIdentifier): TTypeKind; So you can do this instead: procedure TCSVSchemaBuilder.BuldSchema<T>(SchemaTemplate: T); begin FSchemaItems.Clear; FNumRequired := 0; case GetTypeKind(T) of tkClass: BuildSchemaFromClass(...); tkRecord: BuildSchemaFromRecord(...); tkInterface: BuildSchemaFromInterface(...); else raise EImportSchema.Create('Cannot create schema by type'); end; if FSchemaItems.Count = 0 then raise EImportSchema.Create('Schema is missing critical information. Cannot proceed'); end; Prior to XE7, you can replace GetTypeKind() with this instead: case PTypeInfo(TypeInfo(T)).Kind of Either way, the advantage is that T's Kind is known at compile time, which allows this code to optimize out unused code branches at compile-time, whereas the original code does not allow that since the Kind is being queried dynamically at runtime.
  15. Remy Lebeau

    quality.embarcadero.com down?

    Works fine for me just now.
  16. Remy Lebeau


    I would suggest rewriting the function to something more like this: function IsFileInUse(const FileName: String): Boolean; var hf: THandle; begin hf := CreateFile(PChar(FileName), GENERIC_READ or GENERIC_WRITE, 0, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if hf <> INVALID_HANDLE_VALUE then begin CloseHandle(hf); Result := False; end else begin Result := (GetLastError() = ERROR_SHARING_VIOLATION); end; end;
  17. Remy Lebeau

    TIdHTTPServer.OnCommandGet - Timeout

    That means either TCP connections are not being closed, or the threads that own them are not being terminated correctly (deadlocks, etc). Well, you need to debug your code and find out. Something like that, yes.
  18. Remy Lebeau

    TIdHTTPServer.OnCommandGet - Timeout

    Blocked in what way exactly? Please provide more details about what exactly you are seeing happen. Are you seeing blockage when receiving a request, sending a response, or something in between? The OnCommand... event handler is not fired until after TIdHTTPServer has finished reading an entire request in full to populate the TIdHTTPRequestInfo object that gets passed to the OnCommand... handler. A response is not sent back to the client until after the OnCommand... handler exits (unless you trigger the sending of the response manually using various TIdHTTPResponseInfo methods). Any blockage in between receiving and sending would be in your processing. The only way to cancel an HTTP request that is in progress is to close the socket connection. If the blockage is happening while receiving a request, consider setting a non-infinite timeout to the TIdContext.Connection.ReadTimeout property. If the blockage is happening while sending a response, Indy does not implement write timeouts, but you can use the OS's underlying socket API manually to set one, if needed. Any blockage in between receiving and sending would need to be handled in your own code. That property would not help you anyway. It is deprecated and no longer used by Indy, but when it was, it was used only during server shutdown, to specify a timeout for waiting for individual server threads to terminate. It was never used during request/response handling. There is nothing like that in Indy. Such timeouts would have to be implemented in your own code.
  19. Remy Lebeau

    Indy - TIdMultiPartFormDataStream

    You should not use the Request.CustomHeaders property to set the 'Content-Type' header, use the Request.ContentType property instead. And the official way to send an 'application/x-www-form-urlencoded' post with TIdHTTP is to use the overloaded version of the TIdHTTP.Post() method that takes a TStrings as input, not the overload that takes a TStream as input. The TStrings overload takes a list of 'name=value' strings and posts them in 'application/x-www-form-urlencoded' format for you. Absolutely. See above. You are using the wrong approach and should update your code to let TIdHTTP do the hard work for you. Especially in regards to how the 'name=value' strings get formatted. TIdHTTP follows the HTML5 standard in that regard, which saves you the trouble of having to deal with it manually.
  20. Remy Lebeau

    Indy - TIdMultiPartFormDataStream

    Yes, text fields are encoded using MIME's "quoted-printable" format by default. You can use the TIdFormDataField.ContentTransfer property to change the encoding. Supported values are: a blank string (7-bit US-ASCII without sending a 'Content-Transfer-Encoding' header), '7bit', '8bit', 'binary', 'quoted-printable', and 'base64'. I would consider that to be a bug in PHP, if it is not decoding the MIME encoding that is declared in the posted data. In this case, I would suggest setting the TIdFormDataField.ContentTransfer to '8bit' to send the text data in its raw charset form. For instance, this is actually required if you want to send text data in UTF-8. Funny, I just answered a similar question on StackOverflow just this morning: Delphi Indy Post Encoding and PHP. Usually a different one. If no ContentTransfer is specified, US-ASCII is used, which will lose data if the text has non-ASCII characters in it. "quoted-printable" is part of the MIME standard. All MIME implementations are required to support it. However, RFC 7578 deprecates the use of the 'Content-Transfer-Encoding' header in 'multipart/form-data' submissions over HTTP, but TIdMultipartFormDataStream has not been updated to account for that yet. See https://bugs.php.net/bug.php?id=48219
  21. Remy Lebeau

    Is editing posts disabled?

    A post is editable for only a short period of time after it is initially posted. Once the time period expires, the post can no longer be edited without admin intervention.
  22. For instance, think of the Task being created and freed in a try/finally block that is inside of a try/except block. Or if a try/except block calls a function, which creates and frees the Task before exiting. In either case, the exception can be caught after the Task is freed.
  23. And how would you propose to do that exactly? Think of the use-case where the ITask is freed before the EAggregateException is caught. The RTL can't go back after the fact and say "hey, EAggregateException, when I raised you, I gave you some exceptions to hold references to but not take ownership of, but I'm going away now so please take ownership of them now, thanks". The only way I can think of solving this is by making the inner exceptions be reference counted. But Embarcadero/Idera is moving away from object-based ARC in RAD Studio 10.4, so such refcounting would have to be implemented manually by ITask and EAggregateException going forward. And then what happens if the user catches EAggregateException wants to extract the inner exceptions and re-raise them (which you yourself asked about just the other day)? So now the user has to get involved in the refcounting mechanism, or otherwise make EAggregateException relinquish ownership. This is not a very good scenario.
  24. Not at all. They are a perfectly valid, and still fully-supported, form of IPC. The only reason I have ever had to choose sockets over named pipes is security (or lack of) and ease-of-coding. Pipes are securable objects (from the OS's perspective), sockets are not, which can make deployments and configurations a little easier to work with. And pipes can be a little trickier to code for than sockets. But pipes work just fine when used correctly.
  25. Remy Lebeau

    Memory leak in UnicodeString to string conversion

    String is not an automation compatible data type. The IRecognitionResult.Get_text() method and IRecognition.recognition_text property need to be declared to use WideString instead of String. IRecognitionResult = interface(IDispatch) function Get_text: WideString; safecall; property recognition_text: WideString read Get_text; end;