Overview
Recently I was asked to create an executable that contains a pdf, and on a click of a button the application should launch the pdf file in the default pdf reader installed in the system. For you who had read this tutorial you will find it an easy task. Because actually I used exactly the steps explained in that tutorial. For you who haven't read it, you are welcome to read Store Executable (or other kind of file) Inside your Executable and Execute it first before continue.
Since we already know how to do this, I am just going to give you the details. Consider this tutorial as another sample case.
Steps Details
Step 1. Create the .RC file
- Create a simple text file and name it pdf.rc.
- Add the following line to pdf.rc:
Doc1 RCDATA Doc1.pdf
Recall that that line means that we want to create a resource item with name of Doc1 of type RCDATA which content comes from file Doc1.pdf that resides in the same location with the .rc file.
Step 2. Compile the Resource Script into .RES file
To do this, you can do one of these.
- Open command prompt, then browse to the folder where you stored the resource script file. After that, run the following command.
brcc32 -32 -fo pdf.res pdf.rc
You will get new file named pdf.res in the same folder of the pdf.rc file. - Create a new .bat file in the same folder where you stored the resource script file. And add the same command specified above in it. Then execute the .bat file. You will get the pdf.res.
Step 3. Embed the .RES File Into Delphi Project
Add the following line into one of the source code of your Delphi project. It can be in one of the .pas files or in the .dpr.
{$R pdf.res}
Step 4. Extract PDF Document to Temporary Location
The rest of the steps will be done through a class I created, named TPdfOpener. This is in order to harness the power of OOP, especially for encapsulation and reusability. And the class "template" is:
type TPdfOpener=class private FDocName: string; protected procedure ExtractTo(const AFilename: string); procedure DoOpen(const AFilename: string); public procedure Open; property DocName: string read FDocName write FDocName; end;
Property DocName specifies resource name of the PDF. For example, in our case we have to use Doc1 for it.
For this step, we are interested with method ExtractTo, which implementation is:
procedure TPdfOpener.ExtractTo(const AFilename: string); var F: TStream; R: TStream; begin R := TResourceStream.Create(HInstance, FDocName, RT_RCDATA); try F := TFileStream.Create(AFilename, fmCreate); try F.CopyFrom(R, 0); finally F.Free; end; finally R.Free; end; end;
Note that this method does not actually define the temporary location. That should be done by the caller of this method, and pass the temporary location through AFilename parameter. In the class, that was done in Open method. Which implementation is:
procedure TPdfOpener.Open; function GetTempPath: string; var i: Cardinal; begin SetLength(Result, MAX_PATH); i := ExpandEnvironmentStrings('%TEMP%', PChar(Result), MAX_PATH); SetLength(Result, i-1); end; var vTmpFile: string; begin Randomize; // decide the temporary file name and folder vTmpFile := GetTempPath + '\' + IntToStr(Random(10020)) + FDocName + '.pdf'; // write the pdf doc to the temporary file ExtractTo(vTmpFile); // Open the pdf doc DoOpen(vTmpFile); end;
Step 5. Open the Temporary PDF File
For this, we ask the shell to open the temporary pdf file. In turn, the shell will open it with default application to open .pdf files. In our TPdfOpener this step is handled by DoOpen method. And its implementation is:
procedure TPdfOpener.DoOpen(const AFilename: string); begin ShellExecute(0, 'open', PChar(AFilename), nil, nil, SW_NORMAL); end;
And that's it! You can check the complete codes and run it to see if the above steps work.

This is what you get when the demo starts run. Note that you might get different icons for PDF documents. They were retrieved from the system at runtime. Not hardcoded.
And here is the look of the opened pdf document, in my system.

And here is the complete source code.

Edited by LuthfiHakim, 10 February 2013 - 08:33 AM.