Fonte - thenextage.com/wordpress/
I recently needed to embed several PDF files in our executable so we
didn’t have to ship them individually with application and keep track of
updating them separately. The original plan was to try to do something
similar to what pcSoft does with the DLLs in the executable, where they
“self-extract” with the first run. However I ran into a few issues.
1. FExtractResource() looked promising but is only for Mobile
2. You can embed and use images (PNG, etc) easily. just referencing
their names for using DLoadImage, but it doesn’t work with PDFs
3. Embedding the PDF in the EXE is easy, but since there is not a
native function to extract them, it would require a couple of different
Windows API calls to handle, which started making my head hurt.
I finally discovered that there is a little known feature of HF
Classic files that lets you embed them in your executable and then the
standard Hxxxx commands will access the files just like as if the HF was
on disk.
So what I did was create a HF table that has a binary memo where I
store the PDF. I then embed that HF table in my EXE. Then I use
HReadxxxx commands to get the PDFs.
The last challenge was to use ShellExecute to display the PDF in
acrobat etc. the PDF has to be on disk, so I created my own PDF viewer
in WD, so that I could display the PDFs without ever writing them to
disk.
I recently needed to embed several PDF files in our executable so we
didn’t have to ship them individually with application and keep track of
updating them separately. The original plan was to try to do something
similar to what pcSoft does with the DLLs in the executable, where they
“self-extract” with the first run. However I ran into a few issues.
1. FExtractResource() looked promising but is only for Mobile
2. You can embed and use images (PNG, etc) easily. just referencing
their names for using DLoadImage, but it doesn’t work with PDFs
3. Embedding the PDF in the EXE is easy, but since there is not a
native function to extract them, it would require a couple of different
Windows API calls to handle, which started making my head hurt.
I finally discovered that there is a little known feature of HF
Classic files that lets you embed them in your executable and then the
standard Hxxxx commands will access the files just like as if the HF was
on disk.
So what I did was create a HF table that has a binary memo where I
store the PDF. I then embed that HF table in my EXE. Then I use
HReadxxxx commands to get the PDFs.
The last challenge was to use ShellExecute to display the PDF in
acrobat etc. the PDF has to be on disk, so I created my own PDF viewer
in WD, so that I could display the PDFs without ever writing them to
disk.
So let’s take a look at the demo application I put together for all of this.
This is a simple screen that displays a browse of our HF table that
has the binary memo in it. The first two buttons allow you to add either
a file, or an entire directory of PDFs to the HF table. This includes
storing the PDF in a binary memo field. The Delete button is fairly self
explanatory. The refresh button updates the binary memo using the
current PDF located in the original location recorded when the file was
first added. This is useful for updating the HF table after the PDFs
have been updated. As I mentioned this system was created for
distributing PDF help files with an executable, so with each release of
the executable some of the help files are updated to cover new features,
so its a simple matter to run the refresh button before generating the
executable so that the latest PDFs will be included. Finally the view
button is viewing the PDF using a “native” PDF viewer I created. Note:
this viewer is actually displaying the PDF stored in the HF binary memo,
not the physical file on the drive.
The layout for the HF table is very simple.
First there is a autonumbered id field, which all your tables should
have after hearing Andy and I harp on that for years! Then the filename,
and location are in separate fields. You could store them as one field
if desired, but in my production application we are referring to the
PDFs by their name so I need it as an independent field. And last is a
Binary memo field to store the actual contents of the PDF file. This is a
HF Classic table.
Now for the code. First a bit of project code.
If you read the help (which I KNOW you do!), you will discover that
by default WinDev looks for HF classic files embed in the EXE first and
then on disk, but for the sake of the developer that comes after me, I
wanted to make this a little more obvious. So if we are in TestMode(),
the Green Go button in the IDE, then I want to use the HF from the disk.
That means that when I run via the GO mode I am updating the physical
HF table. In my production application I have slightly different logic
to handle this as I have a small help application that is only on the
developers machine for updating the HF table.
The real magic happens when we are not in test mode, the hWDL
constant says to look the the HF table embed in the library either your a
WDL file or the EXE file. As mentioned this is actually the default
access mode for HF classic tables, and if it doesn’t find it in embed it
will search for it on the disk, so you have to be careful that you have
really accomplished what you think you have when testing. We will
discuss that more latter.
Let’s look at adding PDFs to the HF table. The code behind the Add
Directory looks like this. The code behind Add a file is just a simpler
version of this that doesn’t need to step through a directory so we will
only look at the Add Directory code.
Line 1 turns on the hourglass, in case this is a large directory that
could take a few moments to process. Line 2 opens the standard windows
dialog to select a directory. If a directory was selected the real work
begins with line 4 which uses the fListFile function to get a carriage
return separated list of all PDF files in the directory. If there were
PDF files in the directory the Line 6 begins looping through the list
and adding them to the HF table. If you haven’t seen a For Loop like
this before spend a few minutes studying it and reading the help files
as it can be very handy. It takes a string of values separated by a
character in this case a carriage return (CR) it places them into a
single string (tmpFullFileName) one at a time with each pass of the
Loop.
Line 8 and 9 use a few handy string functions from WX to separate the FileName from the Path.
Line 10 checks to see if there is already a record with this file
name and if so it updates the record in lines 11-13, otherwise a new
record is added via lines 15-18. The only line that we should really
need to take a look at in that code is line 12 and 17. What they are
doing is using another great WX function (fLoadBuffer) to load the
physical PDF into the binary memo. This could be any physical file, so
you could use this to store word docs, other applications, whatever you
might need store inside your HF table.
When the Loop as completed Line 23 refreshes the table display, then
we give the user a message to let them know it is done and turn off the
hour glass.
At this point we have our physical HF table with the PDF stored in
the binary memo. Before we take a look at my PDF viewer, lets look at
how to embed this HF table in the EXE we are going to make.
I am sure there are several ways to do this via the IDE, but I tend
to use the Project Explorer for most things. Notice in the project
explorer there is a “Other” folder, anything that we add to this folder
will be incorporated into our executable as a resource.
This opens the Windows file picker and lets you select files to add,
and you can see in this screen shot that I have selected the 3 files
that make up our HF table, the actual file (FIC), the Index (NDX) , and
the Memo (MMO).
Afterwards the files are shown in my project explorer
Now we can generate the EXE
This takes you through several screens, I will assume you have made a
WinDev executable before, so I will only mention a few items from this
screens. First notice on the content of the EXE our HF files are shown.
For simplicity of this demonstration, and because I have UAC turned
off on my system, I will set the directory of the data files to reside
with the executable.
Also to make this demonstration easier, I will include the DLLs in the EXE
After a few more screens we have an executable. And if you run the
executable and View one of the PDFs it will be displaying the PDF from
the Binary Memo from the HF table that is embed in the EXE. If you don’t
believe me and want to verify this, you can move the EXE to a different
directory and even delete the HF table and the PDFs, and the EXE will
still perform fine and display the records.
NOTE: a “downside” to this is that the HF tables that are included in
your EXE are read only, you can not update them. Which when you think
about it makes a lot of sense, as it would be fairly dangerous writing
new data inside an EXE file while you are running it!!! This does
provide yet another way to tell that we are actually using the embed HF
table, if we try to add a file, we will get an error like this
Which again tells us the file is in read only mode because it is embed.
So that is all there is to embedding a HF table inside your
Executable, and I could end the article now, but you know I always have
to give you some bonus material. In our production app we of course
wanted the user to be able to view the PDF files, originally when we
were distributing physical PDF files we would use ShellExecute to
accomplish that using whatever PDF viewer they had installed, the only
problem with that is the files have to physically exists on the drive,
which sort of defeats the purpose of our cool new ability. So I decide
to create my own PDF viewer to display the PDF from the Binary memo
field without ever writing the PDF to disk.
The code behind the view button is pretty simple. If a record is
selected in the table, it performs an HReadSeekFirst to get the record
and then calls my PDFViewer window pass the binary memo as a parameter.
The viewer is a simple window with a toolbar of useful buttons, and an image control.
The display mode of the Image is Homothetic without enlargement and the Anchoring is set to expand both by width and height.
The initialization code of the window, moves the passed binary memo
into the Image control, and sets the zoom mode to fit by width.
The InitTittleBarandPageNumber procedure set the caption to the
display both the current page # and the total number of pages. It also
has some logic to enable/disable the page up / down buttons based on
what page is being displayed. This is done as a procedure so that it can
be called from all of the controls in the toolbar.
If you were expecting some fancy, complicated image/PDF manipulation
code next then you haven’t been paying attention to me going on and on
about how easy WX makes my life!!
Here is the code from the 3 controls that change which page is
displayed. The Page up and down buttons and the page number edit
control. As you see all they do is change the PageNumber property of the
image control and then call the InitTittleBarandPageNumber function to
change the caption and enable/disable the page up/down buttons.
So there must be some complicated code behind the zoom buttons at
least, right? WRONG!!! If it seems hard in WX you are probably doing it
wrong!!! Here is the code for all five zoom buttons.
Again all they are doing is changing the value of the Zoom property, it can’t get much easier than that can it?
And that is the all of the code of my “native” PDF viewer. Nothing fancy, but it sure is handy!.
Hopefully this has inspired you and got you thinking about how you
could use this technique in your projects. Along with distributing PDF
help files like we are doing, some thoughts that come to mind is perhaps
distributing images that you want somewhat protected and don’t want the
user to have direct access to the image files. You could also create a
electronic catalog of products, that could be distributed as a single
EXE file, even if your actually catalog uses several HF tables. Perhaps
this could be used for some type of high end individual licensing of
executable prior to them being shipped. And I am sure there are even
more imaginative ways to use this technique, so be sure to come back and
let us know what you used it for!!!
And as a final bonus, here is a link where you can download this entire project!
http://thenextage.com/opensource/PDFHelp.zip
Uncle Pete’s Corner is webinar series on all things WX, to watch the
watch the Uncle Pete’s corner webinar that is the companion to this
article, and many other WX related webinars go to the
WinDev US YouTube Channel and be sure to also join the
WxLive – US Communityon
Google+ to get notices about upcoming webinars. On the Google+
community you will find a active group developers discussing all things
WX.
Pete Halsted - NextAge
Pete
Halsted has been developing custom business management applications for
small to medium-sized companies, since 1987. His focus is on
client/server, distributed and cloud based development utilizing WinDev,
WebDev, and PostgreSQL. Pete is a Clarion Certified Developer with 25
years in the industry, has spoken at several Developers conferences, and
provided Developer training and mentoring on a one on one basis. He has
served companies both large and small as Project Manager, Lead
Architect, Lead Developer and Chief Technology Officer. Pete is
currently living the beach life in Biloxi, MS with his wife and dog,
enjoying the freedom provided by cloud based technologies. Pete is
available for Project Management, Custom Design, Development, Training,
and Speaking assignments. For more information please visit
www.thenextage.com or follow his blog at
www.thenextage.com/wordpress