winget-cli

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit 88cd81efa17282568c2ce350e22bdcc9bed458e8
parent ec6c840d78a3cb772bf2ae6dd015d907cab0dfb7
Author: Ryan <69221034+ryfu-msft@users.noreply.github.com>
Date:   Thu, 21 Mar 2024 11:05:41 -0700

Fix `EnableWindowsPackageManagerCommandLineInterfaces` Policy Behavior (#4293)


Diffstat:
Msrc/AppInstallerCLICore/Command.cpp | 9+--------
Msrc/AppInstallerCLICore/Core.cpp | 11+++++++++--
Msrc/AppInstallerCLIE2ETests/Interop/GroupPolicyForInterop.cs | 57++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Mtools/SampleWinGetUWPCaller/AppInstallerCaller/GeneratedFromServer/Microsoft.Management.Deployment.winmd | 0
Mtools/SampleWinGetUWPCaller/AppInstallerCaller/MainPage.cpp | 193++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Mtools/SampleWinGetUWPCaller/AppInstallerCaller/MainPage.h | 18+++++++++++++++---
Mtools/SampleWinGetUWPCaller/AppInstallerCaller/MainPage.xaml | 11++++++++++-
7 files changed, 277 insertions(+), 22 deletions(-)

diff --git a/src/AppInstallerCLICore/Command.cpp b/src/AppInstallerCLICore/Command.cpp @@ -861,14 +861,7 @@ namespace AppInstaller::CLI if (!Settings::GroupPolicies().IsEnabled(Settings::TogglePolicy::Policy::WinGet)) { AICLI_LOG(CLI, Error, << "WinGet is disabled by group policy"); - throw GroupPolicyException(Settings::TogglePolicy::Policy::WinGet); - } - - // Block CLI execution if WinGetCommandLineInterfaces is disabled by Policy - if (!Settings::GroupPolicies().IsEnabled(Settings::TogglePolicy::Policy::WinGetCommandLineInterfaces)) - { - AICLI_LOG(CLI, Error, << "WinGet is disabled by group policy"); - throw GroupPolicyException(Settings::TogglePolicy::Policy::WinGetCommandLineInterfaces); + throw Settings::GroupPolicyException::GroupPolicyException(Settings::TogglePolicy::Policy::WinGet); } AICLI_LOG(CLI, Info, << "Executing command: " << Name()); diff --git a/src/AppInstallerCLICore/Core.cpp b/src/AppInstallerCLICore/Core.cpp @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. +// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. #include "pch.h" #include "Public/AppInstallerCLICore.h" @@ -109,7 +109,14 @@ namespace AppInstaller::CLI std::unique_ptr<Command> command = std::make_unique<RootCommand>(); try - { + { + // Block CLI execution if WinGetCommandLineInterfaces is disabled by Policy + if (!Settings::GroupPolicies().IsEnabled(Settings::TogglePolicy::Policy::WinGetCommandLineInterfaces)) + { + AICLI_LOG(CLI, Error, << "WinGet is disabled by group policy"); + throw Settings::GroupPolicyException(Settings::TogglePolicy::Policy::WinGetCommandLineInterfaces); + } + std::unique_ptr<Command> subCommand = command->FindSubCommand(invocation); while (subCommand) { diff --git a/src/AppInstallerCLIE2ETests/Interop/GroupPolicyForInterop.cs b/src/AppInstallerCLIE2ETests/Interop/GroupPolicyForInterop.cs @@ -1,4 +1,4 @@ -// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- // <copyright file="GroupPolicyForInterop.cs" company="Microsoft Corporation"> // Copyright (c) Microsoft Corporation. Licensed under the MIT License. // </copyright> @@ -6,10 +6,15 @@ namespace AppInstallerCLIE2ETests.Interop { + using System; + using System.IO; + using System.Threading.Tasks; + using AppInstallerCLIE2ETests.Helpers; using Microsoft.Management.Deployment; using Microsoft.Management.Deployment.Projection; using Microsoft.WinGet.SharedLib.Exceptions; using NUnit.Framework; + using Windows.System; /// <summary> /// Group Policy Tests for COM/WinRT Interop classes. @@ -89,5 +94,55 @@ namespace AppInstallerCLIE2ETests.Interop Assert.AreEqual(Constants.ErrorCode.ERROR_BLOCKED_BY_POLICY, groupPolicyException.HResult); } } + + /// <summary> + /// Validates disabling the EnableWindowsPackageManagerCommandLineInterfaces policy should still allow COM calls. + /// </summary> + /// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns> + [Test] + public async Task DisableWinGetCommandLineInterfacesPolicy() + { + GroupPolicyHelper.EnableWinGetCommandLineInterfaces.Disable(); + + PackageManager packageManager = this.TestFactory.CreatePackageManager(); + string installDir = TestCommon.GetRandomTestDir(); + + // Create composite package catalog source + var options = this.TestFactory.CreateCreateCompositePackageCatalogOptions(); + var testSource = packageManager.GetPackageCatalogByName(Constants.TestSourceName); + Assert.NotNull(testSource, $"{Constants.TestSourceName} cannot be null"); + options.Catalogs.Add(testSource); + options.CompositeSearchBehavior = CompositeSearchBehavior.AllCatalogs; + PackageCatalogReference compositeSource = packageManager.CreateCompositePackageCatalog(options); + + // Find package + var searchResult = this.FindOnePackage(compositeSource, PackageMatchField.Id, PackageFieldMatchOption.Equals, Constants.ExeInstallerPackageId); + + // Configure installation + var installOptions = this.TestFactory.CreateInstallOptions(); + installOptions.PackageInstallMode = PackageInstallMode.Silent; + installOptions.PreferredInstallLocation = installDir; + installOptions.AcceptPackageAgreements = true; + + // Install + var installResult = await packageManager.InstallPackageAsync(searchResult.CatalogPackage, installOptions); + Assert.AreEqual(InstallResultStatus.Ok, installResult.Status); + + // Find package again, but this time it should detect the installed version + searchResult = this.FindOnePackage(compositeSource, PackageMatchField.Id, PackageFieldMatchOption.Equals, Constants.ExeInstallerPackageId); + Assert.NotNull(searchResult.CatalogPackage.InstalledVersion); + + // Uninstall + var uninstallResult = await packageManager.UninstallPackageAsync(searchResult.CatalogPackage, this.TestFactory.CreateUninstallOptions()); + Assert.AreEqual(UninstallResultStatus.Ok, uninstallResult.Status); + Assert.True(TestCommon.VerifyTestExeUninstalled(installDir)); + + // Download + var downloadResult = await packageManager.DownloadPackageAsync(searchResult.CatalogPackage, this.TestFactory.CreateDownloadOptions()); + Assert.AreEqual(DownloadResultStatus.Ok, downloadResult.Status); + var packageVersion = "2.0.0.0"; + string downloadDir = Path.Combine(TestCommon.GetDefaultDownloadDirectory(), $"{Constants.ExeInstallerPackageId}_{packageVersion}"); + Assert.True(TestCommon.VerifyInstallerDownload(downloadDir, "TestExeInstaller", packageVersion, ProcessorArchitecture.X86, TestCommon.Scope.Unknown, PackageInstallerType.Exe)); + } } } diff --git a/tools/SampleWinGetUWPCaller/AppInstallerCaller/GeneratedFromServer/Microsoft.Management.Deployment.winmd b/tools/SampleWinGetUWPCaller/AppInstallerCaller/GeneratedFromServer/Microsoft.Management.Deployment.winmd Binary files differ. diff --git a/tools/SampleWinGetUWPCaller/AppInstallerCaller/MainPage.cpp b/tools/SampleWinGetUWPCaller/AppInstallerCaller/MainPage.cpp @@ -1,4 +1,4 @@ -#include "pch.h" +#include "pch.h" #include "MainPage.h" #include "MainPage.g.cpp" @@ -23,6 +23,7 @@ const CLSID CLSID_InstallOptions = { 0x1095f097, 0xEB96, 0x453B, 0xB4, 0xE6, 0x1 const CLSID CLSID_FindPackagesOptions = { 0x572DED96, 0x9C60, 0x4526, { 0x8F, 0x92, 0xEE, 0x7D, 0x91, 0xD3, 0x8C, 0x1A } }; //572DED96-9C60-4526-8F92-EE7D91D38C1A const CLSID CLSID_PackageMatchFilter = { 0xD02C9DAF, 0x99DC, 0x429C, { 0xB5, 0x03, 0x4E, 0x50, 0x4E, 0x4A, 0xB0, 0x00 } }; //D02C9DAF-99DC-429C-B503-4E504E4AB000 const CLSID CLSID_CreateCompositePackageCatalogOptions = { 0x526534B8, 0x7E46, 0x47C8, { 0x84, 0x16, 0xB1, 0x68, 0x5C, 0x32, 0x7D, 0x37 } }; //526534B8-7E46-47C8-8416-B1685C327D37 +const CLSID CLSID_DownloadOptions = { 0X4CBABE76, 0X7322, 0X4BE4, {0X9C, 0XEA, 0X25, 0X89, 0XA8, 0X06, 0X82, 0XDC} }; //4CBABE76-7322-4BE4-9CEA-2589A80682DC // CLSIDs for WinGetDev package const CLSID CLSID_PackageManager2 = { 0x74CB3139, 0xB7C5, 0x4B9E, { 0x93, 0x88, 0xE6, 0x61, 0x6D, 0xEA, 0x28, 0x8C } }; //74CB3139-B7C5-4B9E-9388-E6616DEA288C @@ -30,6 +31,7 @@ const CLSID CLSID_InstallOptions2 = { 0x44FE0580, 0x62F7, 0x44D4, 0x9E, 0x91, 0x const CLSID CLSID_FindPackagesOptions2 = { 0x1BD8FF3A, 0xEC50, 0x4F69, { 0xAE, 0xEE, 0xDF, 0x4C, 0x9D, 0x3B, 0xAA, 0x96 } }; //1BD8FF3A-EC50-4F69-AEEE-DF4C9D3BAA96 const CLSID CLSID_PackageMatchFilter2 = { 0x3F85B9F4, 0x487A, 0x4C48, { 0x90, 0x35, 0x29, 0x03, 0xF8, 0xA6, 0xD9, 0xE8 } }; //3F85B9F4-487A-4C48-9035-2903F8A6D9E8 const CLSID CLSID_CreateCompositePackageCatalogOptions2 = { 0xEE160901, 0xB317, 0x4EA7, { 0x9C, 0xC6, 0x53, 0x55, 0xC6, 0xD7, 0xD8, 0xA7 } }; //EE160901-B317-4EA7-9CC6-5355C6D7D8A7 +const CLSID CLSID_DownloadOptions2 = { 0X8EF324ED, 0X367C, 0X4880, {0X83, 0XE5, 0XBB, 0X2A, 0XBD, 0X0B, 0X72, 0XF6} }; //8EF324ED-367C-4880-83E5-BB2ABD0B72F6 namespace winrt::AppInstallerCaller::implementation { @@ -76,6 +78,13 @@ namespace winrt::AppInstallerCaller::implementation } return winrt::create_instance<PackageMatchFilter>(CLSID_PackageMatchFilter, CLSCTX_ALL); } + DownloadOptions MainPage::CreateDownloadOptions() { + if (m_useDev) + { + return winrt::create_instance<DownloadOptions>(CLSID_DownloadOptions2, CLSCTX_ALL); + } + return winrt::create_instance<DownloadOptions>(CLSID_DownloadOptions, CLSCTX_ALL); + } IAsyncOperation<PackageCatalog> MainPage::FindSourceAsync(std::wstring packageSource) { @@ -130,6 +139,19 @@ namespace winrt::AppInstallerCaller::implementation return packageManager.InstallPackageAsync(package, installOptions); } + IAsyncOperationWithProgress<DownloadResult, PackageDownloadProgress> MainPage::DownloadPackage(CatalogPackage package, std::wstring downloadDirectory) + { + PackageManager packageManager = CreatePackageManager(); + DownloadOptions downloadOptions = CreateDownloadOptions(); + + if (!downloadDirectory.empty()) + { + downloadOptions.DownloadDirectory(downloadDirectory); + } + + return packageManager.DownloadPackageAsync(package, downloadOptions); + } + IAsyncAction UpdateUIProgress( InstallProgress progress, winrt::Windows::UI::Xaml::Controls::ProgressBar progressBar, @@ -162,6 +184,33 @@ namespace winrt::AppInstallerCaller::implementation default: statusText.Text(L""); } + } + + IAsyncAction UpdateUIDownloadProgress( + PackageDownloadProgress progress, + winrt::Windows::UI::Xaml::Controls::ProgressBar progressBar, + winrt::Windows::UI::Xaml::Controls::TextBlock statusText) + { + co_await winrt::resume_foreground(progressBar.Dispatcher()); + progressBar.Value(progress.DownloadProgress * 100); + + std::wstring downloadText{ L"Downloading. " }; + switch (progress.State) + { + case PackageDownloadProgressState::Queued: + statusText.Text(L"Queued"); + break; + case PackageDownloadProgressState::Downloading: + downloadText += std::to_wstring(progress.BytesDownloaded) + L" bytes of " + std::to_wstring(progress.BytesRequired); + statusText.Text(downloadText); + break; + case PackageDownloadProgressState::Finished: + statusText.Text(L"Finished download."); + progressBar.IsIndeterminate(false); + break; + default: + statusText.Text(L""); + } } // This method is called from a background thread. @@ -237,6 +286,74 @@ namespace winrt::AppInstallerCaller::implementation } } + // This method is called from a background thread. + IAsyncAction UpdateUIForDownload( + IAsyncOperationWithProgress<DownloadResult, PackageDownloadProgress> operation, + winrt::Windows::UI::Xaml::Controls::Button downloadButton, + winrt::Windows::UI::Xaml::Controls::Button cancelButton, + winrt::Windows::UI::Xaml::Controls::ProgressBar progressBar, + winrt::Windows::UI::Xaml::Controls::TextBlock statusText) + { + operation.Progress([=]( + IAsyncOperationWithProgress<DownloadResult, PackageDownloadProgress> const& /* sender */, + PackageDownloadProgress const& progress) + { + UpdateUIDownloadProgress(progress, progressBar, statusText).get(); + }); + + winrt::hresult downloadOperationHr = S_OK; + std::wstring errorMessage{ L"Unknown Error" }; + DownloadResult downloadResult{ nullptr }; + try + { + downloadResult = co_await operation; + } + catch (hresult_canceled const&) + { + errorMessage = L"Cancelled"; + OutputDebugString(L"Operation was cancelled"); + } + catch (...) + { + // Operation failed + // Example: HRESULT_FROM_WIN32(ERROR_DISK_FULL). + downloadOperationHr = winrt::to_hresult(); + // Example: "There is not enough space on the disk." + errorMessage = winrt::to_message(); + OutputDebugString(L"Operation failed"); + } + + // Switch back to ui thread context. + co_await winrt::resume_foreground(progressBar.Dispatcher()); + + cancelButton.IsEnabled(false); + downloadButton.IsEnabled(true); + progressBar.IsIndeterminate(false); + + if (operation.Status() == AsyncStatus::Canceled) + { + downloadButton.Content(box_value(L"Retry")); + statusText.Text(L"Download cancelled."); + } + if (operation.Status() == AsyncStatus::Error || downloadResult == nullptr) + { + downloadButton.Content(box_value(L"Retry")); + statusText.Text(errorMessage); + } + else if (downloadResult.Status() == DownloadResultStatus::Ok) + { + downloadButton.Content(box_value(L"Download")); + statusText.Text(L"Finished."); + } + else + { + std::wostringstream failText; + failText << L"Download failed: " << downloadResult.ExtendedErrorCode(); + downloadButton.Content(box_value(L"Download")); + statusText.Text(failText.str()); + } + } + IAsyncAction MainPage::GetSources(winrt::Windows::UI::Xaml::Controls::Button button) { co_await winrt::resume_background(); @@ -412,8 +529,48 @@ namespace winrt::AppInstallerCaller::implementation } } + IAsyncAction MainPage::StartDownload( + winrt::Windows::UI::Xaml::Controls::Button button, + winrt::Windows::UI::Xaml::Controls::Button cancelButton, + winrt::Windows::UI::Xaml::Controls::ProgressBar progressBar, + winrt::Windows::UI::Xaml::Controls::TextBlock statusText) + { + button.IsEnabled(false); + cancelButton.IsEnabled(true); + int32_t selectedIndex = catalogsListBox().SelectedIndex(); + + co_await winrt::resume_background(); + + if (selectedIndex < 0) + { + co_await winrt::resume_foreground(button.Dispatcher()); + button.IsEnabled(false); + statusText.Text(L"No catalog selected to download."); + co_return; + } + + // Get the remote catalog + PackageCatalogReference selectedRemoteCatalogRef = m_packageCatalogs.GetAt(selectedIndex); + ConnectResult remoteConnectResult{ co_await selectedRemoteCatalogRef.ConnectAsync() }; + PackageCatalog selectedRemoteCatalog = remoteConnectResult.PackageCatalog(); + if (!selectedRemoteCatalog) + { + co_await winrt::resume_foreground(progressBar.Dispatcher()); + statusText.Text(L"Connecting to catalog failed."); + co_return; + } + FindPackagesResult findPackagesResult{ TryFindPackageInCatalogAsync(selectedRemoteCatalog, m_installAppId).get() }; + winrt::IVectorView<MatchResult> matches = findPackagesResult.Matches(); + if (matches.Size() > 0) + { + m_downloadPackageOperation = DownloadPackage(matches.GetAt(0).CatalogPackage(), m_downloadDirectory); + UpdateUIForDownload(m_downloadPackageOperation, button, cancelButton, progressBar, statusText); + } + } + IAsyncAction MainPage::FindPackage( - winrt::Windows::UI::Xaml::Controls::Button installButton, + winrt::Windows::UI::Xaml::Controls::Button installButton, + winrt::Windows::UI::Xaml::Controls::Button downloadButton, winrt::Windows::UI::Xaml::Controls::ProgressBar progressBar, winrt::Windows::UI::Xaml::Controls::TextBlock statusText) { @@ -461,8 +618,9 @@ namespace winrt::AppInstallerCaller::implementation else { co_await winrt::resume_foreground(installButton.Dispatcher()); - installButton.IsEnabled(true); - statusText.Text(L"Found the package to install."); + installButton.IsEnabled(true); + downloadButton.IsEnabled(true); + statusText.Text(L"Found the package to install or download."); } } else @@ -477,11 +635,13 @@ namespace winrt::AppInstallerCaller::implementation void MainPage::SearchButtonClickHandler(IInspectable const&, RoutedEventArgs const&) { m_installAppId = catalogIdTextBox().Text(); - installButton().IsEnabled(false); + installButton().IsEnabled(false); + downloadButton().IsEnabled(false); cancelButton().IsEnabled(false); installStatusText().Text(L"Looking for package."); - FindPackage(installButton(), installProgressBar(), installStatusText()); - } + FindPackage(installButton(), downloadButton(), installProgressBar(), installStatusText()); + } + void MainPage::InstallButtonClickHandler(IInspectable const&, RoutedEventArgs const&) { if (m_installPackageOperation == nullptr || m_installPackageOperation.Status() != AsyncStatus::Started) @@ -496,7 +656,26 @@ namespace winrt::AppInstallerCaller::implementation { m_installPackageOperation.Cancel(); } + } + + void MainPage::DownloadButtonClickHandler(IInspectable const&, RoutedEventArgs const&) + { + m_downloadDirectory = downloadDirectoryTextBox().Text(); + + if (m_downloadPackageOperation == nullptr || m_downloadPackageOperation.Status() != AsyncStatus::Started) + { + StartDownload(downloadButton(), downloadCancelButton(), downloadProgressBar(), downloadStatusText()); + } } + + void MainPage::DownloadCancelButtonClickHandler(IInspectable const&, RoutedEventArgs const&) + { + if (m_downloadPackageOperation && m_downloadPackageOperation.Status() == AsyncStatus::Started) + { + m_downloadPackageOperation.Cancel(); + } + } + void MainPage::RefreshInstalledButtonClickHandler(IInspectable const&, RoutedEventArgs const&) { GetInstalledPackages(installedStatusText()); diff --git a/tools/SampleWinGetUWPCaller/AppInstallerCaller/MainPage.h b/tools/SampleWinGetUWPCaller/AppInstallerCaller/MainPage.h @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. +// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. #pragma once @@ -21,6 +21,8 @@ namespace winrt::AppInstallerCaller::implementation void FindSourcesButtonClickHandler(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 CancelButtonClickHandler(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 DownloadCancelButtonClickHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& args); void SearchButtonClickHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& args); void RefreshInstalledButtonClickHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& args); void ClearInstalledButtonClickHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& args); @@ -36,8 +38,14 @@ namespace winrt::AppInstallerCaller::implementation winrt::Windows::UI::Xaml::Controls::Button cancelButton, winrt::Windows::UI::Xaml::Controls::ProgressBar progressBar, winrt::Windows::UI::Xaml::Controls::TextBlock statusText); - Windows::Foundation::IAsyncAction FindPackage( + Windows::Foundation::IAsyncAction StartDownload( winrt::Windows::UI::Xaml::Controls::Button installButton, + winrt::Windows::UI::Xaml::Controls::Button cancelButton, + winrt::Windows::UI::Xaml::Controls::ProgressBar progressBar, + winrt::Windows::UI::Xaml::Controls::TextBlock statusText); + Windows::Foundation::IAsyncAction FindPackage( + winrt::Windows::UI::Xaml::Controls::Button installButton, + winrt::Windows::UI::Xaml::Controls::Button downloadButton, winrt::Windows::UI::Xaml::Controls::ProgressBar progressBar, winrt::Windows::UI::Xaml::Controls::TextBlock statusText); @@ -47,17 +55,21 @@ namespace winrt::AppInstallerCaller::implementation Deployment::FindPackagesOptions CreateFindPackagesOptions(); Deployment::CreateCompositePackageCatalogOptions CreateCreateCompositePackageCatalogOptions(); Deployment::PackageMatchFilter CreatePackageMatchFilter(); + Deployment::DownloadOptions CreateDownloadOptions(); Windows::Foundation::IAsyncOperation<Deployment::FindPackagesResult> TryFindPackageInCatalogAsync(Deployment::PackageCatalog catalog, std::wstring packageId); Windows::Foundation::IAsyncOperation<Deployment::CatalogPackage> FindPackageInCatalogAsync(Deployment::PackageCatalog catalog, std::wstring packageId); Windows::Foundation::IAsyncOperationWithProgress<Deployment::InstallResult, Deployment::InstallProgress> InstallPackage(Deployment::CatalogPackage package); + Windows::Foundation::IAsyncOperationWithProgress<Deployment::DownloadResult, Deployment::PackageDownloadProgress> DownloadPackage(Deployment::CatalogPackage package, std::wstring downloadDirectory); Windows::Foundation::IAsyncOperation<Deployment::PackageCatalog> FindSourceAsync(std::wstring packageSource); Windows::Foundation::Collections::IObservableVector<Deployment::PackageCatalogReference> m_packageCatalogs; Windows::Foundation::Collections::IObservableVector<Deployment::CatalogPackage> m_installedPackages; Windows::Foundation::Collections::IObservableVector<winrt::AppInstallerCaller::InstallingPackageView> m_installingPackageViews; Windows::Foundation::IAsyncOperationWithProgress<Deployment::InstallResult, Deployment::InstallProgress> m_installPackageOperation; - std::wstring m_installAppId; + Windows::Foundation::IAsyncOperationWithProgress<Deployment::DownloadResult, Deployment::PackageDownloadProgress> m_downloadPackageOperation; + std::wstring m_installAppId; + std::wstring m_downloadDirectory; Deployment::PackageManager m_packageManager{ nullptr }; bool m_useDev = false; }; diff --git a/tools/SampleWinGetUWPCaller/AppInstallerCaller/MainPage.xaml b/tools/SampleWinGetUWPCaller/AppInstallerCaller/MainPage.xaml @@ -1,4 +1,4 @@ -<!-- Copyright (c) Microsoft Corporation. +<!-- Copyright (c) Microsoft Corporation. Licensed under the MIT License. --> <Page x:Class="AppInstallerCaller.MainPage" @@ -65,6 +65,15 @@ <ProgressBar x:Name="installProgressBar" Value="0" Maximum="100" Width="200px"/> <TextBlock x:Name="installStatusText" Text="" HorizontalAlignment="Center"/> + + <TextBox x:Name="downloadDirectoryTextBox" Header="Download Location:" PlaceholderText="Existing directory path to download to"></TextBox> + <StackPanel Orientation="Horizontal"> + <Button x:Name="downloadButton" Click="DownloadButtonClickHandler" IsEnabled="False">Download</Button> + <Button x:Name="downloadCancelButton" Click="DownloadCancelButtonClickHandler" IsEnabled="False">Cancel</Button> + </StackPanel> + + <ProgressBar x:Name="downloadProgressBar" Value="0" Maximum="100" Width="200px"/> + <TextBlock x:Name="downloadStatusText" Text="" HorizontalAlignment="Center"/> </StackPanel> <StackPanel Grid.Row="2" Margin="3">