Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issues with COM API and retrieving installed packages #4320

Closed
marticliment opened this issue Mar 28, 2024 · 3 comments
Closed

Issues with COM API and retrieving installed packages #4320

marticliment opened this issue Mar 28, 2024 · 3 comments
Labels
Area-COM-API Issue related to COM API Issue-Bug It either shouldn't be doing this or needs an investigation.
Milestone

Comments

@marticliment
Copy link

marticliment commented Mar 28, 2024

Brief description of your issue

I have been trying to implement native WinGet support (WinGet COM API) on a NET/C# App (WingetUI), and I am experiencing issues when fetching installed packages.
More specifically, WinGet does not identify which packages are available on WinGet repositories, and all of the packages are listed as local only.

Running winget list shows the correct package sources on the right of package (nothing is shown if package is local, winget or msstore otherwhise).

Note: Packages do load and the list of installed packages is correct; and searching on remote catalogs works flawlessly.

Steps to reproduce

  1. Clone the repository https://github.com/marticliment/WinGet-API-from-CSharp and open the solution.
  2. On demo console app, replace Program.cs file contents by the following:
using Microsoft.Management.Deployment;
using System.Security.Principal;
using Windows.ApplicationModel;


// Include WinGet Namespace
using WindowsPackageManager.Interop;

namespace WingetTest
{
    internal class Program
    {
        static public void Main(string[] args)
        {
            var WinGetFactory = new WindowsPackageManagerStandardFactory();
            var WinGetManager = WinGetFactory.CreatePackageManager();

            // Tested all of them, none of them worked
            PackageCatalogReference selectedRemoteCatalogRef = WinGetManager.GetPackageCatalogByName("winget");
            // PackageCatalogReference selectedRemoteCatalogRef = WinGetManager.GetPackageCatalogByName("msstore");
            // PackageCatalogReference selectedRemoteCatalogRef = WinGetManager.GetLocalPackageCatalog(LocalPackageCatalog.InstalledPackages);
            // PackageCatalogReference selectedRemoteCatalogRef = WinGetManager.GetPredefinedPackageCatalog(PredefinedPackageCatalog.OpenWindowsCatalog);
            // PackageCatalogReference selectedRemoteCatalogRef = WinGetManager.GetPredefinedPackageCatalog(PredefinedPackageCatalog.MicrosoftStore);
            // PackageCatalogReference selectedRemoteCatalogRef = WinGetManager.GetPredefinedPackageCatalog(PredefinedPackageCatalog.DesktopFrameworks);


            CreateCompositePackageCatalogOptions createCompositePackageCatalogOptions = WinGetFactory.CreateCreateCompositePackageCatalogOptions();
            createCompositePackageCatalogOptions.Catalogs.Append(selectedRemoteCatalogRef);

            createCompositePackageCatalogOptions.CompositeSearchBehavior = CompositeSearchBehavior.LocalCatalogs;
            var LocalCatalogRef = WinGetManager.CreateCompositePackageCatalog(createCompositePackageCatalogOptions);

            var ConnectResult = LocalCatalogRef.Connect();
            if (ConnectResult.Status != ConnectResultStatus.Ok)
            {
                throw new Exception("WinGet: Failed to connect to local catalog.");
            }

            FindPackagesOptions findPackagesOptions = WinGetFactory.CreateFindPackagesOptions();
            PackageMatchFilter filter = WinGetFactory.CreatePackageMatchFilter();
            filter.Field = PackageMatchField.Id;
            filter.Option = PackageFieldMatchOption.Equals;
            filter.Value = "";
            findPackagesOptions.Filters.Append(filter);

            var TaskResult = ConnectResult.PackageCatalog.FindPackages(findPackagesOptions);

            foreach (var match in TaskResult.Matches.ToArray())
            {
                if (match.CatalogPackage.DefaultInstallVersion != null)
                    Console.WriteLine("Package is available Online: " + match.CatalogPackage.DefaultInstallVersion.PackageCatalog.Info.Name);
                else
                    Console.WriteLine("Package is local only: " + match.CatalogPackage.Id);
            }
        }
    }
}

Expected behavior

WinGet identifying the online packages as such when loading a local composite catalog, so they have a valid DefaultInstallVersion and online information can be retieved (update date, origin, newer versions, etc.)

Actual behavior

WinGet does not detect online packages as such. IDs are not reported properly and packages do have a null DefaultInstallVersion property.

Interestingly, the same code works flawlessly on a WinRT/C++ environment (this is from SampleWinGetCaller, tested and working flawlessly):

 int32_t selectedIndex = catalogsListBox().SelectedIndex();
 co_await winrt::resume_background();

 PackageManager packageManager = CreatePackageManager();

 PackageCatalogReference installedSearchCatalogRef{ nullptr };

 // PackageCatalogReference selectedRemoteCatalogRef = packageManager.GetPackageCatalogs().GetAt(0); //msstore
 PackageCatalogReference selectedRemoteCatalogRef = packageManager.GetPackageCatalogs().GetAt(1); //winget
 CreateCompositePackageCatalogOptions createCompositePackageCatalogOptions = CreateCreateCompositePackageCatalogOptions();
 createCompositePackageCatalogOptions.Catalogs().Append(selectedRemoteCatalogRef);

 createCompositePackageCatalogOptions.CompositeSearchBehavior(CompositeSearchBehavior::LocalCatalogs);
 installedSearchCatalogRef = packageManager.CreateCompositePackageCatalog(createCompositePackageCatalogOptions);
 

 ConnectResult connectResult{ co_await installedSearchCatalogRef.ConnectAsync() };
 PackageCatalog installedCatalog = connectResult.PackageCatalog();
 if (!installedCatalog)
 {
     // Connect Error.
     co_await winrt::resume_foreground(statusText.Dispatcher());
     statusText.Text(L"Failed to connect to catalog.");
     co_return;
 }

 FindPackagesOptions findPackagesOptions = CreateFindPackagesOptions();
 auto value = m_installAppId;
 FindPackagesResult findResult{ TryFindPackageInCatalogAsync(installedCatalog, m_installAppId).get() };
 auto matches = findResult.Matches();

 co_await winrt::resume_foreground(statusText.Dispatcher());
 m_installedPackages.Clear();
 for (auto const match : matches)
 {
     // Filter to only packages that match the selectedCatalogRef
     auto version = match.CatalogPackage().DefaultInstallVersion();
     if (selectedIndex < 0 || (version && version.PackageCatalog().Info().Id() == m_packageCatalogs.GetAt(selectedIndex).Info().Id()))
     {
         m_installedPackages.Append(match.CatalogPackage());
     }
 }

 statusText.Text(L"");

Environment

OS:
 - Windows 11 10.0.22635.3350

Tested .NET versions:
 - NET6.0
 - NET8.0

Tested WinGet versions:
 - 1.7.10661
 - 1.8.xxxxx-preview

Tested `Microsoft.WindowsPackageManager.ComInterop` versions:
 - 1.7.10091-preview
 - 1.5.1572
 - 1.4.10052

Microsoft.Management.Deployment.WINMD files provided on:
 - Microsoft.WindowsPackageManager.ComInterop package (all versions above)
 - The latest WinGet release (extracted from the MSIX installer)
 - The WinMD used by SampleWinGetCaller

All of the combinations above do behave as detailed above.
@microsoft-github-policy-service microsoft-github-policy-service bot added the Needs-Triage Issue need to be triaged label Mar 28, 2024
Copy link

Hi I'm an AI powered bot that finds similar issues based off the issue title.

Please view the issues below to see if they solve your problem, and if the issue describes your problem please consider closing this one and thumbs upping the other issue to help us prioritize it. Thank you!

Open similar issues:

Closed similar issues:

Note: You can give me feedback by thumbs upping or thumbs downing this comment.

@denelon denelon added Issue-Bug It either shouldn't be doing this or needs an investigation. Area-COM-API Issue related to COM API and removed Needs-Triage Issue need to be triaged labels Mar 28, 2024
@PatrickSchmidtSE
Copy link

PatrickSchmidtSE commented Jun 25, 2024

@marticliment if you debug, you will see the problem:

its not added to the composit catalog option sadly. BUT it is because you use "append" instead of "add". Add adds the catalog to the composite options. But i tested, does not change anything. Still i get packages shown which are not from the "winget" catalog , but have a empty source. We need a working --source winget option for the COM API
image

@marticliment
Copy link
Author

As of version 1.8.1791, this code seems to be working. Thanks @PatrickSchmidtSE for pointing into the right direction

// var WinGetFactory = new WindowsPackageManagerElevatedFactory();
var WinGetFactory = new WindowsPackageManagerStandardFactory();
var WinGetManager = WinGetFactory.CreatePackageManager();

// CHANGE THIS INDEX
int selectedIndex = 0;

PackageCatalogReference installedSearchCatalogRef;
if (selectedIndex < 0)
{
    installedSearchCatalogRef = WinGetManager.GetLocalPackageCatalog(LocalPackageCatalog.InstalledPackages);
}
else
{
    PackageCatalogReference selectedRemoteCatalogRef = WinGetManager.GetPackageCatalogs().ToArray().ElementAt(selectedIndex);
    
    Console.WriteLine($"Searching on package catalog {selectedRemoteCatalogRef.Info.Name} ");
    CreateCompositePackageCatalogOptions createCompositePackageCatalogOptions = WinGetFactory.CreateCreateCompositePackageCatalogOptions();
    createCompositePackageCatalogOptions.Catalogs.Add(selectedRemoteCatalogRef);
    createCompositePackageCatalogOptions.CompositeSearchBehavior = CompositeSearchBehavior.LocalCatalogs;
    installedSearchCatalogRef = WinGetManager.CreateCompositePackageCatalog(createCompositePackageCatalogOptions);
}

var ConnectResult = installedSearchCatalogRef.Connect();
if (ConnectResult.Status != ConnectResultStatus.Ok)
{
    throw new Exception("WinGet: Failed to connect to local catalog.");
}

FindPackagesOptions findPackagesOptions = WinGetFactory.CreateFindPackagesOptions();
PackageMatchFilter filter = WinGetFactory.CreatePackageMatchFilter();
filter.Field = PackageMatchField.Id;
filter.Option = PackageFieldMatchOption.ContainsCaseInsensitive;
filter.Value = "";
findPackagesOptions.Filters.Add(filter);

var TaskResult = ConnectResult.PackageCatalog.FindPackages(findPackagesOptions);

Console.WriteLine("Begin enumeration");
foreach (var match in TaskResult.Matches.ToArray())
{
    if (match.CatalogPackage.DefaultInstallVersion != null)
        Console.WriteLine($"Package {match.CatalogPackage.Name} is available Online: " + match.CatalogPackage.DefaultInstallVersion.PackageCatalog.Info.Name);
    //else
        //Console.WriteLine("Package is local only: " + match.CatalogPackage.Id);
}
Console.WriteLine("End enumeration");

@denelon denelon added this to the 1.9 Client milestone Jul 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-COM-API Issue related to COM API Issue-Bug It either shouldn't be doing this or needs an investigation.
Projects
None yet
Development

No branches or pull requests

3 participants