Solved

AcroPdf Open File from Resource

Posted on 2010-11-23
35
5,074 Views
Last Modified: 2012-06-27
Hi,

I need to open a PDF file with TAcroPdf activex object (unit AcroPDFLib_TLB with Delphi 7) but the file must stay in the Resource (.RES) not in some folders.

Thanx in advance
0
Comment
Question by:andreamatt
  • 13
  • 10
  • 7
  • +2
35 Comments
 
LVL 25

Expert Comment

by:epasquier
Comment Utility
You can (probably must) save the resource in a temp file, open it and delete it.
0
 
LVL 1

Author Comment

by:andreamatt
Comment Utility
Sorry, but I don't want to use the hard disk, devices or folders. Any type or folders.
0
 
LVL 32

Expert Comment

by:ewangoya
Comment Utility

You can can save the pdf as a resource but unfortunately, AcroPDF can not load pdf from stream. You have to save it to a temporary location or find a different PDF component that can load from stream
0
 
LVL 25

Expert Comment

by:epasquier
Comment Utility
Yes, ewangoya, thank you to confirm that AcroPdf cannot load from a memory/stream.
There are effectively other PDF components, but finding the one that can load from memory will be some work... And it most probably won't be cheap

What is wrong with using a temp file ?
0
 
LVL 1

Author Comment

by:andreamatt
Comment Utility
Thanks for the responses.

For security problems I don't want to save the PDF in a temp file.
I have search for other PDF component but the TAcroPDF has some advantages over other.
0
 
LVL 25

Expert Comment

by:epasquier
Comment Utility
you probably can afford to save the PDF to a file, load it and delete it immediately after.
That would be an adequate solution until you find the PDF component of your dreams, that can do anything and that is cheap or even free...
Well, we have rights to dream no ?
If you find something that suits your needs, tell us so that it could help others
0
 
LVL 25

Expert Comment

by:epasquier
Comment Utility
you are aware that someone competent enough to grab the file the few seconds it is available in your drive before you delete it, will be also capable of getting the file from the resource in the exe ? unless you also crypt that file in your resource and decrypt on the fly before using it
0
 
LVL 32

Expert Comment

by:ewangoya
Comment Utility
@epasquire
You are quite right. There are lots lousy pdf components out there that i dont think its worth wasting time on.
And sure enough, anything in the resource can be accessed.

A temp file is a good idea to me, but then thats me
0
 
LVL 1

Author Comment

by:andreamatt
Comment Utility
I have make many test before asking this question.
If have tested the code for: save the PDF in a temp dir - load the PDF with TAcroPDF - delete the PDF but is it not secure at 100%.

If I save a crypted PDF and after decrypt it on the fly I must save it on a temp folder before load with TAcroPDF... and I have the same problem. Or you have a solution for this?
0
 
LVL 32

Expert Comment

by:ewangoya
Comment Utility
What is the main security concern?, You do not want people to copy or view the document unless from your application

If we know this, we may be able to design a solution for it
0
 
LVL 25

Expert Comment

by:epasquier
Comment Utility
No, there is no solution, except spending more and more time to look for the perfect PDF component that does what you want, if it exists.
Know that there is NO 100% secure solution, that just doesn't exists whatever the problem is. A "secured" solution is then what is enough to avoid the vast majority of the cases.
If the PDF is not that big, then the Acrobat activeX will not take much time to load it. So you can delete it very quickly, and there is not that many people around that will know how to grab it on the fly.
And those people would first have to know what you are doing, and really want to bypass your security. Is your file so sensitive ?
I only talked about crypted file to make you understand that the real security concern in your system is not the temp file, but the resource in the exe. IF you don't crypt that resource.
So no need to talk hours about the temp file if you don't have already secured the biggest problem
0
 
LVL 1

Author Comment

by:andreamatt
Comment Utility
Yes ewangoya, this is my problem. What solution you have?
0
 
LVL 32

Expert Comment

by:ewangoya
Comment Utility
I'm talking of ways to have the file encrypted in the resource and when saved to a temp file, somehow lock that file so it cant be opened or copied by any other process
0
 
LVL 1

Author Comment

by:andreamatt
Comment Utility
For epasquier. Thanks for your long response.
My resource file is also encrypted in the .exe.
I know the problem for "many people around" but the document must be protected for special people. I know also that this is very difficult (and in some cases impossible like you write) but the system to use a temp file PDF is so simple.
For a big PDF (100Mbytes) that stay in a slow device like a USB Flash Drive the time to copy-load-delete is not very quickly.
0
 
LVL 1

Author Comment

by:andreamatt
Comment Utility
For ewangoya.

> I'm talking of ways to have the file encrypted in the resource and when saved to a temp file, somehow lock that file so it cant be opened or copied by any other process

Ok, but if the file is encrypted I can't open it with TAcroPDF!
0
 
LVL 25

Expert Comment

by:epasquier
Comment Utility
> For a big PDF (100Mbytes) that stay in a slow device like a USB Flash Drive
> the time to copy-load-delete is not very quickly.
Only an idiot would set a USB flash Drive for his system TEMP folder. Aside from being real slow, it murders the poor flash drive which have a very limited nb of rewrite longevity (~10.000 cycles)
Or use C:\WINDOWS\TEMP, I don't think Windows can be installed in USB flash drive

Ewangoya idea is to lock the temp file for other operations. That is a good idea. The first thing would be to set that file as Hidden. Then use whatever technique to give exclusive access to your application for this file, even blocking reading access for other process. That is probably possible, but is that really needed ?
0
 
LVL 1

Author Comment

by:andreamatt
Comment Utility

Sorry Epasquier but for your:
"Only an idiot would set a USB flash Drive for his system TEMP folder"
I have not set the USB Flash Drive for a temp folder! I have the .EXE in the flash Drive. But when I try to extract the .RES in a folder like C:\TEMP is very slow... because if you know... the process to read data in a USB Flash Drive is very slow.

Also sorry for the hidden file solution but is so simple to see for an expert.
0
Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

 
LVL 25

Expert Comment

by:epasquier
Comment Utility
ah, but if that is the reading part that is slow, then that is easily fixed : you load the resource in memory, THEN only :
- save to temp file
* hide/lock the file and other techniques
- load the file in PDF componnent
* unlock the file
- delete it

so the file is only on your hard drive the time the PDF component load from hard drive. And besides, since it just has been written, it should be in the system cache so loading time should be just a flash
0
 
LVL 32

Expert Comment

by:ewangoya
Comment Utility

Here is an Object with two methods to lock and unlock the file.
You save the file to a temporary folder then Load it with AcroPDF
(You can create a temporary folder at runtime and later remove it, this way you can always create a folder with a unique name)
Lock the file
when you are done viewing the file,unlock it and delete it

//

private
  FFileLocker: TFileLock;

procedure LoadPDF(const AFileName: string);
begin
  //load to AcroPDF
.....
   FFileLocker.Lock(AFileName);
end;

procedure UnLoadPDF;
begin
   //close AcroPDF
  FileLock.UnLock;
 
  //delete file
end;


type

  TFileLock = class(TObject)

  private

    FFileHandle: THandle;

    FFileName: string;

    FFileSize: Longint;

  public

    function Lock(const AFileName: string): Boolean;

    procedure UnLock;

  end;



implementation



{ TFileLock }



function TFileLock.Lock(const AFileName: string): Boolean;

begin

  FFileName := AFileName;

  FFileHandle := CreateFile(PChar(AFileName), GENERIC_READ or GENERIC_WRITE, 0, nil, OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL, 0);

  Result := FFileHandle <> INVALID_HANDLE_VALUE;

  if Result then

  begin

    FFileSize := GetFileSize(FFileHandle, nil);

    Result := LockFile(FFileHandle, 0, 0, FFileSize, 0);

    if not Result then

    begin

      CloseHandle(FFileHandle);

      FFileHandle := 0;

      FFileSize := 0;

    end;

  end;

end;



procedure TFileLock.UnLock;

begin

  if FFileHandle > 0 then

  begin

    UnlockFile(FFileHandle, 0, 0, FFileSize, 0);

    CloseHandle(FFileHandle);

    FFileHandle := 0;

    FFileSize := 0;

  end;

end;

Open in new window

0
 
LVL 24

Expert Comment

by:jimyX
Comment Utility
I do not know how you managed to compile 100 MB PDF file in .res, I tried even 63 MB with no success.

Let's assume you managed to do that, it is not advisable to have such huge exe file.

If you still insist on having the 100 MB PDF in the exe and you want to open it without extracting to the hard disk, you can use the OleContainer.

First you must set the required security options to your pdf file (disable printing, changing the document, content copying, ... etc) then load it in the OleContainer and when you want to open the file just write in onbuttonclick or onFormCreate:

OleContainer.Run;
OleContainer.DoVerb(ovPrimary);
OleContainer.DoVerb(ovInPlaceActivate);
OleContainer.DoVerb(ovshow);

Please note, it will open the file with the associate default PDF (external application) but from your exe without copying the file to the hard disk.

0
 
LVL 25

Expert Comment

by:epasquier
Comment Utility
ewangoya : excellent job, you only have to add Hidden parameters to further trouble the average guy

JimiX : I have not used OleContainer since a while, are you sure you can first load a PDF from a stream in there ? If that is the case, that is even better than using TAcroPDF at all. A bit more complex during initialization, but then I think you can access the activeX interface of Acrobat from the OleContainer directly, and do whatever is needed
0
 
LVL 8

Expert Comment

by:lomo74
Comment Utility
a simpler solution would be to drop a webbrowser onto the form then point the browser to the resource using the res:// protocol --
see if attached example works for you.
0
 
LVL 8

Expert Comment

by:lomo74
Comment Utility
damn filter
doesn't like my zip

go get example here

http://www.lorenzomonti.it/listing/respdf.zip
0
 
LVL 1

Author Comment

by:andreamatt
Comment Utility
Thanks for every solutions.

For ewangoya:
This can be a particular solution. But for me is very important to not use a temp dir and to load the file in memory.

For jimyX
The OleContainer is a good solution. The problem is that I have the PDF in another new window. I don't have find a solution to view the PDF inside the main Form. Do you have a solution for this?

For lomo74
Thanks for the code. The problem for the TWebBrowser is this: after the view, is it possible to find the PDF file in the cache of Windows. Also... I don't have find a solution for this...


0
 
LVL 25

Expert Comment

by:epasquier
Comment Utility
>> The problem for the TWebBrowser is this: after the view, is it possible to find the PDF file
>> in the cache of Windows.
Most probably, yes...
0
 
LVL 8

Expert Comment

by:lomo74
Comment Utility
what about rendering PDF directly with e.g. ghostscript.
you feed data to ghostscript through pipe (or maybe use DLL version of ghostscript), use the "display" device and receive back raster... have some examples if you are interested.
rather complicated though, and heavy CPU and memory consuming since you have to store all PDF in memory as raster images... don't know if this is acceptable for you
0
 
LVL 1

Author Comment

by:andreamatt
Comment Utility
Thanks Iomo74 but I prefere to use the TAcroPDF.
0
 
LVL 24

Expert Comment

by:jimyX
Comment Utility
> are you sure you can first load a PDF from a stream in there ?

Although the OleContainer has LoadFromStream method but the PDF file should be loaded directly in the OleContainer by browsing and locating it to be embedded in the exe.

> solution to view the PDF inside the main Form.

You can implement the function from the link below which will enable your program to load the Acrobat Reader first in your form and then ask the OleContainer to open the file in it.

http://www.experts-exchange.com/Programming/Languages/Pascal/Delphi/Q_20682510.html#8950787

I tried this method successfully with Adobe Acrobat 8 Professional. However it did not load the Acrobat Reader version 9.
0
 
LVL 25

Expert Comment

by:epasquier
Comment Utility
If Acrobat in OleContainer cannot load from a stream, then there is no gain compared to AcroPDF
andreamatt, I'm starting to really believe you have no choice but implement a hidden+locked temp file solution.
0
 
LVL 1

Author Comment

by:andreamatt
Comment Utility
Thanxs jimyX but it is essential that the code works with any version of the Adobe Reader as well as with any operating system (XP, Vista, Seven).
0
 
LVL 1

Author Comment

by:andreamatt
Comment Utility
Hi ewangoya
I hav try your code in ID: 34202694 but I have an EAccessViolation at
FFileName := AFileName;

Do you have a full functional example?

0
 
LVL 32

Accepted Solution

by:
ewangoya earned 500 total points
Comment Utility

Add your code for loading the pdf from resource

unit Unit3;



interface



uses

  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

  Dialogs, StdCtrls, OleCtrls, AcroPDFLib_TLB, ExtCtrls;



type

  TFileLock = class(TObject)

  private

    FFileHandle: THandle;

    FFileName: string;

    FFileSize: Longint;

    FFolder: String;

  public

    destructor Destroy; override;

    function CreateFolder: string;

    procedure DeleteFile;

    function Lock(const AFileName: string): Boolean;

    procedure RemoveFolder;

    procedure UnLock;

  end;



  TForm3 = class(TForm)

    Panel1: TPanel;

    Panel2: TPanel;

    AcroPDF1: TAcroPDF;

    Button1: TButton;

    Button2: TButton;

    procedure Button1Click(Sender: TObject);

    procedure Button2Click(Sender: TObject);

    procedure FormCreate(Sender: TObject);

    procedure FormDestroy(Sender: TObject);

  private

    FFileLock: TFileLock;

  end;



var

  Form3: TForm3;



implementation



{$R *.dfm}



{ TFileLock }



function TFileLock.CreateFolder: string;

begin                                                    //generate random name with any prefered algorithm

  FFolder := IncludeTrailingPathDelimiter(ExtractFilePath(ParamStr(0))) + IntToStr(Random(100000));

  ForceDirectories(FFolder);

  Result := FFolder;

end;



procedure TFileLock.DeleteFile;

begin

  if FileExists(FFileName) then

    SysUtils.DeleteFile(FFileName);

  FFileName := '';

end;



destructor TFileLock.Destroy;

begin

  Unlock;

  DeleteFile;

  RemoveFolder;

  inherited Destroy;

end;



function TFileLock.Lock(const AFileName: string): Boolean;

begin

  FFileName := AFileName;

  FFileHandle := CreateFile(PChar(AFileName), GENERIC_READ or GENERIC_WRITE, 0, nil, OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL, 0);

  Result := FFileHandle <> INVALID_HANDLE_VALUE;

  if Result then

  begin

    FFileSize := GetFileSize(FFileHandle, nil);

    Result := LockFile(FFileHandle, 0, 0, FFileSize, 0);

    if not Result then

    begin

      CloseHandle(FFileHandle);

      FFileHandle := 0;

      FFileSize := 0;

    end;

  end;

end;



procedure TFileLock.RemoveFolder;

begin

  if DirectoryExists(FFolder) then

    SysUtils.RemoveDir(FFolder);

  FFolder := '';

end;



procedure TFileLock.UnLock;

begin

  if FFileHandle > 0 then

  begin

    UnlockFile(FFileHandle, 0, 0, FFileSize, 0);

    CloseHandle(FFileHandle);

    FFileHandle := 0;

    FFileSize := 0;

  end;

end;



{ TForm3 }



procedure TForm3.Button1Click(Sender: TObject);

var

  FileName, FolderName: string;

begin

  FolderName := FFileLock.CreateFolder;                  //Generate random name with any prefered algorithm

  FileName := IncludeTrailingPathDelimiter(FolderName) + IntToStr(Random(10000)) + 'PDF';

  //Add your code to load and decrypt the PDF stream from your resource

  //save the stream to file



  AcroPDF1.LoadFile(FileName);

  FFileLock.Lock(FileName);

end;



procedure TForm3.Button2Click(Sender: TObject);

begin

  FFileLock.UnLock;

  FFileLock.DeleteFile;

  FFileLock.RemoveFolder;

end;



procedure TForm3.FormCreate(Sender: TObject);

begin

  FFileLock := TFileLock.Create;

  Randomize;

end;



procedure TForm3.FormDestroy(Sender: TObject);

begin

  FreeAndNil(FFileLock);

end;



end.

Open in new window

0
 
LVL 1

Author Comment

by:andreamatt
Comment Utility
After some testing, if I have understand this are the steps:

1) Creation protect folder
2) Save the PDF file that stay in resource to file in the folder protect
3) Load file in TAcroPDF
4) Lock file
5) Unlock file
6) Delete file and protect folder


The problem is to lock the file during the 2-3 step not after.

This is a very good code but this not solve the problem. Right?
0
 
LVL 32

Expert Comment

by:ewangoya
Comment Utility
If you lock the file before loading it, then you will not be able to load it at all.
0
 
LVL 1

Author Comment

by:andreamatt
Comment Utility
Yes... this is the problem.
If no answers come in the comings days, I will give you the 500 points.
0

Featured Post

Threat Intelligence Starter Resources

Integrating threat intelligence can be challenging, and not all companies are ready. These resources can help you build awareness and prepare for defense.

Join & Write a Comment

Have you ever had your Delphi form/application just hanging while waiting for data to load? This is the article to read if you want to learn some things about adding threads for data loading in the background. First, I'll setup a general applica…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
Access reports are powerful and flexible. Learn how to create a query and then a grouped report using the wizard. Modify the report design after the wizard is done to make it look better. There will be another video to explain how to put the final p…
This tutorial demonstrates a quick way of adding group price to multiple Magento products.

763 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now