Jump to content

Remy Lebeau

Members
  • Content Count

    2684
  • Joined

  • Last visited

  • Days Won

    113

Everything posted by Remy Lebeau

  1. Remy Lebeau

    Error handling

    That makes sense for true unexpected/fatal errors, however... If a simple disconnect is being treated as a fatal error, that sounds like a bug that needs fixing.
  2. Remy Lebeau

    Error handling

    A client disconnect should never be treated as a fatal error that kills the server. Just close the client socket and move on. Let the server continue serving other clients normally.
  3. Remy Lebeau

    save probelm in ini file vcl with tlistbox

    First, do not store your INI file in the same folder as your EXE. If the EXE is installed in a protected folder, like under %ProgramFiles%, then this will not work. You should instead save the INI file in a subfolder you create for your app under the user's %APPDATA% folder, for instance. Second, use (Write|Read)Integer() instead of (Write|Read)String(). Third, what is the value of SkinFile? And did you verify that the restoration code is using the same value? You are not loading from the same file that you saved to. Also, why are you checking the current ItemIndex value before loading the value from the INI file? With that said, try something more like this: uses ..., SysUtils, ComObj, SHFolder; procedure TMyForm.GetINIFilePath(CanCreate: Boolean): string; var AppDataPath: array[0..MAX_PATH] of Char; begin OleCheck(SHGetFolderPath(Handle, CSIDL_APPDATA, 0, SHGFP_TYPE_CURRENT, AppDataPath)); Result := IncludeTrailingPathDelimiter(AppDataPath) + 'MyApp'; if CanCreate then ForceDirectories(Result); Result := IncludeTrailingPathDelimiter(Result) + 'my.ini'; end; procedure TMyForm.SaveINI; var Myinifile: TIniFile; SkinFile: string; begin SkinFile := ...; Myinifile := TIniFile.Create(GetINIFilePath(True)); try Myinifile.WriteInteger('LastDiskSkin', SkinFile, lst1.ItemIndex); ... finally Myinifile.Free; end; end; procedure TMyForm.LoadINI; var Myinifile: TIniFile; begin SkinFile := ...; Myinifile := TIniFile.Create(GetINIFilePath(False)); try lst1.ItemIndex := Myinifile.ReadInteger('LastDiskSkin', SkinFile, -1); ... finally Myinifile.Free; end; end; procedure TMyForm.FormCreate(Sender: TObject); begin LoadINI; end; procedure TMyForm.FormClose(Sender: TObject; var Action: TCloseAction); begin SaveINI; end;
  4. Remy Lebeau

    Indy IMAP and Microsoft EWS

    Yes. And you don't actually need OAuth for it, you could use an App-specific password instead if you have 2-step verification enabled. Not very mature at all, considering I just created the branch a couple of months ago, and am still receiving feedback over whether it even works correctly.
  5. Remy Lebeau

    Can't make a popup form go behind the main form in z-order

    Agreed. Embarcadero has tied way too many things in the VCL's internals to the TApplication.MainFormOnTaskbar property, making it a do-all toggle switch to enable/disable all kinds of behaviors it was never meant to toggle. IMHO, they should never have made its scope reach more than it was originally intended for. Introducing MainFormOnTaskbar at the TApplication level was the wrong design choice to begin with, it should have been introduced at the TForm level instead (like WinForms did with its Form.ShowInTaskbar property), and NOT touch anything other than what its name suggests. But that is just my opinion...
  6. Remy Lebeau

    Json create Array

    In the JSON you want to create, "registration_ids" is an array of strings. But in your code, you are creating "registration_ids" as an array of objects instead. To get the result you want, between WriteStartArray() and WriteEndOfArray(), you need to get rid of WriteStartObject(), WritePropertyName(''), and WriteEndObject(): wrtString := TStringWriter.Create(); wrtJSON := TJsonTextWriter.Create(wrtString); try wrtJSON.Formatting := TJsonFormatting.Indented; wrtJson.WriteStartObject; wrtJson.WritePropertyName('registration_ids'); wrtJson.WriteStartArray; //wrtJson.WriteStartObject; // <-- //wrtJson.WritePropertyName(''); // <-- wrtJson.WriteValue(strToken); //wrtJson.WriteEndObject; // <-- wrtJson.WriteEndArray; wrtJson.WritePropertyName('notification'); wrtJSON.WriteStartObject; wrtJSon.WritePropertyName('title'); wrtJson.WriteValue(edtBaslik.Text); wrtJson.WritePropertyName('body'); wrtJson.WriteValue(edtMesaj.Text); wrtJSON.WriteEndObject; wrtJSON.WriteEndObject; That said, why are you using TJsonTextWriter at all? This would be much more straight-forward if you used TJSONObject and TJSONArray instead, eg: uses ..., System.JSON; var arr: TJSONArray; notif, obj: TJSONObject; strJSON: string; begin obj := TJSONObject.Create; try arr := TJSONArray.Create; try arr.Add(strToken); obj.AddPair('registration_ids', arr); except arr.Free; raise; end; notif := TJSONObject.Create; try notif.AddPair('title', 'Hi'); notif.AddPair('body', 'Notification test'); obj.AddPair('notification', notif); except notif.Free; raise; end; strJSON := obj.ToJSON; // or, obj.Format finally obj.Free; end; // use strJSON as needed... end;
  7. The simplest solution that will not require any code changes is to have your Outlook/Exchange users turn on 2-step verification in their accounts and then generate application-specific passwords. Otherwise, you will have to update your code to use OAuth2 when connected to Outlook/Exchange.
  8. TClientSocket is just a thin wrapper around a TCP socket. WebSocket is a protocol that runs on top of TCP. Thus, TClientSocket will happily connect to a WebSocket server... when used correctly, which you are not... But that is not the IP you are trying to connect to... This is where your mistake is. The Host and Address properties are mutually exclusive, you can only use one of them. The Host has priority over the Address. So, you are trying to connect to 'localhost' (ie 127.0.0.1) only. That is why you are getting an error, since there is no TCP server running on port 6667 on your local machine. You need to either 1) drop the assignment of the Host altogether and just use the Address, or else 2) set the Host to the Arduino's hostname/IP: Client.Host := '192.168.0.24'; As far as TClientSocket is concerned, there is no difference. It only knows about TCP, not any protocols on top of TCP (Ethernet is underneath), so if you continue using TClientSocket then you are going to have to implement the WebSocket protocol yourself from scratch. Read RFC 6455 for that. Otherwise, there are plenty of 3rd party WebSocket libraries available that you can use instead.
  9. Remy Lebeau

    Can Rad Studio 11.1 and 11.2 coexist?

    No. Embarcadero changed their versioning scheme in 11.0: https://blogs.embarcadero.com/rad-studio-11-is-coming-new-version-announcement-and-beta-invite-for-update-subscription-customers/ Unlike with 10.x, which were all major versions where 10.x.y were minor updates, 11.x are minor updates to 11.0, which is the major version. Only major versions can co-exist. Minor updates do not. Yes. No.
  10. What kind of credentials, exactly? The IDE doesn't require credentials to compile a project. Chances are, there is something inside your project itself that is requiring credentials when the app starts running. Maybe a database? Or maybe the project contains a UAC manifest that requires the app to run elevated with admin permissions? There is not enough info provided to diagnose this. Can you provide a screenshot of the credential prompt? Then someone can tell you whether it is a native OS dialog or not, at least.
  11. There is currently a sasl-oauth branch in Indy's GitHub repo which adds new SASL components for using OAuth tokens with the POP3/IMAP4/SMTP clients. Yes, because each service provides their OAuth tokens in their own ways. So, outside of POP3/IMAP4/SMTP, you have to first obtain the tokens for the particular services you want to talk to, and then you can give those tokens to Indy for POP3/IMAP4/SMTP authentication.
  12. Remy Lebeau

    Line number of source code at runtime

    I'm sorry, but I don't understand what you are asking for. Please clarify.
  13. Remy Lebeau

    any body can write this code by delphi?

    If you are using Indy, the code would look something like this: uses ..., System.Classes, IdCoderMIME, IdHTTP, System.IOUtils; procedure Main(const filename, MassegeTxt, mobileNo: String); var WebRequest: TIdHTTP; SSL: TIdSSLIOHandlerSocketOpenSSL; bytes: TBytes; file: String; instance_id: String; token: String; mobile_number: String; postdata: TStringList; begin // send image as base64 bytes := TFile.ReadAllBytes(filename); file := TIdEncoderMIME.EncodeBytes(bytes); instance_id := 'instance xxxxx'; token := 'xxxxxxx'; mobile_number := mobileNo; WebRequest := TIdHTTP.Create; try SSL := TIdSSLIOHandlerSocketOpenSSL.Create(WebRequest); SSL.SSLOptions.SSLVersions := [sslvTLSv1, sslvTLSv1_1, sslvTLSv1_2]; WebRequest.IOHandler := SSL; WebRequest.Request.ContentType := 'application/x-www-form-urlencoded'; postdata := TStringList.Create; try postdata.Add('token=' + token); postdata.Add('to=' + mobileNo); postdata.Add('image=' + file); postdata.Add('caption=' + MassegeTxt); Writeln(WebRequest.Post('https://api.ultramsg.com/' + instance_id + '/messages/image', postdata)); finally postdata.Free; end; finally WebRequest.Free; end; end; If you want to use Embarcadero's TNetHTTPClient, the code would look something like this instead: uses ..., System.Classes, System.SysUtils, System.NetEncoding, System.Net.HTTPClientComponent, System.IOUtils; procedure Main(const filename, MassegeTxt, mobileNo: String); var WebClient: TNetHTTPClient; bytes: TBytes; file: String; instance_id: String; token: String; mobile_number: String; postdata: TStringList; begin // send image as base64 bytes := TFile.ReadAllBytes(filename); file := TNetEncoding.Base64.EncodeBytesToString(bytes); instance_id := 'instance xxxxx'; token := 'xxxxxxx'; mobile_number := mobileNo; WebClient := TNetHTTPClient.Create(nil); try WebClient.ContentType := 'application/x-www-form-urlencoded'; postdata := TStringList.Create; try postdata.Add('token=' + token); postdata.Add('to=' + mobileNo); postdata.Add('image=' + file); postdata.Add('caption=' + MassegeTxt); Writeln(WebClient.Post('https://api.ultramsg.com/' + instance_id + '/messages/image', postdata, nil, TEncoding.UTF8, nil).ContentAsString()); finally postdata.Free; end; finally WebClient.Free; end; end; Or, using Embarcadero's THTTPClient instead: uses ..., System.Classes, System.SysUtils, System.IOUtils, System.NetEncoding, System.Net.HttpClient; procedure Main(const filename, MassegeTxt, mobileNo: String); var WebClient: THTTPClient; bytes: TBytes; file: String; instance_id: String; token: String; mobile_number: String; postdata: TStringList; begin // send image as base64 bytes := TFile.ReadAllBytes(filename); file := TNetEncoding.Base64.EncodeBytesToString(bytes); instance_id := 'instance xxxxx'; token := 'xxxxxxx'; mobile_number := mobileNo; WebClient := THTTPClient.Create; try WebClient.ContentType := 'application/x-www-form-urlencoded'; postdata := TStringList.Create; try postdata.Add('token=' + token); postdata.Add('to=' + mobileNo); postdata.Add('image=' + file); postdata.Add('caption=' + MassegeTxt); Writeln(WebClient.Post('https://api.ultramsg.com/' + instance_id + '/messages/image', postdata, nil, TEncoding.UTF8, nil).ContentAsString()); finally postdata.Free; end; finally WebClient.Free; end; end;
  14. Remy Lebeau

    Line number of source code at runtime

    C++ has __FILE__ and __LINE__ macros. There is no equivalent in Delphi. Is that what you are asking for? If not, then please clarify your question.
  15. Remy Lebeau

    Floating Form Designer option gone in Delphi Alexandria?

    I wouldn't hold my breath on that. They made the intentional decision to remove the Floating Designer in 10.4.1. It is gone. I don't see them ever adding it back in, they want people to use the docked editor instead. But, as the blog article explained, you can still have multiple editors open, across multiple monitors.
  16. Remy Lebeau

    Sending SMS via FMX application

    You should be able to simply replace this: Date_SentIdx := Cursor.GetColumnIndex(StringToJstring('date_sent')); with this: Date_SentIdx := Cursor.GetColumnIndex(StringToJstring('report_date'));
  17. Remy Lebeau

    Sending SMS via FMX application

    Known issue, at least for "date_sent". You need to use "report_date" instead. See SMS messages date_sent on Android with Delphi XE5 always returns 0? on StackOverflow. Not sure if there is a similar workaround for "status".
  18. Remy Lebeau

    How to force update to label during a loop

    You don't necessarily need threading, you just need to return control to the main UI message loop periodically. For instance, break up your loop into chunks that you can trigger with TThread.ForceQueue() for each iteration, eg: procedure TMyForm.DoProcessing(i: Integer); begin Label1.Text := 'Step ' + IntToStr(i); Inc(i); if i <= 10 then TThread.ForceQueue(nil, procedure begin DoProcessing(i); end, 200) else TThread.ForceQueue(nil, AfterProcessing); end; procedure TMyForm.StartProcessing; begin DoProcessing(1); end; procedure TMyForm.AfterProcessing; begin ... end;
  19. Remy Lebeau

    TTimer limit..

    Agreed. For lengthy periods, I would ask the OS to notify me when the desired time has been reached, rather than polling the time regularly.
  20. Remy Lebeau

    TTimer limit..

    The TTmer interval is expressed in milliseconds, not microseconds. Yes. 4,294,967,295 milliseconds is 49.7 days. What EXACTLY is not working for you?
  21. Remy Lebeau

    How to force update to label during a loop

    <sigh> Turns out they are methods of TControl, which TForm is not derived from in FMX, unlike in VCL. And this is just one of a hundred reasons why I hate FMX and will never ever use it.
  22. Remy Lebeau

    sorry for the newbe question...

    Then what does this have to do with Delphi/FMX?
  23. Remy Lebeau

    How to force update to label during a loop

    Did you try Repaint()'ing the Form itself, rather than just the TLabel?
  24. Remy Lebeau

    How to force update to label during a loop

    No, but Repaint() is. In any case, depending on what the rest of your loop is doing, it may be worthwhile to move the logic into a worker thread, and then have that post updates to the UI thread when it wants to display something.
  25. Just a small nitpick - you can change this: RE.SelStart := Perform(EM_LINEINDEX, myLineIndex, 0); RE.SelLength := length(Lines[myLineIndex]); To this instead: var myLineStart: Integer; myLineStart := Perform(EM_LINEINDEX, myLineIndex, 0); RE.SelStart := myLineStart; RE.SelLength := Perform(EM_LINELENGTH, myLineStart, 0); That will avoid a memory allocation trying to retrieve the actual String of the line in question. The RichEdit already knows how many characters are on the line without needing to access the actual characters. An then to can be optimized further by using EM_EXSETSEL directly instead of the SelStart/Length properties: var rng: CHARRANGE; rng.cpMin := Perform(EM_LINEINDEX, myLineIndex, 0); rng.cpMax := rng.cpMin + Perform(EM_LINELENGTH, rng.cpMin, 0); Perform(EM_EXSETSEL, 0, LParam(@rng)); Further speed optimizations can be accomplished using EM_SETCHARFORMAT/2 and EM_SETEVENTMASK messages, see Faster Rich Edit Syntax Highlighting for details.
×