Jump to content

Remy Lebeau

Members
  • Content Count

    2958
  • Joined

  • Last visited

  • Days Won

    134

Everything posted by Remy Lebeau

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

    The Android 64bit deadline warnings have started

    You can't. The apps have to actually be build with Unity.
  11. 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.
  12. 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.
  13. Remy Lebeau

    The Android 64bit deadline warnings have started

    The reason was clearly stated in Google's deadline anouncement:
  14. Is there any other interface?
  15. 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.
  16. 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.
  17. 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.
  18. 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.
  19. 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.
  20. 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.
  21. 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.
  22. 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.
  23. 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.
  24. 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.
  25. Remy Lebeau

    Anon methods passed as event handlers?

    That still won't work. No amount of syntax sugar will account for the fact that an anonymous procedure simply does not carry a Self parameter that the event caller can pass in, or the fact that an anonymous procedure is implemented using a compiler-generated reference-counted interface, which is radically different than a simple method pointer. Event handlers are currently implemented under the hood using the TMethod record. When a event owner wants to call an event handler, the compiler has to generate a particular set of code to call the method that is referenced by the record, inserting the Self parameter that is referenced by the record. In order to call an anonymous procedure, the compiler has to generate a completely different set of code to call the Invoke() method of the anonymous interface. There is currently no way for the compiler to decide at the call site at compile-time which set of code it needs to generate based on what kind of handler is assigned at runtime. Embarcadero would have to redesign the way TMethod and/or anonymous procedures are implemented in order to make anonymous procedures be compatible with TMethod, in a way that does not break existing user code. I suppose Embarcadero could make it so when an anonymous procedure is assigned to a TMethod, the record is flagged in a way that lets the compiler know the Data field points to an anonymous interface instead of an object pointer, and the Code field points to the interface's Invoke() method, so the compiler can then branch with the appropriate code to execute Invoke() on the interface. But that still leaves the issue that anonymous procedures are reference counted, and TMethod doesn't know anything about reference counting (outside of object ARC on mobile platforms - which is going away in upcoming Delphi versions). So that is even more boiler plate code that the compiler has to implement everywhere TMethod is used to account for the reference count. The Managed Records feature that was planned for 10.3 might have solved that, but that feature had to be deferred until 10.4 for technical reasons.
×