迁移到Delphi XE7后,StrAlloc无法正常工作

时间:2015-11-30 11:11:34

标签: delphi unicode delphi-2007 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个字节,这可能是个问题。但我尝试了多种方法,没有任何作用。

你能建议一个更好的方法来进行这种转换吗?

2 个答案:

答案 0 :(得分:8)

然而,这是Delphi 2009及以后使用Unicode文本的问题。在Delphi 2007及更早版本中:

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

在Delphi 2009及更高版本中:

  • CharWideChar的别名。
  • PCharPWideChar的别名。
  • stringUnicodeString的别名。

您的代码是在PCharPAnsiChar的情况下编写的。因此你的问题。无论如何,您需要停止使用StrAlloc。你在这里通过手动分配堆内存让自己变得艰难。让编译器完成工作。

您需要在字符串变量中获取文本,然后执行:

Clipboard.AsText := MyStrVariable;

获取字符串的最佳方式取决于TCReport提供的功能。我希望它会直接产生一个字符串,在这种情况下你会写这样的东西:

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

我猜测你的TCReport提供的功能是什么,但我确定你知道。

答案 1 :(得分:0)

通过查看上面hvdDavid Heffernan所写的内容,一种可能的方法是将Error C2065 'timezone': undeclared identifier pythoncore C:\Users\Ira\Downloads\Python-2.7.10\Modules\timemodule.c 713 上的<script src="telerik.kendoui.professional.2015.3.1111.trial/js/kendo.all.min.js"></script> <script src="telerik.kendoui.professional.2015.3.1111.trial/js/jquery.min.js"></script> <link href="telerik.kendoui.professional.2015.3.1111.trial/styles/kendo.default.min.css" rel="stylesheet" /> <link href="telerik.kendoui.professional.2015.3.1111.trial/styles/kendo.common.min.css" rel="stylesheet" /> </head> <body> <div id="example"> <label>First Name</label> <input type="text" name="firstName" id="txtFname" value="" /> <script> $(document).ready(function () { $("txtFname").kendoMaskedTextbox({ }); }); </script> </div> </body> </html> 更改为CTextStream,如下所示:

CopyToClipboard

但您应确保 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; 提供准确的编码文本数据。