[转载]现有 Delphi 项目迁移到 Tiburon 中的注意事项 (上)

本文参考自 RAD Studio 2009 联机帮助

随着 Embarcadero 8 月 25 号发布 RAD Studio 2009 (Tiburon) 以来(Tiburon 的 RTM 日期可能要延后到 9 - 10 月),随着 Tiburon 全面支持 Unicode,现有的 Delphi / C++ Builder 项目要迁移到 Unicode 下应该注意些什么也成为大家最为关心的问题。Tiburon 对 Unicode 的支持不仅仅是将原来 类型映射为 AnsiString 的 String 类型直接改成 WideString,而是对 AnsiString 结构作出修改,同时增加了 UnicodeString 类型来完美支持 Unicode。这意味着,要想平稳迁移到 Unicode 下,程序员不得不对现有代码作出一定的修改。

在 Tiburon 以前的版本中,AnsiString 和 WideString 除了 data size 不同外,在功能上是相同的。早先版本的 AnsiString 的结构如下:

Format of AnsiString Data Type  

Reference Count  
Length  
String Data (Byte sized)  
Null Term 
-8  
-4  
0  
Length  

而这个结构在 Tiburon 中已经发生变化,AnsiString 增加了两个新的 fields, 一个是 CodePage,一个是 ElemSize,这样做可以让新版的 AnsiString 和 UnicodeString 在结构上保持一致。

而 WideString 类型在早先的版本中用来保存双字节数据。其本质和 Windows BSTR 是一样的。在 Tiburon 中 WideString 仍然是为 COM 保持兼容的,也就是说它依然没有引用计数,相比较而言,UnicodeString 在性能和效率上将会是 COM 以外的程序首选的字符类型。

闪亮登场的 UnicodeString 类型

Tiburon 中,新的、默认的 string 就是 UnicodeString。这个类型既可以包含 ANSI 字符,也可以包含 Unicode 字符。下面是 UnicodeString 类型的结构:

Format of UnicodeString Data Type  

CodePage 
Element Size 
Reference Count  
Length  
String Data (element sized)  
Null Term 
-12  
-10  
-8  
-4  
0  
Length * elementsize  

UnicodeString 和 AnsiString 都是如上的结构,尽管 UnicodeString 包含是双字节数据,AnsiString 包含的是单字节的。

用 Object Pascal 语言来描述 UnicodeString 的结构,应该是这样:

type
 StrRec = record
   CodePage: Word;
   ElemSize: Word;
   refCount: Integer;
   Len: Integer;
   case Integer of
     1: array[0..0] of AnsiChar;
     2: array[0..0] of WideChar;
 end;

UnicodeString 增加了 code page 字段和 element size 来描述字符串内容,这使得 UnicodeString 和其它类型的字符串可以很好的相兼容,所以 AnsiString 和 UnicodeString 可以很方便的互相转换,唯一要注意的是,当把 UnicodeString 向下转型到 AnsiString 的时候,可能会丢失数据,因此强烈建议你不要这么做。UnicodeString 保存的是 UTF-16 字符。

在旧的环境下,可以使用编译标志 Unicode 来判断编译环境是否支持 UnicodeString,以便您可以在同一套代码中维护不同版本的字符支持环境。编译指令如下:

Delphi 使用:
    {$IFDEF Unicode}
C++ Builder 使用:
   
#ifdef _DELPHI_STRING_UNICODE

变化概要:
  • String 类型映射为 UnicodeString 而不是 AnsiString
  • Char 类型映射为 WideChar(2 bytes not 1 byte), 并且是 UTF-16 字符
  • PChar 类型映射为 PWideChar
  • C++ 中,System::String 映射到 UnicodeString 类
  • Delphi 中,AnsiString 映射为早先版本中默认的 string
未变化概要:
  • AnsiString
  • WideString
  • AnsiChar
  • PAnsiChar
  • 隐式转换仍然可用
  • 用户的活动页代码(The user's active code page)控制着模式(ANSI vs. Unicode),所以 AnsiString 仍然可以支持
由于这些变化,代码编写上也出现了一些值得注意的情况,特别是在你打算将旧有的项目迁移到 Tiburon 下时更是如此。下面就列出一些发生的变化情况以及编写代码时应该注意的注意事项。

下面的操作将不再依赖字符 Size:
  • 合并字符串
    • <string var> + <string var>
    • <string var> + <literal>
    • <literal> + <literal>
    • Concat(<string> , <string>)
  • 标准字符串函数
    • Length(<string>)返回字符元素的长度,此值可能和字符在字节长度上并不匹配。SizeOf 函数则返回数据的字节长度,这意味着 SizeOf 和 Length 的返回值可能是不同的
    • Copy(<string>, <start>, <length>)返回的 SubString 基于字符元素
    • Pos(<substr>,<string>)返回第一个字符元素的序号
  • 操作
    • <string> <comparison op> <string>
    • CompareStr()
    • CompareText()
    • ...
  • FillChar(<struct or memory>)
    • FillChar(Rect, SizeOf(Rect), #0)
    • FillChar(WndClassEx, SizeOf(TWndClassEx), #0). 使用的时候注意 WndClassEx.cbSize := SizeOf(TWndClassEx)
  • Windows API
    • API 默认使用 WideString (*W)形态的版本
    • PChar(<string>)具有相同的语义
范例:
GetModuleFileName:
function ModuleFileName(Handle: HMODULE): string;
var
  Buffer: array[0..MAX_PATH] of Char;
begin
  SetString(Result, Buffer, GetModuleFileName(Handle, Buffer, Length(Buffer)));
end;

GetWindowText:
function WindowCaption(Handle: HWND): string;
begin
  SetLength(Result, 1024);
  SetLength(Result, GetWindowText(Handle, PChar(Result), Length(Result)));
end;

字符串索引:
function StripHotKeys(const S: string): string;
var
  I, J: Integer;
  LastChar: Char;
begin
  SetLength(Result, Length(S));
  J := 0;
  LastChar := #0;
  for I := 1 to Length(S) do
  begin
    if (S[I] <> '&') or (LastChar = '&') then
    begin
      Inc(J);
      Result[J] := S[I];
    end;
    LastChar := S[I];
  end;
  SetLength(Result, J);
end;
(未完,待续)

原文地址:https://www.cnblogs.com/luckForever/p/7255320.html