From 7df79503897fd3b046246d985a6faf92768a3fc9 Mon Sep 17 00:00:00 2001 From: Howard Kapustein Date: Sun, 27 Jul 2025 21:02:49 -0700 Subject: [PATCH 01/10] Remaining PackageVolume operations --- .../API/M.W.M.D.PackageVolume.cpp | 469 ++++++++++++++++++ .../API/M.W.M.D.PackageVolume.h | 37 ++ dev/PackageManager/API/PackageManager.idl | 153 +++--- .../API/PackageManager.vcxitems.filters | 6 + .../API/PackageVolumeTelemetry.h | 117 +++++ 5 files changed, 726 insertions(+), 56 deletions(-) create mode 100644 dev/PackageManager/API/PackageVolumeTelemetry.h diff --git a/dev/PackageManager/API/M.W.M.D.PackageVolume.cpp b/dev/PackageManager/API/M.W.M.D.PackageVolume.cpp index b288c7dc4f..857036d6b9 100644 --- a/dev/PackageManager/API/M.W.M.D.PackageVolume.cpp +++ b/dev/PackageManager/API/M.W.M.D.PackageVolume.cpp @@ -5,12 +5,15 @@ #include "M.W.M.D.PackageVolume.h" #include "Microsoft.Windows.Management.Deployment.PackageVolume.g.cpp" +#include "PackageVolumeTelemetry.h" + #include namespace winrt::Microsoft::Windows::Management::Deployment::implementation { PackageVolume::PackageVolume(winrt::Windows::Management::Deployment::PackageVolume const& value) { + m_windowsPackageVolume = value; m_isSystemVolume = value.IsSystemVolume(); m_mountPoint = value.MountPoint(); m_name = value.Name(); @@ -56,6 +59,12 @@ namespace winrt::Microsoft::Windows::Management::Deployment::implementation winrt::Windows::Management::Deployment::PackageVolume windowsPackageVolume{ packageManager.FindPackageVolume(name) }; return winrt::make(windowsPackageVolume); } + winrt::Microsoft::Windows::Management::Deployment::PackageVolume PackageVolume::GetDefault() + { + winrt::Windows::Management::Deployment::PackageManager packageManager; + winrt::Windows::Management::Deployment::PackageVolume windowsPackageVolume{ packageManager.GetDefaultPackageVolume() }; + return winrt::make(windowsPackageVolume); + } bool PackageVolume::IsSystemVolume() { return m_isSystemVolume; @@ -105,4 +114,464 @@ namespace winrt::Microsoft::Windows::Management::Deployment::implementation auto msixPackageVolumeRepair{ ::ExportLoader::GetFunction(dll.get(), "MsixPackageVolumeRepair") }; THROW_IF_FAILED(msixPackageVolumeRepair(m_packageStorePath.c_str())); } + + void PackageVolume::SetDefault() + { + THROW_HR_IF_NULL(E_ILLEGAL_METHOD_CALL, m_windowsPackageVolume); + + winrt::Windows::Management::Deployment::PackageManager packageManager; + packageManager.SetDefaultPackageVolume(m_windowsPackageVolume); + } + + winrt::Windows::Foundation::IAsyncOperation PackageVolume::AddAsync(hstring packageStorePath) + { + auto logTelemetry{ PackageVolumeTelemetry::Add::Start(packageStorePath) }; + + auto strong{ get_strong() }; + + auto cancellation{ co_await winrt::get_cancellation_token() }; + cancellation.enable_propagation(true); + + logTelemetry.IgnoreCurrentThread(); + co_await resume_background(); // Allow to register the progress and complete handler + auto logTelemetryContinuation{ logTelemetry.ContinueOnCurrentThread() }; + + winrt::Windows::Management::Deployment::PackageVolume windowsPackageVolume; + HRESULT error{}; + HRESULT extendedError{}; + winrt::hstring errorText; + winrt::guid activityId{}; + try + { + error = LOG_IF_FAILED_MSG(Add(packageStorePath, windowsPackageVolume, extendedError, errorText, activityId), + "ExtendedError:0x%08X PackageVolume.Add PackageStorePath:%ls", + extendedError, m_packageStorePath.c_str()); + } + catch (...) + { + const auto exception{ hresult_error(to_hresult(), take_ownership_from_abi) }; + error = LOG_HR_MSG(exception.code(), + "ExtendedError:0x%08X PackageVolume.Add PackageStorePath:%ls", + extendedError, m_packageStorePath.c_str()); + } + if (FAILED(error)) + { + co_return winrt::make( + PackageDeploymentStatus::CompletedFailure, activityId, error, extendedError, errorText); + } + + logTelemetry.Stop(windowsPackageVolume.MountPoint(), windowsPackageVolume.Name(), windowsPackageVolume.PackageStorePath()); + co_return winrt::make(windowsPackageVolume); + } + + winrt::Windows::Foundation::IAsyncOperationWithProgress PackageVolume::RemoveAsync() + { + THROW_HR_IF_NULL(E_ILLEGAL_METHOD_CALL, m_windowsPackageVolume); + + auto logTelemetry{ PackageVolumeTelemetry::Remove::Start(m_mountPoint, m_name, m_packageStorePath) }; + + auto strong{ get_strong() }; + + auto cancellation{ co_await winrt::get_cancellation_token() }; + cancellation.enable_propagation(true); + + logTelemetry.IgnoreCurrentThread(); + co_await resume_background(); // Allow to register the progress and complete handler + auto logTelemetryContinuation{ logTelemetry.ContinueOnCurrentThread() }; + + auto progress{ co_await winrt::get_progress_token() }; + auto packageDeploymentProgress{ + winrt::Microsoft::Windows::Management::Deployment::PackageDeploymentProgress{ + PackageDeploymentProgressStatus::Queued, 0} }; + progress(packageDeploymentProgress); + + HRESULT error{}; + HRESULT extendedError{}; + winrt::hstring errorText; + winrt::guid activityId{}; + try + { + error = LOG_IF_FAILED_MSG(Remove(packageDeploymentProgress, progress, extendedError, errorText, activityId), + "ExtendedError:0x%08X PackageVolume.Remove MountPoint:%ls Name:%ls PackageStorePath:%ls", + extendedError, m_mountPoint.c_str(), m_name.c_str(), m_packageStorePath.c_str()); + } + catch (...) + { + const auto exception{ hresult_error(to_hresult(), take_ownership_from_abi) }; + error = LOG_HR_MSG(exception.code(), + "ExtendedError:0x%08X PackageVolume.Remove MountPoint:%ls Name:%ls PackageStorePath:%ls", + extendedError, m_mountPoint.c_str(), m_name.c_str(), m_packageStorePath.c_str()); + } + if (FAILED(error)) + { + co_return winrt::make( + PackageDeploymentStatus::CompletedFailure, activityId, error, extendedError, errorText); + } + + logTelemetry.Stop(); + co_return winrt::make(PackageDeploymentStatus::CompletedSuccess, activityId); + } + + winrt::Windows::Foundation::IAsyncOperationWithProgress PackageVolume::SetOfflineAsync() + { + THROW_HR_IF_NULL(E_ILLEGAL_METHOD_CALL, m_windowsPackageVolume); + + auto logTelemetry{ PackageVolumeTelemetry::SetOffline::Start(m_mountPoint, m_name, m_packageStorePath) }; + + auto strong{ get_strong() }; + + auto cancellation{ co_await winrt::get_cancellation_token() }; + cancellation.enable_propagation(true); + + logTelemetry.IgnoreCurrentThread(); + co_await resume_background(); // Allow to register the progress and complete handler + auto logTelemetryContinuation{ logTelemetry.ContinueOnCurrentThread() }; + + auto progress{ co_await winrt::get_progress_token() }; + auto packageDeploymentProgress{ + winrt::Microsoft::Windows::Management::Deployment::PackageDeploymentProgress{ + PackageDeploymentProgressStatus::Queued, 0} }; + progress(packageDeploymentProgress); + + HRESULT error{}; + HRESULT extendedError{}; + winrt::hstring errorText; + winrt::guid activityId{}; + try + { + error = LOG_IF_FAILED_MSG(SetOnline(false, packageDeploymentProgress, progress, extendedError, errorText, activityId), + "ExtendedError:0x%08X PackageVolume.SetOffline MountPoint:%ls Name:%ls PackageStorePath:%ls", + extendedError, m_mountPoint.c_str(), m_name.c_str(), m_packageStorePath.c_str()); + } + catch (...) + { + const auto exception{ hresult_error(to_hresult(), take_ownership_from_abi) }; + error = LOG_HR_MSG(exception.code(), + "ExtendedError:0x%08X PackageVolume.SetOffline MountPoint:%ls Name:%ls PackageStorePath:%ls", + extendedError, m_mountPoint.c_str(), m_name.c_str(), m_packageStorePath.c_str()); + } + if (FAILED(error)) + { + co_return winrt::make( + PackageDeploymentStatus::CompletedFailure, activityId, error, extendedError, errorText); + } + + logTelemetry.Stop(); + co_return winrt::make(PackageDeploymentStatus::CompletedSuccess, activityId); + } + + winrt::Windows::Foundation::IAsyncOperationWithProgress PackageVolume::SetOnlineAsync() + { + THROW_HR_IF_NULL(E_ILLEGAL_METHOD_CALL, m_windowsPackageVolume); + + auto logTelemetry{ PackageVolumeTelemetry::SetOnline::Start(m_mountPoint, m_name, m_packageStorePath) }; + + auto strong{ get_strong() }; + + auto cancellation{ co_await winrt::get_cancellation_token() }; + cancellation.enable_propagation(true); + + logTelemetry.IgnoreCurrentThread(); + co_await resume_background(); // Allow to register the progress and complete handler + auto logTelemetryContinuation{ logTelemetry.ContinueOnCurrentThread() }; + + auto progress{ co_await winrt::get_progress_token() }; + auto packageDeploymentProgress{ + winrt::Microsoft::Windows::Management::Deployment::PackageDeploymentProgress{ + PackageDeploymentProgressStatus::Queued, 0} }; + progress(packageDeploymentProgress); + + HRESULT error{}; + HRESULT extendedError{}; + winrt::hstring errorText; + winrt::guid activityId{}; + try + { + error = LOG_IF_FAILED_MSG(SetOnline(false, packageDeploymentProgress, progress, extendedError, errorText, activityId), + "ExtendedError:0x%08X PackageVolume.SetOnline MountPoint:%ls Name:%ls PackageStorePath:%ls", + extendedError, m_mountPoint.c_str(), m_name.c_str(), m_packageStorePath.c_str()); + } + catch (...) + { + const auto exception{ hresult_error(to_hresult(), take_ownership_from_abi) }; + error = LOG_HR_MSG(exception.code(), + "ExtendedError:0x%08X PackageVolume.SetOnline MountPoint:%ls Name:%ls PackageStorePath:%ls", + extendedError, m_mountPoint.c_str(), m_name.c_str(), m_packageStorePath.c_str()); + } + if (FAILED(error)) + { + co_return winrt::make( + PackageDeploymentStatus::CompletedFailure, activityId, error, extendedError, errorText); + } + + logTelemetry.Stop(); + co_return winrt::make(PackageDeploymentStatus::CompletedSuccess, activityId); + } + + winrt::Windows::Foundation::IAsyncOperation PackageVolume::GetAvailableSpaceAsync() + { + THROW_HR_IF_NULL(E_ILLEGAL_METHOD_CALL, m_windowsPackageVolume); + + auto logTelemetry{ PackageVolumeTelemetry::GetAvailableSpace::Start(m_mountPoint, m_name, m_packageStorePath) }; + + auto strong{ get_strong() }; + + auto cancellation{ co_await winrt::get_cancellation_token() }; + cancellation.enable_propagation(true); + + logTelemetry.IgnoreCurrentThread(); + co_await resume_background(); // Allow to register the progress and complete handler + auto logTelemetryContinuation{ logTelemetry.ContinueOnCurrentThread() }; + + uint64_t availableSpace{}; + HRESULT error{}; + HRESULT extendedError{}; + winrt::hstring errorText; + winrt::guid activityId{}; + try + { + error = LOG_IF_FAILED_MSG(GetAvailableSpace(availableSpace, extendedError, errorText, activityId), + "ExtendedError:0x%08X PackageVolume.GetAvailableSpace MountPoint:%ls Name:%ls PackageStorePath:%ls : %ls", + extendedError, m_mountPoint.c_str(), m_name.c_str(), m_packageStorePath.c_str(), errorText.c_str()); + } + catch (...) + { + const auto exception{ hresult_error(to_hresult(), take_ownership_from_abi) }; + error = LOG_HR_MSG(exception.code(), + "ExtendedError:0x%08X PackageVolume.GetAvailableSpace MountPoint:%ls Name:%ls PackageStorePath:%ls : %ls", + extendedError, m_mountPoint.c_str(), m_name.c_str(), m_packageStorePath.c_str(), errorText.c_str()); + } + if (FAILED(error)) + { + co_return winrt::make( + PackageDeploymentStatus::CompletedFailure, activityId, error, extendedError, errorText); + } + + logTelemetry.Stop(availableSpace); + co_return availableSpace; + } + + HRESULT PackageDeploymentManager::Add( + winrt::hstring const& packageStorePath, + winrt::Windows::Management::Deployment::PackageVolume& windowsPackageVolume, + HRESULT& extendedError, + winrt::hstring& errorText, + winrt::guid& activityId) + { + extendedError = S_OK; + errorText.clear(); + activityId = winrt::guid{}; + + auto deploymentOperation{ m_packageManager.AddPackageVolumeAsync(packageStorePath, wil::out_param(windowsPackageVolume)) }; + deploymentOperation.get(); + try + { + const auto deploymentResult{ deploymentOperation.GetResults() }; + const HRESULT error{ static_cast(deploymentOperation.ErrorCode()) }; + extendedError = deploymentResult.ExtendedErrorCode(); + errorText = deploymentResult.ErrorText(); + activityId = deploymentResult.ActivityId(); + const auto status{ deploymentOperation.Status() }; + if (status == winrt::Windows::Foundation::AsyncStatus::Error) + { + RETURN_IF_FAILED_MSG(error, + "ExtendedError:0x%08X PackageVolume.Add PackageStorePath:%ls : %ls", + extendedError, packageStorePath.c_str(), errorText.c_str()); + + // Status=Error but SUCCEEDED(error) == This.Should.Never.Happen. + FAIL_FAST_HR_MSG(E_UNEXPECTED, + "ExtendedError:0x%08X PackageVolume.Add PackageStorePath:%ls : %ls", + extendedError, packageStorePath.c_str(), errorText.c_str()); + } + else if (status == winrt::Windows::Foundation::AsyncStatus::Canceled) + { + RETURN_WIN32_MSG(ERROR_CANCELLED, + "PackageVolume.Add PackageStorePath:%ls", + packageStorePath.c_str()); + } + FAIL_FAST_HR_IF_MSG(E_UNEXPECTED, status != winrt::Windows::Foundation::AsyncStatus::Completed, + "Status:%d PackageVolume.Add PackageStorePath:%ls : %ls", + static_cast(status), packageStorePath.c_str(), errorText.c_str()); + } + catch (...) + { + auto exception{ hresult_error(to_hresult(), take_ownership_from_abi) }; + THROW_HR_MSG(exception.code(), + "ExtendedError:0x%08X PackageVolume.Add PackageStorePath:%ls : %ls", + extendedError, packageStorePath.c_str(), errorText.c_str()); + } + return S_OK; + } + + HRESULT PackageDeploymentManager::Remove( + winrt::Microsoft::Windows::Management::Deployment::PackageDeploymentProgress& packageDeploymentProgress, + wistd::function progress, + HRESULT& extendedError, + winrt::hstring& errorText, + winrt::guid& activityId) + { + extendedError = S_OK; + errorText.clear(); + activityId = winrt::guid{}; + + auto deploymentOperation{ m_packageManager.RemovePackageVolumeAsync(m_windowsPackageVolume) }; + deploymentOperation.Progress([&](winrt::Windows::Foundation::IAsyncOperationWithProgress< + winrt::Windows::Management::Deployment::DeploymentResult, + winrt::Windows::Management::Deployment::DeploymentProgress> const& /*sender*/, + winrt::Windows::Management::Deployment::DeploymentProgress const& progressInfo) + { + packageDeploymentProgress.Progress = progressInfo.percentage; + progress(packageDeploymentProgress); + }); + deploymentOperation.get(); + try + { + const auto deploymentResult{ deploymentOperation.GetResults() }; + const HRESULT error{ static_cast(deploymentOperation.ErrorCode()) }; + extendedError = deploymentResult.ExtendedErrorCode(); + errorText = deploymentResult.ErrorText(); + activityId = deploymentResult.ActivityId(); + const auto status{ deploymentOperation.Status() }; + if (status == winrt::Windows::Foundation::AsyncStatus::Error) + { + RETURN_IF_FAILED_MSG(error, + "ExtendedError:0x%08X PackageVolume.Remove MountPoint:%ls Name:%ls PackageStorePath:%ls : %ls", + extendedError, m_mountPoint.c_str(), m_name.c_str(), m_packageStorePath.c_str(), errorText.c_str()); + + // Status=Error but SUCCEEDED(error) == This.Should.Never.Happen. + FAIL_FAST_HR_MSG(E_UNEXPECTED, + "ExtendedError:0x%08X PackageVolume.Remove MountPoint:%ls Name:%ls PackageStorePath:%ls : %ls", + extendedError, m_mountPoint.c_str(), m_name.c_str(), m_packageStorePath.c_str(), errorText.c_str()); + } + else if (status == winrt::Windows::Foundation::AsyncStatus::Canceled) + { + RETURN_WIN32_MSG(ERROR_CANCELLED, + "PackageVolume.Remove MountPoint:%ls Name:%ls PackageStorePath:%ls", + m_mountPoint.c_str(), m_name.c_str(), m_packageStorePath.c_str()); + } + FAIL_FAST_HR_IF_MSG(E_UNEXPECTED, status != winrt::Windows::Foundation::AsyncStatus::Completed, + "Status:%d PackageVolume.Remove MountPoint:%ls Name:%ls PackageStorePath:%ls : %ls", + static_cast(status), m_mountPoint.c_str(), m_name.c_str(), m_packageStorePath.c_str(), errorText.c_str()); + } + catch (...) + { + auto exception{ hresult_error(to_hresult(), take_ownership_from_abi) }; + THROW_HR_MSG(exception.code(), + "ExtendedError:0x%08X PackageVolume.Remove MountPoint:%ls Name:%ls PackageStorePath:%ls : %ls", + extendedError, m_mountPoint.c_str(), m_name.c_str(), m_packageStorePath.c_str(), errorText.c_str()); + } + return S_OK; + } + + HRESULT PackageDeploymentManager::SetOnline( + const bool online, + winrt::Microsoft::Windows::Management::Deployment::PackageDeploymentProgress& packageDeploymentProgress, + wistd::function progress, + HRESULT& extendedError, + winrt::hstring& errorText, + winrt::guid& activityId) + { + extendedError = S_OK; + errorText.clear(); + activityId = winrt::guid{}; + + auto deploymentOperation{ m_packageManager.SetPackageVolumeOnlineAsync(m_windowsPackageVolume) }; + deploymentOperation.Progress([&](winrt::Windows::Foundation::IAsyncOperationWithProgress< + winrt::Windows::Management::Deployment::DeploymentResult, + winrt::Windows::Management::Deployment::DeploymentProgress> const& /*sender*/, + winrt::Windows::Management::Deployment::DeploymentProgress const& progressInfo) + { + packageDeploymentProgress.Progress = progressInfo.percentage; + progress(packageDeploymentProgress); + }); + deploymentOperation.get(); + try + { + const auto deploymentResult{ deploymentOperation.GetResults() }; + const HRESULT error{ static_cast(deploymentOperation.ErrorCode()) }; + extendedError = deploymentResult.ExtendedErrorCode(); + errorText = deploymentResult.ErrorText(); + activityId = deploymentResult.ActivityId(); + const auto status{ deploymentOperation.Status() }; + if (status == winrt::Windows::Foundation::AsyncStatus::Error) + { + RETURN_IF_FAILED_MSG(error, + "ExtendedError:0x%08X PackageVolume.Set%hs MountPoint:%ls Name:%ls PackageStorePath:%ls : %ls", + extendedError, online ? "Online" : "Offline", m_mountPoint.c_str(), m_name.c_str(), m_packageStorePath.c_str(), errorText.c_str()); + + // Status=Error but SUCCEEDED(error) == This.Should.Never.Happen. + FAIL_FAST_HR_MSG(E_UNEXPECTED, + "ExtendedError:0x%08X PackageVolume.Set%hs MountPoint:%ls Name:%ls PackageStorePath:%ls : %ls", + extendedError, online ? "Online" : "Offline", m_mountPoint.c_str(), m_name.c_str(), m_packageStorePath.c_str(), errorText.c_str()); + } + else if (status == winrt::Windows::Foundation::AsyncStatus::Canceled) + { + RETURN_WIN32_MSG(ERROR_CANCELLED, + "PackageVolume.Set%hs MountPoint:%ls Name:%ls PackageStorePath:%ls", + online ? "Online" : "Offline", m_mountPoint.c_str(), m_name.c_str(), m_packageStorePath.c_str()); + } + FAIL_FAST_HR_IF_MSG(E_UNEXPECTED, status != winrt::Windows::Foundation::AsyncStatus::Completed, + "Status:%d PackageVolume.Set%hs MountPoint:%ls Name:%ls PackageStorePath:%ls : %ls", + static_cast(status), online ? "Online" : "Offline", m_mountPoint.c_str(), m_name.c_str(), m_packageStorePath.c_str(), errorText.c_str()); + } + catch (...) + { + auto exception{ hresult_error(to_hresult(), take_ownership_from_abi) }; + THROW_HR_MSG(exception.code(), + "ExtendedError:0x%08X PackageVolume.Set%hs MountPoint:%ls Name:%ls PackageStorePath:%ls : %ls", + extendedError, online ? "Online" : "Offline", m_mountPoint.c_str(), m_name.c_str(), m_packageStorePath.c_str(), errorText.c_str()); + } + return S_OK; + } + + HRESULT PackageDeploymentManager::GetAvailableSpace( + uint32_t& availableSpace, + HRESULT& extendedError, + winrt::hstring& errorText, + winrt::guid& activityId) + { + extendedError = S_OK; + errorText.clear(); + activityId = winrt::guid{}; + + auto deploymentOperation{ m_windowsPackageVolume.GetAvailableSpaceAsync(availableSpace) }; + deploymentOperation.get(); + try + { + const auto deploymentResult{ deploymentOperation.GetResults() }; + const HRESULT error{ static_cast(deploymentOperation.ErrorCode()) }; + extendedError = deploymentResult.ExtendedErrorCode(); + errorText = deploymentResult.ErrorText(); + activityId = deploymentResult.ActivityId(); + const auto status{ deploymentOperation.Status() }; + if (status == winrt::Windows::Foundation::AsyncStatus::Error) + { + RETURN_IF_FAILED_MSG(error, + "ExtendedError:0x%08X PackageVolume.GetAvailableSpace MountPoint:%ls Name:%ls PackageStorePath:%ls : %ls", + extendedError, m_mountPoint.c_str(), m_name.c_str(), m_packageStorePath.c_str(), errorText.c_str()); + + // Status=Error but SUCCEEDED(error) == This.Should.Never.Happen. + FAIL_FAST_HR_MSG(E_UNEXPECTED, + "ExtendedError:0x%08X PackageVolume.GetAvailableSpace MountPoint:%ls Name:%ls PackageStorePath:%ls : %ls", + extendedError, m_mountPoint.c_str(), m_name.c_str(), m_packageStorePath.c_str(), errorText.c_str()); + } + else if (status == winrt::Windows::Foundation::AsyncStatus::Canceled) + { + RETURN_WIN32_MSG(ERROR_CANCELLED, + "PackageVolume.GetAvailableSpace MountPoint:%ls Name:%ls PackageStorePath:%ls", + m_mountPoint.c_str(), m_name.c_str(), m_packageStorePath.c_str()); + } + FAIL_FAST_HR_IF_MSG(E_UNEXPECTED, status != winrt::Windows::Foundation::AsyncStatus::Completed, + "Status:%d PackageVolume.GetAvailableSpace MountPoint:%ls Name:%ls PackageStorePath:%ls : %ls", + static_cast(status), m_mountPoint.c_str(), m_name.c_str(), m_packageStorePath.c_str(), errorText.c_str()); + } + catch (...) + { + auto exception{ hresult_error(to_hresult(), take_ownership_from_abi) }; + THROW_HR_MSG(exception.code(), + "ExtendedError:0x%08X PackageVolume.GetAvailableSpace MountPoint:%ls Name:%ls PackageStorePath:%ls : %ls", + extendedError, m_mountPoint.c_str(), m_name.c_str(), m_packageStorePath.c_str(), errorText.c_str()); + } + return S_OK; + } } diff --git a/dev/PackageManager/API/M.W.M.D.PackageVolume.h b/dev/PackageManager/API/M.W.M.D.PackageVolume.h index 5d8ce07b6c..c267048f97 100644 --- a/dev/PackageManager/API/M.W.M.D.PackageVolume.h +++ b/dev/PackageManager/API/M.W.M.D.PackageVolume.h @@ -15,6 +15,7 @@ namespace winrt::Microsoft::Windows::Management::Deployment::implementation static winrt::Windows::Foundation::Collections::IVector FindPackageVolumes(); static winrt::Microsoft::Windows::Management::Deployment::PackageVolume FindPackageVolumeByPath(hstring const& packageStorePath); static winrt::Microsoft::Windows::Management::Deployment::PackageVolume FindPackageVolumeByName(hstring const& name); + static winrt::Microsoft::Windows::Management::Deployment::PackageVolume GetDefault(); bool IsSystemVolume(); hstring MountPoint(); @@ -25,8 +26,44 @@ namespace winrt::Microsoft::Windows::Management::Deployment::implementation bool IsAppxInstallSupported(); bool IsRepairNeeded(); void Repair(); + void SetDefault(); + winrt::Windows::Foundation::IAsyncOperation AddAsync(hstring packageStorePath); + winrt::Windows::Foundation::IAsyncOperationWithProgress RemoveAsync(); + winrt::Windows::Foundation::IAsyncOperationWithProgress SetOfflineAsync(); + winrt::Windows::Foundation::IAsyncOperationWithProgress SetOnlineAsync(); + winrt::Windows::Foundation::IAsyncOperation GetAvailableSpaceAsync(); private: + HRESULT Add( + hstring const& packageStorePath, + winrt::Windows::Management::Deployment::PackageVolume& windowsPackageVolume, + HRESULT& extendedError, + winrt::hstring& errorText, + winrt::guid& activityId); + + HRESULT Remove( + winrt::Microsoft::Windows::Management::Deployment::PackageDeploymentProgress& packageDeploymentProgress, + wistd::function progress, + HRESULT& extendedError, + winrt::hstring& errorText, + winrt::guid& activityId); + + HRESULT SetOnline( + const bool online, + winrt::Microsoft::Windows::Management::Deployment::PackageDeploymentProgress& packageDeploymentProgress, + wistd::function progress, + HRESULT& extendedError, + winrt::hstring& errorText, + winrt::guid& activityId); + + HRESULT GetAvailableSpace( + uint32_t& availableSpace, + HRESULT& extendedError, + winrt::hstring& errorText, + winrt::guid& activityId); + + private: + winrt::Windows::Management::Deployment::PackageVolume m_windowsPackageVolume; bool m_isSystemVolume{}; hstring m_mountPoint; hstring m_name; diff --git a/dev/PackageManager/API/PackageManager.idl b/dev/PackageManager/API/PackageManager.idl index 1a2a0e27b2..da63f8b8c2 100644 --- a/dev/PackageManager/API/PackageManager.idl +++ b/dev/PackageManager/API/PackageManager.idl @@ -23,6 +23,62 @@ namespace Microsoft.Windows.Management.Deployment ProvisionPackage_Framework = 6, }; + /// The progress status of the deployment request. + /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.deploymentprogress.state + [contract(PackageDeploymentContract, 1)] + enum PackageDeploymentProgressStatus + { + Queued = 0, // The request is queued + InProgress = 1, // The request is in progress + CompletedSuccess = 2, // The request completed successfully + CompletedFailure = 3, // The request failed with some critical internal error. + }; + + /// Contains progress information for the deployment request. + /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.deploymentprogress + [contract(PackageDeploymentContract, 1)] + struct PackageDeploymentProgress + { + PackageDeploymentProgressStatus Status; + + /// The progress percentage of the deployment request. + /// @note This is a double with values 0.0-1.0. Windows.Management.Deployment.DeploymentProgress.percentage is uint32 with values 0-100. + Double Progress; + }; + + /// The status of the deployment request. + /// @see PackageDeploymentResult.Status + [contract(PackageDeploymentContract, 1)] + enum PackageDeploymentStatus + { + InProgress = 0, // The request is in progress + CompletedSuccess = 1, // The request completed successfully + CompletedFailure = 2, // The request failed with some critical internal error. + }; + + /// Provides the result of a deployment request. + /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.deploymentresult + [contract(PackageDeploymentContract, 1)] + runtimeclass PackageDeploymentResult + { + PackageDeploymentStatus Status { get; }; + + /// The extended error code can be used to distinguish a specific error condition which needs to be handled differently from the general error indicated by the return code. The extended error code may provide a more specific reason for the failure that caused the general error. Also, it usually corresponds directly to the specific message in the ErrorText. + HRESULT Error { get; }; + + /// The extended error code can be used to distinguish a specific error condition which needs to be handled differently from the general error indicated by the return code. The extended error code may provide a more specific reason for the failure that caused the general error. Also, it usually corresponds directly to the specific message in the ErrorText. + /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.deploymentresult.extendederrorcode + HRESULT ExtendedError { get; }; + + /// Gets extended error text for the error if the deployment operation is not successful. + /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.deploymentresult.errortext + String ErrorText { get; }; + + /// Gets the activity identifier used to look up an event in Windows Event Viewer. Gets the activity identifier used to look up an event. All events of a deployment operation are logged with the same activityId. + /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.deploymentresult.activityid + Guid ActivityId { get; }; + } + /// Represents a package storage volume. /// @note A volume 'name' is the volume's media ID (you can treat 'Volume Name' == 'Volume Media ID'). /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagevolume @@ -71,6 +127,47 @@ namespace Microsoft.Windows.Management.Deployment /// Repair the package volume (if necessary). void Repair(); + + /// Return the default package volume. + /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagemanager.getdefaultpackagevolume + [contract(PackageDeploymentContract, 2)] + static PackageVolume GetDefault(); + + /// Set the default package volume. + /// @see //learn.microsoft.com/uwp/api/windows.management.deployment.packagemanager.setdefaultpackagevolume + [contract(PackageDeploymentContract, 2)] + void SetDefault(); + + /// Create a new package volume. + /// @param packageStorePath The absolute path of the Package store. + /// @note This requires admin privilege. + /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagemanager.addpackagevolumeasync + [contract(PackageDeploymentContract, 2)] + Windows.Foundation.IAsyncOperation AddAsync(String packageStorePath); + + /// @note The caller must be running with Medium IL (or higher) + /// OR running in an AppContainer with the packageManagement restricted capability + /// OR caller has package identity and the publisher matches the publisher of the volume being removed. + /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagemanager.removepackagevolumeasync + [contract(PackageDeploymentContract, 2)] + Windows.Foundation.IAsyncOperationWithProgress RemoveAsync(); + + /// Set the package volume to an offline state. + /// @note This requires admin privilege. + /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagemanager.setpackagevolumeofflineasync + [contract(PackageDeploymentContract, 2)] + Windows.Foundation.IAsyncOperationWithProgress SetOfflineAsync(); + + /// Set the package volume to an online state. + /// @note This requires admin privilege. + /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagemanager.setpackagevolumeonlineasync + [contract(PackageDeploymentContract, 2)] + Windows.Foundation.IAsyncOperationWithProgress SetOnlineAsync(); + + /// Get the available space (bytes). + /// @see https://learn.microsoft.com/en-us/uwp/api/windows.management.deployment.packagevolume.getavailablespaceasync?view=winrt-26100 + [contract(PackageDeploymentContract, 2)] + Windows.Foundation.IAsyncOperation GetAvailableSpaceAsync(); }; /// Defines the stub behavior for an app package that is being added or staged. @@ -93,62 +190,6 @@ namespace Microsoft.Windows.Management.Deployment NewerAvailable = 2, }; - /// The progress status of the deployment request. - /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.deploymentprogress.state - [contract(PackageDeploymentContract, 1)] - enum PackageDeploymentProgressStatus - { - Queued = 0, // The request is queued - InProgress = 1, // The request is in progress - CompletedSuccess = 2, // The request completed successfully - CompletedFailure = 3, // The request failed with some critical internal error. - }; - - /// Contains progress information for the deployment request. - /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.deploymentprogress - [contract(PackageDeploymentContract, 1)] - struct PackageDeploymentProgress - { - PackageDeploymentProgressStatus Status; - - /// The progress percentage of the deployment request. - /// @note This is a double with values 0.0-1.0. Windows.Management.Deployment.DeploymentProgress.percentage is uint32 with values 0-100. - Double Progress; - }; - - /// The status of the deployment request. - /// @see PackageDeploymentResult.Status - [contract(PackageDeploymentContract, 1)] - enum PackageDeploymentStatus - { - InProgress = 0, // The request is in progress - CompletedSuccess = 1, // The request completed successfully - CompletedFailure = 2, // The request failed with some critical internal error. - }; - - /// Provides the result of a deployment request. - /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.deploymentresult - [contract(PackageDeploymentContract, 1)] - runtimeclass PackageDeploymentResult - { - PackageDeploymentStatus Status { get; }; - - /// The extended error code can be used to distinguish a specific error condition which needs to be handled differently from the general error indicated by the return code. The extended error code may provide a more specific reason for the failure that caused the general error. Also, it usually corresponds directly to the specific message in the ErrorText. - HRESULT Error { get; }; - - /// The extended error code can be used to distinguish a specific error condition which needs to be handled differently from the general error indicated by the return code. The extended error code may provide a more specific reason for the failure that caused the general error. Also, it usually corresponds directly to the specific message in the ErrorText. - /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.deploymentresult.extendederrorcode - HRESULT ExtendedError { get; }; - - /// Gets extended error text for the error if the deployment operation is not successful. - /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.deploymentresult.errortext - String ErrorText { get; }; - - /// Gets the activity identifier used to look up an event in Windows Event Viewer. Gets the activity identifier used to look up an event. All events of a deployment operation are logged with the same activityId. - /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.deploymentresult.activityid - Guid ActivityId { get; }; - } - [contract(PackageDeploymentContract, 1)] runtimeclass PackageSetItem { diff --git a/dev/PackageManager/API/PackageManager.vcxitems.filters b/dev/PackageManager/API/PackageManager.vcxitems.filters index e41fd8b76e..0be22da55f 100644 --- a/dev/PackageManager/API/PackageManager.vcxitems.filters +++ b/dev/PackageManager/API/PackageManager.vcxitems.filters @@ -106,6 +106,12 @@ Header Files + + Header Files + + + Header Files + diff --git a/dev/PackageManager/API/PackageVolumeTelemetry.h b/dev/PackageManager/API/PackageVolumeTelemetry.h new file mode 100644 index 0000000000..f5388d0dff --- /dev/null +++ b/dev/PackageManager/API/PackageVolumeTelemetry.h @@ -0,0 +1,117 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT license. + +#pragma once + +#include + +#include "M.W.M.D.PackageDeploymentManager.h" + +DECLARE_TRACELOGGING_CLASS(PackageVolumeTelemetryProvider, + "Microsoft.WindowsAppSDK.Deployment.PackageVolumeTelemetry", + // {e1647c65-18e6-413d-8f81-28ab44c0f4f0} + (0xe1647c65, 0x18e6, 0x413d, 0x8f, 0x81, 0x28, 0xab, 0x44, 0xc0, 0xf4, 0xf0)); + +class PackageVolumeTelemetry : public wil::TraceLoggingProvider +{ + IMPLEMENT_TELEMETRY_CLASS(PackageVolumeTelemetry, PackageVolumeTelemetryProvider); + +public: + BEGIN_COMPLIANT_MEASURES_ACTIVITY_CLASS(Add, PDT_ProductAndServicePerformance); + DEFINE_ACTIVITY_START(winrt::hstring const& packageStorePath) noexcept try + { + TraceLoggingClassWriteStart( + Add, + _GENERIC_PARTB_FIELDS_ENABLED, + TraceLoggingWideString(packageStorePath.c_str(), "PackageStorePath")); + } + CATCH_LOG() + DEFINE_ACTIVITY_STOP(winrt::hstring const& mountPoint, winrt::hstring const& name, winrt::hstring const& packageStorePath) noexcept try + { + TraceLoggingClassWriteStop( + Add, + _GENERIC_PARTB_FIELDS_ENABLED, + TraceLoggingWideString(mountPoint.c_str(), "MountPoint"), + TraceLoggingWideString(name.c_str(), "Name"), + TraceLoggingWideString(packageStorePath.c_str(), "PackageStorePath")); + } + CATCH_LOG() + END_ACTIVITY_CLASS(); + BEGIN_COMPLIANT_MEASURES_ACTIVITY_CLASS(Remove, PDT_ProductAndServicePerformance); + DEFINE_ACTIVITY_START(winrt::hstring const& mountPoint, winrt::hstring const& name, winrt::hstring const& packageStorePath) noexcept try + { + TraceLoggingClassWriteStart( + Remove, + _GENERIC_PARTB_FIELDS_ENABLED, + TraceLoggingWideString(mountPoint.c_str(), "MountPoint"), + TraceLoggingWideString(name.c_str(), "Name"), + TraceLoggingWideString(packageStorePath.c_str(), "PackageStorePath")); + } + CATCH_LOG() + DEFINE_ACTIVITY_STOP() noexcept try + { + TraceLoggingClassWriteStop( + Remove, + _GENERIC_PARTB_FIELDS_ENABLED); + } + CATCH_LOG() + END_ACTIVITY_CLASS(); + BEGIN_COMPLIANT_MEASURES_ACTIVITY_CLASS(SetOffline, PDT_ProductAndServicePerformance); + DEFINE_ACTIVITY_START(winrt::hstring const& mountPoint, winrt::hstring const& name, winrt::hstring const& packageStorePath) noexcept try + { + TraceLoggingClassWriteStart( + SetOffline, + _GENERIC_PARTB_FIELDS_ENABLED, + TraceLoggingWideString(mountPoint.c_str(), "MountPoint"), + TraceLoggingWideString(name.c_str(), "Name"), + TraceLoggingWideString(packageStorePath.c_str(), "PackageStorePath")); + } + CATCH_LOG() + DEFINE_ACTIVITY_STOP() noexcept try + { + TraceLoggingClassWriteStop( + SetOffline, + _GENERIC_PARTB_FIELDS_ENABLED); + } + CATCH_LOG() + END_ACTIVITY_CLASS(); + BEGIN_COMPLIANT_MEASURES_ACTIVITY_CLASS(SetOnline, PDT_ProductAndServicePerformance); + DEFINE_ACTIVITY_START(winrt::hstring const& mountPoint, winrt::hstring const& name, winrt::hstring const& packageStorePath) noexcept try + { + TraceLoggingClassWriteStart( + SetOnline, + _GENERIC_PARTB_FIELDS_ENABLED, + TraceLoggingWideString(mountPoint.c_str(), "MountPoint"), + TraceLoggingWideString(name.c_str(), "Name"), + TraceLoggingWideString(packageStorePath.c_str(), "PackageStorePath")); + } + CATCH_LOG() + DEFINE_ACTIVITY_STOP() noexcept try + { + TraceLoggingClassWriteStop( + SetOnline, + _GENERIC_PARTB_FIELDS_ENABLED); + } + CATCH_LOG() + END_ACTIVITY_CLASS(); + BEGIN_COMPLIANT_MEASURES_ACTIVITY_CLASS(GetAvailableSpace, PDT_ProductAndServicePerformance); + DEFINE_ACTIVITY_START(winrt::hstring const& mountPoint, winrt::hstring const& name, winrt::hstring const& packageStorePath) noexcept try + { + TraceLoggingClassWriteStart( + GetAvailableSpace, + _GENERIC_PARTB_FIELDS_ENABLED, + TraceLoggingWideString(mountPoint.c_str(), "MountPoint"), + TraceLoggingWideString(name.c_str(), "Name"), + TraceLoggingWideString(packageStorePath.c_str(), "PackageStorePath")); + } + CATCH_LOG() + DEFINE_ACTIVITY_STOP(const uint64_t availableSpace) noexcept try + { + TraceLoggingClassWriteStop( + GetAvailableSpace, + _GENERIC_PARTB_FIELDS_ENABLED, + TraceLoggingUInt64(availableSpace, "AvailableSpace")); + } + CATCH_LOG() + END_ACTIVITY_CLASS(); +}; From 1c31e136e4c634b6b48d635f153f21cc3720cf8a Mon Sep 17 00:00:00 2001 From: Howard Kapustein Date: Thu, 7 Aug 2025 00:52:26 -0700 Subject: [PATCH 02/10] Partial implementation --- .../API/M.W.M.D.PackageVolume.cpp | 204 ++++-------------- .../API/M.W.M.D.PackageVolume.h | 16 +- dev/PackageManager/API/PackageManager.idl | 33 ++- .../API/PackageManager.vcxitems.filters | 8 +- 4 files changed, 74 insertions(+), 187 deletions(-) diff --git a/dev/PackageManager/API/M.W.M.D.PackageVolume.cpp b/dev/PackageManager/API/M.W.M.D.PackageVolume.cpp index 857036d6b9..8b753aa9b9 100644 --- a/dev/PackageManager/API/M.W.M.D.PackageVolume.cpp +++ b/dev/PackageManager/API/M.W.M.D.PackageVolume.cpp @@ -11,6 +11,45 @@ namespace winrt::Microsoft::Windows::Management::Deployment::implementation { + bool PackageVolume::IsFeatureSupported(winrt::Microsoft::Windows::Management::Deployment::PackageVolumeFeature feature) + { + switch (feature) + { + case winrt::Microsoft::Windows::Management::Deployment::PackageVolumeFeature::GetDefault: + { + return true; + } + case winrt::Microsoft::Windows::Management::Deployment::PackageVolumeFeature::SetDefault: + { + return true; + } + case winrt::Microsoft::Windows::Management::Deployment::PackageVolumeFeature::Add: + { + return true; + } + case winrt::Microsoft::Windows::Management::Deployment::PackageVolumeFeature::Remove: + { + return true; + } + case winrt::Microsoft::Windows::Management::Deployment::PackageVolumeFeature::SetOffline: + { + return true; + } + case winrt::Microsoft::Windows::Management::Deployment::PackageVolumeFeature::SetOnline: + { + return true; + } + case winrt::Microsoft::Windows::Management::Deployment::PackageVolumeFeature::GetAvailableSpace: + { + return true; + } + default: + { + std::ignore = LOG_HR_MSG(E_UNEXPECTED, "Feature:%d", static_cast(feature)); + return false; + } + } + } PackageVolume::PackageVolume(winrt::Windows::Management::Deployment::PackageVolume const& value) { m_windowsPackageVolume = value; @@ -132,33 +171,8 @@ namespace winrt::Microsoft::Windows::Management::Deployment::implementation auto cancellation{ co_await winrt::get_cancellation_token() }; cancellation.enable_propagation(true); - logTelemetry.IgnoreCurrentThread(); - co_await resume_background(); // Allow to register the progress and complete handler - auto logTelemetryContinuation{ logTelemetry.ContinueOnCurrentThread() }; - - winrt::Windows::Management::Deployment::PackageVolume windowsPackageVolume; - HRESULT error{}; - HRESULT extendedError{}; - winrt::hstring errorText; - winrt::guid activityId{}; - try - { - error = LOG_IF_FAILED_MSG(Add(packageStorePath, windowsPackageVolume, extendedError, errorText, activityId), - "ExtendedError:0x%08X PackageVolume.Add PackageStorePath:%ls", - extendedError, m_packageStorePath.c_str()); - } - catch (...) - { - const auto exception{ hresult_error(to_hresult(), take_ownership_from_abi) }; - error = LOG_HR_MSG(exception.code(), - "ExtendedError:0x%08X PackageVolume.Add PackageStorePath:%ls", - extendedError, m_packageStorePath.c_str()); - } - if (FAILED(error)) - { - co_return winrt::make( - PackageDeploymentStatus::CompletedFailure, activityId, error, extendedError, errorText); - } + winrt::Windows::Management::Deployment::PackageManager packageManager; + winrt::Windows::Management::Deployment::PackageVolume windowsPackageVolume{ co_await packageManager.AddPackageVolumeAsync(packageStorePath) }; logTelemetry.Stop(windowsPackageVolume.MountPoint(), windowsPackageVolume.Name(), windowsPackageVolume.PackageStorePath()); co_return winrt::make(windowsPackageVolume); @@ -319,90 +333,13 @@ namespace winrt::Microsoft::Windows::Management::Deployment::implementation auto cancellation{ co_await winrt::get_cancellation_token() }; cancellation.enable_propagation(true); - logTelemetry.IgnoreCurrentThread(); - co_await resume_background(); // Allow to register the progress and complete handler - auto logTelemetryContinuation{ logTelemetry.ContinueOnCurrentThread() }; - uint64_t availableSpace{}; - HRESULT error{}; - HRESULT extendedError{}; - winrt::hstring errorText; - winrt::guid activityId{}; - try - { - error = LOG_IF_FAILED_MSG(GetAvailableSpace(availableSpace, extendedError, errorText, activityId), - "ExtendedError:0x%08X PackageVolume.GetAvailableSpace MountPoint:%ls Name:%ls PackageStorePath:%ls : %ls", - extendedError, m_mountPoint.c_str(), m_name.c_str(), m_packageStorePath.c_str(), errorText.c_str()); - } - catch (...) - { - const auto exception{ hresult_error(to_hresult(), take_ownership_from_abi) }; - error = LOG_HR_MSG(exception.code(), - "ExtendedError:0x%08X PackageVolume.GetAvailableSpace MountPoint:%ls Name:%ls PackageStorePath:%ls : %ls", - extendedError, m_mountPoint.c_str(), m_name.c_str(), m_packageStorePath.c_str(), errorText.c_str()); - } - if (FAILED(error)) - { - co_return winrt::make( - PackageDeploymentStatus::CompletedFailure, activityId, error, extendedError, errorText); - } + availableSpace = co_await m_windowsPackageVolume.GetAvailableSpaceAsync(); logTelemetry.Stop(availableSpace); co_return availableSpace; } - HRESULT PackageDeploymentManager::Add( - winrt::hstring const& packageStorePath, - winrt::Windows::Management::Deployment::PackageVolume& windowsPackageVolume, - HRESULT& extendedError, - winrt::hstring& errorText, - winrt::guid& activityId) - { - extendedError = S_OK; - errorText.clear(); - activityId = winrt::guid{}; - - auto deploymentOperation{ m_packageManager.AddPackageVolumeAsync(packageStorePath, wil::out_param(windowsPackageVolume)) }; - deploymentOperation.get(); - try - { - const auto deploymentResult{ deploymentOperation.GetResults() }; - const HRESULT error{ static_cast(deploymentOperation.ErrorCode()) }; - extendedError = deploymentResult.ExtendedErrorCode(); - errorText = deploymentResult.ErrorText(); - activityId = deploymentResult.ActivityId(); - const auto status{ deploymentOperation.Status() }; - if (status == winrt::Windows::Foundation::AsyncStatus::Error) - { - RETURN_IF_FAILED_MSG(error, - "ExtendedError:0x%08X PackageVolume.Add PackageStorePath:%ls : %ls", - extendedError, packageStorePath.c_str(), errorText.c_str()); - - // Status=Error but SUCCEEDED(error) == This.Should.Never.Happen. - FAIL_FAST_HR_MSG(E_UNEXPECTED, - "ExtendedError:0x%08X PackageVolume.Add PackageStorePath:%ls : %ls", - extendedError, packageStorePath.c_str(), errorText.c_str()); - } - else if (status == winrt::Windows::Foundation::AsyncStatus::Canceled) - { - RETURN_WIN32_MSG(ERROR_CANCELLED, - "PackageVolume.Add PackageStorePath:%ls", - packageStorePath.c_str()); - } - FAIL_FAST_HR_IF_MSG(E_UNEXPECTED, status != winrt::Windows::Foundation::AsyncStatus::Completed, - "Status:%d PackageVolume.Add PackageStorePath:%ls : %ls", - static_cast(status), packageStorePath.c_str(), errorText.c_str()); - } - catch (...) - { - auto exception{ hresult_error(to_hresult(), take_ownership_from_abi) }; - THROW_HR_MSG(exception.code(), - "ExtendedError:0x%08X PackageVolume.Add PackageStorePath:%ls : %ls", - extendedError, packageStorePath.c_str(), errorText.c_str()); - } - return S_OK; - } - HRESULT PackageDeploymentManager::Remove( winrt::Microsoft::Windows::Management::Deployment::PackageDeploymentProgress& packageDeploymentProgress, wistd::function progress, @@ -414,7 +351,8 @@ namespace winrt::Microsoft::Windows::Management::Deployment::implementation errorText.clear(); activityId = winrt::guid{}; - auto deploymentOperation{ m_packageManager.RemovePackageVolumeAsync(m_windowsPackageVolume) }; + winrt::Windows::Management::Deployment::PackageManager packageManager; + auto deploymentOperation{ packageManager.RemovePackageVolumeAsync(m_windowsPackageVolume) }; deploymentOperation.Progress([&](winrt::Windows::Foundation::IAsyncOperationWithProgress< winrt::Windows::Management::Deployment::DeploymentResult, winrt::Windows::Management::Deployment::DeploymentProgress> const& /*sender*/, @@ -475,7 +413,8 @@ namespace winrt::Microsoft::Windows::Management::Deployment::implementation errorText.clear(); activityId = winrt::guid{}; - auto deploymentOperation{ m_packageManager.SetPackageVolumeOnlineAsync(m_windowsPackageVolume) }; + winrt::Windows::Management::Deployment::PackageManager packageManager; + auto deploymentOperation{ packageManager.SetPackageVolumeOnlineAsync(m_windowsPackageVolume) }; deploymentOperation.Progress([&](winrt::Windows::Foundation::IAsyncOperationWithProgress< winrt::Windows::Management::Deployment::DeploymentResult, winrt::Windows::Management::Deployment::DeploymentProgress> const& /*sender*/, @@ -523,55 +462,4 @@ namespace winrt::Microsoft::Windows::Management::Deployment::implementation } return S_OK; } - - HRESULT PackageDeploymentManager::GetAvailableSpace( - uint32_t& availableSpace, - HRESULT& extendedError, - winrt::hstring& errorText, - winrt::guid& activityId) - { - extendedError = S_OK; - errorText.clear(); - activityId = winrt::guid{}; - - auto deploymentOperation{ m_windowsPackageVolume.GetAvailableSpaceAsync(availableSpace) }; - deploymentOperation.get(); - try - { - const auto deploymentResult{ deploymentOperation.GetResults() }; - const HRESULT error{ static_cast(deploymentOperation.ErrorCode()) }; - extendedError = deploymentResult.ExtendedErrorCode(); - errorText = deploymentResult.ErrorText(); - activityId = deploymentResult.ActivityId(); - const auto status{ deploymentOperation.Status() }; - if (status == winrt::Windows::Foundation::AsyncStatus::Error) - { - RETURN_IF_FAILED_MSG(error, - "ExtendedError:0x%08X PackageVolume.GetAvailableSpace MountPoint:%ls Name:%ls PackageStorePath:%ls : %ls", - extendedError, m_mountPoint.c_str(), m_name.c_str(), m_packageStorePath.c_str(), errorText.c_str()); - - // Status=Error but SUCCEEDED(error) == This.Should.Never.Happen. - FAIL_FAST_HR_MSG(E_UNEXPECTED, - "ExtendedError:0x%08X PackageVolume.GetAvailableSpace MountPoint:%ls Name:%ls PackageStorePath:%ls : %ls", - extendedError, m_mountPoint.c_str(), m_name.c_str(), m_packageStorePath.c_str(), errorText.c_str()); - } - else if (status == winrt::Windows::Foundation::AsyncStatus::Canceled) - { - RETURN_WIN32_MSG(ERROR_CANCELLED, - "PackageVolume.GetAvailableSpace MountPoint:%ls Name:%ls PackageStorePath:%ls", - m_mountPoint.c_str(), m_name.c_str(), m_packageStorePath.c_str()); - } - FAIL_FAST_HR_IF_MSG(E_UNEXPECTED, status != winrt::Windows::Foundation::AsyncStatus::Completed, - "Status:%d PackageVolume.GetAvailableSpace MountPoint:%ls Name:%ls PackageStorePath:%ls : %ls", - static_cast(status), m_mountPoint.c_str(), m_name.c_str(), m_packageStorePath.c_str(), errorText.c_str()); - } - catch (...) - { - auto exception{ hresult_error(to_hresult(), take_ownership_from_abi) }; - THROW_HR_MSG(exception.code(), - "ExtendedError:0x%08X PackageVolume.GetAvailableSpace MountPoint:%ls Name:%ls PackageStorePath:%ls : %ls", - extendedError, m_mountPoint.c_str(), m_name.c_str(), m_packageStorePath.c_str(), errorText.c_str()); - } - return S_OK; - } } diff --git a/dev/PackageManager/API/M.W.M.D.PackageVolume.h b/dev/PackageManager/API/M.W.M.D.PackageVolume.h index c267048f97..17e2703bcc 100644 --- a/dev/PackageManager/API/M.W.M.D.PackageVolume.h +++ b/dev/PackageManager/API/M.W.M.D.PackageVolume.h @@ -9,9 +9,10 @@ namespace winrt::Microsoft::Windows::Management::Deployment::implementation { struct PackageVolume : PackageVolumeT { - PackageVolume() = delete; + PackageVolume() = default; PackageVolume(winrt::Windows::Management::Deployment::PackageVolume const& value); + static bool IsFeatureSupported(winrt::Microsoft::Windows::Management::Deployment::PackageVolumeFeature feature); static winrt::Windows::Foundation::Collections::IVector FindPackageVolumes(); static winrt::Microsoft::Windows::Management::Deployment::PackageVolume FindPackageVolumeByPath(hstring const& packageStorePath); static winrt::Microsoft::Windows::Management::Deployment::PackageVolume FindPackageVolumeByName(hstring const& name); @@ -34,13 +35,6 @@ namespace winrt::Microsoft::Windows::Management::Deployment::implementation winrt::Windows::Foundation::IAsyncOperation GetAvailableSpaceAsync(); private: - HRESULT Add( - hstring const& packageStorePath, - winrt::Windows::Management::Deployment::PackageVolume& windowsPackageVolume, - HRESULT& extendedError, - winrt::hstring& errorText, - winrt::guid& activityId); - HRESULT Remove( winrt::Microsoft::Windows::Management::Deployment::PackageDeploymentProgress& packageDeploymentProgress, wistd::function progress, @@ -56,12 +50,6 @@ namespace winrt::Microsoft::Windows::Management::Deployment::implementation winrt::hstring& errorText, winrt::guid& activityId); - HRESULT GetAvailableSpace( - uint32_t& availableSpace, - HRESULT& extendedError, - winrt::hstring& errorText, - winrt::guid& activityId); - private: winrt::Windows::Management::Deployment::PackageVolume m_windowsPackageVolume; bool m_isSystemVolume{}; diff --git a/dev/PackageManager/API/PackageManager.idl b/dev/PackageManager/API/PackageManager.idl index da63f8b8c2..2d6c914f02 100644 --- a/dev/PackageManager/API/PackageManager.idl +++ b/dev/PackageManager/API/PackageManager.idl @@ -7,7 +7,7 @@ import "M.AM.DynamicDependency.idl"; namespace Microsoft.Windows.Management.Deployment { - [contractversion(2)] + [contractversion(3)] apicontract PackageDeploymentContract{}; /// Features can be queried if currently available/enabled. @@ -23,6 +23,20 @@ namespace Microsoft.Windows.Management.Deployment ProvisionPackage_Framework = 6, }; + /// Features can be queried if currently available/enabled. + /// @see PackageVolume.IsFeatureSupported() + [contract(PackageDeploymentContract, 3)] + enum PackageVolumeFeature + { + GetDefault = 1, + SetDefault = 2, + Add = 3, + Remove = 4, + SetOffline = 5, + SetOnline = 6, + GetAvailableSpace = 7, + }; + /// The progress status of the deployment request. /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.deploymentprogress.state [contract(PackageDeploymentContract, 1)] @@ -128,45 +142,48 @@ namespace Microsoft.Windows.Management.Deployment /// Repair the package volume (if necessary). void Repair(); + [contract(PackageDeploymentContract, 3)] + static Boolean IsFeatureSupported(PackageVolumeFeature feature); + /// Return the default package volume. /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagemanager.getdefaultpackagevolume - [contract(PackageDeploymentContract, 2)] + [contract(PackageDeploymentContract, 3)] static PackageVolume GetDefault(); /// Set the default package volume. /// @see //learn.microsoft.com/uwp/api/windows.management.deployment.packagemanager.setdefaultpackagevolume - [contract(PackageDeploymentContract, 2)] + [contract(PackageDeploymentContract, 3)] void SetDefault(); /// Create a new package volume. /// @param packageStorePath The absolute path of the Package store. /// @note This requires admin privilege. /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagemanager.addpackagevolumeasync - [contract(PackageDeploymentContract, 2)] + [contract(PackageDeploymentContract, 3)] Windows.Foundation.IAsyncOperation AddAsync(String packageStorePath); /// @note The caller must be running with Medium IL (or higher) /// OR running in an AppContainer with the packageManagement restricted capability /// OR caller has package identity and the publisher matches the publisher of the volume being removed. /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagemanager.removepackagevolumeasync - [contract(PackageDeploymentContract, 2)] + [contract(PackageDeploymentContract, 3)] Windows.Foundation.IAsyncOperationWithProgress RemoveAsync(); /// Set the package volume to an offline state. /// @note This requires admin privilege. /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagemanager.setpackagevolumeofflineasync - [contract(PackageDeploymentContract, 2)] + [contract(PackageDeploymentContract, 3)] Windows.Foundation.IAsyncOperationWithProgress SetOfflineAsync(); /// Set the package volume to an online state. /// @note This requires admin privilege. /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagemanager.setpackagevolumeonlineasync - [contract(PackageDeploymentContract, 2)] + [contract(PackageDeploymentContract, 3)] Windows.Foundation.IAsyncOperationWithProgress SetOnlineAsync(); /// Get the available space (bytes). /// @see https://learn.microsoft.com/en-us/uwp/api/windows.management.deployment.packagevolume.getavailablespaceasync?view=winrt-26100 - [contract(PackageDeploymentContract, 2)] + [contract(PackageDeploymentContract, 3)] Windows.Foundation.IAsyncOperation GetAvailableSpaceAsync(); }; diff --git a/dev/PackageManager/API/PackageManager.vcxitems.filters b/dev/PackageManager/API/PackageManager.vcxitems.filters index 0be22da55f..b06d2bb016 100644 --- a/dev/PackageManager/API/PackageManager.vcxitems.filters +++ b/dev/PackageManager/API/PackageManager.vcxitems.filters @@ -106,14 +106,8 @@ Header Files - - Header Files - - - Header Files - - + \ No newline at end of file From 588971ed9b1f023a8d57c57f75818aa885692fac Mon Sep 17 00:00:00 2001 From: Howard Kapustein Date: Sun, 5 Oct 2025 22:44:42 -0700 Subject: [PATCH 03/10] Fixed PackageVolume. Added start of tests --- .../API/M.W.M.D.PackageVolume.cpp | 49 ++++--- .../API/M.W.M.D.PackageVolume.h | 10 +- dev/PackageManager/API/PackageManager.idl | 11 +- .../API/PackageManagerTests.vcxproj | 1 + .../API/PackageManagerTests.vcxproj.filters | 3 + .../PackageManager/API/PackageVolumeTests.cpp | 137 ++++++++++++++++++ 6 files changed, 182 insertions(+), 29 deletions(-) create mode 100644 test/PackageManager/API/PackageVolumeTests.cpp diff --git a/dev/PackageManager/API/M.W.M.D.PackageVolume.cpp b/dev/PackageManager/API/M.W.M.D.PackageVolume.cpp index 8b753aa9b9..588afc9d31 100644 --- a/dev/PackageManager/API/M.W.M.D.PackageVolume.cpp +++ b/dev/PackageManager/API/M.W.M.D.PackageVolume.cpp @@ -5,6 +5,8 @@ #include "M.W.M.D.PackageVolume.h" #include "Microsoft.Windows.Management.Deployment.PackageVolume.g.cpp" +#include "M.W.M.D.PackageDeploymentResult.h" + #include "PackageVolumeTelemetry.h" #include @@ -58,8 +60,9 @@ namespace winrt::Microsoft::Windows::Management::Deployment::implementation m_name = value.Name(); m_packageStorePath = value.PackageStorePath(); m_supportsHardLinks = value.SupportsHardLinks(); - m_isFullTrustPackageSupported = value.IsFullTrustPackageSupported(); m_isAppxInstallSupported = value.IsAppxInstallSupported(); + m_isFullTrustPackageSupported = value.IsFullTrustPackageSupported(); + m_isOffline = value.IsOffline(); } winrt::Windows::Foundation::Collections::IVector PackageVolume::FindPackageVolumes() { @@ -104,6 +107,19 @@ namespace winrt::Microsoft::Windows::Management::Deployment::implementation winrt::Windows::Management::Deployment::PackageVolume windowsPackageVolume{ packageManager.GetDefaultPackageVolume() }; return winrt::make(windowsPackageVolume); } + winrt::Windows::Foundation::IAsyncOperation PackageVolume::AddAsync(hstring packageStorePath) + { + auto logTelemetry{ PackageVolumeTelemetry::Add::Start(packageStorePath) }; + + auto cancellation{ co_await winrt::get_cancellation_token() }; + cancellation.enable_propagation(true); + + winrt::Windows::Management::Deployment::PackageManager packageManager; + winrt::Windows::Management::Deployment::PackageVolume windowsPackageVolume{ co_await packageManager.AddPackageVolumeAsync(packageStorePath) }; + + logTelemetry.Stop(windowsPackageVolume.MountPoint(), windowsPackageVolume.Name(), windowsPackageVolume.PackageStorePath()); + co_return winrt::make(windowsPackageVolume); + } bool PackageVolume::IsSystemVolume() { return m_isSystemVolume; @@ -154,28 +170,17 @@ namespace winrt::Microsoft::Windows::Management::Deployment::implementation THROW_IF_FAILED(msixPackageVolumeRepair(m_packageStorePath.c_str())); } - void PackageVolume::SetDefault() + bool PackageVolume::IsOffline() { - THROW_HR_IF_NULL(E_ILLEGAL_METHOD_CALL, m_windowsPackageVolume); - - winrt::Windows::Management::Deployment::PackageManager packageManager; - packageManager.SetDefaultPackageVolume(m_windowsPackageVolume); + return m_isOffline; } - winrt::Windows::Foundation::IAsyncOperation PackageVolume::AddAsync(hstring packageStorePath) + void PackageVolume::SetDefault() { - auto logTelemetry{ PackageVolumeTelemetry::Add::Start(packageStorePath) }; - - auto strong{ get_strong() }; - - auto cancellation{ co_await winrt::get_cancellation_token() }; - cancellation.enable_propagation(true); + THROW_HR_IF_NULL(E_ILLEGAL_METHOD_CALL, m_windowsPackageVolume); winrt::Windows::Management::Deployment::PackageManager packageManager; - winrt::Windows::Management::Deployment::PackageVolume windowsPackageVolume{ co_await packageManager.AddPackageVolumeAsync(packageStorePath) }; - - logTelemetry.Stop(windowsPackageVolume.MountPoint(), windowsPackageVolume.Name(), windowsPackageVolume.PackageStorePath()); - co_return winrt::make(windowsPackageVolume); + packageManager.SetDefaultPackageVolume(m_windowsPackageVolume); } winrt::Windows::Foundation::IAsyncOperationWithProgress PackageVolume::RemoveAsync() @@ -222,7 +227,7 @@ namespace winrt::Microsoft::Windows::Management::Deployment::implementation PackageDeploymentStatus::CompletedFailure, activityId, error, extendedError, errorText); } - logTelemetry.Stop(); + logTelemetry.Stop(static_cast(S_OK)); co_return winrt::make(PackageDeploymentStatus::CompletedSuccess, activityId); } @@ -270,7 +275,7 @@ namespace winrt::Microsoft::Windows::Management::Deployment::implementation PackageDeploymentStatus::CompletedFailure, activityId, error, extendedError, errorText); } - logTelemetry.Stop(); + logTelemetry.Stop(static_cast(S_OK)); co_return winrt::make(PackageDeploymentStatus::CompletedSuccess, activityId); } @@ -318,7 +323,7 @@ namespace winrt::Microsoft::Windows::Management::Deployment::implementation PackageDeploymentStatus::CompletedFailure, activityId, error, extendedError, errorText); } - logTelemetry.Stop(); + logTelemetry.Stop(static_cast(S_OK)); co_return winrt::make(PackageDeploymentStatus::CompletedSuccess, activityId); } @@ -340,7 +345,7 @@ namespace winrt::Microsoft::Windows::Management::Deployment::implementation co_return availableSpace; } - HRESULT PackageDeploymentManager::Remove( + HRESULT PackageVolume::Remove( winrt::Microsoft::Windows::Management::Deployment::PackageDeploymentProgress& packageDeploymentProgress, wistd::function progress, HRESULT& extendedError, @@ -401,7 +406,7 @@ namespace winrt::Microsoft::Windows::Management::Deployment::implementation return S_OK; } - HRESULT PackageDeploymentManager::SetOnline( + HRESULT PackageVolume::SetOnline( const bool online, winrt::Microsoft::Windows::Management::Deployment::PackageDeploymentProgress& packageDeploymentProgress, wistd::function progress, diff --git a/dev/PackageManager/API/M.W.M.D.PackageVolume.h b/dev/PackageManager/API/M.W.M.D.PackageVolume.h index 17e2703bcc..8035b48d62 100644 --- a/dev/PackageManager/API/M.W.M.D.PackageVolume.h +++ b/dev/PackageManager/API/M.W.M.D.PackageVolume.h @@ -17,18 +17,19 @@ namespace winrt::Microsoft::Windows::Management::Deployment::implementation static winrt::Microsoft::Windows::Management::Deployment::PackageVolume FindPackageVolumeByPath(hstring const& packageStorePath); static winrt::Microsoft::Windows::Management::Deployment::PackageVolume FindPackageVolumeByName(hstring const& name); static winrt::Microsoft::Windows::Management::Deployment::PackageVolume GetDefault(); + static winrt::Windows::Foundation::IAsyncOperation AddAsync(hstring packageStorePath); bool IsSystemVolume(); hstring MountPoint(); hstring Name(); hstring PackageStorePath(); bool SupportsHardLinks(); - bool IsFullTrustPackageSupported(); bool IsAppxInstallSupported(); + bool IsFullTrustPackageSupported(); bool IsRepairNeeded(); void Repair(); + bool IsOffline(); void SetDefault(); - winrt::Windows::Foundation::IAsyncOperation AddAsync(hstring packageStorePath); winrt::Windows::Foundation::IAsyncOperationWithProgress RemoveAsync(); winrt::Windows::Foundation::IAsyncOperationWithProgress SetOfflineAsync(); winrt::Windows::Foundation::IAsyncOperationWithProgress SetOnlineAsync(); @@ -51,14 +52,15 @@ namespace winrt::Microsoft::Windows::Management::Deployment::implementation winrt::guid& activityId); private: - winrt::Windows::Management::Deployment::PackageVolume m_windowsPackageVolume; + winrt::Windows::Management::Deployment::PackageVolume m_windowsPackageVolume{ nullptr }; bool m_isSystemVolume{}; hstring m_mountPoint; hstring m_name; hstring m_packageStorePath; bool m_supportsHardLinks{}; - bool m_isFullTrustPackageSupported{}; bool m_isAppxInstallSupported{}; + bool m_isFullTrustPackageSupported{}; + bool m_isOffline{}; }; } namespace winrt::Microsoft::Windows::Management::Deployment::factory_implementation diff --git a/dev/PackageManager/API/PackageManager.idl b/dev/PackageManager/API/PackageManager.idl index 2d6c914f02..e9963383db 100644 --- a/dev/PackageManager/API/PackageManager.idl +++ b/dev/PackageManager/API/PackageManager.idl @@ -130,11 +130,16 @@ namespace Microsoft.Windows.Management.Deployment /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagevolume.supportshardlinks Boolean SupportsHardLinks{ get; }; + /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagevolume.isappxinstallsupported + Boolean IsAppxInstallSupported{ get; }; + /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagevolume.isfulltrustpackagesupported Boolean IsFullTrustPackageSupported{ get; }; - /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagevolume.isappxinstallsupported - Boolean IsAppxInstallSupported{ get; }; + /// Return the default package volume. + /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagevolume.isoffline + [contract(PackageDeploymentContract, 3)] + Boolean IsOffline(); /// Return true if the package volume is damaged and needs to be repaired. Boolean IsRepairNeeded(); @@ -160,7 +165,7 @@ namespace Microsoft.Windows.Management.Deployment /// @note This requires admin privilege. /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagemanager.addpackagevolumeasync [contract(PackageDeploymentContract, 3)] - Windows.Foundation.IAsyncOperation AddAsync(String packageStorePath); + static Windows.Foundation.IAsyncOperation AddAsync(String packageStorePath); /// @note The caller must be running with Medium IL (or higher) /// OR running in an AppContainer with the packageManagement restricted capability diff --git a/test/PackageManager/API/PackageManagerTests.vcxproj b/test/PackageManager/API/PackageManagerTests.vcxproj index 96d55f4590..7137f9d59f 100644 --- a/test/PackageManager/API/PackageManagerTests.vcxproj +++ b/test/PackageManager/API/PackageManagerTests.vcxproj @@ -127,6 +127,7 @@ + diff --git a/test/PackageManager/API/PackageManagerTests.vcxproj.filters b/test/PackageManager/API/PackageManagerTests.vcxproj.filters index aa5b312029..813f4e643c 100644 --- a/test/PackageManager/API/PackageManagerTests.vcxproj.filters +++ b/test/PackageManager/API/PackageManagerTests.vcxproj.filters @@ -69,6 +69,9 @@ Source Files + + Source Files + diff --git a/test/PackageManager/API/PackageVolumeTests.cpp b/test/PackageManager/API/PackageVolumeTests.cpp new file mode 100644 index 0000000000..b58e2523c6 --- /dev/null +++ b/test/PackageManager/API/PackageVolumeTests.cpp @@ -0,0 +1,137 @@ +// Copyright (c) Microsoft Corporation and Contributors. +// Licensed under the MIT License. + +#include "pch.h" + +#include "PackageDeploymentManagerTests.h" + +#include + +namespace TD = ::Test::Diagnostics; +namespace TB = ::Test::Bootstrap; +namespace TP = ::Test::Packages; +namespace TPF = ::Test::Packages::Framework; +namespace TPM = ::Test::Packages::Main; +namespace TPMT = ::Test::PackageManager::Tests; + +namespace Test::PackageVolume::Tests +{ + class PackageVolumeTests_Stage_Elevated : PackageDeploymentManagerTests_Base + { + public: + BEGIN_TEST_CLASS(PackageVolumeTests_Stage_Elevated) + TEST_METHOD_PROPERTY(L"RunAs", L"ElevatedUser") + TEST_CLASS_PROPERTY(L"ThreadingModel", L"MTA") + TEST_CLASS_PROPERTY(L"IsolationLevel", L"Method") + END_TEST_CLASS() + + TEST_CLASS_SETUP(ClassSetup) + { + //***SEEME***TD::DumpExecutionContext(); + + ::TB::Setup(); + + CreateTempDirectory(); + return true; + } + + TEST_CLASS_CLEANUP(ClassCleanup) + { + RemoveTempDirectory(); + + ::TB::Cleanup(); + return true; + } + + private: + winrt::hstring m_tempPath; + + private: + void RemoveTempDirectory() + { + if (m_tempPath.empty()) + { + return; + } + + if (std::filesystem::is_directory(m_tempPath.c_str())) + { + VERIFY_SUCCESS(wil::RemoveDirectoryRecursiveNoThrow(m_tempPath.c_str())); + } + VERIFY_IS_TRUE(std::filesystem::create_directory(m_tempPath.c_str())); + + m_tempPath.clear(); + } + + void CreateTempDirectory() + { + if (m_tempPath.empty()) + { + const auto tempDirectory{ std::filesystem::temp_directory_path() / L"PackageVolumeTests" }; + m_tempPath = tempDirectory.c_str(); + } + + RemoveTempDirectory(); + + VERIFY_IS_TRUE(std::filesystem::create_directory(m_tempPath.c_str())); + + VERIFY_IS_TRUE(std::filesystem::is_directory(m_tempPath.c_str())); + } + + bool TempDirectoryExists() const + { + return std::filesystem::is_directory(m_tempPath.c_str()) + + public: + + TEST_METHOD(GetDefault) + { + const auto packageVolume{ winrt::Microsoft::Windows::Management::Deployment::PackageVolume::GetDefault() }; + const auto windowsPackageVolume{ winrt::Windows::Management::Deployment::PackageManager::GetDefaultPackageVolume() }; + Verify(packageVolume, windowsPackageVolume); + } + + TEST_METHOD(Add_Online_Offline_Remove) + { + auto packageVolumeAdded{ winrt::Microsoft::Windows::Management::Deployment::PackageVolume::AddAsync(m_tempPath).get() }; + auto packageVolume{ winrt::Microsoft::Windows::Management::Deployment::PackageVolume::FindPackageVolumeByPath(m_tempPath) }; + Verify(packageVolumeAdded, packageVolume); + + VERIFY_IS_FALSE(packageVolumeAdded.IsOffline()); + + { + auto deploymentOperation{ packageVolumeAdded.SetOfflineAsync() }; + auto deploymentResult{ WaitForDeploymentOperation(deploymentOperation) }; + TPMT::VerifyDeploymentSucceeded(deploymentResult, __FILE__, __LINE__, __FUNCTION__); + auto packageVolume{ winrt::Microsoft::Windows::Management::Deployment::PackageVolume::FindPackageVolumeByPath(m_tempPath) }; + VERIFY_IS_TRUE(packageVolume.IsOffline()); + } + + { + auto deploymentOperation{ packageVolumeAdded.SetOnlineAsync() }; + auto deploymentResult{ WaitForDeploymentOperation(deploymentOperation) }; + TPMT::VerifyDeploymentSucceeded(deploymentResult, __FILE__, __LINE__, __FUNCTION__); + auto packageVolume{ winrt::Microsoft::Windows::Management::Deployment::PackageVolume::FindPackageVolumeByPath(m_tempPath) }; + VERIFY_IS_FALSE(packageVolume.IsOffline()); + } + + { + auto deploymentOperation{ winrt::Microsoft::Windows::Management::Deployment::PackageVolume::RemoveAsync(m_tempPath) }; + auto deploymentResult{ WaitForDeploymentOperation(deploymentOperation) }; + TPMT::VerifyDeploymentSucceeded(deploymentResult, __FILE__, __LINE__, __FUNCTION__); + } + } + + TEST_METHOD(GetAvailableSpace) + { + const auto packageVolume{ winrt::Microsoft::Windows::Management::Deployment::PackageVolume::GetDefault() }; + WEX::Logging::Log::Comment(WEX::Common::String().Format(L"PackgeVolume.Default: MountPoint=%ls Name=%ls PackageStorePath=%ls", + packageVolume.MountPoint().c_str(), packageVolume.Name().c_str(), packageVolume.PackageStorePath().c_str())); + std::uint64_t availableSpace{ packageVolume.GetAvailableSpaceAsync().get() }; + std::uint64_t kb{ availableSpace / 1024 }; + std::uint64_t mb{ kb / 1024 }; + std::uint64_t gb{ mb / 1024 }; + WEX::Logging::Log::Comment(WEX::Common::String().Format(L"AvailableSpace=%llu bytes / %lluKB / %lluMB / %lluGB", availableSpace, kb, mb, gb)); + } + }; +} From dfec617373c94f7da736c3ab7e1610afce2c730c Mon Sep 17 00:00:00 2001 From: Howard Kapustein Date: Sun, 5 Oct 2025 22:46:11 -0700 Subject: [PATCH 04/10] Fixed build break --- test/PackageManager/API/PackageVolumeTests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/PackageManager/API/PackageVolumeTests.cpp b/test/PackageManager/API/PackageVolumeTests.cpp index b58e2523c6..fa6a2fc228 100644 --- a/test/PackageManager/API/PackageVolumeTests.cpp +++ b/test/PackageManager/API/PackageVolumeTests.cpp @@ -16,7 +16,7 @@ namespace TPMT = ::Test::PackageManager::Tests; namespace Test::PackageVolume::Tests { - class PackageVolumeTests_Stage_Elevated : PackageDeploymentManagerTests_Base + class PackageVolumeTests_Stage_Elevated : TPMT::PackageDeploymentManagerTests_Base { public: BEGIN_TEST_CLASS(PackageVolumeTests_Stage_Elevated) From 462a115c3733b3ed6cf248073f75b468eb7bdd7c Mon Sep 17 00:00:00 2001 From: Howard Kapustein Date: Sun, 5 Oct 2025 22:58:38 -0700 Subject: [PATCH 05/10] Fixed build errors. Added PackageVolume test to .testdef --- .../PackageManager/API/PackageVolumeTests.cpp | 31 ++++++++++++++----- test/PackageManager/API/Test.testdef | 7 +++++ test/PackageManager/API/pch.h | 1 + 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/test/PackageManager/API/PackageVolumeTests.cpp b/test/PackageManager/API/PackageVolumeTests.cpp index fa6a2fc228..5f8d4476cf 100644 --- a/test/PackageManager/API/PackageVolumeTests.cpp +++ b/test/PackageManager/API/PackageVolumeTests.cpp @@ -14,12 +14,12 @@ namespace TPF = ::Test::Packages::Framework; namespace TPM = ::Test::Packages::Main; namespace TPMT = ::Test::PackageManager::Tests; -namespace Test::PackageVolume::Tests +namespace Test::PackageManager::Tests { - class PackageVolumeTests_Stage_Elevated : TPMT::PackageDeploymentManagerTests_Base + class PackageVolumeTests_Elevated : PackageDeploymentManagerTests_Base { public: - BEGIN_TEST_CLASS(PackageVolumeTests_Stage_Elevated) + BEGIN_TEST_CLASS(PackageVolumeTests_Elevated) TEST_METHOD_PROPERTY(L"RunAs", L"ElevatedUser") TEST_CLASS_PROPERTY(L"ThreadingModel", L"MTA") TEST_CLASS_PROPERTY(L"IsolationLevel", L"Method") @@ -56,7 +56,7 @@ namespace Test::PackageVolume::Tests if (std::filesystem::is_directory(m_tempPath.c_str())) { - VERIFY_SUCCESS(wil::RemoveDirectoryRecursiveNoThrow(m_tempPath.c_str())); + VERIFY_SUCCEEDED(wil::RemoveDirectoryRecursiveNoThrow(m_tempPath.c_str())); } VERIFY_IS_TRUE(std::filesystem::create_directory(m_tempPath.c_str())); @@ -80,14 +80,31 @@ namespace Test::PackageVolume::Tests bool TempDirectoryExists() const { - return std::filesystem::is_directory(m_tempPath.c_str()) + return std::filesystem::is_directory(m_tempPath.c_str()); + } + + private: + void Verify( + const winrt::Microsoft::Windows::Management::Deployment::PackageVolume& packageVolume, + const winrt::Windows::Management::Deployment::PackageVolume& windowsPackageVolume) + { + throw winrt::hresult_not_implemented(); + } + + void Verify( + const winrt::Microsoft::Windows::Management::Deployment::PackageVolume& actual, + const winrt::Microsoft::Windows::Management::Deployment::PackageVolume& expected) + { + throw winrt::hresult_not_implemented(); + } public: TEST_METHOD(GetDefault) { const auto packageVolume{ winrt::Microsoft::Windows::Management::Deployment::PackageVolume::GetDefault() }; - const auto windowsPackageVolume{ winrt::Windows::Management::Deployment::PackageManager::GetDefaultPackageVolume() }; + winrt::Windows::Management::Deployment::PackageManager packageManager; + const auto windowsPackageVolume{ packageManager.GetDefaultPackageVolume() }; Verify(packageVolume, windowsPackageVolume); } @@ -116,7 +133,7 @@ namespace Test::PackageVolume::Tests } { - auto deploymentOperation{ winrt::Microsoft::Windows::Management::Deployment::PackageVolume::RemoveAsync(m_tempPath) }; + auto deploymentOperation{ packageVolumeAdded.RemoveAsync() }; auto deploymentResult{ WaitForDeploymentOperation(deploymentOperation) }; TPMT::VerifyDeploymentSucceeded(deploymentResult, __FILE__, __LINE__, __FUNCTION__); } diff --git a/test/PackageManager/API/Test.testdef b/test/PackageManager/API/Test.testdef index 21cdbb48a8..763b4ec623 100644 --- a/test/PackageManager/API/Test.testdef +++ b/test/PackageManager/API/Test.testdef @@ -91,5 +91,12 @@ "Architectures": ["x86", "x64"], "Status": "Enabled" } + { + "Description": "PackageManagerTests.PackageVolume* tests for feature PackageManager (arm64 not currently enabled)", + "Filename": "PackageManagerTests.dll", + "Parameters": "/name=Test::PackageManager::Tests::PackageVolumeTests*", + "Architectures": ["x86", "x64"], + "Status": "Enabled" + } ] } diff --git a/test/PackageManager/API/pch.h b/test/PackageManager/API/pch.h index 900c25a3d3..de5cd6727d 100644 --- a/test/PackageManager/API/pch.h +++ b/test/PackageManager/API/pch.h @@ -10,6 +10,7 @@ #include #include +#include #include #include From e70f88b44c0d9144dd0dc581aa7413ffd2f57a42 Mon Sep 17 00:00:00 2001 From: Howard Kapustein Date: Tue, 23 Dec 2025 22:04:16 -0800 Subject: [PATCH 06/10] Forgot to implement the WASDK API for operations related to PackageVolume? #5485. 57784255: PackageVolume methods (most 'write' plus some 'read'). https://task.ms/57784255 --- WindowsAppRuntime.sln | 3 + dev/Interop/StoragePickers/PickerCommon.cpp | 10 +- .../API/M.W.M.D.PackageVolume.cpp | 52 ++- .../API/M.W.M.D.PackageVolume.h | 2 + dev/PackageManager/API/PackageManager.idl | 22 + test/ABForward/FunctionalTests.cpp | 4 +- ...ate_Add_Architectures_Explicit_NoMatch.cpp | 1 + .../API/PackageDeploymentManagerTests.cpp | 19 + .../API/PackageDeploymentManagerTests.h | 51 ++- .../PackageManager/API/PackageVolumeTests.cpp | 409 +++++++++++++++--- test/PackageManager/API/pch.h | 3 +- test/PowerNotifications/APITests.cpp | 14 +- test/PowerNotifications/FunctionalTests.cpp | 14 +- .../StoragePickersTests.cpp | 1 - 14 files changed, 519 insertions(+), 86 deletions(-) diff --git a/WindowsAppRuntime.sln b/WindowsAppRuntime.sln index 714bda40d2..b73716314b 100644 --- a/WindowsAppRuntime.sln +++ b/WindowsAppRuntime.sln @@ -690,6 +690,9 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Decimal", "Decimal", "{5012149E-F09F-4F18-A03C-FFE597203821}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Windows.Foundation.Projection", "dev\Projections\CS\Microsoft.Windows.Foundation\Microsoft.Windows.Foundation.Projection.csproj", "{8EBA8758-19D5-AE31-FD9C-86BBA3BFF6CA}" + ProjectSection(ProjectDependencies) = postProject + {B73AD907-6164-4294-88FB-F3C9C10DA1F1} = {B73AD907-6164-4294-88FB-F3C9C10DA1F1} + EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CPP", "CPP", "{7C0F3E70-BDB3-40B2-84E1-B1B77A80CB53}" EndProject diff --git a/dev/Interop/StoragePickers/PickerCommon.cpp b/dev/Interop/StoragePickers/PickerCommon.cpp index d5c003cc77..f9de786acb 100644 --- a/dev/Interop/StoragePickers/PickerCommon.cpp +++ b/dev/Interop/StoragePickers/PickerCommon.cpp @@ -180,7 +180,7 @@ namespace PickerCommon { return; } - for (int i = 0; i < value.size(); i++) + for (size_t i = 0; i < value.size(); i++) { if (value[i] == L'\0') { @@ -203,7 +203,7 @@ namespace PickerCommon { PickerLocalization::GetStoragePickersLocalizationText(ImproperFileExtensionLocalizationKey)); } - for (int i = 1; i < filter.size(); i++) + for (size_t i = 1; i < filter.size(); i++) { if (filter[i] == L'.' || filter[i] == L'*' || filter[i] == L'?') { @@ -243,7 +243,7 @@ namespace PickerCommon { } // The method SHSimpleIDListFromPath does syntax check on the path string. - wil::unique_cotaskmem_ptr pidl(SHSimpleIDListFromPath(path.c_str())); + wil::unique_cotaskmem_ptr pidl{ SHSimpleIDListFromPath(path.c_str()) }; if (!pidl) { throw std::invalid_argument(propertyName); @@ -428,11 +428,11 @@ namespace PickerCommon { if (FileTypeFilterPara.size() > 0) { - check_hresult(dialog->SetFileTypes((UINT)FileTypeFilterPara.size(), FileTypeFilterPara.data())); + check_hresult(dialog->SetFileTypes(static_cast(FileTypeFilterPara.size()), FileTypeFilterPara.data())); if (FocusLastFilter) { - check_hresult(dialog->SetFileTypeIndex(FileTypeFilterPara.size())); + check_hresult(dialog->SetFileTypeIndex(static_cast(FileTypeFilterPara.size()))); } } } diff --git a/dev/PackageManager/API/M.W.M.D.PackageVolume.cpp b/dev/PackageManager/API/M.W.M.D.PackageVolume.cpp index 588afc9d31..a3987063f8 100644 --- a/dev/PackageManager/API/M.W.M.D.PackageVolume.cpp +++ b/dev/PackageManager/API/M.W.M.D.PackageVolume.cpp @@ -95,12 +95,47 @@ namespace winrt::Microsoft::Windows::Management::Deployment::implementation } return FindPackageVolumeByName(winrt::hstring{ volumeName }); } + winrt::Microsoft::Windows::Management::Deployment::PackageVolume PackageVolume::GetPackageVolumeByPath(hstring const& path) + { + const auto c_volumePathNameMaxLength{ MAX_PATH }; + wchar_t volumePathName[c_volumePathNameMaxLength]{};//AKA volumeMountPoint + THROW_IF_WIN32_BOOL_FALSE_MSG(::GetVolumePathNameW(path.c_str(), volumePathName, ARRAYSIZE(volumePathName)), "Path:%ls", path.c_str()); + GUID mediaId{}; + const size_t c_volumeNameMaxLength{ 50 }; // "\\?\Volume{GUID}\" == 11 + 11111111-2222-3333-4444-555555555555 + 2 + null-terminator == 11 + 36 + 3 = 50 + wchar_t volumeName[c_volumeNameMaxLength]{}; + THROW_IF_WIN32_BOOL_FALSE_MSG(::GetVolumeNameForVolumeMountPoint(volumePathName, volumeName, ARRAYSIZE(volumeName)), "Path:%ls VolumePathName:%ls", path.c_str(), volumePathName); + const auto volumeNameLength{ wcslen(volumeName) }; + THROW_HR_IF_MSG(E_UNEXPECTED, volumeNameLength == 0, "Path:%ls VolumePathName:%ls", path.c_str(), volumePathName); + const auto offset{ volumeNameLength - 1 }; + if (volumeName[offset] == L'\\') + { + volumeName[offset] = L'\0'; + } + return GetPackageVolumeByName(winrt::hstring{ volumeName }); + } winrt::Microsoft::Windows::Management::Deployment::PackageVolume PackageVolume::FindPackageVolumeByName(hstring const& name) { winrt::Windows::Management::Deployment::PackageManager packageManager; winrt::Windows::Management::Deployment::PackageVolume windowsPackageVolume{ packageManager.FindPackageVolume(name) }; return winrt::make(windowsPackageVolume); } + winrt::Microsoft::Windows::Management::Deployment::PackageVolume PackageVolume::GetPackageVolumeByName(hstring const& name) + { + try + { + winrt::Windows::Management::Deployment::PackageManager packageManager; + winrt::Windows::Management::Deployment::PackageVolume windowsPackageVolume{ packageManager.FindPackageVolume(name) }; + return winrt::make(windowsPackageVolume); + } + catch (winrt::hresult_error const& exception) + { + if (exception.code() != HRESULT_FROM_WIN32(ERROR_NOT_FOUND)) + { + throw; + } + } + return winrt::Microsoft::Windows::Management::Deployment::PackageVolume(nullptr); + } winrt::Microsoft::Windows::Management::Deployment::PackageVolume PackageVolume::GetDefault() { winrt::Windows::Management::Deployment::PackageManager packageManager; @@ -111,9 +146,14 @@ namespace winrt::Microsoft::Windows::Management::Deployment::implementation { auto logTelemetry{ PackageVolumeTelemetry::Add::Start(packageStorePath) }; + //auto strong{ get_strong() }; + auto cancellation{ co_await winrt::get_cancellation_token() }; cancellation.enable_propagation(true); + logTelemetry.IgnoreCurrentThread(); + co_await resume_background(); // Allow to register the progress and complete handler + winrt::Windows::Management::Deployment::PackageManager packageManager; winrt::Windows::Management::Deployment::PackageVolume windowsPackageVolume{ co_await packageManager.AddPackageVolumeAsync(packageStorePath) }; @@ -306,7 +346,7 @@ namespace winrt::Microsoft::Windows::Management::Deployment::implementation winrt::guid activityId{}; try { - error = LOG_IF_FAILED_MSG(SetOnline(false, packageDeploymentProgress, progress, extendedError, errorText, activityId), + error = LOG_IF_FAILED_MSG(SetOnline(true, packageDeploymentProgress, progress, extendedError, errorText, activityId), "ExtendedError:0x%08X PackageVolume.SetOnline MountPoint:%ls Name:%ls PackageStorePath:%ls", extendedError, m_mountPoint.c_str(), m_name.c_str(), m_packageStorePath.c_str()); } @@ -419,7 +459,15 @@ namespace winrt::Microsoft::Windows::Management::Deployment::implementation activityId = winrt::guid{}; winrt::Windows::Management::Deployment::PackageManager packageManager; - auto deploymentOperation{ packageManager.SetPackageVolumeOnlineAsync(m_windowsPackageVolume) }; + winrt::Windows::Foundation::IAsyncOperationWithProgress deploymentOperation; + if (online) + { + deploymentOperation = packageManager.SetPackageVolumeOnlineAsync(m_windowsPackageVolume); + } + else + { + deploymentOperation = packageManager.SetPackageVolumeOfflineAsync(m_windowsPackageVolume); + } deploymentOperation.Progress([&](winrt::Windows::Foundation::IAsyncOperationWithProgress< winrt::Windows::Management::Deployment::DeploymentResult, winrt::Windows::Management::Deployment::DeploymentProgress> const& /*sender*/, diff --git a/dev/PackageManager/API/M.W.M.D.PackageVolume.h b/dev/PackageManager/API/M.W.M.D.PackageVolume.h index 8035b48d62..5db1f47d55 100644 --- a/dev/PackageManager/API/M.W.M.D.PackageVolume.h +++ b/dev/PackageManager/API/M.W.M.D.PackageVolume.h @@ -15,7 +15,9 @@ namespace winrt::Microsoft::Windows::Management::Deployment::implementation static bool IsFeatureSupported(winrt::Microsoft::Windows::Management::Deployment::PackageVolumeFeature feature); static winrt::Windows::Foundation::Collections::IVector FindPackageVolumes(); static winrt::Microsoft::Windows::Management::Deployment::PackageVolume FindPackageVolumeByPath(hstring const& packageStorePath); + static winrt::Microsoft::Windows::Management::Deployment::PackageVolume GetPackageVolumeByPath(hstring const& packageStorePath); static winrt::Microsoft::Windows::Management::Deployment::PackageVolume FindPackageVolumeByName(hstring const& name); + static winrt::Microsoft::Windows::Management::Deployment::PackageVolume GetPackageVolumeByName(hstring const& name); static winrt::Microsoft::Windows::Management::Deployment::PackageVolume GetDefault(); static winrt::Windows::Foundation::IAsyncOperation AddAsync(hstring packageStorePath); diff --git a/dev/PackageManager/API/PackageManager.idl b/dev/PackageManager/API/PackageManager.idl index e9963383db..f138eeab3d 100644 --- a/dev/PackageManager/API/PackageManager.idl +++ b/dev/PackageManager/API/PackageManager.idl @@ -108,13 +108,35 @@ namespace Microsoft.Windows.Management.Deployment /// Get the specified volume. /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagemanager.findpackagevolume + /// @see GetPackageVolumeByPath() + /// + /// @note This API is deprecated and will be removed in a future release. + /// Use GetPackageVolumeByPath(). static PackageVolume FindPackageVolumeByPath(String packageStorePath); + /// Get the specified volume. + /// @return the volume or null if not found. + /// @see GetPackageVolumeByName() + /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagemanager.findpackagevolume + [contract(PackageDeploymentContract, 3)] + static PackageVolume GetPackageVolumeByPath(String packageStorePath); + /// Get the specified volume. /// @name The volume media ID (a GUID value) + /// @see GetPackageVolumeByName() /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagemanager.findpackagevolume + /// + /// @note This API is deprecated and will be removed in a future release. + /// Use GetPackageVolumeByName(). static PackageVolume FindPackageVolumeByName(String name); + /// Get the specified volume. + /// @name The volume media ID (a GUID value) + /// @see GetPackageVolumeByPath() + /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagemanager.findpackagevolume + [contract(PackageDeploymentContract, 3)] + static PackageVolume GetPackageVolumeByName(String name); + /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagevolume.issystemvolume Boolean IsSystemVolume{ get; }; diff --git a/test/ABForward/FunctionalTests.cpp b/test/ABForward/FunctionalTests.cpp index b05d3d33cc..743f2b2e5c 100644 --- a/test/ABForward/FunctionalTests.cpp +++ b/test/ABForward/FunctionalTests.cpp @@ -50,7 +50,7 @@ namespace Test::ABForward public: FunctionalTests() = default; - + BEGIN_TEST_CLASS(FunctionalTests) TEST_CLASS_PROPERTY(L"ThreadingModel", L"MTA") TEST_CLASS_PROPERTY(L"RunAs:Class", L"RestrictedUser") @@ -110,7 +110,7 @@ namespace Test::ABForward TEST_METHOD(BatteryStatus) { - auto batteryStatus{ winrt::Microsoft::Windows::System::Power::PowerManager::BatteryStatus() }; + [[maybe_unused]] const auto batteryStatus{ winrt::Microsoft::Windows::System::Power::PowerManager::BatteryStatus() }; } TEST_METHOD(DeploymentManager) diff --git a/test/DynamicDependency/Test_Win32/Test_Win32_Create_Add_Architectures_Explicit_NoMatch.cpp b/test/DynamicDependency/Test_Win32/Test_Win32_Create_Add_Architectures_Explicit_NoMatch.cpp index 5bd575bfb3..cd208c9ac5 100644 --- a/test/DynamicDependency/Test_Win32/Test_Win32_Create_Add_Architectures_Explicit_NoMatch.cpp +++ b/test/DynamicDependency/Test_Win32/Test_Win32_Create_Add_Architectures_Explicit_NoMatch.cpp @@ -55,6 +55,7 @@ void Test::DynamicDependency::Test_Win32::Create_Add_Architectures_Explicit_NoMa const HRESULT expectedHR{ STATEREPOSITORY_E_DEPENDENCY_NOT_RESOLVED }; wil::unique_process_heap_string packageFullName_FrameworkMathAdd; MDD_PACKAGEDEPENDENCY_CONTEXT packageDependencyContext_FrameworkMathAdd{ Mdd_Add(expectedHR, packageDependencyId_FrameworkMathAdd.get(), packageFullName_FrameworkMathAdd) }; + VERIFY_IS_NULL(packageDependencyContext_FrameworkMathAdd); VERIFY_IS_NULL(packageFullName_FrameworkMathAdd.get(), WEX::Common::String().Format(L"PackageFullName=%s Expected=not-", !packageFullName_FrameworkMathAdd ? L"" : packageFullName_FrameworkMathAdd.get())); VerifyPackageInPackageGraph(expectedPackageFullName_WindowsAppRuntimeFramework, S_OK); VerifyPackageNotInPackageGraph(expectedPackageFullName_FrameworkMathAdd, S_OK); diff --git a/test/PackageManager/API/PackageDeploymentManagerTests.cpp b/test/PackageManager/API/PackageDeploymentManagerTests.cpp index ffb44b1191..be6c0b2fee 100644 --- a/test/PackageManager/API/PackageDeploymentManagerTests.cpp +++ b/test/PackageManager/API/PackageDeploymentManagerTests.cpp @@ -72,3 +72,22 @@ void Test::PackageManager::Tests::VerifyDeploymentSucceeded( deploymentResult.Status(), deploymentResult.Error(), deploymentResult.ExtendedError(), deploymentResult.ErrorText().c_str(), message)); } + +void Test::PackageManager::Tests::VerifyDeploymentSucceeded( + const winrt::Windows::Management::Deployment::DeploymentResult& deploymentResult, + PCSTR filename, + int line, + PCSTR function) +{ + WEX::Common::String source; + source.Format(L"File: %hs, Function: %hs, Line: %d", filename, function, line); + PCWSTR message{ static_cast(source) }; + + WEX::Logging::Log::Comment(WEX::Common::String().Format(L"VERIFY Deployment Suceeded: %ls", message)); + + const bool ok{ (deploymentResult.ExtendedErrorCode() == S_OK) && + deploymentResult.ErrorText().empty() }; + VERIFY_IS_TRUE(ok, WEX::Common::String().Format(L"ExtendedError:0x%X ErrorText:%ls %ls", + deploymentResult.ExtendedErrorCode(), + deploymentResult.ErrorText().c_str(), message)); +} diff --git a/test/PackageManager/API/PackageDeploymentManagerTests.h b/test/PackageManager/API/PackageDeploymentManagerTests.h index bd74f63735..aec2dc1642 100644 --- a/test/PackageManager/API/PackageDeploymentManagerTests.h +++ b/test/PackageManager/API/PackageDeploymentManagerTests.h @@ -105,6 +105,12 @@ namespace Test::PackageManager::Tests int line, PCSTR function); + void VerifyDeploymentSucceeded( + const winrt::Windows::Management::Deployment::DeploymentResult& deploymentResult, + PCSTR filename, + int line, + PCSTR function); + class PackageDeploymentManagerTests_Base { protected: @@ -154,10 +160,53 @@ namespace Test::PackageManager::Tests [&](const IAsyncOperationWithProgress&, PackageDeploymentProgress progress) { WEX::Logging::Log::Comment(WEX::Common::String().Format(L"...State:%d Percentage:%lf", static_cast(progress.Status), progress.Progress)); - if (progress.Progress != 0) +/****SEEME*** + VERIFY_IS_LESS_THAN_OR_EQUAL(progress.Progress, 1.0); + VERIFY_IS_GREATER_THAN_OR_EQUAL(progress.Progress, 0.0); + if (progress.Progress >= 1.0) + { + VERIFY_IS_TRUE((progress.Status == PackageDeploymentProgressStatus::CompletedSuccess) || + (progress.Status == PackageDeploymentProgressStatus::CompletedFailure)); + } + else if (progress.Progress > 0) { VERIFY_ARE_EQUAL(PackageDeploymentProgressStatus::InProgress, progress.Status); } + else if (progress.Progress == 0) + { + VERIFY_ARE_EQUAL(PackageDeploymentProgressStatus::Queued, progress.Status); + } +***SEEME****/ + } + ); + deploymentOperation.Progress(progressCallback); + auto deploymentResult{ deploymentOperation.get() }; + return deploymentResult; + } + + winrt::Windows::Management::Deployment::DeploymentResult WaitForDeploymentOperation( + winrt::Windows::Foundation::IAsyncOperationWithProgress& deploymentOperation) + { + using namespace winrt::Windows::Foundation; + using namespace winrt::Windows::Management::Deployment; + AsyncOperationProgressHandler progressCallback( + [&](const IAsyncOperationWithProgress&, DeploymentProgress progress) + { + WEX::Logging::Log::Comment(WEX::Common::String().Format(L"...State:%d Percentage:%lf", static_cast(progress.state), progress.percentage)); + VERIFY_IS_LESS_THAN_OR_EQUAL(progress.percentage, 100u); + VERIFY_IS_GREATER_THAN_OR_EQUAL(progress.percentage, 0u); + if (progress.percentage >= 100u) + { + VERIFY_IS_TRUE(progress.state == DeploymentProgressState::Processing); + } + else if (progress.percentage > 0u) + { + VERIFY_ARE_EQUAL(DeploymentProgressState::Processing, progress.state); + } + else if (progress.percentage == 0u) + { + VERIFY_ARE_EQUAL(DeploymentProgressState::Queued, progress.state); + } } ); deploymentOperation.Progress(progressCallback); diff --git a/test/PackageManager/API/PackageVolumeTests.cpp b/test/PackageManager/API/PackageVolumeTests.cpp index 5f8d4476cf..3246aa9b9f 100644 --- a/test/PackageManager/API/PackageVolumeTests.cpp +++ b/test/PackageManager/API/PackageVolumeTests.cpp @@ -16,90 +16,287 @@ namespace TPMT = ::Test::PackageManager::Tests; namespace Test::PackageManager::Tests { - class PackageVolumeTests_Elevated : PackageDeploymentManagerTests_Base + class PackageVolumeTests_Base : protected PackageDeploymentManagerTests_Base { - public: - BEGIN_TEST_CLASS(PackageVolumeTests_Elevated) - TEST_METHOD_PROPERTY(L"RunAs", L"ElevatedUser") - TEST_CLASS_PROPERTY(L"ThreadingModel", L"MTA") - TEST_CLASS_PROPERTY(L"IsolationLevel", L"Method") - END_TEST_CLASS() - - TEST_CLASS_SETUP(ClassSetup) + protected: + const winrt::hstring& GetTempDirectory() const { - //***SEEME***TD::DumpExecutionContext(); - - ::TB::Setup(); - - CreateTempDirectory(); - return true; + return m_tempPath; } - TEST_CLASS_CLEANUP(ClassCleanup) + bool VerifyTestVolume(PCWSTR drive) { - RemoveTempDirectory(); + VERIFY_IS_NOT_NULL(drive); + VERIFY_IS_TRUE(wcslen(drive) == 1, WEX::Common::String().Format(L"/p:PackageVolume.Drive=%s not valid", drive)); + VERIFY_IS_TRUE(CompareStringOrdinal(drive, -1, L"C", -1, TRUE) != CSTR_EQUAL, WEX::Common::String().Format(L"/p:PackageVolume.Drive=%s not valid (cannot be system drive)", drive)); - ::TB::Cleanup(); - return true; - } + m_tempPath = std::format(L"{}:\\WindowsApps", drive).c_str(); - private: - winrt::hstring m_tempPath; + return VerifyTestVolume(); + } - private: - void RemoveTempDirectory() + bool VerifyTestVolume() { if (m_tempPath.empty()) { - return; + return false; } + WEX::Logging::Log::Comment(WEX::Common::String().Format(L"Path %sfound: %s", TempDirectoryExists() ? L"" : L"not ", m_tempPath.c_str())); - if (std::filesystem::is_directory(m_tempPath.c_str())) + winrt::Windows::Management::Deployment::PackageManager packageManager; + try { - VERIFY_SUCCEEDED(wil::RemoveDirectoryRecursiveNoThrow(m_tempPath.c_str())); + auto packageVolume{ packageManager.FindPackageVolume(m_tempPath) }; + WEX::Logging::Log::Comment(WEX::Common::String().Format(L"PackageVolume found: %s", m_tempPath.c_str())); + + VERIFY_IS_FALSE(packageVolume.IsSystemVolume(), + WEX::Common::String().Format(L"Invalid test path (%s) - cannot be system drive)", m_tempPath.c_str())); + VERIFY_IS_TRUE(CompareStringOrdinal(packageVolume.PackageStorePath().c_str(), -1, m_tempPath.c_str(), -1, TRUE) == CSTR_EQUAL, + WEX::Common::String().Format(L"Invalid test path %s != PackageVolume.PackageStorePath %s", m_tempPath.c_str(), packageVolume.PackageStorePath().c_str())); + } + catch (winrt::hresult_error& e) + { + if (e.code() == HRESULT_FROM_WIN32(ERROR_NOT_FOUND)) + { + WEX::Logging::Log::Comment(WEX::Common::String().Format(L"PackageVolume not found: %s", m_tempPath.c_str())); + return false; + } + else + { + std::ignore = LOG_HR_MSG(e.code(), + "PackageVolume.GetPackageVolumeByPath PackageStorePath:%ls : %ls", + m_tempPath.c_str(), e.message().c_str()); + throw; + } + } + catch (...) + { + const auto exception{ winrt::hresult_error(winrt::to_hresult(), winrt::take_ownership_from_abi) }; + if (exception.code() == HRESULT_FROM_WIN32(ERROR_NOT_FOUND)) + { + WEX::Logging::Log::Comment(WEX::Common::String().Format(L"PackageVolume not found: %s", m_tempPath.c_str())); + return false; + } + else + { + std::ignore = LOG_HR_MSG(exception.code(), + "PackageVolume.FindPackageVolumeByPath PackageStorePath:%ls : %ls", + m_tempPath.c_str(), exception.message().c_str()); + throw; + } } - VERIFY_IS_TRUE(std::filesystem::create_directory(m_tempPath.c_str())); - m_tempPath.clear(); + return true; } - void CreateTempDirectory() + bool BlockIfTestVolumeExists(PCWSTR drive) { - if (m_tempPath.empty()) + const auto exists{ VerifyTestVolume(drive) }; + if (exists) { - const auto tempDirectory{ std::filesystem::temp_directory_path() / L"PackageVolumeTests" }; - m_tempPath = tempDirectory.c_str(); + WEX::Logging::Log::Result(WEX::Logging::TestResults::Blocked, + WEX::Common::String().Format(L"Test PackageVolume exists (%s). Blocking tests", m_tempPath.c_str())); } + return exists; + } - RemoveTempDirectory(); + bool TempDirectoryExists() const + { + return DirectoryExists(m_tempPath); + } - VERIFY_IS_TRUE(std::filesystem::create_directory(m_tempPath.c_str())); + bool DirectoryExists(const winrt::hstring& path) const + { + return !path.empty() && std::filesystem::is_directory(path.c_str()); + } - VERIFY_IS_TRUE(std::filesystem::is_directory(m_tempPath.c_str())); + protected: + void Dump( + const winrt::Microsoft::Windows::Management::Deployment::PackageVolume& packageVolume) const + { + WEX::Logging::Log::Comment(WEX::Common::String().Format(L"PackageVolume: Microsoft\n" + L" MountPoint: %s\n" + L" Name: %s\n" + L" PackageStorePath: %s\n" + L" State:%s%s%s%s%s\n", + packageVolume.MountPoint().c_str(), + packageVolume.Name().c_str(), + packageVolume.PackageStorePath().c_str(), + packageVolume.IsSystemVolume() ? L" System" : L"", + packageVolume.IsOffline() ? L" Offline" : L" Online", + packageVolume.SupportsHardLinks() ? L" Hardlinks" : L"", + packageVolume.IsAppxInstallSupported() ? L" AppxInstall" : L"", + packageVolume.IsFullTrustPackageSupported() ? L" FullTrust" : L"")); + //TODO IsRepairNeeded } - bool TempDirectoryExists() const + void Dump( + const winrt::Windows::Management::Deployment::PackageVolume& packageVolume) const { - return std::filesystem::is_directory(m_tempPath.c_str()); + WEX::Logging::Log::Comment(WEX::Common::String().Format(L"PackageVolume: Windows\n" + L" MountPoint: %s\n" + L" Name: %s\n" + L" PackageStorePath: %s\n" + L" State:%s%s%s%s%s\n", + packageVolume.MountPoint().c_str(), + packageVolume.Name().c_str(), + packageVolume.PackageStorePath().c_str(), + packageVolume.IsSystemVolume() ? L" System" : L"", + packageVolume.IsOffline() ? L" Offline" : L" Online", + packageVolume.SupportsHardLinks() ? L" Hardlinks" : L"", + packageVolume.IsAppxInstallSupported() ? L" AppxInstall" : L"", + packageVolume.IsFullTrustPackageSupported() ? L" FullTrust" : L"")); } - private: + winrt::Microsoft::Windows::Management::Deployment::PackageVolume Dump( + const winrt::hstring& path) const + { + auto packageVolume{ winrt::Microsoft::Windows::Management::Deployment::PackageVolume::GetPackageVolumeByPath(path) }; + Dump(packageVolume); + return packageVolume; + } + + protected: void Verify( const winrt::Microsoft::Windows::Management::Deployment::PackageVolume& packageVolume, const winrt::Windows::Management::Deployment::PackageVolume& windowsPackageVolume) { - throw winrt::hresult_not_implemented(); + VERIFY_ARE_EQUAL(packageVolume.IsSystemVolume(), windowsPackageVolume.IsSystemVolume()); + VERIFY_ARE_EQUAL(packageVolume.MountPoint(), windowsPackageVolume.MountPoint()); + VERIFY_ARE_EQUAL(packageVolume.Name(), windowsPackageVolume.Name()); + VERIFY_ARE_EQUAL(packageVolume.PackageStorePath(), windowsPackageVolume.PackageStorePath()); + VERIFY_ARE_EQUAL(packageVolume.SupportsHardLinks(), windowsPackageVolume.SupportsHardLinks()); + VERIFY_ARE_EQUAL(packageVolume.IsAppxInstallSupported(), windowsPackageVolume.IsAppxInstallSupported()); + VERIFY_ARE_EQUAL(packageVolume.IsFullTrustPackageSupported(), windowsPackageVolume.IsFullTrustPackageSupported()); + VERIFY_ARE_EQUAL(packageVolume.IsOffline(), windowsPackageVolume.IsOffline()); } void Verify( const winrt::Microsoft::Windows::Management::Deployment::PackageVolume& actual, const winrt::Microsoft::Windows::Management::Deployment::PackageVolume& expected) { - throw winrt::hresult_not_implemented(); + VERIFY_ARE_EQUAL(expected.IsSystemVolume(), actual.IsSystemVolume()); + VERIFY_ARE_EQUAL(expected.MountPoint(), actual.MountPoint()); + VERIFY_ARE_EQUAL(expected.Name(), actual.Name()); + VERIFY_ARE_EQUAL(expected.PackageStorePath(), actual.PackageStorePath()); + VERIFY_ARE_EQUAL(expected.SupportsHardLinks(), actual.SupportsHardLinks()); + VERIFY_ARE_EQUAL(expected.IsAppxInstallSupported(), actual.IsAppxInstallSupported()); + VERIFY_ARE_EQUAL(expected.IsFullTrustPackageSupported(), actual.IsFullTrustPackageSupported()); + VERIFY_ARE_EQUAL(expected.IsOffline(), actual.IsOffline()); + } + + protected: + bool RemovePackageVolumeIfNecessary() + { + if (m_tempPath.empty()) + { + WEX::Common::String drive; + if (!::Test::TAEF::TryGetOption(L"PackageVolume.Drive", drive)) + { + WEX::Logging::Log::Result(WEX::Logging::TestResults::Skipped, L"/p:PackageVolume.Drive= not specified. Skipping tests"); + return true; + } + const auto exists{ VerifyTestVolume(drive) }; + if (!exists) + { + return true; + } + } + + winrt::Windows::Management::Deployment::PackageManager packageManager; + try + { + auto packageVolume{ packageManager.FindPackageVolume(m_tempPath) }; + if (packageVolume) + { + VERIFY_IS_FALSE(packageVolume.IsSystemVolume(), + WEX::Common::String().Format(L"Invalid test path (%s) - cannot be system drive)", m_tempPath.c_str())); + VERIFY_IS_TRUE(CompareStringOrdinal(packageVolume.PackageStorePath().c_str(), -1, m_tempPath.c_str(), -1, TRUE) == CSTR_EQUAL, + WEX::Common::String().Format(L"Invalid test path %s != PackageVolume.PackageStorePath %s", m_tempPath.c_str(), packageVolume.PackageStorePath().c_str())); + + WEX::Logging::Log::Comment(WEX::Common::String().Format(L"Removing PackageVolume %s", m_tempPath.c_str())); + auto deploymentOperation{ packageManager.RemovePackageVolumeAsync(packageVolume) }; + auto deploymentResult{ WaitForDeploymentOperation(deploymentOperation) }; + TPMT::VerifyDeploymentSucceeded(deploymentResult, __FILE__, __LINE__, __FUNCTION__); + } + } + catch (winrt::hresult_error& e) + { + if (e.code() == HRESULT_FROM_WIN32(ERROR_NOT_FOUND)) + { + WEX::Logging::Log::Comment(WEX::Common::String().Format(L"PackageVolume not found: %s", m_tempPath.c_str())); + } + else + { + std::ignore = LOG_HR_MSG(e.code(), + "PackageVolume.GetPackageVolumeByPath PackageStorePath:%ls : %ls", + m_tempPath.c_str(), e.message().c_str()); + throw; + } + } + catch (...) + { + const auto exception{ winrt::hresult_error(winrt::to_hresult(), winrt::take_ownership_from_abi) }; + if (exception.code() == HRESULT_FROM_WIN32(ERROR_NOT_FOUND)) + { + WEX::Logging::Log::Comment(WEX::Common::String().Format(L"PackageVolume not found: %s", m_tempPath.c_str())); + } + else + { + std::ignore = LOG_HR_MSG(exception.code(), + "PackageVolume.FindPackageVolumeByPath PackageStorePath:%ls : %ls", + m_tempPath.c_str(), exception.message().c_str()); + throw; + } + } + + try + { + winrt::Windows::Management::Deployment::PackageVolume windowsPackageVolume{ packageManager.FindPackageVolume(m_tempPath) }; + } + catch (winrt::hresult_error const& e) + { + if (e.code() == HRESULT_FROM_WIN32(ERROR_NOT_FOUND)) + { + WEX::Logging::Log::Comment(WEX::Common::String().Format(L"PackageVolume not defined for %s", m_tempPath.c_str())); + } + else + { + WEX::Logging::Log::Comment(WEX::Common::String().Format(L"PackageManager.FindPackageVolume(%ls) = 0x%08X", m_tempPath.c_str(), e.code())); + throw; + } + } + return true; } + protected: + winrt::hstring m_tempPath; + }; + + class PackageVolumeTests_Elevated : protected PackageVolumeTests_Base + { public: + BEGIN_TEST_CLASS(PackageVolumeTests_Elevated) + TEST_METHOD_PROPERTY(L"RunAs", L"ElevatedUser") + TEST_CLASS_PROPERTY(L"ThreadingModel", L"MTA") + END_TEST_CLASS() + + TEST_CLASS_SETUP(ClassSetup) + { + ::TB::Setup(); + + return true; + } + + TEST_CLASS_CLEANUP(ClassCleanup) + { + const auto exists{ VerifyTestVolume() }; + + ::TB::Cleanup(); + return exists; + } + public: TEST_METHOD(GetDefault) { const auto packageVolume{ winrt::Microsoft::Windows::Management::Deployment::PackageVolume::GetDefault() }; @@ -108,47 +305,139 @@ namespace Test::PackageManager::Tests Verify(packageVolume, windowsPackageVolume); } + TEST_METHOD(GetAvailableSpace) + { + const auto packageVolume{ winrt::Microsoft::Windows::Management::Deployment::PackageVolume::GetDefault() }; + WEX::Logging::Log::Comment(WEX::Common::String().Format(L"PackgeVolume.Default: MountPoint=%ls Name=%ls PackageStorePath=%ls", + packageVolume.MountPoint().c_str(), packageVolume.Name().c_str(), packageVolume.PackageStorePath().c_str())); + std::uint64_t availableSpace{ packageVolume.GetAvailableSpaceAsync().get() }; + std::uint64_t kb{ availableSpace / 1024 }; + std::uint64_t mb{ kb / 1024 }; + std::uint64_t gb{ mb / 1024 }; + WEX::Logging::Log::Comment(WEX::Common::String().Format(L"AvailableSpace=%llu bytes / %lluKB / %lluMB / %lluGB", availableSpace, kb, mb, gb)); + } + }; + + class PackageVolumeTests_System : protected PackageVolumeTests_Base + { + public: + BEGIN_TEST_CLASS(PackageVolumeTests_System) + TEST_METHOD_PROPERTY(L"RunAs", L"ElevatedUser") + TEST_METHOD_PROPERTY(L"RunFixtureAs", L"System") + TEST_CLASS_PROPERTY(L"ThreadingModel", L"MTA") + END_TEST_CLASS() + + TEST_CLASS_SETUP(ClassSetup) + { + return true; + } + + TEST_CLASS_CLEANUP(ClassCleanup) + { + return RemovePackageVolumeIfNecessary(); + } + TEST_METHOD(Add_Online_Offline_Remove) { - auto packageVolumeAdded{ winrt::Microsoft::Windows::Management::Deployment::PackageVolume::AddAsync(m_tempPath).get() }; - auto packageVolume{ winrt::Microsoft::Windows::Management::Deployment::PackageVolume::FindPackageVolumeByPath(m_tempPath) }; - Verify(packageVolumeAdded, packageVolume); + ::TB::Setup(); + auto cleanup{ wil::scope_exit([this]{ + ::TB::Cleanup(); + }) }; + + WEX::Common::String drive; + if (!::Test::TAEF::TryGetOption(L"PackageVolume.Drive", drive)) + { + WEX::Logging::Log::Result(WEX::Logging::TestResults::Skipped, L"/p:PackageVolume.Drive= not specified. Skipping tests"); + return; + } + if (BlockIfTestVolumeExists(drive)) + { + return; + } + + // Add a package volume + auto asyncOperation{ winrt::Microsoft::Windows::Management::Deployment::PackageVolume::AddAsync(GetTempDirectory()) }; + const auto hr{ static_cast(asyncOperation.ErrorCode()) }; + WEX::Logging::Log::Comment(WEX::Common::String().Format(L"AddAsync: Status=%d ErrorCode=0x%X", asyncOperation.Status(), hr)); + auto packageVolumeAdded{ asyncOperation.get() }; + Dump(packageVolumeAdded); + // + // NOTE: Newly created PackageVolumes are Online + VERIFY_IS_FALSE(packageVolumeAdded.IsOffline()); + + // Verify the new package volume is query'able + { + auto packageVolume{ Dump(GetTempDirectory()) }; + Verify(packageVolumeAdded, packageVolume); + } VERIFY_IS_FALSE(packageVolumeAdded.IsOffline()); + // Set the package volume Offline (or 'Dismount-PackageVolume' in Powershell-speak) + // FYI interactively: powershell -c "Get-AppxVolume -Path X: | Dismount-AppxVolume" + { + auto packageVolumeBefore{ Dump(GetTempDirectory()) }; + VERIFY_IS_FALSE(packageVolumeBefore.IsOffline()); + + auto deploymentOperation{ packageVolumeAdded.SetOfflineAsync() }; + auto deploymentResult{ WaitForDeploymentOperation(deploymentOperation) }; + TPMT::VerifyDeploymentSucceeded(deploymentResult, __FILE__, __LINE__, __FUNCTION__); + + auto packageVolumeAfter{ Dump(GetTempDirectory()) }; + VERIFY_IS_TRUE(packageVolumeAfter.IsOffline()); + } + + // Set the package volume Offline again (Offline->Offline == Offline (no change)) { + auto packageVolumeBefore{ Dump(GetTempDirectory()) }; + VERIFY_IS_TRUE(packageVolumeBefore.IsOffline()); + auto deploymentOperation{ packageVolumeAdded.SetOfflineAsync() }; auto deploymentResult{ WaitForDeploymentOperation(deploymentOperation) }; TPMT::VerifyDeploymentSucceeded(deploymentResult, __FILE__, __LINE__, __FUNCTION__); - auto packageVolume{ winrt::Microsoft::Windows::Management::Deployment::PackageVolume::FindPackageVolumeByPath(m_tempPath) }; - VERIFY_IS_TRUE(packageVolume.IsOffline()); + + auto packageVolumeAfter{ Dump(GetTempDirectory()) }; + VERIFY_IS_TRUE(packageVolumeAfter.IsOffline()); } + // Set the package volume Online (or 'Mount-PackageVolume' in Powershell-speak) + // FYI interactively: powershell -c "Get-AppxVolume -Path X: | Mount-AppxVolume" { + auto packageVolumeBefore{ Dump(GetTempDirectory()) }; + VERIFY_IS_TRUE(packageVolumeBefore.IsOffline()); + auto deploymentOperation{ packageVolumeAdded.SetOnlineAsync() }; auto deploymentResult{ WaitForDeploymentOperation(deploymentOperation) }; TPMT::VerifyDeploymentSucceeded(deploymentResult, __FILE__, __LINE__, __FUNCTION__); - auto packageVolume{ winrt::Microsoft::Windows::Management::Deployment::PackageVolume::FindPackageVolumeByPath(m_tempPath) }; - VERIFY_IS_FALSE(packageVolume.IsOffline()); + + auto packageVolumeAfter{ Dump(GetTempDirectory()) }; + VERIFY_IS_FALSE(packageVolumeAfter.IsOffline()); } + // Set the package volume Online again (Online->Online == Online (no change)) { - auto deploymentOperation{ packageVolumeAdded.RemoveAsync() }; + auto packageVolumeBefore{ Dump(GetTempDirectory()) }; + VERIFY_IS_FALSE(packageVolumeBefore.IsOffline()); + + auto deploymentOperation{ packageVolumeAdded.SetOnlineAsync() }; auto deploymentResult{ WaitForDeploymentOperation(deploymentOperation) }; TPMT::VerifyDeploymentSucceeded(deploymentResult, __FILE__, __LINE__, __FUNCTION__); + + auto packageVolumeAfter{ Dump(GetTempDirectory()) }; + VERIFY_IS_FALSE(packageVolumeAfter.IsOffline()); } - } - TEST_METHOD(GetAvailableSpace) - { - const auto packageVolume{ winrt::Microsoft::Windows::Management::Deployment::PackageVolume::GetDefault() }; - WEX::Logging::Log::Comment(WEX::Common::String().Format(L"PackgeVolume.Default: MountPoint=%ls Name=%ls PackageStorePath=%ls", - packageVolume.MountPoint().c_str(), packageVolume.Name().c_str(), packageVolume.PackageStorePath().c_str())); - std::uint64_t availableSpace{ packageVolume.GetAvailableSpaceAsync().get() }; - std::uint64_t kb{ availableSpace / 1024 }; - std::uint64_t mb{ kb / 1024 }; - std::uint64_t gb{ mb / 1024 }; - WEX::Logging::Log::Comment(WEX::Common::String().Format(L"AvailableSpace=%llu bytes / %lluKB / %lluMB / %lluGB", availableSpace, kb, mb, gb)); + // Remove the package volume + // + // FYI interactively: powershell -c "Get-AppxVolume -Path X: | Remove-AppxVolume" + { + auto packageVolume{ Dump(GetTempDirectory()) }; + VERIFY_IS_FALSE(packageVolume.IsOffline()); + + auto deploymentOperation{ packageVolumeAdded.RemoveAsync() }; + auto deploymentResult{ WaitForDeploymentOperation(deploymentOperation) }; + TPMT::VerifyDeploymentSucceeded(deploymentResult, __FILE__, __LINE__, __FUNCTION__); + } } }; } diff --git a/test/PackageManager/API/pch.h b/test/PackageManager/API/pch.h index de5cd6727d..f329a4cbbe 100644 --- a/test/PackageManager/API/pch.h +++ b/test/PackageManager/API/pch.h @@ -8,8 +8,8 @@ #include -#include #include +#include #include #include @@ -29,6 +29,7 @@ #include #include #include +#include #include "PackageManagerTests.Packages.h" diff --git a/test/PowerNotifications/APITests.cpp b/test/PowerNotifications/APITests.cpp index d2346eb87e..5642123297 100644 --- a/test/PowerNotifications/APITests.cpp +++ b/test/PowerNotifications/APITests.cpp @@ -81,7 +81,7 @@ namespace Test::PowerNotifications auto batteryStat = BatteryStatus::Discharging; auto powerStat = PowerSupplyStatus::Inadequate; int32_t remainingCharge = 15; - auto token = PowerManager::BatteryStatusChanged([&](const auto&, winrt::Windows::Foundation::IInspectable obj) + auto token = PowerManager::BatteryStatusChanged([&](const auto&, winrt::Windows::Foundation::IInspectable /*obj*/) { batteryStat = PowerManager::BatteryStatus(); powerStat = PowerManager::PowerSupplyStatus(); @@ -108,7 +108,7 @@ namespace Test::PowerNotifications THROW_LAST_ERROR_IF_NULL(event.get()); auto value = winrt::Windows::Foundation::TimeSpan(1s); - auto token = PowerManager::RemainingDischargeTimeChanged([&](const auto&, winrt::Windows::Foundation::IInspectable obj) + auto token = PowerManager::RemainingDischargeTimeChanged([&](const auto&, winrt::Windows::Foundation::IInspectable /*obj*/) { value = PowerManager::RemainingDischargeTime(); SetEvent(event.get()); @@ -129,7 +129,7 @@ namespace Test::PowerNotifications wil::unique_handle event(CreateEvent(nullptr, false, false, nullptr)); THROW_LAST_ERROR_IF_NULL(event.get()); auto value = EnergySaverStatus::Disabled; - auto token = PowerManager::EnergySaverStatusChanged([&](const auto&, winrt::Windows::Foundation::IInspectable obj) + auto token = PowerManager::EnergySaverStatusChanged([&](const auto&, winrt::Windows::Foundation::IInspectable /*obj*/) { value = PowerManager::EnergySaverStatus(); SetEvent(event.get()); @@ -151,7 +151,7 @@ namespace Test::PowerNotifications wil::unique_handle event(CreateEvent(nullptr, false, false, nullptr)); THROW_LAST_ERROR_IF_NULL(event.get()); auto value = PowerSourceKind::DC; - auto token = PowerManager::PowerSourceKindChanged([&](const auto&, winrt::Windows::Foundation::IInspectable obj) + auto token = PowerManager::PowerSourceKindChanged([&](const auto&, winrt::Windows::Foundation::IInspectable /*obj*/) { value = PowerManager::PowerSourceKind(); SetEvent(event.get()); @@ -173,7 +173,7 @@ namespace Test::PowerNotifications wil::unique_handle event(CreateEvent(nullptr, false, false, nullptr)); THROW_LAST_ERROR_IF_NULL(event.get()); auto value = DisplayStatus::Off; - auto token = PowerManager::DisplayStatusChanged([&](const auto&, winrt::Windows::Foundation::IInspectable obj) + auto token = PowerManager::DisplayStatusChanged([&](const auto&, winrt::Windows::Foundation::IInspectable /*obj*/) { value = PowerManager::DisplayStatus(); SetEvent(event.get()); @@ -193,7 +193,7 @@ namespace Test::PowerNotifications END_TEST_METHOD_PROPERTIES() auto callback_success = false; - auto token = PowerManager::SystemIdleStatusChanged([&](const auto&, winrt::Windows::Foundation::IInspectable obj) + auto token = PowerManager::SystemIdleStatusChanged([&](const auto&, winrt::Windows::Foundation::IInspectable /*obj*/) { callback_success = true; }); @@ -213,7 +213,7 @@ namespace Test::PowerNotifications wil::unique_handle event(CreateEvent(nullptr, false, false, nullptr)); THROW_LAST_ERROR_IF_NULL(event.get()); auto value = UserPresenceStatus::Absent; - auto token = PowerManager::UserPresenceStatusChanged([&](const auto&, winrt::Windows::Foundation::IInspectable obj) + auto token = PowerManager::UserPresenceStatusChanged([&](const auto&, winrt::Windows::Foundation::IInspectable /*obj*/) { value = PowerManager::UserPresenceStatus(); SetEvent(event.get()); diff --git a/test/PowerNotifications/FunctionalTests.cpp b/test/PowerNotifications/FunctionalTests.cpp index 4058d2a5e1..06fba49e69 100644 --- a/test/PowerNotifications/FunctionalTests.cpp +++ b/test/PowerNotifications/FunctionalTests.cpp @@ -63,7 +63,7 @@ namespace Test::PowerNotifications auto batteryStat = BatteryStatus::Discharging; auto powerStat = PowerSupplyStatus::Inadequate; int32_t remainingCharge = 15; - auto token = PowerManager::BatteryStatusChanged([&](const auto&, winrt::Windows::Foundation::IInspectable obj) + auto token = PowerManager::BatteryStatusChanged([&](const auto&, winrt::Windows::Foundation::IInspectable /*obj*/) { batteryStat = PowerManager::BatteryStatus(); powerStat = PowerManager::PowerSupplyStatus(); @@ -90,7 +90,7 @@ namespace Test::PowerNotifications THROW_LAST_ERROR_IF_NULL(event.get()); auto value = winrt::Windows::Foundation::TimeSpan(1s); - auto token = PowerManager::RemainingDischargeTimeChanged([&](const auto&, winrt::Windows::Foundation::IInspectable obj) + auto token = PowerManager::RemainingDischargeTimeChanged([&](const auto&, winrt::Windows::Foundation::IInspectable /*obj*/) { value = PowerManager::RemainingDischargeTime(); SetEvent(event.get()); @@ -111,7 +111,7 @@ namespace Test::PowerNotifications wil::unique_handle event(CreateEvent(nullptr, false, false, nullptr)); THROW_LAST_ERROR_IF_NULL(event.get()); auto value = EnergySaverStatus::Disabled; - auto token = PowerManager::EnergySaverStatusChanged([&](const auto&, winrt::Windows::Foundation::IInspectable obj) + auto token = PowerManager::EnergySaverStatusChanged([&](const auto&, winrt::Windows::Foundation::IInspectable /*obj*/) { value = PowerManager::EnergySaverStatus(); SetEvent(event.get()); @@ -133,7 +133,7 @@ namespace Test::PowerNotifications wil::unique_handle event(CreateEvent(nullptr, false, false, nullptr)); THROW_LAST_ERROR_IF_NULL(event.get()); auto value = PowerSourceKind::DC; - auto token = PowerManager::PowerSourceKindChanged([&](const auto&, winrt::Windows::Foundation::IInspectable obj) + auto token = PowerManager::PowerSourceKindChanged([&](const auto&, winrt::Windows::Foundation::IInspectable /*obj*/) { value = PowerManager::PowerSourceKind(); SetEvent(event.get()); @@ -155,7 +155,7 @@ namespace Test::PowerNotifications wil::unique_handle event(CreateEvent(nullptr, false, false, nullptr)); THROW_LAST_ERROR_IF_NULL(event.get()); auto value = DisplayStatus::Off; - auto token = PowerManager::DisplayStatusChanged([&](const auto&, winrt::Windows::Foundation::IInspectable obj) + auto token = PowerManager::DisplayStatusChanged([&](const auto&, winrt::Windows::Foundation::IInspectable /*obj*/) { value = PowerManager::DisplayStatus(); SetEvent(event.get()); @@ -175,7 +175,7 @@ namespace Test::PowerNotifications END_TEST_METHOD_PROPERTIES() auto callback_success = false; - auto token = PowerManager::SystemIdleStatusChanged([&](const auto&, winrt::Windows::Foundation::IInspectable obj) + auto token = PowerManager::SystemIdleStatusChanged([&](const auto&, winrt::Windows::Foundation::IInspectable /*obj*/) { callback_success = true; }); @@ -195,7 +195,7 @@ namespace Test::PowerNotifications wil::unique_handle event(CreateEvent(nullptr, false, false, nullptr)); THROW_LAST_ERROR_IF_NULL(event.get()); auto value = UserPresenceStatus::Absent; - auto token = PowerManager::UserPresenceStatusChanged([&](const auto&, winrt::Windows::Foundation::IInspectable obj) + auto token = PowerManager::UserPresenceStatusChanged([&](const auto&, winrt::Windows::Foundation::IInspectable /*obj*/) { value = PowerManager::UserPresenceStatus(); SetEvent(event.get()); diff --git a/test/StoragePickersTests/StoragePickersTests.cpp b/test/StoragePickersTests/StoragePickersTests.cpp index 97721e7c2a..ff4647b3aa 100644 --- a/test/StoragePickersTests/StoragePickersTests.cpp +++ b/test/StoragePickersTests/StoragePickersTests.cpp @@ -192,7 +192,6 @@ namespace Test::StoragePickersTests TEST_METHOD(VerifyFolderPickerOptionsAreReadCorrectly) { - auto parentWindow = ::GetForegroundWindow(); winrt::Microsoft::UI::WindowId windowId{}; winrt::Microsoft::Windows::Storage::Pickers::FolderPicker picker(windowId); From 884d98db6a2177b39702dd906d1cee93e4b67c27 Mon Sep 17 00:00:00 2001 From: Howard Kapustein Date: Tue, 23 Dec 2025 22:48:42 -0800 Subject: [PATCH 07/10] Fixed Progress reporting for *Async() - was Status=Queued and raw uint32=0-100 (not our double=0.0-1.0) --- dev/PackageManager/API/M.W.M.D.PackageVolume.cpp | 6 ++++-- test/PackageManager/API/PackageDeploymentManagerTests.h | 9 ++++----- test/PackageManager/API/PackageVolumeTests.cpp | 4 ++++ 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/dev/PackageManager/API/M.W.M.D.PackageVolume.cpp b/dev/PackageManager/API/M.W.M.D.PackageVolume.cpp index a3987063f8..09d03576c6 100644 --- a/dev/PackageManager/API/M.W.M.D.PackageVolume.cpp +++ b/dev/PackageManager/API/M.W.M.D.PackageVolume.cpp @@ -403,7 +403,8 @@ namespace winrt::Microsoft::Windows::Management::Deployment::implementation winrt::Windows::Management::Deployment::DeploymentProgress> const& /*sender*/, winrt::Windows::Management::Deployment::DeploymentProgress const& progressInfo) { - packageDeploymentProgress.Progress = progressInfo.percentage; + packageDeploymentProgress.Status = PackageDeploymentProgressStatus::InProgress; + packageDeploymentProgress.Progress = static_cast(progressInfo.percentage) / 100.0; progress(packageDeploymentProgress); }); deploymentOperation.get(); @@ -473,7 +474,8 @@ namespace winrt::Microsoft::Windows::Management::Deployment::implementation winrt::Windows::Management::Deployment::DeploymentProgress> const& /*sender*/, winrt::Windows::Management::Deployment::DeploymentProgress const& progressInfo) { - packageDeploymentProgress.Progress = progressInfo.percentage; + packageDeploymentProgress.Status = PackageDeploymentProgressStatus::InProgress; + packageDeploymentProgress.Progress = static_cast(progressInfo.percentage) / 100.0; progress(packageDeploymentProgress); }); deploymentOperation.get(); diff --git a/test/PackageManager/API/PackageDeploymentManagerTests.h b/test/PackageManager/API/PackageDeploymentManagerTests.h index aec2dc1642..d513e06f19 100644 --- a/test/PackageManager/API/PackageDeploymentManagerTests.h +++ b/test/PackageManager/API/PackageDeploymentManagerTests.h @@ -159,13 +159,13 @@ namespace Test::PackageManager::Tests AsyncOperationProgressHandler progressCallback( [&](const IAsyncOperationWithProgress&, PackageDeploymentProgress progress) { - WEX::Logging::Log::Comment(WEX::Common::String().Format(L"...State:%d Percentage:%lf", static_cast(progress.Status), progress.Progress)); -/****SEEME*** + WEX::Logging::Log::Comment(WEX::Common::String().Format(L"...Status:%d Progress:%lf", static_cast(progress.Status), progress.Progress)); VERIFY_IS_LESS_THAN_OR_EQUAL(progress.Progress, 1.0); VERIFY_IS_GREATER_THAN_OR_EQUAL(progress.Progress, 0.0); if (progress.Progress >= 1.0) { - VERIFY_IS_TRUE((progress.Status == PackageDeploymentProgressStatus::CompletedSuccess) || + VERIFY_IS_TRUE((progress.Status == PackageDeploymentProgressStatus::InProgress) || + (progress.Status == PackageDeploymentProgressStatus::CompletedSuccess) || (progress.Status == PackageDeploymentProgressStatus::CompletedFailure)); } else if (progress.Progress > 0) @@ -176,7 +176,6 @@ namespace Test::PackageManager::Tests { VERIFY_ARE_EQUAL(PackageDeploymentProgressStatus::Queued, progress.Status); } -***SEEME****/ } ); deploymentOperation.Progress(progressCallback); @@ -192,7 +191,7 @@ namespace Test::PackageManager::Tests AsyncOperationProgressHandler progressCallback( [&](const IAsyncOperationWithProgress&, DeploymentProgress progress) { - WEX::Logging::Log::Comment(WEX::Common::String().Format(L"...State:%d Percentage:%lf", static_cast(progress.state), progress.percentage)); + WEX::Logging::Log::Comment(WEX::Common::String().Format(L"...State:%d Percentage:%u", static_cast(progress.state), progress.percentage)); VERIFY_IS_LESS_THAN_OR_EQUAL(progress.percentage, 100u); VERIFY_IS_GREATER_THAN_OR_EQUAL(progress.percentage, 0u); if (progress.percentage >= 100u) diff --git a/test/PackageManager/API/PackageVolumeTests.cpp b/test/PackageManager/API/PackageVolumeTests.cpp index 3246aa9b9f..c08a099358 100644 --- a/test/PackageManager/API/PackageVolumeTests.cpp +++ b/test/PackageManager/API/PackageVolumeTests.cpp @@ -379,6 +379,7 @@ namespace Test::PackageManager::Tests auto packageVolumeBefore{ Dump(GetTempDirectory()) }; VERIFY_IS_FALSE(packageVolumeBefore.IsOffline()); + WEX::Logging::Log::Comment(WEX::Common::String().Format(L"SetOfflineAsync...")); auto deploymentOperation{ packageVolumeAdded.SetOfflineAsync() }; auto deploymentResult{ WaitForDeploymentOperation(deploymentOperation) }; TPMT::VerifyDeploymentSucceeded(deploymentResult, __FILE__, __LINE__, __FUNCTION__); @@ -392,6 +393,7 @@ namespace Test::PackageManager::Tests auto packageVolumeBefore{ Dump(GetTempDirectory()) }; VERIFY_IS_TRUE(packageVolumeBefore.IsOffline()); + WEX::Logging::Log::Comment(WEX::Common::String().Format(L"SetOfflineAsync...")); auto deploymentOperation{ packageVolumeAdded.SetOfflineAsync() }; auto deploymentResult{ WaitForDeploymentOperation(deploymentOperation) }; TPMT::VerifyDeploymentSucceeded(deploymentResult, __FILE__, __LINE__, __FUNCTION__); @@ -406,6 +408,7 @@ namespace Test::PackageManager::Tests auto packageVolumeBefore{ Dump(GetTempDirectory()) }; VERIFY_IS_TRUE(packageVolumeBefore.IsOffline()); + WEX::Logging::Log::Comment(WEX::Common::String().Format(L"SetOnlineAsync...")); auto deploymentOperation{ packageVolumeAdded.SetOnlineAsync() }; auto deploymentResult{ WaitForDeploymentOperation(deploymentOperation) }; TPMT::VerifyDeploymentSucceeded(deploymentResult, __FILE__, __LINE__, __FUNCTION__); @@ -419,6 +422,7 @@ namespace Test::PackageManager::Tests auto packageVolumeBefore{ Dump(GetTempDirectory()) }; VERIFY_IS_FALSE(packageVolumeBefore.IsOffline()); + WEX::Logging::Log::Comment(WEX::Common::String().Format(L"SetOnlineAsync...")); auto deploymentOperation{ packageVolumeAdded.SetOnlineAsync() }; auto deploymentResult{ WaitForDeploymentOperation(deploymentOperation) }; TPMT::VerifyDeploymentSucceeded(deploymentResult, __FILE__, __LINE__, __FUNCTION__); From ca4d4d4342bd98916f7cb3ea5e2faaa7d61d5c99 Mon Sep 17 00:00:00 2001 From: Howard Kapustein Date: Tue, 23 Dec 2025 23:23:54 -0800 Subject: [PATCH 08/10] Fixed some doc-comments --- .../API/M.W.M.D.PackageVolume.cpp | 8 ++++---- .../API/M.W.M.D.PackageVolume.h | 2 +- dev/PackageManager/API/PackageManager.idl | 20 +++++++++++++++++-- 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/dev/PackageManager/API/M.W.M.D.PackageVolume.cpp b/dev/PackageManager/API/M.W.M.D.PackageVolume.cpp index 09d03576c6..3d05f55434 100644 --- a/dev/PackageManager/API/M.W.M.D.PackageVolume.cpp +++ b/dev/PackageManager/API/M.W.M.D.PackageVolume.cpp @@ -77,17 +77,17 @@ namespace winrt::Microsoft::Windows::Management::Deployment::implementation } return microsoftPackageVolumes; } - winrt::Microsoft::Windows::Management::Deployment::PackageVolume PackageVolume::FindPackageVolumeByPath(hstring const& path) + winrt::Microsoft::Windows::Management::Deployment::PackageVolume PackageVolume::FindPackageVolumeByPath(hstring const& packageStorePath) { const auto c_volumePathNameMaxLength{ MAX_PATH }; wchar_t volumePathName[c_volumePathNameMaxLength]{};//AKA volumeMountPoint - THROW_IF_WIN32_BOOL_FALSE_MSG(::GetVolumePathNameW(path.c_str(), volumePathName, ARRAYSIZE(volumePathName)), "Path:%ls", path.c_str()); + THROW_IF_WIN32_BOOL_FALSE_MSG(::GetVolumePathNameW(packageStorePath.c_str(), volumePathName, ARRAYSIZE(volumePathName)), "Path:%ls", packageStorePath.c_str()); GUID mediaId{}; const size_t c_volumeNameMaxLength{ 50 }; // "\\?\Volume{GUID}\" == 11 + 11111111-2222-3333-4444-555555555555 + 2 + null-terminator == 11 + 36 + 3 = 50 wchar_t volumeName[c_volumeNameMaxLength]{}; - THROW_IF_WIN32_BOOL_FALSE_MSG(::GetVolumeNameForVolumeMountPoint(volumePathName, volumeName, ARRAYSIZE(volumeName)), "Path:%ls VolumePathName:%ls", path.c_str(), volumePathName); + THROW_IF_WIN32_BOOL_FALSE_MSG(::GetVolumeNameForVolumeMountPoint(volumePathName, volumeName, ARRAYSIZE(volumeName)), "Path:%ls VolumePathName:%ls", packageStorePath.c_str(), volumePathName); const auto volumeNameLength{ wcslen(volumeName) }; - THROW_HR_IF_MSG(E_UNEXPECTED, volumeNameLength == 0, "Path:%ls VolumePathName:%ls", path.c_str(), volumePathName); + THROW_HR_IF_MSG(E_UNEXPECTED, volumeNameLength == 0, "Path:%ls VolumePathName:%ls", packageStorePath.c_str(), volumePathName); const auto offset{ volumeNameLength - 1 }; if (volumeName[offset] == L'\\') { diff --git a/dev/PackageManager/API/M.W.M.D.PackageVolume.h b/dev/PackageManager/API/M.W.M.D.PackageVolume.h index 5db1f47d55..7a4ba6893e 100644 --- a/dev/PackageManager/API/M.W.M.D.PackageVolume.h +++ b/dev/PackageManager/API/M.W.M.D.PackageVolume.h @@ -15,7 +15,7 @@ namespace winrt::Microsoft::Windows::Management::Deployment::implementation static bool IsFeatureSupported(winrt::Microsoft::Windows::Management::Deployment::PackageVolumeFeature feature); static winrt::Windows::Foundation::Collections::IVector FindPackageVolumes(); static winrt::Microsoft::Windows::Management::Deployment::PackageVolume FindPackageVolumeByPath(hstring const& packageStorePath); - static winrt::Microsoft::Windows::Management::Deployment::PackageVolume GetPackageVolumeByPath(hstring const& packageStorePath); + static winrt::Microsoft::Windows::Management::Deployment::PackageVolume GetPackageVolumeByPath(hstring const& path); static winrt::Microsoft::Windows::Management::Deployment::PackageVolume FindPackageVolumeByName(hstring const& name); static winrt::Microsoft::Windows::Management::Deployment::PackageVolume GetPackageVolumeByName(hstring const& name); static winrt::Microsoft::Windows::Management::Deployment::PackageVolume GetDefault(); diff --git a/dev/PackageManager/API/PackageManager.idl b/dev/PackageManager/API/PackageManager.idl index f138eeab3d..148b681d5e 100644 --- a/dev/PackageManager/API/PackageManager.idl +++ b/dev/PackageManager/API/PackageManager.idl @@ -107,6 +107,11 @@ namespace Microsoft.Windows.Management.Deployment static IVector FindPackageVolumes(); /// Get the specified volume. + /// @param packageStorePath a path on the volume e.g. "F:", "F:\Foo\Bar", "\\?\Volume{dd992d3d-8505-4adb-a622-82cdc2398a29}\" + /// and "\\?\Volume{dd992d3d-8505-4adb-a622-82cdc2398a29}\Foo\Bar" are equally valid. + /// @note The packageStorePath parameter is used to identify the device Volume. + /// The actual path for packages in a PackageVolume is defined by Windows. + /// @return the volume or null if not found. /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagemanager.findpackagevolume /// @see GetPackageVolumeByPath() /// @@ -115,11 +120,15 @@ namespace Microsoft.Windows.Management.Deployment static PackageVolume FindPackageVolumeByPath(String packageStorePath); /// Get the specified volume. + /// @param path a path on the volume e.g. "F:", "F:\Foo\Bar", "\\?\Volume{dd992d3d-8505-4adb-a622-82cdc2398a29}\" + /// and "\\?\Volume{dd992d3d-8505-4adb-a622-82cdc2398a29}\Foo\Bar" are equally valid. + /// @note The path parameter is used to identify the device Volume. + /// The actual path for packages in a PackageVolume is defined by Windows. /// @return the volume or null if not found. /// @see GetPackageVolumeByName() /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagemanager.findpackagevolume [contract(PackageDeploymentContract, 3)] - static PackageVolume GetPackageVolumeByPath(String packageStorePath); + static PackageVolume GetPackageVolumeByPath(String path); /// Get the specified volume. /// @name The volume media ID (a GUID value) @@ -137,28 +146,35 @@ namespace Microsoft.Windows.Management.Deployment [contract(PackageDeploymentContract, 3)] static PackageVolume GetPackageVolumeByName(String name); + /// Return true if the package volume is an internal system volume mapped to the %SYSTEMDRIVER% environment variable. /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagevolume.issystemvolume Boolean IsSystemVolume{ get; }; + /// Get the path of the last known mount point for the package volume. /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagevolume.mountpoint String MountPoint{ get; }; + /// Get the media ID of the package volume. /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagevolume.name String Name{ get; }; + /// Get the absolute path for the Package store on the volume. /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagevolume.packagestorepath String PackageStorePath{ get; }; + /// Return true if the package volume supports the creation of hard links in its file system. /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagevolume.supportshardlinks Boolean SupportsHardLinks{ get; }; + /// Return true if APPX installing is supported. /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagevolume.isappxinstallsupported Boolean IsAppxInstallSupported{ get; }; + /// Return true if full-trust packages are supported. /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagevolume.isfulltrustpackagesupported Boolean IsFullTrustPackageSupported{ get; }; - /// Return the default package volume. + /// Return true if the package volume is in an offline state. /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagevolume.isoffline [contract(PackageDeploymentContract, 3)] Boolean IsOffline(); From ef6d8a8f663929973c29aad684d92d045dd4a4d9 Mon Sep 17 00:00:00 2001 From: Howard Kapustein Date: Tue, 23 Dec 2025 23:29:30 -0800 Subject: [PATCH 09/10] Updated .idl (corrected syntax typos/bugs, updated doc-comments) --- specs/packagemanager/PackageManagement.md | 237 +++++++++++----------- 1 file changed, 117 insertions(+), 120 deletions(-) diff --git a/specs/packagemanager/PackageManagement.md b/specs/packagemanager/PackageManagement.md index b8e4cb541b..6c62addcaa 100644 --- a/specs/packagemanager/PackageManagement.md +++ b/specs/packagemanager/PackageManagement.md @@ -940,7 +940,7 @@ if (options.IsLimitToExistingPackagesSupported) ```c# (but really MIDL3) namespace Microsoft.Windows.Management.Deployment { - [contractversion(2)] + [contractversion(3)] apicontract PackageDeploymentContract{}; /// Represents a package storage volume. @@ -957,40 +957,127 @@ namespace Microsoft.Windows.Management.Deployment static IVector FindPackageVolumes(); /// Get the specified volume. + /// @param packageStorePath a path on the volume e.g. "F:", "F:\Foo\Bar", "\\?\Volume{dd992d3d-8505-4adb-a622-82cdc2398a29}\" + /// and "\\?\Volume{dd992d3d-8505-4adb-a622-82cdc2398a29}\Foo\Bar" are equally valid. + /// @note The packageStorePath parameter is used to identify the device Volume. + /// The actual path for packages in a PackageVolume is defined by Windows. + /// @return the volume or null if not found. /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagemanager.findpackagevolume + /// @see GetPackageVolumeByPath() + /// + /// @note This API is deprecated and will be removed in a future release. + /// Use GetPackageVolumeByPath(). static PackageVolume FindPackageVolumeByPath(String packageStorePath); + /// Get the specified volume. + /// @param path a path on the volume e.g. "F:", "F:\Foo\Bar", "\\?\Volume{dd992d3d-8505-4adb-a622-82cdc2398a29}\" + /// and "\\?\Volume{dd992d3d-8505-4adb-a622-82cdc2398a29}\Foo\Bar" are equally valid. + /// @note The path parameter is used to identify the device Volume. + /// The actual path for packages in a PackageVolume is defined by Windows. + /// @return the volume or null if not found. + /// @see GetPackageVolumeByName() + /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagemanager.findpackagevolume + [contract(PackageDeploymentContract, 3)] + static PackageVolume GetPackageVolumeByPath(String path); + /// Get the specified volume. /// @name The volume media ID (a GUID value) + /// @see GetPackageVolumeByName() /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagemanager.findpackagevolume + /// + /// @note This API is deprecated and will be removed in a future release. + /// Use GetPackageVolumeByName(). static PackageVolume FindPackageVolumeByName(String name); + /// Get the specified volume. + /// @name The volume media ID (a GUID value) + /// @see GetPackageVolumeByPath() + /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagemanager.findpackagevolume + [contract(PackageDeploymentContract, 3)] + static PackageVolume GetPackageVolumeByName(String name); + + /// Return true if the package volume is an internal system volume mapped to the %SYSTEMDRIVER% environment variable. /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagevolume.issystemvolume Boolean IsSystemVolume{ get; }; + /// Get the path of the last known mount point for the package volume. /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagevolume.mountpoint String MountPoint{ get; }; + /// Get the media ID of the package volume. /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagevolume.name String Name{ get; }; + /// Get the absolute path for the Package store on the volume. /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagevolume.packagestorepath String PackageStorePath{ get; }; + /// Return true if the package volume supports the creation of hard links in its file system. /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagevolume.supportshardlinks Boolean SupportsHardLinks{ get; }; + /// Return true if APPX installing is supported. + /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagevolume.isappxinstallsupported + Boolean IsAppxInstallSupported{ get; }; + + /// Return true if full-trust packages are supported. /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagevolume.isfulltrustpackagesupported Boolean IsFullTrustPackageSupported{ get; }; - /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagevolume.isappxinstallsupported - Boolean IsAppxInstallSupported{ get; }; + /// Return true if the package volume is in an offline state. + /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagevolume.isoffline + [contract(PackageDeploymentContract, 3)] + Boolean IsOffline(); /// Return true if the package volume is damaged and needs to be repaired. Boolean IsRepairNeeded(); /// Repair the package volume (if necessary). void Repair(); + + [contract(PackageDeploymentContract, 3)] + static Boolean IsFeatureSupported(PackageVolumeFeature feature); + + /// Return the default package volume. + /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagemanager.getdefaultpackagevolume + [contract(PackageDeploymentContract, 3)] + static PackageVolume GetDefault(); + + /// Set the default package volume. + /// @see //learn.microsoft.com/uwp/api/windows.management.deployment.packagemanager.setdefaultpackagevolume + [contract(PackageDeploymentContract, 3)] + void SetDefault(); + + /// Create a new package volume. + /// @param packageStorePath The absolute path of the Package store. + /// @note This requires admin privilege. + /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagemanager.addpackagevolumeasync + [contract(PackageDeploymentContract, 3)] + static Windows.Foundation.IAsyncOperation AddAsync(String packageStorePath); + + /// @note The caller must be running with Medium IL (or higher) + /// OR running in an AppContainer with the packageManagement restricted capability + /// OR caller has package identity and the publisher matches the publisher of the volume being removed. + /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagemanager.removepackagevolumeasync + [contract(PackageDeploymentContract, 3)] + Windows.Foundation.IAsyncOperationWithProgress RemoveAsync(); + + /// Set the package volume to an offline state. + /// @note This requires admin privilege. + /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagemanager.setpackagevolumeofflineasync + [contract(PackageDeploymentContract, 3)] + Windows.Foundation.IAsyncOperationWithProgress SetOfflineAsync(); + + /// Set the package volume to an online state. + /// @note This requires admin privilege. + /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.packagemanager.setpackagevolumeonlineasync + [contract(PackageDeploymentContract, 3)] + Windows.Foundation.IAsyncOperationWithProgress SetOnlineAsync(); + + /// Get the available space (bytes). + /// @see https://learn.microsoft.com/en-us/uwp/api/windows.management.deployment.packagevolume.getavailablespaceasync?view=winrt-26100 + [contract(PackageDeploymentContract, 3)] + Windows.Foundation.IAsyncOperation GetAvailableSpaceAsync(); }; /// Defines the stub behavior for an app package that is being added or staged. @@ -1013,99 +1100,6 @@ namespace Microsoft.Windows.Management.Deployment NewerAvailable = 2, }; - [contract(PackageDeploymentContract, 3)] - runtimeclass PackageValidationEventArgs - { - Windows.Foundation.Uri PackageUri{ get; }; - IInspectable AppxPackagingObject{ get; }; - Boolean Cancel; - - Windows.Foundation.Deferral GetDeferral(); - } - - [contract(PackageDeploymentContract, 3)] - runtimeclass PackageValidationEventSource - { - event Windows.Foundation.TypedEventHandler ValidationRequested; - } - - [contract(PackageDeploymentContract, 3)] - runtimeclass PackageFamilyNameValidator - { - PackageFamilyNameValidator(String packageUri, String expectedPackageFamilyName); - Windows.Foundation.TypedEventHandler Handler{ get; }; - } - - [contract(PackageDeploymentContract, 3)] - runtimeclass PackageMinimumVersionValidator - { - PackageMinimumVersionValidator(Windows.ApplicationModel.PackageVersion minimumVersion); - Windows.Foundation.TypedEventHandler Handler{ get; }; - } - - [contract(PackageDeploymentContract, 3)] - runtimeclass PackageCertificateEkuValidator - { - PackageCertificateEkuValidator(String expectedCertificateEku); - Windows.Foundation.TypedEventHandler Handler{ get; }; - } - - /// The progress status of the deployment request. - /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.deploymentprogress.state - [contract(PackageDeploymentContract, 1)] - enum PackageDeploymentProgressStatus - { - Queued = 0, // The request is queued - InProgress = 1, // The request is in progress - CompletedSuccess = 2, // The request completed successfully - CompletedFailure = 3, // The request failed with some critical internal error. - }; - - /// Contains progress information for the deployment request. - /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.deploymentprogress - [contract(PackageDeploymentContract, 1)] - struct PackageDeploymentProgress - { - PackageDeploymentProgressStatus Status; - - /// The progress percentage of the deployment request. - /// @note This is a double with values 0.0-1.0. Windows.Management.Deployment.DeploymentProgress.percentage is uint32 with values 0-100. - Double Progress; - }; - - /// The status of the deployment request. - /// @see PackageDeploymentResult.Status - [contract(PackageDeploymentContract, 1)] - enum PackageDeploymentStatus - { - InProgress = 0, // The request is in progress - CompletedSuccess = 1, // The request completed successfully - CompletedFailure = 2, // The request failed with some critical internal error. - }; - - /// Provides the result of a deployment request. - /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.deploymentresult - [contract(PackageDeploymentContract, 1)] - runtimeclass PackageDeploymentResult - { - PackageDeploymentStatus Status { get; }; - - /// The extended error code can be used to distinguish a specific error condition which needs to be handled differently from the general error indicated by the return code. The extended error code may provide a more specific reason for the failure that caused the general error. Also, it usually corresponds directly to the specific message in the ErrorText. - HRESULT Error { get; }; - - /// The extended error code can be used to distinguish a specific error condition which needs to be handled differently from the general error indicated by the return code. The extended error code may provide a more specific reason for the failure that caused the general error. Also, it usually corresponds directly to the specific message in the ErrorText. - /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.deploymentresult.extendederrorcode - HRESULT ExtendedError { get; }; - - /// Gets extended error text for the error if the deployment operation is not successful. - /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.deploymentresult.errortext - String ErrorText { get; }; - - /// Gets the activity identifier used to look up an event in Windows Event Viewer. Gets the activity identifier used to look up an event. All events of a deployment operation are logged with the same activityId. - /// @see https://learn.microsoft.com/uwp/api/windows.management.deployment.deploymentresult.activityid - Guid ActivityId { get; }; - } - [contract(PackageDeploymentContract, 1)] runtimeclass PackageSetItem { @@ -1157,15 +1151,6 @@ namespace Microsoft.Windows.Management.Deployment Boolean IsLimitToExistingPackagesSupported { get; }; // Requires Windows >= 10.0.22621.0 (aka Win11 22H2) Boolean LimitToExistingPackages; - - [contract(PackageDeploymentContract, 3)] - Boolean IsPackageValidationSupported{ get; }; - - [contract(PackageDeploymentContract, 3)] - IMapView PackageValidators{ get; }; - - [contract(PackageDeploymentContract, 3)] - PackageValidationEventSource GetValidationEventSourceForUri(Windows.Foundation.Uri uri); } // Requires Windows >= 10.0.19041.0 (aka 2004 aka 20H1) @@ -1190,15 +1175,6 @@ namespace Microsoft.Windows.Management.Deployment Boolean IsExpectedDigestsSupported { get; }; // Requires Windows >= 10.0.22621.0 (aka Win11 22H2) IMap ExpectedDigests{ get; }; - - [contract(PackageDeploymentContract, 3)] - Boolean IsPackageValidationSupported{ get; }; - - [contract(PackageDeploymentContract, 3)] - IMapView PackageValidators{ get; }; - - [contract(PackageDeploymentContract, 3)] - PackageValidationEventSource GetValidationEventSourceForUri(Windows.Foundation.Uri uri); } // Requires Windows >= 10.0.19041.0 (aka 2004 aka 20H1) @@ -1256,7 +1232,7 @@ namespace Microsoft.Windows.Management.Deployment AddPackageOptions AddPackageOptions { get; }; - [contractversion(2)] + [contract(PackageDeploymentContract, 2)] Boolean RegisterNewerIfAvailable; } @@ -1266,6 +1242,12 @@ namespace Microsoft.Windows.Management.Deployment // Get an instance of the manager static PackageDeploymentManager GetDefault(); + //------------------------------------------------------------- + // IsPackageDeploymentFeatureSupported + + [contract(PackageDeploymentContract, 2)] + static Boolean IsPackageDeploymentFeatureSupported(PackageDeploymentFeature feature); + //------------------------------------------------------------- // IsReady @@ -1275,6 +1257,7 @@ namespace Microsoft.Windows.Management.Deployment Boolean IsPackageReadyByUri(Windows.Foundation.Uri packageUri); + /// @note packageSet[Item].PackageUri is optional Boolean IsPackageSetReady(PackageSet packageSet); //------------------------------------------------------------- @@ -1282,13 +1265,14 @@ namespace Microsoft.Windows.Management.Deployment // Return true if the package(s) are present and available for use - [contractversion(2)] + [contract(PackageDeploymentContract, 2)] PackageReadyOrNewerAvailableStatus IsPackageReadyOrNewerAvailable(String package); - [contractversion(2)] + [contract(PackageDeploymentContract, 2)] PackageReadyOrNewerAvailableStatus IsPackageReadyOrNewerAvailableByUri(Windows.Foundation.Uri packageUri); - [contractversion(2)] + /// @note packageSet[Item].PackageUri is optional + [contract(PackageDeploymentContract, 2)] PackageReadyOrNewerAvailableStatus IsPackageSetReadyOrNewerAvailable(PackageSet packageSet); //------------------------------------------------------------- @@ -1306,6 +1290,7 @@ namespace Microsoft.Windows.Management.Deployment Windows.Foundation.IAsyncOperationWithProgress EnsurePackageReadyByUriAsync(Windows.Foundation.Uri packageUri, EnsureReadyOptions options); + /// @note packageSet[Item].PackageUri is required Windows.Foundation.IAsyncOperationWithProgress EnsurePackageSetReadyAsync(PackageSet packageSet, EnsureReadyOptions options); @@ -1318,6 +1303,7 @@ namespace Microsoft.Windows.Management.Deployment Windows.Foundation.IAsyncOperationWithProgress AddPackageByUriAsync(Windows.Foundation.Uri packageUri, AddPackageOptions options); + /// @note packageSet[Item].PackageUri is required Windows.Foundation.IAsyncOperationWithProgress AddPackageSetAsync(PackageSet packageSet, AddPackageOptions options); @@ -1330,6 +1316,7 @@ namespace Microsoft.Windows.Management.Deployment Windows.Foundation.IAsyncOperationWithProgress StagePackageByUriAsync(Windows.Foundation.Uri packageUri, StagePackageOptions options); + /// @note packageSet[Item].PackageUri is required Windows.Foundation.IAsyncOperationWithProgress StagePackageSetAsync(PackageSet packageSet, StagePackageOptions options); @@ -1342,6 +1329,7 @@ namespace Microsoft.Windows.Management.Deployment Windows.Foundation.IAsyncOperationWithProgress RegisterPackageByUriAsync(Windows.Foundation.Uri packageUri, RegisterPackageOptions options); + /// @note packageSet[Item].PackageUri is optional Windows.Foundation.IAsyncOperationWithProgress RegisterPackageSetAsync(PackageSet packageSet, RegisterPackageOptions options); @@ -1360,6 +1348,7 @@ namespace Microsoft.Windows.Management.Deployment Windows.Foundation.IAsyncOperationWithProgress RemovePackageByUriAsync(Windows.Foundation.Uri packageUri, RemovePackageOptions options); + /// @note packageSet[Item].PackageUri is optional Windows.Foundation.IAsyncOperationWithProgress RemovePackageSetAsync(PackageSet packageSet, RemovePackageOptions options); @@ -1372,6 +1361,7 @@ namespace Microsoft.Windows.Management.Deployment Windows.Foundation.IAsyncOperationWithProgress ResetPackageByUriAsync(Windows.Foundation.Uri packageUri); + /// @note packageSet[Item].PackageUri is optional Windows.Foundation.IAsyncOperationWithProgress ResetPackageSetAsync(PackageSet packageSet); @@ -1384,6 +1374,7 @@ namespace Microsoft.Windows.Management.Deployment Windows.Foundation.IAsyncOperationWithProgress RepairPackageByUriAsync(Windows.Foundation.Uri packageUri); + /// @note packageSet[Item].PackageUri is optional Windows.Foundation.IAsyncOperationWithProgress RepairPackageSetAsync(PackageSet packageSet); @@ -1411,6 +1402,7 @@ namespace Microsoft.Windows.Management.Deployment Windows.Foundation.IAsyncOperationWithProgress ProvisionPackageByUriAsync(Windows.Foundation.Uri packageUri, ProvisionPackageOptions options); + /// @note packageSet[Item].PackageUri is optional Windows.Foundation.IAsyncOperationWithProgress ProvisionPackageSetAsync(PackageSet packageSet, ProvisionPackageOptions options); @@ -1423,15 +1415,20 @@ namespace Microsoft.Windows.Management.Deployment Windows.Foundation.IAsyncOperationWithProgress DeprovisionPackageByUriAsync(Windows.Foundation.Uri packageUri); + /// @note packageSet[Item].PackageUri is optional Windows.Foundation.IAsyncOperationWithProgress DeprovisionPackageSetAsync(PackageSet packageSet); //------------------------------------------------------------- // IsRegistrationPending - Boolean IsPackageRegistrationPending(String packageFullName); + /// @warning The parameter is should be "packageFullName" but can't due to http://task.ms/53280356. + /// Consider the current (wrong) parameter name deprecated until vFuture (2.0) when we can change to the new (right) parameter name. + Boolean IsPackageRegistrationPending(String packageFamilyName); - Boolean IsPackageRegistrationPendingForUser(String userSecurityId, String packageFullName); + /// @warning The parameter is should be "packageFullName" but can't due to http://task.ms/53280356. + /// Consider the current (wrong) parameter name deprecated until vFuture (2.0) when we can change to the new (right) parameter name. + Boolean IsPackageRegistrationPendingForUser(String userSecurityId, String packageFamilyName); } [contract(PackageDeploymentContract, 1)] From aed51e8d882c58b32ff718bd29fc34d2342b6723 Mon Sep 17 00:00:00 2001 From: Howard Kapustein Date: Wed, 24 Dec 2025 16:10:44 -0800 Subject: [PATCH 10/10] Fixed bad merge --- dev/PackageManager/API/PackageManager.idl | 13 +++-- specs/packagemanager/PackageManagement.md | 68 +++++++++++++++++++++-- 2 files changed, 71 insertions(+), 10 deletions(-) diff --git a/dev/PackageManager/API/PackageManager.idl b/dev/PackageManager/API/PackageManager.idl index 148b681d5e..e1bd689dd5 100644 --- a/dev/PackageManager/API/PackageManager.idl +++ b/dev/PackageManager/API/PackageManager.idl @@ -402,11 +402,12 @@ namespace Microsoft.Windows.Management.Deployment // IsReady // Return true if the package(s) are present and available for use - Boolean IsPackageReady(String package); + // Return true if the package(s) are present and available for use Boolean IsPackageReadyByUri(Windows.Foundation.Uri packageUri); + // Return true if the package(s) are present and available for use /// @note packageSet[Item].PackageUri is optional Boolean IsPackageSetReady(PackageSet packageSet); @@ -414,13 +415,14 @@ namespace Microsoft.Windows.Management.Deployment // IsReadyOrNewerAvailable // Return true if the package(s) are present and available for use - [contract(PackageDeploymentContract, 2)] PackageReadyOrNewerAvailableStatus IsPackageReadyOrNewerAvailable(String package); + // Return true if the package(s) are present and available for use [contract(PackageDeploymentContract, 2)] PackageReadyOrNewerAvailableStatus IsPackageReadyOrNewerAvailableByUri(Windows.Foundation.Uri packageUri); + // Return true if the package(s) are present and available for use /// @note packageSet[Item].PackageUri is optional [contract(PackageDeploymentContract, 2)] PackageReadyOrNewerAvailableStatus IsPackageSetReadyOrNewerAvailable(PackageSet packageSet); @@ -532,13 +534,14 @@ namespace Microsoft.Windows.Management.Deployment // IsProvisioned // Return true if the package(s) are provisioned - [contract(PackageDeploymentContract, 2)] Boolean IsPackageProvisioned(String package); + // Return true if the package(s) are provisioned [contract(PackageDeploymentContract, 2)] Boolean IsPackageProvisionedByUri(Windows.Foundation.Uri packageUri); + // Return true if the package(s) are provisioned /// @note packageSet[Item].PackageUri is optional [contract(PackageDeploymentContract, 2)] Boolean IsPackageSetProvisioned(PackageSet packageSet); @@ -572,11 +575,11 @@ namespace Microsoft.Windows.Management.Deployment //------------------------------------------------------------- // IsRegistrationPending - /// @warning The parameter is should be "packageFullName" but can't due to http://task.ms/53280356. + /// @warning The parameter should be "packageFullName" but can't due to http://task.ms/53280356. /// Consider the current (wrong) parameter name deprecated until vFuture (2.0) when we can change to the new (right) parameter name. Boolean IsPackageRegistrationPending(String packageFamilyName); - /// @warning The parameter is should be "packageFullName" but can't due to http://task.ms/53280356. + /// @warning The parameter should be "packageFullName" but can't due to http://task.ms/53280356. /// Consider the current (wrong) parameter name deprecated until vFuture (2.0) when we can change to the new (right) parameter name. Boolean IsPackageRegistrationPendingForUser(String userSecurityId, String packageFamilyName); } diff --git a/specs/packagemanager/PackageManagement.md b/specs/packagemanager/PackageManagement.md index 6c62addcaa..e689345b88 100644 --- a/specs/packagemanager/PackageManagement.md +++ b/specs/packagemanager/PackageManagement.md @@ -1100,6 +1100,43 @@ namespace Microsoft.Windows.Management.Deployment NewerAvailable = 2, }; + [contract(PackageDeploymentContract, 3)] + runtimeclass PackageValidationEventArgs + { + Windows.Foundation.Uri PackageUri{ get; }; + IInspectable AppxPackagingObject{ get; }; + Boolean Cancel; + + Windows.Foundation.Deferral GetDeferral(); + } + + [contract(PackageDeploymentContract, 3)] + runtimeclass PackageValidationEventSource + { + event Windows.Foundation.TypedEventHandler ValidationRequested; + } + + [contract(PackageDeploymentContract, 3)] + runtimeclass PackageFamilyNameValidator + { + PackageFamilyNameValidator(String packageUri, String expectedPackageFamilyName); + Windows.Foundation.TypedEventHandler Handler{ get; }; + } + + [contract(PackageDeploymentContract, 3)] + runtimeclass PackageMinimumVersionValidator + { + PackageMinimumVersionValidator(Windows.ApplicationModel.PackageVersion minimumVersion); + Windows.Foundation.TypedEventHandler Handler{ get; }; + } + + [contract(PackageDeploymentContract, 3)] + runtimeclass PackageCertificateEkuValidator + { + PackageCertificateEkuValidator(String expectedCertificateEku); + Windows.Foundation.TypedEventHandler Handler{ get; }; + } + [contract(PackageDeploymentContract, 1)] runtimeclass PackageSetItem { @@ -1151,6 +1188,15 @@ namespace Microsoft.Windows.Management.Deployment Boolean IsLimitToExistingPackagesSupported { get; }; // Requires Windows >= 10.0.22621.0 (aka Win11 22H2) Boolean LimitToExistingPackages; + + [contract(PackageDeploymentContract, 3)] + Boolean IsPackageValidationSupported{ get; }; + + [contract(PackageDeploymentContract, 3)] + IMapView PackageValidators{ get; }; + + [contract(PackageDeploymentContract, 3)] + PackageValidationEventSource GetValidationEventSourceForUri(Windows.Foundation.Uri uri); } // Requires Windows >= 10.0.19041.0 (aka 2004 aka 20H1) @@ -1175,6 +1221,15 @@ namespace Microsoft.Windows.Management.Deployment Boolean IsExpectedDigestsSupported { get; }; // Requires Windows >= 10.0.22621.0 (aka Win11 22H2) IMap ExpectedDigests{ get; }; + + [contract(PackageDeploymentContract, 3)] + Boolean IsPackageValidationSupported{ get; }; + + [contract(PackageDeploymentContract, 3)] + IMapView PackageValidators{ get; }; + + [contract(PackageDeploymentContract, 3)] + PackageValidationEventSource GetValidationEventSourceForUri(Windows.Foundation.Uri uri); } // Requires Windows >= 10.0.19041.0 (aka 2004 aka 20H1) @@ -1252,11 +1307,12 @@ namespace Microsoft.Windows.Management.Deployment // IsReady // Return true if the package(s) are present and available for use - Boolean IsPackageReady(String package); + // Return true if the package(s) are present and available for use Boolean IsPackageReadyByUri(Windows.Foundation.Uri packageUri); + // Return true if the package(s) are present and available for use /// @note packageSet[Item].PackageUri is optional Boolean IsPackageSetReady(PackageSet packageSet); @@ -1264,13 +1320,14 @@ namespace Microsoft.Windows.Management.Deployment // IsReadyOrNewerAvailable // Return true if the package(s) are present and available for use - [contract(PackageDeploymentContract, 2)] PackageReadyOrNewerAvailableStatus IsPackageReadyOrNewerAvailable(String package); + // Return true if the package(s) are present and available for use [contract(PackageDeploymentContract, 2)] PackageReadyOrNewerAvailableStatus IsPackageReadyOrNewerAvailableByUri(Windows.Foundation.Uri packageUri); + // Return true if the package(s) are present and available for use /// @note packageSet[Item].PackageUri is optional [contract(PackageDeploymentContract, 2)] PackageReadyOrNewerAvailableStatus IsPackageSetReadyOrNewerAvailable(PackageSet packageSet); @@ -1382,13 +1439,14 @@ namespace Microsoft.Windows.Management.Deployment // IsProvisioned // Return true if the package(s) are provisioned - [contract(PackageDeploymentContract, 2)] Boolean IsPackageProvisioned(String package); + // Return true if the package(s) are provisioned [contract(PackageDeploymentContract, 2)] Boolean IsPackageProvisionedByUri(Windows.Foundation.Uri packageUri); + // Return true if the package(s) are provisioned /// @note packageSet[Item].PackageUri is optional [contract(PackageDeploymentContract, 2)] Boolean IsPackageSetProvisioned(PackageSet packageSet); @@ -1422,11 +1480,11 @@ namespace Microsoft.Windows.Management.Deployment //------------------------------------------------------------- // IsRegistrationPending - /// @warning The parameter is should be "packageFullName" but can't due to http://task.ms/53280356. + /// @warning The parameter should be "packageFullName" but can't due to http://task.ms/53280356. /// Consider the current (wrong) parameter name deprecated until vFuture (2.0) when we can change to the new (right) parameter name. Boolean IsPackageRegistrationPending(String packageFamilyName); - /// @warning The parameter is should be "packageFullName" but can't due to http://task.ms/53280356. + /// @warning The parameter should be "packageFullName" but can't due to http://task.ms/53280356. /// Consider the current (wrong) parameter name deprecated until vFuture (2.0) when we can change to the new (right) parameter name. Boolean IsPackageRegistrationPendingForUser(String userSecurityId, String packageFamilyName); }