diff --git a/cmd/podman-msihooks/main.go b/cmd/podman-msihooks/main.go deleted file mode 100644 index 903c91abbc..0000000000 --- a/cmd/podman-msihooks/main.go +++ /dev/null @@ -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() {} diff --git a/contrib/win-installer/build-hooks.bat b/contrib/win-installer/build-hooks.bat index d663f87b8c..50b24d532b 100644 --- a/contrib/win-installer/build-hooks.bat +++ b/contrib/win-installer/build-hooks.bat @@ -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 diff --git a/contrib/win-installer/podman-msihooks/check.c b/contrib/win-installer/podman-msihooks/check.c new file mode 100644 index 0000000000..1a3b10e479 --- /dev/null +++ b/contrib/win-installer/podman-msihooks/check.c @@ -0,0 +1,66 @@ +#include +#include + +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; +}