Free Extractor |
This is a free open source tool which can be used to create simple "bootstrapper exe programs" containing your msi and potentially other files.
The program takes a zip file and can make a self extracting executable which can also launch a process. It is available from "http://freeextractor.sourceforge.net/". Choose the "command line" download for example "MakeSFX.exe - Optional Command Line Version, v1.44 (30 kb)".
The "MakeSFX.exe" download needs to be placed into a directory which is listed by the "PATH" environment variable.
I have created a header file which simply needs to be included (see the header for available options) after normal MAKEMSI headers and it will build the executable.
What Does the Generated EXE do? |
Example of using the Framework |
This is a version of "TryMe.MM" where the only important changes are the insertion of 2 lines, the first to #define an option and the "#include" to invoke the framework:
#include "ME.MMH" ;;Load MAKEMSI #define EXE_MAKESFX.EXE_SWITCHES_DEBUG /openexplorerwindow ;;Open at extracted files #include "FreeExtractor.MMH" ;;Build EXE from generated MSI ;--- Normal MSI stuff... --- <$DirectoryTree Key="INSTALLDIR" Dir="c:\program files\TryMe (makemsi sample)\<$MAKEMSI_MM_BASENAME>" CHANGE="\" PrimaryFolder="Y"> <$Files "*.mm" DestDir="INSTALLDIR">
MakeSx.exe /? |
MakeSFX v1.44 (Mar 19 2001) Converts a zip file into a 32-bit GUI Windows self-extractor. ® Example usage ¯ makesfx.exe /zip="source.zip" /sfx="output.exe" [/title="Your Title"] [/website="http://www.example.com"] [/intro="This is a test self extractor"] [/defaultpath="$desktop$\My Files"] [/autoextract] [/openexplorerwindow] [/shortcut="$desktop$\Program Shortcut.lnk|$targetdir$\Program.exe] [/delete] [/icon="MyIcon.ico"] [/overwrite] [/?] ® Self-extractor options ¯ /zip="file.zip" The source zip file (Required) /sfx="out.exe" The output self-extractor (Required) /title="Your Title" The user-friendly name /website="http://www.example.com" The embedded URL /intro="This is the intro." The splash screen intro text /icon="MyIcon.ico" Changes the SFX icon. This must be a 2,238 byte, 32x32, 256 color icon. /exec="setup.exe" Command to execute after extraction /defaultpath="$desktop$\Folder" Default extraction path. Valid variables are: $desktop$, $temp$, $programfiles$, $windir$, $targetdir$ and $sysdir$. You may also hard-code a path. /autoextract Automatically extract the contents to the default path. Don't prompt the user. /openexplorerwindow Open the target directory in Windows Explorer. /delete Deletes extracted files after program specified in /exec is completed. /shortcut="shortcut.lnk|target.ext" Creates a shortcut to target. Each may include scriptable paths. ® MakeSFX Options ¯ /overwrite Overwrite the output EXE, if it exists. /? Show this help message ® Path Variables ¯ The following variables can be used in paths: $desktop$ The user's desktop folder $programfiles$ Computer's program files folder $temp$ System Temp Directory $windir$ Windows directory (i.e. "c:\windows") $sysdir$ Windows System Directory (i.e. "c:\windows\system") $curdir$ The directory where the self-extractor is run from $targetdir$ The extraction directory $favorites$ Internet Explorer Favorites Folder $quicklaunch$ Quick Launch Directory (IE4+ only) $startup$ The User's "Startup" Folder $startmenu$ The User's "Programs" Folder in the Start Menu MakeSFX is open source. Visit http://www.disoriented.com for updates.
FreeExtractor.MMH |
;---------------------------------------------------------------------------- ; ; MODULE NAME: FreeExtractor.MMH ; ; $Author: USER "Dennis" $ ; $Revision: 1.2 $ ; $Date: 15 Sep 2007 18:31:14 $ ; $Logfile: C:/DBAREIS/Projects.PVCS/Win32/MakeMsi/FreeExtractor.MMH.pvcs $ ; COPYRIGHT: (C)opyright Dennis Bareis, Australia, 2003 ; All rights reserved. ; ; This headet is NOT automatically included by MAKEMSI however you can ; #include it yourself to indicate that you want to build an EXE from ; the generated MSI using the open source tool "FreeExtractor", available ; from "http://www.disoriented.com/FreeExtractor/". ; ; You also need to put the "MakeSFX.EXE" tool into a directory where MAKEMSI ; can find it (such as a directory in the "PATH"). The download I tested with ; was: ; MakeSFX.exe - Optional Command Line Version, v1.44 (30 kb) ; ; The tool creates an EXE from a ZIP file and then launches a program/file, ; a limitation in this tool means that the MSI needs to be launched from a ; batch file and this will briefly flash up a "black window". ; ; All options are set via macros prior to the inclusion of this header file. ; ; One reason for using this is that the generated product can be significantly ; smaller (TryMe.MSI of 152K versus TryMe.EXE of 83K) and also that it may ; be bundling many files (this not yet supported). ; ; No command line switches are supported, it is simply a matter of letting ; the install start and copying the extracted files elsewhere. ;---------------------------------------------------------------------------- #NextId #NextId LOCK "FreeExtractor.MMH" ;---------------------------------------------------------------------------- ;--- Constants -------------------------------------------------------------- ;---------------------------------------------------------------------------- #define VERSION_FREEEXTRACTOR 07.251 ;---------------------------------------------------------------------------- ;--- Options ---------------------------------------------------------------- ;---------------------------------------------------------------------------- #define? EXE_FULL_EXE_NAME <$MSI_MSINAME $$FilePart:withoutextn>.EXE ;;Name and location of EXE being created #define? EXE_ICON ;;If non-blank name of 2,238 byte, 32x32, 256 color icon #define? EXE_BUILD_WHICH_HOOK ONEXIT_AFTER_MSI_BUILT_AND_VALIDATED ;;When will we create the EXE? #define? EXE_MAKESFX.EXE_EXTRACT_PATH_ROOT %Temp% ;;Relative paths are relative to the runtime EXE dir #define? EXE_MAKESFX.EXE_EXTRACT_PATH_REL2ROOT MSI2EXE\<$ProdInfo.ProductName>\<$ProductVersion> ;;Try to prevent possible overlap!!! #define? EXE_MAKESFX.EXE_EXTRACT_PATH_KNOWN_BUGGY_CHARS () ;;Cause EXE to fail to successfully start lancher #define? EXE_TMP_DIR <$MAKEMSI_OTHER_DIR>\MAKESFX.EXE ;;Want "working" or "intermediate" files to go here #define? EXE_INSTALL_LAUNCHER_NAME INSTALL.BAT ;;Name of the launcher we need to overomelimitations in "FreeExtractor" #define? EXE_EXTRA_FILES ;;List of zero or more files (delimitered by ";" etc) #define? EXE_ZIPOPTIONS -8 -o -j ;;Zip options #define? EXE_STORE .zip;.cab ;;Already compressed and/or time consuming (-9 must not be used or this will have no effect) #( '<?NewLine>' #define EXE_LAUNCHER_FILE_CONTENTS ;--- Just invoke msi and exit ------------------------------------------- @cls @start "" "<$MSI_MSINAME $$FilePart:NAME>" @exit #) #if ['<$EXE_ICON $$ISBlank>' = 'Y'] #define @@EXE_MAKESFX.EXE_SWITCHES_EXEICON ;;Do nothing (use default icon) #elseif #define @@EXE_MAKESFX.EXE_SWITCHES_EXEICON /ICON="<$EXE_ICON>" #endif #( ' ' #define? EXE_MAKESFX.EXE_SWITCHES_MAIN /zip="<$EXE_FULL_ZIPFILE_NAME>" ;;Name of ZIP containing files /SFX="<$EXE_FULL_EXE_NAME>" ;;Name of EXE to build /EXEC="$targetdir$\<$EXE_INSTALL_LAUNCHER_NAME>" ;;What 'launcher" does the EXE execute? /defaultpath="<??@@EXE_MAKESFX.EXE_EXTRACT_PATH>" ;;MakeSFX.EXE bug(s) restrict allowable character set #) #( ' ' #define? EXE_MAKESFX.EXE_SWITCHES_GUI /autoextract ;;Automatically extract the imbedded (and zipped) files (/NoGui must also be used) /nogui ;;No GUI presented to users /overwrite ;;Ovrwrite any files at the "defaultpath" location #) #( ' ' #define? EXE_MAKESFX.EXE_SWITCHES_DEBUG ;/openexplorerwindow ;;Open explorer at extracted location #) #define? EXE_FULL_ZIPFILE_NAME <$EXE_TMP_DIR>\ExeContents.zip #define? EXE_FULL_LAUNCHER_NAME <$EXE_TMP_DIR>\<$EXE_INSTALL_LAUNCHER_NAME> #define? EXE_FULL_MAKESFX.EXE_OUTPUT_NAME <$EXE_TMP_DIR>\BuildExe.txt #define? EXE_MESSAGE_INITIALIZATION Scheduling EXE build using FreeExtractor (version <$VERSION_FREEEXTRACTOR>) #define? EXE_MESSAGE_STARTING Building EXE from generated MSI (using FreeExtractor) #define? EXE_MESSAGE_CREATING_ZIP Creating the ZIP for imbedding in the EXE #define? EXE_MESSAGE_CREATING_EXE Now creating EXE from the zip #define? EXE_MESSAGE_ENDING EXE successfully generated. ;---------------------------------------------------------------------------- ;--- INITIALIZATION (scheduling etc) ---------------------------------------- ;---------------------------------------------------------------------------- #DefineRexx '' ;--- Remove any preexisting EXE from a previous build ------------------- call FileDelete '<$EXE_FULL_EXE_NAME>'; #DefineRexx #define @@FreeExtractorExe MakeSfx.exe <$GetFullBuildTimeFileName RcVar="@@FullMakeSfxExeName" Macro="EXE_MAKESFX.EXE" File="<$@@FreeExtractorExe>" MustExist="N"> #if [@@FullMakeSfxExeName = ''] ;--- Report error ------------------------------------------------------- #error ^Could not find "<$@@FreeExtractorExe>"!{NL}Please download from "http://www.disoriented.com/FreeExtractor/"^ #endif #( ;--- Code we wish to execute early in build (but after logging locations known) --- #define @@BuildExe ;--- Intro -------------------------------------------------------------- #if ['<$EXE_MESSAGE_STARTING $$ISBLANK>' = 'N'] #info ^<$EXE_MESSAGE_STARTING>^ #endif ;--- Build the launcher ------------------------------------------------- #output "<$EXE_FULL_LAUNCHER_NAME>" ASIS <$EXE_LAUNCHER_FILE_CONTENTS> #output ;--- Build the zip file which will be imbedded in the EXE --------------- #evaluate ^^ ^<$@@BuildZipForExe>^ ;--- Now Build the EXE -------------------------------------------------- #evaluate ^^ ^<$@@MakeExtractPathSafeFromMakeSfxExeBug>^ #evaluate ^^ ^<$@@BuildExeFromZip>^ #if ['<$EXE_MESSAGE_ENDING $$ISBLANK>' = 'N'] #info ^<$EXE_MESSAGE_ENDING>^ #endif #) #if ['<$EXE_MESSAGE_INITIALIZATION $$ISBLANK>' = 'N'] #info ^<$EXE_MESSAGE_INITIALIZATION>^ #endif <$HookInto "<$EXE_BUILD_WHICH_HOOK>" Before="@@BuildExe"> ;---------------------------------------------------------------------------- ;--- Working Macros --------------------------------------------------------- ;---------------------------------------------------------------------------- #DefineRexx '@@BuildZipForExe' @@ZipDir = '<$EXE_TMP_DIR>'; call MakeDirectoryTree @@ZipDir; @@TmpZipFile = '<$EXE_FULL_ZIPFILE_NAME>' @@Sample.1 = '<$EXE_TMP_DIR>\<$EXE_INSTALL_LAUNCHER_NAME>'; @@Sample.2 = '<$MSI_MSINAME>'; @@Cnt = 2; @@SemiDelListOrig = '<$EXE_EXTRA_FILES>'; <$Rexx2ConvertDelimiters RxVar="@@SemiDelListOrig" ToDelChar=";"> @@SemiDelList = @@SemiDelListOrig; do while @@SemiDelList <> '' ;--- Get next file ignore "empty" files ----------------------------- parse var @@SemiDelList @@OneFile ';' @@SemiDelList; @@OneFile = strip(@@OneFile); ;;Remove any leading or trailing spaces (if required user should double quote) if @@OneFile <> '' then do ;--- Allow value to be quoted (allows for spaces etc) ----------- if left(@@OneFile, 1) = '"' then @@OneFile = substr(@@OneFile, 2, length(@@OneFile)-2); ;;Remove leading and trailing double quotes. ;--- Now lets check file existance here (will be checked later but better error message possible here!) --- if FileQueryExists(@@OneFile) = '' then do #( call error 'The file "' || @@OneFile || '" doesn''t exist!' , ,'This "extra" file was specified by the "EXE_EXTRA_FILES" macro which contained:' , ,@@SemiDelListOrig #) end; ;--- File exists so add to the list ----------------------------- @@Cnt = @@Cnt + 1; @@Sample.@@Cnt = @@OneFile; end; end; @@Sample.0 = @@Cnt; <$RexxZipUpFiles List="@@Sample" ZipFileExp=^@@TmpZipFile^ InfoMsgExp=^'<$EXE_MESSAGE_CREATING_ZIP>'^ ZipOptions=^<$EXE_ZIPOPTIONS>^ Store=^<$EXE_STORE>^> #DefineRexx #DefineRexx '@@MakeExtractPathSafeFromMakeSfxExeBug' @@RelPath = '<$EXE_MAKESFX.EXE_EXTRACT_PATH_REL2ROOT>'; @@BadChars = '<$EXE_MAKESFX.EXE_EXTRACT_PATH_KNOWN_BUGGY_CHARS>'; @@RelPath = translate(@@RelPath,, @@BadChars, '_'); @@EXE_MAKESFX.EXE_EXTRACT_PATH = '<$EXE_MAKESFX.EXE_EXTRACT_PATH_ROOT $$DEL:\>' || @@RelPath; #DefineRexx #DefineRexx '@@BuildExeFromZip' @@Msg = '<$EXE_MESSAGE_CREATING_EXE>'; if @@Msg <> '' then call Info @@Msg; @@Exe = '<$EXE_FULL_EXE_NAME>'; @@Output = '<$EXE_FULL_MAKESFX.EXE_OUTPUT_NAME>'; call FileDelete @@Exe; @@Cmd = '"<??@@FullMakeSfxExeName>" <$EXE_MAKESFX.EXE_SWITCHES_MAIN><$@@EXE_MAKESFX.EXE_SWITCHES_EXEICON $$SPCPLUS><$EXE_MAKESFX.EXE_SWITCHES_GUI $$SPCPLUS><$EXE_MAKESFX.EXE_SWITCHES_DEBUG $$SPCPLUS>'; call FileDelete @@Output; call LineOut @@Output, copies('#', 78) call LineOut @@Output, @@Cmd; call LineOut @@Output, copies('#', 78) call LineOut @@Output, '' call LineOut @@Output, '' call FileClose @@Output; @@Cmd = @@Cmd || ' >>"' || @@Output || '" <$Stderr2Out>'; @@Cmd = 'cmd.exe /c "' || @@Cmd || '"'; ;;Windows crap... call AddressCmd @@Cmd, '<$EXE_FULL_MAKESFX.EXE_OUTPUT_NAME>'; if FileQueryExists(@@Exe) = '' then do <$RexxDebugViewFile FileVar="@@Output">; call error 'The EXE file "' || @@Exe || '" wasn''t created!'; end; #DefineRexx ;---------------------------------------------------------------------------- ;--- Make sure we record details about this header -------------------------- ;---------------------------------------------------------------------------- <$SourceFile Version="<$VERSION_FREEEXTRACTOR>"> #NextId UNLOCK "FreeExtractor.MMH"