winget-cli

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

MainPage.cpp (31028B)


      1 #include "pch.h"
      2 #include "MainPage.h"
      3 #include "MainPage.g.cpp"
      4 
      5 #include <wrl.h>
      6 #include <winrt/Microsoft.Management.Deployment.h>
      7 #include <winrt/Windows.UI.Core.h>
      8 
      9 using namespace Microsoft::WRL;
     10 using namespace std::chrono_literals;
     11 using namespace winrt::Microsoft::Management::Deployment;
     12 
     13 namespace winrt
     14 {
     15     using namespace Windows::UI::Xaml;
     16     using namespace Windows::Foundation;
     17     using namespace Windows::Foundation::Collections;
     18 }
     19 
     20 // CLSIDs for WinGet package
     21 const CLSID CLSID_PackageManager = { 0xC53A4F16, 0x787E, 0x42A4, 0xB3, 0x04, 0x29, 0xEF, 0xFB, 0x4B, 0xF5, 0x97 };  //C53A4F16-787E-42A4-B304-29EFFB4BF597
     22 const CLSID CLSID_InstallOptions = { 0x1095f097, 0xEB96, 0x453B, 0xB4, 0xE6, 0x16, 0x13, 0x63, 0x7F, 0x3B, 0x14 };  //1095F097-EB96-453B-B4E6-1613637F3B14
     23 const CLSID CLSID_FindPackagesOptions = { 0x572DED96, 0x9C60, 0x4526, { 0x8F, 0x92, 0xEE, 0x7D, 0x91, 0xD3, 0x8C, 0x1A } }; //572DED96-9C60-4526-8F92-EE7D91D38C1A
     24 const CLSID CLSID_PackageMatchFilter = { 0xD02C9DAF, 0x99DC, 0x429C, { 0xB5, 0x03, 0x4E, 0x50, 0x4E, 0x4A, 0xB0, 0x00 } }; //D02C9DAF-99DC-429C-B503-4E504E4AB000
     25 const CLSID CLSID_CreateCompositePackageCatalogOptions = { 0x526534B8, 0x7E46, 0x47C8, { 0x84, 0x16, 0xB1, 0x68, 0x5C, 0x32, 0x7D, 0x37 } }; //526534B8-7E46-47C8-8416-B1685C327D37
     26 const CLSID CLSID_DownloadOptions = { 0X4CBABE76, 0X7322, 0X4BE4, {0X9C, 0XEA, 0X25, 0X89, 0XA8, 0X06, 0X82, 0XDC} };  //4CBABE76-7322-4BE4-9CEA-2589A80682DC
     27 
     28 // CLSIDs for WinGetDev package
     29 const CLSID CLSID_PackageManager2 = { 0x74CB3139, 0xB7C5, 0x4B9E, { 0x93, 0x88, 0xE6, 0x61, 0x6D, 0xEA, 0x28, 0x8C } };  //74CB3139-B7C5-4B9E-9388-E6616DEA288C
     30 const CLSID CLSID_InstallOptions2 = { 0x44FE0580, 0x62F7, 0x44D4, 0x9E, 0x91, 0xAA, 0x96, 0x14, 0xAB, 0x3E, 0x86 };  //44FE0580-62F7-44D4-9E91-AA9614AB3E86
     31 const CLSID CLSID_FindPackagesOptions2 = { 0x1BD8FF3A, 0xEC50, 0x4F69, { 0xAE, 0xEE, 0xDF, 0x4C, 0x9D, 0x3B, 0xAA, 0x96 } }; //1BD8FF3A-EC50-4F69-AEEE-DF4C9D3BAA96
     32 const CLSID CLSID_PackageMatchFilter2 = { 0x3F85B9F4, 0x487A, 0x4C48, { 0x90, 0x35, 0x29, 0x03, 0xF8, 0xA6, 0xD9, 0xE8 } }; //3F85B9F4-487A-4C48-9035-2903F8A6D9E8
     33 const CLSID CLSID_CreateCompositePackageCatalogOptions2 = { 0xEE160901, 0xB317, 0x4EA7, { 0x9C, 0xC6, 0x53, 0x55, 0xC6, 0xD7, 0xD8, 0xA7 } }; //EE160901-B317-4EA7-9CC6-5355C6D7D8A7
     34 const CLSID CLSID_DownloadOptions2 = { 0X8EF324ED, 0X367C, 0X4880, {0X83, 0XE5, 0XBB, 0X2A, 0XBD, 0X0B, 0X72, 0XF6} };  //8EF324ED-367C-4880-83E5-BB2ABD0B72F6
     35 
     36 namespace winrt::AppInstallerCaller::implementation
     37 {
     38     MainPage::MainPage()
     39     {
     40         InitializeComponent();
     41         m_packageCatalogs = winrt::single_threaded_observable_vector<PackageCatalogReference>();
     42         m_installedPackages = winrt::single_threaded_observable_vector<CatalogPackage>();
     43         m_installingPackageViews = winrt::single_threaded_observable_vector<winrt::AppInstallerCaller::InstallingPackageView>();
     44     }
     45 
     46     PackageManager MainPage::CreatePackageManager() {
     47         if (m_useDev)
     48         {
     49             return winrt::create_instance<PackageManager>(CLSID_PackageManager2, CLSCTX_ALL);
     50         }
     51         return winrt::create_instance<PackageManager>(CLSID_PackageManager, CLSCTX_ALL);
     52     }
     53     InstallOptions MainPage::CreateInstallOptions() {
     54         if (m_useDev)
     55         {
     56             return winrt::create_instance<InstallOptions>(CLSID_InstallOptions2, CLSCTX_ALL);
     57         }
     58         return winrt::create_instance<InstallOptions>(CLSID_InstallOptions, CLSCTX_ALL);
     59     }
     60     FindPackagesOptions MainPage::CreateFindPackagesOptions() {
     61         if (m_useDev)
     62         {
     63             return winrt::create_instance<FindPackagesOptions>(CLSID_FindPackagesOptions2, CLSCTX_ALL);
     64         }
     65         return winrt::create_instance<FindPackagesOptions>(CLSID_FindPackagesOptions, CLSCTX_ALL);
     66     }
     67     CreateCompositePackageCatalogOptions MainPage::CreateCreateCompositePackageCatalogOptions() {
     68         if (m_useDev)
     69         {
     70             return winrt::create_instance<CreateCompositePackageCatalogOptions>(CLSID_CreateCompositePackageCatalogOptions2, CLSCTX_ALL);
     71         }
     72         return winrt::create_instance<CreateCompositePackageCatalogOptions>(CLSID_CreateCompositePackageCatalogOptions, CLSCTX_ALL);
     73     }
     74     PackageMatchFilter MainPage::CreatePackageMatchFilter() {
     75         if (m_useDev)
     76         {
     77             return winrt::create_instance<PackageMatchFilter>(CLSID_PackageMatchFilter2, CLSCTX_ALL);
     78         }
     79         return winrt::create_instance<PackageMatchFilter>(CLSID_PackageMatchFilter, CLSCTX_ALL);
     80     }
     81     DownloadOptions MainPage::CreateDownloadOptions() {
     82         if (m_useDev)
     83         {
     84             return winrt::create_instance<DownloadOptions>(CLSID_DownloadOptions2, CLSCTX_ALL);
     85         }
     86         return winrt::create_instance<DownloadOptions>(CLSID_DownloadOptions, CLSCTX_ALL);
     87     }
     88 
     89     IAsyncOperation<PackageCatalog> MainPage::FindSourceAsync(std::wstring packageSource)
     90     {
     91         PackageManager packageManager = CreatePackageManager();
     92         PackageCatalogReference catalogRef{ packageManager.GetPackageCatalogByName(packageSource) };
     93         if (catalogRef)
     94         {
     95             ConnectResult connectResult{ co_await catalogRef.ConnectAsync() };
     96             // PackageCatalog will be null if connectResult.ErrorCode() is a failure
     97             PackageCatalog catalog = connectResult.PackageCatalog();
     98             co_return catalog;
     99         }
    100     }
    101 
    102     IAsyncOperation<FindPackagesResult> MainPage::TryFindPackageInCatalogAsync(PackageCatalog catalog, std::wstring packageId)
    103     {
    104         FindPackagesOptions findPackagesOptions = CreateFindPackagesOptions();
    105         PackageMatchFilter filter = CreatePackageMatchFilter();
    106         filter.Field(PackageMatchField::Id);
    107         filter.Option(PackageFieldMatchOption::Equals);
    108         filter.Value(packageId);
    109         findPackagesOptions.Filters().Append(filter);
    110         return catalog.FindPackagesAsync(findPackagesOptions);
    111     }
    112     IAsyncOperation<CatalogPackage> MainPage::FindPackageInCatalogAsync(PackageCatalog catalog, std::wstring packageId)
    113     {
    114         FindPackagesOptions findPackagesOptions = CreateFindPackagesOptions();
    115         PackageMatchFilter filter = CreatePackageMatchFilter();
    116         filter.Field(PackageMatchField::Id);
    117         filter.Option(PackageFieldMatchOption::Equals);
    118         filter.Value(packageId);
    119         findPackagesOptions.Filters().Append(filter);
    120         FindPackagesResult findPackagesResult{ co_await catalog.FindPackagesAsync(findPackagesOptions) };
    121 
    122         winrt::IVectorView<MatchResult> matches = findPackagesResult.Matches();
    123         if (matches.Size() == 0)
    124         {
    125             co_return nullptr;
    126         }
    127         co_return matches.GetAt(0).CatalogPackage();
    128     }
    129 
    130     IAsyncOperationWithProgress<InstallResult, InstallProgress> MainPage::InstallPackage(CatalogPackage package)
    131     {
    132         PackageManager packageManager = CreatePackageManager();
    133         InstallOptions installOptions = CreateInstallOptions();
    134 
    135         // Passing PackageInstallScope::User causes the install to fail if there's no installer that supports that.
    136         installOptions.PackageInstallScope(PackageInstallScope::Any);
    137         installOptions.PackageInstallMode(PackageInstallMode::Silent);
    138 
    139         return packageManager.InstallPackageAsync(package, installOptions);
    140     }
    141 
    142     IAsyncOperationWithProgress<DownloadResult, PackageDownloadProgress> MainPage::DownloadPackage(CatalogPackage package, std::wstring downloadDirectory)
    143     {
    144         PackageManager packageManager = CreatePackageManager();
    145         DownloadOptions downloadOptions = CreateDownloadOptions();
    146 
    147         if (!downloadDirectory.empty())
    148         {
    149             downloadOptions.DownloadDirectory(downloadDirectory);
    150         }
    151 
    152         return packageManager.DownloadPackageAsync(package, downloadOptions);
    153     }
    154 
    155     IAsyncAction UpdateUIProgress(
    156         InstallProgress progress,
    157         winrt::Windows::UI::Xaml::Controls::ProgressBar progressBar,
    158         winrt::Windows::UI::Xaml::Controls::TextBlock statusText)
    159     {
    160         co_await winrt::resume_foreground(progressBar.Dispatcher());
    161         progressBar.Value(progress.DownloadProgress*100);
    162 
    163         std::wstring downloadText{ L"Downloading. " };
    164         switch (progress.State)
    165         {
    166         case PackageInstallProgressState::Queued:
    167             statusText.Text(L"Queued");
    168             break;
    169         case PackageInstallProgressState::Downloading:
    170             downloadText += std::to_wstring(progress.BytesDownloaded) + L" bytes of " + std::to_wstring(progress.BytesRequired);
    171             statusText.Text(downloadText);
    172             break;
    173         case PackageInstallProgressState::Installing:
    174             statusText.Text(L"Installing");
    175             progressBar.IsIndeterminate(true);
    176             break;
    177         case PackageInstallProgressState::PostInstall:
    178             statusText.Text(L"Finishing install");
    179             break;
    180         case PackageInstallProgressState::Finished:
    181             statusText.Text(L"Finished install.");
    182             progressBar.IsIndeterminate(false);
    183             break;
    184         default:
    185             statusText.Text(L"");
    186         }
    187     }
    188 
    189     IAsyncAction UpdateUIDownloadProgress(
    190         PackageDownloadProgress progress,
    191         winrt::Windows::UI::Xaml::Controls::ProgressBar progressBar,
    192         winrt::Windows::UI::Xaml::Controls::TextBlock statusText)
    193     {
    194         co_await winrt::resume_foreground(progressBar.Dispatcher());
    195         progressBar.Value(progress.DownloadProgress * 100);
    196 
    197         std::wstring downloadText{ L"Downloading. " };
    198         switch (progress.State)
    199         {
    200         case PackageDownloadProgressState::Queued:
    201             statusText.Text(L"Queued");
    202             break;
    203         case PackageDownloadProgressState::Downloading:
    204             downloadText += std::to_wstring(progress.BytesDownloaded) + L" bytes of " + std::to_wstring(progress.BytesRequired);
    205             statusText.Text(downloadText);
    206             break;
    207         case PackageDownloadProgressState::Finished:
    208             statusText.Text(L"Finished download.");
    209             progressBar.IsIndeterminate(false);
    210             break;
    211         default:
    212             statusText.Text(L"");
    213         }
    214     }
    215 
    216     // This method is called from a background thread.
    217     IAsyncAction UpdateUIForInstall(
    218         IAsyncOperationWithProgress<InstallResult, InstallProgress> installPackageOperation,
    219         winrt::Windows::UI::Xaml::Controls::Button installButton,
    220         winrt::Windows::UI::Xaml::Controls::Button cancelButton,
    221         winrt::Windows::UI::Xaml::Controls::ProgressBar progressBar,
    222         winrt::Windows::UI::Xaml::Controls::TextBlock statusText)
    223     {
    224         installPackageOperation.Progress([=](
    225             IAsyncOperationWithProgress<InstallResult, InstallProgress> const& /* sender */,
    226             InstallProgress const& progress)
    227             {
    228                 UpdateUIProgress(progress, progressBar, statusText).get();
    229             });
    230 
    231         winrt::hresult installOperationHr = S_OK;
    232         std::wstring errorMessage{ L"Unknown Error" };
    233         InstallResult installResult{ nullptr };
    234         try
    235         {
    236             installResult = co_await installPackageOperation;
    237         }
    238         catch (hresult_canceled const&)
    239         {
    240             errorMessage = L"Cancelled";
    241             OutputDebugString(L"Operation was cancelled");
    242         }
    243         catch (...)
    244         {
    245             // Operation failed
    246             // Example: HRESULT_FROM_WIN32(ERROR_DISK_FULL).
    247             installOperationHr = winrt::to_hresult();
    248             // Example: "There is not enough space on the disk."
    249             errorMessage = winrt::to_message();
    250             OutputDebugString(L"Operation failed");
    251         }
    252 
    253         // Switch back to ui thread context.
    254         co_await winrt::resume_foreground(progressBar.Dispatcher());
    255 
    256         cancelButton.IsEnabled(false);
    257         installButton.IsEnabled(true);
    258         progressBar.IsIndeterminate(false);
    259 
    260         if (installPackageOperation.Status() == AsyncStatus::Canceled)
    261         {
    262             installButton.Content(box_value(L"Retry"));
    263             statusText.Text(L"Install cancelled.");
    264         }
    265         if (installPackageOperation.Status() == AsyncStatus::Error || installResult == nullptr)
    266         {
    267             installButton.Content(box_value(L"Retry"));
    268             statusText.Text(errorMessage);
    269         }
    270         else if (installResult.RebootRequired())
    271         {
    272             installButton.Content(box_value(L"Install"));
    273             statusText.Text(L"Reboot to finish installation.");
    274         }
    275         else if (installResult.Status() == InstallResultStatus::Ok)
    276         {
    277             installButton.Content(box_value(L"Install"));
    278             statusText.Text(L"Finished.");
    279         }
    280         else
    281         {
    282             std::wostringstream failText;
    283             failText << L"Install failed: " << installResult.ExtendedErrorCode() << L" [" << installResult.InstallerErrorCode() << L"]";
    284             installButton.Content(box_value(L"Install"));
    285             statusText.Text(failText.str());
    286         }
    287     }
    288 
    289     // This method is called from a background thread.
    290     IAsyncAction UpdateUIForDownload(
    291         IAsyncOperationWithProgress<DownloadResult, PackageDownloadProgress> operation,
    292         winrt::Windows::UI::Xaml::Controls::Button downloadButton,
    293         winrt::Windows::UI::Xaml::Controls::Button cancelButton,
    294         winrt::Windows::UI::Xaml::Controls::ProgressBar progressBar,
    295         winrt::Windows::UI::Xaml::Controls::TextBlock statusText)
    296     {
    297         operation.Progress([=](
    298             IAsyncOperationWithProgress<DownloadResult, PackageDownloadProgress> const& /* sender */,
    299             PackageDownloadProgress const& progress)
    300             {
    301                 UpdateUIDownloadProgress(progress, progressBar, statusText).get();
    302             });
    303 
    304         winrt::hresult downloadOperationHr = S_OK;
    305         std::wstring errorMessage{ L"Unknown Error" };
    306         DownloadResult downloadResult{ nullptr };
    307         try
    308         {
    309             downloadResult = co_await operation;
    310         }
    311         catch (hresult_canceled const&)
    312         {
    313             errorMessage = L"Cancelled";
    314             OutputDebugString(L"Operation was cancelled");
    315         }
    316         catch (...)
    317         {
    318             // Operation failed
    319             // Example: HRESULT_FROM_WIN32(ERROR_DISK_FULL).
    320             downloadOperationHr = winrt::to_hresult();
    321             // Example: "There is not enough space on the disk."
    322             errorMessage = winrt::to_message();
    323             OutputDebugString(L"Operation failed");
    324         }
    325 
    326         // Switch back to ui thread context.
    327         co_await winrt::resume_foreground(progressBar.Dispatcher());
    328 
    329         cancelButton.IsEnabled(false);
    330         downloadButton.IsEnabled(true);
    331         progressBar.IsIndeterminate(false);
    332 
    333         if (operation.Status() == AsyncStatus::Canceled)
    334         {
    335             downloadButton.Content(box_value(L"Retry"));
    336             statusText.Text(L"Download cancelled.");
    337         }
    338         if (operation.Status() == AsyncStatus::Error || downloadResult == nullptr)
    339         {
    340             downloadButton.Content(box_value(L"Retry"));
    341             statusText.Text(errorMessage);
    342         }
    343         else if (downloadResult.Status() == DownloadResultStatus::Ok)
    344         {
    345             downloadButton.Content(box_value(L"Download"));
    346             statusText.Text(L"Finished.");
    347         }
    348         else
    349         {
    350             std::wostringstream failText;
    351             failText << L"Download failed: " << downloadResult.ExtendedErrorCode();
    352             downloadButton.Content(box_value(L"Download"));
    353             statusText.Text(failText.str());
    354         }
    355     }
    356 
    357     IAsyncAction MainPage::GetSources(winrt::Windows::UI::Xaml::Controls::Button button)
    358     {
    359         co_await winrt::resume_background();
    360 
    361         PackageManager packageManager = CreatePackageManager();
    362         auto catalogs{ packageManager.GetPackageCatalogs() };
    363         auto storeCatalog{ packageManager.GetPredefinedPackageCatalog(PredefinedPackageCatalog::MicrosoftStore) };
    364 
    365         co_await winrt::resume_foreground(button.Dispatcher());
    366 
    367         m_packageCatalogs.Clear();
    368         for (auto const catalog : catalogs)
    369         {
    370             m_packageCatalogs.Append(catalog);
    371         }
    372         m_packageCatalogs.Append(storeCatalog);
    373 
    374         co_return;
    375     }
    376 
    377     IAsyncAction MainPage::GetInstalledPackages(winrt::Windows::UI::Xaml::Controls::TextBlock statusText)
    378     {
    379         int32_t selectedIndex = catalogsListBox().SelectedIndex();
    380         co_await winrt::resume_background();
    381 
    382         PackageManager packageManager = CreatePackageManager();
    383 
    384         PackageCatalogReference installedSearchCatalogRef{ nullptr };
    385 
    386         if (selectedIndex < 0)
    387         {
    388             installedSearchCatalogRef = packageManager.GetLocalPackageCatalog(LocalPackageCatalog::InstalledPackages);
    389         }
    390         else
    391         {
    392             PackageCatalogReference selectedRemoteCatalogRef = m_packageCatalogs.GetAt(selectedIndex);
    393             CreateCompositePackageCatalogOptions createCompositePackageCatalogOptions = CreateCreateCompositePackageCatalogOptions();
    394             createCompositePackageCatalogOptions.Catalogs().Append(selectedRemoteCatalogRef);
    395 
    396             createCompositePackageCatalogOptions.CompositeSearchBehavior(CompositeSearchBehavior::LocalCatalogs);
    397             installedSearchCatalogRef = packageManager.CreateCompositePackageCatalog(createCompositePackageCatalogOptions);
    398         }
    399 
    400         ConnectResult connectResult{ co_await installedSearchCatalogRef.ConnectAsync() };
    401         PackageCatalog installedCatalog = connectResult.PackageCatalog();
    402         if (!installedCatalog)
    403         {
    404             // Connect Error.
    405             co_await winrt::resume_foreground(statusText.Dispatcher());
    406             statusText.Text(L"Failed to connect to catalog.");
    407             co_return;
    408         }
    409 
    410         FindPackagesOptions findPackagesOptions = CreateFindPackagesOptions();
    411 
    412         FindPackagesResult findResult{ TryFindPackageInCatalogAsync(installedCatalog, m_installAppId).get() };
    413         auto matches = findResult.Matches();
    414 
    415         co_await winrt::resume_foreground(statusText.Dispatcher());
    416         m_installedPackages.Clear();
    417         for (auto const match : matches)
    418         {
    419             // Filter to only packages that match the selectedCatalogRef
    420             auto version = match.CatalogPackage().DefaultInstallVersion();
    421             if (selectedIndex < 0 || (version && version.PackageCatalog().Info().Id() == m_packageCatalogs.GetAt(selectedIndex).Info().Id()))
    422             {
    423                 m_installedPackages.Append(match.CatalogPackage());
    424             }
    425         }
    426 
    427         statusText.Text(L"");
    428         co_return;
    429     }
    430     IAsyncAction MainPage::GetInstallingPackages(winrt::Windows::UI::Xaml::Controls::TextBlock statusText)
    431     {
    432         int32_t selectedIndex = catalogsListBox().SelectedIndex();
    433         co_await winrt::resume_background();
    434 
    435         PackageManager packageManager = CreatePackageManager();
    436 
    437         PackageCatalogReference installingSearchCatalogRef{ nullptr };
    438 
    439         if (selectedIndex < 0)
    440         {
    441             // Installing package querying is only really useful if you know what Catalog you're interested in.
    442             co_await winrt::resume_foreground(statusText.Dispatcher());
    443             statusText.Text(L"No catalog selected.");
    444             co_return;
    445         }
    446 
    447         installingSearchCatalogRef = packageManager.GetLocalPackageCatalog(LocalPackageCatalog::InstallingPackages);
    448 
    449         PackageCatalogReference selectedRemoteCatalogRef = m_packageCatalogs.GetAt(selectedIndex);
    450         ConnectResult remoteConnectResult{ co_await selectedRemoteCatalogRef.ConnectAsync() };
    451         PackageCatalog selectedRemoteCatalog = remoteConnectResult.PackageCatalog();
    452         if (!selectedRemoteCatalog)
    453         {
    454             co_await winrt::resume_foreground(statusText.Dispatcher());
    455             statusText.Text(L"Failed to connect to catalog.");
    456             co_return;
    457         }
    458 
    459         ConnectResult connectResult{ co_await installingSearchCatalogRef.ConnectAsync() };
    460         PackageCatalog installingCatalog = connectResult.PackageCatalog();
    461         if (!installingCatalog)
    462         {
    463             co_await winrt::resume_foreground(statusText.Dispatcher());
    464             statusText.Text(L"Failed to connect to catalog.");
    465             co_return;
    466         }
    467 
    468         FindPackagesOptions findPackagesOptions = CreateFindPackagesOptions();
    469 
    470         FindPackagesResult findResult{ TryFindPackageInCatalogAsync(selectedRemoteCatalog, m_installAppId).get() };
    471         auto matches = findResult.Matches();
    472 
    473         co_await winrt::resume_foreground(statusText.Dispatcher());
    474 
    475         m_installingPackageViews.Clear();
    476         for (auto const match : matches)
    477         {
    478             winrt::AppInstallerCaller::InstallingPackageView installingView;
    479             installingView.Package(match.CatalogPackage());
    480             auto installOperation = packageManager.GetInstallProgress(installingView.Package(), selectedRemoteCatalog.Info());
    481             if (installOperation)
    482             {
    483                 installingView.Dispatcher(statusText.Dispatcher());
    484                 installingView.AsyncOperation(installOperation);
    485                 m_installingPackageViews.Append(installingView);
    486             }
    487         }
    488 
    489         statusText.Text(L"");
    490         co_return;
    491     }
    492 
    493     IAsyncAction MainPage::StartInstall(
    494         winrt::Windows::UI::Xaml::Controls::Button installButton,
    495         winrt::Windows::UI::Xaml::Controls::Button cancelButton,
    496         winrt::Windows::UI::Xaml::Controls::ProgressBar progressBar,
    497         winrt::Windows::UI::Xaml::Controls::TextBlock statusText)
    498     {
    499         installButton.IsEnabled(false);
    500         cancelButton.IsEnabled(true);
    501         int32_t selectedIndex = catalogsListBox().SelectedIndex();
    502 
    503         co_await winrt::resume_background();
    504 
    505         if (selectedIndex < 0)
    506         {
    507             co_await winrt::resume_foreground(installButton.Dispatcher());
    508             installButton.IsEnabled(false);
    509             statusText.Text(L"No catalog selected to install.");
    510             co_return;
    511         }
    512 
    513         // Get the remote catalog
    514         PackageCatalogReference selectedRemoteCatalogRef = m_packageCatalogs.GetAt(selectedIndex);
    515         ConnectResult remoteConnectResult{ co_await selectedRemoteCatalogRef.ConnectAsync() };
    516         PackageCatalog selectedRemoteCatalog = remoteConnectResult.PackageCatalog();
    517         if (!selectedRemoteCatalog)
    518         {
    519             co_await winrt::resume_foreground(progressBar.Dispatcher());
    520             statusText.Text(L"Connecting to catalog failed.");
    521             co_return;
    522         }
    523         FindPackagesResult findPackagesResult{ TryFindPackageInCatalogAsync(selectedRemoteCatalog, m_installAppId).get() };
    524         winrt::IVectorView<MatchResult> matches = findPackagesResult.Matches();
    525         if (matches.Size() > 0)
    526         {
    527             m_installPackageOperation = InstallPackage(matches.GetAt(0).CatalogPackage());
    528             UpdateUIForInstall(m_installPackageOperation, installButton, cancelButton, progressBar, statusText);
    529         }
    530     }
    531 
    532     IAsyncAction MainPage::StartDownload(
    533         winrt::Windows::UI::Xaml::Controls::Button button,
    534         winrt::Windows::UI::Xaml::Controls::Button cancelButton,
    535         winrt::Windows::UI::Xaml::Controls::ProgressBar progressBar,
    536         winrt::Windows::UI::Xaml::Controls::TextBlock statusText)
    537     {
    538         button.IsEnabled(false);
    539         cancelButton.IsEnabled(true);
    540         int32_t selectedIndex = catalogsListBox().SelectedIndex();
    541 
    542         co_await winrt::resume_background();
    543 
    544         if (selectedIndex < 0)
    545         {
    546             co_await winrt::resume_foreground(button.Dispatcher());
    547             button.IsEnabled(false);
    548             statusText.Text(L"No catalog selected to download.");
    549             co_return;
    550         }
    551 
    552         // Get the remote catalog
    553         PackageCatalogReference selectedRemoteCatalogRef = m_packageCatalogs.GetAt(selectedIndex);
    554         ConnectResult remoteConnectResult{ co_await selectedRemoteCatalogRef.ConnectAsync() };
    555         PackageCatalog selectedRemoteCatalog = remoteConnectResult.PackageCatalog();
    556         if (!selectedRemoteCatalog)
    557         {
    558             co_await winrt::resume_foreground(progressBar.Dispatcher());
    559             statusText.Text(L"Connecting to catalog failed.");
    560             co_return;
    561         }
    562         FindPackagesResult findPackagesResult{ TryFindPackageInCatalogAsync(selectedRemoteCatalog, m_installAppId).get() };
    563         winrt::IVectorView<MatchResult> matches = findPackagesResult.Matches();
    564         if (matches.Size() > 0)
    565         {
    566             m_downloadPackageOperation = DownloadPackage(matches.GetAt(0).CatalogPackage(), m_downloadDirectory);
    567             UpdateUIForDownload(m_downloadPackageOperation, button, cancelButton, progressBar, statusText);
    568         }
    569     }
    570 
    571     IAsyncAction MainPage::FindPackage(
    572         winrt::Windows::UI::Xaml::Controls::Button installButton,
    573         winrt::Windows::UI::Xaml::Controls::Button downloadButton,
    574         winrt::Windows::UI::Xaml::Controls::ProgressBar progressBar,
    575         winrt::Windows::UI::Xaml::Controls::TextBlock statusText)
    576     {
    577         int32_t selectedIndex = catalogsListBox().SelectedIndex();
    578         if (selectedIndex < 0)
    579         {
    580             co_await winrt::resume_foreground(installButton.Dispatcher());
    581             installButton.IsEnabled(false);
    582             statusText.Text(L"No catalog selected to search.");
    583             co_return;
    584         }
    585 
    586         co_await winrt::resume_background();
    587 
    588         // Get the remote catalog
    589         PackageCatalogReference selectedRemoteCatalogRef = m_packageCatalogs.GetAt(selectedIndex);
    590         // Create the composite catalog
    591         CreateCompositePackageCatalogOptions createCompositePackageCatalogOptions = CreateCreateCompositePackageCatalogOptions();
    592         createCompositePackageCatalogOptions.Catalogs().Append(selectedRemoteCatalogRef);
    593         PackageManager packageManager = CreatePackageManager();
    594         PackageCatalogReference catalogRef{ packageManager.CreateCompositePackageCatalog(createCompositePackageCatalogOptions) };
    595         ConnectResult connectResult{ co_await catalogRef.ConnectAsync() };
    596         PackageCatalog compositeCatalog = connectResult.PackageCatalog();
    597         if (!compositeCatalog)
    598         {
    599             co_await winrt::resume_foreground(installButton.Dispatcher());
    600             installButton.IsEnabled(false);
    601             statusText.Text(L"Failed to connect to catalog.");
    602             co_return;
    603         }
    604 
    605         // Do the search.
    606         FindPackagesResult findPackagesResult{ TryFindPackageInCatalogAsync(compositeCatalog, m_installAppId).get() };
    607 
    608         winrt::IVectorView<MatchResult> matches = findPackagesResult.Matches();
    609         if (matches.Size() > 0)
    610         {
    611             auto installedVersion = matches.GetAt(0).CatalogPackage().InstalledVersion();
    612             if (installedVersion != nullptr)
    613             {
    614                 co_await winrt::resume_foreground(installButton.Dispatcher());
    615                 installButton.IsEnabled(false);
    616                 statusText.Text(L"Already installed. Product code: " + installedVersion.ProductCodes().GetAt(0));
    617             }
    618             else
    619             {
    620                 co_await winrt::resume_foreground(installButton.Dispatcher());
    621                 installButton.IsEnabled(true);
    622                 downloadButton.IsEnabled(true);
    623                 statusText.Text(L"Found the package to install or download.");
    624             }
    625         }
    626         else
    627         {
    628             co_await winrt::resume_foreground(installButton.Dispatcher());
    629             installButton.IsEnabled(false);
    630             statusText.Text(L"Did not find package.");
    631         }
    632         co_return;
    633     }
    634 
    635     void MainPage::SearchButtonClickHandler(IInspectable const&, RoutedEventArgs const&)
    636     {
    637         m_installAppId = catalogIdTextBox().Text();
    638         installButton().IsEnabled(false);
    639         downloadButton().IsEnabled(false);
    640         cancelButton().IsEnabled(false);
    641         installStatusText().Text(L"Looking for package.");
    642         FindPackage(installButton(), downloadButton(), installProgressBar(), installStatusText());
    643     }
    644 
    645     void MainPage::InstallButtonClickHandler(IInspectable const&, RoutedEventArgs const&)
    646     {
    647         if (m_installPackageOperation == nullptr || m_installPackageOperation.Status() != AsyncStatus::Started)
    648         {
    649             StartInstall(installButton(), cancelButton(), installProgressBar(), installStatusText());
    650         }
    651     }
    652 
    653     void MainPage::CancelButtonClickHandler(IInspectable const&, RoutedEventArgs const&)
    654     {
    655         if (m_installPackageOperation && m_installPackageOperation.Status() == AsyncStatus::Started)
    656         {
    657             m_installPackageOperation.Cancel();
    658         }
    659     }
    660 
    661     void MainPage::DownloadButtonClickHandler(IInspectable const&, RoutedEventArgs const&)
    662     {
    663         m_downloadDirectory = downloadDirectoryTextBox().Text();
    664 
    665         if (m_downloadPackageOperation == nullptr || m_downloadPackageOperation.Status() != AsyncStatus::Started)
    666         {
    667             StartDownload(downloadButton(), downloadCancelButton(), downloadProgressBar(), downloadStatusText());
    668         }
    669     }
    670 
    671     void MainPage::DownloadCancelButtonClickHandler(IInspectable const&, RoutedEventArgs const&)
    672     {
    673         if (m_downloadPackageOperation && m_downloadPackageOperation.Status() == AsyncStatus::Started)
    674         {
    675             m_downloadPackageOperation.Cancel();
    676         }
    677     }
    678 
    679     void MainPage::RefreshInstalledButtonClickHandler(IInspectable const&, RoutedEventArgs const&)
    680     {
    681         GetInstalledPackages(installedStatusText());
    682     }
    683     void MainPage::ClearInstalledButtonClickHandler(IInspectable const&, RoutedEventArgs const&)
    684     {
    685         m_installedPackages.Clear();
    686     }
    687     void MainPage::RefreshInstallingButtonClickHandler(IInspectable const&, RoutedEventArgs const&)
    688     {
    689         GetInstallingPackages(installingStatusText());
    690     }
    691     void MainPage::ClearInstallingButtonClickHandler(IInspectable const&, RoutedEventArgs const&)
    692     {
    693         m_installingPackageViews.Clear();
    694     }
    695 
    696     void MainPage::ToggleDevSwitchToggled(IInspectable const&, winrt::Windows::UI::Xaml::RoutedEventArgs const&)
    697     {
    698         m_useDev = toggleDevSwitch().IsOn();
    699     }
    700     void MainPage::FindSourcesButtonClickHandler(IInspectable const&, RoutedEventArgs const&)
    701     {
    702         GetSources(installButton());
    703     }
    704 
    705     Windows::Foundation::Collections::IObservableVector<Microsoft::Management::Deployment::PackageCatalogReference> MainPage::PackageCatalogs()
    706     {
    707         return m_packageCatalogs;
    708     }
    709     Windows::Foundation::Collections::IObservableVector<Microsoft::Management::Deployment::CatalogPackage> MainPage::InstalledApps()
    710     {
    711         return m_installedPackages;
    712     }
    713     Windows::Foundation::Collections::IObservableVector<winrt::AppInstallerCaller::InstallingPackageView> MainPage::InstallingPackages()
    714     {
    715         return m_installingPackageViews;
    716     }
    717 }