Reputation: 27
I am exporting a FastReport as PDFFile using TfrxPDFExport. I made a function that returns me a PDF as IStream:
Function TPDFReport.GetAsFile (): IStream;
var
MStream: TMemoryStream;
Begin
MStream := TMemoryStream.Create;
try
With formReport.Create (NIL) do begin
frxPDFExport.Stream := MStream;
frxReport.PrepareReport;
frxReport.Export(frxPDFExport);
end;
Result := TStreamAdapter.Create(MStream) as IStream;
finally
end;
End;
Afterwards in a different unit I execute this function, get an IStream and load it into a TMemoryStream:
PDFOleStream := TOleStream.Create(PDFReport.GetAsFile ());
PDFMemoryStream.LoadFromStream(PDFOleStream);
Now I got the MemoryStream, but I don't really know the next step. I searched through web and found out that's not possible to send a Stream as a mail attachment with Indy. So I think, it's better to save a TMemoryStream as a temp file and then send it as an attachment. But as soon as I execute
PDFMemoryStream.SaveToFile('c:\\PDFExp.pdf');
I get an access violation. What have I done wrong? Thanks.
Upvotes: 0
Views: 704
Reputation: 596352
You do not need to save the TMemoryStream
to a file just to attach it to an email. Indy's TIdMessage
component is flexible in the types of data you can attach to it.
For instance, Indy has a TIdAttachmentMemory
class you can use, eg:
uses
..., IdAttachmentMemory;
var
Attach: TIdAttachmentMemory;
begin
...
Attach := TIdAttachmentMemory.Create(IdMessage1, PDFMemoryStream); // alternatively, use PDFOleStream instead...
Attach.FileName := 'report.pdf';
// set other properties as needed...
// send the email...
...
end;
Note that TIdAttachmentMemory
uses its own internal TMemoryStream
and will copy the source TStream
's data into that internal stream. If you want to avoid that copy and send your own TStream
as-is, you can derive your own class from TIdAttachment
for that, eg:
uses
Classes, IdAttachment, IdMessageParts, IdGlobal;
type
TIdAttachmentStream = class(TIdAttachment)
protected
FDataStream: TStream;
FDataStreamBeforeLoadPosition: TIdStreamSize;
public
constructor Create(Collection: TIdMessageParts; Stream: TStream); reintroduce;
property DataStream: TStream read FDataStream;
function OpenLoadStream: TStream; override;
procedure CloseLoadStream; override;
procedure FinishTempStream; override;
function PrepareTempStream: TStream; override;
end;
constructor TIdAttachmentStream.Create(Collection: TIdMessageParts; Stream: TStream);
begin
inherited Create(Collection);
FDataStream := Stream;
end;
procedure TIdAttachmentStream.CloseLoadStream;
begin
DataStream.Position := FDataStreamBeforeLoadPosition;
end;
function TIdAttachmentStream.OpenLoadStream: TStream;
begin
FDataStreamBeforeLoadPosition := DataStream.Position;
DataStream.Position := 0;
Result := DataStream;
end;
procedure TIdAttachmentStream.FinishTempStream;
begin
DataStream.Position := 0;
end;
function TIdAttachmentStream.PrepareTempStream: TStream;
begin
DataStream.Size := 0;
Result := DataStream;
end;
var
Attach: TIdAttachmentStream;
begin
...
Attach := TIdAttachmentStream.Create(IdMessage1, PDFMemoryStream); // alternatively, use PDFOleStream instead...
Attach.FileName := 'report.pdf';
// set other properties as needed...
// send the email...
...
end;
Or, you can write a class to send the original IStream
directly, eg:
uses
Classes, IdAttachment, IdMessageParts, IdGlobal;
type
TIdAttachmentIStream = class(TIdAttachment)
protected
FDataStream: TStream;
FDataStreamBeforeLoadPosition: TIdStreamSize;
public
constructor Create(Collection: TIdMessageParts; Stream: IStream); reintroduce;
destructor Destroy; override;
property DataStream: TStream read FDataStream;
function OpenLoadStream: TStream; override;
procedure CloseLoadStream; override;
procedure FinishTempStream; override;
function PrepareTempStream: TStream; override;
end;
constructor TIdAttachmentIStream.Create(Collection: TIdMessageParts; Stream: IStream);
begin
inherited Create(Collection);
FDataStream := TOleStream.Create(Stream);
end;
destructor TIdAttachmentIStream.Destroy;
begin
FDataStream.Free;
inherited;
end;
procedure TIdAttachmentIStream.CloseLoadStream;
begin
DataStream.Position := FDataStreamBeforeLoadPosition;
end;
function TIdAttachmentIStream.OpenLoadStream: TStream;
begin
FDataStreamBeforeLoadPosition := DataStream.Position;
DataStream.Position := 0;
Result := DataStream;
end;
procedure TIdAttachmentIStream.FinishTempStream;
begin
DataStream.Position := 0;
end;
function TIdAttachmentIStream.PrepareTempStream: TStream;
begin
DataStream.Size := 0;
Result := DataStream;
end;
var
Attach: TIdAttachmentIStream;
begin
...
Attach := TIdAttachmentIStream.Create(IdMessage1, PDFReport.GetAsFile());
Attach.FileName := 'report.pdf';
// set other properties as needed...
// send the email...
...
end;
Upvotes: 3