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
變化概要:
下麵的操作將不再依賴字元 Size:
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;
接上文
依賴字元 Size 的代碼結構:
在 Tiburon 中,下列列表中列出的這些函數和特性依賴字元 Size,並且已經包含了一個“輕便”的版本,遷移代碼的時候只需要將列出的代碼遷移到後面提供的輕便版本即可。
var
Count: Integer;
Buffer: array[0..MAX_PATH - 1] of Char;
begin
// 現有代碼 - 當 string = UnicodeString 的時候這段代碼是錯的
Count := SizeOf(Buffer);
GetWindowText(Handle, Buffer, Count);
// 正確的應該是下面這樣
Count := Length(Buffer); // <<-- Count 應該是 Chars 而不是 Bytes
GetWindowText(Handle, Buffer, Count);
end;
SizeOf 返回的是陣列的位元組數,而 GetWindowText 的 Counts 參數需要的是字元數,所以這裏需要把 SizeOf 換成 Length。
Count: Integer;
Buf1, Buf2: array[0..255] of Char;
begin
// 現有代碼 - 當 string = UnicodeString (char = 2 bytes) 時,下面的代碼是錯誤的
Count := Length(Buf1);
Move(Buf1, Buf2, Count);
// 正確的寫法應該是
Count := SizeOf(Buf1); // <<-- Specify buffer size in bytes
Count := Length(Buf1) * SizeOf(Char); // <<-- Specify buffer size in bytes
Move(Buf1, Buf2, Count);
end;
由於 Length 返回的是字元數,而 Move 的 Count 參數需要的是位元組數,所以應該用 SizeOf 或者 Length(Buf1) * SizeOf(Char) 替換 Length(Buf1)。
var
S: string;
L: Integer;
Stream: TStream;
Temp: AnsiString;
begin
// 現有代碼- 當 string = UnicodeString 時它是不正確的
Stream.Read(L, SizeOf(Integer));
SetLength(S, L);
Stream.Read(Pointer(S)^, L);
// 正確的 Unicode 寫法如下
Stream.Read(L, SizeOf(Integer));
SetLength(S, L);
Stream.Read(Pointer(S)^, L * SizeOf(Char)); // <<-- Specify buffer size in bytes
//正確的 Ansi 寫法如下
Stream.Read(L, SizeOf(Integer));
SetLength(Temp, L); // <<-- 使用臨時的變數 AnsiString
Stream.Read(Pointer(Temp)^, L * SizeOf(AnsiChar)); // <<-- Specify buffer size in bytes
S := Temp; // <<-- 放寬 string 到 Unicode
end;
上面的解決方案依賴於您存儲在 Stream 中的字串的編碼格式,更好的讀取和轉換他們建議使用 TEncoding 類。
調用 Write/WriteBuffer 的範例:
var
S: string;
Stream: TStream;
Temp: AnsiString;
begin
// 現有代碼 - 當 string = UnicodeString 時它是錯的
Stream.Write(Pointer(S)^, Length(S));
// 正確的讀取 Unicode 的代碼
Stream.Write(Pointer(S)^, Length(S) * SizeOf(Char)); // <<-- Specify buffer size in bytes
// 正確的讀取 Ansi 的代碼
Temp := S; // <<-- Use temporary AnsiString
Stream.Write(Pointer(Temp)^, Length(Temp) * SizeOf(AnsiChar));// <<-- Specify buffer size in bytes
end;
上面的解決方案依賴於您要存儲進 Stream 中的字串的編碼格式,建議使用 TEncoding 類來更好的對格式進行處理。
var
Count: Integer;
Buffer: array[0..255] of Char;
begin
// 現有代碼 - 當 string = UnicodeString ( char = 2 位元組) 時,這段代碼是錯的
Count := Length(Buffer);
FillChar(Buffer, Count, 0);
// 正確的代碼應該寫作下面這樣
Count := SizeOf(Buffer); // <<-- Specify buffer size in bytes
Count := Length(Buffer) * SizeOf(Char); // <<-- Specify buffer size in bytes
FillChar(Buffer, Count, 0);
end;
Length 返回的是字元數,而 FillChar 的 Count 參數需要的是位元組數,所以必須用 SizeOf 替換 Length,或者使用 Length * SizeOf(Char)。
另外,需要注意的是,Tiburon 中 Char 等於 2 個位元組,FillChar 填充的時候確是按照 Bytes 來計算的,所以,下面的代碼
var
Buf: array[0..32] of Char;
begin
FillChar(Buf, Length(Buf), #9);
end;
並不是向目標中填充 $09,而是 $0909,要得到正確的數值,應該改寫成下面這樣:
var
Buf: array[0..32] of Char;
begin
StrPCopy(Buf, StringOfChar(#9, Length(Buf)));
...
end;
procedure CallLibraryProc(const LibraryName, ProcName: string);
var
Handle: THandle;
RegisterProc: function: HResult stdcall;
begin
Handle := LoadOleControlLibrary(LibraryName, True);
@RegisterProc := GetProcAddress(Handle, PAnsiChar(AnsiString(ProcName)));
end;
Len := MAX_PATH;
if RegQueryValueEx(reg, PChar(Name), nil, nil, PByte(@Data[0]), @Len) = ERROR_SUCCESS
then
SetString(Result, Data, Len - 1) // Len includes #0
else
RaiseLastOSError;
應該換成下面這樣:
Len := MAX_PATH * SizeOf(Char);
if RegQueryValueEx(reg, PChar(Name), nil, nil, PByte(@Data[0]), @Len) = ERROR_SUCCES
then
SetString(Result, Data, Len div SizeOf(Char) - 1) // Len includes #0, Len contains the number of bytes
else
RaiseLastOSError;
// 傳入了一個 string 常量
CreateProcess(nil, 'foo.exe', nil, nil, False, 0,
nil, nil, StartupInfo, ProcessInfo);
// 傳入了一個常量運算式
const
cMyExe = 'foo.exe'
CreateProcess(nil, cMyExe, nil, nil, False, 0,
nil, nil, StartupInfo, ProcessInfo);
// 傳入了一個引用計數為 -1 的字串:
const
cMyExe = 'foo.exe'
var
sMyExe: string;
sMyExe := cMyExe;
CreateProcess(nil, PChar(sMyExe), nil, nil, False, 0, nil, nil, StartupInfo, ProcessInfo);
if Str[I] in LeadBytes then
現在你需要將它改成調用 IsLeaderChar 函數
if IsLeadChar(Str[I]) then
var
Bom: TBytes;
begin
...
Bom := TEncoding.UTF8.GetPreamble;
Write(Bom[0], Length(Bom));
而任何寫入的字元需要被轉換成 UTF-8 編碼:
var
Temp: Utf8String;
begin
...
Temp := Utf8Encode(Str); // Str 是要寫入檔的字元
Write(Pointer(Temp)^, Length(Temp));
//Write(Pointer(Str)^, Length(Str)); 原來寫入字串的代碼
接上文
procedure TWideCharStrList.AddString(const S: string);
var
Size, D: Integer;
begin
Size := SizeOf(S);
D := (Size + 1) * SizeOf(WideChar);
FList[FUsed] := AllocMem(D);
MultiByteToWideChar(0, 0, PChar(S), Size, FList[FUsed], D);
Inc(FUsed);
end;
轉換到 Unicode 下可以寫作這樣(同時支援 Unicode 和 ANSI 字元):
procedure TWideCharStrList.AddString(const S: string);
{$IFNDEF UNICODE}
var
L, D: Integer;
{$ENDIF}
begin
{$IFDEF UNICODE}
FList[FUsed] := StrNew(PWideChar(S));
{$ELSE}
L := Length(S);
D := (L + 1) * SizeOf(WideChar);
FList[FUsed] := AllocMem(D);
MultiByteToWideChar(0, 0, PAnsiChar(S), L, FList[FUsed], D);
{$ENDIF}
Inc(FUsed);
end;
AppendStr(String1, String2);
應該換成:
String1 := String1 + String2;
您也可以使用新的 TStringBuilder 類來替換。
type
TThreadNameInfo = record
FType: LongWord; // must be 0x1000
FName: PChar; // pointer to name (in user address space)
FThreadID: LongWord; // thread ID (-1 indicates caller thread)
FFlags: LongWord; // reserved for future use, must be zero
end;
在調試器中,Named Thread 的處理器期待 FName 成員是 ANSI 字元,不是 Unicode,所以上面的聲明必須改成下面這樣:
type
TThreadNameInfo = record
FType: LongWord; // must be 0x1000
FName: PAnsiChar; // pointer to name (in user address space)
FThreadID: LongWord; // thread ID (-1 indicates caller thread)
FFlags: LongWord; // reserved for future use, must be zero
end;
在新版本中上述聲明已經修改,提示這段代碼是需要您注意早先版本中您手工創建並聲明的代碼需要您自己修改。
如果您需要在 Named Thread 中使用 Unicode 字元,您必須將字串格式化成 UTF-8 編碼,調試器可以完全支援改編碼。例如:
ThreadNameInfo.FName := UTF8String('UnicodeThread_фис');
注意:C++ Builder 裏面一直使用的是正確的代碼,所以上述問題在 C++ Builder 中並不存在。
下面的例子是一個將某類型指標轉換成 PChar 後的指標運算:
function TCustomVirtualStringTree.InternalData(Node: PVirtualNode): Pointer;
begin
if (Node = FRoot) or (Node = nil) then
Result := nil
else
Result := PChar(Node) + FInternalDataOffset;
end;
您應該將其修改成 PByte 而不是 PChar:
function TCustomVirtualStringTree.InternalData(Node: PVirtualNode): Pointer;
begin
if (Node = FRoot) or (Node = nil) then
Result := nil
else
Result := PByte(Node) + FInternalDataOffset;
end;
在上面的例子中,Node 真實的資料不是 PChar 的資料。將其強制轉換成 PChar 的操作在早先的版本中是正常的,因為早先版本中 SizeOf(Char) == Sizeof(Byte)。但是現在不同了,所以這樣的代碼必須從 PChar 改換成 PByte。如果不做這樣的更改,返回的 Pointer 將指向錯誤的資料。
procedure RegisterPropertiesInCategory(const CategoryName: string;
const Filters: array of const); overload;
var
I: Integer;
begin
if Assigned(RegisterPropertyInCategoryProc) then
for I := Low(Filters) to High(Filters) do
with Filters[I] do
case vType of
vtPointer:
RegisterPropertyInCategoryProc(CategoryName, nil,
PTypeInfo(vPointer), );
vtClass:
RegisterPropertyInCategoryProc(CategoryName, vClass, nil, );
vtAnsiString:
RegisterPropertyInCategoryProc(CategoryName, nil, nil,
string(vAnsiString));
vtUnicodeString:
RegisterPropertyInCategoryProc(CategoryName, nil, nil,
string(vUnicodeString));
else
raise Exception.CreateResFmt(@sInvalidFilter, [I, vType]);
end;
end;
帶字元的集合類型
您可能需要修改下列類型:
您需要檢查下列可能引起錯誤的結構:
BOM 必須添加到檔中以便判斷檔的編碼方式。
from http://www.cnpack.org/showdetail.php?id=598&lang=zh-cn
用 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 仍然可以支援
下麵的操作將不再依賴字元 Size:
- 合併字串
-
- +
- +
- +
- Concat( , )
- 標準字串函數
-
- Length()返回字元元素的長度,此值可能和字元在位元組長度上並不匹配。SizeOf 函數則返回資料的位元組長度,這意味著 SizeOf 和 Length 的返回值可能是不同的
- Copy(, , )返回的 SubString 基於字元元素
- Pos(,)返回第一個字元元素的序號
- 操作
-
- CompareStr()
- CompareText()
- ...
- FillChar()
-
- FillChar(Rect, SizeOf(Rect), #0)
- FillChar(WndClassEx, SizeOf(TWndClassEx), #0). 使用的時候注意 WndClassEx.cbSize := SizeOf(TWndClassEx)
- Windows API
-
- API 默認使用 WideString (*W)形態的版本
- PChar()具有相同的語義
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;
接上文
依賴字元 Size 的代碼結構:
在 Tiburon 中,下列列表中列出的這些函數和特性依賴字元 Size,並且已經包含了一個“輕便”的版本,遷移代碼的時候只需要將列出的代碼遷移到後面提供的輕便版本即可。
- SizeOf() 替換為 Length()
var
Count: Integer;
Buffer: array[0..MAX_PATH - 1] of Char;
begin
// 現有代碼 - 當 string = UnicodeString 的時候這段代碼是錯的
Count := SizeOf(Buffer);
GetWindowText(Handle, Buffer, Count);
// 正確的應該是下面這樣
Count := Length(Buffer); // <<-- Count 應該是 Chars 而不是 Bytes
GetWindowText(Handle, Buffer, Count);
end;
SizeOf 返回的是陣列的位元組數,而 GetWindowText 的 Counts 參數需要的是字元數,所以這裏需要把 SizeOf 換成 Length。
- Move(... CharCount) 替換為 Move( ,,, CharCount * SizeOf(Char))
Count: Integer;
Buf1, Buf2: array[0..255] of Char;
begin
// 現有代碼 - 當 string = UnicodeString (char = 2 bytes) 時,下面的代碼是錯誤的
Count := Length(Buf1);
Move(Buf1, Buf2, Count);
// 正確的寫法應該是
Count := SizeOf(Buf1); // <<-- Specify buffer size in bytes
Count := Length(Buf1) * SizeOf(Char); // <<-- Specify buffer size in bytes
Move(Buf1, Buf2, Count);
end;
由於 Length 返回的是字元數,而 Move 的 Count 參數需要的是位元組數,所以應該用 SizeOf 或者 Length(Buf1) * SizeOf(Char) 替換 Length(Buf1)。
- Stream 的 Read/Write 替換為 AnsiString, SizeOf(Char),或者使用 TEncoding 類
var
S: string;
L: Integer;
Stream: TStream;
Temp: AnsiString;
begin
// 現有代碼- 當 string = UnicodeString 時它是不正確的
Stream.Read(L, SizeOf(Integer));
SetLength(S, L);
Stream.Read(Pointer(S)^, L);
// 正確的 Unicode 寫法如下
Stream.Read(L, SizeOf(Integer));
SetLength(S, L);
Stream.Read(Pointer(S)^, L * SizeOf(Char)); // <<-- Specify buffer size in bytes
//正確的 Ansi 寫法如下
Stream.Read(L, SizeOf(Integer));
SetLength(Temp, L); // <<-- 使用臨時的變數 AnsiString
Stream.Read(Pointer(Temp)^, L * SizeOf(AnsiChar)); // <<-- Specify buffer size in bytes
S := Temp; // <<-- 放寬 string 到 Unicode
end;
上面的解決方案依賴於您存儲在 Stream 中的字串的編碼格式,更好的讀取和轉換他們建議使用 TEncoding 類。
調用 Write/WriteBuffer 的範例:
var
S: string;
Stream: TStream;
Temp: AnsiString;
begin
// 現有代碼 - 當 string = UnicodeString 時它是錯的
Stream.Write(Pointer(S)^, Length(S));
// 正確的讀取 Unicode 的代碼
Stream.Write(Pointer(S)^, Length(S) * SizeOf(Char)); // <<-- Specify buffer size in bytes
// 正確的讀取 Ansi 的代碼
Temp := S; // <<-- Use temporary AnsiString
Stream.Write(Pointer(Temp)^, Length(Temp) * SizeOf(AnsiChar));// <<-- Specify buffer size in bytes
end;
上面的解決方案依賴於您要存儲進 Stream 中的字串的編碼格式,建議使用 TEncoding 類來更好的對格式進行處理。
- FillChar(, , ) 如果採用 #0 填充, 替換為 * SizeOf(Char);如果填充其他字元,替換為 StringOfChar 函數
var
Count: Integer;
Buffer: array[0..255] of Char;
begin
// 現有代碼 - 當 string = UnicodeString ( char = 2 位元組) 時,這段代碼是錯的
Count := Length(Buffer);
FillChar(Buffer, Count, 0);
// 正確的代碼應該寫作下面這樣
Count := SizeOf(Buffer); // <<-- Specify buffer size in bytes
Count := Length(Buffer) * SizeOf(Char); // <<-- Specify buffer size in bytes
FillChar(Buffer, Count, 0);
end;
Length 返回的是字元數,而 FillChar 的 Count 參數需要的是位元組數,所以必須用 SizeOf 替換 Length,或者使用 Length * SizeOf(Char)。
另外,需要注意的是,Tiburon 中 Char 等於 2 個位元組,FillChar 填充的時候確是按照 Bytes 來計算的,所以,下面的代碼
var
Buf: array[0..32] of Char;
begin
FillChar(Buf, Length(Buf), #9);
end;
並不是向目標中填充 $09,而是 $0909,要得到正確的數值,應該改寫成下面這樣:
var
Buf: array[0..32] of Char;
begin
StrPCopy(Buf, StringOfChar(#9, Length(Buf)));
...
end;
- GetProcAddress(, )
procedure CallLibraryProc(const LibraryName, ProcName: string);
var
Handle: THandle;
RegisterProc: function: HResult stdcall;
begin
Handle := LoadOleControlLibrary(LibraryName, True);
@RegisterProc := GetProcAddress(Handle, PAnsiChar(AnsiString(ProcName)));
end;
- RegQueryValueEx 函數
Len := MAX_PATH;
if RegQueryValueEx(reg, PChar(Name), nil, nil, PByte(@Data[0]), @Len) = ERROR_SUCCESS
then
SetString(Result, Data, Len - 1) // Len includes #0
else
RaiseLastOSError;
應該換成下面這樣:
Len := MAX_PATH * SizeOf(Char);
if RegQueryValueEx(reg, PChar(Name), nil, nil, PByte(@Data[0]), @Len) = ERROR_SUCCES
then
SetString(Result, Data, Len div SizeOf(Char) - 1) // Len includes #0, Len contains the number of bytes
else
RaiseLastOSError;
- CreateProcessW 函數
// 傳入了一個 string 常量
CreateProcess(nil, 'foo.exe', nil, nil, False, 0,
nil, nil, StartupInfo, ProcessInfo);
// 傳入了一個常量運算式
const
cMyExe = 'foo.exe'
CreateProcess(nil, cMyExe, nil, nil, False, 0,
nil, nil, StartupInfo, ProcessInfo);
// 傳入了一個引用計數為 -1 的字串:
const
cMyExe = 'foo.exe'
var
sMyExe: string;
sMyExe := cMyExe;
CreateProcess(nil, PChar(sMyExe), nil, nil, False, 0, nil, nil, StartupInfo, ProcessInfo);
- LeadBytes 常量
if Str[I] in LeadBytes then
現在你需要將它改成調用 IsLeaderChar 函數
if IsLeadChar(Str[I]) then
- 使用 TMemoryStream 類
var
Bom: TBytes;
begin
...
Bom := TEncoding.UTF8.GetPreamble;
Write(Bom[0], Length(Bom));
而任何寫入的字元需要被轉換成 UTF-8 編碼:
var
Temp: Utf8String;
begin
...
Temp := Utf8Encode(Str); // Str 是要寫入檔的字元
Write(Pointer(Temp)^, Length(Temp));
//Write(Pointer(Str)^, Length(Str)); 原來寫入字串的代碼
接上文
- MultiByteToWideChar 函數
procedure TWideCharStrList.AddString(const S: string);
var
Size, D: Integer;
begin
Size := SizeOf(S);
D := (Size + 1) * SizeOf(WideChar);
FList[FUsed] := AllocMem(D);
MultiByteToWideChar(0, 0, PChar(S), Size, FList[FUsed], D);
Inc(FUsed);
end;
轉換到 Unicode 下可以寫作這樣(同時支援 Unicode 和 ANSI 字元):
procedure TWideCharStrList.AddString(const S: string);
{$IFNDEF UNICODE}
var
L, D: Integer;
{$ENDIF}
begin
{$IFDEF UNICODE}
FList[FUsed] := StrNew(PWideChar(S));
{$ELSE}
L := Length(S);
D := (L + 1) * SizeOf(WideChar);
FList[FUsed] := AllocMem(D);
MultiByteToWideChar(0, 0, PAnsiChar(S), L, FList[FUsed], D);
{$ENDIF}
Inc(FUsed);
end;
- SysUtils.AppendStr 函數
AppendStr(String1, String2);
應該換成:
String1 := String1 + String2;
您也可以使用新的 TStringBuilder 類來替換。
- 使用 Named Threads
type
TThreadNameInfo = record
FType: LongWord; // must be 0x1000
FName: PChar; // pointer to name (in user address space)
FThreadID: LongWord; // thread ID (-1 indicates caller thread)
FFlags: LongWord; // reserved for future use, must be zero
end;
在調試器中,Named Thread 的處理器期待 FName 成員是 ANSI 字元,不是 Unicode,所以上面的聲明必須改成下面這樣:
type
TThreadNameInfo = record
FType: LongWord; // must be 0x1000
FName: PAnsiChar; // pointer to name (in user address space)
FThreadID: LongWord; // thread ID (-1 indicates caller thread)
FFlags: LongWord; // reserved for future use, must be zero
end;
在新版本中上述聲明已經修改,提示這段代碼是需要您注意早先版本中您手工創建並聲明的代碼需要您自己修改。
如果您需要在 Named Thread 中使用 Unicode 字元,您必須將字串格式化成 UTF-8 編碼,調試器可以完全支援改編碼。例如:
ThreadNameInfo.FName := UTF8String('UnicodeThread_фис');
注意:C++ Builder 裏面一直使用的是正確的代碼,所以上述問題在 C++ Builder 中並不存在。
- 使用 PChar 轉換的指針運算
下面的例子是一個將某類型指標轉換成 PChar 後的指標運算:
function TCustomVirtualStringTree.InternalData(Node: PVirtualNode): Pointer;
begin
if (Node = FRoot) or (Node = nil) then
Result := nil
else
Result := PChar(Node) + FInternalDataOffset;
end;
您應該將其修改成 PByte 而不是 PChar:
function TCustomVirtualStringTree.InternalData(Node: PVirtualNode): Pointer;
begin
if (Node = FRoot) or (Node = nil) then
Result := nil
else
Result := PByte(Node) + FInternalDataOffset;
end;
在上面的例子中,Node 真實的資料不是 PChar 的資料。將其強制轉換成 PChar 的操作在早先的版本中是正常的,因為早先版本中 SizeOf(Char) == Sizeof(Byte)。但是現在不同了,所以這樣的代碼必須從 PChar 改換成 PByte。如果不做這樣的更改,返回的 Pointer 將指向錯誤的資料。
- 變體開放陣列(Variant Open Array)參數
procedure RegisterPropertiesInCategory(const CategoryName: string;
const Filters: array of const); overload;
var
I: Integer;
begin
if Assigned(RegisterPropertyInCategoryProc) then
for I := Low(Filters) to High(Filters) do
with Filters[I] do
case vType of
vtPointer:
RegisterPropertyInCategoryProc(CategoryName, nil,
PTypeInfo(vPointer), );
vtClass:
RegisterPropertyInCategoryProc(CategoryName, vClass, nil, );
vtAnsiString:
RegisterPropertyInCategoryProc(CategoryName, nil, nil,
string(vAnsiString));
vtUnicodeString:
RegisterPropertyInCategoryProc(CategoryName, nil, nil,
string(vUnicodeString));
else
raise Exception.CreateResFmt(@sInvalidFilter, [I, vType]);
end;
end;
- 其他需要注意的代碼:
-
- AllocMem(
- AnsiChar
- of AnsiChar
- AnsiString
- of Char
- Copy(
- GetMem(
- Length(
- PAnsiChar(
- Pointer(
- Seek(
- ShortString
- string[
帶字元的集合類型
您可能需要修改下列類型:
- in AnsiChar> 這樣的代碼生成的程式是正確的(>#255 的字元不會包含在集合內)。編譯器會提出 "WideChar reduced in set operations" 的警告,基於您代碼的需要,您可以關閉這個警告,或者使用 CharInSet 函數替代。
- in LeadBytes 全局的 LeadBytes 變數包含的是本地 MBCS Ansi 字元的集合。UTF-16 格式也有 LeadChar 的概念((#$D800 - #$DBFF 是高 surrogate, #$DC00 - #$DFFF 是低 surrogate)。因此建議使用 overload 函數 IsLeadChar 來判斷,該函數的 ANSI 版本檢測 LeadBytes,WideChar 版本檢測 high/low surrogate。
- 字元分類 使用靜態類 TCharacter。Character 單元中提供了一些函數對字元分類:IsDigit, IsLetter, IsLetterOrDigit, IsSymbol, IsWhiteSpace, IsSurrogatePair,等等。
您需要檢查下列可能引起錯誤的結構:
- 模糊的類型轉換
-
- AnsiString(Pointer(foo))
- 檢查正確性:代碼是什麼意圖?
- 可疑的類型轉換引發的警告
-
- PChar()
- PAnsiChar()
- 直接建立、操作、訪問 string 的內部結構。例如 AnsiString 的內部結構已經發生變化,所以這樣的操作是危險的。您應該使用 StringRefCount, StringCodePage, StringElementSize 等方法來獲得額外資訊。
- TStrings: 內部存儲的是 UnicodeStrings。
- TWideString:(可能被廢棄)沒有更改,內部使用 WideString (BSTR)
- TStringStream
-
- 被重寫成內部存儲 ANSI 字元
- 字元編碼可以被重載
- 考慮使用 TStringBuilder 替代 TStringStream 來逐步構建字串
- TEncoding
-
- Default 屬性是用戶活動頁碼(users’ active code page)
- 支持 UTF-8
- 支持 UTF-16, big 和 little endian
- 支持 Byte Order Mark (BOM)
- 您可以繼承子類實現特殊的編碼
BOM 必須添加到檔中以便判斷檔的編碼方式。
- UTF-8 使用 EF BB EF
- UTF-16 Little Endian 使用 FF FE
- UTF-16 Big Endian 使用 FE FF
from http://www.cnpack.org/showdetail.php?id=598&lang=zh-cn