LMD VCL - LMD Packs

From LMD
Revision as of 16:58, 27 May 2015 by Rafael (talk | contribs)

Jump to: navigation, search
[edit]

<< Back to Overview page

LMD ShellPack

Using Paste/Copy commands at runtime

LMD RichPack

Which MS RichEdit DLL Version can I expect on a specific operating system?

Please check list of different RichEdit versions.

Searching for specific attributes

Q: I was trying out the LMD RTF wrapper (using BCB 6) and wanted to know what would be the best way to search for words or characters with a specific attribute. A:

  • Use FindTextEx
  • Check SelAttributes
    if attrs not ok then FindTextEx again.

LMD WebPack

[Linker Error] Unresolved external "InternetCloseHandle" referenced from

Simply add wininet.lib to your project (file can be found in \lib directory of your C++ Builder / BDS / CRS installation). In recent IDEs you can also add
#pragma link "wininet.lib"
in your code.

NG Serialization

How to serialize collections

Serializing collections, including custom or standard collections (like TList) requires writing custom converters. For example, lets consider the folowing collection declaration:

type
  TItem = class
  public
    X: Integer;
    Y: Integer;
  end;

  TItems = class(TObjectList<TItem>);

To be able to serialize it, we need to declare a converter class, and associate this class with our collection using Converter attribute:

type  
  TItemsConverter = class(TConverter)
  public
    function  GetReadMode: TReadMode; override;
    procedure Write(S: TSerializer; const V); override;
    procedure Read(D: TDeserializer; var V); override;
  end;

  [Converter(TItemsConverter)]
  TItems = class(TObjectList<TItem>);

The converter can be implemented like this:

function TItemsConverter.GetReadMode: TReadMode;
begin
  Result := rmFillRead; // Indicate fill-read mode.
end;

procedure TItemsConverter.Read(D: TDeserializer; var V);
var
  lst: TItems;
begin
  lst := TItems(V); // Since we work in fill-read mode,
                    // V already contains a reference to
                    // TItems instance; we should not
                    // create it here.
  lst.Clear;

  D.BeginArray;
  while D.HasNext do
    lst.Add(D.Value<TItem>);
  D.EndArray;
end;

procedure TItemsConverter.Write(S: TSerializer; const V);
var
  lst: TItems;
  i:   Integer;
begin
  S.BeginArray;
  lst := TItems(V);
  for i := 0 to lst.Count - 1 do
    S.Value(lst[i]);
  S.EndArray;
end;

As can be seen, GetReadMode returns rmFillRead, which indicates that de-serializer should use fill-read mode. This means that no new TItems instance is created during de-serialization. This mode is especially usefull for collection like classes, because they usually owned by some other objects. For example, lets look at the following class:

type  
  TOwner = class
  private
    FItems: TItems;
  public
    constructor Create;
    destructor  Destroy; override;
    property    Items: TItems read FItems;
  end;

constructor TOwner.Create;
begin
  inherited Create;
  FItems := TItems.Create;
end;

destructor TOwner.Destroy;
begin
  FItems.Free;
  inherited;
end;

As can be seen, TItems collection is oqned by TOwner class. TOwner expose Items as read-only property, and thus, there no way to replace collection as a whole. Only collection content can be changed.

But, fortunately, TOwner class can be serialized and de-serialized, because TItems collection has fill-read mode converter:

var
  src, dst: TOwner;
  stream:   TStream;
  s:        TBinarySerializer;
  d:        TBinaryDeserializer;
begin
  stream := TMemoryStream.Create;
  try
    src := TOwner.Create;
    src.Items.Add(TItem.Create);
    src.Items.Add(TItem.Create);
    src.Items.Add(TItem.Create);

    s := TBinarySerializer.Create(stream);
    s.Value(src);
    s.Free;

    stream.Position := 0;

    d   := TBinaryDeserializer.Create(stream);
    dst := d.Value<TOwner>;
    d.Free;
  finally
    stream.Free;
  end;
end;

Please use the following link for more information about fill-read mode: Fill-Read Mode