Author Topic: add multiple files to an EXE file  (Read 902 times)

0 Members and 1 Guest are viewing this topic.

Offline Petr

  • Forum Resident
  • Posts: 1580
  • The best code is the DNA of the hops.
add multiple files to an EXE file
« on: December 26, 2018, 11:19:56 AM »
Yesterday, I and Steve discussed about the possibility of adding more than one file to the end of an EXE file. I went to sleep with a good feeling as I did it all right ... I woke up in the morning and realized how stupid I do it all! It was bad!  So here is the tried and tested procedure. First, wrap the files you want to add to the EXE into the PMF file (this is my own uncompressed file format) and then add this PMF file to the end of the EXE file. This is actually the same as the MP3 file used by Steve. The difference is that PMF using the attached SUB can carry virtually unlimited number of files of any type.

So here are all SUBs you need for it.

Code: QB64: [Select]
  1.  
  2. DIM SHARED vystup AS STRING 'output PMF file name
  3.  
  4. 'how to add pmf to project:
  5.  
  6. '1] write bas program
  7. '2] create pmf file using DO_PMF, add files which need your program to PMF, this create potocol.txt file
  8. '3] add ExtractPMF SUB and Extract_From_EXE SUB to your BAS file
  9. '4] insert row which call extracting function   ->  Extract_From_EXE offset (offset is writed am end in file protocol.txt and printed also to screen in step 2) , EXEname (name of your program)
  10. '5] Compile to EXE (NOT RUN!)
  11. '6] in new IDE window run SUB Insert_PMF_to_EXE exe filename$, pmf filename$
  12.  
  13. 'DONE. Run your upgraded EXE file.
  14.  
  15.  
  16.  
  17.  
  18.  
  19.  
  20. SUB DO_PMF 'select files and add it to PMF container
  21.     DIM pocet AS LONG
  22.     INPUT "Multirecorder. Record more files to one. How many files for record? ", pocet
  23.     IF pocet < 1 THEN PRINT "Your choice is recording "; pocet; "files to one file. ": PRINT "Contact Chuck Norris for this operation.": SLEEP 3: END
  24.     DIM fils(pocet) AS STRING
  25.     DIM recs(pocet) AS LONG
  26.     FOR loud = 1 TO pocet
  27.         PRINT "Input file name - file"; loud: INPUT fils(loud)
  28.     NEXT
  29.  
  30.     jmeno:
  31.     INPUT "Input OUTPUT filename:"; vystup$
  32.     IF _FILEEXISTS(vystup$) THEN BEEP: PRINT "File already exists.": GOTO jmeno
  33.     IF INSTR(1, vystup$, LCASE$(".pmf")) = 0 THEN vystup$ = vystup$ + ".pmf"
  34.  
  35.  
  36.     c = FREEFILE
  37.  
  38.     OPEN vystup$ FOR OUTPUT AS #c: CLOSE #c: OPEN vystup$ FOR BINARY AS #c
  39.     identity$ = "Petr's MultiFile"
  40.     PUT #c, 1, identity$
  41.     PUT #c, , pocet: SEEK #c, 21 + pocet * 4
  42.     FOR rec = 1 TO pocet
  43.         d = FREEFILE
  44.         OPEN fils(rec) FOR BINARY AS #d
  45.         e$ = SPACE$(LOF(d))
  46.         GET #d, , e$
  47.         PUT #c, , e$
  48.         recs(rec) = SEEK(c)
  49.         CLOSE #d
  50.     NEXT rec
  51.  
  52.     SEEK #c, 21
  53.     g = FREEFILE
  54.     OPEN "protocol.txt" FOR OUTPUT AS #g
  55.     FOR delky = 1 TO pocet
  56.         PUT #c, , recs(delky)
  57.         PRINT #g, recs(delky)
  58.         PRINT "Saving...("; delky; ") -"; recs(delky)
  59.     NEXT
  60.     SEEK #c, LOF(c) + 1
  61.  
  62.     FOR names = 1 TO pocet
  63.         NL$ = MKI$(LEN(fils(names)))
  64.         PUT #c, , NL$
  65.     NEXT names
  66.  
  67.     FOR names = 1 TO pocet
  68.         jm$ = SPACE$(LEN(fils(names)))
  69.         jm$ = fils(names)
  70.         PUT #c, , jm$
  71.         '    PRINT fils(names)
  72.     NEXT names
  73.  
  74.  
  75.  
  76.     PRINT #g, "For using file "; vystup$; "with SUB Extract_From_EXE use this value: "; LOF(c)
  77.     CLOSE #g
  78.     PRINT "Completed. Lenght for rewriting back are writed in protocol.txt, parameter OFFSET for SUB Extract_From_EXE is: "; LOF(c)
  79.     CLOSE #c
  80.  
  81.  
  82.  
  83. SUB Insert_PMF_to_EXE (exe AS STRING, pmf AS STRING)
  84.     IF _FILEEXISTS(exe$) THEN
  85.         f = FREEFILE
  86.         OPEN exe$ FOR BINARY AS #f
  87.         PRINT "EXE file found, size "; LOF(f)
  88.     ELSE
  89.         PRINT "EXE file not found": SLEEP 3: SYSTEM
  90.     END IF
  91.  
  92.     IF _FILEEXISTS(pmf) THEN
  93.         p = FREEFILE
  94.         OPEN pmf$ FOR BINARY AS #p
  95.         PRINT "PMF file found, size "; LOF(p)
  96.     ELSE
  97.         PRINT "PMF file not found": SLEEP 3: SYSTEM
  98.     END IF
  99.  
  100.     in$ = SPACE$(LOF(p))
  101.     GET #p, , in$
  102.     SEEK #f, LOF(f)
  103.     PUT #f, , in$
  104.  
  105.     CLOSE #e
  106.     CLOSE #p
  107.  
  108.     PRINT "EXE file upgraded."
  109.  
  110.  
  111.  
  112.  
  113.  
  114.  
  115. SUB Extract_From_EXE (offset AS _UNSIGNED LONG, EXEname AS STRING) 'EXEname is bas file name after saving as EXE
  116.  
  117.     g = FREEFILE
  118.     OPEN "internalPMF.pmf" FOR OUTPUT AS #g: CLOSE #g
  119.     g = FREEFILE
  120.     OPEN "internalPMF.pmf" FOR BINARY AS #g
  121.     f = FREEFILE
  122.     OPEN EXEname FOR BINARY AS #f
  123.     size$ = SPACE$(offset)
  124.     SEEK #f, LOF(f) - offset + 1
  125.     GET #f, , size$
  126.     PUT #g, , size$
  127.     CLOSE #g
  128.     CLOSE #f
  129.     ExtractPMF "internalPMF.pmf"
  130.     _DELAY .5
  131.     KILL "internalPMF.pmf"
  132.  
  133.  
  134. SUB ExtractPMF (Vystup AS STRING) ' here insert PMF file name for extracting files
  135.     PRINT "Extracting files from "; Vystup$
  136.     TYPE head
  137.         identity AS STRING * 16
  138.         much AS LONG
  139.     END TYPE
  140.     DIM head AS head
  141.     e = FREEFILE
  142.     OPEN Vystup$ FOR BINARY AS #e
  143.     GET #e, , head
  144.     IF head.identity = "Petr's MultiFile" THEN PRINT "Head PASS" ELSE PRINT "Head Failure": SLEEP 3: END
  145.     PRINT "Total records in file:"; head.much
  146.     DIM starts(head.much) AS LONG
  147.  
  148.     FOR celek = 1 TO head.much
  149.         GET #e, , starts(celek)
  150.     NEXT
  151.  
  152.     SEEK #e, 21 + head.much * 4 ' start DATA area
  153.     FOR total = 1 TO head.much
  154.         IF total = 1 THEN velikost& = starts(1) - (21 + head.much * 4) ELSE velikost& = starts(total) - starts(total - 1)
  155.         record$ = SPACE$(velikost&)
  156.         GET #e, , record$
  157.         i = FREEFILE
  158.         jmeno$ = "$Ext" + LTRIM$(STR$(total))
  159.         OPEN jmeno$ FOR OUTPUT AS #i: CLOSE #i: OPEN jmeno$ FOR BINARY AS #i
  160.         PUT #i, , record$
  161.         CLOSE #i
  162.     NEXT total
  163.  
  164.     DIM NamesLenght(head.much) AS INTEGER
  165.     FOR NameIt = 1 TO head.much
  166.         GET #e, , NamesLenght(NameIt)
  167.     NEXT NameIt
  168.  
  169.     CLOSE #i
  170.     FOR Name2 = 1 TO head.much
  171.         s$ = SPACE$(NamesLenght(Name2))
  172.         GET #e, , s$
  173.         jm$ = "$Ext" + LTRIM$(STR$(Name2))
  174.         erh:
  175.         IF _FILEEXISTS(s$) THEN
  176.             BEEP: INPUT "Warnig! Extracted file the same name already exists!!!! (O)verwrite, (R)ename or (E)xit? "; er$
  177.             SELECT CASE LCASE$(er$)
  178.                 CASE "o": KILL s$: NAME jm$ AS s$
  179.                 CASE "r": INPUT "Input new name"; s$: GOTO erh
  180.                 CASE "e": SYSTEM
  181.             END SELECT
  182.         ELSE
  183.             NAME jm$ AS s$
  184.         END IF
  185.     NEXT Name2
  186.     CLOSE #e
  187.     PRINT "All ok."
  188.  

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3572
    • Steve’s QB64 Archive Forum
Re: add multiple files to an EXE file
« Reply #1 on: December 26, 2018, 11:43:15 AM »
You might want to add a CASE ELSE to the error handler:

CASE ELSE: PRINT “INVALID INPUT.  “: GOTO erh

;)

Edit:  Add one warning from me — This file extraction method may not play nice with certain anti viruses on the market.  It also may not work properly in certain folders (such as under Program Files).

The first is a case of an antivirus seeing it extracting parts from itself and flagging the process as a PUP (potentially unwanted program), or a virus attempting to replicate itself.  The EXE you finish with may need whitelisting to perform properly.

The second common glitch is just OS permissions.  Windows expects certain things to extract in certain places (usually the hidden App Data folder), and may not allow write permissions in all folders/sub folders, causing the program to fail.

Be aware of these 2 issues when attaching files to your EXE.  ;)
« Last Edit: December 26, 2018, 11:53:22 AM by SMcNeill »
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline Petr

  • Forum Resident
  • Posts: 1580
  • The best code is the DNA of the hops.
Re: add multiple files to an EXE file
« Reply #2 on: December 26, 2018, 07:08:22 PM »
Hi Steve. Thank you for the warning. Perhaps the file permissions can be set over powershell, with the path where file extraction will occur should also not be a problem, I think, we can use ENVIRON$ to set the correct path. Even...  well, I will not even write it here... You surely know what I mean.