Search code examples
delphiunicodedelphi-2007delphi-xe7

StrAlloc not working after migrating to Delphi XE7


I am working on an application which was recently upgraded from Delphi 2007 to XE7. There is one particular scenario where the conversion of TMemoryStream to PChar is failing. Here is the code:

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;

Adding the code for 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;

I observed that the StrLen(PChar) is also coming out to be half the size of TMemoryStream. But in Delphi 2007 it was coming out to be same as the size of TMemoryStream.

I know that the above code is assuming the size of a char to be 1 byte, and that could be a problem. But I tried multiple approaches, and nothing works.

Could you suggest a better way to go about this conversion?


Solution

  • By reffering to what hvd and David Heffernan wrote above, one possible way is to change CTextStream on CopyToClipboard to TStringStream as follow :

    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;
    

    But you should make sure that SaveToTextStream function provides CTextStream with the exact encoding text data.