-
Content Count
2633 -
Joined
-
Last visited
-
Days Won
109
Everything posted by Remy Lebeau
-
TIdHTTPServer.OnCommandGet - Timeout
Remy Lebeau replied to chkaufmann's topic in Network, Cloud and Web
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. -
Indy - TIdMultiPartFormDataStream
Remy Lebeau replied to chkaufmann's topic in Network, Cloud and Web
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. -
Indy - TIdMultiPartFormDataStream
Remy Lebeau replied to chkaufmann's topic in Network, Cloud and Web
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 -
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.
-
ITask.Wait() behaving differently when called multiple times
Remy Lebeau replied to Der schöne Günther's topic in RTL and Delphi Object Pascal
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. -
ITask.Wait() behaving differently when called multiple times
Remy Lebeau replied to Der schöne Günther's topic in RTL and Delphi Object Pascal
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. -
Named pipe failure, multithreading and asynchronous I/O
Remy Lebeau replied to FPiette's topic in Windows API
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. -
Memory leak in UnicodeString to string conversion
Remy Lebeau replied to dkprojektai's topic in OmniThreadLibrary
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; -
Is it possible to raise an aggregated exception?
Remy Lebeau replied to Der schöne Günther's topic in RTL and Delphi Object Pascal
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. -
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.
-
The Android 64bit deadline warnings have started
Remy Lebeau replied to Yaron's topic in Cross-platform
You can't. The apps have to actually be build with Unity. -
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.
-
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.
-
The Android 64bit deadline warnings have started
Remy Lebeau replied to Yaron's topic in Cross-platform
The reason was clearly stated in Google's deadline anouncement: -
Hide/Ignore comments from certain individuals?
Remy Lebeau replied to DJSox's topic in Community Management
Is there any other interface? -
screen shot - reliable method
Remy Lebeau replied to johnnydp's topic in RTL and Delphi Object Pascal
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. -
Tools Api: how to detect a key has been pressed in the editor window?
Remy Lebeau replied to santiago's topic in Delphi IDE and APIs
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. -
The Android 64bit deadline warnings have started
Remy Lebeau replied to Yaron's topic in Cross-platform
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. -
The Android 64bit deadline warnings have started
Remy Lebeau replied to Yaron's topic in Cross-platform
Except for 32bit games that use Unity 5.6.6+. 32bit-only updates for those apps will continue to be accepted until August 2021. -
The Android 64bit deadline warnings have started
Remy Lebeau replied to Yaron's topic in Cross-platform
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. -
The Android 64bit deadline warnings have started
Remy Lebeau replied to Yaron's topic in Cross-platform
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. -
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.
-
Anon methods passed as event handlers?
Remy Lebeau replied to David Schwartz's topic in RTL and Delphi Object Pascal
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. -
Anon methods passed as event handlers?
Remy Lebeau replied to David Schwartz's topic in RTL and Delphi Object Pascal
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. -
Anon methods passed as event handlers?
Remy Lebeau replied to David Schwartz's topic in RTL and Delphi Object Pascal
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.