diff --git a/src/windows/WslcSDK/wslcsdk.cpp b/src/windows/WslcSDK/wslcsdk.cpp index b6946afb9..2deec5de3 100644 --- a/src/windows/WslcSDK/wslcsdk.cpp +++ b/src/windows/WslcSDK/wslcsdk.cpp @@ -303,6 +303,30 @@ std::pair, HRESULT> CreateSessionManagerRaw() { wil::com_ptr result; HRESULT hr = CoCreateInstance(__uuidof(WSLCSessionManager), nullptr, CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&result)); + if (SUCCEEDED(hr)) + { + WSLCVersion minimumClientVersion{}; + THROW_IF_FAILED(result->GetMinimumSupportedClientVersion(&minimumClientVersion)); + + decltype(wsl::shared::PackageVersion) requiredClientVersion{ + minimumClientVersion.Major, minimumClientVersion.Minor, minimumClientVersion.Revision}; + + if (requiredClientVersion > wsl::shared::PackageVersion) + { + LOG_HR_MSG( + WSLC_E_SDK_UPDATE_NEEDED, + "WSLC SDK update required. Minimum supported version: %lu.%lu.%lu, current SDK version: %lu.%lu.%lu", + minimumClientVersion.Major, + minimumClientVersion.Minor, + minimumClientVersion.Revision, + WSL_PACKAGE_VERSION_MAJOR, + WSL_PACKAGE_VERSION_MINOR, + WSL_PACKAGE_VERSION_REVISION); + + return {result, WSLC_E_SDK_UPDATE_NEEDED}; + } + } + return {result, hr}; } @@ -330,20 +354,6 @@ wil::com_ptr CreateSessionManager() return result; } -bool NeedsWslRuntimeInstalled() -{ - auto hr = CreateSessionManagerRaw().second; - - if (SUCCEEDED(hr)) - { - return false; - } - else if (hr == REGDB_E_CLASSNOTREG) - { - return true; - } - THROW_HR(hr); -} } // namespace // SESSION DEFINITIONS @@ -1346,7 +1356,20 @@ try WslcComponentFlags componentCheck = WSLC_COMPONENT_FLAG_NONE; WI_SetFlagIf(componentCheck, WSLC_COMPONENT_FLAG_VIRTUAL_MACHINE_PLATFORM, NeedsVirtualMachineServicesInstalled()); - WI_SetFlagIf(componentCheck, WSLC_COMPONENT_FLAG_WSL_PACKAGE, NeedsWslRuntimeInstalled()); + + auto hr = CreateSessionManagerRaw().second; + if (hr == REGDB_E_CLASSNOTREG) + { + WI_SetFlag(componentCheck, WSLC_COMPONENT_FLAG_WSL_PACKAGE); + } + else if (hr == WSLC_E_SDK_UPDATE_NEEDED) + { + WI_SetFlag(componentCheck, WSLC_COMPONENT_FLAG_SDK_NEEDS_UPDATE); + } + else if (FAILED(hr)) + { + THROW_HR(hr); + } *canRun = componentCheck == WSLC_COMPONENT_FLAG_NONE ? TRUE : FALSE; *missingComponents = componentCheck; diff --git a/src/windows/WslcSDK/wslcsdk.h b/src/windows/WslcSDK/wslcsdk.h index a581afd7f..b977ffaf1 100644 --- a/src/windows/WslcSDK/wslcsdk.h +++ b/src/windows/WslcSDK/wslcsdk.h @@ -20,6 +20,14 @@ Module Name: EXTERN_C_START +// WSLC specific error codes +#define WSLC_E_BASE (0x0600) +#define WSLC_E_IMAGE_NOT_FOUND MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, WSLC_E_BASE + 1) /* 0x80040601 */ +#define WSLC_E_CONTAINER_PREFIX_AMBIGUOUS MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, WSLC_E_BASE + 2) /* 0x80040602 */ +#define WSLC_E_CONTAINER_NOT_FOUND MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, WSLC_E_BASE + 3) /* 0x80040603 */ +#define WSLC_E_VOLUME_NOT_FOUND MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, WSLC_E_BASE + 4) /* 0x80040604 */ +#define WSLC_E_SDK_UPDATE_NEEDED MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, WSLC_E_BASE + 5) /* 0x80040605 */ + // Session values #define WSLC_SESSION_OPTIONS_SIZE 80 #define WSLC_SESSION_OPTIONS_ALIGNMENT 8 @@ -494,6 +502,8 @@ typedef enum WslcComponentFlags WSLC_COMPONENT_FLAG_VIRTUAL_MACHINE_PLATFORM = 1, // The WSL runtime package, at an appropriate version to provide support for WSLC. WSLC_COMPONENT_FLAG_WSL_PACKAGE = 2, + // Set if the WSLC SDK itself needs to be updated. + WSLC_COMPONENT_FLAG_SDK_NEEDS_UPDATE = 4, } WslcComponentFlags; DEFINE_ENUM_FLAG_OPERATORS(WslcComponentFlags); diff --git a/src/windows/service/exe/WSLCSessionManager.cpp b/src/windows/service/exe/WSLCSessionManager.cpp index 1b4333a2a..c489a0baa 100644 --- a/src/windows/service/exe/WSLCSessionManager.cpp +++ b/src/windows/service/exe/WSLCSessionManager.cpp @@ -193,13 +193,6 @@ void WSLCSessionManagerImpl::ListSessions(_Out_ WSLCSessionInformation** Session *SessionsCount = static_cast(sessionInfo.size()); } -void WSLCSessionManagerImpl::GetVersion(_Out_ WSLCVersion* Version) -{ - Version->Major = WSL_PACKAGE_VERSION_MAJOR; - Version->Minor = WSL_PACKAGE_VERSION_MINOR; - Version->Revision = WSL_PACKAGE_VERSION_REVISION; -} - WSLCSessionInitSettings WSLCSessionManagerImpl::CreateSessionSettings(_In_ ULONG SessionId, _In_ DWORD CreatorPid, _In_ const WSLCSessionSettings* Settings) { WSLCSessionInitSettings sessionSettings{}; @@ -276,7 +269,33 @@ WSLCSessionManager::WSLCSessionManager(WSLCSessionManagerImpl* Impl) : COMImplCl HRESULT WSLCSessionManager::GetVersion(_Out_ WSLCVersion* Version) { - return CallImpl(&WSLCSessionManagerImpl::GetVersion, Version); + Version->Major = WSL_PACKAGE_VERSION_MAJOR; + Version->Minor = WSL_PACKAGE_VERSION_MINOR; + Version->Revision = WSL_PACKAGE_VERSION_REVISION; + + return S_OK; +} + +HRESULT WSLCSessionManager::GetMinimumSupportedClientVersion(_Out_ WSLCVersion* Version) +{ + constexpr std::tuple c_minClientVersion{2, 8, 0}; + + // If the current version is below the minimum version, return the current version for convenience. + // TODO: Remove once 2.8.0 is published. + if constexpr (wsl::shared::PackageVersion < c_minClientVersion) + { + Version->Major = WSL_PACKAGE_VERSION_MAJOR; + Version->Minor = WSL_PACKAGE_VERSION_MINOR; + Version->Revision = WSL_PACKAGE_VERSION_REVISION; + } + else + { + Version->Major = std::get<0>(c_minClientVersion); + Version->Minor = std::get<1>(c_minClientVersion); + Version->Revision = std::get<2>(c_minClientVersion); + } + + return S_OK; } HRESULT WSLCSessionManager::CreateSession(const WSLCSessionSettings* WslcSessionSettings, WSLCSessionFlags Flags, IWSLCSession** WslcSession) diff --git a/src/windows/service/exe/WSLCSessionManager.h b/src/windows/service/exe/WSLCSessionManager.h index 197e8b174..6355f5576 100644 --- a/src/windows/service/exe/WSLCSessionManager.h +++ b/src/windows/service/exe/WSLCSessionManager.h @@ -71,7 +71,6 @@ class WSLCSessionManagerImpl WSLCSessionManagerImpl() = default; ~WSLCSessionManagerImpl(); - void GetVersion(_Out_ WSLCVersion* Version); void CreateSession(const WSLCSessionSettings* WslcSessionSettings, WSLCSessionFlags Flags, IWSLCSession** WslcSession); void ListSessions(_Out_ WSLCSessionInformation** Sessions, _Out_ ULONG* SessionsCount); void OpenSession(_In_ ULONG Id, _Out_ IWSLCSession** Session); @@ -172,6 +171,7 @@ class DECLSPEC_UUID("a9b7a1b9-0671-405c-95f1-e0612cb4ce8f") WSLCSessionManager WSLCSessionManager(wsl::windows::service::wslc::WSLCSessionManagerImpl* Impl); IFACEMETHOD(GetVersion)(_Out_ WSLCVersion* Version) override; + IFACEMETHOD(GetMinimumSupportedClientVersion)(_Out_ WSLCVersion* Version) override; IFACEMETHOD(CreateSession)(const WSLCSessionSettings* WslcSessionSettings, WSLCSessionFlags Flags, IWSLCSession** WslcSession) override; IFACEMETHOD(ListSessions)(_Out_ WSLCSessionInformation** Sessions, _Out_ ULONG* SessionsCount) override; IFACEMETHOD(OpenSession)(_In_ ULONG Id, _Out_ IWSLCSession** Session) override; diff --git a/src/windows/service/inc/wslc.idl b/src/windows/service/inc/wslc.idl index d3b92eab3..7ae0112ad 100644 --- a/src/windows/service/inc/wslc.idl +++ b/src/windows/service/inc/wslc.idl @@ -678,6 +678,7 @@ typedef enum _WSLCSessionFlags interface IWSLCSessionManager : IUnknown { HRESULT GetVersion([out] WSLCVersion* Version); + HRESULT GetMinimumSupportedClientVersion([out] WSLCVersion* Version); // Session management. HRESULT CreateSession([in, ref] const WSLCSessionSettings* Settings, WSLCSessionFlags Flags, [out] IWSLCSession** Session); @@ -690,4 +691,5 @@ cpp_quote("#define WSLC_E_BASE (0x0600)") cpp_quote("#define WSLC_E_IMAGE_NOT_FOUND MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, WSLC_E_BASE + 1) /* 0x80040601 */") cpp_quote("#define WSLC_E_CONTAINER_PREFIX_AMBIGUOUS MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, WSLC_E_BASE + 2) /* 0x80040602 */") cpp_quote("#define WSLC_E_CONTAINER_NOT_FOUND MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, WSLC_E_BASE + 3) /* 0x80040603 */") -cpp_quote("#define WSLC_E_VOLUME_NOT_FOUND MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, WSLC_E_BASE + 4) /* 0x80040604 */") \ No newline at end of file +cpp_quote("#define WSLC_E_VOLUME_NOT_FOUND MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, WSLC_E_BASE + 4) /* 0x80040604 */") +cpp_quote("#define WSLC_E_SDK_UPDATE_NEEDED MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, WSLC_E_BASE + 5) /* 0x80040605 */") \ No newline at end of file diff --git a/test/windows/WSLCTests.cpp b/test/windows/WSLCTests.cpp index 42ecb0829..4c082f074 100644 --- a/test/windows/WSLCTests.cpp +++ b/test/windows/WSLCTests.cpp @@ -183,6 +183,31 @@ class WSLCTests VERIFY_ARE_EQUAL(version.Revision, WSL_PACKAGE_VERSION_REVISION); } + TEST_METHOD(GetMinimumSupportedVersion) + { + WSL2_TEST_ONLY(); + + wil::com_ptr sessionManager; + VERIFY_SUCCEEDED(CoCreateInstance(__uuidof(WSLCSessionManager), nullptr, CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&sessionManager))); + + WSLCVersion version{}; + + VERIFY_SUCCEEDED(sessionManager->GetMinimumSupportedClientVersion(&version)); + + if (WSL_PACKAGE_VERSION_MAJOR < 2 || (WSL_PACKAGE_VERSION_MAJOR == 2 && WSL_PACKAGE_VERSION_MINOR < 8)) + { + VERIFY_ARE_EQUAL(version.Major, WSL_PACKAGE_VERSION_MAJOR); + VERIFY_ARE_EQUAL(version.Minor, WSL_PACKAGE_VERSION_MINOR); + VERIFY_ARE_EQUAL(version.Revision, WSL_PACKAGE_VERSION_REVISION); + } + else + { + VERIFY_ARE_EQUAL(version.Major, 2); + VERIFY_ARE_EQUAL(version.Minor, 8); + VERIFY_ARE_EQUAL(version.Revision, 0); + } + } + static RunningWSLCProcess::ProcessResult RunCommand(IWSLCSession* session, const std::vector& command, int timeout = 600000) { WSLCProcessLauncher process(command[0], command);