For pre-Unicode versions of Delphi, the unique way of having UTF-16 native
type is to use the WideString
type.
This type, under Windows, matched the BSTR managed
type, as used by OLE and COM components.
In Delphi, WideString
implementation calls directly the
corresponding Windows API, and do not use the main Delphi heap manager.
Even if since Vista, this API did have a huge speed-up, it is still in practice
much slower than the regular string
type. Problems is not about
UTF-16 encoding, but about the memory allocation, which is shared among
processes, using the Windows global heap, and is much slower than our beloved
FastMM4.
Newer versions of Delphi (since Delphi 2009) feature a refactored
string
= UnicodeString
type, which relies on
FastMM4 and not the Windows API, and is much faster than
WideString
.
Within our mORMot framework,
we by-passed this limitation by using our RawUTF8
type, which is
UTF-8 encoded, so as Unicode ready as the new UnicodeString
type,
and pretty fast.
In a recent internal project, we had to use a lot of
WideString
instances, to support UTF-16 encoding in Delphi
7/2007, involving a lot of text.
It sounded to be very slow, so we had to do something!

This is where our new SynFastWideString
unit comes in.
Purpose of this unit is to patch the system.pas
unit for older
versions of Delphi, so that WideString
memory allocation would use
FastMM4 instead of the slow BSTR Windows API.
It will speed up the WideString
process a lot, especially when a
lot of content is allocated, since FastMM4 is much more aggressive
than Windows' global heap and the BSTR slow API. It could be more than 50 times
faster, especially when releasing the used memory.
The WideString
implementation pattern does NOT feature Copy-On-Write, so is still
slower than the string UnicodeString
type as implemented since
Delphi 2009. This is the reason why this unit won't do anything on
Unicode versions of the compiler, since the new string type is to be
preferred there.
How to use
Just add the unit at the TOP of your .dpr
uses clause, just
after FastMM4 (if you use it, and you should!) i.e. before all other
units used by your program.
It should be initialized before any WideString
is
allocated.
Then the patch will be applied at runtime.
Nothing to recompile!
WARNING
USING THIS UNIT MAY BREAK COMPATIBILITY WITH OLE/COM
LIBRARIES !
You won't be able to retrieve and
release WideString
/BSTR variables from an OleDB / ADO
database provider, or any COM object.
Do not use this unit if you are calling such external call!
In practice, if you only send some BSTR content to the provider
(e.g. if you use our SynOleDB
unit without stored procedure call,
or if you use TWideStringField
for most SynDBDataSet
classes), it will work. As far as we tested.
You would have issues if you retrieve a BSTR from the COM
object, or expect the COM object to change the BSTR size, e.g.
with a var WideString
parameter or a COM method returning a
WideString
.
The following method should work, since it is using a
WideString
as input parameter:
type
_Catalog = interface(IDispatch)
function Create(const ConnectString: WideString): OleVariant; safecall;
But the following won't, since it returns a WideString
value,
which will fail to be released by our SynFastWideString unit, since it
is a true BSTR instance allocated by the COM library, and not an
AnsiString
allocated via FastMM4:
type
_Catalog = interface(IDispatch)
function GetObjectOwner(const ObjectName: WideString; ObjectType: OleVariant;
ObjectTypeId: OleVariant): WideString; safecall;
In this case, you could use the WideStringFree()
procedure, as
defined in the SynFastWideString unit, to release such an
instance.
This unit is for educational purpose only, and/or if you are 100% sure that
your code will stay self-contained, under Delphi 7 or Delphi 2007, and need use
of WideString
instead of string AnsiString
.
YOU HAVE BEEN WARNED - USE AT YOUR OWN RISK
!