Switch to C based msi hooks for win installer

Fixes automated WSL installation on ARM

Signed-off-by: Jason T. Greene <jason.greene@redhat.com>
This commit is contained in:
Jason T. Greene
2023-01-04 22:36:51 -06:00
committed by Jason T. Greene
parent b89435a820
commit 54afda22bf
3 changed files with 69 additions and 47 deletions

View File

@ -1,46 +0,0 @@
//go:build windows
// +build windows
package main
import (
"C"
"syscall"
"unsafe"
"github.com/containers/podman/v4/pkg/machine/wsl"
)
const KernelWarning = "WSL Kernel installation did not complete successfully. " +
"Podman machine will attempt to install this at a later time. " +
"You can also manually complete the installation using the " +
"\"wsl --update\" command."
//export CheckWSL
func CheckWSL(hInstall uint32) uint32 {
installed := wsl.IsWSLInstalled()
feature := wsl.IsWSLFeatureEnabled()
setMsiProperty(hInstall, "HAS_WSL", strBool(installed))
setMsiProperty(hInstall, "HAS_WSLFEATURE", strBool(feature))
return 0
}
func setMsiProperty(hInstall uint32, name string, value string) {
nameW, _ := syscall.UTF16PtrFromString(name)
valueW, _ := syscall.UTF16PtrFromString(value)
msi := syscall.NewLazyDLL("msi")
proc := msi.NewProc("MsiSetPropertyW")
_, _, _ = proc.Call(uintptr(hInstall), uintptr(unsafe.Pointer(nameW)), uintptr(unsafe.Pointer(valueW)))
}
func strBool(val bool) string {
if val {
return "1"
}
return "0"
}
func main() {}

View File

@ -1,4 +1,6 @@
cd ../..
go build -buildmode=c-shared -o contrib/win-installer/artifacts/podman-msihooks.dll ./cmd/podman-msihooks || exit /b 1
set GOARCH=amd64
go build -ldflags -H=windowsgui -o contrib/win-installer/artifacts/podman-wslkerninst.exe ./cmd/podman-wslkerninst || exit /b 1
cd contrib/win-installer
@rem Build using x86 toolchain, see comments in check.c for rationale and details
x86_64-w64-mingw32-gcc podman-msihooks/check.c -shared -lmsi -mwindows -o artifacts/podman-msihooks.dll || exit /b 1

View File

@ -0,0 +1,66 @@
#include <windows.h>
#include <MsiQuery.h>
BOOL isWSLEnabled();
LPCWSTR boolToNStr(BOOL bool);
/**
* CheckWSL is a custom action loaded by the Podman Windows installer
* to determine whether the system already has WSL installed.
*
* The intention is that this action is compiled for x86_64, which
* can be ran on both Intel and Arm based systems (the latter through
* emulation). While the code should build fine on MSVC and clang, the
* intended usage is MingW-W64 (cross-compiling gcc targeting Windows).
*
* Previously this was implemented as a Golang c-shared cgo library,
* however, the WoW x86_64 emulation layer struggled with dynamic
* hot-loaded transformation of the goruntime into an existing process
* (required by MSI custom actions). In the future this could be
* converted back, should the emulation issue be resolved.
*/
__declspec(dllexport) UINT __cdecl CheckWSL(MSIHANDLE hInstall) {
BOOL hasWSL = isWSLEnabled();
// Set a property with the WSL state for the installer to operate on
MsiSetPropertyW(hInstall, L"HAS_WSLFEATURE", boolToNStr(hasWSL));
return 0;
}
LPCWSTR boolToNStr(BOOL bool) {
return bool ? L"1" : L"0";
}
BOOL isWSLEnabled() {
/*
* The simplest, and most reliable check across all variants and versions
* of WSL appears to be changing the default version to WSL 2 and check
* for errors, which we need to do anyway.
*/
STARTUPINFOW startup;
PROCESS_INFORMATION process;
ZeroMemory(&startup, sizeof(STARTUPINFOW));
startup.cb = sizeof(STARTUPINFOW);
// These settings hide the console window, so there is no annoying flash
startup.dwFlags = STARTF_USESHOWWINDOW;
startup.wShowWindow = SW_HIDE;
// CreateProcessW requires lpCommandLine to be mutable
wchar_t cmd[] = L"wsl --set-default-version 2";
if (! CreateProcessW(NULL, cmd, NULL, NULL, FALSE, CREATE_NEW_CONSOLE,
NULL, NULL, &startup, &process)) {
return FALSE;
}
DWORD exitCode;
WaitForSingleObject(process.hProcess, INFINITE);
if (! GetExitCodeProcess(process.hProcess, &exitCode)) {
return FALSE;
}
return exitCode == 0;
}