Saving string or stringlist to unicode text file

TextAfter moving to recent Delphis (as 2009 or newer) saving to text files has changed as strings now are full unicode. So your old code writing to textfile also must change.

If you use TStringList to write its lines to text files, you most probably used:


var StrList : TStringList;

with StrList do
begin
 Add( “Msg” );
 SaveToFile(sFileName); //your filename
end;

This won’t work in recent Delphi, if you write unicode symbols. You need to provide Encoding for your file or else you will write only ANSI text file, so rebuild you need a TEncoding class:


var StrList : TStringList;

with StrList do
begin
 Add( “Msg” );
 SaveToFile(sFileName, TEncoding.Unicode); //your unicode filename
end;

Now, if you just want to write a single string to text file. Above function will work but you need to create a StringList first.

First you need to write a Unicode preambule to a text file and sadly convert your string to UTF8 string ( or widestring), but still you will  retain your unicode symbols. Here’s a function:


procedure StringtoFileUTF8(Filename, Line: String; Append : boolean);
var
fs: TFileStream;
preamble:TBytes;
outpututf8: RawByteString;
amode: Integer;
begin
if Append and FileExists(FileName)
then amode := fmOpenReadWrite
else amode := fmCreate;
fs := TFileStream.Create(filename, { mode } amode, fmShareDenyWrite);
{ sharing mode allows read during our writes }
try

{internal Char (UTF16) codepoint, to UTF8 encoding conversion:}
outpututf8 := Utf8Encode(line); // this converts UnicodeString to WideString, sadly.

if (amode = fmCreate) then
begin
preamble := TEncoding.UTF8.GetPreamble;
fs.WriteBuffer( PAnsiChar(preamble)^, Length(preamble));
end
else
begin
fs.Seek(fs.Size, 0); { go to the end, append }
end;

outpututf8 := outpututf8 + AnsiChar(#13) + AnsiChar(#10);
fs.WriteBuffer( PAnsiChar(outpututf8)^, Length(outpututf8) );
finally
fs.Free;
end;
end;

There is also another method if you have Delphi 2010 or newer using TStreamWriter class. This is taken from embarcadero help:


procedure TMainForm.btLoadClick(Sender: TObject);
var
 Reader: TStreamReader;
begin
 { Create a new stream writer directly. }
 Reader := TStreamReader.Create( 'local_file.txt',
 TEncoding.UTF8);

 { Read the title and then the actual text. }
 edtTitle.Text := Reader.ReadLine();
 mmText.Text := Reader.ReadToEnd();

 { Close and Free the writer. }
 Reader.Free();
end;

procedure TMainForm.btSaveClick(Sender: TObject);
var
 Writer: TStreamWriter;
begin
 { Create a new stream writer directly. }
 Writer := TStreamWriter.Create('local_file.txt',
 false, TEncoding.UTF8);

 { Store the title and then the text. }
 Writer.WriteLine(edtTitle.Text);
 Writer.Write(mmText.Text);

 { Close and Free the writer. }
 Writer.Free();
end;

Free e-books from Microsoft

Microsoft has just released 8 free technical e-books:

free_ebooks

Programming Windows Phone 7, by Charles Petzold

Moving to Microsoft Visual Studio 2010

Introducing Microsoft SQL Server 2008 R2

Understanding Microsoft Virtualization Solutions (Second Edition)

Own Your Future: Update Your Skills with Resources and Career Ideas from Microsoft

Introducing Windows Server 2008 R2

First Look Microsoft Office 2010

Deploying Windows 7, Essential Guidance

Free gifts for M$, wee! Nice.


How to open *.xps files

What is XPS File Extension

XPS is XML Paper Specification which is used in Windows Printing machine and doesn’t support non Microsotf platforms.

How to open XPS file.

If you have not modern M$ Office orther viewer, you can simply open and view xps files in Internet Explorer 8.0+.


Creating a Unique FileName

Text To Create a Unique filename for your working temporary or permanent file you can use a WinAPI function  GetTempFileName .

Here is my variant of making unique filename in specified folder:

function CreateUniqueFileName(sPath, sPrefix, sExtension : string) : string;
  var sFileName : array[0..MAX_PATH] of Char;
begin
  Result := '';
  repeat
    if GetTempFileName(PChar(sPath), PChar(sPrefix), 0, sFileName) <> 0
      then begin
         DeleteFile(sFileName);
         Result := ChangeFileExt(sFileName, sExtension)
      end
      else break; //error or failed
  until not FileExists(Result);
end;

sPath – your folder (you can windows temp folder GetTempPath(SizeOf(Buffer) - 1, Buffer); )
sPrefix – any prefix to attach to filename
sExtension – your extension of filename
if Function fails , empty string is returned.

But I don’t like this approach very much, because Windows creates a temporary file with tmp extension, that you have to delete later, if you don’t want additional files in system. Also deleting files on some OS might be slow.

Much better approach is by creating Unique filenames using GUID – global identifier, it is very little probability that generated GUIDs will be the same.

So here it is my variant of function:

function CreateUniqueGUIDFileName(sPath, sPrefix, sExtension : string) : string;
   var sFileName : string;
        Guid : TGUID;
begin
  Result := '';
  repeat
   SFileName := '';
   CreateGUID(Guid);
   SFileName := sPath + sPrefix + GUIDtoString(GUID);
   Result := ChangeFileExt(sFileName, sExtension)
  until not FileExists(Result);
end;

The variables are the same.


Delphi vs C#

Icon_Delphi Recently a very interesting discussion was going in LinkedIn forums regarding choosing Delphi programming language versus VB or C#. Here I will repost one comment because I agree on it 100%🙂.

Phil Caetano (Senior Programmer at Flairbase) wrote:

Why Delphi?
1) Ease of programming.
This is pascal, one of the easier languages to learn. Very old language too and was used as a teaching language. This makes it easy for anyone to learn. http://en.wikipedia.org/wiki/Pascal_(programming_language )
2) Component based Programming.
There is quite a large base of components available, free or paid that allows you concentrate on the "Core" of your application and not the little other details like how to connect a database.
3) No Dependency!!!
C# has the Framework that it depends on. An application compiled in Delphi has none by default. Even components used don’t create an external dependency. In C#, all the 3rd party components have to be included and some even have to be registered in the GAC (That on its own is a problem)
4) Easy Database Support.
Since the beginning Delphi has always had Database support. Many other components exist that expanded off that base. You can program using BDE (Please don’t), ADO, SQL, MSSQL, SQLite, MySQL, Interbase/Firebird just about any database (Except Compact SQL, very limited). And there is even Components that allow you design your entire application "Database independent" Which allows you to switch from MS SQL to Oracle with just a connection setting. (Provided the sql syntax is compatible)
5) Low Memory usage.
If you compare to C#, or VB. You’ll see a simple Hello World will require more memory than Delphi. This is usually not that important for Desktop software, but can be!
6) Small Foot Print.
Your compiled result is your application. No 300 megs download library, or QT, mingw, etc. It compiles into just a few megs.
7) Native SPEED.
Yes, we can debate speed vs C++ or .Net and what you define fast. But overall, it is mostly faster than .NET apps.
8) Believe it or not, Cross Platform!
Yes Free Pascal that is. Sure Delphi doesn’t do it anymore (Kylix), but the time you spend in learning Delphi is not a waste, since your knowledge can be used with Free Pascal and you can have a Linux, Mac and others.
9) Known Factor. (Not sure how to word that)
But in C# for example, you just NEVER EVER know when the Garbage collector will trigger or if a framework update will break your code/security, or as it happened with me, some other application installed and broke the .NET GAC, causing my application to no longer work.

Why not use Delphi? Versus C# (Since this is what MS Pushes)

1) No Garbage collector.
(Yes, this can be debated on its usefulness, but in the end its still a missing feature and useful)
2) No 64 Compiler!
THIS BLOWS ME MIND. Free Pascal has it, many of the other languages have it, but yet. Delphi is still sitting on 32. Most desktop application will not need 64 bit. But 64 has been around for quite some time now and yet no 64 compile.
3) Shrinking User base
SHhhhh don’t say it too loud, but sadly, C# is stealing programmers away. I’m not talking huge numbers, but all the fuss about C# and .NET makes decision makers think its the best thing since slice bread. Which leads to less updates in Components or new Components released. Seen companies drop Delphi and go .NET only components. Always buy the source!!
4) The Tossing game.
What is the tossing game? I’m referring to the Borland/Imprise tossing it to CodeGear, which now is tossed (bought) by Embarcadero. I’m sure they will do good stuff with it. But in the end, it just doesn’t look good.

Anyhow, I prefer Delphi, but its just a language in the end, the end user will most likely not know what you used.

————————-

Nice comment Phil. And I’m also waiting for 64bit.


Be careful with FormCloseQuery

help 64 Recently I had a very hard to find bug-problem with closing my application (made in Delphi).
It just refused to respond to Windows shutdown messages and prevented Windows to shutdown and restart..

I spent a lot of hours investigating this problem.
Initially the first part of the problem, because I was showing a dialog  for "Really close?" and preventing closing if some files are not saved, this was done in FormCloseQuery and it was stupid approach, because FormCloseQuery doesn’t know if windows is shutting down and thus preventing shutdown.

Then, I made a Message listeners for windows asking applications query for shutdown : WM_QueryEndSession and WM_EndSession:

// Shutdown messages

procedure WMEndSession(var Msg: TWMEndSession); message WM_ENDSESSION;

// Query to Shutdown

procedure WMQueryEndSession(var Msg: TMessage); message WM_QUERYENDSESSION;


The problem remained: the messages were received only second time. The first time when Windows was shutting down the application was still preventing shutdown, and only for the second Shutdown call, the messages were received and Application quit.

So something else was corrupting even the messages queue.

After some time, I accidentally came under another Form in same application, which also had FormCloseQuery, this time it was really needed because this Form was closing with fading effect and Query was preventing close until fader finished. So that was the second part of the problem.

Again I needed to listen for Shutdown messages in this Form.

So to conclude: you need to listen for Windows shut down Messages and Queries in every form that has FormCloseQuery or better yet avoid it, if you want to let windows shutdown normally.

Also to note: Delphi made applications (on Windows shutdown) exit instantly without freeing objects, so be careful and it is a good practice to listen to Shutdown procedure and to call your own Closing and Freeing procedure manually:

//Windows' Query for Shutdown

procedure TMainForm.WMQueryEndSession(var Msg: TMessage);

begin

  //Windows is about to shut down - Alow or not

  bForceClose := True;

  Msg.Result := 1; // 1 for Signal that it is OK to shut down

  inherited; // let the inherited message handler respond

end;

 

//Windows is shutting down

procedure TMainForm.WMEndSession(var Msg: TWMEndSession);

begin

  // shutdowning

  if Msg.EndSession = True then

  begin

    //Windows is shutting down -- Closing'

    bForceClose := True;

    //Be CAREFULLL - MIGTH BE DOUBLE OR NO FREEING AT ALL

    CleanUp;   // My Closing procedure

    FinalDestroy; // Destructor sometimes never called on shutdown !!!!!!

 

    inherited; // let the inherited message handler respond

  end

  else

    inherited;

    // Msg.Result:=0;  //Signal that we got the message - not needed

end;

bForceClose here is a global boolean variable, signaling that we should force our application closing, and if you still need FormCloseQuery  check for bForceClose there (of course you need to set it false on application start):

procedure TMainForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);

begin

  CanClose := True;

  if not bForceClose then begin

        //no close 

        CanClose := False;

        //Do what you need here;

  end

  else CanClose := TRUE; //Forced close

end;

And you need this done in every form with FormCloseQuery.


Saving and Loading strings in stream the Delphi 2009 way

Refresh Lately, I had a simple task to save and load some short strings in file.
The quickest and fastest way is to do it with streams (TFileStream or TMemoryStream).

Because in Delphi 2009 string type strings are Unicode so they are also double byte sized than in previous Delphi strings.
So you need to be very strict to write exact BYTES of the string, not characters, because character size is now 2 Bytes!

For Writing String to any stream use these Functions :


procedure WriteStreamInt(Stream : TStream; Num : integer);
begin
 Stream.WriteBuffer(Num, SizeOf(Integer));
end;

procedure WriteStreamStr(Stream : TStream; Str : string);
var
 StrLen : integer;
begin
 StrLen := Length(Str); //All Delphi versions compatible
 WriteStreamInt(Stream, StrLen);
 Stream.WriteBuffer(Pointer(Str)^, StrLen * SizeOf(Char)); //All Delphi versions compatible
end;

The reading of string shoud be also exact with character size in mind. Because you can read only half of string:


function ReadStreamInt(Stream : TStream) : integer;
begin
Stream.ReadBuffer(Result, SizeOf(Integer));
end;

function ReadStreamStr(Stream : TStream) : string;
var
StrLen : integer;
TempStr : string;
begin
TempStr := '';
StrLen := ReadStreamInt(Stream);
if StrLen > -1 then
begin
SetLength(TempStr, StrLen);
//Here you should also check the character size
//Reading Bytes!
Stream.ReadBuffer(Pointer(TempStr)^, StrLen * SizeOf(Char));
result := TempStr;
end
else Result := '';
end;

Then you can write functions for writing and loading strings for example:


function SaveToDFile( FileName: String; sDescr : string; ) : boolean;
var  MemStr: TMemoryStream;
begin
MemStr:= TMemoryStream.Create;
try
try
WriteStreamStr( MemStr, sDescr );
MemStr.SaveToFile(FileName);
result := True;
except
on E:EWriteError do result := False;
end;
finally
MemStr.Free;
end;
end;

function LoadFromDFile( FileName: String; var sDescr : string; ) : boolean;
var MemStr: TMemoryStream;
begin
MemStr:= TMemoryStream.Create;
try
try
MemStr.LoadFromFile(FileName);
sDescr := ReadStreamStr( MemStr );
result := True;
except
on E:EReadError do result := False;
end;
finally
MemStr.Free;
end;
end;

Hope it helps some.


How to install Microsoft TTS Anna engine on Windows XP

book open sound 128  Microsoft introduced new TTS voice called "Anna" on Vista OS. Sadly it is only available for Vista and no separate download option for Windows XP users, personally I still use Windows XP on many machines.😦

You can find more info about TTS (Text To Speech engines on Microsoft site). New voice "Anna" is more clear and more natural, than any other voice available on XP versi0ns.

Still, there is an option to use "Anna" voice on XP for FREE. You need to download and install Microsoft Street And Trips 2009 !
It is available for FREE (60 day trial version is download-able from Microsoft here ). Its huge, about 1,5 GB, so you need some place on your hard disk for download.

So download and install Streets 2009. With it also Microsoft nice "Anna" TTS engine is installed to pronounce (speak) street names.
You can enjoy this product for 60 days, or uninstall it the same day — "Anna" engine will not be uninstalled ! Cool.🙂
It is still left on system.
You can check its properties through Control Panel’s Speech category settings.

Enjoy!

PS. It is also possible to extract only TTS Anna setup files (About 32 MB). But still you should download Streets at first. Then after installation start, look for temp folder where temporary installation files were extracted. Most probably it will be your User’s "Documents and Settings/Local settings/Temp" Folder. Look for TTS.


TCoolTrayIcon component for Delphi 2009

view quick bar For those who are searching TCoolTrayIcon component written by Troels Jakobsen to support newest Delphi versions.

It’s a comprehensive component for adding icons to the traybar, allowing you to put a tray icon in your own programs. Can hide, show program button on Taskbar, show hide hint balloons and similar. The original component you can find on Troel’s website here: http://subsimple.com/delphi.asp

 

It’s freeware, so you can use it freely.

The problem is, it was updated very long ago, and supports Delphi versions until 6, though it should function ok till 2007 version.

As with Delphi 2009, where all string and char become full Unicode, version on Troel’s website isn’t compatible with Delphi 2009 anymore.

No problem. Sebastian Zierer already made some changes to support Unicode chars. You can find TCoolTrayIcon component for Delphi 2009 on his website : http://tib.s.songbeamer.eu/downloads/Cooltray.zip or you can download same copy here from my website: Download TCoolTrayIcon zip package

Update: 2008.11.12 fixes for Delphi 2009
Update: 2009.09.04 with Delphi 2010 package


Upgrade to Delphi 2009 or Not?

For those who consider whether upgrade or buy Delphi 2009 I suggest to read these pages:

Some user opinions:

http://www.codegear.com/products/delphi/win32/quotes/

Some more views:

http://blogs.codegear.com/ao/2008/09/17/38947

In my personal opinion Delphi 2009 is worth buying, even for Unicode alone. At last.