接上文
依赖字符 Size 的代码结构:
在 Tiburon 中,下列列表中列出的这些函数和特性依赖字符 Size,并且已经包含了一个“轻便”的版本,迁移代码的时候只需要将列出的代码迁移到后面提供的轻便版本即可。
依赖字符 Size 的代码结构:
在 Tiburon 中,下列列表中列出的这些函数和特性依赖字符 Size,并且已经包含了一个“轻便”的版本,迁移代码的时候只需要将列出的代码迁移到后面提供的轻便版本即可。
- SizeOf(<Char array>) 替换为 Length(<Char array>)
范例:
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。
var
begin
end;
SizeOf 返回的是数组的字节数,而 GetWindowText 的 Counts 参数需要的是字符数,所以这里需要把 SizeOf 换成 Length。
- Move(<Char buffer>... CharCount) 替换为 Move(<Char buffer> ,,, CharCount * SizeOf(Char))
var
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)。
begin
end;
由于 Length 返回的是字符数,而 Move 的 Count 参数需要的是字节数,所以应该用 SizeOf 或者 Length(Buf1) * SizeOf(Char) 替换 Length(Buf1)。
- Stream 的 Read/Write 替换为 AnsiString, SizeOf(Char),或者使用 TEncoding 类
调用
Read/ReadBuffer 方法的范例:
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
begin
end;
上面的解决方案依赖于您存储在 Stream 中的字符串的编码格式,更好的读取和转换他们建议使用 TEncoding 类。
调用 Write/WriteBuffer 的范例:
var
begin
end;
上面的解决方案依赖于您要存储进 Stream 中的字符串的编码格式,建议使用 TEncoding 类来更好的对格式进行处理。
- FillChar(<Char
array>, <size>,
<AnsiChar>) 如果采用 #0
填充,<size> 替换为
<size> * 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;
var
begin
end;
Length 返回的是字符数,而 FillChar 的 Count 参数需要的是字节数,所以必须用 SizeOf 替换 Length,或者使用 Length * SizeOf(Char)。
另外,需要注意的是,Tiburon 中 Char 等于 2 个字节,FillChar 填充的时候确是按照 Bytes 来计算的,所以,下面的代码
var
begin
end;
并不是向目标中填充 $09,而是 $0909,要得到正确的数值,应该改写成下面这样:
var
begin
...
end;
- GetProcAddress(<module>,
<PAnsiChar>)
由于 GetProcAddres 没有对应的 *W (Unicode)
版本的 API,所以只能使用下面的代码来正确调用它:
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;
procedure CallLibraryProc(const LibraryName, ProcName: string);
var
begin
end;
- RegQueryValueEx 函数
由于 RegQueryValueEx 函数的
Len
指定的是字节数,而不是字符数,所以 Unicode 版本中它的大小是实际需要大小的 2 倍,所以这样的代码:
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;
Len := MAX_PATH;
if RegQueryValueEx(reg, PChar(Name), nil, nil, PByte(@Data[0]), @Len) = ERROR_SUCCESS
then
else
应该换成下面这样:
Len := MAX_PATH * SizeOf(Char);
if RegQueryValueEx(reg, PChar(Name), nil, nil, PByte(@Data[0]), @Len) = ERROR_SUCCES
then
else
- CreateProcessW 函数
在 Unicode 版本的 CreateProcess
函数中,其行为和 ANSI 的版本略有不同。Unicode 的 CreateProcessW 会改变参数 lpCommandLine 传入的数据,因此调用 CreateProcess /
CreateProcessW 的时候,不可以给 lpCommandLine 赋值常量,或者是一个变量指向的常量,否则函数会抛出 access
violations 的异常。下面是错误的代码:
// 传入了一个 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);
// 传入了一个 string 常量
CreateProcess(nil, 'foo.exe', nil, nil, False, 0,
// 传入了一个常量表达式
// 传入了一个引用计数为 -1 的字符串:
const
var
- LeadBytes 常量
早先的版本中 LeadBytes
常量包含了本地系统中所有可以作为双字节字符 LeadByte 的列表,常常有这样的代码:
if Str[I] in LeadBytes then
现在你需要将它改成调用 IsLeaderChar 函数
if IsLeadChar(Str[I]) then
if Str[I] in LeadBytes then
现在你需要将它改成调用 IsLeaderChar 函数
if IsLeadChar(Str[I]) then
- 使用 TMemoryStream 类
当您需要用 TMemoryStream
写入一个文本文件的时候,最好在写入任何字符数据进去之前先写入一个 Byte Order Mark (BOM):
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));
原来写入字符串的代码
未完,待续...var
begin
而任何写入的字符需要被转换成 UTF-8 编码:
var
begin