迁移到 Delphi XE7 后 StrAlloc 不工作
StrAlloc not working after migrating to Delphi XE7
我正在开发最近从 Delphi 2007 升级到 XE7 的应用程序。有一种特殊情况,TMemoryStream 到 PChar 的转换失败。这是代码:
procedure TCReport.CopyToClipboard;
var
CTextStream: TMemoryStream;
PValue: PChar;
begin
CTextStream := TMemoryStream.Create;
//Assume that this code is saving a report column to CTextStream
//Verified that the value in CTextStream is correct
Self.SaveToTextStream(CTextStream);
//The value stored in PValue below is corrupt
PValue := StrAlloc(CTextStream.Size + 1);
CTextStream.Read(PValue^, CTextStream.Size + 1);
PValue[CTextStream.Size] := #0;
{ Copy text stream to clipboard }
Clipboard.Clear;
Clipboard.SetTextBuf(PValue);
CTextStream.Free;
StrDispose(PValue);
end;
为 SaveToTextStream 添加代码:
procedure TCReport.SaveToTextStream(CTextStream: TStream);
var
CBinaryMemoryStream: TMemoryStream;
CWriter: TWriter;
begin
CBinaryMemoryStream := TMemoryStream.Create;
CWriter := TWriter.Create(CBinaryMemoryStream, 24);
try
CWriter.Ancestor := nil;
CWriter.WriteRootComponent(Self);
CWriter.Free;
CBinaryMemoryStream.Position := 0;
{ Convert Binary 'WriteComponent' stream to text}
ObjectBinaryToText(CBinaryMemoryStream, CTextStream);
CTextStream.Position := 0;
finally
CBinaryMemoryStream.Free;
end;
end;
我观察到 StrLen(PChar) 的大小也是 TMemoryStream 的一半。但在 Delphi 2007 年,它与 TMemoryStream 的大小相同。
我知道上面的代码假设 char 的大小为 1 个字节,这可能是个问题。但是我尝试了多种方法,都没有用。
您能否建议一种更好的方法来进行此转换?
再一次,这是 Delphi 2009 年及以后使用 Unicode 文本的问题。 Delphi 2007 年及更早版本:
Char
是 AnsiChar
. 的别名
PChar
是 PAnsiChar
. 的别名
string
是 AnsiString
. 的别名
在 Delphi 2009 年及以后:
Char
是 WideChar
的别名。
PChar
是 PWideChar
. 的别名
string
是 UnicodeString
. 的别名
您的代码是假设 PChar
是 PAnsiChar
编写的。因此你的问题。无论如何,您需要停止使用 StrAlloc
。通过在此处手动分配堆内存,您正在让自己的生活变得艰难。让编译器完成工作。
您需要在字符串变量中获取您的文本,然后只需执行以下操作:
Clipboard.AsText := MyStrVariable;
获取字符串的最佳方式取决于 TCReport
提供的工具。我希望它会直接产生一个字符串,在这种情况下你会写这样的东西:
procedure TCReport.CopyToClipboard;
begin
Clipboard.AsText := Self.ReportAsText;
end;
我猜你的 TCReport
提供了哪些功能,但我相信你知道。
参考上面hvd and David Heffernan写的内容,一种可能的方法是将CopyToClipboard
上的CTextStream
更改为TStringStream
,如下所示:
procedure TCReport.CopyToClipboard;
var
CTextStream: TStringStream;
begin
CTextStream := TStringStream.Create;
try
//Assume no error with Self.SaveToTextStream
Self.SaveToTextStream(CTextStream);
{ Copy text stream to clipboard }
Clipboard.AsText := CTextStream.DataString;
finally
CTextStream.Free;
end;
end;
但是您应该确保 SaveToTextStream
函数为 CTextStream
提供了准确的编码文本数据。
我正在开发最近从 Delphi 2007 升级到 XE7 的应用程序。有一种特殊情况,TMemoryStream 到 PChar 的转换失败。这是代码:
procedure TCReport.CopyToClipboard;
var
CTextStream: TMemoryStream;
PValue: PChar;
begin
CTextStream := TMemoryStream.Create;
//Assume that this code is saving a report column to CTextStream
//Verified that the value in CTextStream is correct
Self.SaveToTextStream(CTextStream);
//The value stored in PValue below is corrupt
PValue := StrAlloc(CTextStream.Size + 1);
CTextStream.Read(PValue^, CTextStream.Size + 1);
PValue[CTextStream.Size] := #0;
{ Copy text stream to clipboard }
Clipboard.Clear;
Clipboard.SetTextBuf(PValue);
CTextStream.Free;
StrDispose(PValue);
end;
为 SaveToTextStream 添加代码:
procedure TCReport.SaveToTextStream(CTextStream: TStream);
var
CBinaryMemoryStream: TMemoryStream;
CWriter: TWriter;
begin
CBinaryMemoryStream := TMemoryStream.Create;
CWriter := TWriter.Create(CBinaryMemoryStream, 24);
try
CWriter.Ancestor := nil;
CWriter.WriteRootComponent(Self);
CWriter.Free;
CBinaryMemoryStream.Position := 0;
{ Convert Binary 'WriteComponent' stream to text}
ObjectBinaryToText(CBinaryMemoryStream, CTextStream);
CTextStream.Position := 0;
finally
CBinaryMemoryStream.Free;
end;
end;
我观察到 StrLen(PChar) 的大小也是 TMemoryStream 的一半。但在 Delphi 2007 年,它与 TMemoryStream 的大小相同。
我知道上面的代码假设 char 的大小为 1 个字节,这可能是个问题。但是我尝试了多种方法,都没有用。
您能否建议一种更好的方法来进行此转换?
再一次,这是 Delphi 2009 年及以后使用 Unicode 文本的问题。 Delphi 2007 年及更早版本:
Char
是AnsiChar
. 的别名
PChar
是PAnsiChar
. 的别名
string
是AnsiString
. 的别名
在 Delphi 2009 年及以后:
Char
是WideChar
的别名。PChar
是PWideChar
. 的别名
string
是UnicodeString
. 的别名
您的代码是假设 PChar
是 PAnsiChar
编写的。因此你的问题。无论如何,您需要停止使用 StrAlloc
。通过在此处手动分配堆内存,您正在让自己的生活变得艰难。让编译器完成工作。
您需要在字符串变量中获取您的文本,然后只需执行以下操作:
Clipboard.AsText := MyStrVariable;
获取字符串的最佳方式取决于 TCReport
提供的工具。我希望它会直接产生一个字符串,在这种情况下你会写这样的东西:
procedure TCReport.CopyToClipboard;
begin
Clipboard.AsText := Self.ReportAsText;
end;
我猜你的 TCReport
提供了哪些功能,但我相信你知道。
参考上面hvd and David Heffernan写的内容,一种可能的方法是将CopyToClipboard
上的CTextStream
更改为TStringStream
,如下所示:
procedure TCReport.CopyToClipboard;
var
CTextStream: TStringStream;
begin
CTextStream := TStringStream.Create;
try
//Assume no error with Self.SaveToTextStream
Self.SaveToTextStream(CTextStream);
{ Copy text stream to clipboard }
Clipboard.AsText := CTextStream.DataString;
finally
CTextStream.Free;
end;
end;
但是您应该确保 SaveToTextStream
函数为 CTextStream
提供了准确的编码文本数据。