Document Attachments and RVAttachedFile

General TRichView support forum. Please post your questions here
Post Reply
standay
Posts: 274
Joined: Fri Jun 18, 2021 3:07 pm

Document Attachments and RVAttachedFile

Post by standay »

Hi Sergey,

I've been working on a way to embed attachments in my rvf files. I found a post on RVAttachedFile. I tried that but can't get it to work, it looks like the post is pretty old now. Did RVAttachedFile ever get updated?

What I'm doing now is using TNetEncoding base64. Here's what I'm using:

Code: Select all

//https://stackoverflow.com/questions/5795263/binary-to-base64-delphi
function TryEncodeFile(const AFileName: string; out ABase64string: string): Boolean;
var
  MemStream: TMemoryStream;
begin
  MemStream := TMemoryStream.Create;
  try
    MemStream.LoadFromFile(AFileName);
    ABase64string :=
      TNetEncoding.Base64.EncodeBytesToString(MemStream.Memory, MemStream.Size);
    Result := True;
  finally
    MemStream.Free;
  end;
end;

//https://stackoverflow.com/questions/6445089/how-to-convert-tbytes-to-binary-file-using-memorystream
procedure SaveBytesToFile(const Data: TBytes; const FileName: string);
var
  Stream: TFileStream;
begin
  Stream := TFileStream.Create(FileName, fmCreate);
  try
    if Data <> nil then
      Stream.WriteBuffer(Data[0], Length(Data));
  finally
    Stream.Free;
  end;
end;
I insert an attachment like this:

Code: Select all

    if TryEncodeFile( OpenDialog1.FileName, MimeFile ) then
    begin
      rve.DocProperties.Values[ 'att:' + ExtractFileName(OpenDialog1.FileName) ] := MimeFile;
      rve.ApplyTextStyle(4); //jump
      rve.InsertTextW(ExtractFileName(OpenDialog1.FileName));
      rve.ApplyTextStyle(0); //normal
      rve.InsertTextW(' '); //add trailing space
    end;
And in my rveJump, I use this to open the attachment:

Code: Select all

    if rve.DocProperties.Values['att:' + rve.GetCurrentItemTextW] <> '' then
    begin
      Data := TNetEncoding.Base64.DecodeStringToBytes(rve.DocProperties.Values['att:' + rve.GetCurrentItemTextW]);
      if Data = nil then exit;
      SaveBytesToFile(Data,ExtractFilePath(Application.ExeName) + rve.GetCurrentItemTextW );
      if FileExists(ExtractFilePath(Application.ExeName) + rve.GetCurrentItemTextW) then
        ShellExecute(0,PChar('open'),
          PChar(ExtractFilePath(Application.ExeName) + rve.GetCurrentItemTextW), nil, nil, SW_NORMAL );
    end;
This works great IF the file being "attached" is < 75MB. If it's larger the TNetEncoding.Base64 calls fail with an out of memory error.

Have you ever gotten this working? And if so, do you have some code you can post?

Thanks Sergey

Stan
Sergey Tkachenko
Site Admin
Posts: 17566
Joined: Sat Aug 27, 2005 10:28 am
Contact:

Re: Document Attachments and RVAttachedFile

Post by Sergey Tkachenko »

There is one more way for saving additional information in RVF file: DocObjects property.
This is a collection of objects inherited from TRVDocObject class. All these objects, including all their published properties, can be stored in RVF.

When using DocObjects, you can save binary data as they are, without encoding as text.

I attached a unit that implements TRVFileDocObject, an object that can store file content and a file name.
To use it, make sure that rvoSaveDocObjects and rvoLoadDocObjects are included in RichViewEdit1.RVFOptions.

Example of adding a file:

Code: Select all

var
  FO: TRVFileDocObject;
begin
  FO := TRVFileDocObject.Create(RichViewEdit1.DocObjects);
  FO.LoadFromFile('d:\test\1.bmp');
  FO.FileName := '1.bmp';
Attachments
RVFileDocObject.pas
(2.12 KiB) Downloaded 1121 times
standay
Posts: 274
Joined: Fri Jun 18, 2021 3:07 pm

Re: Document Attachments and RVAttachedFile

Post by standay »

Hi Sergey,

Yes, this works as well as the base64 method but without the size limits. I was able to store and retrieve a 131MB audio project with no problems.

I don't plan to store much of anything as "attachments," but if I do need to do that it's good to know I can do it without issues.

Thanks Sergey

Stan
Post Reply