1

I have a DSL-tools project where I use [ProvideAutoLoad] because it adds a set of menu commands to Visual Studio to allow the user to transform code (we have lots of text templates), and few other things.

Since VS2019 does not allow to autoload sync packages anymore, I get that annoying warnings even when the option to allow autoload is on.

Apparently Microsoft has no plans to provide an async version of ModelingPackage (I am in fact begining to question if their not in the way to descontinue DSL-tools alltogether).

As anyone found a way of working around this?

I have tried to use another package - built as AsyncPackage - so that one would load my DSL-tools package on InitializeAsync() but I end up with all sorts of exceptions using the IVsShell service.

protected override async Task InitializeAsync(CancellationToken cancellationToken, IProgress<VSShell.ServiceProgressData> progress)
{
    // Default behavior

    await base.InitializeAsync(cancellationToken, progress).ConfigureAwait(false);

    // Load the service designer package

    this.EnsureDesignerPackage();

    // Switche to the UI thread

    await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);

    // Menu commands

    this.InitializeMenuCommands();
}

private void EnsureDesignerPackage()
{
    // Package already loaded?

    if (!this.IsDesignerPackageLoaded())
    {
        this.LoadDesignerPackage();
    }
}

private bool IsDesignerPackageLoaded()
{
    // Package identifier

    Guid packageId = new Guid(GlobalConstants.ServiceDesignerPackageId);

    // Is loaded?

    IVsShell service = this.VsShellService;

    int hr = this.VsShellService.IsPackageLoaded(ref packageId, out IVsPackage package);
    if (ErrorHandler.Succeeded(hr) && package != null)
    {
        return true;
    }

    // Default result

    return false;
}

private void LoadDesignerPackage()
{
    // Package identifier

    Guid packageId = new Guid(GlobalConstants.ServiceDesignerPackageId);

    // Not loaded?

    int hr = this.VsShellService.IsPackageLoaded(ref packageId, out IVsPackage package);
    if (hr != VSConstants.S_OK || package == null)
    {
        // Load

        hr = this.VsShellService.LoadPackage(ref packageId, out package);
        if (ErrorHandler.Failed(hr))
        {
            string message = "Service designer loading failed: {0}.".Format().With(hr);
            this.ShowException(message);
        }
    }
}
  • 2
    IMHO, DSL tools has always been on the edge of being dropped, with every VS release... I has not really evolved for all these years, it just continues to work because most of VS still supports 20 years old interfaces. I sure wouldn't bet on this for the long term, but you should ask Microsoft about that (why not add comments to Mads Kristensen's blog) – Simon Mourier Aug 22 '19 at 14:14

1 Answers1

1

I just happened to walk a customer through this same scenario earlier today. Unfortunately, the last time I asked there were no current plans to update the underlying DSL framework to leverage AsyncPackage or similar. I saw you already logged a suggestion in the dev community site, and just up voted and added my own $.02. I would encourage anyone hitting this to up vote this suggestion linked above.

To add support for Async Load, to your DSL Package object, you'll want to add a reference the Microsoft.VisualStudio.Shell.Interop.14.0.DesignTime.dll assembly, and then edit your Package.tt file, to add a VSShell.PackageRegistration attribute with AllowsBackgroundLoading set to true, and implement the IAsyncLoadablePackageInitialize interface on that same class. For example:

namespace <#= CodeGenerationUtilities.GetPackageNamespace(this.Dsl) #>
{
    /// <summary>
    /// Double-derived class to allow easier code customization.
    /// </summary>
    [VSShell::ProvideMenuResource("1000.ctmenu", 1)]
    [VSShell::ProvideToolboxItems(1)]
    [VSShell::PackageRegistration(AllowsBackgroundLoading = true)]
    [global::Microsoft.VisualStudio.TextTemplating.VSHost.ProvideDirectiveProcessor(typeof(global::<#= this.Dsl.Namespace #>.<#= directiveName #>DirectiveProcessor), global::<#= this.Dsl.Namespace #>.<#= directiveName #>DirectiveProcessor.<#= directiveName #>DirectiveProcessorName, "A directive processor that provides access to <#= directiveName #> files")]
    [global::System.Runtime.InteropServices.Guid(Constants.<#= dslName #>PackageId)]
    internal sealed partial class <#= dslName #>Package : <#= dslName #>PackageBase, VSShellInterop.IAsyncLoadablePackageInitialize
    {
        public VSShellInterop.IVsTask Initialize(VSShellInterop.IAsyncServiceProvider pServiceProvider, VSShellInterop.IProfferAsyncService pProfferService, VSShellInterop.IAsyncProgressCallback pProgressCallback)
        {
            // do async initialization here
            return null;
        }
    }
}

Sincerely,

Ed Dore
  • 2,013
  • 1
  • 10
  • 8