Why does looping over C++ projects and configurations in a VSIX extension cause Visual Studio to freeze?

Ben G 0 Reputation points
2023-07-29T10:52:48.9933333+00:00

I'm doing some work on a Visual Studio plugin and I've come across an issue when I'm trying to loop over a large number of C++ projects and their configurations. What I observe when I try to iterate over a solution containing ~200 projects is that around the 130 to 150 projects processed mark, Visual Studio goes into a not responding state and cannot be recovered. In the debugger the CPU usage drops to zero - it shows no activity at all.

I've extracted the method from the plugin and created this minimal reproducible example which I can consistently reproduce the issue with:

 private dynamic GetLocalConfiguration(dynamic configurations, string configName, string platformName)
{
    foreach (dynamic config in configurations)
    {
        if (config.ConfigurationName == configName &&
            config.Platform.Name == platformName)
        {
            return config;
        }
    }
    return null;
}

private void Execute(object sender, EventArgs e)
{
    ThreadHelper.ThrowIfNotOnUIThread();


    // NOTE: ServiceProvider is an instance of Microsoft.VisualStudio.Shell.Package
    var dte = (DTE2)ServiceProvider.GetService(typeof(EnvDTE.DTE));

    var solution = (Solution2)dte.Solution;
    var solutionBuild = (SolutionBuild2)solution.SolutionBuild;
    var activeConfiguration = (SolutionConfiguration2)solutionBuild.ActiveConfiguration;

    var contexts = activeConfiguration.SolutionContexts.Cast<SolutionContext>();
    var projects = solution.Projects;

    int projectsProcessed = 0;
    foreach (dynamic pj in projects)
    {
        var localContext = contexts.FirstOrDefault(c =>
        {
            Microsoft.VisualStudio.Shell.ThreadHelper.ThrowIfNotOnUIThread();
            return c.ProjectName == pj.UniqueName;
        });

        if (localContext == null || !localContext.ShouldBuild)
            break;

        dynamic projectObject = pj.Object;

        var localConfigurations = projectObject.Configurations;
        var localConfiguration = GetLocalConfiguration(localConfigurations, localContext.ConfigurationName, localContext.PlatformName);

        if (localConfiguration != null)
        {
            Debug.WriteLine("Got configuration");

            // Do required work with the configuration here
        }

        projectsProcessed++;
        Debug.WriteLine("Processed project {0}", projectsProcessed);
    }
}

I've created a test extension where the code above is just hooked up to an entry in the tools drop-down. This is the only code that I've added to the extension that is executed. The ServiceProvider is an instance of Microsoft.VisualStudio.Shell.Package.

I can confirm that the issue is present on multiple machines too. I've tried on 3 separate Windows 10 machines and the issue is present in both Visual Studio 2022 Community and Visual Studio 2022 Professional. This is my first foray into VSIX plugin development and I've not really worked with COM objects before so my instinct is that potentially this is being handled in the wrong way. Perhaps there's some kind of manual cleanup that needs to be performed? I've struggled to find documentation on the subject beyond just basic usage of DTE and its related objects so any insight into what could be wrong would be very much appreciated.

C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
10,627 questions
Visual Studio Extensions
Visual Studio Extensions
Visual Studio: A family of Microsoft suites of integrated development tools for building applications for Windows, the web and mobile devices.Extensions: A program or program module that adds functionality to or extends the effectiveness of a program.
192 questions
{count} votes