Skip to content
This repository has been archived by the owner on Jul 5, 2024. It is now read-only.

Commit

Permalink
New setup architecture; more cross platform friendly and no need to l…
Browse files Browse the repository at this point in the history
…oad everything into memory
  • Loading branch information
caesay committed Feb 19, 2022
1 parent 061904d commit 01aab4d
Show file tree
Hide file tree
Showing 45 changed files with 886 additions and 245 deletions.
50 changes: 50 additions & 0 deletions Squirrel.sln
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SquirrelCli", "src\Squirrel
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Setup", "src\Setup\Setup.vcxproj", "{6B406985-B2E1-4FED-A405-BD0694D68E93}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Squirrel.Shared", "src\Squirrel.Shared\Squirrel.Shared.csproj", "{352C15EA-622F-4132-80D8-9B6E3C83404E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
CIBuild|Any CPU = CIBuild|Any CPU
Expand Down Expand Up @@ -340,6 +342,54 @@ Global
{6B406985-B2E1-4FED-A405-BD0694D68E93}.Release|x64.Build.0 = Release|x64
{6B406985-B2E1-4FED-A405-BD0694D68E93}.Release|x86.ActiveCfg = Release|Win32
{6B406985-B2E1-4FED-A405-BD0694D68E93}.Release|x86.Build.0 = Release|Win32
{352C15EA-622F-4132-80D8-9B6E3C83404E}.CIBuild|Any CPU.ActiveCfg = Debug|Any CPU
{352C15EA-622F-4132-80D8-9B6E3C83404E}.CIBuild|Any CPU.Build.0 = Debug|Any CPU
{352C15EA-622F-4132-80D8-9B6E3C83404E}.CIBuild|Mixed Platforms.ActiveCfg = Debug|Any CPU
{352C15EA-622F-4132-80D8-9B6E3C83404E}.CIBuild|Mixed Platforms.Build.0 = Debug|Any CPU
{352C15EA-622F-4132-80D8-9B6E3C83404E}.CIBuild|x64.ActiveCfg = Debug|Any CPU
{352C15EA-622F-4132-80D8-9B6E3C83404E}.CIBuild|x64.Build.0 = Debug|Any CPU
{352C15EA-622F-4132-80D8-9B6E3C83404E}.CIBuild|x86.ActiveCfg = Debug|Any CPU
{352C15EA-622F-4132-80D8-9B6E3C83404E}.CIBuild|x86.Build.0 = Debug|Any CPU
{352C15EA-622F-4132-80D8-9B6E3C83404E}.Coverage|Any CPU.ActiveCfg = Debug|Any CPU
{352C15EA-622F-4132-80D8-9B6E3C83404E}.Coverage|Any CPU.Build.0 = Debug|Any CPU
{352C15EA-622F-4132-80D8-9B6E3C83404E}.Coverage|Mixed Platforms.ActiveCfg = Debug|Any CPU
{352C15EA-622F-4132-80D8-9B6E3C83404E}.Coverage|Mixed Platforms.Build.0 = Debug|Any CPU
{352C15EA-622F-4132-80D8-9B6E3C83404E}.Coverage|x64.ActiveCfg = Debug|Any CPU
{352C15EA-622F-4132-80D8-9B6E3C83404E}.Coverage|x64.Build.0 = Debug|Any CPU
{352C15EA-622F-4132-80D8-9B6E3C83404E}.Coverage|x86.ActiveCfg = Debug|Any CPU
{352C15EA-622F-4132-80D8-9B6E3C83404E}.Coverage|x86.Build.0 = Debug|Any CPU
{352C15EA-622F-4132-80D8-9B6E3C83404E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{352C15EA-622F-4132-80D8-9B6E3C83404E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{352C15EA-622F-4132-80D8-9B6E3C83404E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{352C15EA-622F-4132-80D8-9B6E3C83404E}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{352C15EA-622F-4132-80D8-9B6E3C83404E}.Debug|x64.ActiveCfg = Debug|Any CPU
{352C15EA-622F-4132-80D8-9B6E3C83404E}.Debug|x64.Build.0 = Debug|Any CPU
{352C15EA-622F-4132-80D8-9B6E3C83404E}.Debug|x86.ActiveCfg = Debug|Any CPU
{352C15EA-622F-4132-80D8-9B6E3C83404E}.Debug|x86.Build.0 = Debug|Any CPU
{352C15EA-622F-4132-80D8-9B6E3C83404E}.Mono Debug|Any CPU.ActiveCfg = Debug|Any CPU
{352C15EA-622F-4132-80D8-9B6E3C83404E}.Mono Debug|Any CPU.Build.0 = Debug|Any CPU
{352C15EA-622F-4132-80D8-9B6E3C83404E}.Mono Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{352C15EA-622F-4132-80D8-9B6E3C83404E}.Mono Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{352C15EA-622F-4132-80D8-9B6E3C83404E}.Mono Debug|x64.ActiveCfg = Debug|Any CPU
{352C15EA-622F-4132-80D8-9B6E3C83404E}.Mono Debug|x64.Build.0 = Debug|Any CPU
{352C15EA-622F-4132-80D8-9B6E3C83404E}.Mono Debug|x86.ActiveCfg = Debug|Any CPU
{352C15EA-622F-4132-80D8-9B6E3C83404E}.Mono Debug|x86.Build.0 = Debug|Any CPU
{352C15EA-622F-4132-80D8-9B6E3C83404E}.Mono Release|Any CPU.ActiveCfg = Release|Any CPU
{352C15EA-622F-4132-80D8-9B6E3C83404E}.Mono Release|Any CPU.Build.0 = Release|Any CPU
{352C15EA-622F-4132-80D8-9B6E3C83404E}.Mono Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{352C15EA-622F-4132-80D8-9B6E3C83404E}.Mono Release|Mixed Platforms.Build.0 = Release|Any CPU
{352C15EA-622F-4132-80D8-9B6E3C83404E}.Mono Release|x64.ActiveCfg = Release|Any CPU
{352C15EA-622F-4132-80D8-9B6E3C83404E}.Mono Release|x64.Build.0 = Release|Any CPU
{352C15EA-622F-4132-80D8-9B6E3C83404E}.Mono Release|x86.ActiveCfg = Release|Any CPU
{352C15EA-622F-4132-80D8-9B6E3C83404E}.Mono Release|x86.Build.0 = Release|Any CPU
{352C15EA-622F-4132-80D8-9B6E3C83404E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{352C15EA-622F-4132-80D8-9B6E3C83404E}.Release|Any CPU.Build.0 = Release|Any CPU
{352C15EA-622F-4132-80D8-9B6E3C83404E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{352C15EA-622F-4132-80D8-9B6E3C83404E}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{352C15EA-622F-4132-80D8-9B6E3C83404E}.Release|x64.ActiveCfg = Release|Any CPU
{352C15EA-622F-4132-80D8-9B6E3C83404E}.Release|x64.Build.0 = Release|Any CPU
{352C15EA-622F-4132-80D8-9B6E3C83404E}.Release|x86.ActiveCfg = Release|Any CPU
{352C15EA-622F-4132-80D8-9B6E3C83404E}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
129 changes: 21 additions & 108 deletions src/Setup/Setup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,54 +2,12 @@
#include <versionhelpers.h>
#include <string>
#include <functional>
#include <tchar.h>
#include "unzip.h"
#include "bundle_marker.h"
#include "platform_util.h"

using namespace std;

wstring getTempExePath()
{
wchar_t tempFolderBuf[MAX_PATH];
DWORD cTempFolder = GetTempPath(MAX_PATH, tempFolderBuf);
wchar_t tempFileBuf[MAX_PATH];
GetTempFileName(tempFolderBuf, L"squirrel", 0, tempFileBuf);
DeleteFile(tempFileBuf);
wstring tempFile(tempFileBuf);
tempFile += L".exe";
return tempFile;
}

BYTE* getByteResource(int idx, DWORD* cBuf)
{
auto f = FindResource(NULL, MAKEINTRESOURCE(idx), L"DATA");
if (!f) throw wstring(L"Unable to find resource " + to_wstring(idx));

auto r = LoadResource(NULL, f);
if (!r) throw wstring(L"Unable to load resource " + to_wstring(idx));

*cBuf = SizeofResource(NULL, f);
return (BYTE*)LockResource(r);
}

wstring getCurrentExecutablePath()
{
wchar_t ourFile[MAX_PATH];
HMODULE hMod = GetModuleHandle(NULL);
GetModuleFileName(hMod, ourFile, _countof(ourFile));
return wstring(ourFile);
}

wstring getNameFromPath(wstring path)
{
auto idx = path.find_last_of('\\');

// if we can't find last \ or the name is too short, default to 'Setup'
if (idx == wstring::npos || path.length() < idx + 3)
return L"Setup";

return path.substr(idx + 1);
}

// https://stackoverflow.com/a/874160/184746
bool hasEnding(std::wstring const& fullString, std::wstring const& ending)
{
Expand Down Expand Up @@ -90,96 +48,51 @@ void unzipSingleFile(BYTE* zipBuf, DWORD cZipBuf, wstring fileLocation, std::fun
if (!unzipSuccess) throw wstring(L"Unable to extract embedded package (predicate not found).");
}

// https://stackoverflow.com/a/17387176/184746
void throwLastWin32Error()
{
DWORD errorMessageID = ::GetLastError();
if (errorMessageID == 0) {
return;
}

LPWSTR messageBuffer = nullptr;
size_t size = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&messageBuffer, 0, NULL);

std::wstring message(messageBuffer, size);
throw message;
}

void wexec(const wchar_t* cmd)
{
LPTSTR szCmdline = _tcsdup(cmd); // https://stackoverflow.com/a/10044348/184746

STARTUPINFO si = { 0 };
si.cb = sizeof(STARTUPINFO);
si.wShowWindow = SW_SHOW;
si.dwFlags = STARTF_USESHOWWINDOW;

PROCESS_INFORMATION pi = { 0 };
if (!CreateProcess(NULL, szCmdline, NULL, NULL, false, 0, NULL, NULL, &si, &pi)) {
throwLastWin32Error();
}

WaitForSingleObject(pi.hProcess, INFINITE);

DWORD dwExitCode = 0;
if (!GetExitCodeProcess(pi.hProcess, &dwExitCode)) {
dwExitCode = (DWORD)-9;
}

CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);

if (dwExitCode != 0) {
throw wstring(L"Process exited with error code: " + to_wstring(dwExitCode));
}
}

int showErrorDialog(wstring msg)
{
wstring myPath = getCurrentExecutablePath();
wstring myName = getNameFromPath(myPath);
wstring errorTitle = myName + L" Error";
MessageBox(0, msg.c_str(), errorTitle.c_str(), MB_OK | MB_ICONERROR);
return -1;
}

int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ PWSTR pCmdLine, _In_ int nCmdShow)
{
if (!IsWindows7SP1OrGreater()) {
return showErrorDialog(L"This application requires Windows 7 SP1 or later and cannot be installed on this computer.");
util::show_error_dialog(L"This application requires Windows 7 SP1 or later and cannot be installed on this computer.");
return 0;
}

wstring myPath = getCurrentExecutablePath();
wstring updaterPath = getTempExePath();
wstring myPath = util::get_current_process_path();
wstring updaterPath = util::get_temp_file_path(L"exe");

try {
// locate bundled package
DWORD cZipBuf;
BYTE* zipBuf = getByteResource(205, &cZipBuf); // 205 = BundledPackageBytes
BYTE* memAddr = util::mmap_read(myPath, 0);
int64_t packageOffset, packageLength;
bundle_marker_t::header_offset(&packageOffset, &packageLength);
BYTE* pkgStart = memAddr + packageOffset;
if (packageOffset == 0 || packageLength == 0) {
util::munmap(memAddr);
util::show_error_dialog(L"An error occurred while running setup. The embedded package was not found. Please contact the application author.");
return 0;
}

// extract Squirrel installer
std::function<bool(ZIPENTRY&)> endsWithSquirrel([](ZIPENTRY& z) {
return hasEnding(std::wstring(z.name), L"Squirrel.exe");
});
unzipSingleFile(zipBuf, cZipBuf, updaterPath, endsWithSquirrel);
unzipSingleFile(pkgStart, packageLength, updaterPath, endsWithSquirrel);
util::munmap(memAddr);

// run installer and forward our command line arguments
wstring cmd = L"\"" + updaterPath + L"\" --setup \"" + myPath + L"\" " + pCmdLine;
wexec(cmd.c_str());
util::wexec(cmd.c_str());
}
catch (wstring wsx) {
return showErrorDialog(L"An error occurred while running setup: " + wsx + L". Please contact the application author.");
util::show_error_dialog(L"An error occurred while running setup. " + wsx + L". Please contact the application author.");
}
catch (std::exception ex) {
// nasty shit to convert from ascii to wide-char. this will fail if there are multi-byte characters.
// hopefully we remember to throw 'wstring' everywhere instead of 'exception' and it doesn't matter.
string msg = ex.what();
wstring wsTmp(msg.begin(), msg.end());
return showErrorDialog(L"An error occurred while running setup: " + wsTmp + L". Please contact the application author.");
util::show_error_dialog(L"An error occurred while running setup. " + wsTmp + L". Please contact the application author.");
}
catch (...) {
return showErrorDialog(L"An unknown error occurred while running setup. Please contact the application author.");
util::show_error_dialog(L"An unknown error occurred while running setup. Please contact the application author.");
}

// clean-up after ourselves
Expand Down
4 changes: 4 additions & 0 deletions src/Setup/Setup.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,14 @@
</Manifest>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="bundle_marker.cpp" />
<ClCompile Include="platform_util.cpp" />
<ClCompile Include="Setup.cpp" />
<ClCompile Include="unzip.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="bundle_marker.h" />
<ClInclude Include="platform_util.h" />
<ClInclude Include="unzip.h" />
</ItemGroup>
<ItemGroup>
Expand Down
12 changes: 12 additions & 0 deletions src/Setup/Setup.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,23 @@
<ClCompile Include="unzip.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="bundle_marker.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="platform_util.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="unzip.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="bundle_marker.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="platform_util.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Text Include="compatibility.manifest">
Expand Down
29 changes: 29 additions & 0 deletions src/Setup/bundle_marker.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#include "bundle_marker.h"
#include <windows.h>
#include <string>

using namespace std;

void bundle_marker_t::header_offset(int64_t* pOffset, int64_t* pLength)
{
// Contains the bundle_placeholder default value at compile time.
// the first 8 bytes are replaced by squirrel with the offset
// where the package is located.
static volatile uint8_t placeholder[] =
{
// 8 bytes represent the package offset
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 8 bytes represent the package length
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 64 bytes represent the bundle signature: SHA-256 for "squirrel bundle"
0x94, 0xf0, 0xb1, 0x7b, 0x68, 0x93, 0xe0, 0x29,
0x37, 0xeb, 0x34, 0xef, 0x53, 0xaa, 0xe7, 0xd4,
0x2b, 0x54, 0xf5, 0x70, 0x7e, 0xf5, 0xd6, 0xf5,
0x78, 0x54, 0x98, 0x3e, 0x5e, 0x94, 0xed, 0x7d
};

volatile bundle_marker_t* marker = reinterpret_cast<volatile bundle_marker_t*>(placeholder);
*pOffset = marker->locator.bundle_header_offset;
*pLength = marker->locator.bundle_header_length;
}

28 changes: 28 additions & 0 deletions src/Setup/bundle_marker.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#ifndef __BUNDLE_MARKER_H__
#define __BUNDLE_MARKER_H__

#include <cstdint>

#pragma pack(push, 1)
union bundle_marker_t
{
public:
uint8_t placeholder[48];
struct
{
int64_t bundle_header_offset;
int64_t bundle_header_length;
uint8_t signature[32];
} locator;

static void header_offset(int64_t* pOffset, int64_t* pLength);
static bool is_bundle()
{
int64_t offset, length;
header_offset(&offset, &length);
return offset != 0;
}
};
#pragma pack(pop)

#endif // __BUNDLE_MARKER_H__
Loading

0 comments on commit 01aab4d

Please sign in to comment.