Instructions are in the program, no need for a help file.
It will take a folder of files, allow adding some more, then lump everything into a self extracting .EXE file for installation.
This installer Generator can be used with ANY EXE file
This was my final version.
Code: Select all
'Installer Generator v3.24 for Just Basic v2.0 and Liberty Basic v4.5.1 and Pro projects
' xxgeek July 2026
nomainwin
q$ = chr$(34)
WindowWidth = 600
WindowHeight = 560
UpperLeftX = (DisplayWidth - WindowWidth) / 2
UpperLeftY = (DisplayHeight - WindowHeight) / 2
groupbox #main.cfgGroup, "Configuration Settings", 15, 10, 555, 165
statictext #main.lbl1, "1. Your Source Folder\EXE File:", 10, 38, 190, 20
textbox #main.txtSourceFolder, 205, 30, 260, 24
button #main.btnBrowseFolder, "Browse...", [browseSourceFolder], ul, 475, 29, 80, 25
statictext #main.lbl2, "Output Installer EXE Filename:", 25, 70, 180, 20
textbox #main.txtFinalExe, 205, 65, 150, 24
statictext #main.lbl3, "Your Program's EXE Filename:", 25, 103, 180, 20
textbox #main.txtTargetExe, 205, 100, 150, 24
statictext #main.lbl4, "Installed Program's Shortcut Name:", 25, 138, 180, 40
textbox #main.txtShortcut, 205, 135, 150, 24
button #main.btnDropZone, "2 - Add Extra Files and Folders", [openDropZone], ul, 45, 185, 230, 35
button #main.btnCompile, "3 - Compile Application Installer", [buildInstaller], ul, 300, 185, 230, 35
statictext #main.title, "I n s t a l l e r", 395, 80, 160, 40
statictext #main.title2, "G e n e r a t o r", 385, 120, 180, 40
texteditor #main.log, 15, 235, 555, 225
checkbox #main.overWrite, "Over-Write Any Existing Installer of Same Name";folderName$;"-Installer.exe", [ovWrite], [novWrite], 25, 470, 285, 20
open "Single EXE File Installer Compiler for JB, LB and LB Pro Projects" for window as #main
print #main, "trapclose [quit]"
#main "font Times New Roman 10 bold"
#main.log, "!font arial 10 bold"
#main.title2, "!font Times New Roman 20 bold"
#main.title, "!font Times New Roman 20 bold"
print #main.log, "System initialized."
print #main.log, ""
print #main.log, "Step #1 - 'Browse' to and Select Your Projects EXE File"
print #main.log, " (use generated defaults until familiar with Installer Generator - editing is allowed)"
print #main.log, ""
print #main.log, "Step #2 - Use the 'Add Extra Files and Folders' Button - If Desired, not Necessary"
print #main.log, ""
print #main.log, "Step #3 - Use the 'Compile Application Installer' Button."
print #main.log, ""
print #main.log, "Step #4 - Wait Until Windows Explorer Opens Up With Your Installer.exe Selected"
print #main.log, ""
print #main.log, "System Ready."
print #main.btnBrowseFolder, "!setfocus"
wait
[browseSourceFolder]
print #main.log, "SELECT YOUR PROJECT EXE FILE..."
filedialog "SELECT YOUR PROJECT EXE FILE", "*.exe", assetFile$
if assetFile$ <> "" then
derivedFolder$ = ""
lastSlash = 0
for i = len(assetFile$) to 1 step -1
if mid$(assetFile$, i, 1) = "\" then
lastSlash = i
derivedFolder$ = left$(assetFile$, i - 1)
exit for
end if
next i
if right$(derivedFolder$, 1) = ":" then derivedFolder$ = derivedFolder$ ; "\"
folderName$ = ""
if lastSlash > 0 then
prevSlash = 0
for i = (lastSlash - 1) to 1 step -1
if mid$(derivedFolder$, i, 1) = "\" then
prevSlash = i
exit for
end if
next i
if prevSlash > 0 then
folderName$ = right$(derivedFolder$, len(derivedFolder$) - prevSlash)
else
if mid$(derivedFolder$, 2, 2) = ":\" then
folderName$ = right$(derivedFolder$, len(derivedFolder$) - 3)
else
folderName$ = derivedFolder$
end if
end if
end if
if folderName$ = "" then folderName$ = "App"
upperShortcut$ = upper$(folderName$)
print #main.txtSourceFolder, derivedFolder$
print #main.txtFinalExe, folderName$;"-Installer.exe"
print #main.txtTargetExe, folderName$;".exe"
print #main.txtShortcut, upperShortcut$
print #main.log, "Configuration populated automatically."
print #main.btnDropZone, "!setfocus"
else
print #main.log, "!cls"
print #main.log, "Browse canceled."
print #main.btnBrowseFolder, "!setfocus"
end if
wait
[openDropZone]
workPath$ = DefaultDir$
if right$(workPath$, 1) <> "\" then workPath$ = workPath$ ; "\"
stagingFolder$ = workPath$ ; "StagingTemp"
print #main.log, "!cls"
print #main.log, "Opening Multi-Drop Files/Folders Staging Panel..."
open workPath$ ; "stager.ps1" for output as #psOut
print #psOut, "Add-Type -AssemblyName System.Windows.Forms"
print #psOut, "$form = New-Object Windows.Forms.Form"
print #psOut, "$form.Text = 'Asset Staging Drop Zone'"
print #psOut, "$form.Width = 480; $form.Height = 290"
print #psOut, "$form.StartPosition = 'CenterScreen'"
print #psOut, "$form.TopMost = $true"
print #psOut, "$form.AllowDrop = $true"
' Colors
print #psOut, "$normalColor = 'LightGreen'"
print #psOut, "$flashColor = 'Cyan'"
' Label
print #psOut, "$label = New-Object Windows.Forms.Label"
print #psOut, "$label.Text = ' DRAG AND DROP FILES AND FOLDERS HERE'"
print #psOut, "$label.Location = New-Object System.Drawing.Point(15, 15)"
print #psOut, "$label.Size = New-Object System.Drawing.Size(430, 130)"
print #psOut, "$label.TextAlign = 'MiddleCenter'"
print #psOut, "$form.BackColor = $normalColor"
print #psOut, "$label.BackColor = 'Yellow'"
print #psOut, "$label.Font = New-Object System.Drawing.Font('Segoe UI', 10, [System.Drawing.FontStyle]::Bold)"
print #psOut, "$form.Controls.Add($label)"
' Button
print #psOut, "$btn = New-Object Windows.Forms.Button"
print #psOut, "$btn.Text = 'Finished Adding File/Folders'"
print #psOut, "$btn.Location = New-Object System.Drawing.Point(140, 175)"
print #psOut, "$btn.Size = New-Object System.Drawing.Size(180, 35)"
print #psOut, "$btn.Add_Click({ Out-File -FilePath '" ; workPath$ ; "stage_done.txt' -InputObject 'done'; $form.Close() })"
print #psOut, "$form.Controls.Add($btn)"
' FLASH TIMER: This triggers the reset after a flash
print #psOut, "$flashTimer = New-Object Windows.Forms.Timer"
print #psOut, "$flashTimer.Interval = 300"
print #psOut, "$flashTimer.Add_Tick({ "
print #psOut, " $form.BackColor = $normalColor"
print #psOut, " $flashTimer.Stop()"
print #psOut, "})"
' Drag Logic
print #psOut, "$form.Add_DragEnter({ if ($_.Data.GetDataPresent([Windows.Forms.DataFormats]::FileDrop)) { $_.Effect = 'Copy' } })"
print #psOut, "$form.Add_DragDrop({ "
print #psOut, " $files = $_.Data.GetData([Windows.Forms.DataFormats]::FileDrop)"
print #psOut, " $dest = '" ; stagingFolder$ ; "'"
print #psOut, " if (!(Test-Path $dest)) { New-Item -ItemType Directory -Path $dest | Out-Null }"
print #psOut, " $listFile = '" ; workPath$ ; "dropped_list.txt'"
print #psOut, " foreach ($file in $files) {"
print #psOut, " if (Test-Path $file -PathType Container) {"
print #psOut, " robocopy.exe " ; q$ ; "$file" ; q$ ; " " ; q$ ; "$dest\$(Split-Path $file -Leaf)" ; q$ ; " /E /IS /IT /R:0 /W:0"
print #psOut, " Add-Content -Path $listFile -Value $(Split-Path $file -Leaf)"
print #psOut, " } else {"
print #psOut, " robocopy.exe " ; q$ ; "$(Split-Path $file -Parent)" ; q$ ; " " ; q$ ; "$dest" ; q$ ; " " ; q$ ; "$(Split-Path $file -Leaf)" ; q$ ; " /IS /IT /R:0 /W:0"
print #psOut, " Add-Content -Path $listFile -Value $(Split-Path $file -Leaf)"
print #psOut, " }"
print #psOut, " }"
' Trigger the flash
print #psOut, " $form.BackColor = $flashColor"
print #psOut, " $flashTimer.Start()"
print #psOut, " $label.Text = 'Items processed! Drop more items, or click below when finished.'"
print #psOut, "})"
print #psOut, "[Windows.Forms.Application]::Run($form)"
close #psOut
if fileExists(workPath$, "stage_done.txt") > 0 then kill workPath$ ; "stage_done.txt"
if fileExists(workPath$, "dropped_list.txt") > 0 then kill workPath$ ; "dropped_list.txt"
run "powershell.exe -NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File " ; q$ ; workPath$ ; "stager.ps1" ; q$, hide
[waitForStager]
scan
if fileExists(workPath$, "stage_done.txt") > 0 then goto [stagerFinished]
timer 250, [stageDelay]
wait
[stageDelay]
timer 0
goto [waitForStager]
[stagerFinished]
if fileExists(workPath$, "stager.ps1") > 0 then kill workPath$ ; "stager.ps1"
if fileExists(workPath$, "stage_done.txt") > 0 then kill workPath$ ; "stage_done.txt"
print #main.log, "Drop zone completed safely."
if fileExists(workPath$, "dropped_list.txt") > 0 then
print #main.log, "Staged Items Added:"
open workPath$ ; "dropped_list.txt" for input as #listIn
[readLogLoop]
if eof(#listIn) <> 0 then goto [readLogDone]
line input #listIn, entry$
if instr(entry$, ".") <> 0 then print #main.log, "File - ";entry$ else print #main.log, "Folder - [";entry$;"]"
goto [readLogLoop]
[readLogDone]
close #listIn
kill workPath$ ; "dropped_list.txt"
print #main.log, ""
print #main.log, " ###### READY TO COMPILE THE INSTALLER ######"
end if
print #main.btnCompile, "!setfocus"
wait
[buildInstaller]
print #main.txtSourceFolder, "!contents? sourceAppFolder$"
sourceAppFolder$ = trim$(sourceAppFolder$)
print #main.txtFinalExe, "!contents? finalExeName$"
finalExeName$ = trim$(finalExeName$)
print #main.txtTargetExe, "!contents? targetExecutable$"
targetExecutable$ = trim$(targetExecutable$)
print #main.txtShortcut, "!contents? shortcutName$"
shortcutName$ = trim$(shortcutName$)
if sourceAppFolder$ = "" or finalExeName$ = "" or targetExecutable$ = "" or shortcutName$ = "" then
print #main.log, "ERROR: All settings must be defined before compiling."
wait
end if
workPath$ = DefaultDir$
if right$(workPath$, 1) <> "\" then workPath$ = workPath$ ; "\"
stagingFolder$ = workPath$ ; "StagingTemp"
[generateEngine]
print #main.log, "Generating specialized deployment layout scripts..."
progFolder$ = targetExecutable$
if lower$(right$(progFolder$, 4)) = ".exe" then progFolder$ = left$(progFolder$, len(progFolder$) - 4)
open workPath$ ; "prompt.vbs" for output as #vbsPrompt
print #vbsPrompt, "Set w = CreateObject("; q$; "WScript.Shell"; q$; ")"
print #vbsPrompt, "Set f = CreateObject("; q$; "Scripting.FileSystemObject"; q$; ")"
print #vbsPrompt, "p = f.GetParentFolderName(WScript.ScriptFullName)"
print #vbsPrompt, "Set s = CreateObject("; q$; "Shell.Application"; q$; ")"
print #vbsPrompt, "Set b = s.BrowseForFolder(0, "; q$; "Select Installation Destination Drive or Folder:"; q$; ", 1, 0)"
print #vbsPrompt, "If b Is Nothing Then WScript.Quit"
print #vbsPrompt, "targetDir = f.BuildPath(b.Self.Path, "; q$; progFolder$; q$; ")"
print #vbsPrompt, "Set out = f.CreateTextFile(f.BuildPath(p, "; q$; "path.tmp"; q$; "), True)"
print #vbsPrompt, "out.WriteLine targetDir"
print #vbsPrompt, "out.Close"
print #vbsPrompt, "w.Run "; q$; "cmd.exe /c powershell.exe -NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File "; q$; " & chr(34) & f.BuildPath(p, "; q$; "deploy.ps1"; q$; ") & chr(34), 0, True"
close #vbsPrompt
open workPath$ ; "deploy.ps1" for output as #psDeploy
print #psDeploy, "param([string]$PassedPath)"
print #psDeploy, "$scriptFile = $MyInvocation.MyCommand.Path"
print #psDeploy, "$scriptDir = Split-Path $scriptFile -Parent"
print #psDeploy, "$tmpFile = Join-Path $scriptDir 'path.tmp'"
print #psDeploy, "if ($PassedPath) { $InstallDir = $PassedPath } else {"
print #psDeploy, " if (Test-Path $tmpFile) { $InstallDir = Get-Content $tmpFile -First 1 } else { Exit }"
print #psDeploy, "}"
print #psDeploy, "$needsAdmin = $false"
print #psDeploy, "if (!(Test-Path $InstallDir)) { try { New-Item -ItemType Directory -Path $InstallDir -Force | Out-Null } catch { $needsAdmin = $true } }"
print #psDeploy, "$testFile = [System.IO.Path]::Combine($InstallDir, 'perm_test.tmp')"
print #psDeploy, "if (!$needsAdmin) { try { 'test' | Out-File $testFile -ErrorAction Stop; Remove-Item $testFile } catch { $needsAdmin = $true } }"
print #psDeploy, "if ($needsAdmin) {"
print #psDeploy, " $currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())"
print #psDeploy, " if (!$currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {"
print #psDeploy, " $arguments = '-NoProfile -ExecutionPolicy Bypass -File ' + [char]34 + $scriptFile + [char]34 + ' -PassedPath ' + [char]34 + $InstallDir + [char]34"
print #psDeploy, " $process = Start-Process powershell.exe -ArgumentList $arguments -WorkingDirectory $scriptDir -Verb RunAs -WindowStyle Hidden -PassThru"
print #psDeploy, " $process.WaitForExit(); Exit"
print #psDeploy, " } else {"
print #psDeploy, " $ws = New-Object -ComObject WScript.Shell; $ws.Popup('Target directory write-protected.', 0, 'Access Error', 16); Exit"
print #psDeploy, " }"
print #psDeploy, "}"
print #psDeploy, "$archive = [System.IO.Path]::Combine($scriptDir, 'payload.tar')"
print #psDeploy, "if (Test-Path $archive) {"
print #psDeploy, " Move-Item -Path $archive -Destination $InstallDir -Force; $oldDir = Get-Location; Set-Location $InstallDir"
print #psDeploy, " $tarProc = Start-Process tar.exe -ArgumentList '-xf payload.tar' -WindowStyle Hidden -PassThru"
print #psDeploy, " while (!$tarProc.HasExited) { Start-Sleep -Milliseconds 100 }"
print #psDeploy, " Remove-Item payload.tar -Force; Set-Location $oldDir"
print #psDeploy, "}"
print #psDeploy, "if (Test-Path $tmpFile) { Remove-Item $tmpFile -Force }"
print #psDeploy, "$wsh = New-Object -ComObject WScript.Shell"
print #psDeploy, "if ($wsh.Popup('Do you want to create a shortcut on your Desktop?', 0, 'Shortcut Setup', 36) -eq 6) {"
print #psDeploy, " $lnk = $wsh.CreateShortcut([System.IO.Path]::Combine([Environment]::GetFolderPath('Desktop'), '" ; shortcutName$ ; ".lnk'))"
print #psDeploy, " $lnk.TargetPath = [System.IO.Path]::Combine($InstallDir, '" ; targetExecutable$ ; "'); $lnk.WorkingDirectory = $InstallDir; $lnk.Save()"
print #psDeploy, "}"
print #psDeploy, "if ($wsh.Popup('Do you want to add this application to your Start Menu?', 0, 'Shortcut Setup', 36) -eq 6) {"
print #psDeploy, " $lnk = $wsh.CreateShortcut([System.IO.Path]::Combine([Environment]::GetFolderPath('Programs'), '" ; shortcutName$ ; ".lnk'))"
print #psDeploy, " $lnk.TargetPath = [System.IO.Path]::Combine($InstallDir, '" ; targetExecutable$ ; "'); $lnk.WorkingDirectory = $InstallDir; $lnk.Save()"
print #psDeploy, "}"
print #psDeploy, "$wsh.Popup('Installation Completed Successfully!', 0, 'Complete', 64) | Out-Null"
close #psDeploy
[writeSED]
print #main.log, "Building Self Extraction Directive file for Iexpress config..."
open workPath$ ; "app.sed" for output as #sedOut
print #sedOut, "[Version]"
print #sedOut, "Class=IEXPRESS"
print #sedOut, "SEDVersion=3"
print #sedOut, "[Options]"
print #sedOut, "PackagePurpose=InstallApp"
print #sedOut, "ShowInstallProgramWindow=0"
print #sedOut, "HideExtractAnimation=1"
print #sedOut, "UseLongFileName=1"
print #sedOut, "InsideCompressed=0"
print #sedOut, "CAB_FixedSize=0"
print #sedOut, "CAB_ReserVecZero=0"
print #sedOut, "RebootMode=N"
print #sedOut, "InstallPrompt="
print #sedOut, "DisplayLicense="
print #sedOut, "FinishMessage="
print #sedOut, "TargetName="; finalExeName$
print #sedOut, "AppLaunched=wscript.exe prompt.vbs"
print #sedOut, "PostInstallCmd=<None>"
print #sedOut, "UACExecutionLevel=AsInvoker"
print #sedOut, "SourceFiles=SourceFiles"
print #sedOut, "[SourceFiles]"
print #sedOut, "SourceFiles0=."
print #sedOut, "[SourceFiles0]"
print #sedOut, "%FILE0%="
print #sedOut, "%FILE1%="
print #sedOut, "%FILE2%="
print #sedOut, "[Strings]"
print #sedOut, "FILE0="; q$; "prompt.vbs"; q$
print #sedOut, "FILE1="; q$; "deploy.ps1"; q$
print #sedOut, "FILE2="; q$; "payload.tar"; q$
close #sedOut
print #main.log, "Generating execution control block script..."
if fileExists(workPath$, "comp_done.txt") > 0 then kill workPath$ ; "comp_done.txt"
overWrite$=folderName$;"-Installer.exe"
if fileExists(workPath$,overWrite$) and overWrite=1 then run "cmd.exe /c del /f /q ";q$;overWrite$;q$,hide
open workPath$ ; "compile.bat" for output as #cBat
print #cBat, "@echo off"
print #cBat, "mode con: cols=45 lines=6"
print #cBat, "title Pipeline Engine"
print #cBat, "echo ==================================================="
print #cBat, "echo 1. SYNCHRONIZING PRIMARY APPLICATION ASSETS..."
print #cBat, "echo ==================================================="
print #cBat, "robocopy.exe " ; q$ ; sourceAppFolder$ ; q$ ; " " ; q$ ; stagingFolder$ ; q$ ; " /E /IS /IT /R:0 /W:0"
print #cBat, "echo."
print #cBat, "echo ==================================================="
print #cBat, "echo 2. RUNNING TAR PACKAGING COMPRESSION ENGINE..."
print #cBat, "echo ==================================================="
print #cBat, "tar.exe -cvf payload.tar -C "; q$; stagingFolder$; q$; " ."
print #cBat, "echo."
print #cBat, "echo ==================================================="
print #cBat, "echo 3. RUNNING IEXPRESS EXECUTABLE COMPILER..."
print #cBat, "echo ==================================================="
print #cBat, "iexpress.exe /n app.sed"
print #cBat, "echo done > comp_done.txt"
print #cBat, "exit"
close #cBat
print #main.log, "Launching native console pipeline compilation stage..."
run "cmd.exe /c compile.bat"
[waitForCompilation]
scan
if fileExists(workPath$, "comp_done.txt") > 0 then goto [cleanUpAll]
timer 150, [cDelay]
wait
[cDelay]
timer 0
goto [waitForCompilation]
[cleanUpAll]
print #main.log, "" : print #main.log, ""
if fileExists(workPath$, finalExeName$) > 0 then
print #main.log, "###### SUCCESS! Master distribution EXE file generated. ######"
print #main.btnBrowseFolder, "!setfocus"
run "explorer.exe /select," ; q$ ; workPath$ ; finalExeName$ ; q$
else
notice "Installer file " + finalExeName$ + " was NOT created"
end if
if fileExists(workPath$, "prompt.vbs") > 0 then kill "prompt.vbs"
if fileExists(workPath$, "deploy.ps1") > 0 then kill "deploy.ps1"
if fileExists(workPath$, "payload.tar") > 0 then kill "payload.tar"
if fileExists(workPath$, "app.sed") > 0 then kill "app.sed"
if fileExists(workPath$, "compile.bat") > 0 then kill "compile.bat"
if fileExists(workPath$, "comp_done.txt") > 0 then kill "comp_done.txt"
run "cmd.exe /c rmdir /s /q " ; q$ ; workPath$ ; "StagingTemp" ; q$, hide
wait
[ovWrite]
overWrite = 1
wait
[novWrite]
overWrite = 0
wait
[quit]
timer 0
#main.log "!cls"
close #main
end
function fileExists(path$, filename$)
dim info$(10,10)
files path$, filename$, info$()
fileExists = val(info$(0,0))
end function
sub pause mil
t=time$("ms")+mil
while time$("ms")<t
scan
wend
end sub Give it a try too. You may prefer it.
Code: Select all
nomainwin
q$ = chr$(34)
WindowWidth = 900
WindowHeight = 765
UpperLeftX = (DisplayWidth - WindowWidth) / 2
UpperLeftY = (DisplayHeight - WindowHeight) / 2
'--- Section 1 : Configuration Settings -------------------------------
groupbox #main.cfgGroup, " 1. CONFIGURATION SETTINGS ", 15, 10, 853, 230
statictext #main.lbl1, "Your Source Folder\EXE File:", 25, 35, 200, 18
statictext #main.lbl1d, "Select the main EXE file to compile.", 25, 53, 200, 16
textbox #main.txtSourceFolder, 280, 40, 230, 24
button #main.btnBrowseFolder, " Browse...", [browseSourceFolder], ul, 520, 39, 70, 25
statictext #main.lbl2, "Output Installer EXE Filename:", 25, 88, 200, 18
statictext #main.lbl2d, "Name of the generated installer.", 25, 106, 200, 16
textbox #main.txtFinalExe, 280, 93, 230, 24
statictext #main.lbl3, "Your Program's EXE Filename:", 25, 138, 200, 18
statictext #main.lbl3d, "Name of the program being installed.", 25, 156, 200, 16
textbox #main.txtTargetExe, 280, 143, 230, 24
statictext #main.lbl4, "Installed Program's Shortcut Name:", 25, 188, 200, 18
statictext #main.lbl4d, "Shortcut name shown in Start Menu.", 25, 206, 200, 16
textbox #main.txtShortcut, 280, 193, 230, 24
statictext #main.title, "INSTALLER", 650, 55, 200, 30
statictext #main.title2, "GENERATOR", 640, 90, 200, 30
statictext #main.tagline3, "_____________", 680, 120, 110, 60
statictext #main.tagline, "Create professional installers in just a few simple steps.", 645, 150, 180, 60
statictext #main.tagline4, "by xxgeek - 2026", 685, 190, 180, 20
'--- Section 2 : Add Extra Files and Folders ---------------------------
groupbox #main.dropGroup, " 2. ADD EXTRA FILES AND FOLDERS ", 15, 250, 420, 110
statictext #main.dropDesc, "_____________________________________________________", 40, 267, 380, 30
statictext #main.dropDesc, "Include additional files or folders in your installer. (optional)", 40, 300, 240, 40
button #main.btnDropZone, "Open File Manager", [openDropZone], ul, 285, 297, 125, 35
'--- Section 3 : Compile Application Installer --------------------------
groupbox #main.compGroup, " 3. COMPILE APPLICATION INSTALLER ", 445, 250, 425, 110
statictext #main.dropDesc, "_____________________________________________________", 465, 267, 380, 30
statictext #main.compDesc, "Compile your application into a single self-extracting installer EXE file.", 465, 300, 240, 40
button #main.btnCompile, "Compile Installer", [buildInstaller], ul, 715, 297, 125, 35
'--- Status / Instructions ----------------------------------------------
groupbox #main.logGroup, "STATUS / INSTRUCTIONS", 15, 370, 853, 310
texteditor #main.log, 25, 395, 835, 270
'--- Footer ---------------------------------------------------------------
checkbox #main.overWrite, " Over-Write Any Existing Installer of Same Name";folderName$;"-Installer.exe", [ovWrite], [novWrite], 25, 685, 400, 20
open "Vrs 3.25" for window_nf as #main
print #main, "trapclose [quit]"
#main "font Segoe UI 10"
#main.log, "!font arial 10 bold"
#main.title2, "!font Times New Roman 20 bold"
#main.title, "!font Times New Roman 20 bold"
#main.lbl1, "!font Segoe UI 10 bold"
#main.lbl2, "!font Segoe UI 10 bold"
#main.lbl3, "!font Segoe UI 10 bold"
#main.lbl4, "!font Segoe UI 10 bold"
#main.lbl1d, "!font Segoe UI 9"
#main.lbl2d, "!font Segoe UI 9"
#main.lbl3d, "!font Segoe UI 9"
#main.lbl4d, "!font Segoe UI 9"
#main.tagline, "!font Segoe UI 9"
#main.dropDesc, "!font Segoe UI 9"
#main.compDesc, "!font Segoe UI 9"
#main.cfgGroup,"!font Segoe UI 10 bold"
#main.dropGroup,"!font Segoe UI 10 bold"
#main.compGroup, "!font Segoe UI 10 bold"
#main.logGroup, "!font Segoe UI 10 bold"
#main.tagline4, "!font Segoe UI 8 bold italic"
print #main.log, "System initialized."
print #main.log, ""
print #main.log, "Step #1 - 'Browse' to and Select Your Projects EXE File"
print #main.log, " (use generated defaults until familiar with Installer Generator - editing is allowed)"
print #main.log, ""
print #main.log, "Step #2 - Use the 'Add Extra Files and Folders' Button - If Desired, not Necessary"
print #main.log, ""
print #main.log, "Step #3 - Use the 'Compile Application Installer' Button."
print #main.log, ""
print #main.log, "Step #4 - Wait Until Windows Explorer Opens Up With Your Installer.exe Selected"
print #main.log, ""
print #main.log, "System Ready."
print #main.btnBrowseFolder, "!setfocus"
wait
[browseSourceFolder]
print #main.log, "SELECT YOUR PROJECT EXE FILE..."
filedialog "SELECT YOUR PROJECT EXE FILE", "*.exe", assetFile$
if assetFile$ <> "" then
derivedFolder$ = ""
lastSlash = 0
for i = len(assetFile$) to 1 step -1
if mid$(assetFile$, i, 1) = "\" then
lastSlash = i
derivedFolder$ = left$(assetFile$, i - 1)
exit for
end if
next i
if right$(derivedFolder$, 1) = ":" then derivedFolder$ = derivedFolder$ ; "\"
folderName$ = ""
if lastSlash > 0 then
prevSlash = 0
for i = (lastSlash - 1) to 1 step -1
if mid$(derivedFolder$, i, 1) = "\" then
prevSlash = i
exit for
end if
next i
if prevSlash > 0 then
folderName$ = right$(derivedFolder$, len(derivedFolder$) - prevSlash)
else
if mid$(derivedFolder$, 2, 2) = ":\" then
folderName$ = right$(derivedFolder$, len(derivedFolder$) - 3)
else
folderName$ = derivedFolder$
end if
end if
end if
if folderName$ = "" then folderName$ = "App"
upperShortcut$ = upper$(folderName$)
print #main.txtSourceFolder, derivedFolder$
print #main.txtFinalExe, folderName$;"-Installer.exe"
print #main.txtTargetExe, folderName$;".exe"
print #main.txtShortcut, upperShortcut$
print #main.log, "Configuration populated automatically."
print #main.btnDropZone, "!setfocus"
else
print #main.log, "!cls"
print #main.log, "Browse canceled."
print #main.btnBrowseFolder, "!setfocus"
end if
wait
[openDropZone]
workPath$ = DefaultDir$
if right$(workPath$, 1) <> "\" then workPath$ = workPath$ ; "\"
stagingFolder$ = workPath$ ; "StagingTemp"
print #main.log, "!cls"
print #main.log, "Opening Multi-Drop Files/Folders Staging Panel..."
open workPath$ ; "stager.ps1" for output as #psOut
print #psOut, "Add-Type -AssemblyName System.Windows.Forms"
print #psOut, "$form = New-Object Windows.Forms.Form"
print #psOut, "$form.Text = 'Asset Staging Drop Zone'"
print #psOut, "$form.Width = 480; $form.Height = 290"
print #psOut, "$form.StartPosition = 'CenterScreen'"
print #psOut, "$form.TopMost = $true"
print #psOut, "$form.AllowDrop = $true"
' Colors
print #psOut, "$normalColor = 'white'"
print #psOut, "$flashColor = 'darkgray'"
' Label
print #psOut, "$label = New-Object Windows.Forms.Label"
print #psOut, "$label.Text = ' DRAG AND DROP FILES AND FOLDERS HERE'"
print #psOut, "$label.Location = New-Object System.Drawing.Point(15, 15)"
print #psOut, "$label.Size = New-Object System.Drawing.Size(430, 150)"
print #psOut, "$label.TextAlign = 'MiddleCenter'"
print #psOut, "$form.BackColor = $normalColor"
print #psOut, "$label.BackColor = 'lightgray'"
print #psOut, "$label.Font = New-Object System.Drawing.Font('Segoe UI', 10, [System.Drawing.FontStyle]::Bold)"
print #psOut, "$form.Controls.Add($label)"
' Button
print #psOut, "$btn = New-Object Windows.Forms.Button"
print #psOut, "$btn.Text = 'Finished Adding File/Folders'"
print #psOut, "$btn.Location = New-Object System.Drawing.Point(140, 190)"
print #psOut, "$btn.Size = New-Object System.Drawing.Size(180, 35)"
print #psOut, "$btn.Add_Click({ Out-File -FilePath '" ; workPath$ ; "stage_done.txt' -InputObject 'done'; $form.Close() })"
print #psOut, "$form.Controls.Add($btn)"
' FLASH TIMER: This triggers the reset after a flash
print #psOut, "$flashTimer = New-Object Windows.Forms.Timer"
print #psOut, "$flashTimer.Interval = 300"
print #psOut, "$flashTimer.Add_Tick({ "
print #psOut, " $form.BackColor = $normalColor"
print #psOut, " $flashTimer.Stop()"
print #psOut, "})"
' Drag Logic
print #psOut, "$form.Add_DragEnter({ if ($_.Data.GetDataPresent([Windows.Forms.DataFormats]::FileDrop)) { $_.Effect = 'Copy' } })"
print #psOut, "$form.Add_DragDrop({ "
print #psOut, " $files = $_.Data.GetData([Windows.Forms.DataFormats]::FileDrop)"
print #psOut, " $dest = '" ; stagingFolder$ ; "'"
print #psOut, " if (!(Test-Path $dest)) { New-Item -ItemType Directory -Path $dest | Out-Null }"
print #psOut, " $listFile = '" ; workPath$ ; "dropped_list.txt'"
print #psOut, " foreach ($file in $files) {"
print #psOut, " if (Test-Path $file -PathType Container) {"
print #psOut, " robocopy.exe " ; q$ ; "$file" ; q$ ; " " ; q$ ; "$dest\$(Split-Path $file -Leaf)" ; q$ ; " /E /IS /IT /R:0 /W:0"
print #psOut, " Add-Content -Path $listFile -Value $(Split-Path $file -Leaf)"
print #psOut, " } else {"
print #psOut, " robocopy.exe " ; q$ ; "$(Split-Path $file -Parent)" ; q$ ; " " ; q$ ; "$dest" ; q$ ; " " ; q$ ; "$(Split-Path $file -Leaf)" ; q$ ; " /IS /IT /R:0 /W:0"
print #psOut, " Add-Content -Path $listFile -Value $(Split-Path $file -Leaf)"
print #psOut, " }"
print #psOut, " }"
' Trigger the flash
print #psOut, " $form.BackColor = $flashColor"
print #psOut, " $flashTimer.Start()"
print #psOut, " $label.Text = 'Items processed! Drop more items, or click below when finished.'"
print #psOut, "})"
print #psOut, "[Windows.Forms.Application]::Run($form)"
close #psOut
if fileExists(workPath$, "stage_done.txt") > 0 then kill workPath$ ; "stage_done.txt"
if fileExists(workPath$, "dropped_list.txt") > 0 then kill workPath$ ; "dropped_list.txt"
run "powershell.exe -NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File " ; q$ ; workPath$ ; "stager.ps1" ; q$, hide
[waitForStager]
scan
if fileExists(workPath$, "stage_done.txt") > 0 then goto [stagerFinished]
timer 250, [stageDelay]
wait
[stageDelay]
timer 0
goto [waitForStager]
[stagerFinished]
if fileExists(workPath$, "stager.ps1") > 0 then kill workPath$ ; "stager.ps1"
if fileExists(workPath$, "stage_done.txt") > 0 then kill workPath$ ; "stage_done.txt"
print #main.log, "Drop zone completed safely."
if fileExists(workPath$, "dropped_list.txt") > 0 then
print #main.log, "Staged Items Added:"
open workPath$ ; "dropped_list.txt" for input as #listIn
[readLogLoop]
if eof(#listIn) <> 0 then goto [readLogDone]
line input #listIn, entry$
if instr(entry$, ".") <> 0 then print #main.log, "File - ";entry$ else print #main.log, "Folder - [";entry$;"]"
goto [readLogLoop]
[readLogDone]
close #listIn
kill workPath$ ; "dropped_list.txt"
print #main.log, ""
print #main.log, " ###### READY TO COMPILE THE INSTALLER ######"
end if
print #main.btnCompile, "!setfocus"
wait
[buildInstaller]
print #main.txtSourceFolder, "!contents? sourceAppFolder$"
sourceAppFolder$ = trim$(sourceAppFolder$)
print #main.txtFinalExe, "!contents? finalExeName$"
finalExeName$ = trim$(finalExeName$)
print #main.txtTargetExe, "!contents? targetExecutable$"
targetExecutable$ = trim$(targetExecutable$)
print #main.txtShortcut, "!contents? shortcutName$"
shortcutName$ = trim$(shortcutName$)
if sourceAppFolder$ = "" or finalExeName$ = "" or targetExecutable$ = "" or shortcutName$ = "" then
print #main.log, "ERROR: All settings must be defined before compiling."
wait
end if
workPath$ = DefaultDir$
if right$(workPath$, 1) <> "\" then workPath$ = workPath$ ; "\"
stagingFolder$ = workPath$ ; "StagingTemp"
[generateEngine]
print #main.log, "Generating specialized deployment layout scripts..."
progFolder$ = targetExecutable$
if lower$(right$(progFolder$, 4)) = ".exe" then progFolder$ = left$(progFolder$, len(progFolder$) - 4)
open workPath$ ; "prompt.vbs" for output as #vbsPrompt
print #vbsPrompt, "Set w = CreateObject("; q$; "WScript.Shell"; q$; ")"
print #vbsPrompt, "Set f = CreateObject("; q$; "Scripting.FileSystemObject"; q$; ")"
print #vbsPrompt, "p = f.GetParentFolderName(WScript.ScriptFullName)"
print #vbsPrompt, "Set s = CreateObject("; q$; "Shell.Application"; q$; ")"
print #vbsPrompt, "Set b = s.BrowseForFolder(0, "; q$; "Select Installation Destination Drive or Folder:"; q$; ", 1, 0)"
print #vbsPrompt, "If b Is Nothing Then WScript.Quit"
print #vbsPrompt, "targetDir = f.BuildPath(b.Self.Path, "; q$; progFolder$; q$; ")"
print #vbsPrompt, "Set out = f.CreateTextFile(f.BuildPath(p, "; q$; "path.tmp"; q$; "), True)"
print #vbsPrompt, "out.WriteLine targetDir"
print #vbsPrompt, "out.Close"
print #vbsPrompt, "w.Run "; q$; "cmd.exe /c powershell.exe -NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File "; q$; " & chr(34) & f.BuildPath(p, "; q$; "deploy.ps1"; q$; ") & chr(34), 0, True"
close #vbsPrompt
open workPath$ ; "deploy.ps1" for output as #psDeploy
print #psDeploy, "param([string]$PassedPath)"
print #psDeploy, "$scriptFile = $MyInvocation.MyCommand.Path"
print #psDeploy, "$scriptDir = Split-Path $scriptFile -Parent"
print #psDeploy, "$tmpFile = Join-Path $scriptDir 'path.tmp'"
print #psDeploy, "if ($PassedPath) { $InstallDir = $PassedPath } else {"
print #psDeploy, " if (Test-Path $tmpFile) { $InstallDir = Get-Content $tmpFile -First 1 } else { Exit }"
print #psDeploy, "}"
print #psDeploy, "$needsAdmin = $false"
print #psDeploy, "if (!(Test-Path $InstallDir)) { try { New-Item -ItemType Directory -Path $InstallDir -Force | Out-Null } catch { $needsAdmin = $true } }"
print #psDeploy, "$testFile = [System.IO.Path]::Combine($InstallDir, 'perm_test.tmp')"
print #psDeploy, "if (!$needsAdmin) { try { 'test' | Out-File $testFile -ErrorAction Stop; Remove-Item $testFile } catch { $needsAdmin = $true } }"
print #psDeploy, "if ($needsAdmin) {"
print #psDeploy, " $currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())"
print #psDeploy, " if (!$currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {"
print #psDeploy, " $arguments = '-NoProfile -ExecutionPolicy Bypass -File ' + [char]34 + $scriptFile + [char]34 + ' -PassedPath ' + [char]34 + $InstallDir + [char]34"
print #psDeploy, " $process = Start-Process powershell.exe -ArgumentList $arguments -WorkingDirectory $scriptDir -Verb RunAs -WindowStyle Hidden -PassThru"
print #psDeploy, " $process.WaitForExit(); Exit"
print #psDeploy, " } else {"
print #psDeploy, " $ws = New-Object -ComObject WScript.Shell; $ws.Popup('Target directory write-protected.', 0, 'Access Error', 16); Exit"
print #psDeploy, " }"
print #psDeploy, "}"
print #psDeploy, "$archive = [System.IO.Path]::Combine($scriptDir, 'payload.tar')"
print #psDeploy, "if (Test-Path $archive) {"
print #psDeploy, " Move-Item -Path $archive -Destination $InstallDir -Force; $oldDir = Get-Location; Set-Location $InstallDir"
print #psDeploy, " $tarProc = Start-Process tar.exe -ArgumentList '-xf payload.tar' -WindowStyle Hidden -PassThru"
print #psDeploy, " while (!$tarProc.HasExited) { Start-Sleep -Milliseconds 100 }"
print #psDeploy, " Remove-Item payload.tar -Force; Set-Location $oldDir"
print #psDeploy, "}"
print #psDeploy, "if (Test-Path $tmpFile) { Remove-Item $tmpFile -Force }"
print #psDeploy, "$wsh = New-Object -ComObject WScript.Shell"
print #psDeploy, "if ($wsh.Popup('Do you want to create a shortcut on your Desktop?', 0, 'Shortcut Setup', 36) -eq 6) {"
print #psDeploy, " $lnk = $wsh.CreateShortcut([System.IO.Path]::Combine([Environment]::GetFolderPath('Desktop'), '" ; shortcutName$ ; ".lnk'))"
print #psDeploy, " $lnk.TargetPath = [System.IO.Path]::Combine($InstallDir, '" ; targetExecutable$ ; "'); $lnk.WorkingDirectory = $InstallDir; $lnk.Save()"
print #psDeploy, "}"
print #psDeploy, "if ($wsh.Popup('Do you want to add this application to your Start Menu?', 0, 'Shortcut Setup', 36) -eq 6) {"
print #psDeploy, " $lnk = $wsh.CreateShortcut([System.IO.Path]::Combine([Environment]::GetFolderPath('Programs'), '" ; shortcutName$ ; ".lnk'))"
print #psDeploy, " $lnk.TargetPath = [System.IO.Path]::Combine($InstallDir, '" ; targetExecutable$ ; "'); $lnk.WorkingDirectory = $InstallDir; $lnk.Save()"
print #psDeploy, "}"
print #psDeploy, "$wsh.Popup('Installation Completed Successfully!', 0, 'Complete', 64) | Out-Null"
close #psDeploy
[writeSED]
print #main.log, "Building Self Extraction Directive file for Iexpress config..."
open workPath$ ; "app.sed" for output as #sedOut
print #sedOut, "[Version]"
print #sedOut, "Class=IEXPRESS"
print #sedOut, "SEDVersion=3"
print #sedOut, "[Options]"
print #sedOut, "PackagePurpose=InstallApp"
print #sedOut, "ShowInstallProgramWindow=0"
print #sedOut, "HideExtractAnimation=1"
print #sedOut, "UseLongFileName=1"
print #sedOut, "InsideCompressed=0"
print #sedOut, "CAB_FixedSize=0"
print #sedOut, "CAB_ReserVecZero=0"
print #sedOut, "RebootMode=N"
print #sedOut, "InstallPrompt="
print #sedOut, "DisplayLicense="
print #sedOut, "FinishMessage="
print #sedOut, "TargetName="; finalExeName$
print #sedOut, "AppLaunched=wscript.exe prompt.vbs"
print #sedOut, "PostInstallCmd=<None>"
print #sedOut, "UACExecutionLevel=AsInvoker"
print #sedOut, "SourceFiles=SourceFiles"
print #sedOut, "[SourceFiles]"
print #sedOut, "SourceFiles0=."
print #sedOut, "[SourceFiles0]"
print #sedOut, "%FILE0%="
print #sedOut, "%FILE1%="
print #sedOut, "%FILE2%="
print #sedOut, "[Strings]"
print #sedOut, "FILE0="; q$; "prompt.vbs"; q$
print #sedOut, "FILE1="; q$; "deploy.ps1"; q$
print #sedOut, "FILE2="; q$; "payload.tar"; q$
close #sedOut
print #main.log, "Generating execution control block script..."
if fileExists(workPath$, "comp_done.txt") > 0 then kill workPath$ ; "comp_done.txt"
overWrite$=folderName$;"-Installer.exe"
if fileExists(workPath$,overWrite$) and overWrite=1 then run "cmd.exe /c del /f /q ";q$;overWrite$;q$,hide
open workPath$ ; "compile.bat" for output as #cBat
print #cBat, "@echo off"
print #cBat, "mode con: cols=45 lines=6"
print #cBat, "title Pipeline Engine"
print #cBat, "echo ==================================================="
print #cBat, "echo 1. SYNCHRONIZING PRIMARY APPLICATION ASSETS..."
print #cBat, "echo ==================================================="
print #cBat, "robocopy.exe " ; q$ ; sourceAppFolder$ ; q$ ; " " ; q$ ; stagingFolder$ ; q$ ; " /E /IS /IT /R:0 /W:0"
print #cBat, "echo."
print #cBat, "echo ==================================================="
print #cBat, "echo 2. RUNNING TAR PACKAGING COMPRESSION ENGINE..."
print #cBat, "echo ==================================================="
print #cBat, "tar.exe -cvf payload.tar -C "; q$; stagingFolder$; q$; " ."
print #cBat, "echo."
print #cBat, "echo ==================================================="
print #cBat, "echo 3. RUNNING IEXPRESS EXECUTABLE COMPILER..."
print #cBat, "echo ==================================================="
print #cBat, "iexpress.exe /n app.sed"
print #cBat, "echo done > comp_done.txt"
print #cBat, "exit"
close #cBat
print #main.log, "Launching native console pipeline compilation stage..."
run "cmd.exe /c compile.bat"
[waitForCompilation]
scan
if fileExists(workPath$, "comp_done.txt") > 0 then goto [cleanUpAll]
timer 150, [cDelay]
wait
[cDelay]
timer 0
goto [waitForCompilation]
[cleanUpAll]
print #main.log, "" : print #main.log, ""
if fileExists(workPath$, finalExeName$) > 0 then
print #main.log, "###### SUCCESS! Master distribution EXE file generated. ######"
print #main.btnBrowseFolder, "!setfocus"
run "explorer.exe /select," ; q$ ; workPath$ ; finalExeName$ ; q$
else
notice "Installer file " + finalExeName$ + " was NOT created"
end if
if fileExists(workPath$, "prompt.vbs") > 0 then kill "prompt.vbs"
if fileExists(workPath$, "deploy.ps1") > 0 then kill "deploy.ps1"
if fileExists(workPath$, "payload.tar") > 0 then kill "payload.tar"
if fileExists(workPath$, "app.sed") > 0 then kill "app.sed"
if fileExists(workPath$, "compile.bat") > 0 then kill "compile.bat"
if fileExists(workPath$, "comp_done.txt") > 0 then kill "comp_done.txt"
run "cmd.exe /c rmdir /s /q " ; q$ ; workPath$ ; "StagingTemp" ; q$, hide
wait
[ovWrite]
overWrite = 1
wait
[novWrite]
overWrite = 0
wait
[quit]
timer 0
#main.log "!cls"
close #main
end
function fileExists(path$, filename$)
dim info$(10,10)
files path$, filename$, info$()
fileExists = val(info$(0,0))
end function
sub pause mil
t=time$("ms")+mil
while time$("ms")<t
scan
wend
end sub