diff --git a/samples/WinGetUWPCaller/WinGetUWPCaller.sln b/samples/WinGetUWPCaller/WinGetUWPCaller.sln new file mode 100644 index 0000000000..16cbf3a6c8 --- /dev/null +++ b/samples/WinGetUWPCaller/WinGetUWPCaller.sln @@ -0,0 +1,43 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30704.19 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WinGetUWPCaller", "WinGetUWPCaller\WinGetUWPCaller.vcxproj", "{37F1FD2A-4D63-45A0-82AA-66EF126CB322}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|ARM64 = Debug|ARM64 + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|ARM64 = Release|ARM64 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {37F1FD2A-4D63-45A0-82AA-66EF126CB322}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {37F1FD2A-4D63-45A0-82AA-66EF126CB322}.Debug|ARM64.Build.0 = Debug|ARM64 + {37F1FD2A-4D63-45A0-82AA-66EF126CB322}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {37F1FD2A-4D63-45A0-82AA-66EF126CB322}.Debug|x64.ActiveCfg = Debug|x64 + {37F1FD2A-4D63-45A0-82AA-66EF126CB322}.Debug|x64.Build.0 = Debug|x64 + {37F1FD2A-4D63-45A0-82AA-66EF126CB322}.Debug|x64.Deploy.0 = Debug|x64 + {37F1FD2A-4D63-45A0-82AA-66EF126CB322}.Debug|x86.ActiveCfg = Debug|Win32 + {37F1FD2A-4D63-45A0-82AA-66EF126CB322}.Debug|x86.Build.0 = Debug|Win32 + {37F1FD2A-4D63-45A0-82AA-66EF126CB322}.Debug|x86.Deploy.0 = Debug|Win32 + {37F1FD2A-4D63-45A0-82AA-66EF126CB322}.Release|ARM64.ActiveCfg = Release|ARM64 + {37F1FD2A-4D63-45A0-82AA-66EF126CB322}.Release|ARM64.Build.0 = Release|ARM64 + {37F1FD2A-4D63-45A0-82AA-66EF126CB322}.Release|ARM64.Deploy.0 = Release|ARM64 + {37F1FD2A-4D63-45A0-82AA-66EF126CB322}.Release|x64.ActiveCfg = Release|x64 + {37F1FD2A-4D63-45A0-82AA-66EF126CB322}.Release|x64.Build.0 = Release|x64 + {37F1FD2A-4D63-45A0-82AA-66EF126CB322}.Release|x64.Deploy.0 = Release|x64 + {37F1FD2A-4D63-45A0-82AA-66EF126CB322}.Release|x86.ActiveCfg = Release|Win32 + {37F1FD2A-4D63-45A0-82AA-66EF126CB322}.Release|x86.Build.0 = Release|Win32 + {37F1FD2A-4D63-45A0-82AA-66EF126CB322}.Release|x86.Deploy.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {D7D1DE2E-A7C1-4FB3-A191-C848562A3EBD} + EndGlobalSection +EndGlobal diff --git a/samples/WinGetUWPCaller/WinGetUWPCaller/ActivePackageView.cpp b/samples/WinGetUWPCaller/WinGetUWPCaller/ActivePackageView.cpp new file mode 100644 index 0000000000..aff6c3a8aa --- /dev/null +++ b/samples/WinGetUWPCaller/WinGetUWPCaller/ActivePackageView.cpp @@ -0,0 +1,87 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#include "pch.h" +#include "ActivePackageView.h" +#include "ActivePackageView.g.cpp" +#include + +namespace winrt::WinGetUWPCaller::implementation +{ + Microsoft::Management::Deployment::CatalogPackage ActivePackageView::Package() + { + return m_package; + } + + void ActivePackageView::Package(Microsoft::Management::Deployment::CatalogPackage const& value) + { + m_package = value; + } + + ActivePackageView::AsyncOperation_t ActivePackageView::AsyncOperation() + { + return m_asyncOperation; + } + + Windows::Foundation::IAsyncAction UpdateUIProgress( + Microsoft::Management::Deployment::InstallProgress progress, + WinGetUWPCaller::ActivePackageView view) + { + co_await resume_foreground(view.Dispatcher()); + view.Progress(progress.DownloadProgress * 100); + } + + void ActivePackageView::AsyncOperation(ActivePackageView::AsyncOperation_t const& value) + { + m_asyncOperation = value; + m_asyncOperation.Progress([=]( + ActivePackageView::AsyncOperation_t const& /* sender */, + Microsoft::Management::Deployment::InstallProgress const& progress) + { + UpdateUIProgress(progress, *this); + }); + } + + double ActivePackageView::Progress() + { + return m_progress; + } + + void ActivePackageView::Progress(double value) + { + if (m_progress != value) + { + m_progress = value; + m_propertyChanged(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"Progress" }); + } + } + + hstring ActivePackageView::StatusText() + { + return m_text; + } + + void ActivePackageView::StatusText(hstring const& value) + { + m_text = value; + } + + Windows::UI::Core::CoreDispatcher ActivePackageView::Dispatcher() + { + return m_dispatcher; + } + + void ActivePackageView::Dispatcher(Windows::UI::Core::CoreDispatcher const& value) + { + m_dispatcher = value; + } + + event_token ActivePackageView::PropertyChanged(Windows::UI::Xaml::Data::PropertyChangedEventHandler const& handler) + { + return m_propertyChanged.add(handler); + } + + void ActivePackageView::PropertyChanged(event_token const& token) + { + m_propertyChanged.remove(token); + } +} diff --git a/samples/WinGetUWPCaller/WinGetUWPCaller/ActivePackageView.h b/samples/WinGetUWPCaller/WinGetUWPCaller/ActivePackageView.h new file mode 100644 index 0000000000..b9cdfeeed7 --- /dev/null +++ b/samples/WinGetUWPCaller/WinGetUWPCaller/ActivePackageView.h @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#pragma once +#include "ActivePackageView.g.h" + +namespace winrt::WinGetUWPCaller::implementation +{ + struct ActivePackageView : ActivePackageViewT + { + using AsyncOperation_t = Windows::Foundation::IAsyncOperationWithProgress; + + ActivePackageView() = default; + + Microsoft::Management::Deployment::CatalogPackage Package(); + void Package(Microsoft::Management::Deployment::CatalogPackage const& value); + AsyncOperation_t AsyncOperation(); + void AsyncOperation(AsyncOperation_t const& value); + double Progress(); + void Progress(double value); + hstring StatusText(); + void StatusText(hstring const& value); + Windows::UI::Core::CoreDispatcher Dispatcher(); + void Dispatcher(Windows::UI::Core::CoreDispatcher const& value); + event_token PropertyChanged(Windows::UI::Xaml::Data::PropertyChangedEventHandler const& value); + void PropertyChanged(event_token const& token); + + private: + Microsoft::Management::Deployment::CatalogPackage m_package{ nullptr }; + AsyncOperation_t m_asyncOperation{ nullptr }; + double m_progress = 0; + hstring m_text; + Windows::UI::Core::CoreDispatcher m_dispatcher{ nullptr }; + event m_propertyChanged; + }; +} + +namespace winrt::WinGetUWPCaller::factory_implementation +{ + struct ActivePackageView : ActivePackageViewT + { + }; +} diff --git a/samples/WinGetUWPCaller/WinGetUWPCaller/App.cpp b/samples/WinGetUWPCaller/WinGetUWPCaller/App.cpp new file mode 100644 index 0000000000..a9e9cbc1a2 --- /dev/null +++ b/samples/WinGetUWPCaller/WinGetUWPCaller/App.cpp @@ -0,0 +1,121 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#include "pch.h" + +#include "App.h" +#include "MainPage.h" + +using namespace winrt; +using namespace Windows::ApplicationModel; +using namespace Windows::ApplicationModel::Activation; +using namespace Windows::Foundation; +using namespace Windows::UI::Xaml; +using namespace Windows::UI::Xaml::Controls; +using namespace Windows::UI::Xaml::Navigation; +using namespace WinGetUWPCaller; +using namespace WinGetUWPCaller::implementation; + +/// +/// Initializes the singleton application object. This is the first line of authored code +/// executed, and as such is the logical equivalent of main() or WinMain(). +/// +App::App() +{ + InitializeComponent(); + Suspending({ this, &App::OnSuspending }); + +#if defined _DEBUG && !defined DISABLE_XAML_GENERATED_BREAK_ON_UNHANDLED_EXCEPTION + UnhandledException([this](IInspectable const&, UnhandledExceptionEventArgs const& e) + { + if (IsDebuggerPresent()) + { + auto errorMessage = e.Message(); + __debugbreak(); + } + }); +#endif +} + +/// +/// Invoked when the application is launched normally by the end user. Other entry points +/// will be used such as when the application is launched to open a specific file. +/// +/// Details about the launch request and process. +void App::OnLaunched(LaunchActivatedEventArgs const& e) +{ + Frame rootFrame{ nullptr }; + auto content = Window::Current().Content(); + if (content) + { + rootFrame = content.try_as(); + } + + // Do not repeat app initialization when the Window already has content, + // just ensure that the window is active + if (rootFrame == nullptr) + { + // Create a Frame to act as the navigation context and associate it with + // a SuspensionManager key + rootFrame = Frame(); + + rootFrame.NavigationFailed({ this, &App::OnNavigationFailed }); + + if (e.PreviousExecutionState() == ApplicationExecutionState::Terminated) + { + // Restore the saved session state only when appropriate, scheduling the + // final launch steps after the restore is complete + } + + if (e.PrelaunchActivated() == false) + { + if (rootFrame.Content() == nullptr) + { + // When the navigation stack isn't restored navigate to the first page, + // configuring the new page by passing required information as a navigation + // parameter + rootFrame.Navigate(xaml_typename(), box_value(e.Arguments())); + } + // Place the frame in the current Window + Window::Current().Content(rootFrame); + // Ensure the current window is active + Window::Current().Activate(); + } + } + else + { + if (e.PrelaunchActivated() == false) + { + if (rootFrame.Content() == nullptr) + { + // When the navigation stack isn't restored navigate to the first page, + // configuring the new page by passing required information as a navigation + // parameter + rootFrame.Navigate(xaml_typename(), box_value(e.Arguments())); + } + // Ensure the current window is active + Window::Current().Activate(); + } + } +} + +/// +/// Invoked when application execution is being suspended. Application state is saved +/// without knowing whether the application will be terminated or resumed with the contents +/// of memory still intact. +/// +/// The source of the suspend request. +/// Details about the suspend request. +void App::OnSuspending([[maybe_unused]] IInspectable const& sender, [[maybe_unused]] SuspendingEventArgs const& e) +{ + // Save application state and stop any background activity +} + +/// +/// Invoked when Navigation to a certain page fails +/// +/// The Frame which failed navigation +/// Details about the navigation failure +void App::OnNavigationFailed(IInspectable const&, NavigationFailedEventArgs const& e) +{ + throw hresult_error(E_FAIL, hstring(L"Failed to load Page ") + e.SourcePageType().Name); +} diff --git a/samples/WinGetUWPCaller/WinGetUWPCaller/App.h b/samples/WinGetUWPCaller/WinGetUWPCaller/App.h new file mode 100644 index 0000000000..1f9fbf7704 --- /dev/null +++ b/samples/WinGetUWPCaller/WinGetUWPCaller/App.h @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#pragma once +#include "App.xaml.g.h" + +namespace winrt::WinGetUWPCaller::implementation +{ + struct App : AppT + { + App(); + + void OnLaunched(Windows::ApplicationModel::Activation::LaunchActivatedEventArgs const&); + void OnSuspending(IInspectable const&, Windows::ApplicationModel::SuspendingEventArgs const&); + void OnNavigationFailed(IInspectable const&, Windows::UI::Xaml::Navigation::NavigationFailedEventArgs const&); + }; +} diff --git a/samples/WinGetUWPCaller/WinGetUWPCaller/App.idl b/samples/WinGetUWPCaller/WinGetUWPCaller/App.idl new file mode 100644 index 0000000000..d42b0b33de --- /dev/null +++ b/samples/WinGetUWPCaller/WinGetUWPCaller/App.idl @@ -0,0 +1,3 @@ +namespace WinGetUWPCaller +{ +} diff --git a/samples/WinGetUWPCaller/WinGetUWPCaller/App.xaml b/samples/WinGetUWPCaller/WinGetUWPCaller/App.xaml new file mode 100644 index 0000000000..710944ef82 --- /dev/null +++ b/samples/WinGetUWPCaller/WinGetUWPCaller/App.xaml @@ -0,0 +1,9 @@ + + + + diff --git a/samples/WinGetUWPCaller/WinGetUWPCaller/Assets/LockScreenLogo.scale-200.png b/samples/WinGetUWPCaller/WinGetUWPCaller/Assets/LockScreenLogo.scale-200.png new file mode 100644 index 0000000000..3c5ba2c736 Binary files /dev/null and b/samples/WinGetUWPCaller/WinGetUWPCaller/Assets/LockScreenLogo.scale-200.png differ diff --git a/samples/WinGetUWPCaller/WinGetUWPCaller/Assets/SplashScreen.scale-200.png b/samples/WinGetUWPCaller/WinGetUWPCaller/Assets/SplashScreen.scale-200.png new file mode 100644 index 0000000000..23e8eeb811 Binary files /dev/null and b/samples/WinGetUWPCaller/WinGetUWPCaller/Assets/SplashScreen.scale-200.png differ diff --git a/samples/WinGetUWPCaller/WinGetUWPCaller/Assets/Square150x150Logo.scale-200.png b/samples/WinGetUWPCaller/WinGetUWPCaller/Assets/Square150x150Logo.scale-200.png new file mode 100644 index 0000000000..0ae664127b Binary files /dev/null and b/samples/WinGetUWPCaller/WinGetUWPCaller/Assets/Square150x150Logo.scale-200.png differ diff --git a/samples/WinGetUWPCaller/WinGetUWPCaller/Assets/Square44x44Logo.scale-200.png b/samples/WinGetUWPCaller/WinGetUWPCaller/Assets/Square44x44Logo.scale-200.png new file mode 100644 index 0000000000..f0357adbab Binary files /dev/null and b/samples/WinGetUWPCaller/WinGetUWPCaller/Assets/Square44x44Logo.scale-200.png differ diff --git a/samples/WinGetUWPCaller/WinGetUWPCaller/Assets/Square44x44Logo.targetsize-24_altform-unplated.png b/samples/WinGetUWPCaller/WinGetUWPCaller/Assets/Square44x44Logo.targetsize-24_altform-unplated.png new file mode 100644 index 0000000000..fa1edd468c Binary files /dev/null and b/samples/WinGetUWPCaller/WinGetUWPCaller/Assets/Square44x44Logo.targetsize-24_altform-unplated.png differ diff --git a/samples/WinGetUWPCaller/WinGetUWPCaller/Assets/StoreLogo.png b/samples/WinGetUWPCaller/WinGetUWPCaller/Assets/StoreLogo.png new file mode 100644 index 0000000000..5db65cb83f Binary files /dev/null and b/samples/WinGetUWPCaller/WinGetUWPCaller/Assets/StoreLogo.png differ diff --git a/samples/WinGetUWPCaller/WinGetUWPCaller/Assets/Wide310x150Logo.scale-200.png b/samples/WinGetUWPCaller/WinGetUWPCaller/Assets/Wide310x150Logo.scale-200.png new file mode 100644 index 0000000000..4d31be0494 Binary files /dev/null and b/samples/WinGetUWPCaller/WinGetUWPCaller/Assets/Wide310x150Logo.scale-200.png differ diff --git a/samples/WinGetUWPCaller/WinGetUWPCaller/MainPage.cpp b/samples/WinGetUWPCaller/WinGetUWPCaller/MainPage.cpp new file mode 100644 index 0000000000..37d7434448 --- /dev/null +++ b/samples/WinGetUWPCaller/WinGetUWPCaller/MainPage.cpp @@ -0,0 +1,951 @@ +#include "pch.h" +#include "MainPage.h" +#include "MainPage.g.cpp" + +#include + +using namespace std::chrono_literals; +using namespace std::string_view_literals; +using namespace winrt::Microsoft::Management::Deployment; + +namespace winrt +{ + using namespace Windows::UI::Xaml; + using namespace Windows::Foundation; + using namespace Windows::Foundation::Collections; +} + +namespace winrt::WinGetUWPCaller::implementation +{ + namespace + { + std::wstring ConvertExceptionToStatusString(std::wstring_view context, std::exception_ptr exceptionPtr) + { + std::wostringstream result; + + try + { + std::rethrow_exception(exceptionPtr); + } + catch (const winrt::hresult_error& error) + { + result << context << L" :: " << L"0x" << std::hex << std::setw(8) << std::setfill(L'0') << error.code() << L": " << static_cast(error.message()); + } + catch (const std::exception& exception) + { + result << context << L" :: " << exception.what(); + } + catch (...) + { + result << context << L" :: Unknown exception"; + } + + return std::move(result).str(); + } + + template + std::wstring RunAndReturnStatus(std::wstring_view context, Operation&& operation) + { + try + { + operation(); + } + catch (...) + { + return ConvertExceptionToStatusString(context, std::current_exception()); + } + + return {}; + } + + // Helper object to control button states and status text. + struct BackgroundActionData + { + // This object should be constructed on the foreground thread. + // disabledButtons will be disabled during the operation. + // enabledButtons will be enabled during the operation. + // statusText will be updated with the result. + BackgroundActionData( + std::initializer_list disabledButtons, + Windows::UI::Xaml::Controls::TextBlock statusText) : + m_disabledButtons(disabledButtons), + m_statusText(statusText) + { + if (m_disabledButtons.empty()) + { + throw std::exception("Must specify at least one disabled button."); + } + + for (const auto& button : m_disabledButtons) + { + button.IsEnabled(false); + } + + m_statusText.Text(L""); + } + + BackgroundActionData( + std::initializer_list disabledButtons, + std::initializer_list enabledButtons, + Windows::UI::Xaml::Controls::TextBlock statusText) : + BackgroundActionData(disabledButtons, statusText) + { + m_enabledButtons = enabledButtons; + for (const auto& button : m_enabledButtons) + { + button.IsEnabled(true); + } + } + + // This should be run on the foreground thread. + void Finalize() const + { + for (const auto& button : m_disabledButtons) + { + button.IsEnabled(true); + } + + for (const auto& button : m_enabledButtons) + { + button.IsEnabled(false); + } + + m_statusText.Text(m_status); + } + + template + void RunAndCatchStatus(std::wstring_view context, Operation&& operation) + { + if (m_status.empty()) + { + m_status = RunAndReturnStatus(context, operation); + } + } + + void Status(std::wstring&& value) + { + m_status = std::move(value); + } + + bool Successful() const + { + return m_status.empty(); + } + + Windows::UI::Core::CoreDispatcher Dispatcher() const + { + return m_disabledButtons[0].Dispatcher(); + } + + private: + std::vector m_disabledButtons; + std::vector m_enabledButtons; + Windows::UI::Xaml::Controls::TextBlock m_statusText; + std::wstring m_status; + }; + + std::wstring MakeCompactByteString(uint64_t bytes) + { + static constexpr std::array s_sizeStrings = { L"B"sv, L"KB"sv, L"MB"sv, L"GB"sv }; + static constexpr size_t s_sizeIncrement = 1000; + + size_t sizeIndex = 0; + while (sizeIndex < s_sizeStrings.size() && bytes > s_sizeIncrement) + { + sizeIndex += 1; + bytes /= s_sizeIncrement; + } + + return std::to_wstring(bytes).append(L" ").append(s_sizeStrings[sizeIndex]); + } + } + + MainPage::MainPage() + { + InitializeComponent(); + m_packageCatalogs = winrt::single_threaded_observable_vector(); + m_installedPackages = winrt::single_threaded_observable_vector(); + m_activePackageViews = winrt::single_threaded_observable_vector(); + } + + Windows::Foundation::Collections::IObservableVector MainPage::PackageCatalogs() + { + return m_packageCatalogs; + } + + Windows::Foundation::Collections::IObservableVector MainPage::InstalledPackages() + { + return m_installedPackages; + } + + Windows::Foundation::Collections::IObservableVector MainPage::ActivePackages() + { + return m_activePackageViews; + } + + void MainPage::LoadCatalogsButtonClickHandler(IInspectable const&, RoutedEventArgs const&) + { + LoadCatalogsAsync(); + } + + void MainPage::CatalogSelectionChangedHandler(Windows::Foundation::IInspectable const&, Windows::UI::Xaml::RoutedEventArgs const&) + { + m_catalog = nullptr; + } + + void MainPage::SearchButtonClickHandler(IInspectable const&, RoutedEventArgs const&) + { + FindPackageAsync(); + } + + void MainPage::InstallButtonClickHandler(IInspectable const&, RoutedEventArgs const&) + { + if (m_packageOperation == nullptr || m_packageOperation.Status() != AsyncStatus::Started) + { + InstallOrUpgradeAsync(false); + } + } + + void MainPage::UpgradeButtonClickHandler(IInspectable const&, RoutedEventArgs const&) + { + if (m_packageOperation == nullptr || m_packageOperation.Status() != AsyncStatus::Started) + { + InstallOrUpgradeAsync(true); + } + } + + void MainPage::DownloadButtonClickHandler(IInspectable const&, RoutedEventArgs const&) + { + if (m_packageOperation == nullptr || m_packageOperation.Status() != AsyncStatus::Started) + { + DownloadAsync(); + } + } + + void MainPage::CancelButtonClickHandler(IInspectable const&, RoutedEventArgs const&) + { + if (m_packageOperation && m_packageOperation.Status() == AsyncStatus::Started) + { + m_packageOperation.Cancel(); + } + } + + void MainPage::RefreshInstalledButtonClickHandler(IInspectable const&, RoutedEventArgs const&) + { + GetInstalledPackagesAsync(); + } + + void MainPage::UninstallButtonClickHandler(IInspectable const&, RoutedEventArgs const&) + { + UninstallAsync(); + } + + void MainPage::RefreshActiveButtonClickHandler(IInspectable const&, RoutedEventArgs const&) + { + GetActivePackagesAsync(); + } + + std::wstring MainPage::EnsurePackageManager(bool forceRecreate) + { + std::lock_guard lock{ m_packageManagerMutex }; + + std::wstring result; + + if (!m_packageManager || forceRecreate) + { + result = RunAndReturnStatus(L"Create PackageManager", [&]() { + m_packageManager = PackageManager{}; + }); + } + + return result; + } + + IAsyncAction MainPage::LoadCatalogsAsync() + { + BackgroundActionData actionData{ { loadCatalogsButton() }, catalogStatusText() }; + + co_await winrt::resume_background(); + + actionData.Status(EnsurePackageManager(true)); + + decltype(m_packageManager.GetPackageCatalogs()) catalogs{ nullptr }; + actionData.RunAndCatchStatus(L"Load Catalogs", [&]() { + catalogs = m_packageManager.GetPackageCatalogs(); + }); + + co_await winrt::resume_foreground(actionData.Dispatcher()); + + m_packageCatalogs.Clear(); + + if (catalogs) + { + for (auto const catalog : catalogs) + { + m_packageCatalogs.Append(catalog); + } + } + + actionData.Finalize(); + } + + IAsyncAction MainPage::FindPackageAsync() + { + hstring queryInput = queryTextBox().Text(); + auto selectedItems = catalogsListBox().SelectedItems(); + int32_t searchType = searchField().SelectedIndex(); + PackageCatalog catalog = m_catalog; + + BackgroundActionData actionData{ { searchButton() }, operationStatusText() }; + + co_await winrt::resume_background(); + + actionData.Status(EnsurePackageManager()); + + if (!catalog) + { + actionData.RunAndCatchStatus(L"Connect catalog(s)", [&]() { + PackageCatalogReference catalogReference{ nullptr }; + + if (selectedItems.Size() == 0) + { + // If no items are selected, we use all available catalogs. + CreateCompositePackageCatalogOptions createCompositePackageCatalogOptions; + createCompositePackageCatalogOptions.CompositeSearchBehavior(CompositeSearchBehavior::RemotePackagesFromRemoteCatalogs); + + for (const auto& item : m_packageManager.GetPackageCatalogs()) + { + createCompositePackageCatalogOptions.Catalogs().Append(item); + } + + catalogReference = m_packageManager.CreateCompositePackageCatalog(createCompositePackageCatalogOptions); + } + else if (selectedItems.Size() == 1) + { + // If one items is selected, we can directly use this catalog. + catalogReference = selectedItems.GetAt(0).as(); + } + else + { + // If multiple items are selected, we create a composite catalog using those catalogs. + CreateCompositePackageCatalogOptions createCompositePackageCatalogOptions; + createCompositePackageCatalogOptions.CompositeSearchBehavior(CompositeSearchBehavior::RemotePackagesFromRemoteCatalogs); + + for (const auto& item : selectedItems) + { + createCompositePackageCatalogOptions.Catalogs().Append(item.as()); + } + + catalogReference = m_packageManager.CreateCompositePackageCatalog(createCompositePackageCatalogOptions); + } + + ConnectResult connectResult{ catalogReference.Connect() }; + + switch (connectResult.Status()) + { + case ConnectResultStatus::Ok: break; + case ConnectResultStatus::CatalogError: throw std::exception{ "Catalog connection error." }; + case ConnectResultStatus::SourceAgreementsNotAccepted: throw std::exception{ "Required catalog agreements not accepted." }; + } + + catalog = connectResult.PackageCatalog(); + }); + } + + CatalogPackage package{ nullptr }; + + actionData.RunAndCatchStatus(L"Find package", [&]() { + FindPackagesOptions findPackagesOptions; + PackageMatchFilter filter; + + switch (searchType) + { + case 0: // Generic query + filter.Field(PackageMatchField::CatalogDefault); + filter.Option(PackageFieldMatchOption::ContainsCaseInsensitive); + break; + case 1: // Identifier (case-insensitive) + filter.Field(PackageMatchField::Id); + filter.Option(PackageFieldMatchOption::EqualsCaseInsensitive); + break; + case 2: // Name (substring) + filter.Field(PackageMatchField::Name); + filter.Option(PackageFieldMatchOption::ContainsCaseInsensitive); + break; + } + + filter.Value(queryInput); + findPackagesOptions.Selectors().Append(filter); + FindPackagesResult findPackagesResult = catalog.FindPackages(findPackagesOptions); + + winrt::IVectorView matches = findPackagesResult.Matches(); + if (matches.Size() == 0) + { + throw std::exception{ "No package found matching input" }; + } + else if (matches.Size() > 1) + { + throw std::exception{ "Multiple packages found matching input; refine query." }; + } + else + { + package = matches.GetAt(0).CatalogPackage(); + } + }); + + if (package) + { + // Display the package name using the user's default localization information. + std::wostringstream stream; + stream << L"Found package: " << + static_cast(package.DefaultInstallVersion().GetCatalogPackageMetadata().PackageName()) << L" [" << + static_cast(package.Id()) << L"]"; + actionData.Status(std::move(stream).str()); + } + + co_await winrt::resume_foreground(actionData.Dispatcher()); + + m_catalog = catalog; + m_package = package; + + bool operationButtonsEnabled = static_cast(m_package); + installButton().IsEnabled(operationButtonsEnabled); + upgradeButton().IsEnabled(operationButtonsEnabled); + downloadButton().IsEnabled(operationButtonsEnabled); + + actionData.Finalize(); + } + + IAsyncAction MainPage::InstallOrUpgradeAsync(bool upgrade) + { + PackageManager packageManager = m_packageManager; + CatalogPackage package = m_package; + auto progressBar = operationProgressBar(); + auto statusText = operationStatusText(); + + BackgroundActionData actionData{ { installButton(), upgradeButton(), downloadButton() }, { cancelButton() }, statusText }; + + co_await winrt::resume_background(); + + Windows::Foundation::IAsyncOperationWithProgress packageOperation; + + actionData.RunAndCatchStatus(L"Begin install", [&]() { + InstallOptions installOptions; + + // Passing PackageInstallScope::User causes the install to fail if there's no installer that supports that. + installOptions.PackageInstallScope(PackageInstallScope::Any); + installOptions.PackageInstallMode(PackageInstallMode::Silent); + + if (upgrade) + { + packageOperation = packageManager.UpgradePackageAsync(package, installOptions); + } + else + { + packageOperation = packageManager.InstallPackageAsync(package, installOptions); + } + }); + + actionData.Dispatcher().RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, + [packageOperation, this]() { m_packageOperation = packageOperation; }); + + actionData.RunAndCatchStatus(L"Set progress handler", [&]() { + packageOperation.Progress([&]( + IAsyncOperationWithProgress const& /* sender */, + InstallProgress const& progress) + { + actionData.Dispatcher().RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, + [progressBar, statusText, progress]() { + progressBar.Value(progress.DownloadProgress * 100); + + switch (progress.State) + { + case PackageInstallProgressState::Queued: + statusText.Text(L"Queued"); + break; + case PackageInstallProgressState::Downloading: + { + std::wstring downloadText{ L"Downloaded " }; + downloadText += MakeCompactByteString(progress.BytesDownloaded) + L" of " + MakeCompactByteString(progress.BytesRequired); + statusText.Text(downloadText); + } + break; + case PackageInstallProgressState::Installing: + statusText.Text(L"Installer running"); + progressBar.IsIndeterminate(true); + break; + case PackageInstallProgressState::PostInstall: + statusText.Text(L"Post install bookkeeping"); + break; + case PackageInstallProgressState::Finished: + statusText.Text(L"Done"); + progressBar.IsIndeterminate(false); + break; + default: + statusText.Text(L""); + } + }); + }); + }); + + InstallResult installResult{ nullptr }; + + actionData.RunAndCatchStatus(L"Install", [&]() { + installResult = packageOperation.get(); + }); + + if (packageOperation && packageOperation.Status() == AsyncStatus::Canceled) + { + actionData.Status(L"Cancelled"); + } + else if (installResult) + { + // Error handling for the installResult is done by first examining the Status. + // Any status value other than Ok will have additional error detail in the + // ExtendedErrorCode property. This HRESULT value will typically (but not always) + // have the Windows Package Manager facility value (0xA15). The symbolic names and + // meanings of these error codes can be found at: + // https://github.com/microsoft/winget-cli/blob/master/doc/windows/package-manager/winget/returnCodes.md + // or by using the winget CLI: + // > winget error 0x8A150049 + // > winget error -- -2146762487 + switch (installResult.Status()) + { + case InstallResultStatus::Ok: + actionData.Status(installResult.RebootRequired() ? L"Reboot required" : L"Done"); + break; + case InstallResultStatus::BlockedByPolicy: + // See installResult.ExtendedErrorCode for more detail. + // This is typically caused by system configuration applied by policy. + actionData.Status(L"Blocked by policy"); + break; + case InstallResultStatus::CatalogError: + // See installResult.ExtendedErrorCode for more detail. + // This is typically an issue with an external service. + actionData.Status(L"Catalog error"); + break; + case InstallResultStatus::InternalError: + // See installResult.ExtendedErrorCode for more detail. + // This is typically an issue with the Windows Package Manager code. + actionData.Status(L"Internal error"); + break; + case InstallResultStatus::InvalidOptions: + // See installResult.ExtendedErrorCode for more detail. + // This is caused by invalid input combinations. + actionData.Status(L"Invalid options"); + break; + case InstallResultStatus::DownloadError: + // See installResult.ExtendedErrorCode for more detail. + // This is typically a transient network error. + actionData.Status(L"Download error"); + break; + case InstallResultStatus::InstallError: + // See installResult.ExtendedErrorCode and installResult.InstallerErrorCode for more detail. + // This is caused by an error in the installer or an issue with the system state. + // InstallerErrorCode is the value returned by the installer technology in use for the install + // attempt and may or may not be an HRESULT. + actionData.Status(L"Installation error"); + break; + case InstallResultStatus::ManifestError: + // See installResult.ExtendedErrorCode for more detail. + // This is an issue with the catalog providing the package. + actionData.Status(L"Manifest error"); + break; + case InstallResultStatus::NoApplicableInstallers: + // No applicable installers were available due the combination of the current system, + // user settings, and parameters provided to the install request. + actionData.Status(L"No applicable installers"); + break; + case InstallResultStatus::NoApplicableUpgrade: + // No upgrade was available due the combination of available versions, the current system, + // user settings, and parameters provided to the upgrade request. + actionData.Status(L"No applicable upgrade"); + break; + case InstallResultStatus::PackageAgreementsNotAccepted: + // The user has not accepted the agreements required by the package. + actionData.Status(L"Package agreements not accepted"); + break; + } + } + + // Switch back to ui thread context. + co_await winrt::resume_foreground(actionData.Dispatcher()); + + progressBar.IsIndeterminate(false); + + actionData.Finalize(); + } + + IAsyncAction MainPage::DownloadAsync() + { + hstring downloadDirectory = downloadDirectoryTextBox().Text(); + PackageManager packageManager = m_packageManager; + CatalogPackage package = m_package; + auto progressBar = operationProgressBar(); + auto statusText = operationStatusText(); + + BackgroundActionData actionData{ { installButton(), upgradeButton(), downloadButton() }, { cancelButton() }, statusText}; + + co_await winrt::resume_background(); + + Windows::Foundation::IAsyncOperationWithProgress packageOperation; + + actionData.RunAndCatchStatus(L"Begin download", [&]() { + DownloadOptions downloadOptions; + + if (!downloadDirectory.empty()) + { + downloadOptions.DownloadDirectory(downloadDirectory); + } + + packageOperation = packageManager.DownloadPackageAsync(package, downloadOptions); + }); + + actionData.Dispatcher().RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, + [packageOperation, this]() { m_packageOperation = packageOperation; }); + + actionData.RunAndCatchStatus(L"Set progress handler", [&]() { + packageOperation.Progress([&]( + IAsyncOperationWithProgress const& /* sender */, + PackageDownloadProgress const& progress) + { + actionData.Dispatcher().RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, + [progressBar, statusText, progress]() { + progressBar.Value(progress.DownloadProgress * 100); + + switch (progress.State) + { + case PackageDownloadProgressState::Queued: + statusText.Text(L"Queued"); + break; + case PackageDownloadProgressState::Downloading: + { + std::wstring downloadText{ L"Downloaded " }; + downloadText += MakeCompactByteString(progress.BytesDownloaded) + L" of " + MakeCompactByteString(progress.BytesRequired); + statusText.Text(downloadText); + } + break; + case PackageDownloadProgressState::Finished: + statusText.Text(L"Done"); + progressBar.IsIndeterminate(false); + break; + default: + statusText.Text(L""); + } + }); + }); + }); + + DownloadResult downloadResult{ nullptr }; + + actionData.RunAndCatchStatus(L"Download", [&]() { + downloadResult = packageOperation.get(); + }); + + if (packageOperation && packageOperation.Status() == AsyncStatus::Canceled) + { + actionData.Status(L"Cancelled"); + } + else if (downloadResult) + { + // Error handling for the downloadResult is done by first examining the Status. + // Any status value other than Ok will have additional error detail in the + // ExtendedErrorCode property. This HRESULT value will typically (but not always) + // have the Windows Package Manager facility value (0xA15). The symbolic names and + // meanings of these error codes can be found at: + // https://github.com/microsoft/winget-cli/blob/master/doc/windows/package-manager/winget/returnCodes.md + // or by using the winget CLI: + // > winget error 0x8A150049 + // > winget error -- -2146762487 + switch (downloadResult.Status()) + { + case DownloadResultStatus::Ok: + actionData.Status(L"Done"); + break; + case DownloadResultStatus::BlockedByPolicy: + // See installResult.ExtendedErrorCode for more detail. + // This is typically caused by system configuration applied by policy. + actionData.Status(L"Blocked by policy"); + break; + case DownloadResultStatus::CatalogError: + // See installResult.ExtendedErrorCode for more detail. + // This is typically an issue with an external service. + actionData.Status(L"Catalog error"); + break; + case DownloadResultStatus::InternalError: + // See installResult.ExtendedErrorCode for more detail. + // This is typically an issue with the Windows Package Manager code. + actionData.Status(L"Internal error"); + break; + case DownloadResultStatus::InvalidOptions: + // See installResult.ExtendedErrorCode for more detail. + // This is caused by invalid input combinations. + actionData.Status(L"Invalid options"); + break; + case DownloadResultStatus::DownloadError: + // See installResult.ExtendedErrorCode for more detail. + // This is typically a transient network error. + actionData.Status(L"Download error"); + break; + case DownloadResultStatus::ManifestError: + // See installResult.ExtendedErrorCode for more detail. + // This is an issue with the catalog providing the package. + actionData.Status(L"Manifest error"); + break; + case DownloadResultStatus::NoApplicableInstallers: + // No applicable installers were available due the combination of the current system, + // user settings, and parameters provided to the install request. + actionData.Status(L"No applicable installers"); + break; + case DownloadResultStatus::PackageAgreementsNotAccepted: + // The user has not accepted the agreements required by the package. + actionData.Status(L"Package agreements not accepted"); + break; + } + } + + // Switch back to ui thread context. + co_await winrt::resume_foreground(actionData.Dispatcher()); + + progressBar.IsIndeterminate(false); + + actionData.Finalize(); + } + + IAsyncAction MainPage::GetInstalledPackagesAsync() + { + BackgroundActionData actionData{ { refreshInstalledButton() }, installedStatusText() }; + + co_await winrt::resume_background(); + + actionData.Status(EnsurePackageManager()); + + PackageCatalog catalog{ nullptr }; + + actionData.RunAndCatchStatus(L"Connect installed catalog", [&]() { + PackageCatalogReference catalogReference = m_packageManager.GetLocalPackageCatalog(LocalPackageCatalog::InstalledPackages); + ConnectResult connectResult{ catalogReference.Connect() }; + + switch (connectResult.Status()) + { + case ConnectResultStatus::Ok: break; + case ConnectResultStatus::CatalogError: throw std::exception{ "Catalog connection error." }; + } + + catalog = connectResult.PackageCatalog(); + }); + + winrt::IVectorView matches; + + actionData.RunAndCatchStatus(L"Find package", [&]() { + FindPackagesOptions findPackagesOptions; + FindPackagesResult findPackagesResult = catalog.FindPackages(findPackagesOptions); + + matches = findPackagesResult.Matches(); + }); + + co_await winrt::resume_foreground(actionData.Dispatcher()); + + m_installedPackages.Clear(); + + if (matches) + { + for (auto const& match : matches) + { + m_installedPackages.Append(match.CatalogPackage()); + } + } + + actionData.Finalize(); + } + + IAsyncAction MainPage::UninstallAsync() + { + PackageManager packageManager = m_packageManager; + + auto progressBar = uninstallProgressBar(); + auto statusText = uninstallStatusText(); + + IInspectable selectedValue = installedListBox().SelectedValue(); + CatalogPackage package{ nullptr }; + if (selectedValue) + { + package = selectedValue.as(); + } + else + { + statusText.Text(L"Select a package to uninstall"); + co_return; + } + + BackgroundActionData actionData{ { uninstallButton() }, statusText }; + + co_await winrt::resume_background(); + + Windows::Foundation::IAsyncOperationWithProgress packageOperation; + + actionData.RunAndCatchStatus(L"Begin uninstall", [&]() { + UninstallOptions uninstallOptions; + + uninstallOptions.PackageUninstallScope(PackageUninstallScope::Any); + uninstallOptions.PackageUninstallMode(PackageUninstallMode::Silent); + + packageOperation = packageManager.UninstallPackageAsync(package, uninstallOptions); + }); + + actionData.RunAndCatchStatus(L"Set progress handler", [&]() { + packageOperation.Progress([&]( + IAsyncOperationWithProgress const& /* sender */, + UninstallProgress const& progress) + { + actionData.Dispatcher().RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, + [progressBar, statusText, progress]() { + progressBar.Value(progress.UninstallationProgress * 100); + + switch (progress.State) + { + case PackageUninstallProgressState::Queued: + statusText.Text(L"Queued"); + break; + case PackageUninstallProgressState::Uninstalling: + statusText.Text(L"Uninstaller running"); + progressBar.IsIndeterminate(true); + break; + case PackageUninstallProgressState::PostUninstall: + statusText.Text(L"Post uninstall bookkeeping"); + break; + case PackageUninstallProgressState::Finished: + statusText.Text(L"Done"); + progressBar.IsIndeterminate(false); + break; + default: + statusText.Text(L""); + } + }); + }); + }); + + UninstallResult uninstallResult{ nullptr }; + + actionData.RunAndCatchStatus(L"Uninstall", [&]() { + uninstallResult = packageOperation.get(); + }); + + if (packageOperation && packageOperation.Status() == AsyncStatus::Canceled) + { + actionData.Status(L"Cancelled"); + } + else if (uninstallResult) + { + // Error handling for the installResult is done by first examining the Status. + // Any status value other than Ok will have additional error detail in the + // ExtendedErrorCode property. This HRESULT value will typically (but not always) + // have the Windows Package Manager facility value (0xA15). The symbolic names and + // meanings of these error codes can be found at: + // https://github.com/microsoft/winget-cli/blob/master/doc/windows/package-manager/winget/returnCodes.md + // or by using the winget CLI: + // > winget error 0x8A150049 + // > winget error -- -2146762487 + switch (uninstallResult.Status()) + { + case UninstallResultStatus::Ok: + actionData.Status(uninstallResult.RebootRequired() ? L"Reboot required" : L"Done"); + break; + case UninstallResultStatus::BlockedByPolicy: + // See installResult.ExtendedErrorCode for more detail. + // This is typically caused by system configuration applied by policy. + actionData.Status(L"Blocked by policy"); + break; + case UninstallResultStatus::CatalogError: + // See installResult.ExtendedErrorCode for more detail. + // This is typically an issue with an external service. + actionData.Status(L"Catalog error"); + break; + case UninstallResultStatus::InternalError: + // See installResult.ExtendedErrorCode for more detail. + // This is typically an issue with the Windows Package Manager code. + actionData.Status(L"Internal error"); + break; + case UninstallResultStatus::InvalidOptions: + // See installResult.ExtendedErrorCode for more detail. + // This is caused by invalid input combinations. + actionData.Status(L"Invalid options"); + break; + case UninstallResultStatus::UninstallError: + // See installResult.ExtendedErrorCode and installResult.UninstallerErrorCode for more detail. + // This is caused by an error in the uninstaller or an issue with the system state. + // UninstallerErrorCode is the value returned by the uninstaller technology in use for the uninstall + // attempt and may or may not be an HRESULT. + actionData.Status(L"Uninstallation error"); + break; + case UninstallResultStatus::ManifestError: + // See installResult.ExtendedErrorCode for more detail. + // This is an issue with the catalog providing the package. + actionData.Status(L"Manifest error"); + break; + } + } + + // Switch back to ui thread context. + co_await winrt::resume_foreground(actionData.Dispatcher()); + + progressBar.IsIndeterminate(false); + + actionData.Finalize(); + } + + IAsyncAction MainPage::GetActivePackagesAsync() + { + BackgroundActionData actionData{ { activeRefreshButton() }, activeStatusText() }; + + co_await winrt::resume_background(); + + actionData.Status(EnsurePackageManager()); + + PackageCatalog catalog{ nullptr }; + + actionData.RunAndCatchStatus(L"Connect installed catalog", [&]() { + PackageCatalogReference catalogReference = m_packageManager.GetLocalPackageCatalog(LocalPackageCatalog::InstallingPackages); + ConnectResult connectResult{ catalogReference.Connect() }; + + switch (connectResult.Status()) + { + case ConnectResultStatus::Ok: break; + case ConnectResultStatus::CatalogError: throw std::exception{ "Catalog connection error." }; + } + + catalog = connectResult.PackageCatalog(); + }); + + winrt::IVectorView matches; + + actionData.RunAndCatchStatus(L"Find package", [&]() { + FindPackagesOptions findPackagesOptions; + FindPackagesResult findPackagesResult = catalog.FindPackages(findPackagesOptions); + + matches = findPackagesResult.Matches(); + }); + + co_await winrt::resume_foreground(actionData.Dispatcher()); + + m_activePackageViews.Clear(); + + if (matches) + { + for (auto const& match : matches) + { + WinGetUWPCaller::ActivePackageView activeView; + activeView.Package(match.CatalogPackage()); + auto installOperation = m_packageManager.GetInstallProgress(activeView.Package(), nullptr); + if (installOperation) + { + activeView.Dispatcher(actionData.Dispatcher()); + activeView.AsyncOperation(installOperation); + m_activePackageViews.Append(activeView); + } + } + } + + actionData.Finalize(); + } +} diff --git a/samples/WinGetUWPCaller/WinGetUWPCaller/MainPage.h b/samples/WinGetUWPCaller/WinGetUWPCaller/MainPage.h new file mode 100644 index 0000000000..2debcad2ef --- /dev/null +++ b/samples/WinGetUWPCaller/WinGetUWPCaller/MainPage.h @@ -0,0 +1,79 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#pragma once +#include "MainPage.g.h" +#include "ActivePackageView.h" +#include +#include + +namespace Deployment = winrt::Microsoft::Management::Deployment; + +namespace winrt::WinGetUWPCaller::implementation +{ + struct MainPage : MainPageT + { + MainPage(); + + Windows::Foundation::Collections::IObservableVector PackageCatalogs(); + Windows::Foundation::Collections::IObservableVector InstalledPackages(); + Windows::Foundation::Collections::IObservableVector ActivePackages(); + + // Select Catalog(s) section + void LoadCatalogsButtonClickHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& args); + void CatalogSelectionChangedHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& args); + + // Package Operations section + void SearchButtonClickHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& args); + void InstallButtonClickHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& args); + void UpgradeButtonClickHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& args); + void DownloadButtonClickHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& args); + void CancelButtonClickHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& args); + + // Installed Packages section + void RefreshInstalledButtonClickHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& args); + void UninstallButtonClickHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& args); + + // Active Operations section + void RefreshActiveButtonClickHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& args); + + private: + // Ensures that the package manager object exists; potentially recreating it if requested. + // Should be called from a background thread. + // Is thread-safe. + // Returns an error string if it fails. + std::wstring EnsurePackageManager(bool forceRecreate = false); + + // Select Catalog(s) section + Windows::Foundation::IAsyncAction LoadCatalogsAsync(); + + // Package Operations section + Windows::Foundation::IAsyncAction FindPackageAsync(); + Windows::Foundation::IAsyncAction InstallOrUpgradeAsync(bool upgrade); + Windows::Foundation::IAsyncAction DownloadAsync(); + + // Installed Packages section + Windows::Foundation::IAsyncAction GetInstalledPackagesAsync(); + Windows::Foundation::IAsyncAction UninstallAsync(); + + // Active Operations section + Windows::Foundation::IAsyncAction GetActivePackagesAsync(); + + // Member fields + Windows::Foundation::Collections::IObservableVector m_packageCatalogs; + Windows::Foundation::Collections::IObservableVector m_installedPackages; + Windows::Foundation::Collections::IObservableVector m_activePackageViews; + + std::mutex m_packageManagerMutex; + Deployment::PackageManager m_packageManager{ nullptr }; + Deployment::PackageCatalog m_catalog{ nullptr }; + Deployment::CatalogPackage m_package{ nullptr }; + Windows::Foundation::IAsyncInfo m_packageOperation; + }; +} + +namespace winrt::WinGetUWPCaller::factory_implementation +{ + struct MainPage : MainPageT + { + }; +} diff --git a/samples/WinGetUWPCaller/WinGetUWPCaller/MainPage.idl b/samples/WinGetUWPCaller/WinGetUWPCaller/MainPage.idl new file mode 100644 index 0000000000..39e8ac0a62 --- /dev/null +++ b/samples/WinGetUWPCaller/WinGetUWPCaller/MainPage.idl @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +namespace WinGetUWPCaller +{ + [default_interface] + runtimeclass ActivePackageView : Windows.UI.Xaml.Data.INotifyPropertyChanged + { + ActivePackageView(); + + Microsoft.Management.Deployment.CatalogPackage Package; + Windows.Foundation.IAsyncOperationWithProgress AsyncOperation; + Double Progress; + String StatusText; + Windows.UI.Core.CoreDispatcher Dispatcher; + } + + [default_interface] + runtimeclass MainPage : Windows.UI.Xaml.Controls.Page + { + MainPage(); + + Windows.Foundation.Collections.IObservableVector PackageCatalogs{ get; }; + Windows.Foundation.Collections.IObservableVector InstalledPackages{ get; }; + Windows.Foundation.Collections.IObservableVector ActivePackages{ get; }; + } + + declare + { + interface Windows.Foundation.Collections.IVector; + interface Windows.Foundation.Collections.IVectorView; + } +} diff --git a/samples/WinGetUWPCaller/WinGetUWPCaller/MainPage.xaml b/samples/WinGetUWPCaller/WinGetUWPCaller/MainPage.xaml new file mode 100644 index 0000000000..3282556f19 --- /dev/null +++ b/samples/WinGetUWPCaller/WinGetUWPCaller/MainPage.xaml @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + Select Catalog(s) + + + + Select catalog(s) to use + + + + + + + + + + + Package Operations + Search for a package from the selected catalog(s) and take action on it. + + + + + + + + + + + + + + + + + + + + + + + + + + Installed Packages + View installed package information + + + + + + + + + + + + + + + + + Active Operations + View active package install/upgrade operations + + + + + + + + + + + + + + + + + + diff --git a/samples/WinGetUWPCaller/WinGetUWPCaller/Package.appxmanifest b/samples/WinGetUWPCaller/WinGetUWPCaller/Package.appxmanifest new file mode 100644 index 0000000000..a4f2653665 --- /dev/null +++ b/samples/WinGetUWPCaller/WinGetUWPCaller/Package.appxmanifest @@ -0,0 +1,31 @@ + + + + + + Sample WinGet Caller + Microsoft Corporation + Assets\StoreLogo.png + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/WinGetUWPCaller/WinGetUWPCaller/WinGetUWPCaller.vcxproj b/samples/WinGetUWPCaller/WinGetUWPCaller/WinGetUWPCaller.vcxproj new file mode 100644 index 0000000000..421c70452a --- /dev/null +++ b/samples/WinGetUWPCaller/WinGetUWPCaller/WinGetUWPCaller.vcxproj @@ -0,0 +1,204 @@ + + + + + true + true + true + true + {37f1fd2a-4d63-45a0-82aa-66ef126cb322} + WinGetUWPCaller + WinGetUWPCaller + en-US + 15.0 + true + Windows Store + 10.0 + 10.0.22000.0 + 10.0.17763.0 + + + + + Debug + ARM64 + + + Debug + Win32 + + + Debug + x64 + + + Release + ARM64 + + + Release + Win32 + + + Release + x64 + + + + Application + v140 + v141 + v142 + v143 + Unicode + + + true + true + + + false + true + false + + + + + + + + + False + SHA256 + True + True + x64 + 0 + Always + + + + Use + pch.h + $(IntDir)pch.pch + Level4 + %(AdditionalOptions) /bigobj + + /DWINRT_NO_MAKE_DETECTION %(AdditionalOptions) + + + WIN32_LEAN_AND_MEAN;WINRT_LEAN_AND_MEAN;%(PreprocessorDefinitions) + + + false + + + + + _DEBUG;%(PreprocessorDefinitions) + + + + + + + + + NDEBUG;%(PreprocessorDefinitions) + + + true + true + + + + + + + + + + + App.xaml + + + MainPage.xaml + + + + + Designer + + + Designer + + + + + Designer + + + + + + + + + + + + + + + Create + + + App.xaml + + + MainPage.xaml + + + + + + App.xaml + + + MainPage.xaml + + + + + + + + win10-x86 + win10-x64 + win10-arm64 + + + + Microsoft.Management.Deployment.dll + + + + + + ..\packages\Microsoft.WindowsPackageManager.ComInterop.1.8.1911\lib\Microsoft.Management.Deployment.winmd + true + Microsoft.Management.Deployment.dll + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + \ No newline at end of file diff --git a/samples/WinGetUWPCaller/WinGetUWPCaller/WinGetUWPCaller.vcxproj.filters b/samples/WinGetUWPCaller/WinGetUWPCaller/WinGetUWPCaller.vcxproj.filters new file mode 100644 index 0000000000..5d42a428ca --- /dev/null +++ b/samples/WinGetUWPCaller/WinGetUWPCaller/WinGetUWPCaller.vcxproj.filters @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Assets + + + Assets + + + Assets + + + Assets + + + Assets + + + Assets + + + Assets + + + + + + + + + + + {adeebf4e-70b7-41ae-936b-ded00e6e6777} + + + \ No newline at end of file diff --git a/samples/WinGetUWPCaller/WinGetUWPCaller/packages.config b/samples/WinGetUWPCaller/WinGetUWPCaller/packages.config new file mode 100644 index 0000000000..d716d962e4 --- /dev/null +++ b/samples/WinGetUWPCaller/WinGetUWPCaller/packages.config @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/samples/WinGetUWPCaller/WinGetUWPCaller/pch.cpp b/samples/WinGetUWPCaller/WinGetUWPCaller/pch.cpp new file mode 100644 index 0000000000..e4b1bd6915 --- /dev/null +++ b/samples/WinGetUWPCaller/WinGetUWPCaller/pch.cpp @@ -0,0 +1,3 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#include "pch.h" diff --git a/samples/WinGetUWPCaller/WinGetUWPCaller/pch.h b/samples/WinGetUWPCaller/WinGetUWPCaller/pch.h new file mode 100644 index 0000000000..ad1bd05d51 --- /dev/null +++ b/samples/WinGetUWPCaller/WinGetUWPCaller/pch.h @@ -0,0 +1,25 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include