2015-11-30 37 views
0

我正在研究最近从Delphi 2007升级到XE7的应用程序。 TMemoryStream到PChar的转换失败了。下面是代码:移植到Delphi XE7后,StrAlloc无法正常工作

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的值(P Char)也现身是内存流的一半大小。但在Delphi 2007中,它的出现与TMemoryStream的大小相同。

我知道上面的代码假设char的大小为1个字节,这可能是一个问题。但我尝试了多种方法,没有任何工作。

你能否提出一个更好的方式来进行这种转换?

+1

“SaveToTextStream”以什么编码存储数据?修正你的代码的正确方法取决于使用的编码。三种现实的可能性是:1)与'UnicodeString'(UTF-16LE)相同的编码2)UTF-8 3)与'AnsiString'(取决于Windows活动代码页)相同的编码。 – hvd

+0

这是为什么被拒绝? – jetty

回答

0

通过reffering什么hvdDavid Heffernan上面写道,一个可能的方法是在CopyToClipboard改变CTextStreamTStringStream如下:

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具有确切编码文本数据。

+0

这个作品! SaveToTextStream接受TStream作为输入参数。正是我需要的。谢谢。 – jetty

+0

@jetty您的欢迎。 – theodorusap

+0

这对我来说似乎是一个相当可怜的建议。正如所写的,代码强制使用ANSI。当然应该避免。 @jetty,你真的拥抱Unicode吗? SaveToTextStream是如何实现的? 'TCReport'包含文本表示吗? –

8

再次,这是德尔福2009年的问题,后来使用Unicode文本。在Delphi 2007及更早版本中:

  • CharAnsiChar的别名。
  • PCharPAnsiChar的别名。
  • stringAnsiString的别名。

在2009 Delphi和后来:

  • Char是一个别名WideChar
  • PCharPWideChar的别名。
  • stringUnicodeString的别名。

您的代码是假设PCharPAnsiChar。因此你的问题。无论如何你需要停止使用StrAlloc。通过在此处手动分配堆内存,您正在为自己拼命工作。让编译器完成这项工作。

你需要获得一个字符串变量文本,然后简单地做:

Clipboard.AsText := MyStrVariable; 

究竟如何最有效地获取字符串取决于TCReport提供的设施。我期望它会直接产生一个字符串,在这种情况下,你会写是这样的:

procedure TCReport.CopyToClipboard; 
begin 
    Clipboard.AsText := Self.ReportAsText; 
end; 

我猜测,以你的功能你TCReport报价,但我敢肯定,你知道的。

+0

+1。这个。那些声称自己在做什么而不知道自己在做什么的人将移植到unicode delphi中,他们会做出他们所做的一切。手动分配(使用StrAlloc或GetMem)是一种代码异味,除非有必要。即使在德尔福7时代,仍然存在那些愚蠢的代码,这是一个勉强胜任的开发人员的标志。 –

+0

Hi @DavidHeffernan,你可以看看编辑过的代码吗?我已经提到了SaveToTextStream的代码。 – jetty

+0

ObjectBinaryToText使用什么编码? –