Question

I have a structure like below that needs to be saved and loaded from disk.

 RSecStructure= packed record
   Name               : string[255];       {NEED UNICODE SUPPORT HERE}
   ScreenName         : string[255];
   OrigFileName       : string[255];                    
   Prim               : string[255];                                           
   ParentVersion      : integer;
   sTag1              : string[255];      
   sTag2              : string[255];
   sTag3              : string[255];
   sTag4              : string[255];
   DateAdd            : TDateTime;
   DateModify         : TDateTime;
  end;

Until now I have used something like this to save the structure:

function
var F: FILE;
    Hdr: RSecStructure;
begin
...
 BlockWrite (F, Hdr, SizeOf(Hdr));   
...
end

The above code worked under Delphi 7. Under D2009 I got a lot of warning messages when I make assignments between short and Unicode strings. Until now I managed to write Delphi code without having ANY compiler warnings or hints and I want to stay like that. So I need an elegant was to save strings (Unicode will be great but not critical) to disk without getting warnings.

Was it helpful?

Solution

Alternatively, you can declare storable short unicode string record and implement implicit 'to string' and 'from string' conversions.

program TestShortUnicodeString;

{$APPTYPE CONSOLE}

uses
  SysUtils;

type
  TShortUnicodeString = record
  private
    Data: array [0..255] of char; //WARNING - NOT initialized to an empty string
  public
    class operator Implicit(const sus: TShortUnicodeString): string; inline;
    class operator Implicit(const ws: string): TShortUnicodeString; inline;
  end;

class operator TShortUnicodeString.Implicit(const sus: TShortUnicodeString): string;
begin
  Result := StrPas(sus.Data);
end;

class operator TShortUnicodeString.Implicit(const ws: string): TShortUnicodeString;
begin
  // too long strings are silently truncated
  StrPLCopy(Result.Data, ws, Length(Result.Data)-1);
end;

type
  TTestRec = record
    ws1: TShortUnicodeString;
    ws2: TShortUnicodeString;
  end;

var
  f    : file;
  test1: TTestRec;
  test2: TTestRec;

begin
  test1.ws1 := '6*9 =';
  test1.ws2 := ' 42';
  AssignFile(f, 'test.dat');
  Rewrite(f, 1);
  BlockWrite(f, test1, SizeOf(test1));
  CloseFile(f);
  AssignFile(f, 'test.dat');
  Reset(f, 1);
  Assert(FileSize(f) = SizeOf(test2));
  BlockRead(f, test2, SizeOf(test2));
  CloseFile(f);
  Writeln(string(test2.ws1), string(test2.ws2));
  Readln;
end.

[The code above is released to public domain and carries no license obligations.]

OTHER TIPS

Those string fields are the same in Delphi 2009 as they were in all previous versions. ShortString is not a Unicode type.

So you should be able to continue using that record as-is.

You say it worked in Delphi 7. Does it not work in Delphi 2009? Describe the problem you're having.

Do you mean to say that you want a fixed-length Unicode equivalent to ShortString? There isn't one, so you can't have a record like that, have it hold string-like Unicode values, and save it directly to disk.

I don't think that's a major problem, though, since your disk format wouldn't be compatible with your current format anyway: your characters would be too big.

You can use an array of characters:

type
  TSecStructure = packed record
    Name               : array[0..255] of UnicodeChar;
    ScreenName         : array[0..255] of UnicodeChar;
    OrigFileName       : array[0..255] of UnicodeChar;
    Prim               : array[0..255] of UnicodeChar;
    ParentVersion      : integer;
    sTag1              : array[0..255] of UnicodeChar;
    sTag2              : array[0..255] of UnicodeChar;
    sTag3              : array[0..255] of UnicodeChar;
    sTag4              : array[0..255] of UnicodeChar;
    DateAdd            : TDateTime;
    DateModify         : TDateTime;
  end;

That's not going to be quite as convenient as real string types, but it will work for most purposes.

You can also use a normal UnicodeString type:

type
  TSecStructure = record
    Name               : UnicodeString;
    ScreenName         : UnicodeString;
    OrigFileName       : UnicodeString;
    Prim               : UnicodeString;
    ParentVersion      : integer;
    sTag1              : UnicodeString;
    sTag2              : UnicodeString;
    sTag3              : UnicodeString;
    sTag4              : UnicodeString;
    DateAdd            : TDateTime;
    DateModify         : TDateTime;
  end;

You can't save that directly to disk anymore, but you're also no longer limited to 255 characters. You'll have to store each string field separately. Make sure to store the string's length, too, or you won't know where one string ends and the next begins when it comes time to load your file later.

You can keep existing structure (string[255]), existing file format and even correctly read non-unicode data previously saved by using the following:

before writing data:

...
record.Name:= UTF8EncodeToShortString(Name);

after reading data:

...
Name:= UTF8ToString(record.Name);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top