10

I created a new VSIX extension project in Visual Studio 2012, and wrote a MEF classifier (as a test) that should simply highlight all text in a .mylang file. Here are the relevant parts of my .NET 4.5 code:

internal static class MyLangLanguage
{
    public const string ContentType = "mylang";

    public const string FileExtension = ".mylang";

    [Export(typeof(ClassificationTypeDefinition))]
    [Name(ContentType)]
    [BaseDefinition("code")]
    internal static ContentTypeDefinition MyLangSyntaxContentTypeDefinition = null;

    [Export]
    [FileExtension(FileExtension)]
    [ContentType(ContentType)]
    internal static FileExtensionToContentTypeDefinition MyLangSyntaxFileExtensionDefinition = null;
}

[Export(typeof(IClassifierProvider))]
[ContentType(MyLangLanguage.ContentType)]
[Name("MyLangSyntaxProvider")]
internal sealed class MyLangSyntaxProvider : IClassifierProvider
{
    [Import]
    internal IClassificationTypeRegistryService ClassificationRegistry = null;

    public IClassifier GetClassifier(ITextBuffer buffer)
    {
        return buffer.Properties.GetOrCreateSingletonProperty(() => new MyLangSyntax(ClassificationRegistry, buffer));
    }
}

internal sealed class MyLangSyntax : IClassifier { }

Here is the full code.

These are the relevant parts from my source.extension.vsixmanifest file. Based on suggestions and similar files I found across the web, I added the dependency on MPF and the two assets.

<?xml version="1.0" encoding="utf-8"?>
<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011" xmlns:d="http://schemas.microsoft.com/developer/vsx-schema-design/2011">
    <!-- ... -->
    <Dependencies>
        <Dependency Id="Microsoft.Framework.NDP" DisplayName="Microsoft .NET Framework" d:Source="Manual" Version="4.5" />
        <Dependency d:Source="Installed" Id="Microsoft.VisualStudio.MPF.11.0" DisplayName="Visual Studio MPF 11.0" Version="[11.0,12.0)" />
    </Dependencies>
    <Assets>
        <Asset Type="Microsoft.VisualStudio.VsPackage" d:Source="Project" d:ProjectName="%CurrentProject%" Path="|%CurrentProject%;PkgdefProjectOutputGroup|" />
        <Asset Type="Microsoft.VisualStudio.MefComponent" d:Source="Project" d:ProjectName="%CurrentProject%" Path="|%CurrentProject%|" />
    </Assets>
</PackageManifest>

I also tried a version 1.0 manifest:

<?xml version="1.0" encoding="utf-8"?>
<Vsix Version="1.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2010">
    <!-- ... -->
    <References />
    <Content>
        <MefComponent>|%CurrentProject%|</MefComponent>
    </Content>
</Vsix>

When I run it, it starts an experimental instance of Visual Studio 2012, and the Extensions and Updates window shows that my extension is active. However, it does not do anything when I load or create a .mylang file. Any exceptions I throw (as a test) from my extension are never thrown. Breakpoints are never hit, and get an exclamation mark with the following warning:

The breakpoint will not currently be hit. No symbols have been loaded for this document.

It feels as if my extension is never really loaded at all. My problem is similar to this problem and this problem, but I'm using Visual Studio 2012 which uses a new VSIX manifest format.

What I know:

  • I can find my DLL and VSIX file in the %localappdata%\Microsoft\VisualStudio\11.0Exp\Extensions\MyLang\VSIXProject1\1.0 folder, so I know they are copied.
  • Their timestamp corresponds to when I last built the project, so I know they are up-to-date.
  • Project Properties > Debug > Start external program: is already automatically set to C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\devenv.exe, and the Command line arguments were automatically set to /rootsuffix Exp.
  • The Visual Studio log (created with the /log option) has two entries related to my extension: Successfully loaded extension... and Extension is enabled....
  • My DLL does not appear on the Modules tab (list of all loaded DLLs) of the debugging Visual Studio, while some (not all) other extensions do appear.
  • It doesn't get loaded in Visual Studio 2012 or 2010 both on my laptop and my desktop PC.

What I've tried:

  • Set <IncludeAssemblyInVSIXContainer> to true in the .csproj file, per this suggestion, but it did not make any difference.
  • I can't add the line <MefComponent>|%CurrentProject%|</MefComponent> to the source.extension.vsixmanifest file as it uses a different format (2.0) than VSIX projects for previous versions of Visual Studio (1.0).
  • This suggestion (setting IncludeAssemblyInVSIXContainer and friends in my .csproj to true) but it does not make a difference. And my breakpoints are still showing the warning and not being hit.
  • Reset the VS Experimental instance using the Reset the Visual Studio 2012 Experimental Instance shortcut in the Start Menu, as per this suggestion. It didn't make a difference.

How can I at the very least be sure my VSIX MEF extension is loaded and works? And if possible, how can I make by breakpoint work and debug it?

Community
  • 1
  • 1
Daniel A.A. Pelsmaeker
  • 47,471
  • 20
  • 111
  • 157

3 Answers3

7

Edit: The problem is you've improperly exported your ContentTypeDefinition as a ClassificationTypeDefinition. You should use the following instead:

[Export] // <-- don't specify the type here
[Name(ContentType)]
[BaseDefinition("code")]
internal static ContentTypeDefinition MyLangSyntaxContentTypeDefinition = null;

Here's my two guesses right now:

  1. Try removing the following line from your vsixmanifest. I assume you do not have a class in your project that extends Package, in which case Visual Studio might be refusing to load your package due to the following Asset line (your extension does not actually provide this asset).

    <Asset Type="Microsoft.VisualStudio.VsPackage" d:Source="Project" d:ProjectName="%CurrentProject%" Path="|%CurrentProject%;PkgdefProjectOutputGroup|" />
    
  2. If that fails, try replacing your current source.extension.vsixmanifest with one written to the old schema (version 1.0). I know this form still works in Visual Studio 2012 because all ~20 extensions I work on (with >10 public releases) use the old schema.

Sam Harwell
  • 97,721
  • 20
  • 209
  • 280
  • No, unfortunately both didn't work. Can you reproduce it using my [full source](http://pastebin.com/kpY4fCaU)? – Daniel A.A. Pelsmaeker May 10 '13 at 22:48
  • @Virtlink found your problem and edited my answer to include the solution! – Sam Harwell May 10 '13 at 23:50
  • Well I'll be darned! You are right! I copied that straight from the [Boo Syntax](https://vs2010boo.codeplex.com/SourceControl/latest#1215246) code [someone on SO](http://stackoverflow.com/a/4283125/146622) referred to. But I was never able to test that Boo code since it had missing files. I just assumed it was correct. And I never spotted the difference between my code and [Microsoft's recommendation](http://msdn.microsoft.com/en-us/library/dd885244.aspx). And it also works with VSIX manifest format 2.0. Great job! – Daniel A.A. Pelsmaeker May 11 '13 at 00:12
  • And your suggestion [for the VSIX 2.0 manifest](http://stackoverflow.com/questions/16422004/vsix-extension-for-vs2012-not-running-when-debugging/16492678#comment23559343_16422004), your suggestion [for the VSIX 1.0 manifest](http://stackoverflow.com/questions/16422004/vsix-extension-for-vs2012-not-running-when-debugging/16492678#comment23557414_16422004) and your suggestion to remove the line with `VsPackage` from the manifest all were correct. Not doing any one of those things will cause the extension _not_ to be loaded. – Daniel A.A. Pelsmaeker May 11 '13 at 00:52
  • Mother of god. Would +200 to both of you guys, been frustrated for few days with this problem, debugged through all the visual studio extensibility DLL's. Just to throw it out there: I added my package as MefComponent to the file ShellExtensionsVSIX\source.extension.vsixmanifest & deleted bunch of registry keys / caches(12.0Exp folder) and my own company folder + clean solution. It started to work. Should've not hacked from the zero :-). Though I've learned a lot on the road. – Erti-Chris Eelmaa Apr 29 '14 at 10:44
  • I'm hitting this as well, I think I narrowed it down to my vsix contains a manifest file where %CurrentProject% isn't being replaced. anyone have any ideas – Blake Niemyjski May 17 '17 at 20:48
4

280Z28 solved the problem! For completeness, this is the full tried and tested code that will create a super simple VSIX Visual Studio MEF extension that colors all text in a .mylang file blue (or whatever the current keyword color is).

How to create a simple coloring MEF VSIX extension

  1. Make sure you have the Visual Studio SDK installed. (VS2010 SP1 SDK, VS2012 SDK)
  2. Create a new VSIX Project
    (From the template under InstalledTemplatesVisual C#Extensibility.)
  3. Enter something in the Author field of the VSIX manifest editor, then save and close it.
  4. Add references to the following libraries,
    version 10.0.0.0 for VS2010, or 11.0.0.0 for VS2012:

    • Microsoft.VisualStudio.CoreUtility.dll
    • Microsoft.VisualStudio.Language.StandardClassification.dll
    • Microsoft.VisualStudio.Text.Data.dll
    • Microsoft.VisualStudio.Text.Logic.dll
    • Microsoft.VisualStudio.Text.UI.dll
    • Microsoft.VisualStudio.Text.UI.Wpf.dll
  5. Add a reference to the following library:

    • System.ComponentModel.Composition.dll version 4.0.0.0
  6. Create and add a new code file MyLang.cs, and copy-and-paste the code below in it.

  7. Edit source.extension.vsixmanifest as XML.

    • For Visual Studio 2010, add the following XML just before the closing tag </Vsix>, and save:

      <Content>
          <MefComponent>|%CurrentProject%|</MefComponent>
      </Content>
      

      (If there is already an empty <Content/>, remove it.)

    • For Visual Stuio 2012, add the following XML just before the closing tag </PackageManifest>, and save:

      <Assets>
          <Asset Type="Microsoft.VisualStudio.MefComponent" d:Source="Project" d:ProjectName="%CurrentProject%" Path="|%CurrentProject%|" />
      </Assets>
      

      (If there is already an empty <Assets/>, remove it.)

  8. Only for Visual Studio 2010:

    • Unload the VSIX project (right-click the project → Unload project).

    • Edit the .csproj project file (right-click the project → Edit MyProject.csproj).

    • Change the value at <IncludeAssemblyInVSIXContainer> to true.

    • Save and close the file.

    • Reload the VSIX project (right-click the project → Reload project).

  9. Now build and run it. When you load a .mylang file, all text should be colored blue (or whatever the default keyword color is).


MyLang.cs

using Microsoft.VisualStudio.Language.StandardClassification;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Classification;
using Microsoft.VisualStudio.Utilities;
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;

namespace VSIXProject1
{
    internal static class MyLangLanguage
    {
        public const string ContentType = "mylang";

        public const string FileExtension = ".mylang";

        [Export]
        [Name(ContentType)]
        [BaseDefinition("code")]
        internal static ContentTypeDefinition MyLangSyntaxContentTypeDefinition = null;

        [Export]
        [FileExtension(FileExtension)]
        [ContentType(ContentType)]
        internal static FileExtensionToContentTypeDefinition MyLangSyntaxFileExtensionDefinition = null;
    }

    [Export(typeof(IClassifierProvider))]
    [ContentType(MyLangLanguage.ContentType)]
    [Name("MyLangSyntaxProvider")]
    internal sealed class MyLangSyntaxProvider : IClassifierProvider
    {
        [Import]
        internal IClassificationTypeRegistryService ClassificationRegistry = null;

        public IClassifier GetClassifier(ITextBuffer buffer)
        {
            return buffer.Properties.GetOrCreateSingletonProperty(() => new MyLangSyntax(ClassificationRegistry, buffer));
        }
    }

    internal sealed class MyLangSyntax : IClassifier
    {
        private ITextBuffer buffer;
        private IClassificationType identifierType;
        private IClassificationType keywordType;

        public event EventHandler<ClassificationChangedEventArgs> ClassificationChanged;

        internal MyLangSyntax(IClassificationTypeRegistryService registry, ITextBuffer buffer)
        {
            this.identifierType = registry.GetClassificationType(PredefinedClassificationTypeNames.Identifier);
            this.keywordType = registry.GetClassificationType(PredefinedClassificationTypeNames.Keyword);
            this.buffer = buffer;
            this.buffer.Changed += OnBufferChanged;
        }

        public IList<ClassificationSpan> GetClassificationSpans(SnapshotSpan snapshotSpan)
        {
            var classifications = new List<ClassificationSpan>();

            string text = snapshotSpan.GetText();
            var span = new SnapshotSpan(snapshotSpan.Snapshot, snapshotSpan.Start.Position, text.Length);
            classifications.Add(new ClassificationSpan(span, keywordType));

            return classifications;
        }

        private void OnBufferChanged(object sender, TextContentChangedEventArgs e)
        {
            foreach (var change in e.Changes)
                ClassificationChanged(this, new ClassificationChangedEventArgs(new SnapshotSpan(e.After, change.NewSpan)));
        }
    }
}
Community
  • 1
  • 1
Daniel A.A. Pelsmaeker
  • 47,471
  • 20
  • 111
  • 157
  • Any reason you didn't start with the classifier example? It would have set up most of this for you. – Jason Malinowski May 11 '13 at 01:55
  • @JasonMalinowski You mean the _Editor Classifier project_? Up until your comment, I didn't know it created a VSIX project. And it doesn't include the `internal static ContentTypeDefinition MyDefinition` line, so I could still have screwed the `[Export]` up when I did. – Daniel A.A. Pelsmaeker May 11 '13 at 20:25
  • Yeah, it creates a VSIX project and does steps 4 through 8 for you. I actually despise the empty VSIX project template, as it requires too much subtle knowledge of how the VSSDK build stuff works to get stuff working. – Jason Malinowski May 12 '13 at 02:08
  • Actually, I like your minimal implementation better than the somewhat bloated Editor Classifier (in VS 2015 it's now under "Add new item" in an empty VSIX project). And your MyLang.cs is still working in 2015 without changing a single line of code. Thank you. – wborgsm Oct 14 '15 at 08:27
0

Set <IncludeAssemblyInVSIXContainer> to true in the .csproj file, per this suggestion.

I had exactly the same problem and this solved it. Do a full rebuild.

Sam Harwell
  • 97,721
  • 20
  • 209
  • 280
Asylum
  • 569
  • 4
  • 21
  • How do I know if it works? My breakpoints don't work, my exceptions don't get thrown, my text doesn't get colored. I don't think it worked. Does it work on your installation? Just create a new VSIX project, add the above mentioned references and create a .cs file with [my full source code](http://pastebin.com/kpY4fCaU) in it. – Daniel A.A. Pelsmaeker May 07 '13 at 20:36
  • okay it is not exactly the same problem then :) did you try [this](http://msdn.microsoft.com/en-us/library/vstudio/bb165744.aspx?cs-save-lang=1&cs-lang=csharp) ? – Asylum May 08 '13 at 19:29