2021年12月13日 星期一

delphi 資源

 https://github.com/Fr0sT-Brutal/awesome-delphi

https://asmcn.icopy.site/awesome/awesome-delphi/

Awesome Pascal

https://landof.dev/awesome/pascal/ 
https://sourceforge.net/software/product/Delphi/alternatives

Synapse provides an easy to use serial port and synchronous TCP/IP library.

 Synapse provides an easy to use serial port and synchronous TCP/IP library. 

https://wiki.freepascal.org/Synapse#Overview

Overview

Synapse offers serial port and TCP/IP connectivity. It differs from other libraries that you only require to add some Synapse Pascal source code files to your code; no need for installing packages etc. The only exception is that you will need an external crypto library if you want to use encryption such as SSL/TLS/SSH.

See the documentation on the official site (link below) for more details.
Installation

Installation can be as simple as simply copying over all files to your application directory and adding the relevant Synapse units to your uses clause.

A more elegant and recommended way is compiling the laz_synapse.lpk package so you can use the same units in all your projects.

Synapse download/SVN info page: Synapse download page
Support and bug reporting

The Synapse project has a mailing list where support is given and patches can be submitted.

Bug reports can also be mailed to the mailing list.

See the Synapse support page
SSL/TLS support

You can use OpenSSL, CryptLib, StreamSecII or OpenStreamSecII SSL support with Synapse. By default, no SSL support is used.

The support is activated by putting the chosen unit name in the uses section in your project. You also have to put the binary library file in your project path (Windows), or install it into your library search path (Linux, macOS, FreeBSD).

Synapse loads SSL library files in runtime as dynamic libraries.

    For detailed information refer to SSL/TLS Plugin Architecture
    Some crypt libraries can be obtained from: http://synapse.ararat.cz/files/crypt/

Missing library

On Linux you need to make sure the required dynamic library is present/installed on your system. In case of cryptlib if the library is not present on the system, an error message appears during linking:

/usr/bin/ld: cannot find -lcl

A similar message will be displayed when using other dynamic libraries.

delphi runtime DFM object serializer for Delphi

 delphi runtime DFM

http://www.delphigroups.info/2/07/520442.html

https://torry.net/pages.php?id=51

https://githubmemory.com/repo/jean-lopes/dfm-to-json/issues/2

 http://www.geekinterview.com/question_details/31033

 http://www.delphigroups.info/2/77/421049.html

 http://www.delphigroups.info/2/02/300257.html

 http://www.delphigroups.info/2/75/299813.html

 http://www.delphigroups.info/2/07/520442.html

 DFM-serialization in depth https://www.codeproject.com/Articles/1060345/DFM-serialization-in-depth

delphi runtime DFM xml

Understanding Delphi Project and Unit Source Files 

https://coderedirect.com/questions/292800/delphi-txmldocument-created-at-run-time-generates-av-with-component-on-the-fo

https://www.thoughtco.com/understanding-delphi-project-files-dpr-1057652

https://reposhub.com/python/miscellaneous/ahausladen-DFMCheck.html

 

https://stackoverflow.com/questions/19989389/can-we-load-a-dfm-file-for-a-form-at-runtime/20011340

 


object serializer  Delphi


 

 mORMot / SynDB.pas

https://www.clevercomponents.com/articles/article040/

 https://docwiki.embarcadero.com/RADStudio/Tokyo/en/Serializing_User_Objects

https://github.com/anton-shchyrov/UrsJSON

 https://bitbucket.org/vkrapotkin/unescapejson/src/master/

https://github.com/onryldz/x-superobject

 

load a dfm file for a form at runtime

 
 load a dfm file for a form at runtime 

https://coderedirect.com/questions/382641/can-we-load-a-dfm-file-for-a-form-at-runtime
 

It is indeed possible to load a .dfm file at runtime and create the form represented by that dfm file.

I have written some code to do exactly that:

However: please note: You will need to add more RegisterClass(TSomeComponent) lines in the RegisterNecessaryClasses procedure. As written, if you, for example, try to load a .dfm file that includes a TSpeedbutton, you will get an exception: just add the RegisterClass(TSpeedbutton) to the RegisterNecessaryClasses procedure.

 

unit DynaFormF;  // This is a normal Delphi form - just an empty one (No components dropped on the form)

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs;

type
  TfrmDynaForm = class(TForm)
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  frmDynaForm: TfrmDynaForm;

implementation

{$R *.dfm}

end.
//////////////////////////////////////////////////////////////////////////
unit DynaLoadDfmU;
{$O-}
interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls, ComCtrls, utils08, DynaFormF;

var
  DebugSL : TStrings;

procedure ShowDynaFormModal(Filename:String);

implementation

procedure RegisterNecessaryClasses;
begin
  RegisterClass(TfrmDynaForm);
  RegisterClass(TPanel);
  RegisterClass(TMemo);
  RegisterClass(TTimer);
  RegisterClass(TListBox);
  RegisterClass(TSplitter);
  RegisterClass(TEdit);
  RegisterClass(TCheckBox);
  RegisterClass(TButton);
  RegisterClass(TLabel);
  RegisterClass(TRadioGroup);
end;

type
  TCrackedTComponent = class(TComponent)
  protected
    procedure UpdateState_Designing;
  end;

var
  ClassRegistered : Boolean;

procedure RemoveEventHandlers(SL:TStrings);
const
  Key1 = ' On';
  Key2 = ' = ';

var
  i, k1,k2 : Integer;
  S        : String;

begin
  for i := SL.Count-1 downto 0 do begin
    S := SL[i];

    k1 := pos(Key1, S);
    k2 := pos(Key2, S);

    if (k1 <> 0) AND (k2 > k1) then begin
      // remove it:
      SL.Delete(i);
    end;

  end;
end;

procedure ReportBoolean(S:String; B:Boolean);
const
  Txts : Array[Boolean] of String = (
  'Cleared', 'Set'
  );

begin
  if Assigned(DebugSL) then begin
    S := S + ' : ' + Txts[B];
    DebugSL.Add(S);
  end;
end;

procedure SetComponentStyles(AForm:TForm);
var
  AComponent : TComponent;
  i          : Integer;
  B1, B2     : Boolean;

begin
  for i := 0 to AForm.ComponentCount-1 do begin
    AComponent := AForm.Components[i];
    if AComponent is TTimer then begin
      // TTIMER:
      B1 := csDesigning in AComponent.ComponentState;

      // Does not work: an attempt to make the TTimer visible like it is in Delphi IDE's form designer.
      TCrackedTComponent(AComponent).UpdateState_Designing;

      B2 := csDesigning in AComponent.ComponentState;
      ReportBoolean('Before setting it: ', B1);
      ReportBoolean('After  setting it: ', B2);
    end;
  end;
end;

procedure ShowDynaFormModalPrim(Filename:String);
var
  FormDyna : TfrmDynaForm;

  S1       : TFileStream;
  S1m      : TMemoryStream;
  S2       : TMemoryStream;
  S        : String;
  k1, k2   : Integer;
  Reader   : TReader;
  SLHelper : TStringlist;
  OK       : Boolean;

  MissingClassName, FormName, FormTypeName : String;

begin
  FormName     := 'frmDynaForm';
  FormTypeName := 'TfrmDynaForm';

  FormDyna := NIL;
  OK       := False;

  S1 := TFileStream.Create(Filename, fmOpenRead or fmShareDenyWrite);
  try
    S1m := TMemoryStream.Create;
    try
      SLHelper := TStringlist.Create;
      try
        SLHelper.LoadFromStream(S1);

        S := SLHelper[0];

        k1 := pos(' ', S);
        k2 := pos(': ', S);
        if (k1 <> 0) AND (k2 > k1) then begin
          // match:
          SetLength(S, k2+1);
          S := 'object ' + FormName + ': ' + FormTypeName;
          SLHelper[0] := S;
        end;

        RemoveEventHandlers(SLHelper);
        SLHelper.SaveToStream(S1m);
      finally
        SLHelper.Free;
      end;

      S1m.Position := 0;
      S2 := TMemoryStream.Create;
      try
        ObjectTextToBinary(S1m, S2);
        S2.Position := 0;

        Reader := TReader.Create(S2, 4096);
        try
          try
            FormDyna := TfrmDynaForm.Create(NIL);
            Reader.ReadRootComponent(FormDyna);
            OK       := True;
            SetComponentStyles(FormDyna);
          except
            on E:Exception do begin
              S := E.ClassName + '    ' + E.Message;
              if Assigned(DebugSL) then begin
                DebugSL.add(S);
                if (E.ClassName = 'EClassNotFound') then begin
                  // the class is missing - we need one more "RegisterClass" line in the RegisterNecessaryClasses procedure.
                  MissingClassName := CopyBetween(E.Message, 'Class ', ' not found');
                  S := '    RegisterClass(' + MissingClassName + ');';
                  DebugSL.Add(S);
                end;
              end;
            end;
          end;
        finally
          Reader.Free;
        end;
      finally
        S2.Free;
      end;
    finally
      S1m.Free;
    end;
  finally
    S1.Free;
  end;

  if OK then begin
    try
      FormDyna.Caption := 'Dynamically created form: ' + ' -- ' + FormDyna.Caption;
      FormDyna.ShowModal;

    finally
      FormDyna.Free;
    end;
  end else begin
    // failure:
    S := 'Dynamic loading of form file failed.';
    if Assigned(DebugSL)
      then DebugSL.Add(S)
  end;
end;

procedure ShowDynaFormModal(Filename:String);
begin
  if NOT ClassRegistered then begin
    ClassRegistered := True;
    RegisterNecessaryClasses;
  end;

  ShowDynaFormModalPrim(Filename);
end;

{ TCrackedTComponent }

procedure TCrackedTComponent.UpdateState_Designing;
begin
  SetDesigning(TRUE, FALSE);
end;

end. 
 
Windows

You can associate an event with a socket with WSAEventSelect and wait with WaitForMultipleObjectsEx for the data on the socket or mutex or semaphore event etc.
Linux

You can use the futex syscall with FUTEX_FD argument (however this has been removed from the kernel), or use eventfd to implement the condition variable.

And you can spawn a second thread that would be waiting on the condition variable, and signal the one waiting in select(). Or ask for signals when input is received on the socket, etc. See this related question.
 
 

The reason is because Delphi uses Automatic Reference Counting for Objects on mobile platforms (iOS and Android), but not on desktop platforms (Windows and OSX). Your Free() is effectively a no-op, because accessing the component from the Components[] property will increment its reference count, and then the Free() will decrement it (in fact, the compiler should have issued a warning about the code having no effect). The component still has active references to it (its Owner and Parent), so it is not actually freed.

If you want to force the component to be freed, you need to call DisposeOf() on it, eg:

for LIndex := form4.ComponentCount-1 downto 0 do
begin
  if form4.Components[LIndex] is TVertScrollBox then
  begin
    form4.Components[LIndex].DisposeOf;
  end;
end;

Alternatively, remove the active references and let ARC handle the destruction normally:

var
  VertScrollLink: TVertScrollBox;
  LIndex: Integer;
begin
  ...
  for LIndex := form4.ComponentCount-1 downto 0 do
  begin
    if form4.Components[LIndex] is TVertScrollBox then
    begin
      VertScrollLink := TVertScrollBox(form4.Components[LIndex]);
      VertScrollLink.Parent := nil;
      VertScrollLink.Owner.RemoveComponent(VertScrollLink);
      VertScrollLink := nil;
    end;
  end;
  ...
end;

That being said, you might consider keeping track of the component you create so you don't need to use a loop to find it later:

type
  TForm4 = class(TForm)
    procedure FormShow(Sender: TObject);
    ...
  private
    VertScrollLink: TVertScrollBox;
    ...
  end;

procedure TForm4.FormShow(Sender: TObject);
begin
  VertScrollLink := TVertScrollBox.Create(Self);
  VertScrollLink.Align := TAlignLayout.Client;
  VertScrollLink.Parent := Self;
end;
begin
  ...
  if Assigned(VertScrollLink) then
  begin
    VertScrollLink.DisposeOf;
    { or:
    VertScrollLink.Parent := nil;
    VertScrollLink.Owner.RemoveComponent(VertScrollLink);
    }
    VertScrollLink := nil;
  end;
  ...
end;
 

Delphi object bin­ary Serializing TWinControl Tpanel File save an object to a file in Delphi dfm

 save an object to a file in Delphi

http://robstechcorner.blogspot.com/2009/09/so-what-is-rtti-rtti-is-acronym-for-run.html

Delphi 2010 RTTI - The basics
Using Attributes and TCustomAttribute descendants
Exploring TRTTIType in depth
Introduction to TValue
Exploring TRttiMember Descendants in depth (Part I) Properties and Fields
Why I call TRttiContext.Create() and TRttiContext.Free()
Exploring TRttiMember Descendants in depth (Part II) Methods
TValue in Depth
INI persistence the RTTI way
Xml Serialization - Basic Usage
Xml Serialization - Control via Attributes
Attributes: Practical Example- Object to Client Dataset
Types by Package... Dynamic plug-in systems.

http://robstechcorner.blogspot.com/2009/10/xml-serialization-basic-usage.html
robstechcorner https://code.google.com/archive/p/robstechcorner/source

 Xml Serialization - Basic Usage http://robstechcorner.blogspot.com/2009/10/xml-serialization-basic-usage.html

// Method 1:
var
 o : TypeIWantToSerailze;
 s : TXmlTypeSerializer;
 x : TXmlDocument;
 v : TValue;
begin
  s := TXmlTypeSerializer.create(TypeInfo(o));
  x := TXmlDocument.Create(Self); // NEVER PASS NIL!!!
  s.Serialize(x,o);
  x.SaveToFile('FileName.txt');
  v := s.Deserialize(x);
  o := v.AsType<TypeIWantToSerailze>;
  x.free;
  s.free;
end;

// Method 2:
var
 o : TypeIWantToSerailze;
 s : TXmlSerializer<TypeIWantToSerailze>;
 x : TXmlDocument;
begin
  s := TXmlTypeSerializer<TypeIWantToSerailze>.create;
  x := TXmlDocument.Create(Self); // NEVER PASS NIL!!!
  s.Serialize(x,o);
  x.SaveToFile('FileName.txt');
  o := s.Deserialize(x);
  x.free;
  s.free;
end;

https://pavkam.dev/
 
https://stackoverflow.com/questions/2657502/practical-usage-for-delphis-new-rtti-attributes-values/2657604#2657604
The extended RTTI works like Reflection in .NET. It gives you access to your internal application structure information. You can access class properties, methods etc.. at runtime, at extent you could not do it before.

Some ways of using it:

    Serialization / Deserialization of classes to XML or other media
    Mapping of objects to databases. ORM.
    Cloning of objects
    Dynamic invocation of methods
    "Scanning" of object at runtime and acting according to that.
    Easier development of "plugin" type systems

There is probably a lot of scenarios where it would be beneficial to use it. In short it adds dynamic aspect to your application. Your product is able to do some things at runtime, and more efficiently, than designing everything at designtime. It is not a silver bullet and a lot of people may never use it. But some design patterns or some problems just cannot be solved (at least not in efficient way) without the use of the new RTTI

https://martinfowler.com/articles/injection.html
https://en.wikipedia.org/wiki/Dependency_injection
https://code.google.com/archive/redirect/a/code.google.com/p/delphi-spring-framework?movedTo=https:%2F%2Fbitbucket.org%2Fsglienke%2Fspring4d
https://martinfowler.com/articles/injection.html#ConstructorVersusSetterInjection
https://code.google.com/archive/redirect/a/code.google.com/p/delphi-spring-framework?movedTo=https:%2F%2Fbitbucket.org%2Fsglienke%2Fspring4d
https://delphihaven.wordpress.com/2009/09/02/d2010-rtti-and-active-scripting/

Delphi Haven
Just another Delphi programming port of call on the internet
My book

[Delphi XE2 Foundations]
Some code

    AutoCorrect Components v1.0.3
    CCR Exif v1.5.1
    Generic IDispatch Proxy Classes for Active Scripting (Delphi 2010+)
    Hunspell Wrapper
    Theming Owner-Drawn Tabs
 
Something new for something old: Delphi 2010’s RTTI and Active Scripting

https://theroadtodelphi.com/2009/10/27/convert-string-to-enum-using-delphi-prism/
http://www.malcolmgroves.com/blog/?p=476

RTTI and Attributes in Delphi 2010
How to serialize Delphi object
https://blog.dragonsoft.us/2008/04/21/how-to-serialize-delphi-object/

https://docwiki.embarcadero.com/RADStudio/Alexandria/en/Working_with_RTTI
https://docwiki.embarcadero.com/Libraries/XE2/en/Main_Page

serialize Delphi object  bin­ary  seri­al­iz­a­tion

https://github.com/codejanovic/Delphi-Serialization
https://www.codeproject.com/Articles/1060345/DFM-serialization-in-depth
https://docwiki.embarcadero.com/RADStudio/Sydney/en/Serializing_User_Objects
https://coderedirect.com/questions/441027/binding-an-xml-node-to-a-tree-view-node

https://stackoverflow.com/questions/8782518/getting-the-size-of-a-class-or-object-in-the-same-format-as-a-file-size

https://stackoverflow.com/questions/65171574/how-to-calculate-delphi-class-size-using-tmemorystream-size

A case of using delphiXE RTTI to dynamically obtain information at runtime and obtain RttiType information of a TComponent class or TObject class
https://www.codetd.com/en/article/12146232


Delphi object  bin­ary  Serializing TWinControl  Tpanel File

Speech Synthesis & Speech Recognition: Using SAPI 5.1 Using TTS with Delphi CreateOLEObject('SAPI.SpVoice');

 Using TTS with Delphi
https://en.wikipedia.org/wiki/Microsoft_Speech_API

https://en.wikipedia.org/wiki/SASDK


CreateOLEObject('SAPI.SpVoice');

voz := CreateOLEObject('SAPI.SpVoice');
if not VarIsEmpty(voz) then begin
 vozes := voz.getVoices;
 ComboVoz.Clear;
 for i := 0 to vozes.Count - 1 do
  ComboVoz.Items.Add(vozes.item(i).GetDescription);

  Dialogs, StdCtrls, SpeechLib_TLB, OleServer, XPMan, ExtCtrls, ComCtrls, ENGINE,

  TFlatCheckBoxUnit;
    SAPI: TSpVoice;
  PropriedsF: TPropriedsF;   
  SOTokenVoice: ISpeechObjectToken;  // See the MS SAPI SDK for info on
  SOTokenVoices:ISpeechObjectTokens; // registry tokens that hold resources
  VPT:= 'Você selecionou X como voz padrão do sistema.';
 
  SAPI.EventInterests := SVEAllEvents;
  SOTokenVoices := SAPI.GetVoices('','');  // Use the registry tokens
 
    //For each voice, store the descriptor in the TStrings list
    SOTokenVoice := SOTokenVoices.Item(i);
    CBFA.Items.AddObject(SOTokenVoice.GetDescription(0), TObject(SOTokenVoice));
    //Increment descriptor reference count to ensure it's not destroyed
    SOTokenVoice._AddRef;
 
    CBFA.ItemIndex := CBFA.Items.IndexOf(SAPI.Voice.GetDescription(0));
 
  TB.Position := SAPI.Rate;
  EDTEST.TEXT:= TROCA('X', SAPI.Voice.GetDescription(0), VPT);
var SOTokenVoice:  ISpeechObjectToken;
begin
  SOTokenVoice   := ISpeechObjectToken(Pointer(CBFA.Items.Objects[CBFA.ItemIndex]));
  SAPI.Voice := SOTokenVoice;
  EDTEST.TEXT:= TROCA('X', SAPI.Voice.GetDescription(0), VPT);
  if SAPI.Voice = nil then
  SAPI.Speak(EDTEST.Text, 1);
  SpFileStream1: TSpFileStream;
  FileName : TFileName;
  T: TSTRINGLIST;
  I: INTEGER;
  T:= TSTRINGLIST.CREATE;
  T.LoadFromFile(EXTRACTFILEPATH(PARAMSTR(0))+'LISTA.TXT');
  FileName := extractfilepath(paramstr(0))+'RAQUEL\'+T[I];
  SpFileStream1 := TSpFilestream.Create(nil);
  SpFileStream1.Open(FileName, SSFMCreateForWrite, False);
  SAPI.AudioOutputStream := SPFileStream1.DefaultInterface;
  SAPI.Speak(COPY(T[I], 1, POS('.', T[I])-1), SVSFDefault);
  SPFileStream1.Close;
  SpFileStream1.Free;


procedure TForm1.FormClick(Sender: TObject);
var
  SpVoice: Variant;
begin
  SpVoice := CreateOleObject('SAPI.SpVoice');
  SpVoice.Speak('this is a test', 0);
end;


SpVoice GetVoices method (SAPI 5.3) | Microsoft Docs
 
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, OleServer, SpeechLib_TLB,ActiveX, ComCtrls,ControlCenter;
 
SpVoice1: TSpVoice;
SpSharedRecoContext1: TSpSharedRecoContext;
ProgressBar1: TProgressBar;
SRGrammar: ISpeechRecoGrammar;
CmdLine:string;
ControlActive:Boolean;
adeSoundControl: TadeSoundControl;
 
SOToken: ISpeechObjectToken;
SOTokens: ISpeechObjectTokens;
SOTokens := SpVoice1.GetVoices('', '');
SOToken := SOTokens.Item(id);
SpVoice1.Voice := SOToken;
SpVoice1.Rate:=speech;
SpVoice1.Volume:=100;
spvoice1.Speak(str,SVSFDefault);
Speecker(StrToInt(Edit2.Text),StrToInt(Edit3.Text),Edit1.Text);
 
 
https://github.com/halilhanbadem/delphi-google-speech-to-text
https://www.youant.net/

https://github.com/SirAlex/delphi-jose-jwt
Delphi JOSE and JWT Library
https://github.com/grijjy/DelphiGoogleAPI
Using the Google Cloud Platform APIs

 
voice: OLEVariant;
  voice := CreateOLEObject ('SAPI.SpVoice');
  voice.Voice := voice.GetVoices.Item(combobox1.ItemIndex); // current voice selected
  voice.volume := tbVolume.position;
  voice.rate := tbRate.position;
  voice.Speak (s, SVSFDefault);
  voice.Speak (s, SVSFlagsAsync);
  repeat  Sleep(100); until  voice.WaitUntilDone(10);
 

TMainForm = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
   voice: OLEVariant;
   procedure SayIt(const s:string);
  end;

var
  MainForm: TMainForm;

implementation

uses
   ComObj;

{$R *.dfm}
procedure TMainForm.SayIt(const s:string); // s is the string to be spoken
const
  SVSFDefault = 0;
  SVSFlagsAsync = 1;
  SVSFPurgeBeforeSpeak= 2;
begin
  memo1.setfocus;
  voice.Voice := voice.GetVoices.Item(combobox1.ItemIndex); // current voice selected
  voice.volume := tbVolume.position;
  voice.rate := tbRate.position;
  voice.Speak (s, SVSFlagsAsync {or SVSFPurgeBeforeSpeak});
end;


procedure TMainForm.Button1Click(Sender: TObject);
begin
  SayIt('Hello');
end;

procedure TMainForm.FormCreate(Sender: TObject);
begin
  voice := CreateOLEObject('SAPI.SpVoice');
end;

procedure TMainForm.FormDestroy(Sender: TObject);
begin
  voice  := Unassigned;
end;

end.
https://stackoverflow.com/questions/12117883/sapi-with-dephi-async-speech-doesnt-work


https://github.com/kimond/Jarvis-Project/blob/master/pyttsx/drivers/sapi5.py

MSSAM = 'HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Speech\\Voices\\Tokens\\MSSam'
MSMARY = 'HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Speech\\Voices\\Tokens\\MSMary'
MSMIKE = 'HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Speech\\Voices\\Tokens\\MSMike'

MSSam  MSMary MSMike


http://www.blong.com/conferences/dcon2002/speech/SAPI51/SAPI51.htm

https://edn.embarcadero.com/article/29583

 Speech Synthesis & Speech Recognition: Using SAPI 5.1 


procedure TfrmTextToSpeech.FormCreate(Sender: TObject);
var
  I: Integer;
  SOToken: ISpeechObjectToken;
  SOTokens: ISpeechObjectTokens;
begin
  SendMessage(lstProgress.Handle, LB_SETHORIZONTALEXTENT, Width, 0);
  //Ensure all events fire
  SpVoice.EventInterests := SVEAllEvents;
  Log('About to enumerate voices');
  SOTokens := SpVoice.GetVoices('', '');
  for I := 0 to SOTokens.Count - 1 do
  begin
    //For each voice, store the descriptor in the TStrings list
    SOToken := SOTokens.Item(I);
    cbVoices.Items.AddObject(SOToken.GetDescription(0), TObject(SOToken));
    //Increment descriptor reference count to ensure it's not destroyed
    SOToken._AddRef;
  end;
  if cbVoices.Items.Count > 0 then
  begin
    cbVoices.ItemIndex := 0; //Select 1st voice
    cbVoices.OnChange(cbVoices); //& ensure OnChange triggers
  end;
  Log('Enumerated voices');
  Log('About to check attributes');
  tbRate.Position := SpVoice.Rate;
  lblRate.Caption := IntToStr(tbRate.Position);
  tbVolume.Position := SpVoice.Volume;
  lblVolume.Caption := IntToStr(tbVolume.Position);
  Log('Checked attributes');
end;

XP style TXPManifest is used to enable run-time themes in your application.

 Dialogs, OleCtrls, SHDocVw, StdCtrls, ExtCtrls, XPMan, ComCtrls,MSHTML;
 
   ActiveX;

TXPManifest
Vcl.XPMan.TXPManifest

https://docwiki.embarcadero.com/Libraries/Sydney/en/Vcl.XPMan.TXPManifest

TXPManifest is used to enable run-time themes in your application.

Common Controls and XP Themes

https://docwiki.embarcadero.com/RADStudio/Sydney/en/Common_Controls_and_XP_Themes