Jump to content

Remy Lebeau

Members
  • Content Count

    2633
  • Joined

  • Last visited

  • Days Won

    109

Everything posted by Remy Lebeau

  1. 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.
  2. 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.
  3. 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
  4. 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.
  5. 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.
  6. 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.
  7. 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.
  8. 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;
  9. Remy Lebeau

    Is it possible to raise an aggregated exception?

    Yes, but then you are responsible for freeing it yourself. And that doesn't solve the problem of making it release ownership of its inner exceptions.
  10. Remy Lebeau

    New to Json

    The 2nd JSON object in the "conditions" array DOES NOT have a "bar_sea_level" value in it, so calling JsonObject.GetValue('bar_sea_level') returns nil. The "bar_sea_level" value is actually in the 3rd JSON object in the array, so you need to use Items[2] instead of Items[1]: var JsonValue: TJSONValue; JsonObject, JsonData: TJSONObject; JsonConditions: TJSONArray; Branch: string; ... begin ... JsonValue := TJSONObject.ParseJSONValue(st); if JsonValue <> nil then try JsonObject := JsonValue as TJSONObject; JsonData := JsonObject.GetValue('data') as TJSONObject; JsonConditions := JsonData.GetValue('conditions') as TJSONArray; JsonObject := JsonConditions.Items[0] as TJSONObject; Branch := JsonObject.GetValue('temp').Value; memo1.Lines.add('Parsed temperature '+branch); JsonObject := JsonConditions.Items[2] as TJSONObject; Branch := JsonObject.GetValue('bar_sea_level').Value; memo1.Lines.add('Parsed barometer '+branch); finally JsonValue.Free; end; ... end; It helps to view the JSON in an indented format so you can more clearly see the actual hierarchy of values, objects, and arrays, eg: { "data":{ "did":"001D0A710197", "ts":1557136813, "conditions":[ { "lsid":223656, "data_structure_type":1, "txid":1, "temp": 52.7, "hum":66.3, "dew_point": 41.8, "wet_bulb": 46.2, "heat_index": 51.7, "wind_chill": 52.7, "thw_index": 51.7, "thsw_index": 49.7, "wind_speed_last":0.00, "wind_dir_last":0, "wind_speed_avg_last_1_min":0.00, "wind_dir_scalar_avg_last_1_min":null, "wind_speed_avg_last_2_min":0.00, "wind_dir_scalar_avg_last_2_min":null, "wind_speed_hi_last_2_min":0.00, "wind_dir_at_hi_speed_last_2_min":0, "wind_speed_avg_last_10_min":0.00, "wind_dir_scalar_avg_last_10_min":null, "wind_speed_hi_last_10_min":0.00, "wind_dir_at_hi_speed_last_10_min":0, "rain_size":2, "rain_rate_last":0, "rain_rate_hi":0, "rainfall_last_15_min":0, "rain_rate_hi_last_15_min":0, "rainfall_last_60_min":0, "rainfall_last_24_hr":0, "rain_storm":null, "rain_storm_start_at":null, "solar_rad":0, "uv_index":0.0, "rx_state":0, "trans_battery_flag":0, "rainfall_daily":0, "rainfall_monthly":0, "rainfall_year":0, "rain_storm_last":null, "rain_storm_last_start_at":null, "rain_storm_last_end_at":null }, { "lsid":223554, "data_structure_type":4, "temp_in": 69.1, "hum_in":38.2, "dew_point_in": 42.6, "heat_index_in": 66.8 }, { "lsid":223553, "data_structure_type":3, "bar_sea_level":29.932, "bar_trend": 0.028, "bar_absolute":29.404 } ] }, "error":null } Now you can clearly see that there are 3 objects in the "conditions" array.
  11. Remy Lebeau

    The Android 64bit deadline warnings have started

    You can't. The apps have to actually be build with Unity.
  12. Remy Lebeau

    Get UserID from LogIn form at startup.

    Of course there is. The easiest way would be to update your TLogInForm.Execute() method to return the UserID when it exits, and then add a UserID variable to your TMainForm class that you can assign to after the MainForm has been created, eg: unit LogInFrm; interface ... type TLogInForm = class public ... class function Execute: string; ... end; ... implementation class function TLogInForm.Execute: string; begin ... if LoggedIn then Result := UserID else Result := ''; end; end. program Passwordapp; uses Vcl.Forms, System.UITypes, MainFrm in 'MainFrm.pas' {MainForm} , LogInFrm in 'LogInFrm.pas' {LogInForm}; {$R *.res} var UserID: string; begin // UserID := TLogInForm.Execute; if UserID <> '' then begin Application.Initialize; Application.CreateForm(TMainForm, MainForm); MainForm.UserID := UserID; Application.Run; end ... end. Otherwise, just have the Login Form save the UserID to a global variable if successfully logged in, and then your MainForm can use that global variable when needed. PS: {code} blocks do not work on this forum. You need to use the "Code" (</>) button on the post editor's toolbar instead.
  13. Remy Lebeau

    New to Json

    ParseJSONValue() is a 'class' method, so you don't need to create a TJSONObject instance in order to call it: JsonValue := TJSONObject.ParseJSONValue(st); This is creating a memory leak, because you are losing your pointer to the original TJSONValue object that ParseJSONValue() returns. You need to Free() that original object when you are done using it. You are not doing that. You should use additional variables for your typecasts, eg: var ... JsonValue: TJSONValue; JSonObject: TJOSNObject; JsonData: TJSONObject; JsonConditions: TJSONValue; begin ... JsonValue := TJSONObject.ParseJSONValue(st); if JsonValue <> nil then try JsonObject := JsonValue as TJSONObject; JsonData := JsonObject.GetValue('data') as TJSONObject; JsonConditions := JsonData.GetValue('conditions'); if (JsonConditions is TJSONArray) then begin JsonObject := (JsonConditions as TJSONArray).Items[0] as TJSONObject; Branch := JsonObject.GetValue('temp').Value; end; finally JsonValue.Free; end; ... end; A "second bracketed data" of what exactly? Which element of the JSON document has the pairs you are looking for? You need to be more specific. Are you referring to the "conditions" array? If so, then simply use Items[1] to access the second array element, Items[2] for the third element, etc. If that is not what you need, then what is stopping you from accessing the desired second array? What are you actually stuck on? Where is that array located exactly? It is really hard to help you with that when you have not shown the actual JSON you are working with. Please show the actual JSON.
  14. Remy Lebeau

    The Android 64bit deadline warnings have started

    The reason was clearly stated in Google's deadline anouncement:
  15. Is there any other interface?
  16. Remy Lebeau

    screen shot - reliable method

    The Desktop Duplication API was actually introduced in Windows 8. In Windows Vista and Windows 7, you can use the Magnification API instead (but with some restrictions). Windows 10 build 1803 introduces a new Screen Capture API.
  17. TApplicationEvents works by assigning its own handlers to the TApplication events. So if the IDE, or another plugin, assigns its own handlers to the TApplication events directly then TApplicationEvents will not work correctly. As it should, since TApplicationEvents is specifically designed to be used that way. When everyone uses TApplicationEvents handlers instead of TApplication handlers, then everyone gets notified of events.
  18. Remy Lebeau

    The Android 64bit deadline warnings have started

    Not sure what you are trying to say. Delphi itself only runs on Windows, but it compiles Android apps as native code, using a small Java stub to load and run the native code. So Android apps compiled with Delphi are affected by the August 1 2019 deadline.
  19. Remy Lebeau

    The Android 64bit deadline warnings have started

    Except for 32bit games that use Unity 5.6.6+. 32bit-only updates for those apps will continue to be accepted until August 2021.
  20. Remy Lebeau

    The Android 64bit deadline warnings have started

    No, but as a TeamB member, I'm usually invited to betas for Delphi and C++Builder. I haven't received any invitation for a new version yet. Scratch that. I just received notification that invitations are now starting to be sent out to prospective testers.
  21. Remy Lebeau

    The Android 64bit deadline warnings have started

    SHOULD being the figurative work here. There has been NO announcement from Embarcadero since August 2018 about how they plan to address the Android 64bit issue. There has been NO announcement of a new Delphi version in the works to include a 64bit Android compiler. AFAIK, there is no beta at this time.
  22. Remy Lebeau

    DynArraySetLength exception

    Yes, exactly. It needs a write lock, not a read lock. Yes, you are wrong. A read lock allows multiple threads to read shared data at the same time. A write lock allows only 1 thread at a time to modify shared data. Since you are modifying data (adding a new string to the TStringList, thus modifying its internal memory array and its Count), you need a write lock. You are getting an AV because your read lock is allowing multiple threads to modify the TStringList at the same time, trampling on each other's toes, so to speak.
  23. Remy Lebeau

    Anon methods passed as event handlers?

    You don't have to create instances of the class if you use a non-static 'class' method for the event handler. It still has an implicit Self parameter, but it points to the class type instead of an object instance. Works fine with events, as long as the method doesn't need to access any members of a particular object instance.
  24. Remy Lebeau

    Anon methods passed as event handlers?

    Sometimes I do that, too. But writing a class to wrap a standalone function is not always as convenient as just using the function by itself.
  25. Remy Lebeau

    Anon methods passed as event handlers?

    And yet, it CAN be done with plain/static functions. I do it all the time when writing test apps that have no UIs. It is just a matter of adding an explicit Self parameter to the function, populating a TMethod record with the address of the function in the Code field and an arbitrary value in the Data field, and then assigning that TMethod to the target event via a type-cast.
×