Tuesday, March 31, 2009

English Help Update 2 for RAD Studio, Delphi

English Help Update 2 for RAD Studio, Delphi and C++Builder 2009
more information please go to visit:http://cc.embarcadero.com/Item/26831

Monday, March 30, 2009

Converting to D2009: How to keep PNGs in TImage

Hi,


if you have been using Gustavo Daud’s PNGImage before and consider migrating existing projects to D2009 you must keep in mind that you will loose all previously assigned PNGs in your TImages.


As you all know Delphi 2009 ships with native PNG support but there are some differences. In PngImage.pas CodeGear declared



type
TPNGObject = TPngImage deprecated 'Use TPngImage.';

So the classname for PNGs changed and the old one is marked as deprecated.


The problem: All TImage pictures are stored within the form’s .DFM file. Before inserting the binary data the IDE stores the classname (and it’s length) as a prefix to the data.


When using Gustavo’s component in D2006 it will store 0A54504E474F626A656374 which is in ASCII TPNGObject (the 1st 0A is the length of the following classname). In Delphi 2009 it stores 0954506E67496D616765 which is in ASCII TPngImage (again 09 is the length).


So when opening an existing form in D2009 the IDE searches for TPNGObject classname and as it cannot find it anymore the images are emptied.


With the help of Andreas Hausladen I came up with a solution for this:



PngClassWrapper.pas

{$IFDEF VER200}
uses
Classes, Graphics, PngImage;

type
TPngObject = class(TPngImage);
{$ENDIF}

implementation

{$IFDEF VER200}
initialization
TPicture.RegisterFileFormat('PNG', 'Portable Network Graphics (Compatibility Wrapper)', TPngObject);
finalization
TPicture.UnregisterGraphicClass(TPngObject);
{$ENDIF}

After discussing the issue Uwe Raabe yesterday published a fix inside of the PngComponents for Delphi 2009.


He used:



type
TPNGObject = class(TPngImage);

begin
TPicture.RegisterFileFormat('', '', TPNGObject);
end.

The empty strings will help to hide the wrapper from the FileOpen Dialog within the filter selection in the IDE.


An updated version if his port of the PngComponents for D2009 is available at CG:

PngComponents for Delphi 2009


Btw: The PngComponents Uwe published is still compatible with older Delphi Versions (tested with Delphi 2006). Only the PngImage Gustavo previously released on SourceForge is not available anymore as the license has been revoked as D2009 now ships with an enhanced version of it.

Building a Tweet of the Day Application

I've spend some time (but still too little) to build my Tweet of the Day application. Here are some elements.


I've spend some time (but still too little) to build my Tweet of the Day application. The initial version was made for a DataRage presentation (taking place next Thursday over the Internet).


The program has a single database table (on a remote DB or a local file), in both cases managed using a ClientDataSet with these fields:



FieldName = 'ID'

FieldName = 'EXPECTED'

FieldName = 'POSTED'

FieldName = 'TEXT'


The id is just an internal value (not the twitter id), the date and time for publication (which should be in the future), if it has been posted, and the actual 140 maximum characters for twitter. There is a button to create a new entry, which fills the ID, sets expected to 24 hours after the last entry, creates the initial text with "#number".


Editing is sone in an edit box that refreshes a "how many characters still to go" label:



nChars := 140 - Length (DbEdit1.Text);

if nChars > 10 then ...

The actual code is what the program uses to post to twitter:



listParams := TStringList.Create;
listParams.Add ('status=' + ClientDataSet1TEXT.AsString);
strResult := idhttp1.Post ('http://twitter.com/statuses/update.xml', listParams)

You have to provide a username and password in the IdHTTP1 component configuration, but the code is really as simple as it looks! Of course, the entire application still needs more (the automatic posting is still untested) and it might be worth having a companion web server where you can pre-post entries, to avoid having the application to keep running on a computer connected to the Internet.


But you should get an idea. Again, more info during my talk at DataRage next week, where I'll show also another program I wrote for adding rows to a Goole Apps spreadsheet in real time. I'll probably show the same progams also at Basta! Italia, on Tuesday.

Saturday, March 28, 2009

OpenSSL v0.9.8k for Indy

Hi,

I’ve created an updated pre-compiled version of the OpenSSL libraries to be used with Delphi. They are - as always - available at the Fulgan Mirror. Be sure to update your installation!


Regards,

HiDelphi

Friday, March 27, 2009

On Strings and Unicode in Delphi 2009

There have been a few posts about strings in Delphi 2009. Here are a couple of comments.



There have been a few posts about strings in Delphi 2009:




  • Breaking existing code (on The Doric Temple). The main point here is that CodeGear shoudl have left string as AnsiString, PChar as PAnsiChar to make existing code exactly identical to the past... and introduce Unicode support alongside.


  • 2009 and backwards compatibility (by Gurock Software). The main point here is conversion wasn't that hard and CodeGear made a good job with new warnings.


  • Misunderstood. Who me? (on the Doric Temple). Here the author counters some of the comments and adds that conversion is going on (seems less worried).

  • ...and probably many others I missed


Having delved into Unicode in Delphi 2009 and given sessions about it, I see that as a standard reaction and understand it. But I think CodeGear did the right job making string an alias of UnicodeString and the like. They had two options, which are clear if you look at code like:



var
myString: string;
begin
myString := 'some text';
MessagBox ('title', PChar (myString), ...)

One option was to let those who wanted Unicode make an extra effort. Converting this code to Unicode would have meant changing the string type declaration (to UnicodeString), the API function call (to MessageBoxW), and the PChar cast (to PWideChar). The second option was to let those who want to stick with Ansi make an extra effort, which is what they did. Keeping this code in Ansi in Delphi 2009 means changing the string type declaration (to AnsiString), the API function call (to MessageBoxA), and the PChar cast (to PAnsiChar). But moving the code above to Unicode means... recompiling it!


I know there are several other issues, like the misuse of the PChar pointer for referring to data other than string characters, but they came up with PByte and the TBytes array for that... or the Bookmark property madness. I've converted a lot of code and seens many problems, including performance issues...


However from a high level perspective I think it all boiled down to these two options. And I think asking for an extra effort to those who want to stick to Ansi better serves the product to move to Unicode, even if the initial acceptance might be slower. That's from the point of view of a Western Europe citizen (not too much Unicode need around here, but some) with an accented letter in his last name (so I tend to put more emphasis on Unicode and character support than other people). But my "accented letter in last name" horror stories are for another blog post.


Now I need to pack to go to the US, for the training session with Cary Jensen. You can follow me on twitter, of course.

Strings, PChars and reference counting

Hi folks, in today’s post I will continue with reference counting specifics of Delphi in the particular case of Strings.


We’ll start with a small example:



function ExcludeDigits(const S: String): String;
var
NewS : String;
PNewS : PChar;
I : Integer;
begin
NewS := S;
PNewS := PChar(NewS);

for I := 0 to Length(S) - 1 do
if CharInSet(PNewS[I], ['0' .. '9']) then
PNewS[I] := '_';

Result := NewS;
end;

var
Initial, Result : String;

begin
Initial := 'Hello 001 World';
Result := ExcludeDigits(Initial);

WriteLn('Initial: ', Initial);
WriteLn('Result: ', Result);

ReadLn;
end.

What will the output of this program be? The obvious result (the one we would expect) would be: “Initial: Hello 001 World” and “Result: Hello ___ World”. The actual result is: “Initial: Hello ___ World” and “Result: Hello ___ World”.


To understand why this happens we must dive deep into how reference counting works on strings. Let’s check out how things work by studying the ExcludeDigits function step by step:



  1. We assign S to NewS. And here starts Delphi’s magic! S is actually just a pointer into a heap object where the string is stored, so assigning it to NewS will just copy the pointer and will increase the reference count of that string (in the heap). Basically S and NewS would be 2 pointers that point to the same location in the heap. Current reference count of the string is 2.

  2. After assigning NewS (with conversion) to PNewS, PNewS will point to the first element (character) of the string in the heap. Remember that pointer types do not count as references so nothing else will happen!

  3. Next, the FOR loop will just check at each iteration if each character is a digit and will replace it with _ character. This happens directly in the heap object.

  4. Assigning NewS to Result will do the same as in point 1 — just assign the address and increase the reference count by 1.

  5. At the end of the function, compiler will also add a few calls itself. These calls will decrease the reference count of all local strings and dispose them if that count reached 0. In our case, the reference count will be 2.


Now it should be pretty clear why this function also changed the original string. What you need to remember is that Delphi uses Copy-On-Write technique for the strings — meaning that unless you change the copied string, that copy will occupy the same heap space. This has a nice advantage of saving memory, but also a big disadvantage - you must be careful using pointers because you never know (well, …, actually you know) what you may break.


Let’s revisit our example and add one small line to the code:



function ExcludeDigits(const S: String): String;
var
NewS : String;
PNewS : PChar;
I : Integer;
begin
NewS := S;

{ I have added the following line! }
NewS[1] := NewS[1];

PNewS := PChar(NewS);

for I := 0 to Length(S) - 1 do
if CharInSet(PNewS[I], ['0' .. '9']) then
PNewS[I] := '_';

Result := NewS;
end;

In the code above I have added a new line: “NewS[1] := NewS[1];”. I am modifying the copy so that Delphi copy-on-writes it — this means that NewS will contain a new address after this call happens. PNewS will now contain the address of the first element in the copy. This change will ensure that results are what we expected in the first place: “Initial: Hello 001 World” and “Result: Hello ___ World”.


If you use the CPU mode while debugging this code, take a look what happens for that assignment line: you will notice a call like UniqueStringU– this function actually does the “dirty work”. UniqueString checks to see if the reference count of the given string is more than 1 and if so, it will create a copy of that string and modify the parameter it received (Note: UniqueStringU is the Unicode version of this overloaded function). Let’s try it:



function ExcludeDigits(const S: String): String;
var
NewS : String;
PNewS : PChar;
I : Integer;
begin
NewS := S;

{ I have added the following line! Now using UniqueString }
UniqueString(NewS);

PNewS := PChar(NewS);

for I := 0 to Length(S) - 1 do
if CharInSet(PNewS[I], ['0' .. '9']) then
PNewS[I] := '_';

Result := NewS;
end;

Run it — yes the results are also what we expected in the first place!




General conclusion: Be very careful when you pass Strings to external DLLs by getting PChar references! You may think that you have passed a copy but actually you would pass a pointer into the original string.

Implementing IEnumerable is a nightmare

Now I know why there is no class in the VCL and RTL that implements the IEnumerable<T> or IEnumerator<T> interface. Because doing this makes you sick. Implementing an interface is more or less a very easy job. You copy all the methods from the interface declaration to your class (or you use Ctrl+Space to get a list of all the methods). And then you press Ctrl+Shift+C to generate the method body. But not with IEnumerable<T> and IEnumerator<T>. Both are derived from a non-generic interface (IEnumerable, IEnumerator) and that is where the nightmare begins.



type
IEnumerator = interface(IInterface)
function GetCurrent: TObject;
function MoveNext: Boolean;
procedure Reset;
property Current: TObject read GetCurrent;
end;

IEnumerator<T> = interface(IEnumerator)
function GetCurrent: T;
property Current: T read GetCurrent;
end;

IEnumerable = interface(IInterface)
function GetEnumerator: IEnumerator;
end;

IEnumerable<T> = interface(IEnumerable)
function GetEnumerator: IEnumerator<T>;
end;


If you want to implement the IEnumerable<T> interface the way you are used to, you get the following code.



type
TTest = class(TInterfacedObject, IEnumerable<TObject>)
function GetEnumerator: IEnumerator<TObject>; virtual; abstract;
end;


And if you try to compile this the compiler fails with


[DCC Error] Unit1.pas(27): E2211 Declaration of ‘GetEnumerator’ differs from declaration in interface ‘IEnumerable<System.TObject>’

System.pas(452): Related member: function GetEnumerator: IEnumerator;


That is because IEnumerator.GetEnumerator is in the way. The only solution I found (thanks to Rudy Velthuis posting in the newsgroups) was to add an additional method and rename the IEnumerable<T>.GetEnumerator method.



type
TTest = class(TInterfacedObject, IEnumerable<TObject>, IEnumerable)
function GetEnumerator: IEnumerator; virtual; abstract;
function IEnumerable<TObject>.GetEnumerator = GetGenericEnumerator;
function GetGenericEnumerator: IEnumerator<TObject>; virtual; abstract;
end;

And you have to do the same for IEnumerator<T>.GetCurrent.


My question now is why do IEnumerable<T> and IEnumerator<T> not derive from IInterface like IComparable<T>. That would make life much easier and it would prevent me from adding methods that add invalid functionality to my code. Because how shall I convert a “string” or “Integer” to a TObject that is expected by “IEnumerator.GetCurrent: TObject”.

Wednesday, March 25, 2009

Dynamic Creation of IntraWeb Components

For the past couple of days I’ve been working on an experimental IntraWeb (a.k.a., "VCL for the Web") project. Since I typically generate user interfaces dynamically, I wanted to see how that worked with IntraWeb. On the surface, it’s fairly similar to the regular VCL, but there are some important differences.


Rule number one is that all components you create must have the Name property set. The regular VCL doesn’t require this for components created in code, but IntraWeb uses the Component.Name as part of the HTML id, and if the id isn’t set, the JavaScript generated by IntraWeb won’t work. So always set the Name.


Another thing to note is that the default property values don’t always make sense. If a component looks different when you dynamically generated at runtime versus when you drop it on an IntraWeb form in the designer, take a close look at the text DFM. You’ll probably find non-default property values set by the designer. If you replicate this in your code, you should end up with a component looks the same at runtime.


With all that said, here’s some simple code to add tabs at runtime to an existing tab control:



uses   Graphics, IWContainerBorderOptions;

procedure TfrmUIPageGroup.ClearPageControls;
var
iPage: integer;
begin
for iPage := Pred(TabControl.Pages.Count) downto 0 do begin
TObject(TabControl.Pages[iPage]).Free;
end;
end;

procedure TMyIntraWebForm.AddSomeTabs;
var
iPage, iTabTop, iTabHeight, iTabWidth: integer;
NewTab: TIWTabPage;
begin
// need to have a design-time page to copy sizing properties from
Assert(TabControl.Pages.Count > 0);
iTabTop := TIWTabPage(TabControl.Pages[0]).Top;
iTabHeight := TIWTabPage(TabControl.Pages[0]).Height;
iTabWidth := TIWTabPage(TabControl.Pages[0]).Width;
ClearPageControls;
for iPage := 0 to 2 do begin
NewTab := TIWTabPage.Create(TabControl);
NewTab.BorderOptions.NumericWidth := 0;
NewTab.BorderOptions.BorderWidth := cbwNumeric;
NewTab.BorderOptions.Style := cbsNone;
NewTab.BorderOptions.Color := clNone;
NewTab.Color := clWebWHITE;
NewTab.Top := iTabTop;
NewTab.Width := iTabWidth;
NewTab.Height := iTabHeight;
// WordPress changes the single quote to a typographic quote here, so cutting
// and pasting the next two lines won't work. Sorry; I haven't figured out how
// to stop that
NewTab.Name := 'DynamicPage' + IntToStr(iPage);
NewTab.Title := 'Page ' + IntToStr(iPage);
NewTab.Parent := TabControl;
// TabOrder determines the order of tabs (really!) in this control
// It must be set *after* Parent

NewTab.TabOrder := iPage;
end;
end;


Alignment may not work as expected, either. If I build on this example by creating a control, parenting it to the tab sheet, and setting the Align property to alClient, that control’s size or position doesn’t actually change.


Finally, there is the issue of layout managers. If you use TIWTemplateProcessorHTML or TIWLayoutMgrHTML, there will not be a placeholder in your template for your dynamically generated component. There is probably a way around this, but I have not fully investigated the issue yet. One possible solution would be to do the dynamic component generation inside of a custom IntraWeb control.

Delphi2009 Generics and Type Constraints

The .NET type system is rooted at System.Object. The Delphi/Win32 type system isn’t rooted (built-in simple types, records, and classes don’t have a common ancestor), and primitive types can’t/don’t implement interfaces, so someone in the newsgroups asked how to deal with generics which must perform operations on primitive types, without the use of IComparable, et. al. Here’s one way. I’m not sure if it’s the best way, but it works.



unit Unit5;

interface

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

type
TAdder<T> = class
public
function AddEm(A, B: T): T; virtual; abstract;
end;

TIntAdder = class(TAdder<integer>)
public
function AddEm(A, B: integer): integer; override;
end;

TStringAdder = class(TAdder<string>)
public
function AddEm(A, B: string): string; override;
end;

TMath<T; A: TAdder<T>, constructor> = class
public
function AddTwoDigits(Left, Right: T): T;
end;

TForm5 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
end;

var
Form5: TForm5;

implementation

{$R *.dfm}

procedure TForm5.Button1Click(Sender: TObject);
var
AddInt: TMath<integer, TIntAdder>;
AddString: TMath<string, TStringAdder>;
begin
AddInt := TMath<integer, TIntAdder>.Create;
try
ShowMessage(IntToStr(AddInt.AddTwoDigits(2, 2)));
finally
AddInt.Free;
end;
AddString := TMath<string, TStringAdder>.Create;
try
ShowMessage(AddString.AddTwoDigits('2', '2'));
finally
AddString.Free;
end;
end;

{ TIntAdder }

function TIntAdder.AddEm(A, B: integer): integer;
begin
Result := A + B;
end;

{ TStringAdder }

function TStringAdder.AddEm(A, B: string): string;
begin
Result := IntToStr(StrToInt(A) + StrToInt(B));
end;

{ TMath<T, A> }

function TMath<T, A>.AddTwoDigits(Left, Right: T): T;
var
Add: A;
begin
Add := A.Create;
try
Result := Add.AddEm(Left, Right);
finally
Add.Free;
end;
end;

end.

Why Has the Size of TObject Doubled In Delphi 2009

Because it has a new feature.


Mason Wheeler noticed that TObject.InstanceSize returns 8 (bytes). It turns out that this is new in Delphi 2009; in previous releases, TObject.InstanceSize returned 4. But when you look at the definition of TObject in System.pas, you don’t see any fields declared at all.


Four out of the eight bytes are consumed by the VMT; this has been true since the first version of Delphi. You can read more about that in this chapter from Delphi In A Nutshell, which is old, but still accurate insofar as the VMT is concerned.


But what about the remaining four bytes? I didn’t remember the answer, but I enjoy a good puzzle, so I took a closer look at the source code for TObject. While poking around in System.pas, I happened to notice the following constants:



{ Hidden TObject field info }
hfFieldSize = 4;
hfMonitorOffset = 0;


OK, that explains the four bytes, but what is this used for? Searching for hfFieldSize yielded the answer:



class function TMonitor.GetFieldAddress(AObject: TObject): PPMonitor;
begin
Result := PPMonitor(Integer(AObject) + AObject.InstanceSize - hfFieldSize + hfMonitorOffset);
end;


So any object can have a reference to a TMonitor instance, and that reference is as big as a pointer on the target CPU. That reminded me of Allen Bauer’s long series of blog posts last year on the "Delphi Parallel Library," which discuss the TMonitor class in detail. He notes:


The TMonitor class [...] is now tied directly to any TObject instance or derivative (which means any instance of a Delphi class). [...] For TiburĂ³n [a.k.a. Delphi 2009], you merely need to call System.TMonitor.Enter(<obj>); or System.TMonitor.Exit(<obj>); among the other related methods.


The ability to lock any object is a good feature to have, especially in a multi-CPU, multi-core world. So I’m happy to spend the extra four bytes to get this feature. But I do find the implementation a bit mysterious. Why not just declare an actual field in TObject? I guess one reason would be to reduce the chance of a conflict with existing code. Another possible reason would be to enforce TMonitor’s contract; by obfuscating access to the field, you reduce the chances that an uninformed programmer performs actions on the field which break the contract. But these are just guesses. I don’t know why the Delphi team settled on this implementation. I presume they have some good reason.


Update: In comments, Allen Bauer explains the reasons for this implementation:


The reason for always placing the monitor reference field at the end of the object instance is mainly for backward compatibility. I didn’t want to alter the layout of objects in case there was some code out there that depended upon it. Also, by hiding the implementation the chance of inadvertent mucking with the monitor data was reduced and therefore it increased the overall safety of using it.


If you look closely at what happens on descendant instances, the monitor field is always the last field of the instance. This happens because the compilers (Delphi & C++) ensure that the field is allocated as the last step in the process of laying out the class instance. By doing this, an object laid out in pre-Delphi 2009 will be laid out exactly the same in Delphi 2009 except there is now an extra trailing pointer-sized field.

Tuesday, March 24, 2009

TMS Smooth Controls Pack is COOL







I have just downloaded and installed "TMS Smooth Controls Pack" from the Delphi registered users site and I’m totally impressed. This is exactly what Delphi needs out-of-the-box. TMS components look slick, elegant and modern. Delphi’s getting old? No way. It continues to be the best IDE and the visual component development is in the heart of RAD or "Rapid Application Development" invented with Delphi 1. It makes such a difference what visual component you are dropping on the form and manipulate via Object Inspector.

Here is the description from the download:

"The TMS Smooth Controls Pack provides sophisticated looking and smoothly animated controls for Delphi and C++Builder 2009.

This special edition, available to registered users of Delphi 2009, C++Builder 2009 and CodeGear RAD Studio 2009 as part of our special promotion for purchases during March 2009 includes the full control set in binary format.

The TMS Smooth Controls Pack is provided by a third party, tmssoftware.com bvba (TMS Software)."

Monday, March 23, 2009

How To: Invokable Variants

In this post I will try to explain how to create a “late-bound” dictionary based on invokable variants. Most of the techniques related to the creation of a custom Variant data type are already described in How To: Creating a custom Variant type.


To store the Key/Value pairs in my custom Variant, I will use TDictionary provided in Generics.Collections unit. Also note that the key of the dictionary is String since the we will use the late-bound properties to access specific values in the dictionary. The values are of type Variant, which enables me to store whatever information I want. The following code exemplifies the usage of the variant based dictionary:



var
Person: Variant;
begin
Person := VDict();

Person.FullName := 'John Smith';
Person.Age := 19;
Person.NetWorth := 9000;

WriteLn(Person.FullName);

{ Remove the Age property }

Person.RemoveAge();

{ Write all information stored in dictionary }
WriteLn(Person);
end.

And now let’s get to the actual coding process! The first thing is to create your class that will be held inside the TVarData structure. In my case, I use an already created class called TDictionary. Still, I declared an alias type for my String/Variant dictionary (makes life easier):




{ Declare the String/Variant dictionary that will
hold the real data }
TSVDictionary = TDictionary<String, Variant>;

The next step is the usual “declaring the TVarData record” that will map over our custom variants:



{ Mapping the TSVDictionary into TVarData structure }
TSVDictionaryVarData = packed record
{ Var type, will be assigned at runtime }
VType: TVarType;
{ Reserved stuff }
Reserved1, Reserved2, Reserved3: Word;
{ A reference to the enclosed dictionary }
FDictionary: TSVDictionary;
{ Reserved stuff }
Reserved4: LongWord;
end;

The FDictionary field in TSVDictionaryVarData record holds the dictionary instance used to hold the real key/value pairs. Now comes the important part: declaration of the proxy class that will manage the custom variant type I declared. To support late-binding capabilities in custom variants you have to descend from TInvokeableVariantType class. TInvokeableVariantType adds a few abstract methods which you have to override to intercept all calls made to methods/properties of your custom variant type. Note that TInvokeableVariantType derives from TCustomVariantType which means that you can add all the capabilities of a normal custom variant type on top of the dynamic ones.


The definition of the class I made follows:



{ Manager for our variant type }
TSVDictionaryVariantType = class(TInvokeableVariantType)
private
function DictionaryToString(const ADict: TSVDictionary): String;
public
procedure Clear(var V: TVarData); override;
procedure Copy(var Dest: TVarData; const Source: TVarData;
const Indirect: Boolean); override;
procedure CastTo(var Dest: TVarData; const Source: TVarData;
const AVarType: TVarType); override;
function GetProperty(var Dest: TVarData; const V: TVarData;
const Name: string): Boolean; override;
function SetProperty(const V: TVarData; const Name:
string; const Value: TVarData): Boolean; override;
function DoFunction(var Dest: TVarData; const V: TVarData;
const Name: string; const Arguments: TVarDataArray): Boolean; override;
function DoProcedure(const V: TVarData; const Name: string;
const Arguments: TVarDataArray): Boolean; override;
end;

As seen in the code above, I need the following capabilities for my variant based dictionary:



  • Clearing. When the variant requires clearing, freeing the TSVDictionary instance is required to avoid memory leaks.

  • Copying. Required for the assignments between variants. When copying from a variant to another, I do not copy the instance of the dictionary, rather I create a new one in the copy and copy all Key/Value pairs to it.

  • Casting. My variant based dictionary supports casting to strings. Casting to other types is done through string.

  • Property Get/Set Calls. Each late-bound property is actually a key in the dictionary. So I need to catch calls to get/set operations.

  • Function and Procedure Calls. My dictionary supports three custom operations (one to get the count of pairs, one to remove a pair from a dictionary and one to clear the dictionary).


The next step is to create a function which will create instances of our variant type. The following code shows all the relevant code pieces that are used in registering the proxy class, and creating custom instances of the variant based dictionary.


Most of this code pattern should be already known if you read the previous “How-To”:




...

interface
{ Creates a new Variant Dictionary }
function VDict(): Variant;

implementation

...

var
{ Our singleton that manages our variant type }
SgtSVDictionaryVariantType: TSVDictionaryVariantType;

function VDict(): Variant;
begin
{ Clear out the result }
VarClear(Result);

with TSVDictionaryVarData(Result) do
begin
{ Assign the new variant the var type that was allocated for us }
VType := SgtSVDictionaryVariantType.VarType;

{ Create a new instance of the dictionary object }
FDictionary := TSVDictionary.Create();
end;
end;

...

initialization
{ Register our custom variant type }
SgtSVDictionaryVariantType := TSVDictionaryVariantType.Create();

finalization
{ Uregister our custom variant }
FreeAndNil(SgtSVDictionaryVariantType);

And now let’s see the most important pieces of code that make up the proxy class. Note that I will not present all the methods that make up that class. Most of them are pretty obvious, like CastTo, Clear and Copy.


The first victim is DoFunction, which I implemented to support a late-bound call that returns the count of items in the dictionary:



function TSVDictionaryVariantType.DoFunction(
var Dest: TVarData; const V: TVarData; const Name: string;
const Arguments: TVarDataArray): Boolean;
begin
Result := False;

{ We do not support arguments here }
if Length(Arguments) > 1 then
Exit;

{ Is the first parameter an error variant? }
if (Length(Arguments) = 1) and (Arguments[0].VType <> varError) then
Exit;

{ Requesting dictionary count? }
if Name = 'COUNT' then
begin
VariantInit(Dest);
Dest.VType := varInteger;
Dest.VInteger := TSVDictionaryVarData(V).FDictionary.Count;
Exit(true);
end;

{ Try to call the procedures }
Result := DoProcedure(V, Name, Arguments);
end;

As you can see, I check whether a call is made to the Count function. If that is true, I return the number of pairs contained within this dictionary. Otherwise I forward the call to another method of my proxy class called DoProcedure. I do that because DoProcedure supports two more custom calls which can be made as functions or procedures (I don’t care):



function TSVDictionaryVariantType.DoProcedure(
const V: TVarData; const Name: string;
const Arguments: TVarDataArray): Boolean;
var
Key: String;
begin
Result := False;

{ We do not support arguments here }
if Length(Arguments) > 1 then
Exit;

{ Is the first parameter an error variant? }
if (Length(Arguments) = 1) and (Arguments[0].VType <> varError) then
Exit;

{ Check if this is a removal call }
if Pos('REMOVE', Name) = 1 then
begin
{ Remve the prefix }
Key := System.Copy(Name, Length('REMOVE') + 1, Length(Name));
TSVDictionaryVarData(V).FDictionary.Remove(Key);
Exit(true);
end;

{ Is this a CLEAR call? }
if Name = 'NAME' then
begin
TSVDictionaryVarData(V).FDictionary.Clear();
Exit(true);
end;
end;

The previous code piece is a bit more interesting because I check whether a call is made to a function that starts with “REMOVE” and cosider the text that continues afterwards as being the name of the key to be removed. For example calls like “MyVar.RemoveAge()” will remove the key named “Age” from the dictionary. The second supported call is Clear which clears the enclosed dictionary.


The last important code piece that follows shows the implementation of property set/get processing methods:



function TSVDictionaryVariantType.GetProperty(
var Dest: TVarData; const V: TVarData;
const Name: string): Boolean;
begin
{ Type cast to our data type }
with TSVDictionaryVarData(V) do
begin
{ Try to read the value from the dictionary }
if not FDictionary.TryGetValue(Name, Variant(Dest)) then
Clear(Dest);
end;

{ Return true in any possible case }
Result := True;
end;

function TSVDictionaryVariantType.SetProperty(
const V: TVarData; const Name: string;
const Value: TVarData): Boolean;
begin
{ Type cast to our data type }
with TSVDictionaryVarData(V) do
{ Update the value in dictionary dictionary }
FDictionary.AddOrSetValue(Name, Variant(Value));

{ Return true in any possible case }
Result := True;
end;

A few things to note about the code:



  • In DoProcedure and DoFunction methods, the Arguments array may contain one element even if no parameters are passed to the call. This happens because the compiler treats “MyVar.CallMe()” and “MyVar.CallMe” calls differently. In the first case it adds an argument of type varError, in the second it does not add any arguments.

  • The proposed variant dictionary implementation is case-insensitive. That means that “MyVar.Age := 5” is equal to “MyVar.AGE := 5“. If you need to make it case-sensitive, override the FixupIdent method in the proxy class. FixupIdent as implemented in TInvokeableVariantType coverts all identifiers to upper case.


That is all for now. Unfortunatelly I could not find an interesting example to demonstrate the power of late-binding and dynamic dispatch. Everything that can be done dynamically can be done normally anyway…

Jitter optimization for System.Initialize()

In the newsgroups is a discussion about “Delphi compiler and CPU core usage” and in a subthread the idea of a jittered InitializeRecord, FinalizeRecord and CopyRecord was born.


So here are the first performance statistics for a first (Pure Pascal) implemenation of such a Jitter for Initialize/InitializeRecord/InitializeArray.



type
TTest = record
I1: Integer;
SA: array[0..1] of string;
I2: Integer;
S: string;
Intf: IInterface;
A: array of Byte;
end;

var
m: array[0..1024] of TTest;


First call to Initialize

Original: 0.067819 ms

Jittered: 0.042238 ms (this includes the time for the Jitter itself)

// _InitializeArray(@m, TypeInfo(TTest), Length(m));


Second call to Initialize

Original: 0.057681 ms

Jittered: 0.010007 ms

// _InitializeArray(@m, TypeInfo(TTest), Length(m));


Execution in a tight loop: 10000x

Original: 419.089185 ms

Jittered: 39.533007 ms

// for I := 0 to 10000 - 1 do

// _InitializeArray(@m, TypeInfo(TTest), Length(m));


It is interesting that the Jitter can generate and execute the code in less time than the RTTI version can execute the initialization. This is because the RTTI version must process all array elements while the Jitter generates code for only one iteration and adds a loop to the code.


Generated code:


00200000 xor edx,edx
; inner loop for "array[0..1] of string" (begin)
00200002 push eax
00200003 push ecx
00200004 mov ecx,$00000002
; array elements
00200009 mov [eax+$04],edx
; inner loop for "array[0..1] of string" (end)
0020000C add eax,$04
0020000F dec ecx
00200010 jnz $00200009
00200012 pop ecx
00200013 pop eax
; record fields
00200014 mov [eax+$10],edx
00200017 mov [eax+$14],edx
0020001A mov [eax+$18],edx
; outer loop for array variables
0020001D add eax,$1c
00200020 dec ecx
00200021 jnz $00200002
00200023 ret
; alignment for the next method
00200024 nop
00200025 nop
00200026 nop
00200027 nop

This is only the start. I don’t think that the CopyRecord and FinializeRecord functions will show the same increase in performance, because the cleaning (LStrClr, …) are the real time eaters. But I can only be sure if I have tested it.


But there is also a downside. The Jitter uses a hash table to find an already jittered Initialize function for the TypeInfo. And if the type is a simple type, the original Initialize will outperform the Jitter because in the end both execute the same code but the original Initialize has less overhead. I’m sure this could be worked out by optimizing the hash table access and some other tricks.

Delphi 2009 and UTF8

Today I came to a point where I had a UTF8 string in Delphi 2009 and I wanted to use StringReplace to escape some characters. No big deal.



var
S: UTF8String;
begin
S := UTF8Encode('Hello'#10'World!');
S := StringReplace(S, #10, '\n', [rfReplaceAll]);
end;


The compiler compiled this piece of code without an error but with two warnings about implicit string conversions. Ok, UTF8String is an “AnsiString”, so let’s add the AnsiStrings unit to the uses clause to get access to the AnsiString-StringReplace overload. But what’s that? The two warnings do not disappear. The compiler prefers the Unicode version so let’s change the call to explicitly call AnsiStrings.StringReplace. This doesn’t help either. The opposite happens, now there are four warnings and one with a potential dataloss.


By looking at the generate code in the CPU view, I saw what the compiler has done to my code. It converts my UTF8String to an UnicodeString and then to an AnsiString(CP_ACP). It calls StringReplace and the returned AnsiString(CP_ACP) is converted to an UncodeString and back to my UTF8String. This doesn’t sound good and as if the StringReplace function wasn’t a slow function by itself, this string conversion slows down the call too much.


As a result this simple call to StringReplace is now:



var
S: UTF8String;
begin
S := UTF8Encode('Hello'#10'World!');
S := RawByteString(AnsiStrings.StringReplace(RawByteString(S), #10, '\n', [rfReplaceAll]));
end;

Anonymous Methods

Both Delphi 2009, and the upcoming Delphi Prism have support for anonymous methods. Now while I am very excited about other features, notably generics, I just couldn’t get excited about anonymous methods. I just didn’t get them. I understood the syntax, but to me they looked like inline methods. My biggest question was why should I use an anonymous method, and not a procedural types, like we’ve always done in Delphi? Ok, I save having to write a separate method, but what’s wrong with separate. It’s probably more readable that way anyway.

I read blogs the blogs and articles. I studied examples, which always seemed to be artificial, or just too complicated to actually explain the concepts. I read the Wikipedia entry on closures, which are what everybody else seems to call them, but still no joy. All I really want is to be able to understand the concept, enough that during my everyday work, I can identify areas where an anonymous methods would fit nicely, and where they would be the best choice.

Being a recent convert to Stackoverflow.com, I asked a question there. Can someone explain Anonymous methods to me? I got quite a few answers, some with yet more code examples. I still couldn’t see how any of this was going to make my day to day coding any easier, or even a little bit more exciting! That is until I got one answer which made me go Aha. Actually it was one line within that answer.

Just think of typical callback code where you need to have data available to the callback.

So I looked at some code I’d recently written, which used a callback, and replaced that callback(literally a method pointer) with an anonymous method. The code I had recently written was an implementation of a Direct Acyclic Graph. Basically a way to represent a number of objects (vertices), and the relationships(edges) that exist between those objects. Think cities(the vertices) with possible flights between them(the edges). Then using certain well-defined algorithms, you can traverse those vertices in various ways. So going back to the cities and flights example, it would be possible to find the shortest route between any two cities for example.

I’d originally implemented these traversals using procedural types.


type
TTraversalMethod = procedure(v: TVertex);

TGraph = class(TObject)
private
public
procedure LinearTraversal(aMethod :
TTraversalMethod);
end;

procedure TGraph.LinearTraversal(aMethod :
TTraversalMethod);
var
v : TVertex;
begin
for v in Vertices do
aMethod(v);
end;

So basically LinearTraversal does nothing special except traverse all the vertices in a linear fashion. Not too exciting. So let’s say we now have a graph and we want to display the vertex names as a string, which we’ll implement using a TStringList;

procedure TMyClass.TraverseMethod(v : TVertex);
begin
fStringList.Add(V.Name);
end;

procedure TMyClass.ShowGraphAsText(aGraph : TGraph);
begin
fStringList.Clear;
aGraph.LinearTraversal(TraverseMethod);
ShowMessage(fStringList.Text);
end;

You’ll notice that we need two methods, one to actually prepare the call, and the other is the function called on each vertex. We also need a stringlist which must be visible from both methods. Unfortunately even if we make it private to the class, it’s still visible to all other methods in the class. What if some other method is expecting some other list to be stored in that stringlist? A year down the line how can we possibly remember not to touch that stringlist?


What would be ideal is if we could make the stringlist local to the ShowGraphAsText method. Well it turns out we can. I’m going to rewrite the above using anonymous methods. I’ll use Delphi Prism/Oxygene as that’s what I’ve got at hand, but Delphi 2009 would work just as well.


type
TTraversalMethod = public method(v : TVertex);


TGraph = public class


public
method LinearTraversal(aMethod : TTraversalMethod);
end;

method TGraph.LinearTraversal(aMethod : TTraversalMethod);
begin
for each v in Vertices do //the type of v is inferred
aMethod(v);
end;

The actual code for the traversal looks pretty similar. There are a few Delphi Prism constructs. method instead of procedure, and for each in instead of for in. Also note the type inference in the LinearTraversal method.

It’s the calling code that things get interesting.


method TMyClass.ShowGraphAsText(aGraph : TGraph);
begin
var s: StringBuilder := new StringBuilder(‘’);
Graph.LinearTraversal(
method(v : TVertex);
begin
s.Append(v.Name);
end
);
MessageBox.Show(s.ToString);
end;

We now only have one method (well strictly speaking two), and more importantly we have our local helper variable.

And that was my aha moment. It’s not the actual fact that you can inline an anonymous method where you need it that makes them so powerful, it’s the capture of local variables of the outer method inside the anonymous method. When you look at it like that, you see them in a whole new light. Now I can go back to all those examples I’ve seen and understand them better.

WPF like effects in your Win32 forms

Are you still developing native applications? Would you like to do some cool tricks with your forms? How about making your windows fade in and out?

The Win32 API to the rescue! The function AnimateWindow can be used to blend in and out the form. To the FormShow event handler, add the following code :

AnimateWindow(Self.Handle, 1000, AW_ACTIVATE or AW_BLEND);

To reverse the effect, add the following code to the FormClose event :

AnimateWindow(Self.Handle, 1000, AW_HIDE or AW_BLEND);


You can also get the form to slide in, rather than blend, by changing the flags to AW_SLIDE or AW_HOR_POSITIVE to get the slide to come in from the left for example.



The same approach can be used in Delphi Prism, when using WinForms. While Delphi Win32 imports the AnimateWindow method for you, in windows.pas, in Delphi Prism you have to do it yourself using P/Invoke. (As you would with C# or VB.NET may I add). So in your WinForm, add the following code to the private declaration :



private
const AW_HIDE = $10000;
const AW_ACTIVATE = $20000;
const AW_HOR_POSITIVE = $1;
const AW_HOR_NEGATIVE = $2;
const AW_SLIDE = $40000;
const AW_BLEND = $80000;
[DllImport("user32.dll", CharSet := CharSet.Auto)]
class method AnimateWindow(hwand : IntPtr; dwTime : Integer; dwFlags : Integer) : Integer;external;


Remember to add System.Runtime.InteropServices to the uses clause of your form. Now, you can add the same code as before (it's all object pascal, so the same syntax), to the Load and FormClosing events of your form.



  method MainForm.MainForm_Load(sender: System.Object; e: System.EventArgs);
begin
AnimateWindow(Self.Handle, 1000, AW_ACTIVATE or AW_BLEND);
end;

method MainForm.MainForm_FormClosing(sender: System.Object; e: System.Windows.Forms.FormClosingEventArgs);
begin
AnimateWindow(Self.Handle, 1000, AW_HIDE or AW_BLEND);
end;

So there you have it, forms that fade in and out.

Pointers to Pointers

When you first learn about pointers, it takes a little while to get that aha moment. They're a bit like recursion and closures in that respect. Then, just when you think you've got it, get shown pointers to pointers. You understand the concept, but can't really figure out where they'd be useful. So you look at the examples, but you still can't see their use. The examples are just so contrived, that you're left thinking, I'm never really going to need to pointers to pointers.

Delphi does a pretty good job of hiding anything to do with pointers from you, and you can go for years without using a pointer if you really didn't want to. I resort to pointers quite often, but I can't really remember a time when I really needed a pointer to a pointer. That is until this weekend.

I was looking at the jclExprEval unit in the Jedi Code Library. Now the code as it stands make it very easy to add variables.

var
A : Double;
B : Double;
...
...
begin
ExprEval.AddVar('A', A);
ExprEval.AddVar('B', B);
CompiledExpression := ExprEval.Compile('A+B');
Result := CompiledExpression;

The variables A and B are internally stored as pointers to double. This is all well and good, and this works fine. Now what I wanted to do was to be able to compile an expression once, and repeat it multiple times over an array of values. Actually each variable in the formula is an array. I wanted to do something like


var
DataA : array of double;
DataB : array of double;
A : pDouble;
B : pDouble;
...
begin
A := @DataA;
B := @DataB;
ExprEval.AddVar('A', A);
ExprEval.AddVar('B', B);
CompiledExpression := ExprEval.Compile('A+B');
i := Length(Result);
while i>0 do
begin
Result[i] := CompiledExpression;
Inc(A);
Inc(B);
Dec(i);
end;

I thought initially I'd just override AddVar so it can take a pointer to a double, and store it directly. That was before I thought about it properly. When I did think about it, I realised it wouldn't work. Since the variable internally is stored as a pointer to a double it is basically a copy of A. at least initially it is.


Pointer to double

Incrementing the pointer A just gives you the following

Increment pointer

As soon as you see the picture the solution is obvious.

Pointer to a pointer

A pointer to a pointer! We can manipulate A anyway we like, and our internal copy still points to the right place. Whereas before to get to the value of our variable we'd de-reference the pointer once, now we have to be careful and do it twice. I had to write quite a few classes and methods (basically replicate the whole structure that handled pointers to handle pointers to pointers) to get this to work, but as I said before, the code is well written, and extending it to do what I want was really easy. So while pointers to pointers and even simple pointers are not essential (as I'm sure a load of C# developers will tell me) they do have a place in a Delphi programmers toolbox.

Breaking Existing Code

We finally decided last week to have a go and try and move one of our applications from Delphi 2006 to Delphi 2009. Most of our other applications had been moved to Delphi 2007, this one, due to unfortunate timing, remained with Delphi 2006. I say try, because we are wary of the changes, and if it’s too much upheaval, we just may decide it’s not worth it.

It’s taken us a while to decide on whether we should make the move or not because this application had been made fully unicode compatible using widestrings and TNT components. We don’t actually need Delphi 2009’s unicode support, although we realise the difference between widestrings and Unicodestrings. The fact we’d done that work actually worked against us in this case.

Now I’ve done many of these upgrades. I’ve gone from Delphi 1 to Delphi 2, 2 to 3 so on and so forth, so I’m in a position to compare the experience. So far it hasn’t been easy. We use quite a few third party components which are no longer actively maintained, so we’re not getting a Delphi 2009 version anytime soon. Luckily, we have the source (actually luck doesn’t come into it, we’d never use a component if we didn’t have source!). Now the convention for creating buffers has always been to use PChar. This obviously doesn’t work anymore, and while our code isn’t too bad in this respect, the third party components we use are riddled with PChar buffers, pointer arithmetic etc etc

Now, I got to thinking. How could Codegear have made my life easier? Well for starters, they shouldn’t have broken my existing code! If PChar was a pointer to a (single byte) character, then it should stay that way! If a string is an Ansistring, then it should have stayed that way. In fact I should have been able to recompile my code in Delphi 2009, and my application should have worked exactly the way it did in Delphi 2007 (I’d accept it if older code didn’t completely work first time, but Delphi 2007 code should more or less work the same) Unicode support is a great thing, and hats off to Codegear for implementing it in Delphi 2009, but I would have done it differently. I’d have left a string as an Ansistring, and created a new string for unicodestrings, PChar would’t have changed, and TEdit would still be, in essence a TAnsiEdit. They would then have created a parallel VCL, and appended say a W to the names (TEditW) for the unicode equivilents. So anyone who wants a unicode application needs to do a little work. Not too much, but hey, nothing comes for free. Those who don’t want it, and there must be a few out there who don’t really care, get a compiled application which behaves exactly as it did in Delphi 2007. They can upgrade to unicode, if they wish, at their own pace.

If Codegear had really wanted to be helpful, I guess they could have gone the extra mile and added some compiler directives. D2007 compatibility on or off. That way everybody is happy.

Codegear, and Borland before them, keep making the same mistake. They keep assuming that technology alone can create these magic buttons. Press them, and you get this wonderful transformation. That would be nice, but it just doesn’t work that way in the real world. They tried it with Kylix (just compile your existing Win32 code in Kylix, and you have a Linux application) and it didn’t work, they tried it with Delphi for .NET (just compile your existing Win32 code with Delphi 8, and you have a .NET application) and it didn’t work, and they’ve tried it again with Unicode support (just compile your existing non-unicode code with Delphi 2009, and you have full unicode support), and in my opinion it hasn’t worked either. Sure it works with a contrived example, but try it with any decent sized, real world application, and you are in trouble pretty quick.

I’m sure there’s many out there who have compiled their existing Delphi 2007 code in Delphi 2009, and with a little tweaking here and there have been able to get it to work. I just think it should be the developer’s decision when to introduce Unicode support. I guess it still is our decision, but currently ,if we decide that completely changing the way our code behaves is a step too far, our only option is to remain with Delphi 2007. And if that happens, Codegear are one step closer to losing a another customer.

What a bad ReallocMem can do to Midas

The TClientDataSet isn’t known for its speed. It becomes slower and slower if you add more and more records. But what is the reason for this performance hit? After some research (F12 is a nice key if you want to know which function either gets called very often or consumes a lot of time) I nailed it down to the memory manager that is used inside the Midas code. (BTW: Thank’s CodeGear for compiling MidasLib.dcu with C/C++ source line information what makes reading assembler code a lot easier).


By using the MidasLib.dcu instead of the external Midas.dll the FastMM memory manager is used but this doesn’t give any significant performance improvement. So you would think the memory manager can’t be the bottle neck. But wait, there is a function (I call it) MidasRealloc. And with FastMM you would think it calls System.ReallocMemory. But that isn’t the case. The function looks like this: (translated from assembler to Delphi)



function MidasRealloc(P: Pointer; OldSize, NewSize: LongWord): Pointer; stdcall;
begin
Result := AllocMem(NewSize); // => GetMem+FillChar
if (Result <> nil) and (P <> nil) then
begin
Move(P^, Result^, OldSize);
FreeMem(P);
end;
end;


As you can see the function never calls ReallocMemory. Instead it does it the hard way for every call. Allocate new memory, zero the new memory, copy the previous content and release the old memory block. On the first look the AllocMem could be replaced by GetMem with a FillChar that only zero-fills the “Gap := NewSize - OldSize” block and not the whole memory block. But at a second look you realize that this is nothing else than a really bad ReallocMemory implementation. FastMM’s ReallocMemory is very fast because it doesn’t need to realloc memory blocks and copy memory all the time. Instead it has some inteligence in it to reduce the memory block moving.


Let’s see what can be done against this bad implementation. Replacing MidasRealloc alone woudn’t work because the memory manager has also a malloc(), a calloc() and a free() function. But all in all the replacements that call into FastMM aren’t that hard to write, especially the MidasRealloc becomes less code. The main problem is to find these function in the process space in order to patch them. But I already have the knowledge to find them. And I’ve already have a unit that makes the Midas a lot faster.


Testapplication from QC 7102

[rename Vessels200.xml to Vessels.xml in the source code and put a "for 1 to 10 do" loop before the ClientDataSet1.AppendData"]


Delphi 2009’s MidasLib unit:

1. Call: 858ms

2. Call: 1966ms

3. Call: 3182ms

4. Call: 4414ms

5. Call: 5678ms


Delphi 2009’s MidasLib unit with my MidasSpeedFix.pas unit:

1. Call: 406ms

2. Call: 265ms

3. Call: 374ms

4. Call: 312ms

5. Call: 281ms

ANSI to Unicode: Stream.Write(S[1], Length(S))

Last weekend I have migrated Delphi 2007 code to Delphi 2009. The code uses Stream.Write to write strings to a stream. There are multiple ways of migrating such code.


Stream.Write(S[1], Length(S))



  1. Do a project-wide search for “.Write(”

  2. Read through the search results and identify the Write() calls with Strings.

    Things like Variable[1], PChar(, Pointer(, PAnsiChar( help you to identify the source lines.

  3. Find out the code’s intention to decide if you need an AnsiString, or if a UTF8 string would do it, or if you can use a UnicodeString because it is an internally used stream.

  4. Rewrite the code if necessary




The following code writes a string to an internal stream to save the control’s state. This allows us to write the UnicodeString without any conversion. The missing “* SizeOf(Char)” is the only required source code change.


ANSI:



procedure TJvCustomDBTreeView.DestroyWnd;
var
Node: TTreeNode;
temp: string;
strLength: Integer;
HasChildren: Byte;
begin
if Items.Count > 0 then
begin
// save master values into stream
FMastersStream := TMemoryStream.Create;
Node := Items.GetFirstNode;
while Assigned(Node) do
begin
// save MasterValue as string
temp := VarToStr(TJvDBTreeNode(Node).MasterValue);
strLength := length(temp);
FMastersStream.Write(strLength, SizeOf(strLength));
{*} FMastersStream.Write(temp[1], strLength);
HasChildren := Byte(Node.HasChildren);
FMastersStream.Write(HasChildren, SizeOf(HasChildren));
Node := Node.GetNext;
end;
end;
inherited DestroyWnd;
end;


UNICODE:



procedure TJvCustomDBTreeView.DestroyWnd;
var
Node: TTreeNode;
temp: string;
strLength: Integer;
HasChildren: Byte;
begin
if Items.Count > 0 then
begin
// save master values into stream
FMastersStream := TMemoryStream.Create;
Node := Items.GetFirstNode;
while Assigned(Node) do
begin
// save MasterValue as string
temp := VarToStr(TJvDBTreeNode(Node).MasterValue);
strLength := Length(temp);
FMastersStream.Write(strLength, SizeOf(strLength));
{*} FMastersStream.Write(PChar(temp)[0], strLength * SizeOf(Char)); // internally used stream + bugfix
HasChildren := Byte(Node.HasChildren);
FMastersStream.Write(HasChildren, SizeOf(HasChildren));
Node := Node.GetNext;
end;
end;
inherited DestroyWnd;
end;




The following code writes control names to a stream. For control names the UTF8 encoding can be used to accept Unicode control names. Declaring “ControlName” as UTF8String and calling UTF8Encode is all you have to do. If you need an AnsiString then you can declare “ControlName” as AnsiString and instead of calling UTF8Encode you must do a hard typecast to AnsiString.


ANSI:



procedure TJvDockTabPageControl.SaveToStream(Stream: TStream);
var
//...
{*}ControlName: string;
CurrentControl: TControl;
begin
//...
for I := 0 to ACount - 1 do
begin
if Pages[I].ControlCount > 0 then
begin
CurrentControl := Pages[I].Controls[0];
{*} ControlName := CurrentControl.Name;
NameLen := Length(ControlName);
Stream.Write(NameLen, SizeOf(NameLen));
if NameLen > 0 then
Stream.Write(Pointer(ControlName)^, NameLen);
//...
end;
end;
//...
end;


UNICODE:



procedure TJvDockTabPageControl.SaveToStream(Stream: TStream);
var
//...
{*}ControlName: UTF8String;
CurrentControl: TControl;
begin
//...
for I := 0 to ACount - 1 do
begin
if Pages[I].ControlCount > 0 then
begin
CurrentControl := Pages[I].Controls[0];
{*} ControlName := UTF8Encode(CurrentControl.Name);
NameLen := Length(ControlName);
Stream.Write(NameLen, SizeOf(NameLen));
if NameLen > 0 then
Stream.Write(ControlName[1], NameLen);
//...
end;
end;
//...
end;




Another possibility is to support ANSI and Unicode with one function by using the TEncoding class. If No Encoding is specified the default (ANSI with AciveCodePage) is used. This change requires a complete rewrite but gives you the more flexibility.


ANSI:



procedure TJvStringGrid.SaveToStream(Stream: TStream);
var
//...
{*}St: array [0..BufSize - 1] of Char;
{*}Stt: string;
begin
//...
for I := 0 to RowCount - 1 do
begin
for J := 0 to ColCount - 1 do
begin
//...
{*} Stt := Cells[J, I];
{*} for K := 1 to Length(Stt) do
{*} St[K - 1] := Stt[K];
{*} Stream.Write(St, Length(Cells[J, I]));
//...
end;
//...
end;
//...
end;


UNICODE:



procedure TJvStringGrid.SaveToStream(Stream: TStream; Encoding: TEncoding = nil);
var
//...
{*}Bytes: TBytes;
Len: Integer;
begin
if Encoding = nil then
Encoding := TEncoding.Default;
//...
for I := 0 to RowCount - 1 do
begin
for J := 0 to ColCount - 1 do
begin
//...
{*} Bytes := Encoding.GetBytes(Cells[J, I]);
{*} Len := Length(Bytes);
{*} if Len > 0 then
{*} Stream.Write(Bytes[0], Len);
//...
end;
//...
end;
//...
end;