Knowledge Base Alert November, 2016







CodeRage XI event:

4 sessions from TMS available now at our Youtube channel



CodeRage XI, the online event from Embarcadero for Delphi and C++Builder developers, with dozens of technical sessions by Embarcadero speakers, MVPs, and tech partners.

Bruno Fierens (founder TMS software), Wagner Landgraf (TMS Business product manager) & Roman Yankovsky (TMS FixInsight product manager) brought sessions covering our latest technologies FNC, myCloudData, Aurelius, FixInsight developed at TMS software.
If you missed one of these sessions last week, you can now watch them via our Youtube channel.

New video's published at tmssoftwareTV:


TMS TAdvRichEditor:

Exchange text as HTML via string with TAdvRichEditor



Drop a TAdvRichEditor and TAdvRichEditorHTMLIO instance on the form and add the code:

var
  s:string;
begin
  // set the richeditor  content from a HTML formatted string
  s := '<i>Hello</i> <b>world</b>';
  AdvRichEditorHTMLIO1.LoadHTML(s);

  // return the richeditor content as HTML formatted string
  s := AdvRichEditor1.ContentAsHTML();
  ShowMessage(s);
end;


TMS VCL Cloud Pack:

How to fill a listview with the full drive info from a cloud storage service



This is an example of a recursive function that adds all files and folders including sub files and subfolders to a TListView control:

Storage.GetDriveInfo();
FillListView(ListView1, Storage.Drive);

procedure FillListView(AListView: TListView; Folder: TCloudItems);
var
  li: TListItem;
  i: integer;
begin
  for i := 0 to Folder.Count - 1 do
  begin
    li := AListView.Items.Add();
    li.Caption := Folder.Items[i].FileName;
    li.Data := Folder.Items[i];
    if (Folder.Items[i].ItemType = ciFolder) and Assigned(Folder.Items[i].Folder) then
      FillListView(AListView, Folder.Items[i].Folder);
  end;
end;


TMS Cryptography Pack:

TEncryptedIniFile: easy to use class for handling app settings with encryption



What's wrong with the KIS principle to store application settings in an INI file? The risk that someone is tampering with the INI file is an often heard reason for not using them. Not being able to store private or secret information another one.
Both issues are solved with the introduced TEncryptedIniFile class. It descends from TMemIniFile and is as such a drop-in replacement and will deal only in app memory with decrypted data. In the file itself, the data is at all times encrypted. To build TEncryptedIniFile, we internally use AES 256bit encryption offered by the TAESEncryption class in TMS Cryptography Pack.

The code to use TEncryptedIniFile becomes something like:
const
  aeskey = 'anijd54dee1c3e87e1de1d6e4d4e1de3';
var
  mi: TEncryptedIniFile;
begin
  try
    mi := TEncryptedIniFile.Create('.settings.cfg', aeskey);
    try
      FTPUserNameEdit.Text := mi.ReadString('FTP','USER','');
      FTPPasswordNameEdit.Text := mi.ReadString('FTP','PWD','');
      FTPPortSpin.Value := mi.ReadInteger('FTP','PORT',21);
      mi.WriteDateTime('SETTINGS','LASTUSE',Now);
      mi.UpdateFile;
   finally
      mi.Free;
   end;
  except
    ShowMessage('Error in encrypted file. Someone tampered with the file?');
  end;
end;
Of course, the weakness now is that the AES key is in the EXE file and as such, it won't stop seasoned hackers to extract it from the EXE and use it directly to decrypt/encrypt the settings file and tamper with it this way. Extra steps could be taken to use an AES key that is a combination of a unique machine ID and a part that is encrypted with a Ed25519 generated public key and decrypt the encrypted part of the AES key on the fly in the app with the Ed25519 private key and then use it in combination with the machine ID to encrypt/decrypt the INI file. That should make the effort to hack the settings file already a lot more difficult.

To start using this TEncryptedIniFile you can get TMS Cryptography Pack and you can download the TEncryptedIniFile class source here.

TMS TAdvStringGrid:

Technique to show via a messagebox that a entered cell value cannot be accepted



In this sample code, whenever a new cell value is entered longer than 3 characters, a messagebox is shown to ask to confirm this value or restore the original value:

  TForm1 = class(TForm)
    AdvStringGrid1: TAdvStringGrid;
    procedure FormCreate(Sender: TObject);
    procedure AdvStringGrid1CellValidate(Sender: TObject; ACol, ARow: Integer;
      var Value: string; var Valid: Boolean);
    procedure AdvStringGrid1EditCellDone(Sender: TObject; ACol, ARow: Integer);
  private
    { Private declarations }
  public
    { Public declarations }
    isvalid: boolean;
    origvalue: string;
    newvalue: string;
  end;

procedure TForm1.AdvStringGrid1CellValidate(Sender: TObject; ACol,
  ARow: Integer; var Value: string; var Valid: Boolean);
begin
  isvalid := length(value) <= 3;
  newvalue := value;
  origvalue := advstringgrid1.OriginalCellValue;
end;

procedure TForm1.AdvStringGrid1EditCellDone(Sender: TObject; ACol,
  ARow: Integer);
begin
  if not isvalid then
  begin
    if MessageDlg('new value ' + newvalue +' is not valid, restore old value '+ origvalue + ' ?', mtConfirmation, [mbYes, mbNo], 0 ) = mrYes then
    begin
      AdvStringGrid1.Cells[acol,arow] := origvalue;
    end;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
   AdvStringGrid1.Options :=  AdvStringGrid1.Options + [goEditing];
  AdvStringGrid1.RandomFill(True);
end;


TMS TAdvMultiInputQueryDialog:

How to retrieve the input values



Following sample code snippet shows how you can retrieve results:

begin
  AdvMultiInputQueryDialog1.QueryValues.Clear;
  AdvMultiInputQueryDialog1.QueryValues.Add;
  AdvMultiInputQueryDialog1.QueryValues.Add;

  AdvMultiInputQueryDialog1.QueryValues[0].&Label := 'Value 1';
  AdvMultiInputQueryDialog1.QueryValues[1].&Label := 'Value 2';

  if AdvMultiInputQueryDialog1.Execute = mrOK then
  begin
    listbox1.Items.add(AdvMultiInputQueryDialog1.QueryValues[0].ResultValue);
    listbox1.Items.add(AdvMultiInputQueryDialog1.QueryValues[1].ResultValue);
  end;
end;

The listbox is filled in this example with the input values entered in the dialog.

TMS FlexCel for VCL & FMX:

How to dump a dataset into Excel using the FlexCel API



One question we get asked from time to time is if FlexCel has a method like “DumpDataset” or “CopyFromRecordset” (which is the actual name in OLE Automation). This method should take a dataset and dump it into a sheet.

And the answer is no, we don’t include such a method because we find it too limiting: Normally you will have to customize some way how the cells are written, and you can’t do it with a single method that does the whole export in one piece. So instead, we provide 2 other different solutions to the problem.

1)FlexCel has reports, which you can use to dump a dataset “as is”, mostly as a DumpDataSet would, but it also lets you do the formatting. What is more, it allows you to easily modify the resulting sheets without modifying the code at all, so even the final user can do it. Say for example the logo of the company changes, you can update the logo in the Excel template, and the code stays exactly the same. Or if you prefer you can embed the templates in your exe file, and they won’t be editable by the final user. Your choice.

From reports, the most similar thing to "DumpDataset" is to create an empty file, write "<#mydataset.*> on it, save it, and then run the report against your dataset. You can find an example of this in the demos: <flexcel install folder>\TMSSoftware\FlexCelVCLNT\Demo\Delphi\Modules\20.Reports\88.Generic Reports and <flexcel install folder>\TMSSoftware\FlexCelVCLNT\Demo\Delphi\Modules\20.Reports\89.Generic Reports 2

Of course those 2 demos focus in “generic” datasets which you don’t know beforehand. If you know what data you are outputting, then you can just write <#dataset.field> in the cells where you want that field written, and format each field as you want.

Reports are designed specifically to deal with the problem of exporting datasets into Excel, but allowing formatting.

2)The reports in FlexCel work exclusively by calling the FlexCel API, so anything you can do in a report, you can do it directly with the API. So if for any reason you can’t or don’t want to use reports, you can use a method like this:

uses
  System.SysUtils, Windows,  DB, DBClient,
  VCL.FlexCel.Core,
  FlexCel.XlsAdapter;

procedure DumpDataSet(const ds: TDataSet);
var
  xls: TXlsFile;
  Row, Col: integer;
  Fmt: TFlxFormat;
  DateXF, DateTimeXF: integer;
begin
  xls := TXlsFile.Create(1, true);
  try

  Fmt := xls.GetDefaultFormat;
  Fmt.Format := 'dd/mm/yyyy hh:mm';
  DateTimeXF := xls.AddFormat(Fmt);

  Fmt := xls.GetDefaultFormat;
  Fmt.Format := 'dd/mm/yyyy';
  DateXF := xls.AddFormat(Fmt);

  ds.First;
  row := 1;
  while not ds.Eof do
  begin
    for col := 1 to ds.FieldCount do
    begin
      case ds.Fields[col - 1].DataType of
        TFieldType.ftDateTime:
        begin
          xls.SetCellValue(Row, Col, ds.Fields[col - 1].AsDateTime, DateTimeXF);
        end;
       TFieldType.ftDate:
        begin
          xls.SetCellValue(Row, Col, ds.Fields[col - 1].AsDateTime, DateXF);
        end;
        else
        begin
          xls.SetCellValue(Row, Col, ds.Fields[col - 1].Value);
        end;
      end;

    end;
    ds.Next;
    Inc(row);
  end;

    xls.Save('r:\test.xls');
  finally
    xls.Free;
  end;
end;


TMS FixInsight:

How to exclude an entire folder from FixInsight analysis



In FixInsight Settings dialog you can use file masks to exclude certain units. Furthermore you can exclude an entire folder using a mask like this "C:\FolderToExclude\*.pas". This will make FixInsight to ignore all units in the specified folder.

TMS Analytics & Physics Pack:

How to highlight syntax errors in math expressions using Analytics library



Analytics library allows easily evaluation of math expressions and symbolic derivative calculation. Another feature of the library is that it provides a mechanism for checking syntax of math expression before calculation. Moreover, it is possible to show user the exact error and where it is in the expression.
Analytics library uses exceptions to provide information about syntax (and other) errors (see page 20 of developer guide). Then exception handling must be used in any code when checking errors. The example of code for function calculation with syntax checking:

procedure TFormSyntaxErrorHighlight.ButtonCheckSyntaxClick(Sender: TObject);
var
  f: string;
  formula: TFormula;
  v: TValue;
  s: string;
begin
  f:=LabeledEditF.Text;

  try
    if FTranslator.CheckSyntax(f) then
    begin
      formula:=FTranslator.BuildFormula(f);
      v:=formula.Calculate();
      s:=TUtilities.SafeToString(v);
    end;
  except
    on es: ESyntax do
    begin
       HighlightSyntaxError(es);
       exit;
    end;
    on ex: Exception do
    begin
      ShowException(ex);
      exit;
    end;
  end;

  MessageDlg('Syntax is OK.'+#13+'F='+s, TMsgDlgType.mtInformation, [TMsgDlgBtn.mbOK], 0);
end;

The syntax check is made by CheckSyntax function of TTranslator class. This function returns true if an expression is syntactically correct and throws an exception if not. The exception is always inherited from base ESyntax class. This class contains information about the syntax error and position of the wrong part of the expression. And it makes easy to highlight the error for user. Code for highlighting:

procedure TFormSyntaxErrorHighlight.HighlightSyntaxError(es: ESyntax);
var
  err: TSyntaxError;
  p1: Integer;
  p2: Integer;
begin
  err:=es.Error;
  p1:= err.Position1;
  p2:= err.Position2;
  LabeledEditF.SelStart:=p1-1;
  LabeledEditF.SelLength:=p2-p1+1;

  ShowException(es);
end;

procedure TFormSyntaxErrorHighlight.ShowException(ex: Exception);
begin
  MessageDlg(ex.Message, TMsgDlgType.mtError, [TMsgDlgBtn.mbOK], 0);
end;


The code above selects the wrong part of the expression in the edit. The information for selecting text extracted from generated exception. Some result of syntax errors highlighting presented below.



As can be seen from the pictures, wrong expression parts selected in the edit box and description of the errors shown in message boxes.

Full source code of the example application (VCL) can be downloaded here.

TMS LCL HW Pack for Raspberry Pi:

Open-source components now available in new git repository



If you are, like us, excited about Internet of Things, embedded software development, DIY projects, controlling electronics from your code, ... we have for you a free & open-source bundle of hardware access components for Raspberry Pi. You can download full source code via following git repository:

https://tmssoftware@bitbucket.org/tmssoftware/tms-lcl-hw-pack-for-raspberry-pi.git

We also welcome you to contribute to this open-source package. Contact us with your suggestions, feedback, contributions.


As always, we thank all users for the numerous inputs, feedback, comments and suggestions. This is an invaluable help to steer our developments here at TMS software. We continue to look forward to all your further communications to direct our team to provide you better tools and components for your needs.

Kind regards,
TMS software team
Email: info@tmssoftware.com
Web: http://www.tmssoftware.com
Support, FAQ & Manuals: http://www.tmssoftware.com/site/support.asp


Follow latest developments at tmssoftware.com




NOTICE: If you wish to unsubscribe from the TMS software Newsletter, please click here.