INTELLIGENT WORK FORUMS
FOR COMPUTER PROFESSIONALS

Log In

Come Join Us!

Are you a
Computer / IT professional?
Join Tek-Tips Forums!
  • Talk With Other Members
  • Be Notified Of Responses
    To Your Posts
  • Keyword Search
  • One-Click Access To Your
    Favorite Forums
  • Automated Signatures
    On Your Posts
  • Best Of All, It's Free!

*Tek-Tips's functionality depends on members receiving e-mail. By joining you are opting in to receive e-mail.

Posting Guidelines

Promoting, selling, recruiting, coursework and thesis posting is forbidden.

Jobs

Visual Basic (Microsoft) Versions 5/6 FAQ

Package Deployment

How can I embed files into an EXE? by msc0tt
Posted: 26 Jan 04 (Edited 26 Jan 04)

Q: How can I embed files into an EXE?

A: An executable program (.EXE) doesn't appear to care if 'stuff' has been appended to the end of the binary file.  This behaviour can exploited to 'embed' files into an exe (i.e. single-file installer).  There are some commecial products available that facilitate this, plus a handful of freeware classes and routines.  In general, I will describe my own process to accomplish adding/extracting attachments within an exe.

At the end of the EXE, we append one or more attachments.  Each attachment contains the actual file attached, and a footer record describing the attachment.  So, a program with 2 attachments would be layed out as follows:
 [our EXE program]
 [attachment #1]
 [footer record for attach #1]
 [attachment #2]
 [footer record for attach #2]

The reason for the footer records is because it would be difficult (programically) to determine where the EXE ends and the attachments start.  Therefore, we work backwards from the bottom of the file, extracting the files.  Every footer record has the following format:
 filenameLength as Integer
 filename as String
 filesize as Long
 filePosition as Long
 footerID as String
 footerPosition as Long

The size of the footer is variable, since we want to have filenames of an arbitrary length.  The filePosition and footerPosition both indicate absolute byte positions in the EXE file.  The footerID string will have a fixed value, such as "ATTACHED-FILE".

Obviously, we need to get our files attached before we can extract them.

ATTACHING THE FILES:

I have a simple program I created to append files to an .EXE.  It proceeds something like this:
1. open the .EXE
2. open attachment file, read into a String var, close attachment
3. write attachment (String var) at end of .EXE
4. calculate values for footer record
5. write footer record at end of .EXE
6. IF MORE FILES to attach, go to Step 2
7. close the .EXE

EXTRACTING THE FILES:

Typically the extration routine is performed by the .EXE itself.  That's the whole point.
1. open the .EXE (himself!)
2. keep track of our file position with a Long (initially set to EOF)
3. read the last 2 fields of footer...... if it 'IS' a footer
4. look for the footerID string
5. if the data there is not the footerID string, this ain't no attachment, so exit Step 12.
6. now that we have the footerPosition, we read the top portion of the footer.
7. we've read the whole footer, so read the actual embedded file into a String var.
8. create a new file, using 'filename' from our footer
9. write the String var to this new file, and close, creating our attachment as a separate file
10. we know the size of this file, plus the size of the footer we just read, so calculate where the bottom of the next attachment footer will be (working backwards up the .EXE).
11. goto Step 3.
12. close the .EXE cause we're done

Notes:
My needs were simple.  All the files to be extracted were destined for the same directory, so I didn't keep directory information in the attachment footer.  Obviously, this footer record could be extended to include whatever you wish.  Also, of the files I needed to attach, the largest was just over 1MB, so I was comfortable slurping the whole attachment into a String.  To be truly scalable, this could be enhanced for multiple reads/writes of a maximum size per slurp.  For those unfamiliar to binary I/O and GETing a string, the number of characters read into a String var is determined by the current size of the var.  For example, to read a 5 character string into myString, you first need to initialize myString with 5 characters.  I use: "myString = String(5, chr(0))", but any 5 characters will do.

Good Luck with your own versions of this concept.
Mike Scott, Canada


---------- [ THE CODE ] ---------------------

' Project: AddFiles.VB6
Option Explicit

Private Sub Form_Load()
  Dim sFilesAdded As String
  Dim outputFile As String

  outputFile = App.Path & "\setup.exe"
  Open outputFile For Binary As #1

  Call appendFile("client.exe")
  Call appendFile("admutil.dll")
  Call appendFile("sample.dat")

  Close #1
End Sub

Private Sub appendFile(filename As String)
  Dim fileBuf As String
  Dim filenameLen As Integer
  Dim filesize As Long
  Dim filePosition As Long
  Dim footerIdent As String
  Dim footerPosition As Long

  footerIdent = "MIKES-FOOTER-IDENT"
  filenameLen = Len(filename)
  filePosition = LOF(1) + 1

  'read in file to append, slurp into a String
  Open App.Path & "\" & filename For Binary As #2
  filesize = LOF(2)
  fileBuf = String(filesize, Chr(0))
  Get #2, 1, fileBuf
  Close #2

  ' append the file
  Put #1, filePosition, fileBuf

  ' write the footer record
  footerPosition = filePosition + filesize
  Put #1, , filenameLen
  Put #1, , filename
  Put #1, , filesize
  Put #1, , filePosition
  Put #1, , footerIdent
  Put #1, , footerPosition
End Sub



---------- [ THE CODE ] ---------------------


' Project: MyInstaller.VB6
' this is the routine you would call from the main()

Option Explicit
Const destDir = "C:\Program Files\myProgram"

Private Sub extractFiles()
  Dim footerIdentPosition As Long
  Dim inputFile As String
  Dim footerIdentTag As String

  Dim fileBuf As String
  Dim filenameLen As Integer
  Dim filename As String
  Dim filesize As Long
  Dim filePosition As Long
  Dim footerIdent As String
  Dim footerPosition As Long
   
  footerIdentTag = "MIKES-FOOTER-IDENT"

  inputFile = App.Path & "\" & App.EXEName & ".exe"
  Open inputFile For Binary As #1

  footerIdentPosition = LOF(1) - 21
  footerIdent = footerIdentTag
  Get #1, footerIdentPosition, footerIdent

  Do While (footerIdent = footerIdentTag)
   
    ' read the file footer record
    Get #1, , footerPosition
    Get #1, footerPosition, filenameLen
    filename = String(filenameLen, Chr(0))
    Get #1, , filename
    Get #1, , filesize
    Get #1, , filePosition
      
    ' read the file
    fileBuf = String(filesize, Chr(0))
    Get #1, filePosition, fileBuf
      
    ' create the premanent file
    Open destDir & "\" & filename For Binary As #2
    Put #2, 1, fileBuf
    Close #2
      
    ' check for next (earlier) file attachment
    footerIdentPosition = filePosition - 22
    Get #1, footerIdentPosition, footerIdent
  Loop
   
  Close #1 ' our input .EXE file
End Sub


Back to Visual Basic (Microsoft) Versions 5/6 FAQ Index
Back to Visual Basic (Microsoft) Versions 5/6 Forum

My Archive

Resources

Close Box

Join Tek-Tips® Today!

Join your peers on the Internet's largest technical computer professional community.
It's easy to join and it's free.

Here's Why Members Love Tek-Tips Forums:

Register now while it's still free!

Already a member? Close this window and log in.

Join Us             Close